[kupfer: 5/20] plugins: adjust to Kupfer's standarts



commit a1cd9c404a3d0c3816cb903265d2a7df578d7eab
Author: KarolBedkowski <karol bedkowsk+gh gmail com>
Date:   Sun Oct 4 22:21:18 2009 +0200

    plugins: adjust to Kupfer's standarts
    For clawsmail, putty, tscclient, zim:
    - using FilesystemWatchMixin (except zim)
    - use launch_commandline instead of spawn_async
    - use output_error instead of print
    - use more specific exception
    - checking whether the file and dirs exists before open or lsdir
    - correct names, strings, imports, etc
    - reformat code

 kupfer/plugin/clawsmail.py |  108 +++++++++++++++++++++-----------------
 kupfer/plugin/putty.py     |   47 +++++++++--------
 kupfer/plugin/tsclient.py  |   48 ++++++++++-------
 kupfer/plugin/zim.py       |  124 ++++++++++++++++++++++++++++++--------------
 4 files changed, 199 insertions(+), 128 deletions(-)
---
diff --git a/kupfer/plugin/clawsmail.py b/kupfer/plugin/clawsmail.py
index 804224d..89cd12d 100644
--- a/kupfer/plugin/clawsmail.py
+++ b/kupfer/plugin/clawsmail.py
@@ -4,18 +4,30 @@ import re
 import urllib
 from xml.dom import minidom
 
-from kupfer.objects import Leaf, Action, Source, TextLeaf, UrlLeaf, RunnableLeaf
-from kupfer.utils import spawn_async
+from kupfer.objects import Leaf, Action, Source, TextLeaf, UrlLeaf, RunnableLeaf, FilesystemWatchMixin
+from kupfer import utils
 
-__kupfer_name__ = _("ClawsMail contacts actions")
+__kupfer_name__ = _("Claws Mail")
 __kupfer_sources__ = ("ClawsContactsSource", )
-__description__ = _("Contacts from ClawsMail")
-__version__ = "0.1"
+__kupfer_actions__ = ("NewMailAction", )
+__description__ = _("Claws Mail Contacts and Actions")
+__version__ = "0.2"
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
 
 
+def _get_email_from_url(url):
+	''' convert http://foo bar pl -> foo bar pl '''
+	sep = url.find('://')
+	return url[sep+3:] if sep > -1 else url
 
-class ClawsContactLeaf(Leaf):
+_CHECK_EMAIL_RE = re.compile(r"^[a-z0-9\ _%-+]+\ [a-z0-9 _%-]+\ [a-z]{2,6}$")
+
+def _check_email(email):
+	''' simple email check '''
+	return len(email) > 7 and _CHECK_EMAIL_RE.match(email.lower()) is not None
+
+
+class ClawsContact(Leaf):
 	''' Leaf represent single contact from Claws address book '''
 	def get_actions(self):
 		yield NewMailAction()
@@ -27,28 +39,28 @@ class ClawsContactLeaf(Leaf):
 		return "stock_person"
 
 
-class ComposeMailAction(RunnableLeaf):
+class ComposeMail(RunnableLeaf):
 	''' Create new mail without recipient '''
 	def __init__(self):
-		RunnableLeaf.__init__(self, name=_("Compose new mail"))
+		RunnableLeaf.__init__(self, name=_("Compose New Mail"))
 
 	def run(self):
-		spawn_async(('claws-mail', '--compose'))
+		utils.launch_commandline('claws-mail --compose')
 
 	def get_description(self):
-		return _("Compose new mail with ClawsMail")
+		return _("Compose New Mail with Claws Mail")
 
 	def get_icon_name(self):
 		return "stock_mail-compose"
 
 
-class ReceiveMailAction(RunnableLeaf):
+class ReceiveMail(RunnableLeaf):
 	''' Receive all new mail from all accounts '''
 	def __init__(self):
-		RunnableLeaf.__init__(self, name=_("Receive all mails"))
+		RunnableLeaf.__init__(self, name=_("Receive All Mails"))
 
 	def run(self):
-		spawn_async(('claws-mail', '--receive-all'))
+		utils.launch_commandline('claws-mail --receive-all')
 
 	def get_description(self):
 		return _("Receive new mail from all accounts by ClawsMail")
@@ -58,61 +70,61 @@ class ReceiveMailAction(RunnableLeaf):
 
 
 class NewMailAction(Action):
-	''' Createn new mail to selected leaf (ClawsContactLeaf or TextLeaf)'''
+	''' Createn new mail to selected leaf (ClawsContact or TextLeaf)'''
 	def __init__(self):
