OSDN Git Service

Add very basic support for importing Evernote export files.
authorRandy Baumgarte <randy@fbn.cx>
Sun, 11 Sep 2011 13:35:44 +0000 (09:35 -0400)
committerRandy Baumgarte <randy@fbn.cx>
Sun, 11 Sep 2011 13:35:44 +0000 (09:35 -0400)
src/cx/fbn/nevernote/NeverNote.java
src/cx/fbn/nevernote/xml/ImportEnex.java [new file with mode: 0644]

index 204e74b..7d9aa53 100644 (file)
@@ -193,6 +193,7 @@ import cx.fbn.nevernote.utilities.ListManager;
 import cx.fbn.nevernote.utilities.SyncTimes;
 import cx.fbn.nevernote.xml.ExportData;
 import cx.fbn.nevernote.xml.ImportData;
+import cx.fbn.nevernote.xml.ImportEnex;
 import cx.fbn.nevernote.xml.NoteFormatter;
 
 
@@ -5849,7 +5850,7 @@ public class NeverNote extends QMainWindow{
                fd.setFileMode(FileMode.ExistingFile);
                fd.setConfirmOverwrite(true);
                fd.setWindowTitle(tr("Import Notes"));
-               fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
+               fd.setFilter(tr("NixNote Export (*.nnex);;Evernote Export (*.enex);;All Files (*.*)"));
                fd.setAcceptMode(AcceptMode.AcceptOpen);
                if (saveLastPath == null || saveLastPath.equals(""))
                        fd.setDirectory(System.getProperty("user.home"));
@@ -5867,24 +5868,41 @@ public class NeverNote extends QMainWindow{
                if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
                        selectedNoteGUIDs.add(currentNoteGuid);
                
-       ImportData noteReader = new ImportData(conn, false);
        String fileName = fd.selectedFiles().get(0);
 //     saveLastPath.substring(0,fileName.lastIndexOf("/"));
 
-       if (!fileName.endsWith(".nnex"))
-               fileName = fileName +".nnex";
-       if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
-               noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
-       else
-               noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
+       if (fileName.endsWith(".nnex")) {
+               ImportData noteReader = new ImportData(conn, false);
+               if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
+                       noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
+               else
+                       noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
   
-       noteReader.importData(fileName);
+               noteReader.importData(fileName);
        
-       if (noteReader.lastError != 0) {
-               setMessage(noteReader.getErrorMessage());
-               logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
-               waitCursor(false);
-               return;
+               if (noteReader.lastError != 0) {
+                       setMessage(noteReader.getErrorMessage());
+                       logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
+                       waitCursor(false);
+                       return;
+               }
+       } else {
+               if (fileName.endsWith(".enex")) {
+               ImportEnex noteReader = new ImportEnex(conn, false);
+                       if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
+                               noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
+                       else
+                               noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
+  
+                       noteReader.importData(fileName);
+       
+                       if (noteReader.lastError != 0) {
+                               setMessage(noteReader.getErrorMessage());
+                               logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
+                               waitCursor(false);
+                               return;
+                       }
+               }
        }
        
        listManager.loadNoteTitleColors();
diff --git a/src/cx/fbn/nevernote/xml/ImportEnex.java b/src/cx/fbn/nevernote/xml/ImportEnex.java
new file mode 100644 (file)
index 0000000..3a9627d
--- /dev/null
@@ -0,0 +1,400 @@
+/*\r
+ * This file is part of NixNote \r
+ * Copyright 2011 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.text.DateFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.NoteAttributes;\r
+import com.evernote.edam.type.NoteSortOrder;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Publishing;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.ResourceAttributes;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QUuid;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QPixmap;\r
+import com.trolltech.qt.xml.QXmlStreamReader;\r
+\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class ImportEnex {\r
+\r
+       public int                                                      lastError;\r
+       private String                                          errorMessage;\r
+       private String                                          fileName;\r
+       DatabaseConnection                                      conn;\r
+       QXmlStreamReader                                        reader;\r
+       private Note                                            note;\r
+       private Notebook                                        notebook;\r
+       private boolean                                         notebookIsDirty;\r
+       private boolean                                         notebookIsLocal;\r
+       private boolean                                         notebookIsReadOnly;\r
+       private QIcon                                           notebookIcon;\r
+       private Tag                                                     tag;\r
+       private boolean                                         tagIsDirty;\r
+       public int                                                      highUpdateSequenceNumber;\r
+       public long                                                     lastSequenceDate;\r
+       private final ApplicationLogger         logger;\r
+       private final boolean                           backup;\r
+       private String                                          notebookGuid;\r
+       public final boolean                            importTags = false;\r
+       public final boolean                            importNotebooks = false;\r
+       private String newGuid;\r
+       \r
+       public ImportEnex(DatabaseConnection c, boolean full) {\r
+               logger = new ApplicationLogger("import.log");\r
+               backup = full;\r
+               conn = c;\r
+       }\r
+       \r
+       public void importData(String f) {\r
+               fileName = f;\r
+               errorMessage = "";\r
+                               \r
+               lastError = 0;\r
+               errorMessage = "";\r
+               QFile xmlFile = new QFile(fileName);\r
+               if (!xmlFile.open(QIODevice.OpenModeFlag.ReadOnly)) {\r
+                       lastError = 16;\r
+                       errorMessage = "Cannot open file.";\r
+               }\r
+                       \r
+               reader = new QXmlStreamReader(xmlFile); \r
+               while (!reader.atEnd()) {\r
+                       reader.readNext();\r
+                       if (reader.hasError()) {\r
+                               errorMessage = reader.errorString();\r
+                               logger.log(logger.LOW, "************************* ERROR READING FILE " +reader.errorString());\r
+                               lastError = 16;\r
+                               return;\r
+                       }\r
+                       if (reader.name().equalsIgnoreCase("note") && reader.isStartElement()) {\r
+                               processNoteNode();\r
+                               note.setUpdateSequenceNum(0);\r
+                               if (notebookGuid != null) \r
+                                       note.setNotebookGuid(notebookGuid);\r
+                               for (int i=0; i<note.getResourcesSize(); i++) {\r
+                                       note.getResources().get(i).setUpdateSequenceNum(0);\r
+                               }\r
+                               note.setActive(true);\r
+                               conn.getNoteTable().addNote(note, true);\r
+                       }\r
+                       if (reader.name().equalsIgnoreCase("notebook") && reader.isStartElement() && (backup || importNotebooks)) {\r
+                               processNotebookNode();\r
+                       String existingGuid = conn.getNotebookTable().findNotebookByName(notebook.getName());\r
+                       if (existingGuid == null) {\r
+                               conn.getNotebookTable().addNotebook(notebook, notebookIsDirty, notebookIsLocal);\r
+                       } else {\r
+                               conn.getNotebookTable().updateNotebookGuid(existingGuid, notebook.getGuid());\r
+                               conn.getNotebookTable().updateNotebook(notebook, notebookIsDirty);\r
+                       }\r
+                       conn.getNotebookTable().setIcon(notebook.getGuid(), notebookIcon, "PNG");\r
+                       conn.getNotebookTable().setReadOnly(notebook.getGuid(), notebookIsReadOnly);\r
+                       }\r
+                       if (reader.name().equalsIgnoreCase("tag") && reader.isStartElement() && (backup || importTags)) {\r
+                               processTagNode();\r
+                               String testGuid = conn.getTagTable().findTagByName(tag.getName());\r
+                       if (testGuid == null)\r
+                               conn.getTagTable().addTag(tag, tagIsDirty);\r
+                       else {\r
+                               conn.getTagTable().updateTagGuid(testGuid, tag.getGuid());\r
+                               conn.getTagTable().updateTag(tag,tagIsDirty);\r
+                       }\r
+                       }\r
+               }\r
+               xmlFile.close();\r
+       }\r
+       \r
+       \r
+       private void processNoteNode() {\r
+               note = new Note();\r
+               newGuid = QUuid.createUuid().toString().replace("{", "").replace("}", "");\r
+               note.setGuid(newGuid);\r
+               note.setResources(new ArrayList<Resource>());\r
+               \r
+               boolean atEnd = false;\r
+               while(!atEnd) {\r
+                       if (reader.name().equalsIgnoreCase("title")) \r
+                               note.setTitle(textValue());\r
+                       if (reader.name().equalsIgnoreCase("Created")) \r
+                               note.setCreated(datetimeValue());\r
+                       if (reader.name().equalsIgnoreCase("Content")) \r
+                               note.setContent(textValue());\r
+                       if (reader.name().equalsIgnoreCase("note-attributes")) \r
+                               note.setAttributes(processNoteAttributes());\r
+                       if (reader.name().equalsIgnoreCase("resource")) {\r
+                               note.getResources().add(processResource());\r
+                       }\r
+                       reader.readNext();\r
+                       if (reader.name().equalsIgnoreCase("note") && reader.isEndElement())\r
+                               atEnd = true;\r
+               }\r
+               return;\r
+       }       \r
+       private Resource processResource() {\r
+               Resource resource = new Resource();\r
+               boolean atEnd = false;\r
+               while(!atEnd) {\r
+                       if (reader.isStartElement()) {\r
+                               String newResGuid = QUuid.createUuid().toString().replace("{", "").replace("}", "");\r
+                               resource.setGuid(newResGuid);\r
+                               resource.setNoteGuid(this.newGuid);\r
+                       }\r
+                       if (reader.name().equalsIgnoreCase("mime")) \r
+                               resource.setMime(textValue());\r
+                       if (reader.name().equalsIgnoreCase("height")) \r
+                               resource.setHeight(shortValue());\r
+                       if (reader.name().equalsIgnoreCase("width")) \r
+                               resource.setWidth(shortValue());\r
+                       if (reader.name().equalsIgnoreCase("data")) \r
+                               resource.setData(processData("data"));\r
+//                             if (reader.name().equalsIgnoreCase("recognition")) \r
+//                                     resource.setRecognition(processData("NoteResourceAttribute"));\r
+                       reader.readNext();\r
+                       if (reader.name().equalsIgnoreCase("resource") && reader.isEndElement())\r
+                               atEnd = true;\r
+               }\r
+               resource.setAttributes(new ResourceAttributes());\r
+               resource.getAttributes().setSourceURL("");\r
+               conn.getNoteTable().noteResourceTable.saveNoteResource(resource, true);\r
+\r
+               \r
+               return resource;\r
+       }\r
+       \r
+       private Data processData(String nodeName) {\r
+               Data data = new Data();\r
+               boolean atEnd = false;\r
+               while(!atEnd) {\r
+                       if (reader.isStartElement()) {\r
+                               byte[] b = textValue().getBytes();   // data binary\r
+                               if (b.length > 0) {\r
+                                       QByteArray hexData = new QByteArray(b);\r
+                                       QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
+                                       data.setBody(binData.toByteArray());\r
+                                       MessageDigest md;\r
+                                       try {\r
+                                               md = MessageDigest.getInstance("MD5");\r
+                                               md.update(b);\r
+                                               data.setBodyHash(md.digest());\r
+                                       } catch (NoSuchAlgorithmException e) {\r
+                                               // TODO Auto-generated catch block\r
+                                               e.printStackTrace();\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (reader.name().equalsIgnoreCase(nodeName) && reader.isEndElement())\r
+                               atEnd = true;\r
+                       else \r
+                               reader.readNext();\r
+               }\r
+               return data;\r
+       }\r
+\r
+       \r
+       private NoteAttributes processNoteAttributes() {\r
+       NoteAttributes attributes = new NoteAttributes();\r
+       \r
+       boolean atEnd = false;\r
+       while(!atEnd) {\r
+               if (reader.isStartElement()) {\r
+                       if (reader.name().equalsIgnoreCase("source-url")) \r
+                               attributes.setSourceURL(textValue());\r
+                       if (reader.name().equalsIgnoreCase("source")) \r
+                               attributes.setSource(textValue());\r
+               }\r
+               reader.readNext();\r
+               if (reader.name().equalsIgnoreCase("note-attributes") && reader.isEndElement())\r
+                       atEnd = true;\r
+       }\r
+       \r
+       return attributes;\r
+}\r
+\r
+               \r
+       \r
+\r
+       \r
+\r
+       \r
+       private void processNotebookNode() {\r
+               notebook = new Notebook();\r
+               Publishing p = new Publishing();\r
+               notebook.setPublishing(p);\r
+               notebookIsDirty = false;\r
+               notebookIsLocal = false;\r
+               notebookIsReadOnly = false;\r
+               notebookIcon = null;\r
+               boolean atEnd = false;\r
+               while(!atEnd) {\r
+                       if (reader.isStartElement()) {\r
+                               if (reader.name().equalsIgnoreCase("Guid")) \r
+                                       notebook.setGuid(textValue());\r
+                               if (reader.name().equalsIgnoreCase("Name")) \r
+                                       notebook.setName(textValue());\r
+                               if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+                                       notebook.setUpdateSequenceNum(intValue());\r
+                               if (reader.name().equalsIgnoreCase("ServiceCreated")) \r
+                                       notebook.setServiceCreated(longValue());\r
+                               if (reader.name().equalsIgnoreCase("ServiceUpdated")) \r
+                                       notebook.setServiceUpdated(longValue());\r
+                               if (reader.name().equalsIgnoreCase("DefaultNotebook")) {\r
+                                       notebook.setDefaultNotebook(booleanValue());\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("Dirty")) {\r
+                                       if (booleanValue())\r
+                                               notebookIsDirty = true;\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("LocalNotebook")) {\r
+                                       if (booleanValue())\r
+                                               notebookIsLocal = true;\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("ReadOnly")) {\r
+                                       if (booleanValue())\r
+                                               notebookIsReadOnly = true;\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("PublishingPublicDescription")) {\r
+                                       notebook.getPublishing().setPublicDescription(textValue());\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("PublishingUri")) {\r
+                                       notebook.getPublishing().setUri(textValue());\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("PublishingOrder")) {\r
+                                       notebook.getPublishing().setOrder(NoteSortOrder.findByValue(intValue()));\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("ReadOnly")) {\r
+                                       if (booleanValue())\r
+                                               notebookIsReadOnly = true;\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("PublishingAscending")) {\r
+                                       if (booleanValue())\r
+                                               notebook.getPublishing().setAscending(true);\r
+                                       else\r
+                                               notebook.getPublishing().setAscending(false);\r
+                               }               \r
+                               if (reader.name().equalsIgnoreCase("Icon")) {\r
+                                       byte[] b = textValue().getBytes();   // data binary\r
+                                       QByteArray hexData = new QByteArray(b);\r
+                                       QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
+                                       notebookIcon = new QIcon(QPixmap.fromImage(QImage.fromData(binData)));\r
+                               }\r
+                               if (reader.name().equalsIgnoreCase("Stack"))\r
+                                       notebook.setStack(textValue());\r
+                       }\r
+                       reader.readNext();\r
+                       if (reader.name().equalsIgnoreCase("notebook") && reader.isEndElement())\r
+                               atEnd = true;\r
+               }\r
+               return;\r
+       }\r
+\r
+       \r
+       \r
+       private void processTagNode() {\r
+               tag = new Tag();\r
+               tagIsDirty = false;\r
+               boolean atEnd = false;\r
+               while(!atEnd) {\r
+                       if (reader.isStartElement()) {                  \r
+                               if (reader.name().equalsIgnoreCase("Guid")) \r
+                                       tag.setGuid(textValue());\r
+                               if (reader.name().equalsIgnoreCase("Name")) \r
+                                       tag.setName(textValue());\r
+                               if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+                                       tag.setUpdateSequenceNum(intValue());\r
+                               if (reader.name().equalsIgnoreCase("ParentGuid")) \r
+                                       tag.setParentGuid(textValue());\r
+                               if (reader.name().equalsIgnoreCase("Dirty")) {\r
+                                       if (booleanValue())\r
+                                               tagIsDirty = true;\r
+                               }\r
+                       }\r
+                       reader.readNext();\r
+                       if (reader.name().equalsIgnoreCase("tag") && reader.isEndElement())\r
+                               atEnd = true;\r
+               }\r
+               return;\r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       private String textValue() {\r
+               return reader.readElementText();\r
+       }\r
+       private int intValue() {\r
+               return new Integer(textValue());\r
+       }\r
+       private long longValue() {\r
+               return new Long(textValue());\r
+       }\r
+       private long datetimeValue() {\r
+               Date d;\r
+               String time = textValue();\r
+               String year = time.substring(0,4);\r
+               String month = time.substring(4,6);\r
+               String day = time.substring(6,8);\r
+               String hour = time.substring(9,11);\r
+               String minute = time.substring(11,13);\r
+               String second = time.substring(13,15);\r
+               DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
+               try {\r
+                       d = dfm.parse(year +"-" +month +"-" +day +" " +hour +":" +minute +":" +second);\r
+                       return d.getTime();\r
+               } catch (ParseException e) {\r
+                       // TODO Auto-generated catch block\r
+                       e.printStackTrace();\r
+               }\r
+               return 0;\r
+       }\r
+\r
+       private boolean booleanValue() {\r
+               String value = textValue();\r
+               if (value.equalsIgnoreCase("true"))\r
+                       return true;\r
+               else\r
+                       return false;\r
+       }\r
+       private short shortValue() {\r
+               return new Short(textValue());\r
+       }\r
+       \r
+       public void setNotebookGuid(String g) {\r
+               notebookGuid = g;\r
+       }\r
+       \r
+       public String getErrorMessage() {\r
+               return errorMessage;\r
+       }\r
+}\r