Beta2 relase
[jvcard.git] / src / be / nikiroo / jvcard / Card.java
1 package be.nikiroo.jvcard;
2
3 import java.io.BufferedReader;
4 import java.io.BufferedWriter;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.FileWriter;
8 import java.io.IOException;
9 import java.io.InputStreamReader;
10 import java.security.InvalidParameterException;
11 import java.util.Arrays;
12 import java.util.LinkedList;
13 import java.util.List;
14
15 import be.nikiroo.jvcard.parsers.Format;
16 import be.nikiroo.jvcard.parsers.Parser;
17
18 /**
19 * A card is a contact information card. It contains data about one or more
20 * contacts.
21 *
22 * @author niki
23 *
24 */
25 public class Card {
26 private List<Contact> contacts;
27 private File file;
28 private boolean dirty;
29 private String name;
30 private Format format;
31
32 /**
33 * Create a new {@link Card} from the given {@link File} and {@link Format}.
34 *
35 * @param file
36 * the file containing the {@link Card} data, must not be NULL
37 * @param format
38 * the {@link Format} to use to parse it
39 *
40 * @throws IOException
41 * in case of IO error
42 * @throws NullPointerException
43 * if file is NULL
44 * @throws InvalidParameterException
45 * if format is NULL
46 */
47 public Card(File file, Format format) throws IOException {
48 this.file = file;
49 this.format = format;
50 this.name = file.getName();
51
52 BufferedReader buffer = new BufferedReader(new InputStreamReader(
53 new FileInputStream(file), "UTF-8"));
54 List<String> lines = new LinkedList<String>();
55 for (String line = buffer.readLine(); line != null; line = buffer
56 .readLine()) {
57 lines.add(line);
58 }
59 buffer.close();
60
61 load(lines, format);
62 dirty = false; // initial load, so no change yet, so no need to call
63 // setPristine()
64 }
65
66 /**
67 * Return the number of {@link Contact} present in this {@link Card}.
68 *
69 * @return the number of {@link Contact}s
70 */
71 public int size() {
72 return contacts.size();
73 }
74
75 /**
76 * Return the {@link Contact} at index <i>index</i>.
77 *
78 * @param index
79 * the index of the {@link Contact} to find
80 *
81 * @return the {@link Contact}
82 *
83 * @throws IndexOutOfBoundsException
84 * if the index is < 0 or >= {@link Card#size()}
85 */
86 public Contact get(int index) {
87 return contacts.get(index);
88 }
89
90 /**
91 * Add a new {@link Contact} in this {@link Card}.
92 *
93 * @param contact
94 * the new contact
95 */
96 public void add(Contact contact) {
97 contact.setParent(this);
98 contact.setDirty();
99 contacts.add(contact);
100 }
101
102 /**
103 * Remove the given {@link Contact} from its this {@link Card} if it is in.
104 *
105 * @return TRUE in case of success
106 */
107 public boolean remove(Contact contact) {
108 if (contacts.remove(contact)) {
109 setDirty();
110 }
111
112 return false;
113 }
114
115 /**
116 * Save the {@link Card} to the given {@link File} with the given
117 * {@link Format}.
118 *
119 * @param file
120 * the {@link File} to save to
121 * @param format
122 * the {@link Format} to use
123 *
124 * @return TRUE if it was saved
125 *
126 * @throws IOException
127 * in case of IO errors
128 */
129 public boolean saveAs(File file, Format format) throws IOException {
130 if (file == null)
131 return false;
132
133 BufferedWriter writer = new BufferedWriter(new FileWriter(file));
134 writer.append(toString(format));
135 writer.close();
136
137 if (file.equals(this.file)) {
138 setPristine();
139 }
140
141 return true;
142 }
143
144 /**
145 * Save the {@link Card} to the original {@link File} it was open from.
146 *
147 * @return TRUE if it was saved
148 *
149 * @throws IOException
150 * in case of IO errors
151 */
152 public boolean save() throws IOException {
153 return saveAs(file, format);
154 }
155
156 /**
157 * Return a {@link String} representation of this {@link Card} in the given
158 * {@link Format}.
159 *
160 * @param format
161 * the {@link Format} to use
162 *
163 * @return the {@link String}
164 */
165 public String toString(Format format) {
166 return Parser.toString(this, format);
167 }
168
169 /**
170 * Check if this {@link Card} has unsaved changes.
171 *
172 * @return TRUE if it has
173 */
174 public boolean isDirty() {
175 return dirty;
176 }
177
178 /**
179 * Return the name of this card (the name of the {@link File} which it was
180 * opened from).
181 *
182 * @return the name
183 */
184 public String getName() {
185 return name;
186 }
187
188 @Override
189 public String toString() {
190 return toString(Format.VCard21);
191 }
192
193 /**
194 * Load the given data from the given {@link Format} in this {@link Card}.
195 *
196 * @param serializedContent
197 * the data
198 * @param format
199 * the {@link Format}
200 */
201 protected void load(String serializedContent, Format format) {
202 // note: fixed size array
203 List<String> lines = Arrays.asList(serializedContent.split("\n"));
204 load(lines, format);
205 }
206
207 /**
208 * Load the given data from the given {@link Format} in this {@link Card}.
209 *
210 * @param lines
211 * the data
212 * @param format
213 * the {@link Format}
214 */
215 protected void load(List<String> lines, Format format) {
216 this.contacts = Parser.parse(lines, format);
217 setDirty();
218
219 for (Contact contact : contacts) {
220 contact.setParent(this);
221 }
222 }
223
224 /**
225 * Notify that this element has unsaved changes.
226 */
227 void setDirty() {
228 dirty = true;
229 }
230
231 /**
232 * Notify this element <i>and all its descendants</i> that it is in pristine
233 * state (as opposed to dirty).
234 */
235 void setPristine() {
236 dirty = false;
237 for (Contact contact : contacts) {
238 contact.setPristine();
239 }
240 }
241 }