[gedit-latex/remove-prefs: 1/3] Seperate tool preferences from preferences



commit d3695d8e1526d503fa7401bfb7cc435707ae854f
Author: John Stowers <john stowers gmail com>
Date:   Mon Jun 27 09:44:04 2011 +1200

    Seperate tool preferences from preferences
    
    	* Migrate tool preferences to GObject signals
    	  for change notification
    	* add @singleton decorator and use that

 latex/base/windowactivatable.py |   16 +--
 latex/preferences/Makefile.am   |    1 +
 latex/preferences/__init__.py   |  260 ++-------------------------------------
 latex/preferences/dialog.py     |   33 +++---
 latex/preferences/tools.py      |  221 +++++++++++++++++++++++++++++++++
 latex/util.py                   |   13 ++
 6 files changed, 270 insertions(+), 274 deletions(-)
---
diff --git a/latex/base/windowactivatable.py b/latex/base/windowactivatable.py
index 72897fe..129d27c 100644
--- a/latex/base/windowactivatable.py
+++ b/latex/base/windowactivatable.py
@@ -28,15 +28,16 @@ import string
 
 logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s	%(name)s - %(message)s")
 
-from ..preferences import Preferences, IPreferencesMonitor
+from ..preferences import Preferences
 from ..preferences.dialog import PreferencesDialog
+from ..preferences.tools import ToolPreferences
 from ..tools import ToolAction
 from ..tools.views import ToolView
 from config import UI, WINDOW_SCOPE_VIEWS, EDITOR_SCOPE_VIEWS, ACTIONS
 from . import File, SideView, BottomView, WindowContext
 from decorators import GeditTabDecorator
 
-class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Configurable, IPreferencesMonitor):
+class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Configurable):
 	__gtype_name__ =  "LaTeXWindowActivatable"
 
 	"""
@@ -67,7 +68,8 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 		Called when the window extension is activated
 		"""
 		self._preferences = Preferences()
-		self._preferences.register_monitor(self)
+		self._tool_preferences = ToolPreferences()
+		self._tool_preferences.connect("tools-changed", self._on_tools_changed)
 		
 		#
 		# initialize context object
@@ -97,7 +99,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 		"""
 		# save preferences and stop listening
 		self._preferences.save()
-		self._preferences.remove_monitor(self)
+		self._tool_preferences.save()
 		
 		# destroy tab decorators
 		self._active_tab_decorator = None
@@ -259,7 +261,7 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 		
 		i = 1					# counting tool actions
 		accel_counter = 1		# counting tool actions without custom accel
-		for tool in self._preferences.tools:
+		for tool in self._tool_preferences.tools:
 			# hopefully unique action name
 			name = "Tool%sAction" % i
 			
@@ -312,10 +314,6 @@ class LaTeXWindowActivatable(GObject.Object, Gedit.WindowActivatable, PeasGtk.Co
 		self._save_action.activate()
 	
 	def _on_tools_changed(self):
-		# FIXME: tools reload doesn't work
-		# UPDATE: should work now
-		
-		# see IPreferencesMonitor._on_tools_changed
 		self._log.debug("_on_tools_changed")
 		
 		# remove tool actions and ui
diff --git a/latex/preferences/Makefile.am b/latex/preferences/Makefile.am
index c845283..b06742d 100644
--- a/latex/preferences/Makefile.am
+++ b/latex/preferences/Makefile.am
@@ -2,6 +2,7 @@ plugindir = $(libdir)/gedit/plugins/latex/preferences
 
 plugin_PYTHON = \
 	dialog.py \
+	tools.py \
 	__init__.py
 
 -include $(top_srcdir)/git.mk
diff --git a/latex/preferences/__init__.py b/latex/preferences/__init__.py
index 12e1efb..9b5cea4 100644
--- a/latex/preferences/__init__.py
+++ b/latex/preferences/__init__.py
@@ -22,11 +22,13 @@
 preferences
 """
 
+from gi.repository import GObject
+
 from logging import getLogger
+import xml.etree.ElementTree as ElementTree
 
 from ..base.resources import find_resource, MODE_READWRITE
-from ..tools import Tool, Job
-from ..tools.postprocess import GenericPostProcessor, RubberPostProcessor, LaTeXPostProcessor
+from ..util import singleton
 
 def str_to_bool(x):
 	"""
@@ -53,42 +55,7 @@ class IPreferencesMonitor(object):
 		A simple key-value-pair has changed
 		"""
 
