[gnote] * Bugzilla addin.



commit 75dc9b30561726140509d09b2ad5cf3c0ff6e159
Author: Hubert Figuiere <hub figuiere net>
Date:   Sun Apr 26 20:11:54 2009 -0400

      * Bugzilla addin.
---
 NEWS                                               |    2 +
 configure.ac                                       |    7 +-
 po/POTFILES.in                                     |    2 +
 src/Makefile.am                                    |    1 +
 src/addinmanager.cpp                               |    4 +-
 src/addinmanager.hpp                               |    4 +-
 src/addinpreferencefactory.cpp                     |    2 +-
 src/addinpreferencefactory.hpp                     |   22 ++-
 src/addins/Makefile.am                             |    3 +-
 src/addins/bugzilla/Makefile.am                    |   16 +
 src/addins/bugzilla/bug.png                        |  Bin 0 -> 648 bytes
 src/addins/bugzilla/bugzillalink.cpp               |  121 +++++++
 src/addins/bugzilla/bugzillalink.hpp               |   56 +++
 src/addins/bugzilla/bugzillanoteaddin.cpp          |  183 ++++++++++
 src/addins/bugzilla/bugzillanoteaddin.hpp          |   75 ++++
 src/addins/bugzilla/bugzillapreferences.cpp        |  369 ++++++++++++++++++++
 src/addins/bugzilla/bugzillapreferences.hpp        |   88 +++++
 src/addins/bugzilla/bugzillapreferencesfactory.hpp |   42 +++
 src/addins/bugzilla/insertbugaction.cpp            |  100 ++++++
 src/addins/bugzilla/insertbugaction.hpp            |   54 +++
 .../inserttimestamppreferencesfactory.hpp          |   10 +-
 src/notetag.cpp                                    |   26 ++-
 src/notetag.hpp                                    |   16 +-
 src/preferencesdialog.cpp                          |    2 +-
 src/sharp/directory.cpp                            |   15 +
 src/sharp/directory.hpp                            |    5 +-
 src/sharp/fileinfo.cpp                             |   51 +++
 src/sharp/fileinfo.hpp                             |   48 +++
 src/sharp/files.cpp                                |   10 +
 src/sharp/files.hpp                                |    4 +-
 src/sharp/uri.cpp                                  |    7 +
 src/sharp/uri.hpp                                  |    1 +
 32 files changed, 1317 insertions(+), 29 deletions(-)

diff --git a/NEWS b/NEWS
index 7bc43b8..f05f023 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+  * Bugzilla addin.
+
 0.3.0 -
 
 New features:
diff --git a/configure.ac b/configure.ac
index e24de81..45faad6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(gnote, 0.3.0)
+AC_INIT(gnote, 0.2.1)
 AC_PREREQ(2.59)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
@@ -13,8 +13,8 @@ AC_CONFIG_MACRO_DIR(m4)
 m4_pattern_allow([^BOOST_])
 
 MAJOR_VERSION=0
-MINOR_VERSION=3
-MICRO_VERSION=0
+MINOR_VERSION=2
+MICRO_VERSION=1
 
 GNOTE_VERSION="$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION"
 AC_SUBST(GNOTE_VERSION)
@@ -192,6 +192,7 @@ libtomboy/Makefile
 src/Makefile
 src/addins/Makefile
 src/addins/addins.mk
+src/addins/bugzilla/Makefile
 src/addins/fixedwidth/Makefile
 src/addins/inserttimestamp/Makefile
 src/addins/printnotes/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1c9ce84..1728dc5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -20,6 +20,8 @@ src/notebooks/notebookmanager.cpp
 src/notebooks/notebooknewnotemenuitem.cpp
 src/notebooks/notebookmenuitem.cpp
 src/notebooks/notebooknoteaddin.cpp
+src/addins/bugzilla/bugzillanoteaddin.cpp
+src/addins/bugzilla/bugzillapreferences.cpp
 src/addins/fixedwidth/fixedwidthmenuitem.cpp
 src/addins/fixedwidth/fixedwidthnoteaddin.cpp
 src/addins/printnotes/printnotesnoteaddin.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index 9fcb8e2..fd63cdb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,6 +47,7 @@ libgnote_a_SOURCES = \
 	sharp/dynamicmodule.hpp sharp/dynamicmodule.cpp \
 	sharp/directory.hpp sharp/directory.cpp \
 	sharp/exception.hpp sharp/exception.cpp \
+	sharp/fileinfo.hpp sharp/fileinfo.cpp \
 	sharp/files.hpp sharp/files.cpp \
 	sharp/map.hpp \
 	sharp/modulefactory.hpp \
diff --git a/src/addinmanager.cpp b/src/addinmanager.cpp
index 9addfd4..e41016a 100644
--- a/src/addinmanager.cpp
+++ b/src/addinmanager.cpp
@@ -93,9 +93,9 @@ namespace gnote {
         m_note_addin_infos.insert(std::make_pair(typeid(*f).name(), f));
       }
 
-      f = dmod->query_interface(AddinPreferenceFactory::IFACE_NAME);
+      f = dmod->query_interface(AddinPreferenceFactoryBase::IFACE_NAME);
       if(f) {
-        AddinPreferenceFactory * factory = dynamic_cast<AddinPreferenceFactory*>((*f)());
+        AddinPreferenceFactoryBase * factory = dynamic_cast<AddinPreferenceFactoryBase*>((*f)());
         m_addin_prefs.insert(std::make_pair((*iter)->id(), factory));
       }
       
diff --git a/src/addinmanager.hpp b/src/addinmanager.hpp
index eaec27c..c4b623f 100644
--- a/src/addinmanager.hpp
+++ b/src/addinmanager.hpp
@@ -37,7 +37,7 @@ namespace gnote {
 
 class ApplicationAddin;
 class PreferenceTabAddin;
-class AddinPreferenceFactory;
+class AddinPreferenceFactoryBase;
 
 
 class AddinManager
@@ -76,7 +76,7 @@ private:
   IdInfoMap                                m_note_addin_infos;
   typedef std::map<std::string, PreferenceTabAddin*> IdPrefTabAddinMap;
   IdPrefTabAddinMap                        m_pref_tab_addins;
-  typedef std::map<std::string, AddinPreferenceFactory*> IdAddinPrefsMap;
+  typedef std::map<std::string, AddinPreferenceFactoryBase*> IdAddinPrefsMap;
   IdAddinPrefsMap                          m_addin_prefs;
   sigc::signal<void>         m_application_addin_list_changed;
 };
