Implemented most of the functionality.

Fri, 18 Apr 2014 19:45:32 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 18 Apr 2014 19:45:32 +0200
changeset 1
a9f6842a18f6
parent 0
96fac1d8181f
child 2
024ba1836a94

Implemented most of the functionality.

.hgignore file | annotate | diff | comparison | revisions
PluginSelectionEncloser.py file | annotate | diff | comparison | revisions
SelectionEncloser.e4p file | annotate | diff | comparison | revisions
SelectionEncloser/ConfigurationPage/SelectionEncloserPage.py file | annotate | diff | comparison | revisions
SelectionEncloser/ConfigurationPage/SelectionEncloserPage.ui file | annotate | diff | comparison | revisions
SelectionEncloser/ConfigurationPage/__init__.py file | annotate | diff | comparison | revisions
SelectionEncloser/__init__.py file | annotate | diff | comparison | revisions
SelectionEncloser/icons/selectionEncloser.png file | annotate | diff | comparison | revisions
SelectionEncloser/icons/topAdd.png file | annotate | diff | comparison | revisions
__init__.py file | annotate | diff | comparison | revisions
diff -r 96fac1d8181f -r a9f6842a18f6 .hgignore
--- a/.hgignore	Fri Apr 18 16:15:44 2014 +0200
+++ b/.hgignore	Fri Apr 18 19:45:32 2014 +0200
@@ -15,3 +15,4 @@
 glob:tmp
 glob:__pycache__
 glob:**.DS_Store