-	def _on_tools_changed(self):
-		"""
-		The Tools have changed
-		"""
-
-
-# ElementTree is part of Python 2.5
-# TODO: see http://effbot.org/zone/element-index.htm
-import xml.etree.ElementTree as ElementTree
-
-import uuid
-
-
-class ObjectCache(object):
-	"""
-	"""
-	
-	# TODO:
-	
-	def __init__(self):
-		"""
-		"""
-		self.__objects = None
-		self.__ids = None
-	
-	def save(self, id, object):
-		self.__ids[object] = id
-		self.__objects.append(object)
-	
-	def find_id(self, object):
-		return self.__ids[object]
-	
-	def delete(self, id):
-		pass
-
-
+ singleton
 class Preferences(object):
 	"""
 	A simple map storing preferences as key-value-pairs
@@ -96,42 +63,12 @@ class Preferences(object):
 	
 	_log = getLogger("Preferences")
 	
-	# maps names to classes
-	POST_PROCESSORS = {"GenericPostProcessor" : GenericPostProcessor, 
-					   "LaTeXPostProcessor" : LaTeXPostProcessor, 
-					   "RubberPostProcessor" : RubberPostProcessor}
-	
-	def __new__(cls):
-		if not '_instance' in cls.__dict__:
-			cls._instance = object.__new__(cls)
-		return cls._instance
-	
 	def __init__(self):
-		if not '_ready' in dir(self):
-			#
-			# init Preferences singleton
-			#
-			
-#			self.preferences = { "ConnectOutlineToEditor" : True,
-#								 "ErrorBackgroundColor" : "#ffdddd",
-#								 "WarningBackgroundColor" : "#ffffcf",
-#								 "SpellingBackgroundColor" : "#ffeccf",
-#								 "LightForeground" : "#957d47" }
-
-			self.__monitors = []
-			
-			self.__preferences_changed = False
-			self.__tools_changed = False
-			
-			# TODO: use some object cache mechanism instead of those fields
-			self.__tool_objects = None
-			self.__tool_ids = None
-			
-			# parse
-			self.__preferences = ElementTree.parse(find_resource("preferences.xml", MODE_READWRITE)).getroot()
-			self.__tools = ElementTree.parse(find_resource("tools.xml", MODE_READWRITE)).getroot()
-			
-			self._ready = True
+		self.__monitors = []
+		self.__preferences_changed = False
+		self.__preferences = ElementTree.parse(
+						find_resource("preferences.xml", MODE_READWRITE)).getroot()
+		self._log.debug("Constructed")
 	
 	def register_monitor(self, monitor):
 		"""
@@ -139,9 +76,6 @@ class Preferences(object):
 		
 		@param monitor: an object implementing IPreferencesMonitor 
 		"""
-		
-		# TODO: support a flag indicating which parts are to be monitored
-		
 		self.__monitors.append(monitor)
 		
 	def remove_monitor(self, monitor):
@@ -164,9 +98,6 @@ class Preferences(object):
 			return default_value
 		else:
 			return value_element.text
-		
-		# TODO: use this as soon as ElementTree 1.3 is part of Python:
-		#return self.__preferences.findtext(".//value[ key='%s']" % key, default_value)
 	
 	def get_bool(self, key, default_value=None):
 		"""
@@ -175,9 +106,6 @@ class Preferences(object):
 		return str_to_bool(self.get(key, default_value))
 	
 	def __find_value_element(self, key):
-		# TODO: use this as soon as ElementTree 1.3 is part of Python:
-		#value_element = self.__preferences.find(".//value[ key='%s']" % key)
-		
 		for element in self.__preferences.findall("value"):
 			if element.get("key") == key:
 				return element
@@ -197,167 +125,9 @@ class Preferences(object):
 		
 		self.__preferences_changed = True
 		
-		# notify monitors
 		for monitor in self.__monitors:
 			monitor._on_value_changed(key, value)
 	
