Continued porting the Django project plug-in from eric4.

Sat, 23 Mar 2013 19:41:38 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 23 Mar 2013 19:41:38 +0100
changeset 2
1e97424fda0c
parent 1
13a0cced0c6e
child 3
fbae2b012fac

Continued porting the Django project plug-in from eric4.

PluginDjango.e4p file | annotate | diff | comparison | revisions
PluginProjectDjango.py file | annotate | diff | comparison | revisions
ProjectDjango/DjangoDialog.py file | annotate | diff | comparison | revisions
ProjectDjango/DjangoDumpdataDataDialog.py file | annotate | diff | comparison | revisions
ProjectDjango/DjangoDumpdataDataDialog.ui file | annotate | diff | comparison | revisions
ProjectDjango/DjangoLoaddataDataDialog.py file | annotate | diff | comparison | revisions
ProjectDjango/DjangoLoaddataDataDialog.ui file | annotate | diff | comparison | revisions
ProjectDjango/Project.py file | annotate | diff | comparison | revisions
--- a/PluginDjango.e4p	Fri Mar 22 19:26:49 2013 +0100
+++ b/PluginDjango.e4p	Sat Mar 23 19:41:38 2013 +0100
@@ -20,10 +20,14 @@
     <Source>ProjectDjango/ConfigurationPage/DjangoPage.py</Source>
     <Source>ProjectDjango/Project.py</Source>
     <Source>ProjectDjango/DjangoDialog.py</Source>
+    <Source>ProjectDjango/DjangoLoaddataDataDialog.py</Source>
+    <Source>ProjectDjango/DjangoDumpdataDataDialog.py</Source>
   </Sources>
   <Forms>
     <Form>ProjectDjango/ConfigurationPage/DjangoPage.ui</Form>
     <Form>ProjectDjango/DjangoDialog.ui</Form>
+    <Form>ProjectDjango/DjangoDumpdataDataDialog.ui</Form>
+    <Form>ProjectDjango/DjangoLoaddataDataDialog.ui</Form>
   </Forms>
   <Translations/>
   <Resources/>
--- a/PluginProjectDjango.py	Fri Mar 22 19:26:49 2013 +0100
+++ b/PluginProjectDjango.py	Sat Mar 23 19:41:38 2013 +0100
@@ -213,9 +213,12 @@
         e5App().getObject("Project").projectOpenedHooks.connect(
             self.__object.projectOpenedHooks)
         e5App().getObject("Project").projectClosedHooks.connect(
-                     self.__object.projectClosedHooks)
+            self.__object.projectClosedHooks)
         e5App().getObject("Project").newProjectHooks.connect(
-                     self.__object.projectOpenedHooks)
+            self.__object.projectOpenedHooks)
+        
+        e5App().getObject("Project").projectAboutToBeCreated.connect(
+            self.__object.startProjectOrApplication)
         
         return None, True
     
@@ -236,6 +239,9 @@
         e5App().getObject("Project").newProjectHooks.disconnect(
             self.__object.projectOpenedHooks)
         
+        e5App().getObject("Project").projectAboutToBeCreated.disconnect(
+            self.__object.startProjectOrApplication)
+        
         self.__e5project.unregisterProjectType("Django")
         
         self.__object.projectClosedHooks()
--- a/ProjectDjango/DjangoDialog.py	Fri Mar 22 19:26:49 2013 +0100
+++ b/ProjectDjango/DjangoDialog.py	Sat Mar 23 19:41:38 2013 +0100
@@ -250,12 +250,12 @@
             self.fileFilters,
             None)
         
-        if not fname.isEmpty():
+        if fname:
             ext = QFileInfo(fname).suffix()
-            if ext.isEmpty():
-                ex = selectedFilter.section('(*', 1, 1).section(')', 0, 0)
-                if not ex.isEmpty():
-                    fname.append(ex)
+            if not ext:
+                ex = selectedFilter.split("(*")[1].split(")")[0]
+                if ex:
+                    fname += ex
             
             txt = self.resultbox.toPlainText()
             
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectDjango/DjangoDumpdataDataDialog.py	Sat Mar 23 19:41:38 2013 +0100
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the data for the 'dumpdata' command.
+"""
+
+from PyQt4.QtGui import QDialog
+
+from .Ui_DjangoDumpdataDataDialog import Ui_DjangoDumpdataDataDialog
+
+
+class DjangoDumpdataDataDialog(QDialog, Ui_DjangoDumpdataDataDialog):
+    """
+    Class implementing a dialog to enter the data for the 'dumpdata' command.
+    """
+    def __init__(self, project, parent=None):
+        """
+        Constructor
+        
+        @param project reference to the Django project object
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.__project = project
+        if self.__project.getDjangoVersion() < (1, 0):
+            self.excludeGroup.setEnabled(False)
+        
+        apps = self.__project.getRecentApplications()
+        self.applicationsCombo.addItems(apps)
+        self.excludeCombo.addItems(apps)
+        self.excludeCombo.setEditText("")
+        
+        self.formatCombo.addItem(self.trUtf8("JSON"), "json")
+        self.formatCombo.addItem(self.trUtf8("XML"), "xml")
+        try:
+            import yaml     # __IGNORE_WARNING__
+            self.formatCombo.addItem(self.trUtf8("YAML"), "yaml")
+        except ImportError:
+            pass
+    
+    def getData(self):
+        """
+        Public method to get the data entered into the dialog.
+        
+        @return tuple of two lists of strings, a string and an integer giving
+            the list of applications to work on, the list of applications to
+            exclude, the dump format and the indentation level
+        """
+        applStr = self.applicationsCombo.currentText()
+        if applStr:
+            self.__project.setMostRecentApplication(applStr)
+            appls = applStr.split()
+        else:
+            appls = []
+        
+        exclStr = self.excludeCombo.currentText()
+        if exclStr:
+            excl = exclStr.split()
+        else:
+            excl = []
+        
+        format = self.formatCombo.itemData(self.formatCombo.currentIndex())
+        
+        return appls, excl, format, self.indentationSpinBox.value()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectDjango/DjangoDumpdataDataDialog.ui	Sat Mar 23 19:41:38 2013 +0100
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DjangoDumpdataDataDialog</class>
+ <widget class="QDialog" name="DjangoDumpdataDataDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>287</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>dumpdata Command Options</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_4">
+   <property name="spacing">
+    <number>6</number>
+   </property>
+   <property name="margin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QGroupBox" name="applicationsGroup">
+     <property name="title">
+      <string>Applications</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="margin">
+       <number>6</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Enter the list of applications separated by spaces. Leave empty for all.</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="applicationsCombo">
+        <property name="editable">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="excludeGroup">
+     <property name="title">
+      <string>Exclude Applications</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Enter the list of applications separated by spaces.</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="excludeCombo">
+        <property name="editable">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="formatGroup">
+     <property name="title">
+      <string>Dump Format</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Serialization Format:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" colspan="2">
+       <widget class="QComboBox" name="formatCombo">
+        <property name="sizeAdjustPolicy">
+         <enum>QComboBox::AdjustToContents</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>374</width>
+          <height>19</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Indentation Level:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QSpinBox" name="indentationSpinBox">
+        <property name="toolTip">
+         <string>Enter the indentation level to be used when pretty-printing output</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+        <property name="minimum">
+         <number>2</number>
+        </property>
+        <property name="maximum">
+         <number>12</number>
+        </property>
+        <property name="singleStep">
+         <number>2</number>
+        </property>
+        <property name="value">
+         <number>2</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2" colspan="2">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>389</width>
+          <height>18</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <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>applicationsCombo</tabstop>
+  <tabstop>excludeCombo</tabstop>
+  <tabstop>formatCombo</tabstop>
+  <tabstop>indentationSpinBox</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DjangoDumpdataDataDialog</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>DjangoDumpdataDataDialog</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/ProjectDjango/DjangoLoaddataDataDialog.py	Sat Mar 23 19:41:38 2013 +0100
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the data for the 'loaddata' command.
+"""
+
+from PyQt4.QtCore import pyqtSlot
+from PyQt4.QtGui import QDialog, QDialogButtonBox
+
+from E5Gui import E5FileDialog
+
+from .Ui_DjangoLoaddataDataDialog import Ui_DjangoLoaddataDataDialog
+
+import Utilities
+
+
+class DjangoLoaddataDataDialog(QDialog, Ui_DjangoLoaddataDataDialog):
+    """
+    Class implementing a dialog to enter the data for the 'loaddata' command.
+    """
+    def __init__(self, project, parent=None):
+        """
+        Constructor
+        
+        @param project reference to the Django project object
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.__project = project
+        
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
+    
+    @pyqtSlot(str)
+    def on_fixturesEdit_textChanged(self, txt):
+        """
+        Private slot to handle a change of the fixtures text.
+        """
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(bool(txt))
+    
+    @pyqtSlot()
+    def on_fixtureFileButton_clicked(self):
+        """
+        Private slot to select a fixture file via a file selection dialog.
+        """
+        fileFilters = self.trUtf8("JSON Files (*.json);;XML Files (*.xml);;")
+        try:
+            import yaml     # __IGNORE_WARNING__
+            fileFilters += self.trUtf8("YAML Files (*.yaml);;")
+        except ImportError:
+            pass
+        fileFilters += self.trUtf8("All Files (*)")
+        
+        fixtureFiles = E5FileDialog.getOpenFileNames(
+            self,
+            self.trUtf8("Select fixture file"),
+            self.__project.getProjectPath(),
+            fileFilters)
+        
+        if fixtureFiles:
+            self.fixturesEdit.setText(" ".join(
+                [Utilities.toNativeSeparators(f) for f in fixtureFiles]))
+    
+    def getData(self):
+        """
+        Public method to get the data entered into the dialog.
+        
+        @return list of fixtures (list of strings)
+        """
+        fixturesStr = self.fixturesEdit.text()
+        fixtures = fixturesStr.split()
+        
+        return fixtures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectDjango/DjangoLoaddataDataDialog.ui	Sat Mar 23 19:41:38 2013 +0100
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DjangoLoaddataDataDialog</class>
+ <widget class="QDialog" name="DjangoLoaddataDataDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>102</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>loaddata Command Options</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Enter the list of fixture patterns or the path of a fixture file.</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLineEdit" name="fixturesEdit"/>
+   </item>
+   <item row="1" column="1">
+    <widget class="QPushButton" name="fixtureFileButton">
+     <property name="toolTip">
+      <string>Select a fixture file via a file selection dialog</string>
+     </property>
+     <property name="text">
+      <string>...</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <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>fixturesEdit</tabstop>
+  <tabstop>fixtureFileButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DjangoLoaddataDataDialog</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>DjangoLoaddataDataDialog</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>
--- a/ProjectDjango/Project.py	Fri Mar 22 19:26:49 2013 +0100
+++ b/ProjectDjango/Project.py	Sat Mar 23 19:41:38 2013 +0100
@@ -9,12 +9,14 @@
 
 import sys
 import os
+import re
 
-from PyQt4.QtCore import QObject
-from PyQt4.QtGui import QMenu, QInputDialog, QLineEdit
+from PyQt4.QtCore import QObject, QProcess, QTimer, QUrl, QFileInfo
+from PyQt4.QtGui import QMenu, QInputDialog, QLineEdit, QDesktopServices, QDialog, \
+    QFileDialog
 
 from E5Gui.E5Application import e5App
-from E5Gui import E5MessageBox
+from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Action import E5Action
 
 from .DjangoDialog import DjangoDialog
@@ -62,6 +64,9 @@
         """
         Public method to define the Pyramid actions.
         """
+        # TODO: add support for manage.py changepassword
+        # TODO: add support for manage.py createsuperuser
+        # TODO: add support for manage.py clearsession
         self.actions = []
     
         self.selectSiteAct = E5Action(self.trUtf8('Current Project'),
@@ -128,55 +133,54 @@
             self.__startLocalApplication)
         self.actions.append(self.startLocalApplicationAct)
         