-		Action.__init__(self, _('Write new mail'))
+		Action.__init__(self, _('Compose New Mail to'))
 
 	def activate(self, leaf):
 		email = leaf.object
 		if isinstance(leaf, UrlLeaf):
-			email = NewMailAction._get_email_from_url(email)
+			email = _get_email_from_url(email)
 
-		spawn_async(("claws-mail", "--compose", str(email)))
+		utils.launch_commandline("claws-mail --compose '%s'" % email)
 
 	def get_icon_name(self):
 		return 'stock_mail-compose'
 
 	def item_types(self):
-		yield ClawsContactLeaf
+		yield ClawsContact
 		# we can enter email
 		yield TextLeaf
 		yield UrlLeaf
 
 	def valid_for_item(self, item):
-		if isinstance(item, ClawsContactLeaf):
+		if isinstance(item, ClawsContact):
 			return True
 
-		if isinstance(item, TextLeaf):
-			return ClawsContactLeaf._check_email(self.object)
+		elif isinstance(item, TextLeaf):
+			return _check_email(item.object)
 
 		elif isinstance(item, UrlLeaf):
-			url = NewMailAction._get_email_from_url(item.object)
-			return ClawsContactLeaf._check_email(url)
+			url = _get_email_from_url(item.object)
+			return _check_email(url)
 
 		return False
 
-	@staticmethod
-	def _get_email_from_url(url):
-		sep = url.find('://')
-		return url[sep+3:] if sep > -1 else url
-
-	@staticmethod
-	def _check_email(email):
-		return len(email) > 7 and re.match(r"^[a-z0-9\ _%-+]+\ [a-z0-9 _%-]+\ [a-z]{2,6}$", email.lower()) is not None
-
 
-
-class ClawsContactsSource(Source):
-	def __init__(self, name=_("Claws contacts")):
+class ClawsContactsSource(Source, FilesystemWatchMixin):
+	def __init__(self, name=_("Claws Mail Address Book")):
 		Source.__init__(self, name)
 		self._claws_addrbook_dir = os.path.expanduser('~/.claws-mail/addrbook')
-		self._claws_addrbook_index = os.path.join(self._claws_addrbook_dir, "addrbook--index.xml")
+		self._claws_addrbook_index = os.path.join(self._claws_addrbook_dir, \
+				"addrbook--index.xml")
+		self.unpickle_finish()
 
-	def is_dynamic(self):
-		return False
+	def unpickle_finish(self):
+		if not os.path.isdir(self._claws_addrbook_dir):
+			return
+
+		self.monitor_token = self.monitor_directories(self._claws_addrbook_dir)
+
+	def monitor_include_file(self, gfile):
+		# monitor only addrbook-*.xml files
+		return gfile and gfile.get_basename().endswith('.xml') and \
+				gfile.get_basename().startswith("addrbook-")
 
 	def get_items(self):
-		if os.path.exists(self._claws_addrbook_index):
+		if os.path.isfile(self._claws_addrbook_index):
 			for addrbook_file in self._load_address_books():
 				addrbook_filepath = os.path.join(self._claws_addrbook_dir, addrbook_file)
 				if not os.path.exists(addrbook_filepath):
@@ -126,22 +138,22 @@ class ClawsContactsSource(Source):
 						addresses = person.getElementsByTagName('address')
 						for address in addresses:
 							email = address.getAttribute('email')
-							yield ClawsContactLeaf(email, cn)
+							yield ClawsContact(email, cn)
 
-				except Exception, err:
-					print err
+				except StandardError, err:
+					self.output_error(err)
 
-		yield ComposeMailAction()
-		yield ReceiveMailAction()
+		yield ComposeMail()
+		yield ReceiveMail()
 
 	def get_description(self):
-		return _("Session saved in Putty")
+		return _("Contacts from Claw Mail Address Book")
 
 	def get_icon_name(self):
 		return "claws-mail"
 
 	def provides(self):
-		yield ClawsContactLeaf
+		yield ClawsContact
 		yield RunnableLeaf
 
 	def _load_address_books(self):
@@ -151,8 +163,8 @@ class ClawsContactsSource(Source):
 			for book in dtree.getElementsByTagName('book'):
 				yield book.getAttribute('file')
 
-		except Exception, err:
-			print err
+		except StandardError, err:
+			self.output_error(err)
 
 
 
diff --git a/kupfer/plugin/putty.py b/kupfer/plugin/putty.py
index c30a2f8..d29cbdf 100644
--- a/kupfer/plugin/putty.py
+++ b/kupfer/plugin/putty.py
@@ -4,18 +4,17 @@ from __future__ import with_statement
 import os
 import urllib
 
