[gnote] Sticky Notes import addin.



commit 10449d80a28e1240353e02ecc52535786442b22c
Author: Hubert Figuiere <hub figuiere net>
Date:   Thu May 28 18:28:46 2009 -0400

    Sticky Notes import addin.
---
 NEWS                                               |    2 +
 configure.ac                                       |    1 +
 src/addins/Makefile.am                             |    1 +
 src/addins/stickynoteimport/Makefile.am            |    9 +
 .../stickynoteimport/stickynoteimportnoteaddin.cpp |  297 ++++++++++++++++++++
 .../stickynoteimport/stickynoteimportnoteaddin.hpp |   94 ++++++
 src/sharp/files.cpp                                |   21 ++-
 src/sharp/files.hpp                                |    9 +-
 8 files changed, 428 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index d560927..7807ba0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+  * Sticky Notes import addin.
+
 0.5.0 -
 
 Fixes:
diff --git a/configure.ac b/configure.ac
index 1aadc32..93f7d22 100644
--- a/configure.ac
+++ b/configure.ac
@@ -214,6 +214,7 @@ src/addins/exporttohtml/Makefile
 src/addins/fixedwidth/Makefile
 src/addins/inserttimestamp/Makefile
 src/addins/printnotes/Makefile
+src/addins/stickynoteimport/Makefile
 po/Makefile.in
 po/Makefile
 help/Makefile
diff --git a/src/addins/Makefile.am b/src/addins/Makefile.am
index 0306d8b..045849d 100644
--- a/src/addins/Makefile.am
+++ b/src/addins/Makefile.am
@@ -7,4 +7,5 @@ SUBDIRS = backlinks \
 	fixedwidth \
 	inserttimestamp \
 	printnotes \
+	stickynoteimport \
 	$(NULL)
