Index: configure.ac
===================================================================
--- configure.ac	(revision 1779)
+++ configure.ac	(working copy)
@@ -167,6 +167,7 @@
 deskbar/core/keybinder/Makefile
 deskbar/core/gnomedesktop/Makefile
 deskbar/core/updater/Makefile
+deskbar/core/_userdirs/Makefile
 deskbar/handlers/Makefile
 deskbar/handlers/actions/Makefile
 deskbar/handlers/gdmclient/Makefile
Index: deskbar/core/Utils.py
===================================================================
--- deskbar/core/Utils.py	(revision 1779)
+++ deskbar/core/Utils.py	(working copy)
@@ -6,6 +6,7 @@
 from htmlentitydefs import name2codepoint
 import logging
 from deskbar.core.GconfStore import GconfStore
+from deskbar.core._userdirs import *
 
 ICON_THEME = gtk.icon_theme_get_default()
 factory = gnome.ui.ThumbnailFactory(deskbar.ICON_HEIGHT)
Index: deskbar/core/_userdirs/__userdirsmodule.c
===================================================================
--- deskbar/core/_userdirs/__userdirsmodule.c	(revision 0)
+++ deskbar/core/_userdirs/__userdirsmodule.c	(revision 0)
@@ -0,0 +1,39 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <Python.h>
+#include <stdio.h>
+#include <errno.h>
+#include <glib.h>
+
+/* Function Prototypes */
+static PyObject * userdirs_get_xdg_user_dir (PyObject *self, PyObject *directory);
+
+/* Function Mapping Table */
+static PyMethodDef py__userdirs_functions[] =
+{
+	{ "get_xdg_user_dir", userdirs_get_xdg_user_dir, 0, "" },
+	{ NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC
+init__userdirs (void)
+{
+	Py_InitModule ("__userdirs", py__userdirs_functions);
+}
+	
+static PyObject *
+userdirs_get_xdg_user_dir (PyObject *self, PyObject *directory)
+{
+    if (!PyInt_Check (directory))
+        return NULL;
+    else {
+        const char *dir = g_get_user_special_dir ((GUserDirectory) PyInt_AsLong (directory));
+
+        if (dir)
+            return PyString_FromString (dir);
+        else
+            return Py_None;
+    }
+}
Index: deskbar/core/_userdirs/__init__.py
===================================================================
--- deskbar/core/_userdirs/__init__.py	(revision 0)
+++ deskbar/core/_userdirs/__init__.py	(revision 0)
@@ -0,0 +1,11 @@
+from __userdirs import *
+
+( USER_DIR_DESKTOP,
+  USER_DIR_DOCUMENTS,
+  USER_DIR_DOWNLOAD,
+  USER_DIR_MUSIC,
+  USER_DIR_PICTURES,
+  USER_DIR_PUBLIC_SHARE,
+  USER_DIR_TEMPLATES,
+  USER_DIR_VIDEOS
+) = range(8)
Index: deskbar/core/_userdirs/Makefile.am
===================================================================
--- deskbar/core/_userdirs/Makefile.am	(revision 0)
+++ deskbar/core/_userdirs/Makefile.am	(revision 0)
@@ -0,0 +1,11 @@
+INCLUDES = $(PYTHON_INCLUDES) $(DESKBAR_CFLAGS) $(GLIB_CFLAGS)
+
+__userdirsdir = $(pythondir)/deskbar/core/_userdirs
+__userdirs_LTLIBRARIES = __userdirs.la
+__userdirs_la_LDFLAGS = -module -avoid-version -export-symbols-regex init__userdirs
+__userdirs_la_LIBADD = $(DESKBAR_LIBS) $(GLIB_LIBS)
+__userdirs_la_SOURCES = \
+	__userdirsmodule.c 
+
+__userdirs_PYTHON = \
+	__init__.py
Index: deskbar/core/Makefile.am
===================================================================
--- deskbar/core/Makefile.am	(revision 1779)
+++ deskbar/core/Makefile.am	(working copy)
@@ -1,5 +1,5 @@
-SUBDIRS = gnomedesktop keybinder updater
-
+SUBDIRS = gnomedesktop keybinder updater _userdirs
+	
 deskbar_coredir = $(pythondir)/deskbar/core
 deskbar_core_PYTHON = \
 	__init__.py \
@@ -15,4 +15,4 @@
 	ModuleLoader.py \
 	ThreadPool.py \
 	Utils.py \
-	Watcher.py
\ No newline at end of file
+	Watcher.py
Index: deskbar/handlers/templates.py
===================================================================
--- deskbar/handlers/templates.py	(revision 0)
+++ deskbar/handlers/templates.py	(revision 0)
@@ -0,0 +1,198 @@
+import os, os.path, shutil, subprocess
+from gettext import gettext as _
+
+from deskbar.defs import VERSION
+import deskbar.interfaces.Module, deskbar.interfaces.Action, deskbar.interfaces.Match
+import deskbar.core.Indexer, deskbar.core.Utils
+import gtk
+import gnomevfs
+
+HANDLERS = ["TemplateHandler"]
+
+class TemplateFile(object):
+
+    def __init__(self, uri):
+        self.uri = uri
+
+        basename = os.path.basename(uri)
+        ext_index = basename.rfind(".")
+
+        if ext_index >= 0:
+            self.name = basename[:ext_index]
+            self.extension = basename[ext_index:]
+        else:
+            self.name = basename
+            self.extension = ""
+
+class TemplateAction(deskbar.interfaces.Action):
+
+    def __init__(self, template_file):
+        self.template_file = template_file
+        deskbar.interfaces.Action.__init__(self, template_file.name)
+
+    def get_icon(self):
+        return "gtk-new"
+
+    def get_verb(self):
+        return _("Create %s") % "<b>%(name)s</b>"
+
+    def activate(self, text=None):
+        dialog = gtk.Dialog(_("Create Document"),
+                            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                                       gtk.STOCK_OK, gtk.RESPONSE_OK))
+
+        dialog.set_icon_name(gtk.STOCK_NEW)
+        dialog.set_has_separator(False)
+        dialog.set_default_response(gtk.RESPONSE_OK)
+
+        table = gtk.Table(1, 2)
+        table.set_border_width(5)
+        table.set_row_spacings(6)
+        table.set_col_spacings(12)
+
+        filename_label = gtk.Label(_("Name:"))
+        filename_label.set_alignment(0.0, 0.5)
+        table.attach(filename_label, 0, 1, 0, 1, xoptions=gtk.FILL)
+
+        filename_entry = gtk.Entry()
+        table.attach(filename_entry, 1, 2, 0, 1)
+
+        folder_label = gtk.Label(_("Folder:"))
+        folder_label.set_alignment(0.0, 0.5)
+        table.attach(folder_label, 0, 1, 1, 2, xoptions=gtk.FILL)
+
+        folder_button = gtk.FileChooserButton(_("Choose Folder"))
+        folder_button.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
+        table.attach(folder_button, 1, 2, 1, 2)
+
+        dialog.vbox.pack_start(table)
+        dialog.show_all()
+
+        folder = deskbar.core.Utils.get_xdg_user_dir(deskbar.core.Utils.USER_DIR_DOCUMENTS)
+
+        if not folder:
+            folder = "~"
+
+        folder_button.set_filename(folder)
+
+        filename = "%s%s" % (self.template_file.name, self.template_file.extension)
+
+        if os.path.exists(os.path.join(folder, filename)):
+            index = 1
+
+            while True:
+                filename = "%s (%s)%s" % (self.template_file.name, index,
+                                          self.template_file.extension)
+                
+                if not os.path.exists(filename):
+                    break
+                else:
+                    index += 1
+
+        filename_entry.set_text(filename)
+
+        selection_len = filename.rfind(".")
+        if selection_len < 0:
+            selection_len = len(filename)
+
+        filename_entry.select_region(0, selection_len)
+
+        def filename_entry_activate_cb(entry):
+            dialog.response(gtk.RESPONSE_OK)
+
+        def filename_entry_changed_cb(entry):
+            dialog.set_response_sensitive(gtk.RESPONSE_OK,
+                                          len(filename_entry.get_text().strip()) != 0)
+
+        filename_entry.connect("activate", filename_entry_activate_cb)
+        filename_entry.connect("changed", filename_entry_changed_cb)
+
+        response = dialog.run()
+        dialog.hide()
+
+        if response == gtk.RESPONSE_OK:
+            created_file = os.path.join(folder_button.get_filename(),
+                                        filename_entry.get_text())
+
+            if os.path.exists(created_file):
+                msg_dialog = gtk.MessageDialog(flags=gtk.MESSAGE_QUESTION,
+                        message_format=_("A file named \"%s\" already exists.  " \
+                                         "Do you want to replace it?")
+                                         % filename_entry.get_text())
+
+                msg_dialog.format_secondary_text(_("The file already exists in \"%s\".  " \
+                                                   "Replacing it will overwrite its contents.")
+                                                   % os.path.basename(folder_button.get_filename()))
+
+                msg_dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
+                img = gtk.Image()
+                img.set_from_stock(gtk.STOCK_SAVE_AS, gtk.ICON_SIZE_BUTTON)
+                button = gtk.Button(_("Replace"))
+                button.set_image(img)
+                msg_dialog.add_action_widget(button, gtk.RESPONSE_ACCEPT)
+                msg_dialog.set_default_response(gtk.RESPONSE_ACCEPT)       
+                msg_dialog.show_all()
+
+                response = msg_dialog.run()
+                msg_dialog.destroy()
+
+                if response != gtk.RESPONSE_ACCEPT:
+                    return
+
+            shutil.copyfile(self.template_file.uri, created_file)
+            subprocess.Popen(["gnome-open", created_file])
+
+        dialog.destroy()
+
+    def is_valid(self):
+        return os.path.exists(self.template_file.uri)
+
+class TemplateMatch(deskbar.interfaces.Match):
+
+    def __init__(self, template_file):
+        deskbar.interfaces.Match.__init__(self,
+                                          name = template_file.name,
+                                          category = "documents",
+                                          icon = "gtk-new")
+        self.template_file = template_file
+        self.add_action(TemplateAction(template_file))
+
+    def get_hash(self):
+        return self.template_file.uri
+
+class TemplateHandler(deskbar.interfaces.Module):
+
+    INFOS = {"icon": deskbar.core.Utils.load_icon("text-x-generic-template"),
+             "name": _("Templates"),
+             "description": _("Create new files from your templates"),
+             "version": VERSION}
+
+    def __init__(self):
+        deskbar.interfaces.Module.__init__(self)    
+        self.indexer = deskbar.core.Indexer.Indexer()
+
+    def _add_template_file(self, path):
+        template_file = TemplateFile(path)
+        match = TemplateMatch(template_file)
+        self.indexer.add(match.get_name(), match)
+    
+    def _templates_dir_monitor_cb(self, monitor_uri, info_uri, event_type):
+        if event_type == gnomevfs.MONITOR_EVENT_CREATED:
+            # strip "file://"
+            self._add_template_file(info_uri[7:])
+ 
+    def initialize(self):
+        templates_dir = deskbar.core.Utils.get_xdg_user_dir(deskbar.core.Utils.USER_DIR_TEMPLATES)
+
+        for f in os.listdir(templates_dir):
+            self._add_template_file(os.path.join(templates_dir, f))
+
+        gnomevfs.monitor_add(templates_dir,
+                             gnomevfs.MONITOR_DIRECTORY,
+                             self._templates_dir_monitor_cb)
+
+    def query(self, query):
+        matches = self.indexer.look_up(query)
+        self.set_priority_for_matches(matches)
+        self._emit_query_ready(query, matches)
+
Index: deskbar/handlers/Makefile.am
===================================================================
--- deskbar/handlers/Makefile.am	(revision 1779)
+++ deskbar/handlers/Makefile.am	(working copy)
@@ -20,6 +20,7 @@
 	mozilla.py \
 	programs.py \
 	recent.py \
+	templates.py \
 	web_address.py \
 	yahoo.py
 