-	def __notify_tools_changed(self):
-		"""
-		Notify monitors that the Tools have changed
-		"""
-		for monitor in self.__monitors:
-			monitor._on_tools_changed()
-	
-	@property
-	def tools(self):
-		"""
-		Return all Tools
-		"""
-		self.__tool_ids = {}
-		
-		tools = []
-		
-		for tool_element in self.__tools.findall("tool"):
-			jobs = []
-			for job_element in tool_element.findall("job"):
-				jobs.append(Job(job_element.text.strip(), str_to_bool(job_element.get("mustSucceed")), self.POST_PROCESSORS[job_element.get("postProcessor")]))
-			
-			assert not tool_element.get("extensions") is None
-			
-			extensions = tool_element.get("extensions").split()
-			accelerator = tool_element.get("accelerator")
-			id = tool_element.get("id")
-			tool = Tool(tool_element.get("label"), jobs, tool_element.get("description"), accelerator, extensions)
-			self.__tool_ids[tool] = id
-			
-			tools.append(tool)
-			
-		return tools
-	
-	def __find_tool_element(self, id):
-		"""
-		Find the tool element with the given id 
-		"""
-		for element in self.__tools.findall("tool"):
-			if element.get("id") == id:
-				return element
-		self._log.warning("<tool id='%s'> not found" % id)
-		return None
-	
-	def save_or_update_tool(self, tool):
-		"""
-		Save or update the XML subtree for the given Tool
-		
-		@param tool: a Tool object
-		"""
-		tool_element = None
-		if tool in self.__tool_ids:
-			# find tool tag
-			self._log.debug("Tool element found, updating...")
-			
-			id = self.__tool_ids[tool]
-			tool_element = self.__find_tool_element(id)
-		else:
-			# create new tool tag
-			self._log.debug("Creating new Tool...")
-			
-			id = str(uuid.uuid4())		# random UUID
-			self.__tool_ids[tool] = id
-			
-			tool_element = ElementTree.SubElement(self.__tools, "tool")
-			tool_element.set("id", id)
-		
-		tool_element.set("label", tool.label)
-		tool_element.set("description", tool.description)
-		tool_element.set("extensions", " ".join(tool.extensions))
-		if tool.accelerator is None:
-			if "accelerator" in tool_element.attrib.keys():
-				del tool_element.attrib["accelerator"]
-		else:
-			tool_element.set("accelerator", tool.accelerator)
-		
-		# remove all jobs
-		for job_element in tool_element.findall("job"):
-			tool_element.remove(job_element)
-			
-		# append new jobs
-		for job in tool.jobs:
-			job_element = ElementTree.SubElement(tool_element, "job")
-			job_element.set("mustSucceed", str(job.must_succeed))
-			job_element.set("postProcessor", job.post_processor.name)
-			job_element.text = job.command_template
-		
-		self.__tools_changed = True
-		self.__notify_tools_changed()
-	
-	def swap_tools(self, tool_1, tool_2):
-		"""
-		Swap the order of two Tools
-		"""
-		# grab their ids
-		id_1 = self.__tool_ids[tool_1]
-		id_2 = self.__tool_ids[tool_2]
-		
-		if id_1 == id_2:
-			self._log.warning("Two tools have the same id. Please modify tools.xml to have unique id's.")
-			return
-		
-		self._log.debug("Tool IDs are {%s: %s, %s, %s}" % (tool_1.label, id_1, tool_2.label, id_2))
-		
-		tool_element_1 = None
-		tool_element_2 = None
-		
-		# find the XML elements and current indexes of the tools
-		i = 0
-		for tool_element in self.__tools:
-			if tool_element.get("id") == id_1:
-				tool_element_1 = tool_element
-				index_1 = i
-			elif tool_element.get("id") == id_2:
-				tool_element_2 = tool_element
-				index_2 = i
-			
-			if not (tool_element_1 is None or tool_element_2 is None):
-				break
-			
-			i += 1
-		
-		self._log.debug("Found XML elements, indexes are {%s: %s, %s, %s}" % (tool_1.label, index_1, tool_2.label, index_2))
-		
-		# successively replace each of them by the other in the XML model
-		self.__tools.remove(tool_element_1)
-		self.__tools.insert(index_1, tool_element_2)
-		
-		self._log.debug("Replaced first tool by second in list")
-				
-		self.__tools.remove(tool_element_2)
-		self.__tools.insert(index_2, tool_element_1)
-		
-		self._log.debug("Replaced second tool by first in list")
-		
-		# notify changes
-		self.__tools_changed = True
-		self.__notify_tools_changed()
-	
-	def delete_tool(self, tool):
-		"""
-		Delete the given Tool
-		
-		@param tool: a Tool object
-		"""
-		try:
-			id = self.__tool_ids[tool]
-			tool_element = self.__find_tool_element(id)
-			self.__tools.remove(tool_element)
-			
-			del self.__tool_ids[tool]
-			
-			self.__tools_changed = True
-		except KeyError, e:
-			self._log.error("delete_tool: %s" % e)
-		
-		self.__notify_tools_changed()
-	
 	def save(self):
 		"""
 		Save the preferences to XML
@@ -369,12 +139,4 @@ class Preferences(object):
 			tree.write(find_resource("preferences.xml", MODE_READWRITE), encoding="utf-8")
 			
 			self.__preferences_changed = False
-		
-		if self.__tools_changed:
-			self._log.debug("Saving tools...")
-		
-			tree = ElementTree.ElementTree(self.__tools)
-			tree.write(find_resource("tools.xml", MODE_READWRITE), encoding="utf-8")
-			
-			self.__tools_changed = False
-	
\ No newline at end of file
+
diff --git a/latex/preferences/dialog.py b/latex/preferences/dialog.py
index 0097900..b8d67c6 100644
--- a/latex/preferences/dialog.py
+++ b/latex/preferences/dialog.py
@@ -28,7 +28,10 @@ from gi.repository import Gdk
 
 from ..base.resources import find_resource, MODE_READWRITE
 from ..util import GladeInterface
-from . import Preferences, IPreferencesMonitor
+from ..tools import Tool, Job
+
+from . import Preferences
+from .tools import ToolPreferences
 
 def _insert_column_with_attributes(view, pos, title, rend, **kwargs):
 	print kwargs
@@ -98,9 +101,6 @@ class PreferencesColorProxy(object):
 		return "#%02x%02x%02x" % (r, g, b)
 
 
-from ..tools import Tool, Job
-
-
 class ConfigureToolDialog(GladeInterface):
 	"""
 	Wraps the dialog for setting up a Tool