\ No newline at end of file
diff --git a/src/addins/stickynoteimport/Makefile.am b/src/addins/stickynoteimport/Makefile.am
new file mode 100644
index 0000000..9edada0
--- /dev/null
+++ b/src/addins/stickynoteimport/Makefile.am
@@ -0,0 +1,9 @@
+
+include $(builddir)/../addins.mk
+
+addinsdir = $(ADDINSDIR)
+addins_LTLIBRARIES = stickynoteimport.la
+
+
+stickynoteimport_la_SOURCES = stickynoteimportnoteaddin.hpp stickynoteimportnoteaddin.cpp \
+	$(NULL)
diff --git a/src/addins/stickynoteimport/stickynoteimportnoteaddin.cpp b/src/addins/stickynoteimport/stickynoteimportnoteaddin.cpp
new file mode 100644
index 0000000..008a56b
--- /dev/null
+++ b/src/addins/stickynoteimport/stickynoteimportnoteaddin.cpp
@@ -0,0 +1,297 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2009 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <boost/format.hpp>
+
+#include <glibmm/i18n.h>
+#include <gtkmm/image.h>
+#include <gtkmm/stock.h>
+
+#include "stickynoteimportnoteaddin.hpp"
+#include "sharp/files.hpp"
+#include "sharp/string.hpp"
+#include "sharp/xml.hpp"
+#include "debug.hpp"
+#include "note.hpp"
+#include "notemanager.hpp"
+#include "notewindow.hpp"
+#include "preferences.hpp"
+#include "utils.hpp"
+
+namespace stickynote {
+
+  using gnote::Preferences;
+  using gnote::Note;
+
+
+StickNoteImportModule::StickNoteImportModule()
+{
+  ADD_INTERFACE_IMPL(StickNoteImportNoteAddin);
+}
+const char * StickNoteImportModule::id() const
+{
+  return "StickNoteImportAddin";
+}
+const char * StickNoteImportModule::name() const
+{
+  return _("Sticky Notes Importer");
+}
+const char * StickNoteImportModule::description() const
+{
+  return _("Import your notes from the Sticky Notes applet.");
+}
+const char * StickNoteImportModule::authors() const
+{
+  return _("Hubert Figuiere and the Tomboy Project");
+}
+const char * StickNoteImportModule::category() const
+{
+  return "Tools";
+}
+const char * StickNoteImportModule::version() const
+{
+  return "0.1";
+}
+
+static const char * STICKY_XML_REL_PATH = "/.gnome2/stickynotes_applet";
+static const char * STICKY_NOTE_QUERY = "//note";
+static const char * DEBUG_NO_STICKY_FILE = "StickyNoteImporter: Sticky Notes XML file does not exist or is invalid!";
+static const char * DEBUG_CREATE_ERROR_BASE = "StickyNoteImporter: Error while trying to create note \"%s\": %s";
+static const char * DEBUG_FIRST_RUN_DETECTED = "StickyNoteImporter: Detecting that importer has never been run...";
+//static const char * DEBUG_GCONF_SET_ERROR_BASE = "StickyNoteImporter: Error setting initial GConf first run key value: %s";
+
+
+bool StickNoteImportNoteAddin::s_static_inited = false;
+bool StickNoteImportNoteAddin::s_sticky_file_might_exist = true;
+bool StickNoteImportNoteAddin::s_sticky_file_existence_confirmed = false;
+std::string StickNoteImportNoteAddin::s_sticky_xml_path;
+
+
+void StickNoteImportNoteAddin::_init_static()
+{
+  if(!s_static_inited) {
+    s_sticky_xml_path = Glib::get_home_dir() + STICKY_XML_REL_PATH;
+    s_static_inited = true;
+  }
+}
+
+void StickNoteImportNoteAddin::initialize()
+{
+	// Don't add item to tools menu if Sticky Notes XML file does not
+  // exist. Only check for the file once, since Initialize is called
+  // for each note when Tomboy starts up.
+  if (s_sticky_file_might_exist) {
+    if (s_sticky_file_existence_confirmed || sharp::file_exists (s_sticky_xml_path)) {
+      m_item = manage(new Gtk::ImageMenuItem (_("Import from Sticky Notes")));
+      m_item->set_image(*manage(new Gtk::Image (Gtk::Stock::CONVERT, Gtk::ICON_SIZE_MENU)));
+      m_item->signal_activate().connect(
+        sigc::mem_fun(*this, &StickNoteImportNoteAddin::import_button_clicked));
+      m_item->show ();
+      add_plugin_menu_item (m_item);
+
+      s_sticky_file_existence_confirmed = true;
+      check_for_first_run();
+    } 
+    else {
+      s_sticky_file_might_exist = false;
+      DBG_OUT(DEBUG_NO_STICKY_FILE);
+    }
+  }
+
+}
+
+
+
+void StickNoteImportNoteAddin::shutdown()
+{
+}
+
+
+void StickNoteImportNoteAddin::on_note_opened()
+{
+}
+
+
+void StickNoteImportNoteAddin::check_for_first_run()
+{
+  bool firstRun = Preferences::obj().get<bool> (Preferences::STICKYNOTEIMPORTER_FIRST_RUN);
+
+  if (firstRun) {
+    Preferences::obj().set<bool> (Preferences::STICKYNOTEIMPORTER_FIRST_RUN, false);
+
+    DBG_OUT(DEBUG_FIRST_RUN_DETECTED);
+
+    xmlDocPtr xml_doc = get_sticky_xml_doc();
+    if (xml_doc) {
+      // Don't show dialog when automatically importing
+      import_notes (xml_doc, false);
+      xmlFreeDoc(xml_doc);
+    }
+  }
+
+}
+
+
+xmlDocPtr StickNoteImportNoteAddin::get_sticky_xml_doc()
+{
+  if (sharp::file_exists(s_sticky_xml_path)) {
+    xmlDocPtr xml_doc = xmlReadFile(s_sticky_xml_path.c_str(), "UTF-8", 0);
+    if(xml_doc == NULL) {
+      DBG_OUT(DEBUG_NO_STICKY_FILE);
+    }
+    return xml_doc;
+  }
+  else {
+    DBG_OUT(DEBUG_NO_STICKY_FILE);
+    return NULL;
+  }
+}
+
+
+void StickNoteImportNoteAddin::import_button_clicked()
+{
+  xmlDocPtr xml_doc = get_sticky_xml_doc();
+  if(xml_doc) {
+    import_notes (xml_doc, true);
+  }
+  else {
+    show_no_sticky_xml_dialog(s_sticky_xml_path);
+  }
+}
+
+
+void StickNoteImportNoteAddin::show_no_sticky_xml_dialog(const std::string & xml_path)
+{
+  show_message_dialog (
+    _("No Sticky Notes found"),
+    // %1% is a the file name
+    str(boost::format(_("No suitable Sticky Notes file was found at \"%1%\"."))
+        % xml_path), Gtk::MESSAGE_ERROR);
+}
+
+
+void StickNoteImportNoteAddin::show_results_dialog(int numNotesImported, int numNotesTotal)
+{
+	show_message_dialog (
+    _("Sticky Notes import completed"),
+    // here %1% is the number of notes imported, %2% the total number of notes.
+    str(boost::format(_("<b>%1%</b> of <b>%s%</b> Sticky Notes "
+                        "were successfully imported.")) 
+        % numNotesImported % numNotesTotal), Gtk::MESSAGE_INFO);
+}
+
+
+void StickNoteImportNoteAddin::import_notes(xmlDocPtr xml_doc, bool showResultsDialog)
+{
+  xmlNodePtr root_node = xmlDocGetRootElement(xml_doc);
+  if(!root_node) {
+    if (showResultsDialog)
+      show_no_sticky_xml_dialog(s_sticky_xml_path);
+    return;
+  }
+  sharp::XmlNodeSet nodes = sharp::xml_node_xpath_find(root_node, STICKY_NOTE_QUERY);
+
+  int numSuccessful = 0;
+  const xmlChar * defaultTitle = (const xmlChar *)_("Untitled");
+
+  for(sharp::XmlNodeSet::const_iterator iter = nodes.begin();
+      iter != nodes.end(); ++iter) {
+
+    xmlNodePtr node = *iter;
+    const xmlChar * stickyTitle;
+    xmlChar * titleAttr = xmlGetProp(node, (const xmlChar*)"title");
+    if(titleAttr) {
+      stickyTitle = titleAttr;
+    }
+    else {
+      stickyTitle = defaultTitle;
+    }
+    xmlChar * stickyContent = xmlNodeGetContent(node);
+
+    if(stickyContent) {
+      if (create_note_from_sticky ((const char*)stickyTitle, (const char*)stickyContent)) {
+        numSuccessful++;
+      }
+      xmlFree(stickyContent);
+    }
+
+    if(titleAttr) {
+      xmlFree(titleAttr);
+    }
+  }
+
+  if (showResultsDialog) {
+    show_results_dialog (numSuccessful, nodes.size());
+  }
+}
+
+
+bool StickNoteImportNoteAddin::create_note_from_sticky(const char * stickyTitle, 
+                                                       const char* content)
+{
+  // There should be no XML in the content
+  // TODO: Report the error in the results dialog
+  //  (this error should only happen if somebody has messed with the XML file)
+  if(strchr(content, '>') || strchr(content, '<')) {
+    DBG_OUT(DEBUG_CREATE_ERROR_BASE, stickyTitle,
+            "Invalid characters in note XML");
+    return false;
+  }
+
+  std::string preferredTitle = _("Sticky Note: ");
+  preferredTitle += stickyTitle;
+  std::string title = preferredTitle;
+
+  int i = 2; // Append numbers to create unique title, starting with 2
+  while (manager().find(title)){
+    title = str(boost::format("%1% (#%2%)") % preferredTitle % i);
+    i++;
+  }
+  
+  std::string noteXml = str(boost::format("<note-content><note-title>%1%</note-title>\n\n"
+                                          "%2%</note-content>") % title % content);
+
+  try {
+    Note::Ptr newNote = manager().create(title, noteXml);
+    newNote->queue_save (Note::NO_CHANGE);
+    newNote->save();
+    return true;
+  } 
+  catch (const std::exception & e) {
+    DBG_OUT(DEBUG_CREATE_ERROR_BASE, title.c_str(), e.what());
+    return false;
+  }
+}
+
+
+void StickNoteImportNoteAddin::show_message_dialog(const std::string & title, 
+                                                   const std::string & message,
+                                                   Gtk::MessageType messageType)
+{
+  gnote::utils::HIGMessageDialog dialog(get_window(),
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        messageType,
+                                        Gtk::BUTTONS_OK,
+                                        title,
+                                        message);
+  dialog.run();
+}
+
+  
+}
diff --git a/src/addins/stickynoteimport/stickynoteimportnoteaddin.hpp b/src/addins/stickynoteimport/stickynoteimportnoteaddin.hpp
new file mode 100644
index 0000000..4374ddf
--- /dev/null
+++ b/src/addins/stickynoteimport/stickynoteimportnoteaddin.hpp
@@ -0,0 +1,94 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2009 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STICKYNOTE_IMPORT_NOTE_ADDIN_HPP_
+#define __STICKYNOTE_IMPORT_NOTE_ADDIN_HPP_
+
+#include <string>
+
+#include <libxml/tree.h>
+
+#include <gtkmm/imagemenuitem.h>
+
+#include "sharp/dynamicmodule.hpp"
+#include "noteaddin.hpp"
+
+namespace stickynote {
+
+
+class StickNoteImportModule
+  : public sharp::DynamicModule
+{
+public:
+  StickNoteImportModule();
+  virtual const char * id() const;
+  virtual const char * name() const;
+  virtual const char * description() const;
+  virtual const char * authors() const;
+  virtual const char * category() const;
+  virtual const char * version() const;
+};
+
+
+DECLARE_MODULE(StickNoteImportModule);
+
+class StickNoteImportNoteAddin
+  : public gnote::NoteAddin
+{
+public:
+
+  static StickNoteImportNoteAddin * create()
+    {
+      return new StickNoteImportNoteAddin;
+    }
+
+  StickNoteImportNoteAddin()
+    {
+      _init_static();
+    }
+  virtual void initialize();
+  virtual void shutdown();
+  virtual void on_note_opened();
+
+private:
+  void check_for_first_run();
+  xmlDocPtr get_sticky_xml_doc();
+  void import_button_clicked();
+  void show_no_sticky_xml_dialog(const std::string & xml_path);
+  void show_results_dialog(int numNotesImported, int numNotesTotal);
+  void import_notes(xmlDocPtr xml_doc, bool showResultsDialog);
+  bool create_note_from_sticky(const char * stickyTitle, const char* content);
+  void show_message_dialog(const std::string & title, const std::string & message, 
+                           Gtk::MessageType messageType);
+
+  Gtk::ImageMenuItem *m_item;
+
+  static void _init_static();
+  static bool s_static_inited;
+  static bool s_sticky_file_might_exist;
+  static bool s_sticky_file_existence_confirmed;
+  static std::string s_sticky_xml_path;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/sharp/files.cpp b/src/sharp/files.cpp
index 1035e7a..d15cb32 100644
--- a/src/sharp/files.cpp
+++ b/src/sharp/files.cpp
@@ -22,8 +22,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-
-
 #include <boost/version.hpp>
 #include <boost/filesystem/operations.hpp>
 #include <boost/filesystem/convenience.hpp>
@@ -34,6 +32,14 @@
 namespace sharp {
 
 
+  bool file_exists(const std::string & file)
+  {
+    boost::filesystem::path p(file);
+    // is_regular_file isn't in 1.34. is_regular is deprecated.
+    return (exists(p) && is_regular(p));
+  }
+
+
   std::string file_basename(const std::string & p)
   {
 #if BOOST_VERSION >= 103600
@@ -48,6 +54,12 @@ namespace sharp {
     return boost::filesystem::path(p).branch_path().string();
   }
 
+
+  std::string file_filename(const std::string & p)
+  {
+    return boost::filesystem::path(p).leaf();
+  }
+
   void file_delete(const std::string & p)
   {
     boost::filesystem::remove(p);
@@ -59,6 +71,9 @@ namespace sharp {
     boost::filesystem::copy_file(source, dest);
   }
 
-
+  void file_move(const std::string & from, const std::string & to)
+  {
+    boost::filesystem::rename(from, to);
+  }
 }
 
diff --git a/src/sharp/files.hpp b/src/sharp/files.hpp
index 7f0c1ba..b5e19c2 100644
--- a/src/sharp/files.hpp
+++ b/src/sharp/files.hpp
@@ -22,9 +22,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-
-
-
 #ifndef __SHARP_FILES_HPP_
 #define __SHARP_FILES_HPP_
 
@@ -32,9 +29,15 @@
 
 namespace sharp {
 
+  bool file_exists(const std::string & p);
   void file_delete(const std::string & p);
+  void file_move(const std::string & from, const std::string & to);
+  /** return the basename of the file path */
   std::string file_basename(const std::string & p);
+  /** return the directory from the file path */
   std::string file_dirname(const std::string & p);
+  /** return the filename from the file path */
+  std::string file_filename(const std::string & p);
   void file_copy(const std::string & source, const std::string & dest);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]