-##        ##############################
-##        ## run actions below        ##
-##        ##############################
-##        
-##        self.runServerAct = E4Action(self.trUtf8('Run Server'),
-##                self.trUtf8('Run &Server'), 
-##                0, 0,
-##                self,'django_run_server')
-##        self.runServerAct.setStatusTip(self.trUtf8(
-##            'Starts the Django Web server'))
-##        self.runServerAct.setWhatsThis(self.trUtf8(
-##            """<b>Run Server</b>"""
-##            """<p>Starts the Django Web server using "manage.py runserver".</p>"""
-##        ))
-##        self.connect(self.runServerAct, SIGNAL('triggered()'), self.__runServer)
-##        self.actions.append(self.runServerAct)
-##        
-##        self.runBrowserAct = E4Action(self.trUtf8('Run Web-Browser'),
-##                self.trUtf8('Run &Web-Browser'), 
-##                0, 0,
-##                self,'django_run_browser')
-##        self.runBrowserAct.setStatusTip(self.trUtf8(
-##            'Starts the default Web-Browser with the URL of the Django Web server'))
-##        self.runBrowserAct.setWhatsThis(self.trUtf8(
-##            """<b>Run Web-Browser</b>"""
-##            """<p>Starts the default Web-Browser with the URL of the """
-##            """Django Web server.</p>"""
-##        ))
-##        self.connect(self.runBrowserAct, SIGNAL('triggered()'), self.__runBrowser)
-##        self.actions.append(self.runBrowserAct)
-##        
-##        ##############################
-##        ## caching actions below    ##
-##        ##############################
-##        
-##        self.createCacheTableAct = E4Action(self.trUtf8('Create Cache Tables'),
-##                self.trUtf8('C&reate Cache Tables'), 
-##                0, 0,
-##                self,'django_create_cache_tables')
-##        self.createCacheTableAct.setStatusTip(self.trUtf8(
-##            'Creates the tables needed to use the SQL cache backend'))
-##        self.createCacheTableAct.setWhatsThis(self.trUtf8(
-##            """<b>Create Cache Tables</b>"""
-##            """<p>Creates the tables needed to use the SQL cache backend.</p>"""
-##        ))
-##        self.connect(self.createCacheTableAct, SIGNAL('triggered()'), 
-##            self.__createCacheTables)
-##        self.actions.append(self.createCacheTableAct)
-##        
+        ##############################
+        ## run actions below        ##
+        ##############################
+        
+        self.runServerAct = E5Action(self.trUtf8('Run Server'),
+                self.trUtf8('Run &Server'), 
+                0, 0,
+                self,'django_run_server')
+        self.runServerAct.setStatusTip(self.trUtf8(
+            'Starts the Django Web server'))
+        self.runServerAct.setWhatsThis(self.trUtf8(
+            """<b>Run Server</b>"""
+            """<p>Starts the Django Web server using "manage.py runserver".</p>"""
+        ))
+        self.runServerAct.triggered[()].connect(self.__runServer)
+        self.actions.append(self.runServerAct)
+        
+        self.runBrowserAct = E5Action(self.trUtf8('Run Web-Browser'),
+                self.trUtf8('Run &Web-Browser'), 
+                0, 0,
+                self,'django_run_browser')
+        self.runBrowserAct.setStatusTip(self.trUtf8(
+            'Starts the default Web-Browser with the URL of the Django Web server'))
+        self.runBrowserAct.setWhatsThis(self.trUtf8(
+            """<b>Run Web-Browser</b>"""
+            """<p>Starts the default Web-Browser with the URL of the """
+            """Django Web server.</p>"""
+        ))
+        self.runBrowserAct.triggered[()].connect(self.__runBrowser)
+        self.actions.append(self.runBrowserAct)
+        
+        ##############################
+        ## caching actions below    ##
+        ##############################
+        
+        self.createCacheTableAct = E5Action(self.trUtf8('Create Cache Tables'),
+                self.trUtf8('C&reate Cache Tables'), 
+                0, 0,
+                self,'django_create_cache_tables')
+        self.createCacheTableAct.setStatusTip(self.trUtf8(
+            'Creates the tables needed to use the SQL cache backend'))
+        self.createCacheTableAct.setWhatsThis(self.trUtf8(
+            """<b>Create Cache Tables</b>"""
+            """<p>Creates the tables needed to use the SQL cache backend.</p>"""
+        ))
+        self.createCacheTableAct.triggered[()].connect(self.__createCacheTables)
+        self.actions.append(self.createCacheTableAct)
+        
         ##############################
         ## help action below        ##
         ##############################
@@ -210,351 +214,295 @@
         ))
         self.aboutDjangoAct.triggered[()].connect(self.__djangoInfo)
         self.actions.append(self.aboutDjangoAct)