+glob:**Ui_*.py
diff -r 96fac1d8181f -r a9f6842a18f6 PluginSelectionEncloser.py
--- a/PluginSelectionEncloser.py	Fri Apr 18 16:15:44 2014 +0200
+++ b/PluginSelectionEncloser.py	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,313 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the Selection Encloser plug-in.
+"""
+
+from __future__ import unicode_literals    # __IGNORE_WARNING__
+
+import os
+import json
+
+from PyQt4.QtCore import QObject, QTranslator, QCoreApplication
+from PyQt4.QtGui import QAction, QMenu
+
+from E5Gui.E5Application import e5App
+
+import Preferences
+
+# Start-Of-Header
+name = "Selection Encloser Plug-in"
+author = "Detlev Offenbach <detlev@die-offenbachs.de>"
+autoactivate = True
+deactivateable = True
+version = "0.1.0"
+className = "SelectionEncloserPlugin"
+packageName = "SelectionEncloser"
+shortDescription = "Enclose the selection with a string."
+longDescription = \
+    """This plug-in implements a tool to enclose the selection of""" \
+    """ the current editor with a string. The enclosing string is""" \
+    """ selectable via a configurable menu hierarchy."""
+needsRestart = False
+pyqtApi = 2
+python2Compatible = True
+# End-Of-Header
+
+error = ""
+
+selectionEncloserPluginObject = None
+    
+
+def createSelectionEncloserPage(configDlg):
+    """
+    Module function to create the Selection Encloser configuration page.
+    
+    @param configDlg reference to the configuration dialog
+    @return reference to the configuration page
+    """
+    global selectionEncloserPluginObject
+    from SelectionEncloser.ConfigurationPage.SelectionEncloserPage import \
+        SelectionEncloserPage
+    page = SelectionEncloserPage(selectionEncloserPluginObject)
+    return page
+    
+
+def getConfigData():
+    """
+    Module function returning data as required by the configuration dialog.
+    
+    @return dictionary containing the relevant data
+    """
+    if e5App().getObject("UserInterface").versionIsNewer('5.2.99', '20121012'):
+        return {
+            "selectionEncloserPage": [
+                QCoreApplication.translate("SelectionEncloserPlugin",
+                                           "Selection Encloser"),
+                os.path.join("SelectionEncloser", "icons",
+                             "selectionEncloser.png"),
+                createSelectionEncloserPage, None, None],
+        }
+    else:
+        return {}
+
+
+def prepareUninstall():
+    """
+    Module function to prepare for an uninstallation.
+    """
+    Preferences.Prefs.settings.remove(SelectionEncloserPlugin.PreferencesKey)
+
+
+class SelectionEncloserPlugin(QObject):
+    """
+    Class implementing the Selection Encloser plugin.
+    """
+    PreferencesKey = "SelectionEncloser"
+    
+    def __init__(self, ui):
+        """
+        Constructor
+        
+        @param ui reference to the user interface object (UI.UserInterface)
+        """
+        QObject.__init__(self, ui)
+        self.__ui = ui
+        
+        # menu is a list of lists; each list consists of a string for the
+        # submenu title and a list of submenu entries. The title of the submenu
+        # entry is the enclosing string.
+        defaultMenu = [
+            [self.tr("Quotes"), ['"', "'", '"""', "'''"]],
+        ]
+        self.__defaults = {
+            "MenuHierarchy": json.dumps(defaultMenu),
+        }
+        
+        self.__translator = None
+        self.__loadTranslator()
+        
+        self.__initMenu()
+        
+        self.__editors = {}
+    
+    def activate(self):
+        """
+        Public method to activate this plugin.
+        
+        @return tuple of None and activation status (boolean)
+        """
+        global error
+        error = ""     # clear previous error
+        
+        global selectionEncloserPluginObject
+        selectionEncloserPluginObject = self
+        
+        self.__ui.showMenu.connect(self.__populateMenu)
+        
+        e5App().getObject("ViewManager").editorOpenedEd.connect(
+            self.__editorOpened)
+        e5App().getObject("ViewManager").editorClosedEd.connect(
+            self.__editorClosed)
+        
+        for editor in e5App().getObject("ViewManager").getOpenEditors():
+            self.__editorOpened(editor)
+        
+        return None, True
+    
+    def deactivate(self):
+        """
+        Public method to deactivate this plugin.
+        """
+        self.__ui.showMenu.disconnect(self.__populateMenu)
+        
+        e5App().getObject("ViewManager").editorOpenedEd.disconnect(
+            self.__editorOpened)
+        e5App().getObject("ViewManager").editorClosedEd.disconnect(
+            self.__editorClosed)
+        
+        for editor, acts in self.__editors.items():
+            menu = editor.getMenu("Tools")
+            if menu is not None:
+                for act in acts:
+                    menu.removeAction(act)
+        self.__editors = {}
+    
+    def __loadTranslator(self):
+        """
+        Private method to load the translation file.
+        """
+        if self.__ui is not None:
+            loc = self.__ui.getLocale()
+            if loc and loc != "C":
+                locale_dir = os.path.join(
+                    os.path.dirname(__file__), "SelectionEncloser", "i18n")
+                translation = "selectionencloser_{0}".format(loc)
+                translator = QTranslator(None)
+                loaded = translator.load(translation, locale_dir)
+                if loaded:
+                    self.__translator = translator
+                    e5App().installTranslator(self.__translator)
+                else:
+                    print("Warning: translation file '{0}' could not be"
+                          " loaded.".format(translation))
+                    print("Using default.")
+    
+    def getPreferences(self, key):
+        """
+        Public method to retrieve the various settings.
+        
+        @param key the key of the value to get (string)
+        @return the requested setting
+        """
+        if key in ["MenuHierarchy"]:
+            return json.loads(
+                Preferences.Prefs.settings.value(
+                    self.PreferencesKey + "/" + key, self.__defaults[key]))
+        else:
+            return Preferences.Prefs.settings.value(
+                self.PreferencesKey + "/" + key, self.__defaults[key])
+    
+    def setPreferences(self, key, value):
+        """
+        Public method to store the various settings.
+        
+        @param key the key of the setting to be set (string)
+        @param value the value to be set
+        """
+        if key in ["MenuHierarchy"]:
+            Preferences.Prefs.settings.setValue(
+                self.PreferencesKey + "/" + key, json.dumps(value))
+        else:
+            Preferences.Prefs.settings.setValue(
+                self.PreferencesKey + "/" + key, value)
+    
+    def __initMenu(self):
+        """
+        Private method to initialize the menu.
+        """
+        self.__menu = QMenu("Enclose Selection")
+        self.__menu.setEnabled(False)
+        self.__menu.aboutToShow.connect(self.__showMenu)
+    
+    def __populateMenu(self, name, menu):
+        """
+        Private slot to populate the tools menu with our entry.
+        
+        @param name name of the menu (string)
+        @param menu reference to the menu to be populated (QMenu)
+        """
+        if name != "Tools":
+            return
+        
+        editor = e5App().getObject("ViewManager").activeWindow()
+        
+        if not menu.isEmpty():
+            menu.addSeparator()
+        
+        act = menu.addMenu(self.__menu)
+        act.setEnabled(editor is not None and editor.hasSelectedText())
+    
+    def __editorOpened(self, editor):
+        """
+        Private slot called, when a new editor was opened.
+        
+        @param editor reference to the new editor (QScintilla.Editor)
+        """
+        menu = editor.getMenu("Tools")
+        if menu is not None:
+            self.__editors[editor] = []
+            if not menu.isEmpty():
+                act = menu.addSeparator()
+                self.__editors[editor].append(act)
+            act = menu.addMenu(self.__menu)
+            self.__menu.setEnabled(True)
+            self.__editors[editor].append(act)
+            editor.showMenu.connect(self.__editorShowMenu)
+    
+    def __editorClosed(self, editor):
+        """
+        Private slot called, when an editor was closed.
+        
+        @param editor reference to the editor (QScintilla.Editor)
+        """
+        try:
+            del self.__editors[editor]
+            if not self.__editors:
+                self.__menu.setEnabled(False)
+        except KeyError:
+            pass
+    
+    def __editorShowMenu(self, menuName, menu, editor):
+        """
+        Private slot called, when the the editor context menu or a submenu is
+        about to be shown.
+        
+        @param menuName name of the menu to be shown (string)
+        @param menu reference to the menu (QMenu)
+        @param editor reference to the editor
+        """
+        if menuName == "Tools":
+            for act in self.__editors[editor]:
+                if not act.isSeparator():
+                    act.setEnabled(editor.hasSelectedText())
+    
+    def __showMenu(self):
+        """
+        Private slot to build the menu hierarchy.
+        """
+        self.__menu.clear()
+        hierarchy = self.getPreferences("MenuHierarchy")
+        for menuTitle, entries in hierarchy:
+            submenu = QMenu(menuTitle, self.__menu)
+            for entry in entries:
+                act = submenu.addAction(entry, self.__encloseSelection)
+                act.setData(entry)
+            self.__menu.addMenu(submenu)
+    
+    def __encloseSelection(self):
+        """
+        Private slot to enclose the selection with the selected string.
+        """
+        act = self.sender()
+        if act is None or not isinstance(act, QAction):
+            return
+        
+        editor = e5App().getObject("ViewManager").activeWindow()
+        if editor is None:
+            return
+        
+        if not editor.hasSelectedText():
+            return
+        
+        string = act.data()
+        if not string:
+            return
+        
+        newText = string + editor.selectedText() + string
+        editor.beginUndoAction()
+        editor.replaceSelectedText(newText)
+        editor.endUndoAction()
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser.e4p
--- a/SelectionEncloser.e4p	Fri Apr 18 16:15:44 2014 +0200
+++ b/SelectionEncloser.e4p	Fri Apr 18 19:45:32 2014 +0200
@@ -12,16 +12,24 @@
   <Author>Detlev Offenbach</Author>
   <Email>detlev@die-offenbachs.de</Email>
   <TranslationPattern>SelectionEncloser/i18n/selectionencloser_%language%.ts</TranslationPattern>
