OSDN Git Service

Add very basic support for importing Evernote export files.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / xml / ImportEnex.java
1 /*\r
2  * This file is part of NixNote \r
3  * Copyright 2011 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 \r
20 package cx.fbn.nevernote.xml;\r
21 \r
22 import java.security.MessageDigest;\r
23 import java.security.NoSuchAlgorithmException;\r
24 import java.text.DateFormat;\r
25 import java.text.ParseException;\r
26 import java.text.SimpleDateFormat;\r
27 import java.util.ArrayList;\r
28 import java.util.Date;\r
29 \r
30 import com.evernote.edam.type.Data;\r
31 import com.evernote.edam.type.Note;\r
32 import com.evernote.edam.type.NoteAttributes;\r
33 import com.evernote.edam.type.NoteSortOrder;\r
34 import com.evernote.edam.type.Notebook;\r
35 import com.evernote.edam.type.Publishing;\r
36 import com.evernote.edam.type.Resource;\r
37 import com.evernote.edam.type.ResourceAttributes;\r
38 import com.evernote.edam.type.Tag;\r
39 import com.trolltech.qt.core.QByteArray;\r
40 import com.trolltech.qt.core.QFile;\r
41 import com.trolltech.qt.core.QIODevice;\r
42 import com.trolltech.qt.core.QUuid;\r
43 import com.trolltech.qt.gui.QIcon;\r
44 import com.trolltech.qt.gui.QImage;\r
45 import com.trolltech.qt.gui.QPixmap;\r
46 import com.trolltech.qt.xml.QXmlStreamReader;\r
47 \r
48 import cx.fbn.nevernote.sql.DatabaseConnection;\r
49 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
50 \r
51 public class ImportEnex {\r
52 \r
53         public int                                                      lastError;\r
54         private String                                          errorMessage;\r
55         private String                                          fileName;\r
56         DatabaseConnection                                      conn;\r
57         QXmlStreamReader                                        reader;\r
58         private Note                                            note;\r
59         private Notebook                                        notebook;\r
60         private boolean                                         notebookIsDirty;\r
61         private boolean                                         notebookIsLocal;\r
62         private boolean                                         notebookIsReadOnly;\r
63         private QIcon                                           notebookIcon;\r
64         private Tag                                                     tag;\r
65         private boolean                                         tagIsDirty;\r
66         public int                                                      highUpdateSequenceNumber;\r
67         public long                                                     lastSequenceDate;\r
68         private final ApplicationLogger         logger;\r
69         private final boolean                           backup;\r
70         private String                                          notebookGuid;\r
71         public final boolean                            importTags = false;\r
72         public final boolean                            importNotebooks = false;\r
73         private String newGuid;\r
74         \r
75         public ImportEnex(DatabaseConnection c, boolean full) {\r
76                 logger = new ApplicationLogger("import.log");\r
77                 backup = full;\r
78                 conn = c;\r
79         }\r
80         \r
81         public void importData(String f) {\r
82                 fileName = f;\r
83                 errorMessage = "";\r
84                                 \r
85                 lastError = 0;\r
86                 errorMessage = "";\r
87                 QFile xmlFile = new QFile(fileName);\r
88                 if (!xmlFile.open(QIODevice.OpenModeFlag.ReadOnly)) {\r
89                         lastError = 16;\r
90                         errorMessage = "Cannot open file.";\r
91                 }\r
92                         \r
93                 reader = new QXmlStreamReader(xmlFile); \r
94                 while (!reader.atEnd()) {\r
95                         reader.readNext();\r
96                         if (reader.hasError()) {\r
97                                 errorMessage = reader.errorString();\r
98                                 logger.log(logger.LOW, "************************* ERROR READING FILE " +reader.errorString());\r
99                                 lastError = 16;\r
100                                 return;\r
101                         }\r
102                         if (reader.name().equalsIgnoreCase("note") && reader.isStartElement()) {\r
103                                 processNoteNode();\r
104                                 note.setUpdateSequenceNum(0);\r
105                                 if (notebookGuid != null) \r
106                                         note.setNotebookGuid(notebookGuid);\r
107                                 for (int i=0; i<note.getResourcesSize(); i++) {\r
108                                         note.getResources().get(i).setUpdateSequenceNum(0);\r
109                                 }\r
110                                 note.setActive(true);\r
111                                 conn.getNoteTable().addNote(note, true);\r
112                         }\r
113                         if (reader.name().equalsIgnoreCase("notebook") && reader.isStartElement() && (backup || importNotebooks)) {\r
114                                 processNotebookNode();\r
115                         String existingGuid = conn.getNotebookTable().findNotebookByName(notebook.getName());\r
116                         if (existingGuid == null) {\r
117                                 conn.getNotebookTable().addNotebook(notebook, notebookIsDirty, notebookIsLocal);\r
118                         } else {\r
119                                 conn.getNotebookTable().updateNotebookGuid(existingGuid, notebook.getGuid());\r
120                                 conn.getNotebookTable().updateNotebook(notebook, notebookIsDirty);\r
121                         }\r
122                         conn.getNotebookTable().setIcon(notebook.getGuid(), notebookIcon, "PNG");\r
123                         conn.getNotebookTable().setReadOnly(notebook.getGuid(), notebookIsReadOnly);\r
124                         }\r
125                         if (reader.name().equalsIgnoreCase("tag") && reader.isStartElement() && (backup || importTags)) {\r
126                                 processTagNode();\r
127                                 String testGuid = conn.getTagTable().findTagByName(tag.getName());\r
128                         if (testGuid == null)\r
129                                 conn.getTagTable().addTag(tag, tagIsDirty);\r
130                         else {\r
131                                 conn.getTagTable().updateTagGuid(testGuid, tag.getGuid());\r
132                                 conn.getTagTable().updateTag(tag,tagIsDirty);\r
133                         }\r
134                         }\r
135                 }\r
136                 xmlFile.close();\r
137         }\r
138         \r
139         \r
140         private void processNoteNode() {\r
141                 note = new Note();\r
142                 newGuid = QUuid.createUuid().toString().replace("{", "").replace("}", "");\r
143                 note.setGuid(newGuid);\r
144                 note.setResources(new ArrayList<Resource>());\r
145                 \r
146                 boolean atEnd = false;\r
147                 while(!atEnd) {\r
148                         if (reader.name().equalsIgnoreCase("title")) \r
149                                 note.setTitle(textValue());\r
150                         if (reader.name().equalsIgnoreCase("Created")) \r
151                                 note.setCreated(datetimeValue());\r
152                         if (reader.name().equalsIgnoreCase("Content")) \r
153                                 note.setContent(textValue());\r
154                         if (reader.name().equalsIgnoreCase("note-attributes")) \r
155                                 note.setAttributes(processNoteAttributes());\r
156                         if (reader.name().equalsIgnoreCase("resource")) {\r
157                                 note.getResources().add(processResource());\r
158                         }\r
159                         reader.readNext();\r
160                         if (reader.name().equalsIgnoreCase("note") && reader.isEndElement())\r
161                                 atEnd = true;\r
162                 }\r
163                 return;\r
164         }       \r
165         private Resource processResource() {\r
166                 Resource resource = new Resource();\r
167                 boolean atEnd = false;\r
168                 while(!atEnd) {\r
169                         if (reader.isStartElement()) {\r
170                                 String newResGuid = QUuid.createUuid().toString().replace("{", "").replace("}", "");\r
171                                 resource.setGuid(newResGuid);\r
172                                 resource.setNoteGuid(this.newGuid);\r
173                         }\r
174                         if (reader.name().equalsIgnoreCase("mime")) \r
175                                 resource.setMime(textValue());\r
176                         if (reader.name().equalsIgnoreCase("height")) \r
177                                 resource.setHeight(shortValue());\r
178                         if (reader.name().equalsIgnoreCase("width")) \r
179                                 resource.setWidth(shortValue());\r
180                         if (reader.name().equalsIgnoreCase("data")) \r
181                                 resource.setData(processData("data"));\r
182 //                              if (reader.name().equalsIgnoreCase("recognition")) \r
183 //                                      resource.setRecognition(processData("NoteResourceAttribute"));\r
184                         reader.readNext();\r
185                         if (reader.name().equalsIgnoreCase("resource") && reader.isEndElement())\r
186                                 atEnd = true;\r
187                 }\r
188                 resource.setAttributes(new ResourceAttributes());\r
189                 resource.getAttributes().setSourceURL("");\r
190                 conn.getNoteTable().noteResourceTable.saveNoteResource(resource, true);\r
191 \r
192                 \r
193                 return resource;\r
194         }\r
195         \r
196         private Data processData(String nodeName) {\r
197                 Data data = new Data();\r
198                 boolean atEnd = false;\r
199                 while(!atEnd) {\r
200                         if (reader.isStartElement()) {\r
201                                 byte[] b = textValue().getBytes();   // data binary\r
202                                 if (b.length > 0) {\r
203                                         QByteArray hexData = new QByteArray(b);\r
204                                         QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
205                                         data.setBody(binData.toByteArray());\r
206                                         MessageDigest md;\r
207                                         try {\r
208                                                 md = MessageDigest.getInstance("MD5");\r
209                                                 md.update(b);\r
210                                                 data.setBodyHash(md.digest());\r
211                                         } catch (NoSuchAlgorithmException e) {\r
212                                                 // TODO Auto-generated catch block\r
213                                                 e.printStackTrace();\r
214                                         }\r
215                                 }\r
216                         }\r
217                         if (reader.name().equalsIgnoreCase(nodeName) && reader.isEndElement())\r
218                                 atEnd = true;\r
219                         else \r
220                                 reader.readNext();\r
221                 }\r
222                 return data;\r
223         }\r
224 \r
225         \r
226         private NoteAttributes processNoteAttributes() {\r
227         NoteAttributes attributes = new NoteAttributes();\r
228         \r
229         boolean atEnd = false;\r
230         while(!atEnd) {\r
231                 if (reader.isStartElement()) {\r
232                         if (reader.name().equalsIgnoreCase("source-url")) \r
233                                 attributes.setSourceURL(textValue());\r
234                         if (reader.name().equalsIgnoreCase("source")) \r
235                                 attributes.setSource(textValue());\r
236                 }\r
237                 reader.readNext();\r
238                 if (reader.name().equalsIgnoreCase("note-attributes") && reader.isEndElement())\r
239                         atEnd = true;\r
240         }\r
241         \r
242         return attributes;\r
243 }\r
244 \r
245                 \r
246         \r
247 \r
248         \r
249 \r
250         \r
251         private void processNotebookNode() {\r
252                 notebook = new Notebook();\r
253                 Publishing p = new Publishing();\r
254                 notebook.setPublishing(p);\r
255                 notebookIsDirty = false;\r
256                 notebookIsLocal = false;\r
257                 notebookIsReadOnly = false;\r
258                 notebookIcon = null;\r
259                 boolean atEnd = false;\r
260                 while(!atEnd) {\r
261                         if (reader.isStartElement()) {\r
262                                 if (reader.name().equalsIgnoreCase("Guid")) \r
263                                         notebook.setGuid(textValue());\r
264                                 if (reader.name().equalsIgnoreCase("Name")) \r
265                                         notebook.setName(textValue());\r
266                                 if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
267                                         notebook.setUpdateSequenceNum(intValue());\r
268                                 if (reader.name().equalsIgnoreCase("ServiceCreated")) \r
269                                         notebook.setServiceCreated(longValue());\r
270                                 if (reader.name().equalsIgnoreCase("ServiceUpdated")) \r
271                                         notebook.setServiceUpdated(longValue());\r
272                                 if (reader.name().equalsIgnoreCase("DefaultNotebook")) {\r
273                                         notebook.setDefaultNotebook(booleanValue());\r
274                                 }\r
275                                 if (reader.name().equalsIgnoreCase("Dirty")) {\r
276                                         if (booleanValue())\r
277                                                 notebookIsDirty = true;\r
278                                 }\r
279                                 if (reader.name().equalsIgnoreCase("LocalNotebook")) {\r
280                                         if (booleanValue())\r
281                                                 notebookIsLocal = true;\r
282                                 }\r
283                                 if (reader.name().equalsIgnoreCase("ReadOnly")) {\r
284                                         if (booleanValue())\r
285                                                 notebookIsReadOnly = true;\r
286                                 }\r
287                                 if (reader.name().equalsIgnoreCase("PublishingPublicDescription")) {\r
288                                         notebook.getPublishing().setPublicDescription(textValue());\r
289                                 }\r
290                                 if (reader.name().equalsIgnoreCase("PublishingUri")) {\r
291                                         notebook.getPublishing().setUri(textValue());\r
292                                 }\r
293                                 if (reader.name().equalsIgnoreCase("PublishingOrder")) {\r
294                                         notebook.getPublishing().setOrder(NoteSortOrder.findByValue(intValue()));\r
295                                 }\r
296                                 if (reader.name().equalsIgnoreCase("ReadOnly")) {\r
297                                         if (booleanValue())\r
298                                                 notebookIsReadOnly = true;\r
299                                 }\r
300                                 if (reader.name().equalsIgnoreCase("PublishingAscending")) {\r
301                                         if (booleanValue())\r
302                                                 notebook.getPublishing().setAscending(true);\r
303                                         else\r
304                                                 notebook.getPublishing().setAscending(false);\r
305                                 }               \r
306                                 if (reader.name().equalsIgnoreCase("Icon")) {\r
307                                         byte[] b = textValue().getBytes();   // data binary\r
308                                         QByteArray hexData = new QByteArray(b);\r
309                                         QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
310                                         notebookIcon = new QIcon(QPixmap.fromImage(QImage.fromData(binData)));\r
311                                 }\r
312                                 if (reader.name().equalsIgnoreCase("Stack"))\r
313                                         notebook.setStack(textValue());\r
314                         }\r
315                         reader.readNext();\r
316                         if (reader.name().equalsIgnoreCase("notebook") && reader.isEndElement())\r
317                                 atEnd = true;\r
318                 }\r
319                 return;\r
320         }\r
321 \r
322         \r
323         \r
324         private void processTagNode() {\r
325                 tag = new Tag();\r
326                 tagIsDirty = false;\r
327                 boolean atEnd = false;\r
328                 while(!atEnd) {\r
329                         if (reader.isStartElement()) {                  \r
330                                 if (reader.name().equalsIgnoreCase("Guid")) \r
331                                         tag.setGuid(textValue());\r
332                                 if (reader.name().equalsIgnoreCase("Name")) \r
333                                         tag.setName(textValue());\r
334                                 if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
335                                         tag.setUpdateSequenceNum(intValue());\r
336                                 if (reader.name().equalsIgnoreCase("ParentGuid")) \r
337                                         tag.setParentGuid(textValue());\r
338                                 if (reader.name().equalsIgnoreCase("Dirty")) {\r
339                                         if (booleanValue())\r
340                                                 tagIsDirty = true;\r
341                                 }\r
342                         }\r
343                         reader.readNext();\r
344                         if (reader.name().equalsIgnoreCase("tag") && reader.isEndElement())\r
345                                 atEnd = true;\r
346                 }\r
347                 return;\r
348         }\r
349         \r
350         \r
351         \r
352         \r
353         private String textValue() {\r
354                 return reader.readElementText();\r
355         }\r
356         private int intValue() {\r
357                 return new Integer(textValue());\r
358         }\r
359         private long longValue() {\r
360                 return new Long(textValue());\r
361         }\r
362         private long datetimeValue() {\r
363                 Date d;\r
364                 String time = textValue();\r
365                 String year = time.substring(0,4);\r
366                 String month = time.substring(4,6);\r
367                 String day = time.substring(6,8);\r
368                 String hour = time.substring(9,11);\r
369                 String minute = time.substring(11,13);\r
370                 String second = time.substring(13,15);\r
371                 DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
372                 try {\r
373                         d = dfm.parse(year +"-" +month +"-" +day +" " +hour +":" +minute +":" +second);\r
374                         return d.getTime();\r
375                 } catch (ParseException e) {\r
376                         // TODO Auto-generated catch block\r
377                         e.printStackTrace();\r
378                 }\r
379                 return 0;\r
380         }\r
381 \r
382         private boolean booleanValue() {\r
383                 String value = textValue();\r
384                 if (value.equalsIgnoreCase("true"))\r
385                         return true;\r
386                 else\r
387                         return false;\r
388         }\r
389         private short shortValue() {\r
390                 return new Short(textValue());\r
391         }\r
392         \r
393         public void setNotebookGuid(String g) {\r
394                 notebookGuid = g;\r
395         }\r
396         \r
397         public String getErrorMessage() {\r
398                 return errorMessage;\r
399         }\r
400 }\r