-##        
-##        self.__initDatabaseActions()
-##        self.__initDatabaseSqlActions()
-##        self.__initToolsActions()
-##        self.__initTestingActions()
-##
-##    def __initDatabaseActions(self):
-##        """
-##        Private method to define the database related actions.
-##        """
-##        self.syncDatabaseAct = E4Action(self.trUtf8('Synchronize'),
-##                self.trUtf8('&Synchronize'), 
-##                0, 0,
-##                self,'django_database_syncdb')
-##        self.syncDatabaseAct.setStatusTip(self.trUtf8(
-##            'Synchronizes the database'))
-##        self.syncDatabaseAct.setWhatsThis(self.trUtf8(
-##            """<b>Synchronize</b>"""
-##            """<p>Synchronizes the database.</p>"""
-##        ))
-##        self.connect(self.syncDatabaseAct, SIGNAL('triggered()'), 
-##            self.__databaseSynchronize)
-##        self.actions.append(self.syncDatabaseAct)
-##        
-##        self.inspectDatabaseAct = E4Action(self.trUtf8('Introspect'),
-##                self.trUtf8('&Introspect'), 
-##                0, 0,
-##                self,'django_database_inspect')
-##        self.inspectDatabaseAct.setStatusTip(self.trUtf8(
-##            'Introspects the database tables and outputs a Django model module'))
-##        self.inspectDatabaseAct.setWhatsThis(self.trUtf8(
-##            """<b>Introspect</b>"""
-##            """<p>Introspects the database tables and outputs a """
-##            """Django model module.</p>"""
-##        ))
-##        self.connect(self.inspectDatabaseAct, SIGNAL('triggered()'), 
-##            self.__databaseInspect)
-##        self.actions.append(self.inspectDatabaseAct)
-##        
-##        self.flushDatabaseAct = E4Action(self.trUtf8('Flush'),
-##                self.trUtf8('&Flush'), 
-##                0, 0,
-##                self,'django_database_flush')
-##        self.flushDatabaseAct.setStatusTip(self.trUtf8(
-##            'Returns all database tables to the state just after their installation'))
-##        self.flushDatabaseAct.setWhatsThis(self.trUtf8(
-##            """<b>Flush</b>"""
-##            """<p>Returns all database tables to the state """
-##            """just after their installation.</p>"""
-##        ))
-##        self.connect(self.flushDatabaseAct, SIGNAL('triggered()'), 
-##            self.__databaseFlush)
-##        self.actions.append(self.flushDatabaseAct)
-##        
-##        self.resetDatabaseAct = E4Action(self.trUtf8('Reset Application(s)'),
-##                self.trUtf8('&Reset Application(s)'), 
-##                0, 0,
-##                self,'django_database_reset_application')
-##        self.resetDatabaseAct.setStatusTip(self.trUtf8(
-##            'Resets the database tables of one or more applications'))
-##        self.resetDatabaseAct.setWhatsThis(self.trUtf8(
-##            """<b>Reset Application(s)</b>"""
-##            """<p>Resets the database tables of one or more applications.</p>"""
-##        ))
-##        self.connect(self.resetDatabaseAct, SIGNAL('triggered()'), 
-##            self.__databaseReset)
-##        self.actions.append(self.resetDatabaseAct)
-##        
-##        self.databaseClientAct = E4Action(self.trUtf8('Start Client Console'),
-##                self.trUtf8('Start &Client Console'), 
-##                0, 0,
-##                self,'django_database_client')
-##        self.databaseClientAct.setStatusTip(self.trUtf8(
-##            'Starts a console window for the database client'))
-##        self.databaseClientAct.setWhatsThis(self.trUtf8(
-##            """<b>Start Client Console</b>"""
-##            """<p>Starts a console window for the database client.</p>"""
-##        ))
-##        self.connect(self.databaseClientAct, SIGNAL('triggered()'), 
-##            self.__runDatabaseClient)
-##        self.actions.append(self.databaseClientAct)
-##    
-##    def __initDatabaseSqlActions(self):
-##        """
-##        Private method to define the database SQL related actions.
-##        """
-##        self.databaseSqlCreateTablesAct = E4Action(self.trUtf8('Create Tables'),
-##                self.trUtf8('Create &Tables'), 
-##                0, 0,
-##                self,'django_database_sql_create_tables')
-##        self.databaseSqlCreateTablesAct.setStatusTip(self.trUtf8(
-##            'Prints the CREATE TABLE SQL statements for one or more applications'))
-##        self.databaseSqlCreateTablesAct.setWhatsThis(self.trUtf8(
-##            """<b>Create Tables</b>"""
-##            """<p>Prints the CREATE TABLE SQL statements for one or """
-##            """more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlCreateTablesAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlCreateTables)
-##        self.actions.append(self.databaseSqlCreateTablesAct)
-##        
-##        self.databaseSqlCreateIndexesAct = E4Action(self.trUtf8('Create Indexes'),
-##                self.trUtf8('Create &Indexes'), 
-##                0, 0,
-##                self,'django_database_sql_create_indexes')
-##        self.databaseSqlCreateIndexesAct.setStatusTip(self.trUtf8(
-##            'Prints the CREATE INDEX SQL statements for one or more applications'))
-##        self.databaseSqlCreateIndexesAct.setWhatsThis(self.trUtf8(
-##            """<b>Create Indexes</b>"""
-##            """<p>Prints the CREATE INDEX SQL statements for one or """
-##            """more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlCreateIndexesAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlCreateIndexes)
-##        self.actions.append(self.databaseSqlCreateIndexesAct)
-##        
-##        self.databaseSqlCreateEverythingAct = E4Action(self.trUtf8('Create Everything'),
-##                self.trUtf8('Create &Everything'), 
-##                0, 0,
-##                self,'django_database_sql_create_everything')
-##        self.databaseSqlCreateEverythingAct.setStatusTip(self.trUtf8(
-##            'Prints the CREATE ... SQL statements for one or more applications'))
-##        self.databaseSqlCreateEverythingAct.setWhatsThis(self.trUtf8(
-##            """<b>Create Everything</b>"""
-##            """<p>Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL """
-##            """statements for one or more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlCreateEverythingAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlCreateEverything)
-##        self.actions.append(self.databaseSqlCreateEverythingAct)
-##        
-##        self.databaseSqlCustomAct = E4Action(self.trUtf8('Custom Statements'),
-##                self.trUtf8('&Custom Statements'), 
-##                0, 0,
-##                self,'django_database_sql_custom')
-##        self.databaseSqlCustomAct.setStatusTip(self.trUtf8(
-##            'Prints the custom table modifying SQL statements for '
-##            'one or more applications'))
-##        self.databaseSqlCustomAct.setWhatsThis(self.trUtf8(
-##            """<b>Custom Statements</b>"""
-##            """<p>Prints the custom table modifying SQL statements """
-##            """for one or more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlCustomAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlCustom)
-##        self.actions.append(self.databaseSqlCustomAct)
-##        
-##        self.databaseSqlDropTablesAct = E4Action(self.trUtf8('Drop Tables'),
-##                self.trUtf8('&Drop Tables'), 
-##                0, 0,
-##                self,'django_database_sql_drop_tables')
-##        self.databaseSqlDropTablesAct.setStatusTip(self.trUtf8(
-##            'Prints the DROP TABLE SQL statements for '
-##            'one or more applications'))
-##        self.databaseSqlDropTablesAct.setWhatsThis(self.trUtf8(
-##            """<b>Drop Tables</b>"""
-##            """<p>Prints the DROP TABLE SQL statements """
-##            """for one or more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlDropTablesAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlDropTables)
-##        self.actions.append(self.databaseSqlDropTablesAct)
-##        
-##        self.databaseSqlFlushAct = E4Action(self.trUtf8('Flush Database'),
-##                self.trUtf8('&Flush Database'), 
-##                0, 0,
-##                self,'django_database_sql_flush_database')
-##        self.databaseSqlFlushAct.setStatusTip(self.trUtf8(
-##            'Prints a list of statements to return all database tables to the state '
-##            'just after their installation'))
-##        self.databaseSqlFlushAct.setWhatsThis(self.trUtf8(
-##            """<b>Flush Database</b>"""
-##            """<p>Prints a list of statements to return all database tables to """
-##            """the state just after their installation.</p>"""
-##        ))
-##        self.connect(self.databaseSqlFlushAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlFlushDatabase)
-##        self.actions.append(self.databaseSqlFlushAct)
-##        
-##        self.databaseSqlResetApplAct = E4Action(self.trUtf8('Reset Application(s)'),
-##                self.trUtf8('Reset &Application(s)'), 
-##                0, 0,
-##                self,'django_database_sql_reset_application')
-##        self.databaseSqlResetApplAct.setStatusTip(self.trUtf8(
-##            'Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for '
-##            'one or more applications'))
-##        self.databaseSqlResetApplAct.setWhatsThis(self.trUtf8(
-##            """<b>Reset Application(s)</b>"""
-##            """<p>Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for """
-##            """one or more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlResetApplAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlResetApplication)
-##        self.actions.append(self.databaseSqlResetApplAct)
-##        
-##        self.databaseSqlResetSeqAct = E4Action(self.trUtf8('Reset Sequences'),
-##                self.trUtf8('Reset &Sequences'), 
-##                0, 0,
-##                self,'django_database_sql_reset_sequences')
-##        self.databaseSqlResetSeqAct.setStatusTip(self.trUtf8(
-##            'Prints the SQL statements for resetting sequences for '
-##            'one or more applications'))
-##        self.databaseSqlResetSeqAct.setWhatsThis(self.trUtf8(
-##            """<b>Reset Sequences</b>"""
-##            """<p>Prints the SQL statements for resetting sequences for """
-##            """one or more applications.</p>"""
-##        ))
-##        self.connect(self.databaseSqlResetSeqAct, SIGNAL('triggered()'), 
-##            self.__databaseSqlResetSequences)
-##        self.actions.append(self.databaseSqlResetSeqAct)
-##    
-##    def __initToolsActions(self):
-##        """
-##        Private method to define the tool actions.
-##        """
-##        self.diffSettingsAct = E4Action(self.trUtf8('Diff Settings'),
-##                self.trUtf8('&Diff Settings'), 
-##                0, 0,
-##                self,'django_tools_diffsettings')
-##        self.diffSettingsAct.setStatusTip(self.trUtf8(
-##            'Shows the modification made to the settings'))
-##        self.diffSettingsAct.setWhatsThis(self.trUtf8(
-##            """<b>Diff Settings</b>"""
-##            """<p>Shows the modification made to the settings.</p>"""
-##        ))
-##        self.connect(self.diffSettingsAct, SIGNAL('triggered()'), 
-##            self.__diffSettings)
-##        self.actions.append(self.diffSettingsAct)
-##    
-##        self.cleanupAct = E4Action(self.trUtf8('Cleanup'),
-##                self.trUtf8('&Cleanup'), 
-##                0, 0,
-##                self,'django_tools_cleanup')
-##        self.cleanupAct.setStatusTip(self.trUtf8(
-##            'Cleans out old data from the database'))
-##        self.cleanupAct.setWhatsThis(self.trUtf8(
-##            """<b>Cleanup</b>"""
-##            """<p>Cleans out old data from the database.</p>"""
-##        ))
-##        self.connect(self.cleanupAct, SIGNAL('triggered()'), 
-##            self.__cleanup)
-##        self.actions.append(self.cleanupAct)
-##    
-##        self.validateAct = E4Action(self.trUtf8('Validate'),
-##                self.trUtf8('&Validate'), 
-##                0, 0,
-##                self,'django_tools_validate')
-##        self.validateAct.setStatusTip(self.trUtf8(
-##            'Validates all installed models'))
-##        self.validateAct.setWhatsThis(self.trUtf8(
-##            """<b>Validate</b>"""
-##            """<p>Validates all installed models.</p>"""
-##        ))
-##        self.connect(self.validateAct, SIGNAL('triggered()'), 
-##            self.__validate)
-##        self.actions.append(self.validateAct)
-##    
-##        self.adminindexAct = E4Action(self.trUtf8('Admin Index'),
-##                self.trUtf8('&Admin Index'), 
-##                0, 0,
-##                self,'django_tools_adminindex')
-##        self.adminindexAct.setStatusTip(self.trUtf8(
-##            'Prints the admin-index template snippet'))
-##        self.adminindexAct.setWhatsThis(self.trUtf8(
-##            """<b>Admin Index</b>"""
-##            """<p>Prints the admin-index template snippet.</p>"""
-##        ))
-##        self.connect(self.adminindexAct, SIGNAL('triggered()'), 
-##            self.__adminIndex)
-##        self.actions.append(self.adminindexAct)
-##    
-##        self.runPythonShellAct = E4Action(self.trUtf8('Start Python Console'),
-##                self.trUtf8('Start &Python Console'), 
-##                0, 0,
-##                self,'django_tools_pythonconsole')
-##        self.runPythonShellAct.setStatusTip(self.trUtf8(
-##            'Starts a Python interactive interpreter'))
-##        self.runPythonShellAct.setWhatsThis(self.trUtf8(
-##            """<b>Start Python Console</b>"""
-##            """<p>Starts a Python interactive interpreter.</p>"""
-##        ))
-##        self.connect(self.runPythonShellAct, SIGNAL('triggered()'), 
-##            self.__runPythonShell)
-##        self.actions.append(self.runPythonShellAct)
-##    
-##    def __initTestingActions(self):
-##        """
-##        Private method to define the testing actions.
-##        """
-##        self.dumpDataAct = E4Action(self.trUtf8('Dump Data'),
-##                self.trUtf8('&Dump Data'), 
-##                0, 0,
-##                self,'django_tools_dumpdata')
-##        self.dumpDataAct.setStatusTip(self.trUtf8(
-##            'Dump the database data to a fixture'))
-##        self.dumpDataAct.setWhatsThis(self.trUtf8(
-##            """<b>Dump Data</b>"""
-##            """<p>Dump the database data to a fixture.</p>"""
-##        ))
-##        self.connect(self.dumpDataAct, SIGNAL('triggered()'), 
-##            self.__dumpData)
-##        self.actions.append(self.dumpDataAct)
-##        
-##        self.loadDataAct = E4Action(self.trUtf8('Load Data'),
-##                self.trUtf8('&Load Data'), 
-##                0, 0,
-##                self,'django_tools_loaddata')
-##        self.loadDataAct.setStatusTip(self.trUtf8(
-##            'Load data from fixture files'))
-##        self.loadDataAct.setWhatsThis(self.trUtf8(
-##            """<b>Load Data</b>"""
-##            """<p>Load data from fixture files.</p>"""
-##        ))
-##        self.connect(self.loadDataAct, SIGNAL('triggered()'), 
-##            self.__loadData)
-##        self.actions.append(self.loadDataAct)
-##        
-##        self.runTestAct = E4Action(self.trUtf8('Run Testsuite'),
-##                self.trUtf8('Run &Testsuite'), 
-##                0, 0,
-##                self,'django_tools_run_test')
-##        self.runTestAct.setStatusTip(self.trUtf8(
-##            'Run the test suite for applications or the whole site'))
-##        self.runTestAct.setWhatsThis(self.trUtf8(
-##            """<b>Run Testsuite</b>"""
-##            """<p>Run the test suite for applications or the whole site.</p>"""
-##        ))
-##        self.connect(self.runTestAct, SIGNAL('triggered()'), 
-##            self.__runTestSuite)
-##        self.actions.append(self.runTestAct)
-##        
-##        self.runTestServerAct = E4Action(self.trUtf8('Run Testserver'),
-##                self.trUtf8('Run Test&server'), 
-##                0, 0,
-##                self,'django_tools_run_test_server')
-##        self.runTestServerAct.setStatusTip(self.trUtf8(
-##            'Run a development server with data from a set of fixtures'))
-##        self.runTestServerAct.setWhatsThis(self.trUtf8(
-##            """<b>Run Testserver</b>"""
-##            """<p>Run a development server with data from a set of fixtures.</p>"""
-##        ))
-##        self.connect(self.runTestServerAct, SIGNAL('triggered()'), 
-##            self.__runTestServer)
-##        self.actions.append(self.runTestServerAct)
-##    
+        
+        self.__initDatabaseActions()
+        self.__initDatabaseSqlActions()
+        self.__initToolsActions()
+        self.__initTestingActions()
+
+    def __initDatabaseActions(self):
+        """
+        Private method to define the database related actions.
+        """
+        self.syncDatabaseAct = E5Action(self.trUtf8('Synchronize'),
+                self.trUtf8('&Synchronize'), 
+                0, 0,
+                self,'django_database_syncdb')
+        self.syncDatabaseAct.setStatusTip(self.trUtf8(
+            'Synchronizes the database'))
+        self.syncDatabaseAct.setWhatsThis(self.trUtf8(
+            """<b>Synchronize</b>"""
+            """<p>Synchronizes the database.</p>"""
+        ))
+        self.syncDatabaseAct.triggered[()].connect(self.__databaseSynchronize)
+        self.actions.append(self.syncDatabaseAct)
+        
+        self.inspectDatabaseAct = E5Action(self.trUtf8('Introspect'),
+                self.trUtf8('&Introspect'), 
+                0, 0,
+                self,'django_database_inspect')
+        self.inspectDatabaseAct.setStatusTip(self.trUtf8(
+            'Introspects the database tables and outputs a Django model module'))
+        self.inspectDatabaseAct.setWhatsThis(self.trUtf8(
+            """<b>Introspect</b>"""
+            """<p>Introspects the database tables and outputs a """
+            """Django model module.</p>"""
+        ))
+        self.inspectDatabaseAct.triggered[()].connect(self.__databaseInspect)
+        self.actions.append(self.inspectDatabaseAct)
+        
+        self.flushDatabaseAct = E5Action(self.trUtf8('Flush'),
+                self.trUtf8('&Flush'), 
+                0, 0,
+                self,'django_database_flush')
+        self.flushDatabaseAct.setStatusTip(self.trUtf8(
+            'Returns all database tables to the state just after their installation'))
+        self.flushDatabaseAct.setWhatsThis(self.trUtf8(
+            """<b>Flush</b>"""
+            """<p>Returns all database tables to the state """
+            """just after their installation.</p>"""
+        ))
+        self.flushDatabaseAct.triggered[()].connect(self.__databaseFlush)
+        self.actions.append(self.flushDatabaseAct)
+        
+        self.databaseClientAct = E5Action(self.trUtf8('Start Client Console'),
+                self.trUtf8('Start &Client Console'), 
+                0, 0,
+                self,'django_database_client')
+        self.databaseClientAct.setStatusTip(self.trUtf8(
+            'Starts a console window for the database client'))
+        self.databaseClientAct.setWhatsThis(self.trUtf8(
+            """<b>Start Client Console</b>"""
+            """<p>Starts a console window for the database client.</p>"""
+        ))
+        self.databaseClientAct.triggered[()].connect(self.__runDatabaseClient)
+        self.actions.append(self.databaseClientAct)
+    
+    def __initDatabaseSqlActions(self):
+        """
+        Private method to define the database SQL related actions.
+        """
+        self.databaseSqlCreateTablesAct = E5Action(self.trUtf8('Create Tables'),
+                self.trUtf8('Create &Tables'), 
+                0, 0,
+                self,'django_database_sql_create_tables')
+        self.databaseSqlCreateTablesAct.setStatusTip(self.trUtf8(
+            'Prints the CREATE TABLE SQL statements for one or more applications'))
+        self.databaseSqlCreateTablesAct.setWhatsThis(self.trUtf8(
+            """<b>Create Tables</b>"""
+            """<p>Prints the CREATE TABLE SQL statements for one or """
+            """more applications.</p>"""
+        ))
+        self.databaseSqlCreateTablesAct.triggered[()].connect(
+            self.__databaseSqlCreateTables)
+        self.actions.append(self.databaseSqlCreateTablesAct)
+        
+        self.databaseSqlCreateIndexesAct = E5Action(self.trUtf8('Create Indexes'),
+                self.trUtf8('Create &Indexes'), 
+                0, 0,
+                self,'django_database_sql_create_indexes')
+        self.databaseSqlCreateIndexesAct.setStatusTip(self.trUtf8(
+            'Prints the CREATE INDEX SQL statements for one or more applications'))
+        self.databaseSqlCreateIndexesAct.setWhatsThis(self.trUtf8(
+            """<b>Create Indexes</b>"""
+            """<p>Prints the CREATE INDEX SQL statements for one or """
+            """more applications.</p>"""
+        ))
+        self.databaseSqlCreateIndexesAct.triggered[()].connect(
+            self.__databaseSqlCreateIndexes)
+        self.actions.append(self.databaseSqlCreateIndexesAct)
+        
+        self.databaseSqlCreateEverythingAct = E5Action(self.trUtf8('Create Everything'),
+                self.trUtf8('Create &Everything'), 
+                0, 0,
+                self,'django_database_sql_create_everything')
+        self.databaseSqlCreateEverythingAct.setStatusTip(self.trUtf8(
+            'Prints the CREATE ... SQL statements for one or more applications'))
+        self.databaseSqlCreateEverythingAct.setWhatsThis(self.trUtf8(
+            """<b>Create Everything</b>"""
+            """<p>Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL """
+            """statements for one or more applications.</p>"""
+        ))
+        self.databaseSqlCreateEverythingAct.triggered[()].connect(
+            self.__databaseSqlCreateEverything)
+        self.actions.append(self.databaseSqlCreateEverythingAct)
+        
+        self.databaseSqlCustomAct = E5Action(self.trUtf8('Custom Statements'),
+                self.trUtf8('&Custom Statements'), 
+                0, 0,
+                self,'django_database_sql_custom')
+        self.databaseSqlCustomAct.setStatusTip(self.trUtf8(
+            'Prints the custom table modifying SQL statements for '
+            'one or more applications'))
+        self.databaseSqlCustomAct.setWhatsThis(self.trUtf8(
+            """<b>Custom Statements</b>"""
+            """<p>Prints the custom table modifying SQL statements """
+            """for one or more applications.</p>"""
+        ))
+        self.databaseSqlCustomAct.triggered[()].connect(
+            self.__databaseSqlCustom)
+        self.actions.append(self.databaseSqlCustomAct)
+        
+        self.databaseSqlDropTablesAct = E5Action(self.trUtf8('Drop Tables'),
+                self.trUtf8('&Drop Tables'), 
+                0, 0,
+                self,'django_database_sql_drop_tables')
+        self.databaseSqlDropTablesAct.setStatusTip(self.trUtf8(
+            'Prints the DROP TABLE SQL statements for '
+            'one or more applications'))
+        self.databaseSqlDropTablesAct.setWhatsThis(self.trUtf8(
+            """<b>Drop Tables</b>"""
+            """<p>Prints the DROP TABLE SQL statements """
+            """for one or more applications.</p>"""
+        ))
+        self.databaseSqlDropTablesAct.triggered[()].connect(
+            self.__databaseSqlDropTables)
+        self.actions.append(self.databaseSqlDropTablesAct)
+        
+        self.databaseSqlFlushAct = E5Action(self.trUtf8('Flush Database'),
+                self.trUtf8('&Flush Database'), 
+                0, 0,
+                self,'django_database_sql_flush_database')
+        self.databaseSqlFlushAct.setStatusTip(self.trUtf8(
+            'Prints a list of statements to return all database tables to the state '
+            'just after their installation'))
+        self.databaseSqlFlushAct.setWhatsThis(self.trUtf8(
+            """<b>Flush Database</b>"""
+            """<p>Prints a list of statements to return all database tables to """
+            """the state just after their installation.</p>"""
+        ))
+        self.databaseSqlFlushAct.triggered[()].connect(
+            self.__databaseSqlFlushDatabase)
+        self.actions.append(self.databaseSqlFlushAct)
+        
+        self.databaseSqlResetSeqAct = E5Action(self.trUtf8('Reset Sequences'),
+                self.trUtf8('Reset &Sequences'), 
+                0, 0,
+                self,'django_database_sql_reset_sequences')
+        self.databaseSqlResetSeqAct.setStatusTip(self.trUtf8(
+            'Prints the SQL statements for resetting sequences for '
+            'one or more applications'))
+        self.databaseSqlResetSeqAct.setWhatsThis(self.trUtf8(
+            """<b>Reset Sequences</b>"""
+            """<p>Prints the SQL statements for resetting sequences for """
+            """one or more applications.</p>"""
+        ))
+        self.databaseSqlResetSeqAct.triggered[()].connect(
+            self.__databaseSqlResetSequences)
+        self.actions.append(self.databaseSqlResetSeqAct)
+    
+    def __initToolsActions(self):
+        """
+        Private method to define the tool actions.
+        """
+        self.diffSettingsAct = E5Action(self.trUtf8('Diff Settings'),
+                self.trUtf8('&Diff Settings'), 
+                0, 0,
+                self,'django_tools_diffsettings')
+        self.diffSettingsAct.setStatusTip(self.trUtf8(
+            'Shows the modification made to the settings'))
+        self.diffSettingsAct.setWhatsThis(self.trUtf8(
+            """<b>Diff Settings</b>"""
+            """<p>Shows the modification made to the settings.</p>"""
+        ))
+        self.diffSettingsAct.triggered[()].connect(self.__diffSettings)
+        self.actions.append(self.diffSettingsAct)
+    
+        self.cleanupAct = E5Action(self.trUtf8('Cleanup'),
+                self.trUtf8('&Cleanup'), 
+                0, 0,
+                self,'django_tools_cleanup')
+        self.cleanupAct.setStatusTip(self.trUtf8(
+            'Cleans out old data from the database'))
+        self.cleanupAct.setWhatsThis(self.trUtf8(
+            """<b>Cleanup</b>"""
+            """<p>Cleans out old data from the database.</p>"""
+        ))
+        self.cleanupAct.triggered[()].connect(self.__cleanup)
+        self.actions.append(self.cleanupAct)
+    
+        self.validateAct = E5Action(self.trUtf8('Validate'),
+                self.trUtf8('&Validate'), 
+                0, 0,
+                self,'django_tools_validate')
+        self.validateAct.setStatusTip(self.trUtf8(
+            'Validates all installed models'))
+        self.validateAct.setWhatsThis(self.trUtf8(
+            """<b>Validate</b>"""
+            """<p>Validates all installed models.</p>"""
+        ))
+        self.validateAct.triggered[()].connect(self.__validate)
+        self.actions.append(self.validateAct)
+    
+        self.runPythonShellAct = E5Action(self.trUtf8('Start Python Console'),
+                self.trUtf8('Start &Python Console'), 
+                0, 0,
+                self,'django_tools_pythonconsole')
+        self.runPythonShellAct.setStatusTip(self.trUtf8(
+            'Starts a Python interactive interpreter'))
+        self.runPythonShellAct.setWhatsThis(self.trUtf8(
+            """<b>Start Python Console</b>"""
+            """<p>Starts a Python interactive interpreter.</p>"""
+        ))
+        self.runPythonShellAct.triggered[()].connect(self.__runPythonShell)
+        self.actions.append(self.runPythonShellAct)
+    
+    def __initTestingActions(self):
+        """
+        Private method to define the testing actions.
+        """
+        self.dumpDataAct = E5Action(self.trUtf8('Dump Data'),
+                self.trUtf8('&Dump Data'), 
+                0, 0,
+                self,'django_tools_dumpdata')
+        self.dumpDataAct.setStatusTip(self.trUtf8(
+            'Dump the database data to a fixture'))
+        self.dumpDataAct.setWhatsThis(self.trUtf8(
+            """<b>Dump Data</b>"""
+            """<p>Dump the database data to a fixture.</p>"""
+        ))
+        self.dumpDataAct.triggered[()].connect(self.__dumpData)
+        self.actions.append(self.dumpDataAct)
+        
+        self.loadDataAct = E5Action(self.trUtf8('Load Data'),
+                self.trUtf8('&Load Data'), 
+                0, 0,
+                self,'django_tools_loaddata')
+        self.loadDataAct.setStatusTip(self.trUtf8(
+            'Load data from fixture files'))
+        self.loadDataAct.setWhatsThis(self.trUtf8(
+            """<b>Load Data</b>"""
+            """<p>Load data from fixture files.</p>"""
+        ))
+        self.loadDataAct.triggered[()].connect(self.__loadData)
+        self.actions.append(self.loadDataAct)
+        
+        self.runTestAct = E5Action(self.trUtf8('Run Testsuite'),
+                self.trUtf8('Run &Testsuite'), 
+                0, 0,
+                self,'django_tools_run_test')
+        self.runTestAct.setStatusTip(self.trUtf8(
+            'Run the test suite for applications or the whole site'))
+        self.runTestAct.setWhatsThis(self.trUtf8(
+            """<b>Run Testsuite</b>"""
+            """<p>Run the test suite for applications or the whole site.</p>"""
+        ))
+        self.runTestAct.triggered[()].connect(self.__runTestSuite)
+        self.actions.append(self.runTestAct)
+        
+        self.runTestServerAct = E5Action(self.trUtf8('Run Testserver'),
+                self.trUtf8('Run Test&server'), 
+                0, 0,
+                self,'django_tools_run_test_server')
+        self.runTestServerAct.setStatusTip(self.trUtf8(
+            'Run a development server with data from a set of fixtures'))
+        self.runTestServerAct.setWhatsThis(self.trUtf8(
+            """<b>Run Testserver</b>"""
+            """<p>Run a development server with data from a set of fixtures.</p>"""
+        ))
+        self.runTestServerAct.triggered[()].connect(self.__runTestServer)
+        self.actions.append(self.runTestServerAct)
+    
     def initMenu(self):
         """
         Public slot to initialize the Django menu.
@@ -566,8 +514,8 @@
         
         menu.addAction(self.selectSiteAct)
         menu.addSeparator()
-##        menu.addAction(self.runServerAct)
-##        menu.addAction(self.runBrowserAct)
+        menu.addAction(self.runServerAct)
+        menu.addAction(self.runBrowserAct)
         menu.addSeparator()
         menu.addAction(self.startProjectAct)
         menu.addAction(self.startGlobalApplicationAct)
@@ -577,7 +525,7 @@
         menu.addSeparator()
         menu.addMenu(self.__initToolsMenu())
         menu.addSeparator()
-##        menu.addAction(self.createCacheTableAct)
+        menu.addAction(self.createCacheTableAct)
         menu.addSeparator()
         menu.addMenu(self.__initTestingMenu())
         menu.addSeparator()
@@ -598,14 +546,13 @@
         menu = QMenu(self.trUtf8("&Database"), self.__ui)
         menu.setTearOffEnabled(True)
         
-##        menu.addAction(self.syncDatabaseAct)
+        menu.addAction(self.syncDatabaseAct)
         menu.addSeparator()
-##        menu.addAction(self.inspectDatabaseAct)
+        menu.addAction(self.inspectDatabaseAct)
         menu.addSeparator()
-##        menu.addAction(self.flushDatabaseAct)
-##        menu.addAction(self.resetDatabaseAct)
+        menu.addAction(self.flushDatabaseAct)
         menu.addSeparator()
-##        menu.addAction(self.databaseClientAct)
+        menu.addAction(self.databaseClientAct)
         menu.addSeparator()
         menu.addMenu(self.__initDatabaseSqlMenu())
         
@@ -620,17 +567,16 @@
         menu = QMenu(self.trUtf8("Show &SQL"), self.__ui)
         menu.setTearOffEnabled(True)
         
-##        menu.addAction(self.databaseSqlCreateTablesAct)
-##        menu.addAction(self.databaseSqlCreateIndexesAct)
-##        menu.addAction(self.databaseSqlCreateEverythingAct)
-        menu.addSeparator()
-##        menu.addAction(self.databaseSqlCustomAct)
+        menu.addAction(self.databaseSqlCreateTablesAct)
+        menu.addAction(self.databaseSqlCreateIndexesAct)
+        menu.addAction(self.databaseSqlCreateEverythingAct)
         menu.addSeparator()
-##        menu.addAction(self.databaseSqlDropTablesAct)
+        menu.addAction(self.databaseSqlCustomAct)
         menu.addSeparator()
-##        menu.addAction(self.databaseSqlFlushAct)
-##        menu.addAction(self.databaseSqlResetApplAct)
-##        menu.addAction(self.databaseSqlResetSeqAct)
+        menu.addAction(self.databaseSqlDropTablesAct)
+        menu.addSeparator()
+        menu.addAction(self.databaseSqlFlushAct)
+        menu.addAction(self.databaseSqlResetSeqAct)
         
         return menu
     
@@ -643,12 +589,11 @@
         menu = QMenu(self.trUtf8("&Tools"), self.__ui)
         menu.setTearOffEnabled(True)
         
-##        menu.addAction(self.diffSettingsAct)
-##        menu.addAction(self.cleanupAct)
-##        menu.addAction(self.validateAct)
-##        menu.addAction(self.adminindexAct)
+        menu.addAction(self.diffSettingsAct)
+        menu.addAction(self.cleanupAct)
+        menu.addAction(self.validateAct)
         menu.addSeparator()
-##        menu.addAction(self.runPythonShellAct)
+        menu.addAction(self.runPythonShellAct)
         
         return menu
     
@@ -661,11 +606,11 @@
         menu = QMenu(self.trUtf8("T&esting"), self.__ui)
         menu.setTearOffEnabled(True)
         
-##        menu.addAction(self.dumpDataAct)
-##        menu.addAction(self.loadDataAct)
+        menu.addAction(self.dumpDataAct)
+        menu.addAction(self.loadDataAct)
         menu.addSeparator()
-##        menu.addAction(self.runTestAct)
-##        menu.addAction(self.runTestServerAct)
+        menu.addAction(self.runTestAct)
+        menu.addAction(self.runTestServerAct)
         
         return menu
 
@@ -691,6 +636,12 @@
                 self.updateCatalogs, self.trUtf8("Update all catalogs"))
             self.__translationsBrowser.addHookMethodAndMenuEntry("generateSelected", 
                 self.updateSelectedCatalogs, self.trUtf8("Update selected catalogs"))
+            self.__translationsBrowser.addHookMethodAndMenuEntry(
+                "generateAllWithObsolete", self.updateCatalogsWithObsolete,
+                self.trUtf8("Update all catalogs (with obsolete)"))
+            self.__translationsBrowser.addHookMethodAndMenuEntry(
+                "generateSelectedWithObsolete", self.updateSelectedCatalogsWithObsolete,
+                self.trUtf8("Update selected catalogs (with obsolete)"))
             self.__translationsBrowser.addHookMethodAndMenuEntry("releaseAll", 
                 self.compileCatalogs, self.trUtf8("Compile all catalogs"))
             self.__translationsBrowser.addHookMethodAndMenuEntry("releaseSelected", 
@@ -711,6 +662,8 @@
                 self.__projectLanguageAdded)
             self.__translationsBrowser.removeHookMethod("generateAll")
             self.__translationsBrowser.removeHookMethod("generateSelected")
+            self.__translationsBrowser.removeHookMethod("generateAllWithObsolete")
+            self.__translationsBrowser.removeHookMethod("generateSelectedWithObsolete")
             self.__translationsBrowser.removeHookMethod("releaseAll")
             self.__translationsBrowser.removeHookMethod("releaseSelected")
             self.__translationsBrowser = None
@@ -723,62 +676,63 @@
         
         @param path full directory path for the new form file (string)
         """