-from kupfer.objects import Leaf, Action, Source
-from kupfer.utils import spawn_async
+from kupfer.objects import Leaf, Action, Source, TextSource, FilesystemWatchMixin
+from kupfer import utils
 
-__kupfer_name__ = _("PuTTY sessions")
+__kupfer_name__ = _("PuTTY Sessions")
 __kupfer_sources__ = ("PuttySessionSource", )
-__description__ = _("Session saved in PuTTY")
-__version__ = "0.1"
+__description__ = _("Quick access to PuTTY Sessions")
+__version__ = "0.2"
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
 
 
-
-class PuttySessionLeaf(Leaf):
+class PuttySession(Leaf):
 	""" Leaf represent session saved in PuTTy"""
 
 	def __init__(self, name, description):
@@ -32,31 +31,32 @@ class PuttySessionLeaf(Leaf):
 		return "computer"
 
 
-
 class PuttyOpenSession(Action):
 	''' opens putty session '''
 	def __init__(self):
-		super(PuttyOpenSession, self).__init__(_('Open PuTTy session'))
+		Action.__init__(self, _('Start PuTTY Session'))
 
 	def activate(self, leaf):
-		cli = ("putty", "-load", leaf.object)
-		spawn_async(cli)
+		utils.launch_commandline("putty -load '%s'" % leaf.object)
 
 	def get_icon_name(self):
 		return 'putty'
 
 
-
-class PuttySessionSource(Source):
+class PuttySessionSource(Source, FilesystemWatchMixin):
 	''' indexes session saved in putty '''
-	def __init__(self, name=_("PuTTy Session")):
+	def __init__(self, name=_("PuTTY Sessions")):
 		super(PuttySessionSource, self).__init__(name)
 		self._putty_sessions_dir = os.path.expanduser('~/.putty/sessions')
+		self.unpickle_finish()
 
-	def is_dynamic(self):
-		return True
+	def unpickle_finish(self):
+		self.monitor_token = self.monitor_directories(self._putty_sessions_dir)
 
 	def get_items(self):
+		if not os.path.isdir(self._putty_sessions_dir):
+			return
+
 		for filename in os.listdir(self._putty_sessions_dir):
 			if filename == 'Default%20Settings':
 				continue
@@ -65,7 +65,7 @@ class PuttySessionSource(Source):
 			if os.path.isfile(obj_path):
 				name = urllib.unquote(filename)
 				description = self._load_host_from_session_file(obj_path)
-				yield PuttySessionLeaf(name, description)
+				yield PuttySession(name, description)
 
 	def get_description(self):
 		return _("Session saved in Putty")
@@ -74,7 +74,7 @@ class PuttySessionSource(Source):
 		return "putty"
 
 	def provides(self):
-		yield PuttySessionLeaf
+		yield PuttySession
 
 	def _load_host_from_session_file(self, filepath):
 		user = None
@@ -84,15 +84,18 @@ class PuttySessionSource(Source):
 				for line in session_file:
 					if line.startswith('HostName='):
 						host = line.split('=', 2)[1].strip()
+
 					elif line.startswith('UserName='):
 						user = line.split('=', 2)[1].strip()
-		except Exception, err:
-			print err
+
+		except IOError, err:
+			self.output_error(err)
 
 		else:
-			return user + '@' + host if user else host
+			if host:
+				return unicode(user + '@' + host if user else host)
 
-		return 'PuTTY session'
+		return u'PuTTY Session'
 
 
 
diff --git a/kupfer/plugin/tsclient.py b/kupfer/plugin/tsclient.py
index ded1e7a..c6f05d4 100644
--- a/kupfer/plugin/tsclient.py
+++ b/kupfer/plugin/tsclient.py
@@ -3,18 +3,18 @@ from __future__ import with_statement
 
 import os
 
-from kupfer.objects import Leaf, Action, Source
-from kupfer.utils import spawn_async
+from kupfer.objects import Leaf, Action, Source, FilesystemWatchMixin
+from kupfer import utils
 
 __kupfer_name__ = _("Terminal Server Client")
 __kupfer_sources__ = ("TsclientSessionSource", )
-__description__ = _("Session saved in Terminam Server Client")
-__version__ = "0.1"
+__description__ = _("Session saved in Terminal Server Client")
+__version__ = "0.2"
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
 
 
 
-class TsclientSessionLeaf(Leaf):
+class TsclientSession(Leaf):
 	""" Leaf represent session saved in Tsclient"""
 
 	def __init__(self, obj_path, name, description):