+  <Eol index="-1"/>
   <Sources>
     <Source>__init__.py</Source>
     <Source>PluginSelectionEncloser.py</Source>
+    <Source>SelectionEncloser/__init__.py</Source>
+    <Source>SelectionEncloser/ConfigurationPage/__init__.py</Source>
+    <Source>SelectionEncloser/ConfigurationPage/SelectionEncloserPage.py</Source>
   </Sources>
-  <Forms/>
+  <Forms>
+    <Form>SelectionEncloser/ConfigurationPage/SelectionEncloserPage.ui</Form>
+  </Forms>
   <Translations/>
   <Resources/>
   <Interfaces/>
   <Others>
     <Other>.hgignore</Other>
+    <Other>SelectionEncloser/icons/topAdd.png.png</Other>
+    <Other>SelectionEncloser/icons/selectionEncloser.png</Other>
   </Others>
   <MainScript>PluginSelectionEncloser.py</MainScript>
   <Vcs>
@@ -141,5 +149,6 @@
     <FiletypeAssociation pattern="*.ts" type="TRANSLATIONS"/>
     <FiletypeAssociation pattern="*.ui" type="FORMS"/>
     <FiletypeAssociation pattern="*.ui.h" type="FORMS"/>
+    <FiletypeAssociation pattern="Ui_*.py" type="__IGNORE__"/>
   </FiletypeAssociations>
 </Project>
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/ConfigurationPage/SelectionEncloserPage.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SelectionEncloser/ConfigurationPage/SelectionEncloserPage.py	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,167 @@
+# -*- coding: utf-8 -*-
+
+"""
+Module implementing Selection Encloser configuration page.
+"""
+
+from __future__ import unicode_literals    # __IGNORE_WARNING__
+
+import os
+
+from PyQt4.QtCore import pyqtSlot, Qt
+from PyQt4.QtGui import QTreeWidgetItem, QInputDialog, QLineEdit
+
+from Preferences.ConfigurationPages.ConfigurationPageBase import \
+    ConfigurationPageBase
+from .Ui_SelectionEncloserPage import Ui_SelectionEncloserPage
+
+import UI.PixmapCache
+
+
+class SelectionEncloserPage(ConfigurationPageBase, Ui_SelectionEncloserPage):
+    """
+    Class implementing Selection Encloser configuration page.
+    """
+    def __init__(self, plugin):
+        """
+        Constructor
+        
+        @param plugin reference to the plugin object
+        """
+        super(SelectionEncloserPage, self).__init__()
+        self.setupUi(self)
+        self.setObjectName("SelectionEncloserPage")
+        
+        self.addButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
+        self.deleteButton.setIcon(UI.PixmapCache.getIcon("minus.png"))
+        self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow.png"))
+        self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow.png"))
+        self.addMenuButton.setIcon(UI.PixmapCache.getIcon(
+            os.path.join("SelectionEncloser", "icons", "topAdd.png")))
+        
+        self.addButton.setEnabled(False)
+        self.deleteButton.setEnabled(False)
+        self.upButton.setEnabled(False)
+        self.downButton.setEnabled(False)
+        
+        self.__plugin = plugin
+        
+        # set initial values
+        hierarchy = self.__plugin.getPreferences("MenuHierarchy")
+        for menuTitle, entries in hierarchy:
+            top = QTreeWidgetItem(self.menuTree, [menuTitle])
+            top.setFlags(top.flags() | Qt.ItemIsEditable)
+            for entry in entries:
+                itm = QTreeWidgetItem(top, [entry])
+                itm.setFlags(itm.flags() | Qt.ItemIsEditable)
+            top.setExpanded(True)
+    
+    def save(self):
+        """
+        Public slot to save the Selection Encloser configuration.
+        """
+        hierarchy = []
+        for topIndex in range(self.menuTree.topLevelItemCount()):
+            topItem = self.menuTree.topLevelItem(topIndex)
+            topEntry = [topItem.text(0), []]
+            for index in range(topItem.childCount()):
+                itm = topItem.child(index)
+                topEntry[1].append(itm.text(0))
+            hierarchy.append(topEntry)
+        self.__plugin.setPreferences("MenuHierarchy", hierarchy)
+    
+    @pyqtSlot()
+    def on_addMenuButton_clicked(self):
+        """
+        Private slot to add a top level menu item.
+        """
+        menuTitle, ok = QInputDialog.getText(
+            self,
+            self.tr("Menu Title"),
+            self.tr("Enter menu title:"),
+            QLineEdit.Normal)
+        if ok and menuTitle:
+            top = QTreeWidgetItem(self.menuTree, [menuTitle])
+            top.setFlags(top.flags() | Qt.ItemIsEditable)
+            top.setExpanded(True)
+    
+    @pyqtSlot()
+    def on_addButton_clicked(self):
+        """
+        Private slot to add a menu entry.
+        """
+        entry, ok = QInputDialog.getText(
+            self,
+            self.tr("Menu Entry"),
+            self.tr("Enter menu entry text:"),
+            QLineEdit.Normal)
+        if ok and entry:
+            itm = QTreeWidgetItem(self.menuTree.selectedItems()[0], [entry])
+            itm.setFlags(itm.flags() | Qt.ItemIsEditable)
+    
+    @pyqtSlot()
+    def on_deleteButton_clicked(self):
+        """
+        Private slot to delete the selected entry.
+        """
+        itm = self.menuTree.selectedItems()[0]
+        parent = itm.parent()
+        if parent is None:
+            index = self.menuTree.indexOfTopLevelItem(itm)
+            self.menuTree.takeTopLevelItem(index)
+        else:
+            index = parent.indexOfChild(itm)
+            parent.takeChild(index)
+        del itm
+    
+    @pyqtSlot()
+    def on_upButton_clicked(self):
+        """
+        Slot documentation goes here.
+        """
+        # TODO: not implemented yet
+        raise NotImplementedError
+    
+    @pyqtSlot()
+    def on_downButton_clicked(self):
+        """
+        Slot documentation goes here.
+        """
+        # TODO: not implemented yet
+        raise NotImplementedError
+    
+    @pyqtSlot()
+    def on_menuTree_itemSelectionChanged(self):
+        """
+        Private slot handling the selection of an item.
+        """
+        if len(self.menuTree.selectedItems()) == 0:
+            self.addButton.setEnabled(False)
+            self.deleteButton.setEnabled(False)
+            self.upButton.setEnabled(False)
+            self.downButton.setEnabled(False)
+        else:
+            addEnable = True
+            upEnable = True
+            downEnable = True
+            itm = self.menuTree.selectedItems()[0]
+            parent = itm.parent()
+            if parent is None:
+                # top level item
+                if self.menuTree.indexOfTopLevelItem(itm) == 0:
+                    upEnable = False
+                if self.menuTree.indexOfTopLevelItem(itm) == \
+                        self.menuTree.topLevelItemCount() - 1:
+                    downEnable = False
+            else:
+                # sub item
+                if parent.indexOfChild(itm) == 0:
+                    upEnable = False
+                if parent.indexOfChild(itm) == \
+                        parent.childCount() - 1:
+                    downEnable = False
+                addEnable = False
+            self.addButton.setEnabled(addEnable)
+            self.deleteButton.setEnabled(True)
+            self.upButton.setEnabled(upEnable)
+            self.downButton.setEnabled(downEnable)
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/ConfigurationPage/SelectionEncloserPage.ui
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SelectionEncloser/ConfigurationPage/SelectionEncloserPage.ui	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SelectionEncloserPage</class>
+ <widget class="QWidget" name="SelectionEncloserPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>482</width>
+    <height>363</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="headerLabel">
+     <property name="text">
+      <string>&lt;b&gt;Configure Selection Encloser&lt;/b&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line15">
+     <property name="frameShape">
+      <enum>QFrame::HLine</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Sunken</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Menu Hierarchy:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0" rowspan="6">
+      <widget class="QTreeWidget" name="menuTree">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="headerHidden">
+        <bool>true</bool>
+       </property>
+       <column>
+        <property name="text">
+         <string notr="true">1</string>
+        </property>
+       </column>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QToolButton" name="addMenuButton">
+       <property name="toolTip">
+        <string>Press to add a new top level menu item</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QToolButton" name="addButton">
+       <property name="toolTip">
+        <string>Press to add a new menu item</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QToolButton" name="deleteButton">
+       <property name="toolTip">
+        <string>Press to delete the selected item</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QToolButton" name="upButton">
+       <property name="toolTip">
+        <string>Press to move the selected entry up</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QToolButton" name="downButton">
+       <property name="toolTip">
+        <string>Press to move the selected entry down</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="1">
+      <spacer name="verticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>40</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>menuTree</tabstop>
+  <tabstop>addMenuButton</tabstop>
+  <tabstop>addButton</tabstop>
+  <tabstop>deleteButton</tabstop>
+  <tabstop>upButton</tabstop>
+  <tabstop>downButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/ConfigurationPage/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SelectionEncloser/ConfigurationPage/__init__.py	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the Selection Encloser plug-in configuration page.
+"""
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SelectionEncloser/__init__.py	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the Selection Encloser plug-in data and configuration
+dialog.
+"""
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/icons/selectionEncloser.png
Binary file SelectionEncloser/icons/selectionEncloser.png has changed
diff -r 96fac1d8181f -r a9f6842a18f6 SelectionEncloser/icons/topAdd.png
Binary file SelectionEncloser/icons/topAdd.png has changed
diff -r 96fac1d8181f -r a9f6842a18f6 __init__.py
--- a/__init__.py	Fri Apr 18 16:15:44 2014 +0200
+++ b/__init__.py	Fri Apr 18 19:45:32 2014 +0200
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+
+"""
+Package implementing the Selection Encloser plug-in.
+"""

eric ide

mercurial