-##        selectedFilter = QString("")
-##        filter = self.trUtf8("HTML Files (*.html);;All Files (*)")
-##        fname = KQFileDialog.getSaveFileName(\
-##            self.__ui,
-##            self.trUtf8("New Form"),
-##            path,
-##            filter,
-##            selectedFilter,
-##            QFileDialog.Options(QFileDialog.DontConfirmOverwrite))
-##        
-##        if fname.isEmpty():
-##            # user aborted or didn't enter a filename
-##            return
-##        
-##        ext = QFileInfo(fname).suffix()
-##        if ext.isEmpty():
-##            ex = selectedFilter.section('(*',1,1).section(')',0,0)
-##            if not ex.isEmpty():
-##                fname.append(ex)
-##        
-##        fname = unicode(fname)
-##        if os.path.exists(fname):
-##            res = KQMessageBox.warning(self.__ui,
-##                self.trUtf8("New Form"),
-##                self.trUtf8("The file already exists! Overwrite it?"),
-##                QMessageBox.StandardButtons(\
-##                    QMessageBox.No | \
-##                    QMessageBox.Yes),
-##                QMessageBox.No)
-##            if res != QMessageBox.Yes:
-##                # user selected to not overwrite
-##                return
-##        
-##        try:
-##            f = open(fname, "wb")
-##            f.write('<html>\n')
-##            f.write('  <head>\n')
-##            f.write('    <meta content="" />\n')
-##            f.write('    <title></title>\n')
-##            f.write('    <style>\n')
-##            f.write('    </style>\n')
-##            f.write('  </head>\n')
-##            f.write('\n')
-##            f.write('  <body>\n')
-##            f.write('  </body>\n')
-##            f.write('</html>\n')
-##            f.close()
-##        except IOError, e:
-##            KQMessageBox.critical(self.__ui,
-##                self.trUtf8("New Form"),
-##                self.trUtf8("<p>The new form file <b>%1</b> could not be created.<br>"
-##                    "Problem: %2</p>").arg(fname).arg(unicode(e)))
-##            return
-##        
-##        self.__e4project.appendFile(fname)
-##        self.__formsBrowser.emit(SIGNAL('sourceFile'), fname)
+        fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
+            self.__ui,
+            self.trUtf8("New Form"),
+            path,
+            filter,
+            None,
+            QFileDialog.Options(QFileDialog.DontConfirmOverwrite))
+        
+        if not fname:
+            # user aborted or didn't enter a filename
+            return
+        
+        ext = QFileInfo(fname).suffix()
+        if not ext:
+            ex = selectedFilter.split("(*")[1].split(")")[0]
+            if ex:
+                fname += ex
+        
+        if os.path.exists(fname):
+            res = E5MessageBox.yesNo(self.__ui,
+                self.trUtf8("New Form"),
+                self.trUtf8("The file already exists! Overwrite it?"),
+                icon=E5MessageBox.Warning)
+            
+            if not res:
+                # user selected to not overwrite
+                return
+        
+        try:
+            f = open(fname, "w")
+            f.write('<!DOCTYPE html>')
+            f.write('<html>\n')
+            f.write('  <head>\n')
+            f.write('    <meta content="" />\n')
+            f.write('    <title></title>\n')
+            f.write('    <link rel="stylesheet" type="text/css" href="style.css"/>')
+            f.write('    <!--[if lte IE 7]>')
+            f.write('      <link rel="stylesheet" type="text/css" href="ie.css"/>')
+            f.write('    <![endif]-->')
+            f.write('  </head>\n')
+            f.write('\n')
+            f.write('  <body  class="bodyclass">\n')
+            f.write('    <div id="container">')
+            f.write('    </div>')
+            f.write('  </body>\n')
+            f.close()
+            f.write('</html>\n')
+            f.close()
+        except (IOError, OSError) as e:
+            E5MessageBox.critical(self.__ui,
+                self.trUtf8("New Form"),
+                self.trUtf8("<p>The new form file <b>{0}</b> could not be created.<br>"
+                    "Problem: {1}</p>").format(fname, str(e)))
+            return
+        
+        self.__e5project.appendFile(fname)
+        self.__formsBrowser.sourceFile.emit(fname)
 
     ##################################################################
     ## slots below implement general functionality