@@ -31,31 +31,38 @@ class TsclientSessionLeaf(Leaf):
 		return "computer"
 
 
-
 class TsclientOpenSession(Action):
 	''' opens tsclient session '''
 	def __init__(self):
-		Action.__init__(self, _('Open Terminal Server Client session'))
+		Action.__init__(self, _('Start Terminal Server Session'))
 
 	def activate(self, leaf):
-		cli = ("tsclient", "-x", leaf.object)
-		spawn_async(cli)
+		utils.launch_commandline("tsclient -x '%s'" % leaf.object)
 
 	def get_icon_name(self):
 		return 'tsclient'
 
 
-
-class TsclientSessionSource(Source):
+class TsclientSessionSource(Source, FilesystemWatchMixin):
 	''' indexes session saved in tsclient '''
 	def __init__(self, name=_("TSClient sessions")):
 		Source.__init__(self, name)
 		self._sessions_dir = os.path.expanduser('~/.tsclient')
+		self.unpickle_finish()
+
+	def unpickle_finish(self):
+		if not os.path.isdir(self._sessions_dir):
+			return
+
+		self.monitor_token = self.monitor_directories(self._sessions_dir)
 
-	def is_dynamic(self):
-		return False
+	def monitor_include_file(self, gfile):
+		return gfile and gfile.get_basename().endswith('.rdp')
 
 	def get_items(self):
+		if not os.path.isdir(self._sessions_dir):
+			return
+
 		for filename in os.listdir(self._sessions_dir):
 			if not filename.endswith('.rdp'):
 				continue
@@ -64,7 +71,7 @@ class TsclientSessionSource(Source):
 			if os.path.isfile(obj_path):
 				name = filename[:-4]
 				description = self._load_descr_from_session_file(obj_path)
-				yield TsclientSessionLeaf(obj_path, name, description)
+				yield TsclientSession(obj_path, name, description)
 
 	def get_description(self):
 		return _("Session saved in Terminal Server Client")
@@ -73,7 +80,7 @@ class TsclientSessionSource(Source):
 		return "tsclient"
 
 	def provides(self):
-		yield TsclientSessionLeaf
+		yield TsclientSession
 
 	def _load_descr_from_session_file(self, filepath):
 		user = None
@@ -83,15 +90,18 @@ class TsclientSessionSource(Source):
 				for line in session_file:
 					if line.startswith('full address:s:'):
 						host = line.split(':s:', 2)[1].strip()
+
 					elif line.startswith('username:s:'):
 						user = line.split(':s:', 2)[1].strip()
-		except Exception, err:
-			print err
+
+		except IOError, err:
+			self.output_error(err)
 
 		else:
-			return user + '@' + host if user else host
+			if host:
+				return unicode(user + '@' + host if user else host)
 
-		return 'TSClient; session'
+		return u'Terminal Server Client Session'
 
 
 
diff --git a/kupfer/plugin/zim.py b/kupfer/plugin/zim.py
index 87c1667..b334329 100644
--- a/kupfer/plugin/zim.py
+++ b/kupfer/plugin/zim.py
@@ -3,78 +3,122 @@ from __future__ import with_statement
 
 import os
 
-from kupfer.objects import Leaf, Action, Source, TextLeaf
-from kupfer.utils import spawn_async
+from kupfer.objects import Leaf, Action, Source, TextLeaf, FilesystemWatchMixin, TextSource
+from kupfer import utils
 
-__kupfer_name__ = _("Zim pages")
+__kupfer_name__ = _("Zim")
 __kupfer_sources__ = ("ZimPagesSource", )
-__kupfer_actions__ = ("OpenZimPageAction", )
-__description__ = _("Zim pages")
-__version__ = "0.1"
+__kupfer_actions__ = ("CreateZimPage", )
+__description__ = _("Access to Pages stored in Zim - A Desktop Wiki and Outliner")
+__version__ = "0.2"
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
 
 
+'''
+TODO:
+	use FilesystemWatchMixin (?)
+'''
 
-class ZimPageLeaf(Leaf):
+
+def _start_zim(notebook, page):
+	''' Start zim and open given notebook and page. '''
+	cli = "zim '%s' '%s'" % (notebook, page.replace("'", "_"))
+	utils.launch_commandline(cli)
+
+
+class ZimPage(Leaf):
 	""" Represent single Zim page """
 	def __init__(self, notebook, page):
 		full_name = notebook + " " + page
-		super(ZimPageLeaf, self).__init__(full_name, page)
+		Leaf.__init__(self, full_name, page)
 		self.page = page
 		self.notebook = notebook
 
 	def get_actions(self):