@@ -146,7 +146,7 @@ class ConfigureToolDialog(GladeInterface):
 			
 			tool.jobs = []
 			for row in self._store_job:
-				pp_class = self._preferences.POST_PROCESSORS[row[2]]
+				pp_class = self._tool_preferences.POST_PROCESSORS[row[2]]
 				tool.jobs.append(Job(row[0], row[1], pp_class))
 				
 			tool.extensions = []
@@ -199,7 +199,7 @@ class ConfigureToolDialog(GladeInterface):
 			commandRenderer.connect("edited", self._on_job_command_edited)
 
 			self._store_pp = Gtk.ListStore(str)
-			for p in self._preferences.POST_PROCESSORS.iterkeys():
+			for p in self._tool_preferences.POST_PROCESSORS.iterkeys():
 				self._store_pp.append([p])
 			
 			ppRenderer = Gtk.CellRendererCombo()
@@ -351,7 +351,7 @@ class ConfigureToolDialog(GladeInterface):
 	
 
 
-class PreferencesDialog(GladeInterface, IPreferencesMonitor):
+class PreferencesDialog(GladeInterface):
 	"""
 	This controls the configure dialog
 	"""
@@ -383,6 +383,7 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 			#
 			# tools
 			#
+			self._tool_preferences = ToolPreferences()
 			
 			# grab widgets
 
@@ -398,8 +399,9 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 			_insert_column_with_attributes(self._view_tool, -1, "File Extensions", Gtk.CellRendererText(), text=1)
 			
 			# init tool and listen to tool changes
-			self.__load_tools()
-			self._preferences.register_monitor(self)
+			self._load_tools()
+			self._tool_preferences.connect("tools-changed", self._on_tools_changed)
+
 			
 			# misc
 			check_hide_box = self.find_widget("checkHideBox")
@@ -458,11 +460,10 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 		value = togglebutton.get_active()
 		self._preferences.set("HideBoxWarnings", value)
 	
-	def _on_tools_changed(self):
-		# see IPreferencesMonitor._on_tools_changed
-		self.__load_tools()
+	def _on_tools_changed(self, tools):
+		self._load_tools()
 	
-	def __load_tools(self):
+	def _load_tools(self):
 		# save cursor
 		store, iter = self._view_tool.get_selection().get_selected()
 		if iter is None:
@@ -473,7 +474,7 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 		
 		# reload tools
 		self._store_tool.clear()
-		for tool in self._preferences.tools:
+		for tool in self._tool_preferences.tools:
 			self._store_tool.append(["<b>%s</b>" % tool.label, ", ".join(tool.extensions), tool])
 		
 		# restore cursor