diff --git a/src/addinpreferencefactory.cpp b/src/addinpreferencefactory.cpp
index 771b639..29863c9 100644
--- a/src/addinpreferencefactory.cpp
+++ b/src/addinpreferencefactory.cpp
@@ -25,7 +25,7 @@
 
 namespace gnote {
   
-const char * AddinPreferenceFactory::IFACE_NAME = "gnote::AddinPreferenceFactory";
+const char * AddinPreferenceFactoryBase::IFACE_NAME = "gnote::AddinPreferenceFactoryBase";
 
 
 }
diff --git a/src/addinpreferencefactory.hpp b/src/addinpreferencefactory.hpp
index 8fac0ac..e1c1a3a 100644
--- a/src/addinpreferencefactory.hpp
+++ b/src/addinpreferencefactory.hpp
@@ -30,7 +30,9 @@
 
 namespace gnote {
 
-class AddinPreferenceFactory
+
+/** the base class for the preference dialog factory */
+class AddinPreferenceFactoryBase
   : public sharp::IInterface
 {
 public:
@@ -38,6 +40,24 @@ public:
   virtual Gtk::Widget * create_preference_widget() = 0;
 };
 
+
+/** the template version */
+template <typename _AddinType>
+class AddinPreferenceFactory
+  : public AddinPreferenceFactoryBase
+{
+public:
+  static AddinPreferenceFactoryBase * create()
+    {
+      return new AddinPreferenceFactory<_AddinType>();
+    }
+  virtual Gtk::Widget * create_preference_widget()
+    {
+      return Gtk::manage(new _AddinType);
+    }
+};
+
+
 };
 
 
diff --git a/src/addins/Makefile.am b/src/addins/Makefile.am
index 6e6a16c..e717a5e 100644
--- a/src/addins/Makefile.am
+++ b/src/addins/Makefile.am
@@ -1,7 +1,8 @@
 
 
 
-SUBDIRS = fixedwidth \
+SUBDIRS = bugzilla \
+	fixedwidth \
 	inserttimestamp \
 	printnotes \
 	$(NULL)
