Some fixes (crash when adding raw "x=" field, "dirty" handling)
[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.LinkedList;
12 import java.util.List;
13
14 import be.nikiroo.jvcard.parsers.Format;
15 import be.nikiroo.jvcard.parsers.Parser;
16
17 /**
18 * A card is a contact information card. It contains data about one or more
19 * contacts.
20 *
21 * @author niki
22 *
23 */
24 public class Card extends BaseClass<Contact> {
25 private File file;
26 private String name;
27 private Format format;
28 private long lastModified;
29 private boolean remote;
30
31 /**
32 * Create a new {@link Card} from the given {@link File} and {@link Format}.
33 *
34 * @param file
35 * the input {@link File} containing the {@link Card} data or
36 * NULL for an empty card (usually a {@link File} name or a
37 * network path)
38 * @param format
39 * the {@link Format} to use to parse it
40 *
41 * @throws IOException
42 * in case of IO error
43 * @throws InvalidParameterException
44 * if format is NULL
45 */
46 public Card(File file, Format format) throws IOException {
47 this(load(file, format));
48
49 if (file != null) {
50 if (file.exists()) {
51 lastModified = file.lastModified();
52 }
53 }
54
55 this.format = format;
56
57 if (file != null) {
58 this.file = file;
59 switch (format) {
60 case VCard21:
61 this.name = file.getName().replaceAll(
62 ".[vV][cC][fF]$", "");
63 break;
64 case Abook:
65 default:
66 this.name = file.getName();
67 break;
68 }
69 }
70 }
71
72 /**
73 * Create a new {@link Card} from the given {@link Contact}s.
74 *
75 * @param contacts
76 * the input contacts
77 *
78 * @throws IOException
79 * in case of IO error
80 * @throws InvalidParameterException
81 * if format is NULL
82 */
83 public Card(List<Contact> contacts) throws IOException {
84 super(contacts);
85
86 lastModified = -1;
87 }
88
89 /**
90 * Save the {@link Card} to the given {@link File} with the given
91 * {@link Format}.
92 *
93 * @param output
94 * the output to save to
95 * @param format
96 * the {@link Format} to use
97 *
98 * @return TRUE if it was saved
99 *
100 * @throws IOException
101 * in case of IO errors
102 */
103 public boolean saveAs(File output, Format format) throws IOException {
104 if (output == null)
105 return false;
106
107 BufferedWriter writer = new BufferedWriter(new FileWriter(output));
108 writer.append(toString(format));
109 writer.close();
110
111 if (output.getCanonicalPath().equals(this.file.getCanonicalPath())) {
112 setPristine();
113 }
114
115 return true;
116 }
117
118 /**
119 * Save the {@link Card} to the original {@link File} it was open from.
120 *
121 * @return TRUE if it was saved
122 *
123 * @throws IOException
124 * in case of IO errors
125 */
126 public boolean save() throws IOException {
127 return saveAs(file, format);
128 }
129
130 /**
131 * Reload the data from the input.
132 *
133 * @return TRUE if it was done
134 *
135 * @throws IOException
136 * in case of IO error
137 */
138 public boolean reload() throws IOException {
139 if (file == null)
140 return false;
141
142 this.replaceListContent(load(file, format));
143 setPristine();
144 return true;
145 }
146
147 /**
148 * Return a {@link String} representation of this {@link Card} in the given
149 * {@link Format}.
150 *
151 * @param format
152 * the {@link Format} to use
153 *
154 * @return the {@link String}
155 */
156 public String toString(Format format) {
157 return Parser.toString(this, format);
158 }
159
160 /**
161 * Return the name of this card (the name of the {@link File} which it was
162 * opened from).
163 *
164 * @return the name
165 */
166 public String getName() {
167 return name;
168 }
169
170 /**
171 * Return the original {@link Format} of the {@link Card}.
172 *
173 * @return the {@link Format}
174 */
175 public Format getFormat() {
176 return format;
177 }
178
179 /**
180 * Return the input which was used to open this {@link Card}.
181 *
182 * @return the input
183 */
184 public File getInput() {
185 return file;
186 }
187
188 /**
189 * Return the date of the last modification for this {@link Card} (or -1 if
190 * unknown/new).
191 *
192 * @return the last modified date
193 */
194 public long getLastModified() {
195 return lastModified;
196 }
197
198 /**
199 * Check if this {@link Card} is remote.
200 *
201 * @return TRUE if this {@link Card} is remote
202 */
203 public boolean isRemote() {
204 return remote;
205 }
206
207 /**
208 * Set the remote option on this {@link Card}.
209 *
210 * @param remote
211 * TRUE if this {@link Card} is remote
212 */
213 public void setRemote(boolean remote) {
214 this.remote = remote;
215 }
216
217 @Override
218 public String toString() {
219 return toString(Format.VCard21);
220 }
221
222 /**
223 * Load the data from the given {@link File} under the given {@link Format}.
224 *
225 * @param file
226 * the input to load from
227 * @param format
228 * the {@link Format} to load as
229 *
230 * @return the list of elements
231 *
232 * @throws IOException
233 * in case of IO error
234 */
235 private static List<Contact> load(File file, Format format)
236 throws IOException {
237 List<String> lines = null;
238
239 if (file != null && file.exists()) {
240 BufferedReader buffer = new BufferedReader(new InputStreamReader(
241 new FileInputStream(file), "UTF-8"));
242 lines = new LinkedList<String>();
243 for (String line = buffer.readLine(); line != null; line = buffer
244 .readLine()) {
245 lines.add(line);
246 }
247 buffer.close();
248 }
249
250 if (lines == null)
251 return new LinkedList<Contact>();
252
253 return Parser.parse(lines, format);
254 }
255 }