-		yield OpenZimPageAction()
+		yield OpenZimPage()
+		yield CreateZimSubPage()
 
 	def get_description(self):
-		return _('Zim page from notebook "%s"') % self.notebook
+		return _('Zim Page from Notebook "%s"') % self.notebook
 
 	def get_icon_name(self):
 		return "text-x-generic"
 
 
+class CreateZimPage(Action):
+	''' create new page '''
+	rank_adjust = 5
 
-class OpenZimPageAction(Action):
-	""" Open Zim page (or create it) """
 	def __init__(self):
-		super(OpenZimPageAction, self).__init__(_('Open Zim page'))
+		Action.__init__(self, _('Create Zim Page as SubPage of'))
 
-	def activate(self, leaf):
-		if isinstance(leaf, ZimPageLeaf):
-			# leaf are zim pages
-			cli = ("zim", leaf.notebook, leaf.page)
+	def activate(self, leaf, iobj):
+		_start_zim(iobj.notebook, iobj.page + ":" + leaf.object.strip(':'))
+
+	def get_icon_name(self):
+		return 'document-new'
+
+	def item_types(self):
+		yield TextLeaf
+
+	def requires_object(self):
+		return True
+
+	def object_types(self):
+		yield ZimPage
 
-		else:
-			# leaf is enetere text (textleaf)
-			page = leaf.object
-			if page.find(' :') > -1:
-				notebook, page = page.split(' ', 2)
-				cli = ('zim', notebook, str(page))
+	def object_source(self, for_item=None):
+		return ZimPagesSource()
 
-			else:
-				cli = ('zim', '_default_', str(page))
 
-		spawn_async(cli)
+class OpenZimPage(Action):
+	""" Open Zim page  """
+	rank_adjust = 10
+
+	def __init__(self):
+		Action.__init__(self, _('Open Zim Page'))
+
+	def activate(self, leaf):
+		_start_zim(leaf.notebook, leaf.page)
 
 	def get_icon_name(self):
 		return 'document-open'
 
 	def item_types(self):
-		yield ZimPageLeaf
-		yield TextLeaf
+		yield ZimPage
+
+
+class CreateZimSubPage(Action):
+	""" Open Zim page  """
+	def __init__(self):
+		Action.__init__(self, _('Create Zim SubPage'))
+
+	def activate(self, leaf, iobj):
+		_start_zim(leaf.notebook, leaf.page + ":" + iobj.object.strip(':'))
+
+	def get_icon_name(self):
+		return 'document-new'
+
+	def item_types(self):
+		yield ZimPage
 
+	def requires_object(self):
+		return True
+
+	def object_types(self):
+		yield TextLeaf
+	
+	def object_source(self, for_item=None):
+		return TextSource()
 
 
 class ZimPagesSource(Source):
 	''' Index pages in all Zim notebooks '''
-	def __init__(self, name=_("Zim pages")):
-		super(ZimPagesSource, self).__init__(name)
+	def __init__(self, name=_("Zim Pages")):
+		Source.__init__(self, name)
 		# path to file with list notebooks
 		self._zim_notebooks_file = os.path.expanduser('~/.config/zim/notebooks.list')
 
-	def is_dynamic(self):
-		return False
-
 	def get_items(self):
 		for notebook_name, notebook_path in self._get_notebooks():
 			notebook_path_len = len(notebook_path)
@@ -83,17 +127,18 @@ class ZimPagesSource(Source):
 				for filename in files:
 					if filename.endswith('.txt'):
 						file_path = os.path.join(root, filename)
-						page_name = file_path[notebook_path_len:-4].replace(os.path.sep, ':')
-						yield ZimPageLeaf(notebook_name, page_name)
+						page_name = file_path[notebook_path_len:-4]
+						page_name = page_name.replace(os.path.sep, ':').replace('_', ' ')
+						yield ZimPage(notebook_name, page_name)
 
 	def get_description(self):
-		return _("Pages stored in Zim notebooks")
+		return _("Pages stored in Zim Notebooks")
 
 	def get_icon_name(self):
 		return "zim"
 
 	def provides(self):
-		yield ZimPageLeaf
+		yield ZimPage
 
 	def _get_notebooks(self):
 		''' get (notebook name, notebook path) from zim config '''
@@ -104,6 +149,7 @@ class ZimPagesSource(Source):
 						notebook_name, notebook_path = line.strip().split('\t', 2)
 						notebook_path = os.path.expanduser(notebook_path)
 						yield (notebook_name, notebook_path)
-		except Exception, err:
-			print err
+
+		except IOError, err:
+			self.output_error(err)
 



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