Implemented the wizard dialog.

Sun, 29 Dec 2013 19:41:52 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 29 Dec 2013 19:41:52 +0100
changeset 1
2fa6997ff09c
parent 0
3ad485fab7d4
child 2
f33d9d82ae69

Implemented the wizard dialog.

.hgignore file | annotate | diff | comparison | revisions
PluginWizardDataUriEncoder.e4p file | annotate | diff | comparison | revisions
PluginWizardDataUriEncoder.py file | annotate | diff | comparison | revisions
WizardDataUriEncoder/DataUriEncoderWizardDialog.py file | annotate | diff | comparison | revisions
WizardDataUriEncoder/DataUriEncoderWizardDialog.ui file | annotate | diff | comparison | revisions
WizardDataUriEncoder/__init__.py file | annotate | diff | comparison | revisions
__init__.py file | annotate | diff | comparison | revisions
--- a/.hgignore	Sun Dec 29 15:40:19 2013 +0100
+++ b/.hgignore	Sun Dec 29 19:41:52 2013 +0100
@@ -15,3 +15,4 @@
 glob:tmp
 glob:__pycache__
 glob:**.DS_Store
+glob:**Ui_*.py
--- a/PluginWizardDataUriEncoder.e4p	Sun Dec 29 15:40:19 2013 +0100
+++ b/PluginWizardDataUriEncoder.e4p	Sun Dec 29 19:41:52 2013 +0100
@@ -6,7 +6,7 @@
   <Hash>2144bd61ef339d39bc1790af5e236aaa2a8828ac</Hash>
   <ProgLanguage mixed="0">Python3</ProgLanguage>
   <ProjectType>E4Plugin</ProjectType>
-  <Description>Plug-in implementing a wizard for the generation of code base64 encoded data URIs.</Description>
+  <Description>Plug-in implementing a wizard for the generation of code for base64 encoded data URIs.</Description>
   <Version>0.1</Version>
   <Author>Detlev Offenbach</Author>
   <Email>detlevqdie-offenbachs.de</Email>
@@ -15,13 +15,18 @@
   <Sources>
     <Source>__init__.py</Source>
     <Source>PluginWizardDataUriEncoder.py</Source>
+    <Source>WizardDataUriEncoder/__init__.py</Source>
+    <Source>WizardDataUriEncoder/DataUriEncoderWizardDialog.py</Source>
   </Sources>
-  <Forms/>
+  <Forms>
+    <Form>WizardDataUriEncoder/DataUriEncoderWizardDialog.ui</Form>
+  </Forms>
   <Translations/>
   <Resources/>
   <Interfaces/>
   <Others>
     <Other>.hgignore</Other>
+    <Other>PluginWizardDataUriEncoder.e4p</Other>
   </Others>
   <MainScript>PluginWizardDataUriEncoder.py</MainScript>
   <Vcs>