@@ -527,7 +528,7 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 		tool_2 = store.get_value(iter_next, 2)
 		
 		# swap tools in preferences
-		self._preferences.swap_tools(tool_1, tool_2)
+		self._tool_preferences.swap_tools(tool_1, tool_2)
 		
 		# adjust selection
 		self._view_tool.get_selection().select_path(str(index_next))
@@ -538,7 +539,7 @@ class PreferencesDialog(GladeInterface, IPreferencesMonitor):
 		tool = Tool("New Tool", [], "", [".tex"])
 		
 		if not dialog.run(tool) is None:
-			self._preferences.save_or_update_tool(tool)
+			self._tool_preferences.save_or_update_tool(tool)
 	
 	def _on_delete_bib_clicked(self, button):
 		pass
diff --git a/latex/preferences/tools.py b/latex/preferences/tools.py
new file mode 100644
index 0000000..74fbbba
--- /dev/null
+++ b/latex/preferences/tools.py
@@ -0,0 +1,221 @@
+# -*- coding: utf-8 -*-
+
+# This file is part of the Gedit LaTeX Plugin
+#
+# Copyright (C) 2010 Michael Zeising
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public Licence as published by the Free Software
+# Foundation; either version 2 of the Licence, 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 Licence for more 
+# details.
+#
+# You should have received a copy of the GNU General Public Licence along with
+# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+# Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+from gi.repository import GObject
+
+from logging import getLogger
+from uuid import uuid4
+import xml.etree.ElementTree as ElementTree
+
+from ..base.resources import find_resource, MODE_READWRITE
+from ..tools import Tool, Job
+from ..tools.postprocess import GenericPostProcessor, RubberPostProcessor, LaTeXPostProcessor
+from ..util import singleton
+from . import str_to_bool
+
+ singleton
+class ToolPreferences(GObject.GObject):
+
+	__gsignals__ = {
+		"tools-changed": (
+			GObject.SignalFlags.RUN_LAST, None, []),
+	}
+
+	_log = getLogger("ToolPreferences")
+
+	# maps names to classes
+	POST_PROCESSORS = {"GenericPostProcessor" : GenericPostProcessor, 
+					   "LaTeXPostProcessor" : LaTeXPostProcessor, 
+					   "RubberPostProcessor" : RubberPostProcessor}
+
+	def __init__(self):
+		GObject.GObject.__init__(self)
+		self.__tool_objects = None
+		self.__tool_ids = None
+		self.__tools_changed = False
+		self.__tools = ElementTree.parse(
+							find_resource("tools.xml", MODE_READWRITE)).getroot()
+		self._log.debug("Constructed")
+
+	def __notify_tools_changed(self):
+		self.emit("tools-changed")
+	
+	@property
+	def tools(self):
+		"""
+		Return all Tools
+		"""
+		self.__tool_ids = {}
+		
+		tools = []
+		
+		for tool_element in self.__tools.findall("tool"):
+			jobs = []
+			for job_element in tool_element.findall("job"):
+				jobs.append(Job(job_element.text.strip(), str_to_bool(job_element.get("mustSucceed")), self.POST_PROCESSORS[job_element.get("postProcessor")]))
+			
+			assert not tool_element.get("extensions") is None
+			
+			extensions = tool_element.get("extensions").split()
+			accelerator = tool_element.get("accelerator")
+			id = tool_element.get("id")
+			tool = Tool(tool_element.get("label"), jobs, tool_element.get("description"), accelerator, extensions)
+			self.__tool_ids[tool] = id
+			
+			tools.append(tool)
+			
+		return tools
+	
+	def __find_tool_element(self, id):
+		"""
+		Find the tool element with the given id 
+		"""
+		for element in self.__tools.findall("tool"):
+			if element.get("id") == id:
+				return element
+		self._log.warning("<tool id='%s'> not found" % id)
+		return None
+	
+	def save_or_update_tool(self, tool):
+		"""
+		Save or update the XML subtree for the given Tool
+		
+		@param tool: a Tool object
+		"""
+		tool_element = None
+		if tool in self.__tool_ids:
+			# find tool tag
+			self._log.debug("Tool element found, updating...")
+			
+			id = self.__tool_ids[tool]
+			tool_element = self.__find_tool_element(id)
+		else:
+			# create new tool tag
+			self._log.debug("Creating new Tool...")
+			
+			id = str(uuid4())
+			self.__tool_ids[tool] = id
+			
+			tool_element = ElementTree.SubElement(self.__tools, "tool")
+			tool_element.set("id", id)
+		
+		tool_element.set("label", tool.label)
+		tool_element.set("description", tool.description)
+		tool_element.set("extensions", " ".join(tool.extensions))
+		if tool.accelerator is None:
+			if "accelerator" in tool_element.attrib.keys():
+				del tool_element.attrib["accelerator"]
+		else:
+			tool_element.set("accelerator", tool.accelerator)
+		
+		# remove all jobs
+		for job_element in tool_element.findall("job"):
+			tool_element.remove(job_element)
+			
+		# append new jobs
+		for job in tool.jobs:
+			job_element = ElementTree.SubElement(tool_element, "job")
+			job_element.set("mustSucceed", str(job.must_succeed))
+			job_element.set("postProcessor", job.post_processor.name)
+			job_element.text = job.command_template
+		
+		self.__tools_changed = True
+		self.__notify_tools_changed()
+	
+	def swap_tools(self, tool_1, tool_2):
+		"""
+		Swap the order of two Tools
+		"""
+		# grab their ids
+		id_1 = self.__tool_ids[tool_1]
+		id_2 = self.__tool_ids[tool_2]
+		
+		if id_1 == id_2:
+			self._log.warning("Two tools have the same id. Please modify tools.xml to have unique id's.")
+			return
+		
+		self._log.debug("Tool IDs are {%s: %s, %s, %s}" % (tool_1.label, id_1, tool_2.label, id_2))
+		
+		tool_element_1 = None
+		tool_element_2 = None
+		
+		# find the XML elements and current indexes of the tools
+		i = 0
+		for tool_element in self.__tools:
+			if tool_element.get("id") == id_1:
+				tool_element_1 = tool_element
+				index_1 = i
+			elif tool_element.get("id") == id_2:
+				tool_element_2 = tool_element
+				index_2 = i
+			
+			if not (tool_element_1 is None or tool_element_2 is None):
+				break
+			
+			i += 1
+		
+		self._log.debug("Found XML elements, indexes are {%s: %s, %s, %s}" % (tool_1.label, index_1, tool_2.label, index_2))
+		
+		# successively replace each of them by the other in the XML model
+		self.__tools.remove(tool_element_1)
+		self.__tools.insert(index_1, tool_element_2)
+		
+		self._log.debug("Replaced first tool by second in list")
+				
+		self.__tools.remove(tool_element_2)
+		self.__tools.insert(index_2, tool_element_1)
+		
+		self._log.debug("Replaced second tool by first in list")
+		
+		# notify changes
+		self.__tools_changed = True
+		self.__notify_tools_changed()
+	
+	def delete_tool(self, tool):
+		"""
+		Delete the given Tool
+		
+		@param tool: a Tool object
+		"""
+		try:
+			id = self.__tool_ids[tool]
+			tool_element = self.__find_tool_element(id)
+			self.__tools.remove(tool_element)
+			
+			del self.__tool_ids[tool]
+			
+			self.__tools_changed = True
+		except KeyError, e:
+			self._log.error("delete_tool: %s" % e)
+		
+		self.__notify_tools_changed()
+
+	def save(self):
+		"""
+		Save the preferences to XML
+		"""
+		if self.__tools_changed:
+			self._log.debug("Saving tools...")
+		
+			tree = ElementTree.ElementTree(self.__tools)
+			tree.write(find_resource("tools.xml", MODE_READWRITE), encoding="utf-8")
+			
+			self.__tools_changed = False
+	
diff --git a/latex/util.py b/latex/util.py
index c83e76a..77b8119 100644
--- a/latex/util.py
+++ b/latex/util.py
@@ -28,6 +28,19 @@ the project
 import logging
 from gi.repository import GdkPixbuf
 
+def singleton(cls):
+	"""
+	Singleton decorator that works with GObject derived types. The 'recommended'
+	python one - http://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
+	does not (interacts badly with GObjectMeta
+	"""
+	instances = {}
+	def getinstance():
+		if cls not in instances:
+			instances[cls] = cls()
+		return instances[cls]
+	return getinstance
+
 def require(arg_name, *allowed_types):
 	"""
 	Type-checking decorator (see http://code.activestate.com/recipes/454322/)



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