@@ -814,33 +768,33 @@
             ).format(version)
         )
     
-##    def getDjangoVersion(self):
-##        """
-##        Public method to get the Django version.
-##        
-##        @return Django version as a tuple
-##        """
-##        from django import VERSION
-##        return VERSION
-##    
-##    def __getApplications(self):
-##        """
-##        Private method to ask the user for a list of application names.
-##        
-##        @return list of application names (QStringList)
-##        """
-##        applStr, ok = KQInputDialog.getItem(\
-##            self.__ui,
-##            self.trUtf8("Select Applications"),
-##            self.trUtf8("Enter the list of applications separated by spaces."),
-##            self.getRecentApplications(),
-##            0, True)
-##        if ok and not applStr.isEmpty():
-##            self.setMostRecentApplication(applStr)
-##            return applStr.split(" ", QString.SkipEmptyParts)
-##        else:
-##            return QStringList()
-##
+    def getDjangoVersion(self):
+        """
+        Public method to get the Django version.
+        
+        @return Django version as a tuple
+        """
+        from django import VERSION
+        return VERSION
+    
+    def __getApplications(self):
+        """
+        Private method to ask the user for a list of application names.
+        
+        @return list of application names (list of strings)
+        """
+        applStr, ok = QInputDialog.getItem(
+            self.__ui,
+            self.trUtf8("Select Applications"),
+            self.trUtf8("Enter the list of applications separated by spaces."),
+            self.getRecentApplications(),
+            0, True)
+        if ok and applStr != "":
+            self.setMostRecentApplication(applStr)
+            return applStr.split()
+        else:
+            return []
+
     def __loadRecentApplications(self):
         """
         Private method to load the recently used applications list.
@@ -898,6 +852,7 @@
         
         @return Python executable (string)
         """
+        # TODO: make this differentiate between Python2 and Python3
         return sys.executable.replace("pythonw", "python")
     
     def __showHelpIndex(self):
@@ -908,34 +863,48 @@
                             "Documentation", "help", "index.html")
         self.__ui.launchHelpViewer(page)
     
+    def __isSpawningConsole(self, consoleCmd):
+        """
+        Private method to check, if the given console is a spawning console.
+        
+        @param consoleCmd console command (string)
+        @return tuple of two entries giving an indication, if the console
+            is spawning (boolean) and the (possibly) cleaned console command
+            (string)
+        """
+        if consoleCmd and consoleCmd[0] == '@':
+            return (True, consoleCmd[1:])
+        else:
+            return (False, consoleCmd)
+    
     ##################################################################
     ## slots below implement creation functions
     ##################################################################
     
