2 * This file is part of NixNote/NeighborNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\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
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
20 package cx.fbn.nevernote.xml;
\r
22 import java.util.ArrayList;
\r
23 import java.util.HashMap;
\r
24 import java.util.List;
\r
26 import com.evernote.edam.type.Data;
\r
27 import com.evernote.edam.type.LinkedNotebook;
\r
28 import com.evernote.edam.type.Note;
\r
29 import com.evernote.edam.type.NoteAttributes;
\r
30 import com.evernote.edam.type.Notebook;
\r
31 import com.evernote.edam.type.Publishing;
\r
32 import com.evernote.edam.type.Resource;
\r
33 import com.evernote.edam.type.SavedSearch;
\r
34 import com.evernote.edam.type.SharedNotebook;
\r
35 import com.evernote.edam.type.Tag;
\r
36 import com.trolltech.qt.core.QByteArray;
\r
37 import com.trolltech.qt.core.QFile;
\r
38 import com.trolltech.qt.core.QIODevice;
\r
39 import com.trolltech.qt.xml.QXmlStreamWriter;
\r
41 import cx.fbn.nevernote.Global;
\r
42 import cx.fbn.nevernote.evernote.NoteMetadata;
\r
43 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
44 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
46 public class ExportData {
\r
48 private List<Notebook> notebooks;
\r
49 private final HashMap<String,String> localNotebooks;
\r
50 private final HashMap<String,String> dirtyNotebooks;
\r
51 private final ApplicationLogger logger;
\r
53 private List<SavedSearch> searches;
\r
54 private List<LinkedNotebook> linkedNotebooks;
\r
55 private List<SharedNotebook> sharedNotebooks;
\r
56 private final HashMap<String,String> dirtySearches;
\r
58 private List<Tag> tags;
\r
59 private final HashMap<String,String> dirtyTags;
\r
61 private final HashMap<String, String> exportableNotebooks;
\r
62 private final HashMap<String, String> exportableTags;
\r
63 private List<Note> notes;
\r
64 private final HashMap<String,String> dirtyNotes;
\r
65 private final HashMap<String,String> dirtyLinkedNotebooks;
\r
66 private final HashMap<Long,String> dirtySharedNotebooks;
\r
67 private HashMap<String, NoteMetadata> noteMeta;
\r
68 private final boolean fullBackup;
\r
69 private final DatabaseConnection conn;
\r
70 private QXmlStreamWriter writer;
\r
72 private String errorMessage;
\r
73 public int lastError;
\r
75 public ExportData(DatabaseConnection conn2, boolean full) {
\r
77 logger = new ApplicationLogger("export.log");
\r
78 notebooks = new ArrayList<Notebook>();
\r
79 tags = new ArrayList<Tag>();
\r
80 notes = new ArrayList<Note>();
\r
81 sharedNotebooks = new ArrayList<SharedNotebook>();
\r
82 linkedNotebooks = new ArrayList<LinkedNotebook>();
\r
83 dirtyNotebooks = new HashMap<String,String>();
\r
84 localNotebooks = new HashMap<String,String>();
\r
85 dirtyLinkedNotebooks = new HashMap<String,String>();
\r
86 dirtySharedNotebooks = new HashMap<Long,String>();
\r
87 dirtyTags = new HashMap<String,String>();
\r
90 dirtyNotes = new HashMap<String, String>();
\r
91 dirtySearches = new HashMap<String, String>();
\r
92 searches = new ArrayList<SavedSearch>();
\r
94 exportableNotebooks = new HashMap<String, String>();
\r
95 exportableTags = new HashMap<String, String>();
\r
99 public ExportData(DatabaseConnection conn2, boolean full, List<String> guids) {
\r
101 logger = new ApplicationLogger("export.log");
\r
102 notebooks = new ArrayList<Notebook>();
\r
103 tags = new ArrayList<Tag>();
\r
104 notes = new ArrayList<Note>();
\r
105 for (int i=0; i<guids.size(); i++) {
\r
106 notes.add(conn.getNoteTable().getNote(guids.get(i), true, true, true, true, true));
\r
108 dirtyNotebooks = new HashMap<String,String>();
\r
109 localNotebooks = new HashMap<String,String>();
\r
110 dirtyTags = new HashMap<String,String>();
\r
113 dirtyNotes = new HashMap<String, String>();
\r
114 dirtyLinkedNotebooks = new HashMap<String,String>();
\r
115 dirtySharedNotebooks = new HashMap<Long,String>();
\r
116 dirtySearches = new HashMap<String, String>();
\r
117 searches = new ArrayList<SavedSearch>();
\r
119 exportableNotebooks = new HashMap<String, String>();
\r
120 exportableTags = new HashMap<String, String>();
\r
124 public void exportData(String filename) {
\r
126 notebooks = conn.getNotebookTable().getAll();
\r
127 tags = conn.getTagTable().getAll();
\r
128 List<Notebook> books = conn.getNotebookTable().getAllLocal();
\r
129 for (int i=0; i<books.size(); i++) {
\r
130 localNotebooks.put(books.get(i).getGuid(), "");
\r
133 books = conn.getNotebookTable().getDirty();
\r
134 for (int i=0; i<books.size(); i++) {
\r
135 dirtyNotebooks.put(books.get(i).getGuid(), "");
\r
138 List<Tag> d= conn.getTagTable().getDirty();
\r
139 for (int i=0; i<d.size(); i++) {
\r
140 dirtyTags.put(d.get(i).getGuid(), "");
\r
144 notes = conn.getNoteTable().getAllNotes();
\r
146 List<Note> dn = conn.getNoteTable().getDirty();
\r
147 for (int i=0; i<dn.size(); i++) {
\r
148 dirtyNotes.put(dn.get(i).getGuid(), "");
\r
151 noteMeta = conn.getNoteTable().getNotesMetaInformation();
\r
154 searches = conn.getSavedSearchTable().getAll();
\r
156 List<SavedSearch> ds = conn.getSavedSearchTable().getDirty();
\r
157 for (int i=0; i<ds.size(); i++) {
\r
158 dirtySearches.put(ds.get(i).getGuid(), "");
\r
161 linkedNotebooks = conn.getLinkedNotebookTable().getAll();
\r
162 List<String> dln = conn.getLinkedNotebookTable().getDirtyGuids();
\r
163 for (int i=0; i<dln.size(); i++) {
\r
164 dirtyLinkedNotebooks.put(dln.get(i), "");
\r
167 sharedNotebooks = conn.getSharedNotebookTable().getAll();
\r
168 List<Long> dsn = conn.getSharedNotebookTable().getDirtyIds();
\r
169 for (int i=0; i<dsn.size(); i++) {
\r
170 dirtySharedNotebooks.put(dsn.get(i), "");
\r
175 QFile xmlFile = new QFile(filename);
\r
176 if (!xmlFile.open(QIODevice.OpenModeFlag.WriteOnly, QIODevice.OpenModeFlag.Truncate)) {
\r
178 errorMessage = "Cannot open file.";
\r
181 writer = new QXmlStreamWriter(xmlFile);
\r
182 writer.setAutoFormatting(true);
\r
183 writer.setCodec("UTF-8");
\r
184 writer.writeStartDocument();
\r
185 writer.writeDTD("<!DOCTYPE NeverNote-Export>");
\r
186 writer.writeStartElement("nevernote-export");
\r
187 writer.writeAttribute("version", "0.95");
\r
189 writer.writeAttribute("exportType", "backup");
\r
191 writer.writeAttribute("exportType", "export");
\r
192 writer.writeAttribute("application", "NeverNote");
\r
193 writer.writeAttribute("applicationVersion", Global.version);
\r
195 writer.writeStartElement("Synchronization");
\r
196 long sequenceDate = conn.getSyncTable().getLastSequenceDate();
\r
197 int number = conn.getSyncTable().getUpdateSequenceNumber();
\r
198 createTextNode("UpdateSequenceNumber", new Long(number).toString());
\r
199 createTextNode("LastSequenceDate", new Long(sequenceDate).toString());
\r
200 writer.writeEndElement();
\r
203 for (int i=0; i<notes.size(); i++) {
\r
204 String guid = notes.get(i).getGuid();
\r
205 logger.log(logger.EXTREME, "Getting note " +guid +" : " +notes.get(i).getTitle());
\r
206 Note note = conn.getNoteTable().getNote(guid, true, true, true, true, true);
\r
207 logger.log(logger.EXTREME, "Writing note XML");
\r
213 writeSavedSearches();
\r
214 writeLinkedNotebooks();
\r
215 writeSharedNotebooks();
\r
218 writer.writeEndElement();
\r
219 writer.writeEndDocument();
\r
232 private void writeSavedSearches() {
\r
235 for (int i=0; i<searches.size(); i++) {
\r
236 writer.writeStartElement("SavedSearch");
\r
237 createTextNode("Guid", searches.get(i).getGuid());
\r
238 createTextNode("Name", searches.get(i).getName());
\r
239 createTextNode("Query", searches.get(i).getQuery());
\r
240 createTextNode("Format", new Integer(searches.get(i).getFormat().getValue()).toString());
\r
241 if (dirtySearches.containsKey(searches.get(i).getGuid()))
\r
242 createTextNode("Dirty","true");
\r
244 createTextNode("Dirty","false");
\r
245 writer.writeEndElement();
\r
250 private void writeLinkedNotebooks() {
\r
253 for (int i=0; i<linkedNotebooks.size(); i++) {
\r
254 writer.writeStartElement("LinkedNotebook");
\r
255 createTextNode("Guid", linkedNotebooks.get(i).getGuid());
\r
256 createTextNode("ShardID", linkedNotebooks.get(i).getShardId());
\r
257 createTextNode("ShareKey", linkedNotebooks.get(i).getShareKey());
\r
258 createTextNode("ShareName", linkedNotebooks.get(i).getShareName());
\r
259 createTextNode("Uri", linkedNotebooks.get(i).getUri());
\r
260 createTextNode("Username", linkedNotebooks.get(i).getUsername());
\r
261 createTextNode("UpdateSequenceNumber", new Long(linkedNotebooks.get(i).getUpdateSequenceNum()).toString());
\r
262 if (dirtyLinkedNotebooks.containsKey(linkedNotebooks.get(i).getGuid()))
\r
263 createTextNode("Dirty", "true");
\r
265 createTextNode("Dirty", "false");
\r
266 writer.writeEndElement();
\r
272 private void writeSharedNotebooks() {
\r
275 for (int i=0; i<linkedNotebooks.size(); i++) {
\r
276 writer.writeStartElement("SharedNotebook");
\r
277 createTextNode("Id", new Long(sharedNotebooks.get(i).getId()).toString());
\r
278 createTextNode("Userid", new Integer(sharedNotebooks.get(i).getUserId()).toString());
\r
279 createTextNode("Email", sharedNotebooks.get(i).getEmail());
\r
280 createTextNode("NotebookGuid", sharedNotebooks.get(i).getNotebookGuid());
\r
281 createTextNode("ShareKey", sharedNotebooks.get(i).getShareKey());
\r
282 createTextNode("Username", sharedNotebooks.get(i).getUsername());
\r
283 createTextNode("ServiceCreated", new Long(sharedNotebooks.get(i).getServiceCreated()).toString());
\r
284 if (dirtySharedNotebooks.containsKey(sharedNotebooks.get(i).getId()))
\r
285 createTextNode("Dirty", "true");
\r
287 createTextNode("Dirty", "false");
\r
288 writer.writeEndElement();
\r
294 private void writeNote(Note note) {
\r
296 writer.writeStartElement("Note");
\r
297 createTextNode("Guid", note.getGuid());
\r
298 createTextNode("UpdateSequenceNumber", new Long(note.getUpdateSequenceNum()).toString());
\r
299 createTextNode("Title", note.getTitle());
\r
300 createTextNode("Created", new Long(note.getCreated()).toString());
\r
301 createTextNode("Updated", new Long(note.getUpdated()).toString());
\r
302 createTextNode("Deleted", new Long(note.getDeleted()).toString());
\r
303 createTextNode("Active", new Boolean(note.isActive()).toString());
\r
304 createTextNode("NotebookGuid", note.getNotebookGuid());
\r
305 if (dirtyNotes.containsKey(note.getGuid()))
\r
306 createTextNode("Dirty", "true");
\r
308 createTextNode("Dirty", "false");
\r
309 if (noteMeta.containsKey(note.getGuid())) {
\r
310 Integer color = new Integer(noteMeta.get(note.getGuid()).getColor());
\r
311 createTextNode("TitleColor", color.toString());
\r
313 exportableNotebooks.put(note.getNotebookGuid(), "");
\r
315 if (note.getTagGuidsSize() > 0) {
\r
316 writer.writeStartElement("NoteTags");
\r
317 for (int i=0; i<note.getTagGuidsSize(); i++) {
\r
318 createTextNode("Guid", note.getTagGuids().get(i));
\r
319 exportableTags.put(note.getTagGuids().get(i), "");
\r
321 writer.writeEndElement();
\r
324 NoteAttributes noteAttributes = note.getAttributes();
\r
325 if (noteAttributes != null) {
\r
326 writer.writeStartElement("NoteAttributes");
\r
327 createTextNode("Author", noteAttributes.getAuthor());
\r
328 createTextNode("Source", noteAttributes.getSource());
\r
329 createTextNode("SourceApplication", noteAttributes.getSourceApplication());
\r
330 createTextNode("SourceURL", noteAttributes.getSourceURL());
\r
331 createTextNode("Altitude", new Double(noteAttributes.getAltitude()).toString());
\r
332 createTextNode("Longitude", new Double(noteAttributes.getLongitude()).toString());
\r
333 createTextNode("Latitude", new Double(noteAttributes.getLatitude()).toString());
\r
334 createTextNode("SubjectDate", new Long(noteAttributes.getSubjectDate()).toString());
\r
335 writer.writeEndElement();
\r
338 // writeResources(conn.getNoteTable().noteResourceTable.getNoteResources(note.getGuid(), true));
\r
339 writeResources(note.getResources());
\r
341 logger.log(logger.EXTREME, "Writing content");
\r
342 writer.writeStartElement("Content");
\r
343 writer.writeCDATA(conn.getNoteTable().getNoteContentNoUTFConversion(note.getGuid()));
\r
344 writer.writeEndElement();
\r
345 writer.writeEndElement();
\r
349 private void writeResources(List<Resource> resourceTable) {
\r
351 if (resourceTable.size() == 0)
\r
353 for (int i=0; i<resourceTable.size(); i++) {
\r
354 resource = resourceTable.get(i);
\r
355 writer.writeStartElement("NoteResource");
\r
356 createTextNode("Guid", resource.getGuid());
\r
357 createTextNode("NoteGuid", resource.getNoteGuid());
\r
358 createTextNode("UpdateSequenceNumber", new Integer(resource.getUpdateSequenceNum()).toString());
\r
359 createTextNode("Mime", resource.getMime());
\r
360 createTextNode("Duration", new Integer(resource.getDuration()).toString());
\r
361 createTextNode("Height", new Integer(resource.getHeight()).toString());
\r
362 createTextNode("Width", new Integer(resource.getWidth()).toString());
\r
363 logger.log(logger.EXTREME, "Checking for data node");
\r
364 if (resource.getData() != null)
\r
365 writeDataNode("Data", resource.getData());
\r
366 logger.log(logger.EXTREME, "Checking for alternate data node");
\r
367 if (resource.getAlternateData() != null)
\r
368 writeDataNode("AlternateData", resource.getAlternateData());
\r
369 logger.log(logger.EXTREME, "Checking for recognition");
\r
370 if (resource.getRecognition() != null)
\r
371 writeRecognitionNode("Recognition", resource.getRecognition());
\r
372 if (resource.isActive())
\r
373 createTextNode("Active", "true");
\r
375 createTextNode("Active", "false");
\r
376 logger.log(logger.EXTREME, "Checking resource attributes");
\r
377 if (resource.getAttributes() != null) {
\r
378 writer.writeStartElement("NoteResourceAttribute");
\r
379 createTextNode("CameraMake", resource.getAttributes().getCameraMake());
\r
380 createTextNode("CameraModel", resource.getAttributes().getCameraModel());
\r
381 createTextNode("FileName", resource.getAttributes().getFileName());
\r
382 createTextNode("RecoType", resource.getAttributes().getRecoType());
\r
383 createTextNode("SourceURL", resource.getAttributes().getSourceURL());
\r
384 createTextNode("Altitude", new Double(resource.getAttributes().getAltitude()).toString());
\r
385 createTextNode("Longitude", new Double(resource.getAttributes().getLongitude()).toString());
\r
386 createTextNode("Latitude", new Double(resource.getAttributes().getLatitude()).toString());
\r
387 createTextNode("Timestamp", new Long(resource.getAttributes().getTimestamp()).toString());
\r
388 if (resource.getAttributes().isAttachment())
\r
389 createTextNode("Attachment", "true");
\r
391 createTextNode("Attachment", "false");
\r
392 if (resource.getAttributes().isClientWillIndex())
\r
393 createTextNode("ClientWillIndex", "true");
\r
395 createTextNode("ClientWillIndex", "false");
\r
396 writer.writeEndElement();
\r
398 writer.writeEndElement();
\r
400 logger.log(logger.EXTREME, "Ending resource node");
\r
401 // writer.writeEndElement();
\r
405 private void writeDataNode(String name, Data data) {
\r
406 writer.writeStartElement(name);
\r
407 createTextNode("Size", new Integer(data.getSize()).toString());
\r
408 if (data.getBody() != null && data.getBody().length > 0)
\r
409 createBinaryNode("Body", new QByteArray(data.getBody()).toHex().toString());
\r
411 createBinaryNode("Body", "");
\r
412 if (data.getBodyHash() != null && data.getBodyHash().length > 0)
\r
413 createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());
\r
415 createTextNode("BodyHash", "");
\r
416 writer.writeEndElement();
\r
422 private void writeRecognitionNode(String name, Data data) {
\r
423 writer.writeStartElement(name);
\r
424 createTextNode("Size", new Integer(data.getSize()).toString());
\r
425 if (data.getBody() != null && data.getBody().length > 0) {
\r
426 writer.writeStartElement("Body");
\r
427 writer.writeCDATA(new QByteArray(data.getBody()).toString());
\r
428 // writer.writeCDATA(new QByteArray(data.getBody()).toHex().toString());
\r
429 writer.writeEndElement();
\r
431 createBinaryNode("Body", "");
\r
433 if (data.getBodyHash() != null && data.getBodyHash().length > 0)
\r
434 createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());
\r
436 createTextNode("BodyHash", "");
\r
437 writer.writeEndElement();
\r
441 private void writeNotebooks() {
\r
442 for (int i=0; i<notebooks.size(); i++) {
\r
443 if (exportableNotebooks.containsKey(notebooks.get(i).getGuid()) || fullBackup) {
\r
444 writer.writeStartElement("Notebook");
\r
445 createTextNode("Guid", notebooks.get(i).getGuid());
\r
446 createTextNode("Name", notebooks.get(i).getName());
\r
447 createTextNode("UpdateSequenceNumber", new Long(notebooks.get(i).getUpdateSequenceNum()).toString());
\r
448 if (notebooks.get(i).isDefaultNotebook())
\r
449 createTextNode("DefaultNotebook", "true");
\r
451 createTextNode("DefaultNotebook", "false");
\r
452 createTextNode("ServiceCreated", new Long(notebooks.get(i).getServiceCreated()).toString());
\r
453 createTextNode("ServiceUpdated", new Long(notebooks.get(i).getServiceUpdated()).toString());
\r
454 if (localNotebooks.containsKey(notebooks.get(i).getGuid()))
\r
455 createTextNode("Local","true");
\r
457 createTextNode("Local","false");
\r
458 if (dirtyNotebooks.containsKey(notebooks.get(i).getGuid()))
\r
459 createTextNode("Dirty","true");
\r
461 createTextNode("Dirty","false");
\r
462 if (conn.getNotebookTable().isReadOnly(notebooks.get(i).getGuid()))
\r
463 createTextNode("ReadOnly", "true");
\r
465 createTextNode("ReadOnly", "false");
\r
466 if (notebooks.get(i).getPublishing() != null) {
\r
467 Publishing p = notebooks.get(i).getPublishing();
\r
468 createTextNode("PublishingPublicDescription", p.getPublicDescription());
\r
469 createTextNode("PublishingUri", p.getUri());
\r
470 createTextNode("PublishingOrder", new Integer(p.getOrder().getValue()).toString());
\r
471 if (p.isAscending())
\r
472 createTextNode("PublishingAscending", "true");
\r
474 createTextNode("PublishingAscending", "false");
\r
476 QByteArray b = conn.getNotebookTable().getIconAsByteArray(notebooks.get(i).getGuid());
\r
478 createBinaryNode("Icon", b.toHex().toString());
\r
479 if (notebooks.get(i).getStack() != null && !notebooks.get(i).getStack().trim().equals(""))
\r
480 createTextNode("Stack", notebooks.get(i).getStack());
\r
481 writer.writeEndElement();
\r
487 private void writeTags() {
\r
488 for (int i=0; i<tags.size(); i++) {
\r
489 if (exportableTags.containsKey(tags.get(i).getGuid()) || fullBackup) {
\r
490 writer.writeStartElement("Tag");
\r
491 createTextNode("Guid", tags.get(i).getGuid());
\r
492 createTextNode("Name", tags.get(i).getName());
\r
493 createTextNode("ParentGuid", tags.get(i).getParentGuid());
\r
494 createTextNode("UpdateSequenceNumber", new Long(tags.get(i).getUpdateSequenceNum()).toString());
\r
495 if (dirtyTags.containsKey(tags.get(i).getGuid()))
\r
496 createTextNode("Dirty","true");
\r
498 createTextNode("Dirty","false");
\r
499 writer.writeEndElement();
\r
505 private void createTextNode(String nodeName, String value) {
\r
508 writer.writeTextElement(nodeName, value);
\r
512 private void createBinaryNode(String nodeName, String value) {
\r
515 logger.log(logger.EXTREME, "Writing binary node");
\r
516 writer.writeStartElement(nodeName);
\r
518 for (; i<value.length(); i+=80)
\r
520 writer.writeCharacters("\n"+value.substring(i,i+80));
\r
522 writer.writeCharacters("\n"+value.substring(i)+"\n");
\r
523 */ writer.writeCharacters(value);
\r
524 writer.writeEndElement();
\r
529 public String getErrorMessage() {
\r
530 return errorMessage;
\r