2 * This file is part of NeverNote
\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.Note;
\r
28 import com.evernote.edam.type.NoteAttributes;
\r
29 import com.evernote.edam.type.Notebook;
\r
30 import com.evernote.edam.type.Resource;
\r
31 import com.evernote.edam.type.SavedSearch;
\r
32 import com.evernote.edam.type.Tag;
\r
33 import com.trolltech.qt.core.QByteArray;
\r
34 import com.trolltech.qt.core.QFile;
\r
35 import com.trolltech.qt.core.QIODevice;
\r
36 import com.trolltech.qt.xml.QXmlStreamWriter;
\r
38 import cx.fbn.nevernote.Global;
\r
39 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
40 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
41 import cx.fbn.nevernote.utilities.Pair;
\r
43 public class ExportData {
\r
45 private List<Notebook> notebooks;
\r
46 private final HashMap<String,String> localNotebooks;
\r
47 private final HashMap<String,String> dirtyNotebooks;
\r
48 private final ApplicationLogger logger;
\r
50 private List<SavedSearch> searches;
\r
51 private final HashMap<String,String> dirtySearches;
\r
53 private List<Tag> tags;
\r
54 private final HashMap<String,String> dirtyTags;
\r
56 private final HashMap<String, String> exportableNotebooks;
\r
57 private final HashMap<String, String> exportableTags;
\r
58 private List<Note> notes;
\r
59 private final HashMap<String,String> dirtyNotes;
\r
60 private HashMap<String,Integer> titleColors;
\r
61 private final boolean fullBackup;
\r
62 private final DatabaseConnection conn;
\r
63 private QXmlStreamWriter writer;
\r
65 private String errorMessage;
\r
66 public int lastError;
\r
68 public ExportData(DatabaseConnection conn2, boolean full) {
\r
70 logger = new ApplicationLogger("export.log");
\r
71 notebooks = new ArrayList<Notebook>();
\r
72 tags = new ArrayList<Tag>();
\r
73 notes = new ArrayList<Note>();
\r
74 dirtyNotebooks = new HashMap<String,String>();
\r
75 localNotebooks = new HashMap<String,String>();
\r
76 dirtyTags = new HashMap<String,String>();
\r
79 dirtyNotes = new HashMap<String, String>();
\r
80 dirtySearches = new HashMap<String, String>();
\r
81 searches = new ArrayList<SavedSearch>();
\r
83 exportableNotebooks = new HashMap<String, String>();
\r
84 exportableTags = new HashMap<String, String>();
\r
88 public ExportData(DatabaseConnection conn2, boolean full, List<String> guids) {
\r
90 logger = new ApplicationLogger("export.log");
\r
91 notebooks = new ArrayList<Notebook>();
\r
92 tags = new ArrayList<Tag>();
\r
93 notes = new ArrayList<Note>();
\r
94 for (int i=0; i<guids.size(); i++) {
\r
95 notes.add(conn.getNoteTable().getNote(guids.get(i), true, true, true, true, true));
\r
97 dirtyNotebooks = new HashMap<String,String>();
\r
98 localNotebooks = new HashMap<String,String>();
\r
99 dirtyTags = new HashMap<String,String>();
\r
102 dirtyNotes = new HashMap<String, String>();
\r
103 dirtySearches = new HashMap<String, String>();
\r
104 searches = new ArrayList<SavedSearch>();
\r
106 exportableNotebooks = new HashMap<String, String>();
\r
107 exportableTags = new HashMap<String, String>();
\r
111 public void exportData(String filename) {
\r
113 notebooks = conn.getNotebookTable().getAll();
\r
114 tags = conn.getTagTable().getAll();
\r
115 List<Notebook> books = conn.getNotebookTable().getAllLocal();
\r
116 for (int i=0; i<books.size(); i++) {
\r
117 localNotebooks.put(books.get(i).getGuid(), "");
\r
120 books = conn.getNotebookTable().getDirty();
\r
121 for (int i=0; i<books.size(); i++) {
\r
122 dirtyNotebooks.put(books.get(i).getGuid(), "");
\r
125 List<Tag> d= conn.getTagTable().getDirty();
\r
126 for (int i=0; i<d.size(); i++) {
\r
127 dirtyTags.put(d.get(i).getGuid(), "");
\r
131 notes = conn.getNoteTable().getAllNotes();
\r
133 List<Note> dn = conn.getNoteTable().getDirty();
\r
134 for (int i=0; i<dn.size(); i++) {
\r
135 dirtyNotes.put(dn.get(i).getGuid(), "");
\r
138 List<Pair<String,Integer>> tColors = conn.getNoteTable().getNoteTitleColors();
\r
139 titleColors = new HashMap<String,Integer>();
\r
140 for (int i=0; i<tColors.size(); i++) {
\r
141 titleColors.put(tColors.get(i).getFirst(), tColors.get(i).getSecond());
\r
144 searches = conn.getSavedSearchTable().getAll();
\r
146 List<SavedSearch> ds = conn.getSavedSearchTable().getDirty();
\r
147 for (int i=0; i<ds.size(); i++) {
\r
148 dirtySearches.put(ds.get(i).getGuid(), "");
\r
155 QFile xmlFile = new QFile(filename);
\r
156 if (!xmlFile.open(QIODevice.OpenModeFlag.WriteOnly, QIODevice.OpenModeFlag.Truncate)) {
\r
158 errorMessage = "Cannot open file.";
\r
161 writer = new QXmlStreamWriter(xmlFile);
\r
162 writer.setAutoFormatting(true);
\r
163 writer.setCodec("UTF-8");
\r
164 writer.writeStartDocument();
\r
165 writer.writeDTD("<!DOCTYPE NeverNote-Export>");
\r
166 writer.writeStartElement("nevernote-export");
\r
167 writer.writeAttribute("version", "0.86");
\r
169 writer.writeAttribute("exportType", "backup");
\r
171 writer.writeAttribute("exportType", "export");
\r
172 writer.writeAttribute("application", "NeverNote");
\r
173 writer.writeAttribute("applicationVersion", Global.version);
\r
175 writer.writeStartElement("Synchronization");
\r
176 long sequenceDate = conn.getSyncTable().getLastSequenceDate();
\r
177 int number = conn.getSyncTable().getUpdateSequenceNumber();
\r
178 createTextNode("UpdateSequenceNumber", new Long(number).toString());
\r
179 createTextNode("LastSequenceDate", new Long(sequenceDate).toString());
\r
180 writer.writeEndElement();
\r
183 for (int i=0; i<notes.size(); i++) {
\r
184 String guid = notes.get(i).getGuid();
\r
185 logger.log(logger.EXTREME, "Getting note " +guid +" : " +notes.get(i).getTitle());
\r
186 Note note = conn.getNoteTable().getNote(guid, true, true, true, true, true);
\r
187 logger.log(logger.EXTREME, "Writing note XML");
\r
193 writeSavedSearches();
\r
196 writer.writeEndElement();
\r
197 writer.writeEndDocument();
\r
210 private void writeSavedSearches() {
\r
213 for (int i=0; i<searches.size(); i++) {
\r
214 writer.writeStartElement("SavedSearch");
\r
215 createTextNode("Guid", searches.get(i).getGuid());
\r
216 createTextNode("Name", searches.get(i).getName());
\r
217 createTextNode("Query", searches.get(i).getQuery());
\r
218 createTextNode("Format", new Integer(searches.get(i).getFormat().getValue()).toString());
\r
219 if (dirtySearches.containsKey(searches.get(i).getGuid()))
\r
220 createTextNode("Dirty","true");
\r
222 createTextNode("Dirty","false");
\r
223 writer.writeEndElement();
\r
229 private void writeNote(Note note) {
\r
231 writer.writeStartElement("Note");
\r
232 createTextNode("Guid", note.getGuid());
\r
233 createTextNode("UpdateSequenceNumber", new Long(note.getUpdateSequenceNum()).toString());
\r
234 createTextNode("Title", note.getTitle());
\r
235 createTextNode("Created", new Long(note.getCreated()).toString());
\r
236 createTextNode("Updated", new Long(note.getUpdated()).toString());
\r
237 createTextNode("Deleted", new Long(note.getDeleted()).toString());
\r
238 createTextNode("Active", new Boolean(note.isActive()).toString());
\r
239 createTextNode("NotebookGuid", note.getNotebookGuid());
\r
240 if (dirtyNotes.containsKey(note.getGuid()))
\r
241 createTextNode("Dirty", "true");
\r
243 createTextNode("Dirty", "false");
\r
244 if (titleColors.containsKey(note.getGuid()))
\r
245 createTextNode("TitleColor", new String(titleColors.get(note.getGuid()).toString()));
\r
246 exportableNotebooks.put(note.getNotebookGuid(), "");
\r
248 if (note.getTagGuidsSize() > 0) {
\r
249 writer.writeStartElement("NoteTags");
\r
250 for (int i=0; i<note.getTagGuidsSize(); i++) {
\r
251 createTextNode("Guid", note.getTagGuids().get(i));
\r
252 exportableTags.put(note.getTagGuids().get(i), "");
\r
254 writer.writeEndElement();
\r
257 NoteAttributes noteAttributes = note.getAttributes();
\r
258 if (noteAttributes != null) {
\r
259 writer.writeStartElement("NoteAttributes");
\r
260 createTextNode("Author", noteAttributes.getAuthor());
\r
261 createTextNode("Source", noteAttributes.getSource());
\r
262 createTextNode("SourceApplication", noteAttributes.getSourceApplication());
\r
263 createTextNode("SourceURL", noteAttributes.getSourceURL());
\r
264 createTextNode("Altitude", new Double(noteAttributes.getAltitude()).toString());
\r
265 createTextNode("Longitude", new Double(noteAttributes.getLongitude()).toString());
\r
266 createTextNode("Latitude", new Double(noteAttributes.getLatitude()).toString());
\r
267 createTextNode("SubjectDate", new Long(noteAttributes.getSubjectDate()).toString());
\r
268 writer.writeEndElement();
\r
271 // writeResources(conn.getNoteTable().noteResourceTable.getNoteResources(note.getGuid(), true));
\r
272 writeResources(note.getResources());
\r
274 logger.log(logger.EXTREME, "Writing content");
\r
275 writer.writeStartElement("Content");
\r
276 writer.writeCDATA(conn.getNoteTable().getNoteContentBinary(note.getGuid()));
\r
277 writer.writeEndElement();
\r
278 writer.writeEndElement();
\r
282 private void writeResources(List<Resource> resourceTable) {
\r
284 if (resourceTable.size() == 0)
\r
286 for (int i=0; i<resourceTable.size(); i++) {
\r
287 resource = resourceTable.get(i);
\r
288 writer.writeStartElement("NoteResource");
\r
289 createTextNode("Guid", resource.getGuid());
\r
290 createTextNode("NoteGuid", resource.getNoteGuid());
\r
291 createTextNode("UpdateSequenceNumber", new Integer(resource.getUpdateSequenceNum()).toString());
\r
292 createTextNode("Mime", resource.getMime());
\r
293 createTextNode("Duration", new Integer(resource.getDuration()).toString());
\r
294 createTextNode("Height", new Integer(resource.getHeight()).toString());
\r
295 createTextNode("Width", new Integer(resource.getWidth()).toString());
\r
296 logger.log(logger.EXTREME, "Checking for data node");
\r
297 if (resource.getData() != null)
\r
298 writeDataNode("Data", resource.getData());
\r
299 logger.log(logger.EXTREME, "Checking for alternate data node");
\r
300 if (resource.getAlternateData() != null)
\r
301 writeDataNode("AlternateData", resource.getAlternateData());
\r
302 logger.log(logger.EXTREME, "Checking for recognition");
\r
303 if (resource.getRecognition() != null)
\r
304 writeRecognitionNode("Recognition", resource.getRecognition());
\r
305 if (resource.isActive())
\r
306 createTextNode("Active", "true");
\r
308 createTextNode("Active", "false");
\r
309 logger.log(logger.EXTREME, "Checking resource attributes");
\r
310 if (resource.getAttributes() != null) {
\r
311 writer.writeStartElement("NoteResourceAttribute");
\r
312 createTextNode("CameraMake", resource.getAttributes().getCameraMake());
\r
313 createTextNode("CameraModel", resource.getAttributes().getCameraModel());
\r
314 createTextNode("FileName", resource.getAttributes().getFileName());
\r
315 createTextNode("RecoType", resource.getAttributes().getRecoType());
\r
316 createTextNode("SourceURL", resource.getAttributes().getSourceURL());
\r
317 createTextNode("Altitude", new Double(resource.getAttributes().getAltitude()).toString());
\r
318 createTextNode("Longitude", new Double(resource.getAttributes().getLongitude()).toString());
\r
319 createTextNode("Latitude", new Double(resource.getAttributes().getLatitude()).toString());
\r
320 createTextNode("Timestamp", new Long(resource.getAttributes().getTimestamp()).toString());
\r
321 if (resource.getAttributes().isAttachment())
\r
322 createTextNode("Attachment", "true");
\r
324 createTextNode("Attachment", "false");
\r
325 if (resource.getAttributes().isClientWillIndex())
\r
326 createTextNode("ClientWillIndex", "true");
\r
328 createTextNode("ClientWillIndex", "false");
\r
329 writer.writeEndElement();
\r
331 writer.writeEndElement();
\r
333 logger.log(logger.EXTREME, "Ending resource node");
\r
334 // writer.writeEndElement();
\r
338 private void writeDataNode(String name, Data data) {
\r
339 writer.writeStartElement(name);
\r
340 createTextNode("Size", new Integer(data.getSize()).toString());
\r
341 if (data.getBody() != null && data.getBody().length > 0)
\r
342 createBinaryNode("Body", new QByteArray(data.getBody()).toHex().toString());
\r
344 createBinaryNode("Body", "");
\r
345 if (data.getBodyHash() != null && data.getBodyHash().length > 0)
\r
346 createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());
\r
348 createTextNode("BodyHash", "");
\r
349 writer.writeEndElement();
\r
355 private void writeRecognitionNode(String name, Data data) {
\r
356 writer.writeStartElement(name);
\r
357 createTextNode("Size", new Integer(data.getSize()).toString());
\r
358 if (data.getBody() != null && data.getBody().length > 0) {
\r
359 writer.writeStartElement("Body");
\r
360 writer.writeCDATA(new QByteArray(data.getBody()).toString());
\r
361 // writer.writeCDATA(new QByteArray(data.getBody()).toHex().toString());
\r
362 writer.writeEndElement();
\r
364 createBinaryNode("Body", "");
\r
366 if (data.getBodyHash() != null && data.getBodyHash().length > 0)
\r
367 createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());
\r
369 createTextNode("BodyHash", "");
\r
370 writer.writeEndElement();
\r
374 private void writeNotebooks() {
\r
375 for (int i=0; i<notebooks.size(); i++) {
\r
376 if (exportableNotebooks.containsKey(notebooks.get(i).getGuid()) || fullBackup) {
\r
377 writer.writeStartElement("Notebook");
\r
378 createTextNode("Guid", notebooks.get(i).getGuid());
\r
379 createTextNode("Name", notebooks.get(i).getName());
\r
380 createTextNode("UpdateSequenceNumber", new Long(notebooks.get(i).getUpdateSequenceNum()).toString());
\r
381 if (notebooks.get(i).isDefaultNotebook())
\r
382 createTextNode("DefaultNotebook", "true");
\r
384 createTextNode("DefaultNotebook", "false");
\r
385 createTextNode("ServiceCreated", new Long(notebooks.get(i).getServiceCreated()).toString());
\r
386 createTextNode("ServiceUpdated", new Long(notebooks.get(i).getServiceUpdated()).toString());
\r
387 if (localNotebooks.containsKey(notebooks.get(i).getGuid()))
\r
388 createTextNode("Local","true");
\r
390 createTextNode("Local","false");
\r
391 if (dirtyNotebooks.containsKey(notebooks.get(i).getGuid()))
\r
392 createTextNode("Dirty","true");
\r
394 createTextNode("Dirty","false");
\r
395 writer.writeEndElement();
\r
401 private void writeTags() {
\r
402 for (int i=0; i<tags.size(); i++) {
\r
403 if (exportableTags.containsKey(tags.get(i).getGuid()) || fullBackup) {
\r
404 writer.writeStartElement("Tag");
\r
405 createTextNode("Guid", tags.get(i).getGuid());
\r
406 createTextNode("Name", tags.get(i).getName());
\r
407 createTextNode("ParentGuid", tags.get(i).getParentGuid());
\r
408 createTextNode("UpdateSequenceNumber", new Long(tags.get(i).getUpdateSequenceNum()).toString());
\r
409 if (dirtyTags.containsKey(tags.get(i).getGuid()))
\r
410 createTextNode("Dirty","true");
\r
412 createTextNode("Dirty","false");
\r
413 writer.writeEndElement();
\r
419 private void createTextNode(String nodeName, String value) {
\r
422 writer.writeTextElement(nodeName, value);
\r
426 private void createBinaryNode(String nodeName, String value) {
\r
429 logger.log(logger.EXTREME, "Writing binary node");
\r
430 writer.writeStartElement(nodeName);
\r
432 for (; i<value.length(); i+=80)
\r
434 writer.writeCharacters("\n"+value.substring(i,i+80));
\r
436 writer.writeCharacters("\n"+value.substring(i)+"\n");
\r
437 */ writer.writeCharacters(value);
\r
438 writer.writeEndElement();
\r
443 public String getErrorMessage() {
\r
444 return errorMessage;
\r