-##    def startProjectOrApplication(self):
-##        """
-##        Public slot to start a new Django project or application.
-##        """
-##        if self.__e4project.getProjectType() == "Django":
-##            projectStr = self.trUtf8("Project")
-##            applStr = self.trUtf8("Application")
-##            selections = QStringList() << QString("") << projectStr << applStr
-##            selection,  ok = KQInputDialog.getItem(\
-##                self.__ui,
-##                self.trUtf8("Start Django"),
-##                self.trUtf8("Select if this project should be a "
-##                            "Django Project or Application.<br />"
-##                            "Select the empty entry for none."),
-##                selections,
-##                0, False)
-##            if ok and not selection.isEmpty():
-##                if selection == projectStr:
-##                    path, projectName = os.path.split(self.__e4project.getProjectPath())
-##                    self.__createProject(projectName, path)
-##                elif selection == applStr:
-##                    path, applName = os.path.split(self.__e4project.getProjectPath())
-##                    self.__createApplication(applName, path)
-##    
+    def startProjectOrApplication(self):
+        """
+        Public slot to start a new Django project or application.
+        """
+        if self.__e5project.getProjectType() == "Django":
+            projectStr = self.trUtf8("Project")
+            applStr = self.trUtf8("Application")
+            selections = ["", projectStr, applStr]
+            selection,  ok = QInputDialog.getItem(
+                self.__ui,
+                self.trUtf8("Start Django"),
+                self.trUtf8("Select if this project should be a "
+                            "Django Project or Application.<br />"
+                            "Select the empty entry for none."),
+                selections,
+                0, False)
+            if ok and bool(selection):
+                if selection == projectStr:
+                    path, projectName = os.path.split(self.__e5project.getProjectPath())
+                    self.__createProject(projectName, path)
+                elif selection == applStr:
+                    path, applName = os.path.split(self.__e5project.getProjectPath())
+                    self.__createApplication(applName, path)
+    
     def __createProject(self, projectName, path):
         """
         Private slot to create a new Django project.
@@ -1184,751 +1153,717 @@
     ## slots below implement run functions
     ##################################################################
     
-##    def __runServer(self):
-##        """
-##        Private slot to start the Django Web server.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommand"))
-##        if consoleCmd:
-##            args = Utilities.parseOptionString(consoleCmd)
-##            args[0] = Utilities.getExecutablePath(args[0])
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("runserver")
-##            addr = self.__plugin.getPreferences("ServerAddress")
-##            if addr:
-##                args.append(addr)
-##            
-##            try:
-##                if Utilities.isWindowsPlatform():
-##                    serverProcStarted, pid = \
-##                        QProcess.startDetached(args[0], args[1:], self.__sitePath())
-##                else:
-##                    if self.__serverProc is not None:
-##                        self.__serverProcFinished()
-##                    
-##                    self.__serverProc = QProcess()
-##                    self.connect(self.__serverProc, 
-##                                 SIGNAL('finished(int, QProcess::ExitStatus)'),
-##                                 self.__serverProcFinished)
-##                    self.__serverProc.setWorkingDirectory(self.__sitePath())
-##                    self.__serverProc.start(args[0], args[1:])
-##                    serverProcStarted = self.__serverProc.waitForStarted()
-##                if not serverProcStarted:
-##                    KQMessageBox.critical(None,
-##                        self.trUtf8('Process Generation Error'),
-##                        self.trUtf8('The Django server could not be started.'))
-##            except DjangoNoSiteSelectedException:
-##                pass
-##    
-##    def __serverProcFinished(self):
-##        """
-##        Private slot connected to the finished signal.
-##        """
-##        if self.__serverProc is not None and \
-##           self.__serverProc.state() != QProcess.NotRunning:
-##            self.__serverProc.terminate()
-##            QTimer.singleShot(2000, self.__serverProc, SLOT('kill()'))
-##            self.__serverProc.waitForFinished(3000)
-##        self.__serverProc = None
-##    
-##    def __runBrowser(self):
-##        """
-##        Private slot to start the default web browser with the server URL.
-##        """
-##        addr = self.__plugin.getPreferences("ServerAddress")
-##        if addr:
-##            if ':' in addr:
-##                port = addr.split(':')[1]
-##            else:
-##                port = addr
-##        else:
-##            port = QString("8000")
-##        url = QUrl(QString("http://127.0.0.1:%1").arg(port))
-##        res = QDesktopServices.openUrl(url)
-##        if not res:
-##            KQMessageBox.critical(None,
-##                self.trUtf8('Run Web-Browser'),
-##                self.trUtf8('Could not start the web-browser for the url "%1".')\
-##                    .arg(url.toString()))
+    def __runServer(self):
+        """
+        Private slot to start the Django Web server.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("runserver")
+            addr = self.__plugin.getPreferences("ServerAddress")
+            if addr:
+                args.append(addr)
+            
+            try:
+                if Utilities.isWindowsPlatform():
+                    serverProcStarted, pid = \
+                        QProcess.startDetached(args[0], args[1:], self.__sitePath())
+                else:
+                    if self.__serverProc is not None:
+                        self.__serverProcFinished()
+                    
+                    self.__serverProc = QProcess()
+                    self.__serverProc.finished.connect(self.__serverProcFinished)
+                    self.__serverProc.setWorkingDirectory(self.__sitePath())
+                    self.__serverProc.start(args[0], args[1:])
+                    serverProcStarted = self.__serverProc.waitForStarted()
+                if not serverProcStarted:
+                    E5MessageBox.critical(None,
+                        self.trUtf8('Process Generation Error'),
+                        self.trUtf8('The Django server could not be started.'))
+            except DjangoNoSiteSelectedException:
+                pass
+    
+    def __serverProcFinished(self):
+        """
+        Private slot connected to the finished signal.
+        """
+        if self.__serverProc is not None and \
+           self.__serverProc.state() != QProcess.NotRunning:
+            self.__serverProc.terminate()
+            QTimer.singleShot(2000, self.__serverProc.kill)
+            self.__serverProc.waitForFinished(3000)
+        self.__serverProc = None
+    
+    def __runBrowser(self):
+        """
+        Private slot to start the default web browser with the server URL.
+        """
+        addr = self.__plugin.getPreferences("ServerAddress")
+        if addr:
+            if ':' in addr:
+                port = addr.split(':')[1]
+            else:
+                port = addr
+        else:
+            port = "8000"
+        url = QUrl("http://127.0.0.1:{0}".format(port))
+        res = QDesktopServices.openUrl(url)
+        if not res:
+            E5MessageBox.critical(None,
+                self.trUtf8('Run Web-Browser'),
+                self.trUtf8('Could not start the web-browser for the url "{0}".')\
+                    .format(url.toString()))
 
     ##################################################################
     ## slots below implement database related functions
     ##################################################################
     
-##    def __databaseSynchronize(self):
-##        """
-##        Private slot to synchronize the database.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommandNoClose"))
-##        if consoleCmd:
-##            proc = QProcess()
-##            args = Utilities.parseOptionString(consoleCmd)
-##            args[0] = Utilities.getExecutablePath(args[0])
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("syncdb")
-##            try:
-##                wd = self.__sitePath()
-##                started, pid = QProcess.startDetached(args[0], args[1:], wd)
-##                if not started:
-##                    KQMessageBox.critical(None,
-##                        self.trUtf8('Process Generation Error'),
-##                        self.trUtf8('The Django process could not be started.'))
-##            except DjangoNoSiteSelectedException:
-##                pass
-##    
-##    def __databaseInspect(self):
-##        """
-##        Private slot to introspect the database and output a Django model module.
-##        """
-##        title = self.trUtf8("Introspect Database")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("inspectdb")
-##        
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dia = DjangoDialog(title, fixed = True, linewrap = False)
-##        res = dia.startProcess(args, path, False)
-##        if res:
-##            dia.exec_()
-##    
-##    def __databaseFlush(self):
-##        """
-##        Private slot to return all database tables to the state just after their 
-##        installation.
-##        """
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        title = self.trUtf8("Flush Database")
-##        
-##        res = KQMessageBox.question(self.__ui,
-##            title,
-##            self.trUtf8("""Flushing the database will destroy all data. Are you sure?"""),
-##            QMessageBox.StandardButtons(\
-##                QMessageBox.No | \
-##                QMessageBox.Yes),
-##            QMessageBox.No)
-##        if res == QMessageBox.No:
-##            return
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("flush")
-##        args.append("--noinput")
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = self.trUtf8("Database tables flushed successfully."))
-##        res = dia.startProcess(args, path)
-##        if res:
-##            dia.exec_()
-##    
-##    def __databaseReset(self):
-##        """
-##        Private slot to reset the database tables of one or more applications.
-##        """
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        title = self.trUtf8("Reset Application(s)")
-##        
-##        apps = self.__getApplications()
-##        if apps.isEmpty():
-##            return
-##        
-##        res = KQMessageBox.question(self.__ui,
-##            title,
-##            self.trUtf8("""Resetting the database tables for the applications '%1' """
-##                        """will destroy all data. Are you sure?""")\
-##                .arg(apps.join(", ")),
-##            QMessageBox.StandardButtons(\
-##                QMessageBox.No | \
-##                QMessageBox.Yes),
-##            QMessageBox.No)
-##        if res == QMessageBox.No:
-##            return
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("reset")
-##        args.append("--noinput")
-##        args += apps
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = self.trUtf8("Database tables for applications '%1' reset "
-##                                     "successfully.").arg(apps.join(", "))
-##        )
-##        res = dia.startProcess(args, path)
-##        if res:
-##            dia.exec_()
-##    
-##    def __runDatabaseClient(self):
-##        """
-##        Private slot to start a database client for a Django project.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommand"))
-##        if consoleCmd:
-##            proc = QProcess()
-##            args = Utilities.parseOptionString(consoleCmd)
-##            args[0] = Utilities.getExecutablePath(args[0])
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("dbshell")
-##            try:
-##                wd = self.__sitePath()
-##                started, pid = QProcess.startDetached(args[0], args[1:], wd)
-##                if not started:
-##                    KQMessageBox.critical(None,
-##                        self.trUtf8('Process Generation Error'),
-##                        self.trUtf8('The Django process could not be started.'))
-##            except DjangoNoSiteSelectedException:
-##                pass
+    def __databaseSynchronize(self):
+        """
+        Private slot to synchronize the database.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommandNoClose"))[1]
+        if consoleCmd:
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("syncdb")
+            try:
+                wd = self.__sitePath()
+                started, pid = QProcess.startDetached(args[0], args[1:], wd)
+                if not started:
+                    E5MessageBox.critical(None,
+                        self.trUtf8('Process Generation Error'),
+                        self.trUtf8('The Django process could not be started.'))
+            except DjangoNoSiteSelectedException:
+                pass
+    
+    def __databaseInspect(self):
+        """
+        Private slot to introspect the database and output a Django model module.
+        """
+        title = self.trUtf8("Introspect Database")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("inspectdb")
+        
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        dia = DjangoDialog(title, fixed = True, linewrap = False)
+        res = dia.startProcess(args, path, False)
+        if res:
+            dia.exec_()
+    
+    def __databaseFlush(self):
+        """
+        Private slot to return all database tables to the state just after their 
+        installation.
+        """
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        title = self.trUtf8("Flush Database")
+        
+        res = E5MessageBox.yesNo(self.__ui,
+            title,
+            self.trUtf8("""Flushing the database will destroy all data. Are you sure?"""))
+        if res:
+            args = []
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("flush")
+            args.append("--noinput")
+            
+            dia = DjangoDialog(title, 
+                msgSuccess = self.trUtf8("Database tables flushed successfully."))
+            res = dia.startProcess(args, path)
+            if res:
+                dia.exec_()
+    
+    def __runDatabaseClient(self):
+        """
+        Private slot to start a database client for a Django project.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("dbshell")
+            try:
+                wd = self.__sitePath()
+                started, pid = QProcess.startDetached(args[0], args[1:], wd)
+                if not started:
+                    E5MessageBox.critical(None,
+                        self.trUtf8('Process Generation Error'),
+                        self.trUtf8('The Django process could not be started.'))
+            except DjangoNoSiteSelectedException:
+                pass
     
     #######################################################################
     ## slots below implement database functions outputting SQL statements
     #######################################################################
     
-##    def __sqlCommand(self, title, command, requestApps = True):
-##        """
-##        Private method to perform an SQL creation function.
-##        
-##        @param title dialog title (string or QString)
-##        @param command Django sql... command (string or QString)
-##        @param requestApps flag indicating to request a list of applications
-##            to work on (boolean)
-##        """
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        if requestApps:
-##            apps = self.__getApplications()
-##            if apps.isEmpty():
-##                return
-##        else:
-##            apps = QStringList()
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append(command)
-##        args += apps
-##        
-##        fileFilter = self.trUtf8("SQL Files (*.sql)")
-##        
-##        dia = DjangoDialog(title, fixed = True, linewrap = False, 
-##                           saveFilters = fileFilter)
-##        res = dia.startProcess(args, path, False)
-##        if res:
-##            dia.exec_()
-##    
-##    def __databaseSqlCreateTables(self):
-##        """
-##        Private slot to print the CREATE TABLE SQL statements for one 
-##        or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Create Tables"), "sql")
-##    
-##    def __databaseSqlCreateIndexes(self):
-##        """
-##        Private slot to print the CREATE INDEX SQL statements for one 
-##        or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Create Indexes"), "sqlindexes")
-##    
-##    def __databaseSqlCreateEverything(self):
-##        """
-##        Private slot to print the CREATE TABLE, custom SQL and 
-##        CREATE INDEX SQL statements for one or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Create Everything"), "sqlall")
-##    
-##    def __databaseSqlCustom(self):
-##        """
-##        Private slot to print the custom table modifying SQL statements
-##        for one or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Custom Statements"), "sqlcustom")
-##    
-##    def __databaseSqlDropTables(self):
-##        """
-##        Private slot to print the DROP TABLE SQL statements for one or
-##        more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Drop Tables"), "sqlclear")
-##    
-##    def __databaseSqlFlushDatabase(self):
-##        """
-##        Private slot to print a list of statements to return all database
-##        tables to their initial state.
-##        """
-##        self.__sqlCommand(self.trUtf8("Flush Database"), "sqlflush", False)
-##    
-##    def __databaseSqlResetApplication(self):
-##        """
-##        Private slot to print the DROP TABLE SQL, then the CREATE TABLE SQL 
-##        for one or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Reset Application(s)"), "sqlreset")
-##    
-##    def __databaseSqlResetSequences(self):
-##        """
-##        Private slot to print the SQL statements for resetting sequences for
-##        one or more applications.
-##        """
-##        self.__sqlCommand(self.trUtf8("Reset Sequences"), "sqlsequencereset")
+    def __sqlCommand(self, title, command, requestApps = True):
+        """
+        Private method to perform an SQL creation function.
+        
+        @param title dialog title (string)
+        @param command Django sql... command (string)
+        @param requestApps flag indicating to request a list of applications
+            to work on (boolean)
+        """
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        if requestApps:
+            apps = self.__getApplications()
+            if not apps:
+                return
+        else:
+            apps = []
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append(command)
+        args += apps
+        
+        fileFilter = self.trUtf8("SQL Files (*.sql)")
+        
+        dia = DjangoDialog(title, fixed = True, linewrap = False, 
+                           saveFilters = fileFilter)
+        res = dia.startProcess(args, path, False)
+        if res:
+            dia.exec_()
+    
+    def __databaseSqlCreateTables(self):
+        """
+        Private slot to print the CREATE TABLE SQL statements for one 
+        or more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Create Tables"), "sql")
+    
+    def __databaseSqlCreateIndexes(self):
+        """
+        Private slot to print the CREATE INDEX SQL statements for one 
+        or more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Create Indexes"), "sqlindexes")
+    
+    def __databaseSqlCreateEverything(self):
+        """
+        Private slot to print the CREATE TABLE, custom SQL and 
+        CREATE INDEX SQL statements for one or more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Create Everything"), "sqlall")
+    
+    def __databaseSqlCustom(self):
+        """
+        Private slot to print the custom table modifying SQL statements
+        for one or more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Custom Statements"), "sqlcustom")
+    
+    def __databaseSqlDropTables(self):
+        """
+        Private slot to print the DROP TABLE SQL statements for one or
+        more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Drop Tables"), "sqlclear")
+    
+    def __databaseSqlFlushDatabase(self):
+        """
+        Private slot to print a list of statements to return all database
+        tables to their initial state.
+        """
+        self.__sqlCommand(self.trUtf8("Flush Database"), "sqlflush", False)
+    
+    def __databaseSqlResetSequences(self):
+        """
+        Private slot to print the SQL statements for resetting sequences for
+        one or more applications.
+        """
+        self.__sqlCommand(self.trUtf8("Reset Sequences"), "sqlsequencereset")
     
     ##################################################################
     ## slots below implement some tool functions
     ##################################################################
     
-##    def __diffSettings(self):
-##        """
-##        Private slot to show the changes made to the settings.py file.
-##        """
-##        title = self.trUtf8("Diff Settings")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("diffsettings")
-##        
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dia = DjangoDialog(title, fixed = True, linewrap = False)
-##        res = dia.startProcess(args, path, False)
-##        if res:
-##            dia.exec_()
-##    
-##    def __cleanup(self):
-##        """
-##        Private slot to clean out old data from the database.
-##        """
-##        title = self.trUtf8("Cleanup")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("cleanup")
-##        
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = self.trUtf8("Database cleaned up successfully."))
-##        res = dia.startProcess(args, path)
-##        if res:
-##            dia.exec_()
-##    
-##    def __validate(self):
-##        """
-##        Private slot to validate all installed models.
-##        """
-##        title = self.trUtf8("Validate")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("validate")
-##        
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dia = DjangoDialog(title)
-##        res = dia.startProcess(args, path)
-##        if res:
-##            dia.exec_()
-##    
-##    def __adminIndex(self):
-##        """
-##        Private slot to print the admin-index template snippet.
-##        """
-##        apps = self.__getApplications()
-##        if apps.isEmpty():
-##            return
-##        
-##        title = self.trUtf8("Print admin-index")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("adminindex")
-##        args += apps
-##        
-##        try:
-##            path = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dia = DjangoDialog(title, fixed = True, linewrap = False)
-##        res = dia.startProcess(args, path, False)
-##        if res:
-##            dia.exec_()
-##    
-##    def __runPythonShell(self):
-##        """
-##        Private slot to start a Python console for a Django project.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommand"))
-##        if consoleCmd:
-##            proc = QProcess()
-##            args = Utilities.parseOptionString(consoleCmd)
-##            args[0] = Utilities.getExecutablePath(args[0])
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("shell")
-##            if self.__plugin.getPreferences("UsePlainPython"):
-##                args.append("--plain")
-##            try:
-##                wd = self.__sitePath()
-##                started, pid = QProcess.startDetached(args[0], args[1:], wd)
-##                if not started:
-##                    KQMessageBox.critical(None,
-##                        self.trUtf8('Process Generation Error'),
-##                        self.trUtf8('The Django process could not be started.'))
-##            except DjangoNoSiteSelectedException:
-##                pass
+    def __diffSettings(self):
+        """
+        Private slot to show the changes made to the settings.py file.
+        """
+        title = self.trUtf8("Diff Settings")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("diffsettings")
+        
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        dia = DjangoDialog(title, fixed = True, linewrap = False)
+        res = dia.startProcess(args, path, False)
+        if res:
+            dia.exec_()
+    
+    def __cleanup(self):
+        """
+        Private slot to clean out old data from the database.
+        """
+        title = self.trUtf8("Cleanup")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("cleanup")
+        
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = self.trUtf8("Database cleaned up successfully."))
+        res = dia.startProcess(args, path)
+        if res:
+            dia.exec_()
+    
+    def __validate(self):
+        """
+        Private slot to validate all installed models.
+        """
+        title = self.trUtf8("Validate")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("validate")
+        
+        try:
+            path = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        dia = DjangoDialog(title)
+        res = dia.startProcess(args, path)
+        if res:
+            dia.exec_()
+    
+    def __runPythonShell(self):
+        """
+        Private slot to start a Python console for a Django project.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("shell")
+            if self.__plugin.getPreferences("UsePlainPython"):
+                args.append("--plain")
+            try:
+                wd = self.__sitePath()
+                started, pid = QProcess.startDetached(args[0], args[1:], wd)
+                if not started:
+                    E5MessageBox.critical(None,
+                        self.trUtf8('Process Generation Error'),
+                        self.trUtf8('The Django process could not be started.'))
+            except DjangoNoSiteSelectedException:
+                pass
     
     ##################################################################
     ## slots below implement caching functions
     ##################################################################
     
-##    def __createCacheTables(self):
-##        """
-##        Private slot to create the tables for the SQL caching backend.
-##        """
-##        title = self.trUtf8("Create Cache Tables")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        tblStr, ok = KQInputDialog.getText(\
-##            self.__ui,
-##            title,
-##            self.trUtf8("Enter the names of the cache tables separated by spaces."),
-##            QLineEdit.Normal)
-##        if ok and not tblStr.isEmpty():
-##            tableNames = tblStr.split(" ", QString.SkipEmptyParts)
-##            
-##            args = QStringList()
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("createcachetable")
-##            args += tableNames
-##            
-##            dia = DjangoDialog(title, 
-##                msgSuccess = self.trUtf8("Cache tables created successfully."))
-##            res = dia.startProcess(args, wd)
-##            if res:
-##                dia.exec_()
+    def __createCacheTables(self):
+        """
+        Private slot to create the tables for the SQL caching backend.
+        """
+        title = self.trUtf8("Create Cache Tables")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        tblStr, ok = QInputDialog.getText(
+            self.__ui,
+            title,
+            self.trUtf8("Enter the names of the cache tables separated by spaces."),
+            QLineEdit.Normal)
+        if ok and tblStr != "":
+            tableNames = tblStr.split()
+            
+            args = []
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("createcachetable")
+            args += tableNames
+            
+            dia = DjangoDialog(title, 
+                msgSuccess = self.trUtf8("Cache tables created successfully."))
+            res = dia.startProcess(args, wd)
+            if res:
+                dia.exec_()
     
     ##################################################################
     ## slots below implement testing functions
     ##################################################################
     