@@ -141,5 +146,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>
--- a/PluginWizardDataUriEncoder.py	Sun Dec 29 15:40:19 2013 +0100
+++ b/PluginWizardDataUriEncoder.py	Sun Dec 29 19:41:52 2013 +0100
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the base64 data URI encoder wizard plug-in.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt4.QtCore import QObject, QTranslator
+from PyQt4.QtGui import QDialog
+
+from E5Gui.E5Application import e5App
+from E5Gui.E5Action import E5Action
+from E5Gui import E5MessageBox
+
+# Start-of-Header
+name = "Base64 Data URI Encoder Wizard Plug-in"
+author = "Detlev Offenbach <detlev@die-offenbachs.de>"
+autoactivate = True
+deactivateable = True
+version = "0.1.0"
+className = "WizardDataUriEncoderPlugin"
+packageName = "WizardDataUriEncoder"
+shortDescription = "Wizard for the creation of code for a base64 data URI."
+longDescription = \
+    """This plug-in implements a wizard to generate code for""" \
+    """ base64 encoded data URIs."""
+needsRestart = False
+pyqtApi = 2
+# End-of-Header
+
+error = ""
+
+
+class WizardDataUriEncoderPlugin(QObject):
+    """
+    Class implementing the base64 data URI encoder wizard plug-in.
+    """
+    def __init__(self, ui):
+        """
+        Constructor
+        
+        @param ui reference to the user interface object (UI.UserInterface)
+        """
+        QObject.__init__(self, ui)
+        self.__ui = ui
+        self.__action = None
+        
+        self.__translator = None
+        self.__loadTranslator()
+    
+    def __initialize(self):
+        """
+        Private slot to (re)initialize the plug-in.
+        """
+        self.__act = None
+    
+    def activate(self):
+        """
+        Public method to activate this plug-in.
+        
+        @return tuple of None and activation status (boolean)
+        """
+        self.__initAction()
+        self.__initMenu()
+        
+        return None, True
+    
+    def deactivate(self):
+        """
+        Public method to deactivate this plug-in.
+        """
+        menu = self.__ui.getMenu("wizards")
+        if menu:
+            menu.removeAction(self.__action)
+        self.__ui.removeE5Actions([self.__action], 'wizards')
+    
+    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__), "WizardDataUriEncoder", "i18n")
+                translation = "datauriencoder_{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 __initAction(self):
+        """
+        Private method to initialize the action.
+        """
+        self.__action = E5Action(
+            self.trUtf8('Base64 Data Uri Encoder Wizard'),
+            self.trUtf8('Base&64 Data Uri Encoder Wizard...'),
+            0, 0, self,
+            'wizards_datauriencoder')
+        self.__action.setStatusTip(self.trUtf8('.desktop Wizard'))
+        self.__action.setWhatsThis(self.trUtf8(
+            """<b>Base64 Data Uri Encoder Wizard</b>"""
+            """<p>This wizard opens a dialog for entering all the parameters"""
+            """ needed to create code for a base64 encoded data URI.</p>"""
+        ))
+        self.__action.triggered[()].connect(self.__handle)
+        
+        self.__ui.addE5Actions([self.__action], 'wizards')
+
+    def __initMenu(self):
+        """
+        Private method to add the actions to the right menu.
+        """
+        menu = self.__ui.getMenu("wizards")
+        if menu:
+            menu.addAction(self.__action)
+    
+    def __handle(self):
+        """
+        Private method to handle the wizards action.
+        """
+        editor = e5App().getObject("ViewManager").activeWindow()
+        
+        if editor is None:
+                E5MessageBox.critical(
+                    self.__ui,
+                    self.trUtf8('No current editor'),
+                    self.trUtf8('Please open or create a file first.'))
+        else:
+            from WizardDataUriEncoder.DataUriEncoderWizardDialog import \
+                DataUriEncoderWizardDialog
+            dlg = DataUriEncoderWizardDialog(None)
+            if dlg.exec_() == QDialog.Accepted:
+                code = dlg.getCode()
+                if code:
+                    line, index = editor.getCursorPosition()
+                    # It should be done on this way to allow undo
+                    editor.beginUndoAction()
+                    editor.insertAt(code, line, index)
+                    editor.endUndoAction()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WizardDataUriEncoder/DataUriEncoderWizardDialog.py	Sun Dec 29 19:41:52 2013 +0100
@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+
+"""
+Module implementing DataUriEncoderWizardDialog.
+"""
+
+import os
+import mimetypes
+import base64
+import getpass
+import datetime
+
+from PyQt4.QtCore import pyqtSlot
+from PyQt4.QtGui import QDialog, QDialogButtonBox, QApplication, QInputDialog
+
+from E5Gui.E5Completers import E5FileCompleter
+from E5Gui import E5FileDialog, E5MessageBox
+
+from .Ui_DataUriEncoderWizardDialog import Ui_DataUriEncoderWizardDialog
+
+import Preferences
+import Utilities
+import UI.PixmapCache
+
+
+Python2Template = """#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from base64 import b64decode
+from cStringIO import StringIO
+
+#metadata
+__author__ = '{0}'
+__date__ = '{1}'
+
+
+embedded_file = StringIO(b64decode({2}))
+print(embedded_file.read())
+"""
+
+
+Python3Template = """#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from base64 import b64decode
+from io import BytesIO
+
+#metadata
+__author__ = '{0}'
+__date__ = '{1}'
+
+
+embedded_file = BytesIO(b64decode({2}))
+print(embedded_file.read())
+"""
+
+
+class DataUriEncoderWizardDialog(QDialog, Ui_DataUriEncoderWizardDialog):
+    """
+    Class documentation goes here.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
+        
+        self.__fileCompleter = E5FileCompleter(self.fileEdit)
+        
+        self.fileButton.setIcon(UI.PixmapCache.getIcon("open.png"))
+        
+        self.embeddingComboBox.addItems([
+            self.tr('Do not generate code'),
+            self.tr('Generate CSS embed code'),
+            self.tr('Generate Python3 embed code'),
+            self.tr('Generate Python2 embed code'),
+            self.tr('Generate HTML embed code'),
+            self.tr('Generate JS embed code'),
+            self.tr('Generate QML embed code'),
+        ])
+    
+    def __getStartDir(self):
+        """
+        Private method to get the start directory for selection dialogs.
+        
+        @return start directory (string)
+        """
+        return (Preferences.getMultiProject("Workspace") or
+                Utilities.getHomeDir())
+    
+    @pyqtSlot()
+    def on_fileButton_clicked(self):
+        """
+        Private slot to select the file to be encoded via a selection dialog.
+        """
+        start = Utilities.fromNativeSeparators(self.fileEdit.text()) or \
+            self.__getStartDir()
+        inputFile = E5FileDialog.getOpenFileName(
+            self,
+            self.trUtf8("Data URI Encoder"),
+            start,
+            self.trUtf8(
+                "Audio Files (*.flac *.mp3 *.ogg *.wav *.weba *.wma);;"
+                "Image Files (*.gif *.ico *.jpg *.png *.svg *.tif *.webp"
+                " *.xpm);;"
+                "Video Files (*.3gp *.avi *.flv *.mp4 *.ogv *.webm *.wmv);;"
+                "All Files (*)"
+            )
+        )
+        if inputFile:
+            self.fileEdit.setText(Utilities.toNativeSeparators(inputFile))
+    
+    @pyqtSlot(int)
+    def on_embeddingComboBox_currentIndexChanged(self, index):
+        """
+        Private slot to handle the selection of an embedding method.
+        
+        @param index index of the selected entry (integer)
+        """
+        if index in [1, 4]:
+            self.encryptCheckBox.setChecked(False)
+            self.dataCheckBox.setChecked(True)
+        elif index in [2, 3, 5, 6]:
+            self.encryptCheckBox.setChecked(False)
+            self.dataCheckBox.setChecked(False)
+    
+    @pyqtSlot()
+    def on_encodeButton_clicked(self):
+        """
+        Private slot to encode the contents of the given file.
+        """
+        filepath = Utilities.toNativeSeparators(self.fileEdit.text().strip())
+        mime = mimetypes.guess_type(filepath, strict=False)
+        mimetype = mime if mime is not None else self.__askMime()
+        
+        if os.path.getsize(filepath) // 1024 // 1024 >= 1:
+            res = E5MessageBox.warning(
+                self,
+                self.trUtf8("Data URI Encoder"),
+                self.trUtf8(
+                    """The file size is > 1 Megabyte. Encoding this will"""
+                    """ take some time depending on your CPU processing"""
+                    """ power!"""),
+                E5MessageBox.StandardButtons(
+                    E5MessageBox.Cancel |
+                    E5MessageBox.Ok),
+                E5MessageBox.Cancel)
+            if res == E5MessageBox.Cancel:
+                return
+        
+        try:
+            output = '"{0}{1}{2}{3}"'.format(
+                'data:' if self.dataCheckBox.isChecked() else '',
+                mimetype if self.dataCheckBox.isChecked() else '',
+                ';charset=utf-8;base64,' if self.dataCheckBox.isChecked()
+                    else '',
+                base64.b64encode(open(filepath, "rb").read()).decode()
+            )
+        except (IOError, OSError) as err:
+            E5MessageBox.critical(
+                self,
+                self.trUtf8("Data URI Encoder"),
+                self.trUtf8(
+                    """<p>The file <b>{0}</b> could not be read.</p>"""
+                    """<p>Reason: {1}</p>""").format(filepath, str(err)))
+            return
+        if self.embeddingComboBox.currentIndex() == 1:
+            output = ('html, body {{ margin:0; padding:0; background: url({0})'
+                      ' no-repeat center center fixed; background-size:cover'
+                      ' }}'.format(output))
+        elif self.embeddingComboBox.currentIndex() == 2:
+            output = Python3Template.format(
+                getpass.getuser(),
+                datetime.datetime.now().isoformat().split('.')[0], output)
+        elif self.embeddingComboBox.currentIndex() == 3:
+            output = Python2Template.format(
+                getpass.getuser(),
+                datetime.datetime.now().isoformat().split('.')[0], output)
+        elif self.embeddingComboBox.currentIndex() == 4:
+            output = '<img src={0} alt="{1}" title="{1}"/>'.format(
+                output, os.path.basename(filepath))
+        elif self.embeddingComboBox.currentIndex() == 5:
+            output = 'var embedded_file = window.atob({0}); '.format(output)
+        elif self.embeddingComboBox.currentIndex() == 6:
+            output = 'Image {{ source: {0} }} '.format(output)
+        
+        if self.encryptCheckBox.isChecked():
+            output = output.encode('rot_13')
+        
+        self.outputTextEdit.setPlainText(output)
+    
+    @pyqtSlot()
+    def on_copyButton_clicked(self):
+        """
+        Private slot to copy the output to the clipboard.
+        """
+        QApplication.clipboard().setText(self.outputTextEdit.toPlainText())
+    
+    @pyqtSlot()
+    def on_outputTextEdit_textChanged(self):
+        """
+        Private slot to handle the existence of some output text.
+        """
+        enable = bool(self.outputTextEdit.toPlainText())
+        self.copyButton.setEnabled(enable)
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable)
+    
+    @pyqtSlot(str)
+    def on_fileEdit_textChanged(self, txt):
+        """
+        Private slot to handle the editing of the file name.
+        
+        @param txt current file name (string)
+        """
+        self.encodeButton.setEnabled(bool(txt) and os.path.isfile(txt))
+    
+    def __askMime(self):
+        """
+        Private method to get the mime type from the user.
+        
+        @return entered mime type (string)
+        """
+        mimetypesList = [""] + list(sorted(
+            set(mimetypes.types_map.values()).union( 
+                set(mimetypes.common_types.values()))))
+        try:
+            index = mimetypesList.index("application/octet-stream")
+        except ValueError:
+            index = 0
+        mimetype, ok = QInputDialog.getItem(
+            self,
+            self.trUtf8("Data URI Encoder"),
+            self.trUtf8("Enter a mime type:"),
+            mimetypesList,
+            index, True)
+        if ok:
+            return mimetype.lower()
+        else:
+            return ""
+    
+    def getCode(self):
+        """
+        Public method to get the code.
+        
+        @return generated code (string)
+        """
+        return self.outputTextEdit.toPlainText()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WizardDataUriEncoder/DataUriEncoderWizardDialog.ui	Sun Dec 29 19:41:52 2013 +0100
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DataUriEncoderWizardDialog</class>
+ <widget class="QDialog" name="DataUriEncoderWizardDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>700</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Data URI Encoder</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="3">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&lt;b&gt;Encode file as plain text string&lt;/b&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>File to Encode:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QLineEdit" name="fileEdit">
+     <property name="toolTip">
+      <string>Enter the file to be encoded</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="QToolButton" name="fileButton">
+     <property name="toolTip">
+      <string>Select the file to be encoded</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="3">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QCheckBox" name="dataCheckBox">
+       <property name="text">
+        <string>Use &quot;data:type/subtype;base64,...&quot;</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QCheckBox" name="encryptCheckBox">
+       <property name="toolTip">
+        <string>Select to encrypt the output with 'rot_13' (use &quot;string&quot;.decode(rot_13) to decrypt it)</string>
+       </property>
+       <property name="text">
+        <string>Use basic Caesar Cipher (rot_13)</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="3" column="0">
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>Embedding Template Code:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1" colspan="2">
+    <widget class="QComboBox" name="embeddingComboBox">
+     <property name="toolTip">
+      <string>Select the embedding method</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0" colspan="3">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="encodeButton">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="text">
+        <string>Encode BASE64</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item row="5" column="0" colspan="3">
+    <widget class="Line" name="line">
+     <property name="lineWidth">
+      <number>2</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="0" colspan="3">
+    <widget class="QLabel" name="label_4">
+     <property name="text">
+      <string>Base64 String Output:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="0" colspan="3">
+    <widget class="QPlainTextEdit" name="outputTextEdit">
+     <property name="readOnly">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="0" colspan="3">
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QPushButton" name="copyButton">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="toolTip">
+        <string>Press to copy the encoded output to the system clipboard</string>
+       </property>
+       <property name="text">
+        <string>Copy encoded output to Clipboard</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item row="9" column="0" colspan="3">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>fileEdit</tabstop>
+  <tabstop>fileButton</tabstop>
+  <tabstop>dataCheckBox</tabstop>
+  <tabstop>encryptCheckBox</tabstop>
+  <tabstop>embeddingComboBox</tabstop>
+  <tabstop>encodeButton</tabstop>
+  <tabstop>outputTextEdit</tabstop>
+  <tabstop>copyButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DataUriEncoderWizardDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>DataUriEncoderWizardDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WizardDataUriEncoder/__init__.py	Sun Dec 29 19:41:52 2013 +0100
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the base64 data URI encoder wizard plug-in data
+and dialog.
+"""
--- a/__init__.py	Sun Dec 29 15:40:19 2013 +0100
+++ b/__init__.py	Sun Dec 29 19:41:52 2013 +0100
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the base64 data URI encoder wizard plug-in.
+"""

eric ide

mercurial