\ No newline at end of file
diff --git a/src/addins/bugzilla/Makefile.am b/src/addins/bugzilla/Makefile.am
new file mode 100644
index 0000000..07c90a0
--- /dev/null
+++ b/src/addins/bugzilla/Makefile.am
@@ -0,0 +1,16 @@
+
+include $(builddir)/../addins.mk
+
+addinsdir = $(ADDINSDIR)
+addins_LTLIBRARIES = bugzilla.la
+
+icondir = @datadir@/gnote/icons/hicolor/16x16/apps
+icon_DATA = bug.png
+
+bugzilla_la_SOURCES = bugzillanoteaddin.hpp bugzillanoteaddin.cpp \
+	insertbugaction.hpp insertbugaction.cpp \
+	bugzillalink.hpp bugzillalink.cpp \
+	bugzillapreferencesfactory.hpp \
+	bugzillapreferences.hpp bugzillapreferences.cpp \
+	$(srcdir)/../../sharp/fileinfo.cpp \
+	$(NULL)
diff --git a/src/addins/bugzilla/bug.png b/src/addins/bugzilla/bug.png
new file mode 100644
index 0000000..0a5e49f
Binary files /dev/null and b/src/addins/bugzilla/bug.png differ
diff --git a/src/addins/bugzilla/bugzillalink.cpp b/src/addins/bugzilla/bugzillalink.cpp
new file mode 100644
index 0000000..d08a06c
--- /dev/null
+++ b/src/addins/bugzilla/bugzillalink.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "sharp/uri.hpp"
+#include "debug.hpp"
+#include "utils.hpp"
+#include "bugzillalink.hpp"
+
+namespace bugzilla {
+
+#define URI_ATTRIBUTE_NAME "uri"
+
+  Glib::RefPtr<Gdk::Pixbuf> BugzillaLink::s_bug_icon;
+
+  void BugzillaLink::_static_init()
+  {
+    s_bug_icon = gnote::utils::get_icon("bug", 16);
+  }
+
+
+  BugzillaLink::BugzillaLink()
+  {
+    _static_init();
+  }
+
+
+  void BugzillaLink::initialize(const std::string & element_name)
+  {
+    gnote::DynamicNoteTag::initialize(element_name);
+
+    property_underline() = Pango::UNDERLINE_SINGLE;
+    property_foreground() = "blue";
+    set_can_activate(true);
+    set_can_grow(true);
+    set_can_spell_check(false);
+    set_can_split(false);
+  }
+
+
+  std::string BugzillaLink::get_bug_url() const
+  {
+    std::string url;
+    AttributeMap::const_iterator iter = get_attributes().find(URI_ATTRIBUTE_NAME);
+    if(iter != get_attributes().end()) {
+      url = iter->second;
+    }
+    return url;
+  }
+
+
+  void BugzillaLink::set_bug_url(const std::string & value)
+  {
+    get_attributes()[URI_ATTRIBUTE_NAME] = value;
+    make_image();
+  }
+
+
+  void BugzillaLink::make_image()
+  {
+    sharp::Uri uri(get_bug_url());
+
+    std::string host = uri.get_host();
+
+    std::string imageDir = Glib::get_home_dir() + "/.gnote/BugzillaIcons/";
+    std::string imagePath = imageDir + host + ".png";
+    Glib::RefPtr<Gdk::Pixbuf> image;
+    try {
+      image = Gdk::Pixbuf::create_from_file(imagePath);
+    }
+    catch(...) {
+      image = s_bug_icon;
+    }
+    set_image(image);
+  }
+
+
+  bool BugzillaLink::on_activate(const gnote::NoteEditor & , 
+                                 const Gtk::TextIter & , 
+                                 const Gtk::TextIter & )
+  {
+    if(!get_bug_url().empty()) {
+      DBG_OUT("Opening url '%s'...", get_bug_url().c_str());
+				
+      try {
+        gnote::utils::open_url(get_bug_url());
+      } 
+      catch (const Glib::Error & e) {
+        gnote::utils::show_opening_location_error(NULL, 
+                                                  get_bug_url(), e.what());
+      }
+    }
+    return true;
+  }
+
+
+  void BugzillaLink::on_attribute_read(const std::string & attributeName)
+  {
+    gnote::DynamicNoteTag::on_attribute_read(attributeName);
+    if (attributeName == URI_ATTRIBUTE_NAME) {
+      make_image();
+    }
+  }
+
+}
diff --git a/src/addins/bugzilla/bugzillalink.hpp b/src/addins/bugzilla/bugzillalink.hpp
new file mode 100644
index 0000000..90c9b60
--- /dev/null
+++ b/src/addins/bugzilla/bugzillalink.hpp
@@ -0,0 +1,56 @@
+/*
+ * 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 __BUGZILLA_LINK_HPP_
+#define __BUGZILLA_LINK_HPP_
+
+#include <gtkmm/textiter.h>
+
+#include "noteeditor.hpp"
+#include "notetag.hpp"
+
+namespace bugzilla {
+
+
+class BugzillaLink
+  : public gnote::DynamicNoteTag
+{
+public:
+  typedef Glib::RefPtr<BugzillaLink> Ptr;
+  static gnote::DynamicNoteTag::Ptr create()
+    {
+      return gnote::DynamicNoteTag::Ptr(new BugzillaLink);
+    }
+  BugzillaLink();
+  std::string get_bug_url() const;
+  void set_bug_url(const std::string & );
+protected:
+  virtual void initialize(const std::string & element_name);
+  virtual bool on_activate(const gnote::NoteEditor & , const Gtk::TextIter &, 
+                           const Gtk::TextIter &);
+  virtual void on_attribute_read(const std::string &);
+private:
+  void make_image();
+  static void _static_init();
+  static Glib::RefPtr<Gdk::Pixbuf> s_bug_icon;
+};
+
+}
+
+#endif
diff --git a/src/addins/bugzilla/bugzillanoteaddin.cpp b/src/addins/bugzilla/bugzillanoteaddin.cpp
new file mode 100644
index 0000000..c475368
--- /dev/null
+++ b/src/addins/bugzilla/bugzillanoteaddin.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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/regex.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <glibmm/i18n.h>
+
+
+#include "debug.hpp"
+#include "notebuffer.hpp"
+#include "notewindow.hpp"
+
+#include "bugzillanoteaddin.hpp"
+#include "bugzillalink.hpp"
+#include "bugzillapreferencesfactory.hpp"
+#include "insertbugaction.hpp"
+
+namespace bugzilla {
+
+  BugzillaModule::BugzillaModule()
+  {
+    ADD_INTERFACE_IMPL(BugzillaNoteAddin);
+    ADD_INTERFACE_IMPL(BugzillaPreferencesFactory);
+  }
+  const char * BugzillaModule::id() const
+  {
+    return "BugzillaAddin";
+  }
+  const char * BugzillaModule::name() const
+  {
+    return _("Bugzilla Links");
+  }
+  const char * BugzillaModule::description() const
+  {
+    return _("Allows you to drag a Bugzilla URL from your browser directly into a Gnote note.  The bug number is inserted as a link with a little bug icon next to it.");
+  }
+  const char * BugzillaModule::authors() const
+  {
+    return _("Hubert Figuiere and the Tomboy Project");
+  }
+  const char * BugzillaModule::category() const
+  {
+    return "Desktop Integration";
+  }
+  const char * BugzillaModule::version() const
+  {
+    return "0.1";
+  }
+
+
+  const char * BugzillaNoteAddin::TAG_NAME = "link:bugzilla";
+
+  void BugzillaNoteAddin::initialize()
+  {
+    if(!get_note()->get_tag_table()->is_dynamic_tag_registered(TAG_NAME)) {
+      get_note()->get_tag_table()
+        ->register_dynamic_tag(TAG_NAME, sigc::ptr_fun(&BugzillaLink::create));
+    }
+  }
+
+
+
+  void BugzillaNoteAddin::shutdown()
+  {
+  }
+
+
+  void BugzillaNoteAddin::on_note_opened()
+  {
+    get_window()->editor()->signal_drag_data_received().connect(
+      sigc::mem_fun(*this, &BugzillaNoteAddin::on_drag_data_received), false);
+  }
+
+
+  void BugzillaNoteAddin::on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, 
+                                                int x, int y, 
+                                                const Gtk::SelectionData & selection_data, 
+                                                guint, guint time)
+  {
+    DBG_OUT("Bugzilla.OnDragDataReceived");
+    Gdk::ListHandle_AtomString targets = context->get_targets();
+
+    for(Gdk::ListHandle_AtomString::const_iterator iter = targets.begin();
+        iter != targets.end(); ++iter) {
+      
+      std::string atom(*iter);
+      DBG_OUT("atom is %s", atom.c_str());
+      if((atom == "text/uri-list") || (atom == "_NETSCAPE_URL")) {
+        drop_uri_list(context, x, y, selection_data, time);
+        return;
+      }
+    }
+  }
+
+
+  void BugzillaNoteAddin::drop_uri_list(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, 
+                                        const Gtk::SelectionData & selection_data, guint time)
+  {
+    std::string uriString = selection_data.get_text();
+    if(uriString.empty()) {
+      return;
+    }
+
+    const char * regexString = "\\bhttps?://.*/show_bug\\.cgi\\?(\\S+\\&){0,1}id=(\\d{1,})";
+
+    boost::regex re(regexString, boost::regex::extended|boost::regex_constants::icase);
+    boost::match_results<std::string::const_iterator> m;
+    if(regex_match(uriString, m, re) && m[2].matched) {
+      try {
+        int bugId = boost::lexical_cast<int>(std::string(m[2].first, m[2].second));
+
+        if (insert_bug (x, y, uriString, bugId)) {
+          context->drag_finish(true, false, time);
+          g_signal_stop_emission_by_name(get_window()->editor()->gobj(),
+                                         "drag_data_received");
+        }
+      }
+      catch(const std::exception & e) {
+        ERR_OUT("exception while converting URL '%s': %s",
+                uriString.c_str(), e.what());
+      }
+    }
+  }
+
+
+  bool BugzillaNoteAddin::insert_bug(int x, int y, const std::string & uri, int id)
+  {
+    try {
+      BugzillaLink::Ptr link_tag = 
+        BugzillaLink::Ptr::cast_dynamic(get_note()->get_tag_table()->create_dynamic_tag(TAG_NAME));
+      link_tag->set_bug_url(uri);
+
+      // Place the cursor in the position where the uri was
+      // dropped, adjusting x,y by the TextView's VisibleRect.
+      Gdk::Rectangle rect;
+      get_window()->editor()->get_visible_rect(rect);
+      x = x + rect.get_x();
+      y = y + rect.get_y();
+      Gtk::TextIter cursor;
+      gnote::NoteBuffer::Ptr buffer = get_buffer();
+      get_window()->editor()->get_iter_at_location(cursor, x, y);
+      buffer->place_cursor (cursor);
+
+      std::string string_id = boost::lexical_cast<std::string>(id);
+      buffer->undoer().add_undo_action (new InsertBugAction (cursor, 
+                                                             string_id, 
+                                                             buffer,
+                                                             link_tag));
+
+      std::vector<Glib::RefPtr<Gtk::TextTag> > tags;
+      tags.push_back(link_tag);
+      buffer->insert_with_tags (cursor, 
+                                string_id, 
+                                tags);
+      return true;
+    } 
+    catch (...)
+    {
+		}
+    return false;
+  }
+
+}
+
diff --git a/src/addins/bugzilla/bugzillanoteaddin.hpp b/src/addins/bugzilla/bugzillanoteaddin.hpp
new file mode 100644
index 0000000..6af49b6
--- /dev/null
+++ b/src/addins/bugzilla/bugzillanoteaddin.hpp
@@ -0,0 +1,75 @@
+/*
+ * 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 _BUGZILLA_NOTE_ADDIN_HPP__
+#define _BUGZILLA_NOTE_ADDIN_HPP__
+
+
+#include "sharp/dynamicmodule.hpp"
+#include "noteaddin.hpp"
+
+namespace bugzilla {
+
+
+class BugzillaModule
+  : public sharp::DynamicModule
+{
+public:
+  BugzillaModule();
+  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(BugzillaModule);
+
+class BugzillaNoteAddin
+  : public gnote::NoteAddin
+{
+public:
+  static BugzillaNoteAddin* create()
+    {
+      return new BugzillaNoteAddin;
+    }
+  virtual void initialize();
+  virtual void shutdown();
+  virtual void on_note_opened();
+private:
+  static const char * TAG_NAME;
+
+  void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>&, int, int, const Gtk::SelectionData &,
+                             guint, guint);
+  void drop_uri_list(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, 
+                     const Gtk::SelectionData & selection_data, guint time);
+
+  bool insert_bug (int x, int y, const std::string & uri, int id);
+
+};
+
+
+}
+
+
+#endif
diff --git a/src/addins/bugzilla/bugzillapreferences.cpp b/src/addins/bugzilla/bugzillapreferences.cpp
new file mode 100644
index 0000000..41277d7
--- /dev/null
+++ b/src/addins/bugzilla/bugzillapreferences.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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 <glibmm/i18n.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/filechooserdialog.h>
+#include <gtkmm/label.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/stock.h>
+
+#include "sharp/directory.hpp"
+#include "sharp/fileinfo.hpp"
+#include "sharp/files.hpp"
+#include "sharp/string.hpp"
+#include "debug.hpp"
+#include "utils.hpp"
+
+#include "bugzillapreferences.hpp"
+
+
+namespace bugzilla {
+
+  bool BugzillaPreferences::s_static_inited = false;;
+  std::string BugzillaPreferences::s_image_dir;
+
+  void BugzillaPreferences::_init_static()
+  {
+    if(!s_static_inited) {
+      s_image_dir = Glib::get_home_dir() + "/.gnote/BugzillaIcons";
+      s_static_inited = true;
+    }
+  }
+
+  BugzillaPreferences::BugzillaPreferences()
+    : Gtk::VBox(false, 12)
+  {
+    _init_static();
+    last_opened_dir = Glib::get_home_dir();
+
+    Gtk::Label *l = manage(new Gtk::Label (_("You can use any bugzilla just by dragging links "
+                                   "into notes.  If you want a special icon for "
+                                              "certain hosts, add them here.")));
+    l->property_wrap() = true;
+    l->property_xalign() = 0;
+
+    pack_start(*l, false, false, 0);
+
+    icon_store = Gtk::ListStore::create(m_columns);
+    icon_store->set_sort_column_id(m_columns.host, Gtk::SORT_ASCENDING);
+
+    icon_tree = manage(new Gtk::TreeView (icon_store));
+    icon_tree->set_headers_visible(true);
+    icon_tree->get_selection()->set_mode(Gtk::SELECTION_SINGLE);
+    icon_tree->get_selection()->signal_changed().connect(
+      sigc::mem_fun(*this, &BugzillaPreferences::selection_changed));
+
+    Gtk::TreeViewColumn *host_col = manage(new Gtk::TreeViewColumn(_("Host Name"), m_columns.host));
+    host_col->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
+    host_col->set_resizable(true);
+    host_col->set_expand(true);
+    host_col->set_min_width(200);
+
+    host_col->set_sort_column(m_columns.host);
+    host_col->set_sort_indicator(false);
+    host_col->set_reorderable(false);
+    host_col->set_sort_order(Gtk::SORT_ASCENDING);
+
+    icon_tree->append_column (*host_col);
+
+    Gtk::TreeViewColumn *icon_col = manage(new Gtk::TreeViewColumn(_("Icon"), m_columns.icon));
+    icon_col->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED);
+    icon_col->set_max_width(50);
+    icon_col->set_min_width(50);
+    icon_col->set_resizable(false);
+
+    icon_tree->append_column (*icon_col);
+
+    Gtk::ScrolledWindow *sw = manage(new Gtk::ScrolledWindow ());
+    sw->set_shadow_type(Gtk::SHADOW_IN);
+    sw->property_height_request() = 200;
+    sw->property_width_request() = 300;
+    sw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+    sw->add (*icon_tree);
+
+    pack_start(*sw, true, true, 0);
+
+    add_button = manage(new Gtk::Button (Gtk::Stock::ADD));
+    add_button->signal_clicked().connect(
+      sigc::mem_fun(*this, &BugzillaPreferences::add_clicked));
+
+    remove_button = manage(new Gtk::Button (Gtk::Stock::REMOVE));
+    remove_button->set_sensitive(false);
+    remove_button->signal_clicked().connect(
+      sigc::mem_fun(*this,  &BugzillaPreferences::remove_clicked));
+
+    Gtk::HButtonBox *hbutton_box = manage(new Gtk::HButtonBox ());
+    hbutton_box->set_layout(Gtk::BUTTONBOX_START);
+    hbutton_box->set_spacing(6);
+
+    hbutton_box->pack_start(*add_button);
+    hbutton_box->pack_start(*remove_button);
+    pack_start(*hbutton_box, false, false, 0);
+
+    show_all ();
+  }
+
+
+  void BugzillaPreferences::update_icon_store()
+  {
+    if (!sharp::directory_exists (s_image_dir)) {
+      return;
+    }
+
+    icon_store->clear(); // clear out the old entries
+
+    std::list<std::string> icon_files; 
+    sharp::directory_get_files (s_image_dir, icon_files);
+    for(std::list<std::string>::const_iterator iter = icon_files.begin();
+        iter != icon_files.end(); ++iter) {
+      
+      const std::string & icon_file(*iter);
+      sharp::FileInfo file_info(icon_file);
+
+      Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+      try {
+        pixbuf = Gdk::Pixbuf::create_from_file(icon_file);
+      } 
+      catch (const Glib::Error & e) {
+        DBG_OUT("Error loading Bugzilla Icon %s: %s", icon_file.c_str(), e.what().c_str());
+      }
+
+      if (!pixbuf) {
+        continue;
+      }
+
+      std::string host = parse_host (file_info);
+      if (!host.empty()) {
+        Gtk::TreeIter treeiter = icon_store->append ();
+        
+        (*treeiter)[m_columns.icon] = pixbuf;
+        (*treeiter)[m_columns.host] = host;
+        (*treeiter)[m_columns.file_path] = icon_file;
+      }
+    }
+  }
+
+
+  std::string BugzillaPreferences::parse_host(const sharp::FileInfo & file_info)
+  {
+    std::string name = file_info.get_name();
+    std::string ext = file_info.get_extension();
+
+    if (ext.empty()) {
+      return "";
+    }
+
+    int ext_pos = sharp::string_index_of(name, ext);
+    if (ext_pos <= 0) {
+      return "";
+    }
+
+    std::string host = sharp::string_substring(name, 0, ext_pos);
+    if (host.empty()) {
+      return "";
+    }
+
+    return host;
+  }
+
+  void BugzillaPreferences::on_realize()
+  {
+    Gtk::VBox::on_realize();
+
+    update_icon_store();
+  }
+
+
+  void BugzillaPreferences::selection_changed()
+  {
+    remove_button->set_sensitive(icon_tree->get_selection()->count_selected_rows() > 0);
+  }
+  
+  void BugzillaPreferences::add_clicked()
+  {
+    Gtk::FileChooserDialog dialog(_("Select an icon..."),
+                                  Gtk::FILE_CHOOSER_ACTION_OPEN);
+    dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+    dialog.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
+
+    dialog.set_default_response(Gtk::RESPONSE_OK);
+    dialog.set_local_only(true);
+    dialog.set_current_folder (last_opened_dir);
+
+    Gtk::FileFilter filter;
+    filter.add_pixbuf_formats ();
+
+    dialog.add_filter(filter);
+
+    // Extra Widget
+    Gtk::Label *l = manage(new Gtk::Label (_("_Host name:"), true));
+    Gtk::Entry *host_entry = manage(new Gtk::Entry ());
+    l->set_mnemonic_widget(*host_entry);
+    Gtk::HBox *hbox = manage(new Gtk::HBox (false, 6));
+    hbox->pack_start (*l, false, false, 0);
+    hbox->pack_start (*host_entry, true, true, 0);
+    hbox->show_all ();
+
+    dialog.set_extra_widget(*hbox);
+
+    int response;
+    std::string icon_file;
+    std::string host;
+
+    while(1) {
+      response = dialog.run ();
+      icon_file = dialog.get_filename();
+      host = sharp::string_trim(host_entry->get_text());
+
+      if (response == (int) Gtk::RESPONSE_OK) {
+        if(!host.empty()) {
+          break;
+        }
+        // Let the user know that they
+        // have to specify a host name.
+        gnote::utils::HIGMessageDialog warn(
+          NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
+          Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK,
+          _("No host name specified"),
+          _("You must specify the Bugzilla "
+            "host name to use with this icon."));
+        warn.run ();
+
+        host_entry->grab_focus ();
+      } 
+      else if (response != (int) Gtk::RESPONSE_OK) {
+        return;
+      }
+    }
+
+    // Keep track of the last directory the user had open
+    last_opened_dir = dialog.get_current_folder();
+
+    // Copy the file to the BugzillaIcons directory
+    std::string err_msg;
+    if (!copy_to_bugzilla_icons_dir (icon_file, host, err_msg)) {
+      gnote::utils::HIGMessageDialog err(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
+                                         Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK,
+                                         _("Error saving icon"),
+                                         std::string(_("Could not save the icon file.")) +
+                                         "  " + err_msg);
+      err.run();
+    }
+
+    update_icon_store();
+  }
+
+  bool BugzillaPreferences::copy_to_bugzilla_icons_dir(const std::string & file_path,
+                                                       const std::string & host,
+                                                       std::string & err_msg)
+  {
+    err_msg = "";
+
+    sharp::FileInfo file_info(file_path);
+    std::string ext = file_info.get_extension();
+    std::string saved_path = s_image_dir + "/" + host + ext;
+    try {
+      if (!sharp::directory_exists (s_image_dir)) {
+        sharp::directory_create (s_image_dir);
+      }
+
+      sharp::file_copy (file_path, saved_path);
+    } 
+    catch (const sharp::Exception & e) {
+      err_msg = e.what();
+      return false;
+    }
+
+    resize_if_needed (saved_path);
+    return true;
+  }
+
+  void BugzillaPreferences::resize_if_needed(const std::string & p)
+  {
+    Glib::RefPtr<Gdk::Pixbuf> pix, newpix;
+
+    try {
+      const double dim = 16;
+      pix = Gdk::Pixbuf::create_from_file(p);
+      int height, width;
+      int orig_h, orig_w;
+      orig_h = pix->get_height();
+      orig_w = pix->get_width();
+      int orig_dim = std::max(orig_h, orig_w);
+      double ratio = dim / (double)orig_dim;
+      width = (int)(ratio * orig_w);
+      height = (int)(ratio * orig_h);
+      newpix = pix->scale_simple(width, height, 
+                                 Gdk::INTERP_BILINEAR);
+      newpix->save(p, "png");
+    }
+    catch(...) {
+
+    }
+  }
+
+
+  void BugzillaPreferences::remove_clicked()
+  {
+    // Remove the icon file and call UpdateIconStore ().
+    Gtk::TreeIter iter;
+    iter = icon_tree->get_selection()->get_selected();
+    if (!iter) {
+      return;
+    }
+
+    std::string icon_path = (*iter)[m_columns.file_path];
+
+    gnote::utils::HIGMessageDialog dialog(NULL, 
+                                          GTK_DIALOG_DESTROY_WITH_PARENT,
+                                          Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE,
+                                          _("Really remove this icon?"),
+                                          _("If you remove an icon it is permanently lost."));
+
+    Gtk::Button *button;
+
+    button = manage(new Gtk::Button (Gtk::Stock::CANCEL));
+    button->property_can_default() = true;
+    button->show ();
+    dialog.add_action_widget (*button, Gtk::RESPONSE_CANCEL);
+    dialog.set_default_response(Gtk::RESPONSE_CANCEL);
+
+    button = manage(new Gtk::Button (Gtk::Stock::DELETE));
+    button->property_can_default() = true;
+    button->show ();
+    dialog.add_action_widget (*button, 666);
+
+    int result = dialog.run ();
+    if (result == 666) {
+      try {
+        sharp::file_delete (icon_path);
+        update_icon_store ();
+      } 
+      catch (const sharp::Exception & e) {
+        ERR_OUT("Error removing icon %s: %s", icon_path.c_str(), e.what());
+      }
+    }
+  }
+
+
+}
+
diff --git a/src/addins/bugzilla/bugzillapreferences.hpp b/src/addins/bugzilla/bugzillapreferences.hpp
new file mode 100644
index 0000000..4e9865d
--- /dev/null
+++ b/src/addins/bugzilla/bugzillapreferences.hpp
@@ -0,0 +1,88 @@
+/*
+ * 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 __BUGZILLA_PREFERENCES_HPP_
+#define __BUGZILLA_PREFERENCES_HPP_
+
+#include <gdkmm/pixbuf.h>
+#include <gtkmm/box.h>
+#include <gtkmm/button.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treemodelcolumn.h>
+#include <gtkmm/treeview.h>
+
+namespace sharp {
+
+  class FileInfo;
+
+}
+
+namespace bugzilla {
+
+
+class BugzillaPreferences
+  : public Gtk::VBox
+{
+public:
+  BugzillaPreferences();
+
+protected:
+  virtual void on_realize();
+
+private:
+  void update_icon_store();
+  std::string parse_host(const sharp::FileInfo &);
+  void selection_changed();
+  void add_clicked();
+	bool copy_to_bugzilla_icons_dir(const std::string & file_path,
+                                  const std::string & host,
+                                  std::string & err_msg);
+  void resize_if_needed(const std::string & path);
+  void remove_clicked();
+
+  class Columns
+    : public Gtk::TreeModelColumnRecord
+  {
+  public:
+    Columns()
+      { add(icon); add(host); add(file_path); }
+    Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon;
+    Gtk::TreeModelColumn<std::string>                host;
+    Gtk::TreeModelColumn<std::string>                file_path;
+  };
+
+  Columns        m_columns;
+  Gtk::TreeView *icon_tree;
+  Glib::RefPtr<Gtk::ListStore> icon_store;
+
+  Gtk::Button *add_button;
+  Gtk::Button *remove_button;
+
+  std::string last_opened_dir;
+
+  void _init_static();
+  static bool        s_static_inited;
+  static std::string s_image_dir;
+};
+
+}
+
+#endif
diff --git a/src/addins/bugzilla/bugzillapreferencesfactory.hpp b/src/addins/bugzilla/bugzillapreferencesfactory.hpp
new file mode 100644
index 0000000..300138f
--- /dev/null
+++ b/src/addins/bugzilla/bugzillapreferencesfactory.hpp
@@ -0,0 +1,42 @@
+/*
+ * 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 __BUGZILLA_PREFERENCES_FACTORY_HPP_
+#define __BUGZILLA_PREFERENCES_FACTORY_HPP_
+
+#include "addinpreferencefactory.hpp"
+#include "bugzillapreferences.hpp"
+
+namespace bugzilla {
+
+
+class BugzillaPreferencesFactory
+  : public gnote::AddinPreferenceFactory<BugzillaPreferences>
+{
+
+};
+
+}
+
+
+#endif
diff --git a/src/addins/bugzilla/insertbugaction.cpp b/src/addins/bugzilla/insertbugaction.cpp
new file mode 100644
index 0000000..6fad6af
--- /dev/null
+++ b/src/addins/bugzilla/insertbugaction.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 "insertbugaction.hpp"
+
+using gnote::EditAction;
+using gnote::SplitterAction;
+using gnote::InsertAction;
+
+namespace bugzilla {
+
+  InsertBugAction::InsertBugAction(const Gtk::TextIter & start, const std::string & id,
+                                   const Glib::RefPtr<Gtk::TextBuffer> &,
+                                   const BugzillaLink::Ptr & tag)
+    : m_tag(tag)
+    , m_offset(start.get_offset())
+    , m_id(id)
+  {
+    
+  }
+
+  void InsertBugAction::undo (const Glib::RefPtr<Gtk::TextBuffer> & buffer)
+  {
+    // Tag images change the offset by one, but only when deleting.
+    Gtk::TextIter start_iter = buffer->get_iter_at_offset(m_offset);
+    Gtk::TextIter end_iter = buffer->get_iter_at_offset(m_offset + m_chop.length() + 1);
+    buffer->erase(start_iter, end_iter);
+    buffer->move_mark(buffer->get_insert(), buffer->get_iter_at_offset(m_offset));
+    buffer->move_mark(buffer->get_selection_bound(), buffer->get_iter_at_offset(m_offset));
+
+    m_tag->set_widget_location(Glib::RefPtr<Gtk::TextMark>());
+
+    apply_split_tag(buffer);
+  }
+
+
+  void InsertBugAction::redo (const Glib::RefPtr<Gtk::TextBuffer> & buffer)
+  {
+    remove_split_tags (buffer);
+
+    Gtk::TextIter cursor = buffer->get_iter_at_offset(m_offset);
+
+    std::vector<Glib::RefPtr<Gtk::TextTag> > tags;
+    tags.push_back(m_tag);
+    buffer->insert_with_tags (cursor, m_id, tags);
+
+    buffer->move_mark(buffer->get_selection_bound(), buffer->get_iter_at_offset(m_offset));
+    buffer->move_mark(buffer->get_insert(),
+                      buffer->get_iter_at_offset(m_offset + get_chop().length()));
+  }
+
+  void InsertBugAction::merge (EditAction * action)
+  {
+    SplitterAction *splitter = dynamic_cast<SplitterAction*>(action);
+    m_splitTags = splitter->get_split_tags();
+    m_chop = splitter->get_chop();
+  }
+
+	/*
+   * The internal listeners will create an InsertAction when the text
+   * is inserted.  Since it's ugly to have the bug insertion appear
+   * to the user as two items in the undo stack, have this item eat
+   * the other one.
+   */
+  bool InsertBugAction::can_merge (const EditAction * action) const
+  {
+    const InsertAction *insert = dynamic_cast<const InsertAction *>(action);
+    if (!insert) {
+      return false;
+    }
+
+    if (m_id == insert->get_chop().text()) {
+      return true;
+    }
+
+    return false;
+  }
+
+  void InsertBugAction::destroy ()
+  {
+  }
+
+}
diff --git a/src/addins/bugzilla/insertbugaction.hpp b/src/addins/bugzilla/insertbugaction.hpp
new file mode 100644
index 0000000..8689247
--- /dev/null
+++ b/src/addins/bugzilla/insertbugaction.hpp
@@ -0,0 +1,54 @@
+/*
+ * 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 __BUGZILLA_INSERT_BUG_ACTION_HPP_
+#define __BUGZILLA_INSERT_BUG_ACTION_HPP_
+
+#include <string>
+
+#include "undo.hpp"
+
+#include "bugzillalink.hpp"
+
+namespace bugzilla {
+
+class InsertBugAction
+  : public gnote::SplitterAction
+{
+public:
+  InsertBugAction(const Gtk::TextIter & start, const std::string & id,
+                  const Glib::RefPtr<Gtk::TextBuffer> & buffer,
+                  const BugzillaLink::Ptr & tag);
+  void undo (const Glib::RefPtr<Gtk::TextBuffer> & buffer);
+  void redo (const Glib::RefPtr<Gtk::TextBuffer> & buffer);
+  void merge (EditAction * action);
+  bool can_merge (const EditAction * action) const;
+  void destroy ();
+
+private:
+  BugzillaLink::Ptr m_tag;
+  int               m_offset;
+  std::string       m_id;
+};
+
+
+}
+
+
+#endif
diff --git a/src/addins/inserttimestamp/inserttimestamppreferencesfactory.hpp b/src/addins/inserttimestamp/inserttimestamppreferencesfactory.hpp
index c45f177..8f640ed 100644
--- a/src/addins/inserttimestamp/inserttimestamppreferencesfactory.hpp
+++ b/src/addins/inserttimestamp/inserttimestamppreferencesfactory.hpp
@@ -28,17 +28,9 @@ namespace inserttimestamp {
 
 
   class InsertTimestampPreferencesFactory
-    : public gnote::AddinPreferenceFactory
+    : public gnote::AddinPreferenceFactory<InsertTimestampPreferences>
   {
   public:
-    static gnote::AddinPreferenceFactory * create()
-      {
-        return new InsertTimestampPreferencesFactory;
-      }
-    virtual Gtk::Widget * create_preference_widget()
-      {
-        return Gtk::manage(new InsertTimestampPreferences());
-      }
   };
 
 
diff --git a/src/notetag.cpp b/src/notetag.cpp
index f9f6a7b..fc5ff44 100644
--- a/src/notetag.cpp
+++ b/src/notetag.cpp
@@ -45,9 +45,26 @@ namespace gnote {
                               "DynamicNoteTag for constructing "
                               "anonymous tags.");
     }
+    
+  }
+
+  
+  NoteTag::NoteTag()
+    : Gtk::TextTag()
+    , m_widget(NULL)
+    , m_flags(0)
+  {
   }
 
 
+  void NoteTag::initialize(const std::string & element_name)
+  {
+    m_element_name = element_name;
+    m_flags = CAN_SERIALIZE | CAN_SPLIT;
+  }
+  
+
+
   void NoteTag::set_can_serialize(bool value)
   {
     if (value) {
@@ -517,19 +534,20 @@ namespace gnote {
       
   DynamicNoteTag::Ptr NoteTagTable::create_dynamic_tag(const std::string & tag_name)
   {
-    std::map<std::string, TagType>::iterator iter = m_tag_types.find(tag_name);
+    std::map<std::string, Factory>::iterator iter = m_tag_types.find(tag_name);
     if(iter == m_tag_types.end()) {
       return DynamicNoteTag::Ptr();
     }
-    DynamicNoteTag::Ptr tag(iter->second.create(tag_name));
+    DynamicNoteTag::Ptr tag(iter->second());
+    tag->initialize(tag_name);
     add(tag);
     return tag;
   }
 
  
-  void NoteTagTable::register_dynamic_tag(const std::string & tag_name, const TagType & type)
+  void NoteTagTable::register_dynamic_tag(const std::string & tag_name, const FactorySlot & factory)
   {
-    m_tag_types[tag_name] = type;
+    m_tag_types[tag_name].connect(factory);
   }
 
 
diff --git a/src/notetag.hpp b/src/notetag.hpp
index 2993a59..14591fb 100644
--- a/src/notetag.hpp
+++ b/src/notetag.hpp
@@ -145,6 +145,10 @@ public:
     }
 protected:
   NoteTag(const std::string & tag_name, int flags = 0) throw(sharp::Exception);
+  NoteTag();
+  virtual void initialize(const std::string & element_name);
+
+  friend class NoteTagTable;
 
   virtual bool on_event(const Glib::RefPtr<Glib::Object> &, GdkEvent *, const Gtk::TextIter & );
   virtual bool on_activate(const NoteEditor & , const Gtk::TextIter &, const Gtk::TextIter &);
@@ -174,6 +178,10 @@ public:
     {
       return m_attributes;
     }
+  AttributeMap & get_attributes()
+    {
+      return m_attributes;
+    }
   virtual void write(sharp::XmlWriter &, bool) const;
   virtual void read(xmlpp::TextReader &, bool);
   /// <summary>
@@ -216,6 +224,7 @@ private:
 };
 
 
+#if 0
 class TagType 
 {
 public:
@@ -238,6 +247,7 @@ public:
 private:
   Factory m_factory;
 };
+#endif
 
 
 class NoteTagTable
@@ -245,6 +255,8 @@ class NoteTagTable
 {
 public:
   typedef Glib::RefPtr<NoteTagTable> Ptr;
+  typedef sigc::signal<DynamicNoteTag::Ptr> Factory;
+  typedef sigc::slot<DynamicNoteTag::Ptr> FactorySlot;
 
   static NoteTagTable & instance() 
     {
@@ -261,7 +273,7 @@ public:
   static bool tag_has_depth(const Glib::RefPtr<Gtk::TextBuffer::Tag> & );
   DepthNoteTag::Ptr get_depth_tag(int depth, Pango::Direction direction);
   DynamicNoteTag::Ptr create_dynamic_tag(const std::string & );
-  void register_dynamic_tag (const std::string & tag_name, const TagType & type);
+  void register_dynamic_tag (const std::string & tag_name, const FactorySlot & factory);
   bool is_dynamic_tag_registered(const std::string &);
 
 protected:
@@ -278,7 +290,7 @@ private:
   void _init_common_tags();
 
   static NoteTagTable                   *s_instance;
-  std::map<std::string, TagType>         m_tag_types;
+  std::map<std::string, Factory>     m_tag_types;
   std::list<Glib::RefPtr<Gtk::TextTag> > m_added_tags;
 };
 
diff --git a/src/preferencesdialog.cpp b/src/preferencesdialog.cpp
index 323ea95..1c6a257 100644
--- a/src/preferencesdialog.cpp
+++ b/src/preferencesdialog.cpp
@@ -632,7 +632,7 @@ namespace gnote {
       enable_addin_button->set_sensitive(!module->enabled());
       disable_addin_button->set_sensitive(module->enabled());
       addin_prefs_button->set_sensitive(
-        module->has_interface(AddinPreferenceFactory::IFACE_NAME));
+        module->has_interface(AddinPreferenceFactoryBase::IFACE_NAME));
       addin_info_button->set_sensitive(true);
     }
     else {
diff --git a/src/sharp/directory.cpp b/src/sharp/directory.cpp
index 3d9e016..b4f5ceb 100644
--- a/src/sharp/directory.cpp
+++ b/src/sharp/directory.cpp
@@ -61,5 +61,20 @@ namespace sharp {
     directory_get_files_with_ext(dir, "", files);
   }
 
+  bool directory_exists(const std::string & dir)
+  {
+    boost::filesystem::path p(dir);
+    return (exists(p) && is_directory(p));
+  }
+
+  bool directory_create(const std::string & dir)
+  {
+    try {
+      return boost::filesystem::create_directories(dir);
+    }
+    catch(...) {
+    }
+    return false;
+  }
 
 }
diff --git a/src/sharp/directory.hpp b/src/sharp/directory.hpp
index 753175b..220295e 100644
--- a/src/sharp/directory.hpp
+++ b/src/sharp/directory.hpp
@@ -43,9 +43,12 @@ namespace sharp {
                                     const std::string & ext,
                                     std::list<std::string>  & files);
 
-
   void directory_get_files(const std::string & dir, 
                            std::list<std::string>  & files);
+
+  bool directory_exists(const std::string & dir);
+  bool directory_create(const std::string & dir);
+
 }
 
 
diff --git a/src/sharp/fileinfo.cpp b/src/sharp/fileinfo.cpp
new file mode 100644
index 0000000..d8f5c24
--- /dev/null
+++ b/src/sharp/fileinfo.cpp
@@ -0,0 +1,51 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2009 Hubert Figuiere
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include "sharp/fileinfo.hpp"
+
+
+namespace sharp {
+
+  FileInfo::FileInfo(const std::string & s)
+    : m_path(s)
+  {
+  }
+
+
+  std::string FileInfo::get_name() const
+  {
+    return boost::filesystem::path(m_path).filename();
+  }
+
+
+  std::string FileInfo::get_extension() const
+  {
+    return boost::filesystem::extension(m_path);
+  }
+
+
+}
diff --git a/src/sharp/fileinfo.hpp b/src/sharp/fileinfo.hpp
new file mode 100644
index 0000000..b046129
--- /dev/null
+++ b/src/sharp/fileinfo.hpp
@@ -0,0 +1,48 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2009 Hubert Figuiere
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __SHARP_FILEINFO_HPP_
+#define __SHARP_FILEINFO_HPP_
+
+
+#include <string>
+
+namespace sharp {
+
+
+class FileInfo
+{
+public:
+  FileInfo(const std::string & );
+  std::string get_name() const;
+  std::string get_extension() const;
+private: 
+  std::string m_path;
+};
+
+}
+
+#endif
+
diff --git a/src/sharp/files.cpp b/src/sharp/files.cpp
index 0cf337b..bbef286 100644
--- a/src/sharp/files.cpp
+++ b/src/sharp/files.cpp
@@ -45,6 +45,16 @@ namespace sharp {
   }
 
 
+  void file_delete(const std::string & p)
+  {
+    boost::filesystem::remove(p);
+  }
+
+
+  void file_copy(const std::string & source, const std::string & dest)
+  {
+    boost::filesystem::copy_file(source, dest);
+  }
 
 
 }
diff --git a/src/sharp/files.hpp b/src/sharp/files.hpp
index 181c0c0..35dd2ab 100644
--- a/src/sharp/files.hpp
+++ b/src/sharp/files.hpp
@@ -32,9 +32,9 @@
 
 namespace sharp {
 
-
+  void file_delete(const std::string & p);
   std::string file_basename(const std::string & p);
-
+  void file_copy(const std::string & source, const std::string & dest);
 }
 
 
diff --git a/src/sharp/uri.cpp b/src/sharp/uri.cpp
index 86b1842..07221a8 100644
--- a/src/sharp/uri.cpp
+++ b/src/sharp/uri.cpp
@@ -46,6 +46,13 @@ namespace sharp {
     return string_replace_first(m_uri, FILE_URI_SCHEME, "");
   }
 
+  std::string Uri::get_host() const
+  {
+    std::string host;
+    
+    return host;
+  }
+
 
   /** this is a very minimalistic implementation */
   std::string Uri::escape_uri_string(const std::string &s)
diff --git a/src/sharp/uri.hpp b/src/sharp/uri.hpp
index 83e50df..cee8d2b 100644
--- a/src/sharp/uri.hpp
+++ b/src/sharp/uri.hpp
@@ -46,6 +46,7 @@ namespace sharp {
       }
     bool is_file() const;
     std::string local_path() const;
+    std::string get_host() const;
     static std::string escape_uri_string(const std::string &);
   private:
     std::string m_uri;



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