-##    def __dumpData(self):
-##        """
-##        Private slot to dump the database data to a fixture.
-##        """
-##        title = self.trUtf8("Dump Data")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dlg = DjangoDumpdataDataDialog(self, self.__ui)
-##        if dlg.exec_() == QDialog.Accepted:
-##            appls, excls, format = dlg.getData()
-##            
-##            args = QStringList()
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("dumpdata")
-##            args.append("--format=%s" % format)
-##            args.append("--indent=2")
-##            for excl in excls:
-##                args.append("--exclude=%s" % excl)
-##            if not appls.isEmpty():
-##                args += appls
-##            
-##            if format == "json":
-##                fileFilters = self.trUtf8("JSON Files (*.json)")
-##            elif format == "xml":
-##                fileFilters = self.trUtf8("XML Files (*.xml)")
-##            elif format == "yaml":
-##                fileFilters = self.trUtf8("YAML Files (*.yaml)")
-##            
-##            dia = DjangoDialog(title, fixed = True, linewrap = False, 
-##                saveFilters = fileFilters)
-##            res = dia.startProcess(args, wd, showCommand = False)
-##            if res:
-##                dia.exec_()
-##    
-##    def __loadData(self):
-##        """
-##        Private slot to load data from fixture files.
-##        """
-##        title = self.trUtf8("Load Data")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            return
-##        
-##        dlg = DjangoLoaddataDataDialog(self, self.__ui)
-##        if dlg.exec_() == QDialog.Accepted:
-##            fixtures = dlg.getData()
-##            
-##            args = QStringList()
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("loaddata")
-##            args += fixtures
-##            
-##            dia = DjangoDialog(title)
-##            res = dia.startProcess(args, wd)
-##            if res:
-##                dia.exec_()
-##    
-##    def __runTestSuite(self):
-##        """
-##        Private slot to run the test suite for applications or the whole site.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommandNoClose"))
-##        if consoleCmd:
-##            try:
-##                wd = self.__sitePath()
-##            except DjangoNoSiteSelectedException:
-##                return
-##            
-##            proc = QProcess()
-##            args = Utilities.parseOptionString(consoleCmd)
-##            args[0] = Utilities.getExecutablePath(args[0])
-##            args.append(self.__getPythonExecutable())
-##            args.append("manage.py")
-##            args.append("test")
-##            args += self.__getApplications()
-##            
-##            started, pid = QProcess.startDetached(args[0], args[1:], wd)
-##            if not started:
-##                KQMessageBox.critical(None,
-##                    self.trUtf8('Process Generation Error'),
-##                    self.trUtf8('The Django process could not be started.'))
-##    
-##    def __runTestServer(self):
-##        """
-##        Private slot to run a development server with data from a set of fixtures.
-##        """
-##        consoleCmd = unicode(self.__plugin.getPreferences("ConsoleCommand"))
-##        if consoleCmd:
-##            dlg = DjangoLoaddataDataDialog(self, self.__ui)
-##            if dlg.exec_() == QDialog.Accepted:
-##                fixtures = dlg.getData()
-##                
-##                args = Utilities.parseOptionString(consoleCmd)
-##                args[0] = Utilities.getExecutablePath(args[0])
-##                args.append(self.__getPythonExecutable())
-##                args.append("manage.py")
-##                args.append("testserver")
-##                addr = self.__plugin.getPreferences("ServerAddress")
-##                if addr:
-##                    args.append("--addrport=%s" % addr)
-##                args += fixtures
-##                
-##                try:
-##                    if Utilities.isWindowsPlatform():
-##                        serverProcStarted, pid = \
-##                            QProcess.startDetached(args[0], args[1:], self.__sitePath())
-##                    else:
-##                        if self.__testServerProc is not None:
-##                            self.__testServerProcFinished()
-##                        
-##                        self.__testServerProc = QProcess()
-##                        self.connect(self.__testServerProc, 
-##                            SIGNAL('finished(int, QProcess::ExitStatus)'),
-##                            self.__serverProcFinished)
-##                        
-##                        self.__testServerProc.setWorkingDirectory(self.__sitePath())
-##                        self.__testServerProc.start(args[0], args[1:])
-##                        serverProcStarted = self.__testServerProc.waitForStarted()
-##                    if not serverProcStarted:
-##                        KQMessageBox.critical(None,
-##                            self.trUtf8('Process Generation Error'),
-##                            self.trUtf8('The Django test server could not be started.'))
-##                except DjangoNoSiteSelectedException:
-##                    pass
-##    
-##    def __testServerProcFinished(self):
-##        """
-##        Private slot connected to the finished signal of the test server.
-##        """
-##        if self.__testServerProc is not None and \
-##           self.__testServerProc.state() != QProcess.NotRunning:
-##            self.__testServerProc.terminate()
-##            QTimer.singleShot(2000, self.__testServerProc, SLOT('kill()'))
-##            self.__testServerProc.waitForFinished(3000)
-##        self.__testServerProc = None
+    def __dumpData(self):
+        """
+        Private slot to dump the database data to a fixture.
+        """
+        title = self.trUtf8("Dump Data")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        from .DjangoDumpdataDataDialog import DjangoDumpdataDataDialog
+        dlg = DjangoDumpdataDataDialog(self, self.__ui)
+        if dlg.exec_() == QDialog.Accepted:
+            appls, excls, format, indent = dlg.getData()
+            
+            args = []
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("dumpdata")
+            args.append("--format={0}".format(format))
+            args.append("--indent={0}".format(indent))
+            for excl in excls:
+                args.append("--exclude={0}".format(excl))
+            args += appls
+            
+            if format == "json":
+                fileFilters = self.trUtf8("JSON Files (*.json)")
+            elif format == "xml":
+                fileFilters = self.trUtf8("XML Files (*.xml)")
+            elif format == "yaml":
+                fileFilters = self.trUtf8("YAML Files (*.yaml)")
+            
+            dia = DjangoDialog(title, fixed = True, linewrap = False, 
+                saveFilters = fileFilters)
+            res = dia.startProcess(args, wd, showCommand = False)
+            if res:
+                dia.exec_()
+    
+    def __loadData(self):
+        """
+        Private slot to load data from fixture files.
+        """
+        title = self.trUtf8("Load Data")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            return
+        
+        from .DjangoLoaddataDataDialog import DjangoLoaddataDataDialog
+        dlg = DjangoLoaddataDataDialog(self, self.__ui)
+        if dlg.exec_() == QDialog.Accepted:
+            fixtures = dlg.getData()
+            
+            args = []
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("loaddata")
+            args += fixtures
+            
+            dia = DjangoDialog(title)
+            res = dia.startProcess(args, wd)
+            if res:
+                dia.exec_()
+    
+    def __runTestSuite(self):
+        """
+        Private slot to run the test suite for applications or the whole site.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommandNoClose"))[1]
+        if consoleCmd:
+            try:
+                wd = self.__sitePath()
+            except DjangoNoSiteSelectedException:
+                return
+            
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.__getPythonExecutable())
+            args.append("manage.py")
+            args.append("test")
+            args += self.__getApplications()
+            
+            started, pid = QProcess.startDetached(args[0], args[1:], wd)
+            if not started:
+                E5MessageBox.critical(None,
+                    self.trUtf8('Process Generation Error'),
+                    self.trUtf8('The Django process could not be started.'))
+    
+    def __runTestServer(self):
+        """
+        Private slot to run a development server with data from a set of fixtures.
+        """
+        consoleCmd = self.__isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            from .DjangoLoaddataDataDialog import DjangoLoaddataDataDialog
+            dlg = DjangoLoaddataDataDialog(self, self.__ui)
+            if dlg.exec_() == QDialog.Accepted:
+                fixtures = dlg.getData()
+                
+                args = Utilities.parseOptionString(consoleCmd)
+                args[0] = Utilities.getExecutablePath(args[0])
+                args.append(self.__getPythonExecutable())
+                args.append("manage.py")
+                args.append("testserver")
+                addr = self.__plugin.getPreferences("ServerAddress")
+                if addr:
+                    args.append("--addrport=%s" % addr)
+                args += fixtures
+                
+                try:
+                    if Utilities.isWindowsPlatform():
+                        serverProcStarted, pid = \
+                            QProcess.startDetached(args[0], args[1:], self.__sitePath())
+                    else:
+                        if self.__testServerProc is not None:
+                            self.__testServerProcFinished()
+                        
+                        self.__testServerProc = QProcess()
+                        self.__testServerProc.finished.connect(self.__serverProcFinished)
+                        self.__testServerProc.setWorkingDirectory(self.__sitePath())
+                        self.__testServerProc.start(args[0], args[1:])
+                        serverProcStarted = self.__testServerProc.waitForStarted()
+                    if not serverProcStarted:
+                        E5MessageBox.critical(None,
+                            self.trUtf8('Process Generation Error'),
+                            self.trUtf8('The Django test server could not be started.'))
+                except DjangoNoSiteSelectedException:
+                    pass
+    
+    def __testServerProcFinished(self):
+        """
+        Private slot connected to the finished signal of the test server.
+        """
+        if self.__testServerProc is not None and \
+           self.__testServerProc.state() != QProcess.NotRunning:
+            self.__testServerProc.terminate()
+            QTimer.singleShot(2000, self.__testServerProc.kill)
+            self.__testServerProc.waitForFinished(3000)
+        self.__testServerProc = None
     
     ##################################################################
     ## slots below implement translation functions
     ##################################################################
     
-##    def __getLocale(self, filename):
-##        """
-##        Private method to extract the locale out of a file name.
-##        
-##        @param filename name of the file used for extraction (string or QString)
-##        @return extracted locale (string) or None
-##        """
-##        if self.__e4project.pdata["TRANSLATIONPATTERN"]:
-##            pattern = unicode(self.__e4project.pdata["TRANSLATIONPATTERN"][0])\
-##                .replace("%language%", "(.*?)")
-##            match = re.search(pattern, unicode(filename))
-##            if match is not None:
-##                loc = match.group(1)
-##                return loc
-##            else:
-##                loc = None
-##        else:
-##            loc = None
-##        
-##        return loc
-##    
-##    def __normalizeList(self, filenames):
-##        """
-##        Private method to normalize a list of file names.
-##        
-##        @param filenames list of file names to normalize (list of string or QString)
-##        @return normalized file names (list of string)
-##        """
-##        nfilenames = []
-##        for filename in filenames:
-##            filename = unicode(filename)
-##            if filename.endswith(".mo"):
-##                filename = filename.replace(".mo", ".po")
-##            if filename not in nfilenames:
-##                nfilenames.append(filename)
-##        
-##        return nfilenames
-##    
-##    def __siteFilteredList(self, filenames):
-##        """
-##        Private method to filter a list of file names by site.
-##        
-##        @param filenames list of file names to be filtered (list of string or QString)
-##        @return file names belonging to the current site (list of string)
-##        """
-##        site = self.__site()
-##        nfilenames = []
-##        for filename in filenames:
-##            filename = unicode(filename)
-##            if site == "" or filename.startswith(site + os.sep):
-##                nfilenames.append(filename)
-##        
-##        return nfilenames
+    # TODO: the below stuff needs testing
+    def __getLocale(self, filename):
+        """
+        Private method to extract the locale out of a file name.
+        
+        @param filename name of the file used for extraction (string)
+        @return extracted locale (string) or None
+        """
+        if self.__e5project.pdata["TRANSLATIONPATTERN"]:
+            pattern = self.__e5project.pdata["TRANSLATIONPATTERN"][0]\
+                .replace("%language%", "(.*?)")
+            match = re.search(pattern, filename)
+            if match is not None:
+                loc = match.group(1)
+                return loc
+            else:
+                loc = None
+        else:
+            loc = None
+        
+        return loc
+    
+    def __normalizeList(self, filenames):
+        """
+        Private method to normalize a list of file names.
+        
+        @param filenames list of file names to normalize (list of strings)
+        @return normalized file names (list of strings)
+        """
+        nfilenames = []
+        for filename in filenames:
+            if filename.endswith(".mo"):
+                filename = filename.replace(".mo", ".po")
+            if filename not in nfilenames:
+                nfilenames.append(filename)
+        
+        return nfilenames
+    
+    def __siteFilteredList(self, filenames):
+        """
+        Private method to filter a list of file names by site.
+        
+        @param filenames list of file names to be filtered (list of strings)
+        @return file names belonging to the current site (list of strings)
+        """
+        site = self.__site()
+        nfilenames = []
+        for filename in filenames:
+            if site == "" or filename.startswith(site + os.sep):
+                nfilenames.append(filename)
+        
+        return nfilenames
     
     def __projectLanguageAdded(self, code):
         """
         Private slot handling the addition of a new language.
         
-        @param code language code of the new language (string or QString)
+        @param code language code of the new language (string)
         """
-##        title = self.trUtf8("Initializing message catalog for '%1'").arg(code)
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("makemessages")
-##        args.append("-l")
-##        args.append(code)
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No current site selected or no site created yet.'
-##                            ' Aborting...'))
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = \
-##                self.trUtf8("\nMessage catalog initialized successfully."))
-##        res = dia.startProcess(args, wd)
-##        if res:
-##            dia.exec_()
-##            
-##            langFile = self.__e4project.pdata["TRANSLATIONPATTERN"][0]\
-##                .replace("%language%", code)
-##            self.__e4project.appendFile(langFile)
+        title = self.trUtf8("Initializing message catalog for '{0}'").format(code)
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("makemessages")
+        args.append("--domain=django")
+        args.append("--domain=djangojs")
+        args.append("-l")
+        args.append(code)
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalog initialized successfully."))
+        res = dia.startProcess(args, wd)
+        if res:
+            dia.exec_()
+            
+            langFile = self.__e5project.pdata["TRANSLATIONPATTERN"][0]\
+                .replace("%language%", code)
+            self.__e5project.appendFile(langFile)
     
     def updateSelectedCatalogs(self, filenames):
         """
         Public method to update the message catalogs.
         
+        @param filenames list of file names (list of strings)
+        """
+        title = self.trUtf8("Updating message catalogs")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        argsLists = []
+        
+        for filename in self.__normalizeList(self.__siteFilteredList(filenames)):
+            locale = self.__getLocale(filename)
+            if locale:
+                args = []
+                args.append(self.__getPythonExecutable())
+                args.append("manage.py")
+                args.append("makemessages")
+                args.append("--no-obsolete")
+                args.append("--domain=django")
+                args.append("--domain=djangojs")
+                args.append("-l")
+                args.append(locale)
+                argsLists.append(args)
+        
+        if len(argsLists) == 0:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No locales detected. Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs updated successfully."))
+        res = dia.startBatchProcesses(argsLists, wd)
+        if res:
+            dia.exec_()
+    
+    def updateSelectedCatalogsWithObsolete(self, filenames):
+        """
+        Public method to update the message catalogs keeping obsolete messages.
+        
         @param filenames list of filenames
         """
-##        title = self.trUtf8("Updating message catalogs")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No current site selected or no site created yet.'
-##                            ' Aborting...'))
-##            return
-##        
-##        argsLists = []
-##        
-##        for filename in self.__normalizeList(self.__siteFilteredList(filenames)):
-##            locale = self.__getLocale(filename)
-##            if locale:
-##                args = QStringList()
-##                args.append(self.__getPythonExecutable())
-##                args.append("manage.py")
-##                args.append("makemessages")
-##                args.append("-l")
-##                args.append(locale)
-##                argsLists.append(args)
-##        
-##        if len(argsLists) == 0:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No locales detected.'
-##                            ' Aborting...'))
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = \
-##                self.trUtf8("\nMessage catalogs updated successfully."))
-##        res = dia.startBatchProcesses(argsLists, wd)
-##        if res:
-##            dia.exec_()
+        title = self.trUtf8("Updating message catalogs (keeping obsolete messages)")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        argsLists = []
+        
+        for filename in self.__normalizeList(self.__siteFilteredList(filenames)):
+            locale = self.__getLocale(filename)
+            if locale:
+                args = []
+                args.append(self.__getPythonExecutable())
+                args.append("manage.py")
+                args.append("makemessages")
+                args.append("--domain=django")
+                args.append("--domain=djangojs")
+                args.append("-l")
+                args.append(locale)
+                argsLists.append(args)
+        
+        if len(argsLists) == 0:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No locales detected. Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs updated successfully."))
+        res = dia.startBatchProcesses(argsLists, wd)
+        if res:
+            dia.exec_()
     
     def updateCatalogs(self, filenames):
         """
@@ -1936,29 +1871,64 @@
         
         @param filenames list of filenames (not used)
         """
-##        title = self.trUtf8("Updating message catalogs")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("makemessages")
-##        args.append("-a")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No current site selected or no site created yet.'
-##                            ' Aborting...'))
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = \
-##                self.trUtf8("\nMessage catalogs updated successfully."))
-##        res = dia.startProcess(args, wd)
-##        if res:
-##            dia.exec_()
+        title = self.trUtf8("Updating message catalogs")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("makemessages")
+        args.append("-a")
+        args.append("--no-obsolete")
+        args.append("--domain=django")
+        args.append("--domain=djangojs")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs updated successfully."))
+        res = dia.startProcess(args, wd)
+        if res:
+            dia.exec_()
+    
+    def updateCatalogsWithObsolete(self, filenames):
+        """
+        Public method to update the message catalogs keeping obsolete messages.
+        
+        @param filenames list of filenames (not used)
+        """
+        title = self.trUtf8("Updating message catalogs (keeping obsolete messages)")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("makemessages")
+        args.append("-a")
+        args.append("--domain=django")
+        args.append("--domain=djangojs")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs updated successfully."))
+        res = dia.startProcess(args, wd)
+        if res:
+            dia.exec_()
     
     def compileSelectedCatalogs(self, filenames):
         """
@@ -1966,49 +1936,48 @@
         
         @param filenames list of filenames
         """
-##        title = self.trUtf8("Compiling message catalogs")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No current site selected or no site created yet.'
-##                            ' Aborting...'))
-##            return
-##        
-##        argsLists = []
-##        
-##        for filename in self.__normalizeList(self.__siteFilteredList(filenames)):
-##            locale = self.__getLocale(filename)
-##            if locale:
-##                args = QStringList()
-##                args.append(self.__getPythonExecutable())
-##                args.append("manage.py")
-##                args.append("compilemessages")
-##                args.append("-l")
-##                args.append(locale)
-##                argsLists.append(args)
-##        
-##        if len(argsLists) == 0:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No locales detected.'
-##                            ' Aborting...'))
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = \
-##                self.trUtf8("\nMessage catalogs compiled successfully."))
-##        res = dia.startBatchProcesses(argsLists, wd, mergedOutput = True)
-##        if res:
-##            dia.exec_()
-##            
-##            for entry in os.walk(self.__sitePath()):
-##                for fileName in entry[2]:
-##                    fullName = os.path.join(entry[0], fileName)
-##                    if fullName.endswith('.mo'):
-##                        self.__e4project.appendFile(fullName)
+        title = self.trUtf8("Compiling message catalogs")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        argsLists = []
+        
+        for filename in self.__normalizeList(self.__siteFilteredList(filenames)):
+            locale = self.__getLocale(filename)
+            if locale:
+                args = []
+                args.append(self.__getPythonExecutable())
+                args.append("manage.py")
+                args.append("compilemessages")
+                args.append("-l")
+                args.append(locale)
+                argsLists.append(args)
+        
+        if len(argsLists) == 0:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No locales detected. Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs compiled successfully."))
+        res = dia.startBatchProcesses(argsLists, wd, mergedOutput = True)
+        if res:
+            dia.exec_()
+            
+            for entry in os.walk(self.__sitePath()):
+                for fileName in entry[2]:
+                    fullName = os.path.join(entry[0], fileName)
+                    if fullName.endswith('.mo'):
+                        self.__e5project.appendFile(fullName)
     
     def compileCatalogs(self, filenames):
         """
@@ -2016,31 +1985,31 @@
         
         @param filenames list of filenames (not used)
         """
-##        title = self.trUtf8("Compiling message catalogs")
-##        
-##        args = QStringList()
-##        args.append(self.__getPythonExecutable())
-##        args.append("manage.py")
-##        args.append("compilemessages")
-##        
-##        try:
-##            wd = self.__sitePath()
-##        except DjangoNoSiteSelectedException:
-##            KQMessageBox.warning(None,
-##                title,
-##                self.trUtf8('No current site selected or no site created yet.'
-##                            ' Aborting...'))
-##            return
-##        
-##        dia = DjangoDialog(title, 
-##            msgSuccess = \
-##                self.trUtf8("\nMessage catalogs compiled successfully."))
-##        res = dia.startProcess(args, wd, mergedOutput = True)
-##        if res:
-##            dia.exec_()
-##            
-##            for entry in os.walk(self.__sitePath()):
-##                for fileName in entry[2]:
-##                    fullName = os.path.join(entry[0], fileName)
-##                    if fullName.endswith('.mo'):
-##                        self.__e4project.appendFile(fullName)
+        title = self.trUtf8("Compiling message catalogs")
+        
+        args = []
+        args.append(self.__getPythonExecutable())
+        args.append("manage.py")
+        args.append("compilemessages")
+        
+        try:
+            wd = self.__sitePath()
+        except DjangoNoSiteSelectedException:
+            E5MessageBox.warning(None,
+                title,
+                self.trUtf8('No current site selected or no site created yet.'
+                            ' Aborting...'))
+            return
+        
+        dia = DjangoDialog(title, 
+            msgSuccess = \
+                self.trUtf8("\nMessage catalogs compiled successfully."))
+        res = dia.startProcess(args, wd, mergedOutput = True)
+        if res:
+            dia.exec_()
+            
+            for entry in os.walk(self.__sitePath()):
+                for fileName in entry[2]:
+                    fullName = os.path.join(entry[0], fileName)
+                    if fullName.endswith('.mo'):
+                        self.__e5project.appendFile(fullName)

eric ide

mercurial