From d75ef7982aaf96572ea26b1986b3578d9b1eca06 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 04:45:48 +0900
Subject: first attempt at class splitting

war on spaguetti! :D
---
 src/leap/baseapp/mainwindow.py | 506 ++++++++++++++++++++++-------------------
 1 file changed, 270 insertions(+), 236 deletions(-)

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py
index 2f7a14dd..ca9b79b3 100644
--- a/src/leap/baseapp/mainwindow.py
+++ b/src/leap/baseapp/mainwindow.py
@@ -2,7 +2,9 @@
 #!/usr/bin/env python
 import logging
 import time
+logging.basicConfig()
 logger = logging.getLogger(name=__name__)
+logger.setLevel(logging.DEBUG)
 
 from PyQt4.QtGui import (QMainWindow, QWidget, QVBoxLayout, QMessageBox,
                          QSystemTrayIcon, QGroupBox, QLabel, QPixmap,
@@ -14,63 +16,22 @@ from PyQt4.QtCore import (pyqtSlot, pyqtSignal, QTimer)
 from leap.baseapp.dialogs import ErrorDialog
 from leap.eip import exceptions as eip_exceptions
 from leap.eip.eipconnection import EIPConnection
-from leap.gui import mainwindow_rc
-
-
-class LeapWindow(QMainWindow):
-    #XXX tbd: refactor into model / view / controller
-    #and put in its own modules...
-
-    newLogLine = pyqtSignal([str])
-    statusChange = pyqtSignal([object])
-
-    def __init__(self, opts):
-        super(LeapWindow, self).__init__()
-        self.debugmode = getattr(opts, 'debug', False)
-
-        self.eip_service_started = False
-
-        self.createWindowHeader()
-        self.createIconGroupBox()
 
-        self.createActions()
-        self.createTrayIcon()
-        if self.debugmode:
-            self.createLogBrowser()
-
-        # create timer
-        self.timer = QTimer()
-
-        # bind signals
-        self.trayIcon.activated.connect(self.iconActivated)
-        self.newLogLine.connect(self.onLoggerNewLine)
-        self.statusChange.connect(self.onStatusChange)
-        self.timer.timeout.connect(self.onTimerTick)
-
-        widget = QWidget()
-        self.setCentralWidget(widget)
+from leap.gui import mainwindow_rc
 
-        # add widgets to layout
-        mainLayout = QVBoxLayout()
-        mainLayout.addWidget(self.headerBox)
-        mainLayout.addWidget(self.statusIconBox)
-        if self.debugmode:
-            mainLayout.addWidget(self.statusBox)
-            mainLayout.addWidget(self.loggerBox)
-        widget.setLayout(mainLayout)
 
-        self.trayIcon.show()
-        self.setWindowTitle("LEAP Client")
-        self.resize(400, 300)
-        self.set_statusbarMessage('ready')
+class EIPConductorApp(object):
 
+    def __init__(self, *args, **kwargs):
         #
         # conductor is in charge of all
         # vpn-related configuration / monitoring.
         # we pass a tuple of signals that will be
         # triggered when status changes.
         #
+        opts = kwargs.pop('opts')
         config_file = getattr(opts, 'config_file', None)
+
         self.conductor = EIPConnection(
             watcher_cb=self.newLogLine.emit,
             config_file=config_file,
@@ -79,7 +40,11 @@ class LeapWindow(QMainWindow):
 
         # XXX remove skip download when sample service is ready
         self.conductor.run_checks(skip_download=True)
+        self.error_check()
+        if self.conductor.autostart:
+            self.start_or_stopVPN()
 
+    def error_check(self):
         ####### error checking ################
         #
         # bunch of self checks.
@@ -142,78 +107,89 @@ class LeapWindow(QMainWindow):
                 'error')
 
         ############ end error checking ###################
-
-        if self.conductor.autostart:
-            self.start_or_stopVPN()
-
-    def closeEvent(self, event):
+    @pyqtSlot()
+    def statusUpdate(self):
         """
-        redefines close event (persistent window behaviour)
+        called on timer tick
+        polls status and updates ui with real time
+        info about transferred bytes / connection state.
         """
-        if self.trayIcon.isVisible() and not self.debugmode:
-            QMessageBox.information(self, "Systray",
-                                    "The program will keep running "
-                                    "in the system tray. To "
-                                    "terminate the program, choose "
-                                    "<b>Quit</b> in the "
-                                    "context menu of the system tray entry.")
-            self.hide()
-            event.ignore()
+        # XXX it's too expensive to poll
+        # continously. move to signal events instead.
+
+        if not self.eip_service_started:
+            return
+
+        # XXX remove all access to manager layer
+        # from here.
+        if self.conductor.with_errors:
+            #XXX how to wait on pkexec???
+            #something better that this workaround, plz!!
+            time.sleep(5)
+            print('errors. disconnect.')
+            self.start_or_stopVPN()  # is stop
+
+        state = self.conductor.poll_connection_state()
+        if not state:
+            return
+
+        ts, con_status, ok, ip, remote = state
+        self.set_statusbarMessage(con_status)
+        self.setIconToolTip()
+
+        ts = time.strftime("%a %b %d %X", ts)
         if self.debugmode:
-            self.cleanupAndQuit()
+            self.updateTS.setText(ts)
+            self.status_label.setText(con_status)
+            self.ip_label.setText(ip)
+            self.remote_label.setText(remote)
 
-    def setIcon(self, name):
-        icon = self.Icons.get(name)
-        self.trayIcon.setIcon(icon)
-        self.setWindowIcon(icon)
+        # status i/o
 
-    def setToolTip(self):
-        """
-        get readable status and place it on systray tooltip
-        """
-        status = self.conductor.status.get_readable_status()
-        self.trayIcon.setToolTip(status)
+        status = self.conductor.get_status_io()
+        if status and self.debugmode:
+            #XXX move this to systray menu indicators
+            ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read) = status
+            ts = time.strftime("%a %b %d %X", ts)
+            self.updateTS.setText(ts)
+            self.tun_read_bytes.setText(tun_read)
+            self.tun_write_bytes.setText(tun_write)
 
-    def iconActivated(self, reason):
+    @pyqtSlot()
+    def start_or_stopVPN(self):
         """
-        handles left click, left double click
-        showing the trayicon menu
+        stub for running child process with vpn
         """
-        #XXX there's a bug here!
-        #menu shows on (0,0) corner first time,
-        #until double clicked at least once.
-        if reason in (QSystemTrayIcon.Trigger,
-                      QSystemTrayIcon.DoubleClick):
-            self.trayIconMenu.show()
+        if self.eip_service_started is False:
+            try:
+                self.conductor.connect()
+                # XXX move this to error queue
+            except eip_exceptions.EIPNoCommandError:
+                dialog = ErrorDialog()
+                dialog.warningMessage(
+                    'No suitable openvpn command found. '
+                    '<br/>(Might be a permissions problem)',
+                    'error')
+            if self.debugmode:
+                self.startStopButton.setText('&Disconnect')
+            self.eip_service_started = True
 
-    def createWindowHeader(self):
-        """
-        description lines for main window
-        """
-        #XXX good candidate to refactor out! :)
-        self.headerBox = QGroupBox()
-        self.headerLabel = QLabel("<font size=40><b>E</b>ncryption \
-<b>I</b>nternet <b>P</b>roxy</font>")
-        self.headerLabelSub = QLabel("<i>trust your \
-technolust</i>")
+            # XXX what is optimum polling interval?
+            # too little is overkill, too much
+            # will miss transition states..
 
-        pixmap = QPixmap(':/images/leapfrog.jpg')
-        frog_lbl = QLabel()
-        frog_lbl.setPixmap(pixmap)
+            self.timer.start(250.0)
+            return
+        if self.eip_service_started is True:
+            self.conductor.disconnect()
+            if self.debugmode:
+                self.startStopButton.setText('&Connect')
+            self.eip_service_started = False
+            self.timer.stop()
+            return
 
-        headerLayout = QHBoxLayout()
-        headerLayout.addWidget(frog_lbl)
-        headerLayout.addWidget(self.headerLabel)
-        headerLayout.addWidget(self.headerLabelSub)
-        headerLayout.addStretch()
-        self.headerBox.setLayout(headerLayout)
 
-    def getIcon(self, icon_name):
-        # XXX get from connection dict
-        icons = {'disconnected': 0,
-                 'connecting': 1,
-                 'connected': 2}
-        return icons.get(icon_name, None)
+class StatusAwareTrayIcon(object):
 
     def createIconGroupBox(self):
         """
@@ -254,6 +230,25 @@ technolust</i>")
         statusIconLayout.itemAt(2).widget().hide()
         self.statusIconBox.setLayout(statusIconLayout)
 
+    def createTrayIcon(self):
+        """
+        creates the tray icon
+        """
+        self.trayIconMenu = QMenu(self)
+
+        self.trayIconMenu.addAction(self.connectVPNAction)
+        self.trayIconMenu.addAction(self.dis_connectAction)
+        self.trayIconMenu.addSeparator()
+        self.trayIconMenu.addAction(self.minimizeAction)
+        self.trayIconMenu.addAction(self.maximizeAction)
+        self.trayIconMenu.addAction(self.restoreAction)
+        self.trayIconMenu.addSeparator()
+        self.trayIconMenu.addAction(self.quitAction)
+
+        self.trayIcon = QSystemTrayIcon(self)
+        self.setIcon('disconnected')
+        self.trayIcon.setContextMenu(self.trayIconMenu)
+
     def createActions(self):
         """
         creates actions to be binded to tray icon
@@ -261,8 +256,9 @@ technolust</i>")
         self.connectVPNAction = QAction("Connect to &VPN", self,
                                         triggered=self.hide)
         # XXX change action name on (dis)connect
-        self.dis_connectAction = QAction("&(Dis)connect", self,
-                                         triggered=self.start_or_stopVPN)
+        self.dis_connectAction = QAction(
+            "&(Dis)connect", self,
+            triggered=lambda: self.start_or_stopVPN())
         self.minimizeAction = QAction("Mi&nimize", self,
                                       triggered=self.hide)
         self.maximizeAction = QAction("Ma&ximize", self,
@@ -272,24 +268,128 @@ technolust</i>")
         self.quitAction = QAction("&Quit", self,
                                   triggered=self.cleanupAndQuit)
 
-    def createTrayIcon(self):
+    def setConnWidget(self, icon_name):
+        #print 'changing icon to %s' % icon_name
+        oldlayout = self.statusIconBox.layout()
+
+        # XXX reuse with icons
+        # XXX move states to StateWidget
+        states = {"disconnected": 0,
+                  "connecting": 1,
+                  "connected": 2}
+
+        for i in range(3):
+            oldlayout.itemAt(i).widget().hide()
+        new = states[icon_name]
+        oldlayout.itemAt(new).widget().show()
+
+    def setIcon(self, name):
+        icon = self.Icons.get(name)
+        self.trayIcon.setIcon(icon)
+        self.setWindowIcon(icon)
+
+    def getIcon(self, icon_name):
+        # XXX get from connection dict
+        icons = {'disconnected': 0,
+                 'connecting': 1,
+                 'connected': 2}
+        return icons.get(icon_name, None)
+
+    def setIconToolTip(self):
         """
-        creates the tray icon
+        get readable status and place it on systray tooltip
         """
-        self.trayIconMenu = QMenu(self)
+        status = self.conductor.status.get_readable_status()
+        self.trayIcon.setToolTip(status)
 
-        self.trayIconMenu.addAction(self.connectVPNAction)
-        self.trayIconMenu.addAction(self.dis_connectAction)
-        self.trayIconMenu.addSeparator()
-        self.trayIconMenu.addAction(self.minimizeAction)
-        self.trayIconMenu.addAction(self.maximizeAction)
-        self.trayIconMenu.addAction(self.restoreAction)
-        self.trayIconMenu.addSeparator()
-        self.trayIconMenu.addAction(self.quitAction)
+    def iconActivated(self, reason):
+        """
+        handles left click, left double click
+        showing the trayicon menu
+        """
+        #XXX there's a bug here!
+        #menu shows on (0,0) corner first time,
+        #until double clicked at least once.
+        if reason in (QSystemTrayIcon.Trigger,
+                      QSystemTrayIcon.DoubleClick):
+            self.trayIconMenu.show()
 
-        self.trayIcon = QSystemTrayIcon(self)
-        self.setIcon('disconnected')
-        self.trayIcon.setContextMenu(self.trayIconMenu)
+    @pyqtSlot()
+    def onTimerTick(self):
+        self.statusUpdate()
+
+    @pyqtSlot(object)
+    def onStatusChange(self, status):
+        """
+        slot for status changes. triggers new signals for
+        updating icon, status bar, etc.
+        """
+
+        #print('STATUS CHANGED! (on Qt-land)')
+        #print('%s -> %s' % (status.previous, status.current))
+        icon_name = self.conductor.get_icon_name()
+        self.setIcon(icon_name)
+        #print 'icon = ', icon_name
+
+        # change connection pixmap widget
+        self.setConnWidget(icon_name)
+
+
+class LeapMainWindow(object):
+
+    def createWindowHeader(self):
+        """
+        description lines for main window
+        """
+        #XXX good candidate to refactor out! :)
+        self.headerBox = QGroupBox()
+        self.headerLabel = QLabel("<font size=40><b>E</b>ncryption \
+<b>I</b>nternet <b>P</b>roxy</font>")
+        self.headerLabelSub = QLabel("<i>trust your \
+technolust</i>")
+
+        pixmap = QPixmap(':/images/leapfrog.jpg')
+        frog_lbl = QLabel()
+        frog_lbl.setPixmap(pixmap)
+
+        headerLayout = QHBoxLayout()
+        headerLayout.addWidget(frog_lbl)
+        headerLayout.addWidget(self.headerLabel)
+        headerLayout.addWidget(self.headerLabelSub)
+        headerLayout.addStretch()
+        self.headerBox.setLayout(headerLayout)
+
+    def set_statusbarMessage(self, msg):
+        self.statusBar().showMessage(msg)
+
+    def closeEvent(self, event):
+        """
+        redefines close event (persistent window behaviour)
+        """
+        if self.trayIcon.isVisible() and not self.debugmode:
+            QMessageBox.information(self, "Systray",
+                                    "The program will keep running "
+                                    "in the system tray. To "
+                                    "terminate the program, choose "
+                                    "<b>Quit</b> in the "
+                                    "context menu of the system tray entry.")
+            self.hide()
+            event.ignore()
+        if self.debugmode:
+            self.cleanupAndQuit()
+
+    def cleanupAndQuit(self):
+        """
+        cleans state before shutting down app.
+        """
+        # TODO:make sure to shutdown all child process / threads
+        # in conductor
+        # XXX send signal instead?
+        self.conductor.cleanup()
+        qApp.quit()
+
+
+class LogPane(object):
 
     def createLogBrowser(self):
         """
@@ -301,7 +401,7 @@ technolust</i>")
         self.logbrowser = QTextBrowser()
 
         startStopButton = QPushButton("&Connect")
-        startStopButton.clicked.connect(self.start_or_stopVPN)
+        #startStopButton.clicked.connect(self.start_or_stopVPN)
         self.startStopButton = startStopButton
 
         logging_layout.addWidget(self.logbrowser)
@@ -342,130 +442,64 @@ technolust</i>")
         if self.debugmode:
             self.logbrowser.append(line[:-1])
 
-    def set_statusbarMessage(self, msg):
-        self.statusBar().showMessage(msg)
-
-    @pyqtSlot(object)
-    def onStatusChange(self, status):
-        """
-        slot for status changes. triggers new signals for
-        updating icon, status bar, etc.
-        """
-
-        #print('STATUS CHANGED! (on Qt-land)')
-        #print('%s -> %s' % (status.previous, status.current))
-        icon_name = self.conductor.get_icon_name()
-        self.setIcon(icon_name)
-        #print 'icon = ', icon_name
-
-        # change connection pixmap widget
-        self.setConnWidget(icon_name)
-
-    def setConnWidget(self, icon_name):
-        #print 'changing icon to %s' % icon_name
-        oldlayout = self.statusIconBox.layout()
-
-        # XXX reuse with icons
-        # XXX move states to StateWidget
-        states = {"disconnected": 0,
-                  "connecting": 1,
-                  "connected": 2}
-
-        for i in range(3):
-            oldlayout.itemAt(i).widget().hide()
-        new = states[icon_name]
-        oldlayout.itemAt(new).widget().show()
 
-    @pyqtSlot()
-    def start_or_stopVPN(self):
-        """
-        stub for running child process with vpn
-        """
-        if self.eip_service_started is False:
-            try:
-                self.conductor.connect()
-                # XXX move this to error queue
-            except eip_exceptions.EIPNoCommandError:
-                dialog = ErrorDialog()
-                dialog.warningMessage(
-                    'No suitable openvpn command found. '
-                    '<br/>(Might be a permissions problem)',
-                    'error')
-            if self.debugmode:
-                self.startStopButton.setText('&Disconnect')
-            self.eip_service_started = True
+# XXX
+# main (leave only this here)
+class LeapWindow(QMainWindow, LeapMainWindow, EIPConductorApp,
+                 StatusAwareTrayIcon,
+                 LogPane):
 
-            # XXX what is optimum polling interval?
-            # too little is overkill, too much
-            # will miss transition states..
+    newLogLine = pyqtSignal([str])
+    statusChange = pyqtSignal([object])
 
-            self.timer.start(250.0)
-            return
-        if self.eip_service_started is True:
-            self.conductor.disconnect()
-            if self.debugmode:
-                self.startStopButton.setText('&Connect')
-            self.eip_service_started = False
-            self.timer.stop()
-            return
+    def __init__(self, opts):
+        logger.debug('init leap window')
+        super(LeapWindow, self).__init__()
 
-    @pyqtSlot()
-    def onTimerTick(self):
-        self.statusUpdate()
+        self.debugmode = getattr(opts, 'debug', False)
+        self.eip_service_started = False
 
-    @pyqtSlot()
-    def statusUpdate(self):
-        """
-        called on timer tick
-        polls status and updates ui with real time
-        info about transferred bytes / connection state.
-        """
-        # XXX it's too expensive to poll
-        # continously. move to signal events instead.
+        # create timer
+        self.timer = QTimer()
 
-        if not self.eip_service_started:
-            return
+        if self.debugmode:
+            self.createLogBrowser()
+        EIPConductorApp.__init__(self, opts=opts)
 
-        # XXX remove all access to manager layer
-        # from here.
-        if self.conductor.with_errors:
-            #XXX how to wait on pkexec???
-            #something better that this workaround, plz!!
-            time.sleep(5)
-            print('errors. disconnect.')
-            self.start_or_stopVPN()  # is stop
+        # LeapWindow init
+        self.createWindowHeader()
 
-        state = self.conductor.poll_connection_state()
-        if not state:
-            return
+        # StatusAwareTrayIcon init
+        self.createIconGroupBox()
+        self.createActions()
+        self.createTrayIcon()
 
-        ts, con_status, ok, ip, remote = state
-        self.set_statusbarMessage(con_status)
-        self.setToolTip()
+        widget = QWidget()
+        self.setCentralWidget(widget)
 
-        ts = time.strftime("%a %b %d %X", ts)
+        # add widgets to layout
+        mainLayout = QVBoxLayout()
+        mainLayout.addWidget(self.headerBox)
+        mainLayout.addWidget(self.statusIconBox)
         if self.debugmode:
-            self.updateTS.setText(ts)
-            self.status_label.setText(con_status)
-            self.ip_label.setText(ip)
-            self.remote_label.setText(remote)
+            mainLayout.addWidget(self.statusBox)
+            mainLayout.addWidget(self.loggerBox)
+        widget.setLayout(mainLayout)
 
-        # status i/o
+        # move to icons?
+        self.trayIcon.show()
+        self.setWindowTitle("LEAP Client")
+        self.resize(400, 300)
+        self.set_statusbarMessage('ready')
 
-        status = self.conductor.get_status_io()
-        if status and self.debugmode:
-            #XXX move this to systray menu indicators
-            ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read) = status
-            ts = time.strftime("%a %b %d %X", ts)
-            self.updateTS.setText(ts)
-            self.tun_read_bytes.setText(tun_read)
-            self.tun_write_bytes.setText(tun_write)
+        # bind signals
+        # XXX move to parent classes init??
+        self.trayIcon.activated.connect(self.iconActivated)
+        self.newLogLine.connect(lambda line: self.onLoggerNewLine(line))
+        self.statusChange.connect(lambda status: self.onStatusChange(status))
+        self.timer.timeout.connect(lambda: self.onTimerTick())
 
-    def cleanupAndQuit(self):
-        """
-        cleans state before shutting down app.
-        """
-        # TODO:make sure to shutdown all child process / threads
-        # in conductor
-        self.conductor.cleanup()
-        qApp.quit()
+        # move to eipconductor init?
+        if self.debugmode:
+            self.startStopButton.clicked.connect(
+                lambda: self.start_or_stopVPN())
-- 
cgit v1.2.3


From 3fbc512a49923ac73d2413a083e0bb1f7e163866 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 05:20:31 +0900
Subject: actual split of classes into own modules

still a bit rough, but makes everything a bit more
readable.
---
 src/leap/baseapp/eip.py        | 175 ++++++++++++++++
 src/leap/baseapp/leap_app.py   |  57 +++++
 src/leap/baseapp/log.py        |  56 +++++
 src/leap/baseapp/mainwindow.py | 466 ++---------------------------------------
 src/leap/baseapp/systray.py    | 150 +++++++++++++
 5 files changed, 461 insertions(+), 443 deletions(-)
 create mode 100644 src/leap/baseapp/eip.py
 create mode 100644 src/leap/baseapp/leap_app.py
 create mode 100644 src/leap/baseapp/log.py
 create mode 100644 src/leap/baseapp/systray.py

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py
new file mode 100644
index 00000000..e8b9fe53
--- /dev/null
+++ b/src/leap/baseapp/eip.py
@@ -0,0 +1,175 @@
+import time
+
+from PyQt4 import QtCore
+
+from leap.baseapp.dialogs import ErrorDialog
+from leap.eip import exceptions as eip_exceptions
+from leap.eip.eipconnection import EIPConnection
+
+
+class EIPConductorApp(object):
+
+    def __init__(self, *args, **kwargs):
+        #
+        # conductor is in charge of all
+        # vpn-related configuration / monitoring.
+        # we pass a tuple of signals that will be
+        # triggered when status changes.
+        #
+        opts = kwargs.pop('opts')
+        config_file = getattr(opts, 'config_file', None)
+
+        self.conductor = EIPConnection(
+            watcher_cb=self.newLogLine.emit,
+            config_file=config_file,
+            status_signals=(self.statusChange.emit, ),
+            debug=self.debugmode)
+
+        # XXX remove skip download when sample service is ready
+        self.conductor.run_checks(skip_download=True)
+        self.error_check()
+        if self.conductor.autostart:
+            self.start_or_stopVPN()
+
+    def error_check(self):
+        ####### error checking ################
+        #
+        # bunch of self checks.
+        # XXX move somewhere else alltogether.
+        #
+        if self.conductor.missing_definition is True:
+            dialog = ErrorDialog()
+            dialog.criticalMessage(
+                'The default '
+                'definition.json file cannot be found',
+                'error')
+
+        if self.conductor.missing_provider is True:
+            dialog = ErrorDialog()
+            dialog.criticalMessage(
+                'Missing provider. Add a remote_ip entry '
+                'under section [provider] in eip.cfg',
+                'error')
+
+        if self.conductor.missing_vpn_keyfile is True:
+            dialog = ErrorDialog()
+            dialog.criticalMessage(
+                'Could not find the vpn keys file',
+                'error')
+
+        # ... btw, review pending.
+        # os.kill of subprocess fails if we have
+        # some of this errors.
+
+        if self.conductor.bad_provider is True:
+            dialog = ErrorDialog()
+            dialog.criticalMessage(
+                'Bad provider entry. Check that remote_ip entry '
+                'has an IP under section [provider] in eip.cfg',
+                'error')
+
+        if self.conductor.bad_keyfile_perms is True:
+            dialog = ErrorDialog()
+            dialog.criticalMessage(
+                'The vpn keys file has bad permissions',
+                'error')
+
+        if self.conductor.missing_auth_agent is True:
+            dialog = ErrorDialog()
+            dialog.warningMessage(
+                'We could not find any authentication '
+                'agent in your system.<br/>'
+                'Make sure you have '
+                '<b>polkit-gnome-authentication-agent-1</b> '
+                'running and try again.',
+                'error')
+
+        if self.conductor.missing_pkexec is True:
+            dialog = ErrorDialog()
+            dialog.warningMessage(
+                'We could not find <b>pkexec</b> in your '
+                'system.<br/> Do you want to try '
+                '<b>setuid workaround</b>? '
+                '(<i>DOES NOTHING YET</i>)',
+                'error')
+
+    @QtCore.pyqtSlot()
+    def statusUpdate(self):
+        """
+        called on timer tick
+        polls status and updates ui with real time
+        info about transferred bytes / connection state.
+        """
+        # XXX it's too expensive to poll
+        # continously. move to signal events instead.
+
+        if not self.eip_service_started:
+            return
+
+        # XXX remove all access to manager layer
+        # from here.
+        if self.conductor.with_errors:
+            #XXX how to wait on pkexec???
+            #something better that this workaround, plz!!
+            time.sleep(5)
+            print('errors. disconnect.')
+            self.start_or_stopVPN()  # is stop
+
+        state = self.conductor.poll_connection_state()
+        if not state:
+            return
+
+        ts, con_status, ok, ip, remote = state
+        self.set_statusbarMessage(con_status)
+        self.setIconToolTip()
+
+        ts = time.strftime("%a %b %d %X", ts)
+        if self.debugmode:
+            self.updateTS.setText(ts)
+            self.status_label.setText(con_status)
+            self.ip_label.setText(ip)
+            self.remote_label.setText(remote)
+
+        # status i/o
+
+        status = self.conductor.get_status_io()
+        if status and self.debugmode:
+            #XXX move this to systray menu indicators
+            ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read) = status
+            ts = time.strftime("%a %b %d %X", ts)
+            self.updateTS.setText(ts)
+            self.tun_read_bytes.setText(tun_read)
+            self.tun_write_bytes.setText(tun_write)
+
+    @QtCore.pyqtSlot()
+    def start_or_stopVPN(self):
+        """
+        stub for running child process with vpn
+        """
+        if self.eip_service_started is False:
+            try:
+                self.conductor.connect()
+                # XXX move this to error queue
+            except eip_exceptions.EIPNoCommandError:
+                dialog = ErrorDialog()
+                dialog.warningMessage(
+                    'No suitable openvpn command found. '
+                    '<br/>(Might be a permissions problem)',
+                    'error')
+            if self.debugmode:
+                self.startStopButton.setText('&Disconnect')
+            self.eip_service_started = True
+
+            # XXX what is optimum polling interval?
+            # too little is overkill, too much
+            # will miss transition states..
+
+            self.timer.start(250.0)
+            return
+        if self.eip_service_started is True:
+            self.conductor.disconnect()
+            if self.debugmode:
+                self.startStopButton.setText('&Connect')
+            self.eip_service_started = False
+            self.timer.stop()
+            return
diff --git a/src/leap/baseapp/leap_app.py b/src/leap/baseapp/leap_app.py
new file mode 100644
index 00000000..fb736ee3
--- /dev/null
+++ b/src/leap/baseapp/leap_app.py
@@ -0,0 +1,57 @@
+from PyQt4 import QtGui
+
+from leap.gui import mainwindow_rc
+
+
+class MainWindow(object):
+
+    def createWindowHeader(self):
+        """
+        description lines for main window
+        """
+        self.headerBox = QtGui.QGroupBox()
+        self.headerLabel = QtGui.QLabel("<font size=40><b>E</b>ncryption \
+<b>I</b>nternet <b>P</b>roxy</font>")
+        self.headerLabelSub = QtGui.QLabel("<i>trust your \
+technolust</i>")
+
+        pixmap = QtGui.QPixmap(':/images/leapfrog.jpg')
+        frog_lbl = QtGui.QLabel()
+        frog_lbl.setPixmap(pixmap)
+
+        headerLayout = QtGui.QHBoxLayout()
+        headerLayout.addWidget(frog_lbl)
+        headerLayout.addWidget(self.headerLabel)
+        headerLayout.addWidget(self.headerLabelSub)
+        headerLayout.addStretch()
+        self.headerBox.setLayout(headerLayout)
+
+    def set_statusbarMessage(self, msg):
+        self.statusBar().showMessage(msg)
+
+    def closeEvent(self, event):
+        """
+        redefines close event (persistent window behaviour)
+        """
+        if self.trayIcon.isVisible() and not self.debugmode:
+            QtGui.QMessageBox.information(
+                self, "Systray",
+                "The program will keep running "
+                "in the system tray. To "
+                "terminate the program, choose "
+                "<b>Quit</b> in the "
+                "context menu of the system tray entry.")
+            self.hide()
+            event.ignore()
+        if self.debugmode:
+            self.cleanupAndQuit()
+
+    def cleanupAndQuit(self):
+        """
+        cleans state before shutting down app.
+        """
+        # TODO:make sure to shutdown all child process / threads
+        # in conductor
+        # XXX send signal instead?
+        self.conductor.cleanup()
+        QtGui.qApp.quit()
diff --git a/src/leap/baseapp/log.py b/src/leap/baseapp/log.py
new file mode 100644
index 00000000..139de845
--- /dev/null
+++ b/src/leap/baseapp/log.py
@@ -0,0 +1,56 @@
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+
+class LogPane(object):
+
+    def createLogBrowser(self):
+        """
+        creates Browser widget for displaying logs
+        (in debug mode only).
+        """
+        self.loggerBox = QtGui.QGroupBox()
+        logging_layout = QtGui.QVBoxLayout()
+        self.logbrowser = QtGui.QTextBrowser()
+
+        startStopButton = QtGui.QPushButton("&Connect")
+        #startStopButton.clicked.connect(self.start_or_stopVPN)
+        self.startStopButton = startStopButton
+
+        logging_layout.addWidget(self.logbrowser)
+        logging_layout.addWidget(self.startStopButton)
+        self.loggerBox.setLayout(logging_layout)
+
+        # status box
+
+        self.statusBox = QtGui.QGroupBox()
+        grid = QtGui.QGridLayout()
+
+        self.updateTS = QtGui.QLabel('')
+        self.status_label = QtGui.QLabel('Disconnected')
+        self.ip_label = QtGui.QLabel('')
+        self.remote_label = QtGui.QLabel('')
+
+        tun_read_label = QtGui.QLabel("tun read")
+        self.tun_read_bytes = QtGui.QLabel("0")
+        tun_write_label = QtGui.QLabel("tun write")
+        self.tun_write_bytes = QtGui.QLabel("0")
+
+        grid.addWidget(self.updateTS, 0, 0)
+        grid.addWidget(self.status_label, 0, 1)
+        grid.addWidget(self.ip_label, 1, 0)
+        grid.addWidget(self.remote_label, 1, 1)
+        grid.addWidget(tun_read_label, 2, 0)
+        grid.addWidget(self.tun_read_bytes, 2, 1)
+        grid.addWidget(tun_write_label, 3, 0)
+        grid.addWidget(self.tun_write_bytes, 3, 1)
+
+        self.statusBox.setLayout(grid)
+
+    @QtCore.pyqtSlot(str)
+    def onLoggerNewLine(self, line):
+        """
+        simple slot: writes new line to logger Pane.
+        """
+        if self.debugmode:
+            self.logbrowser.append(line[:-1])
diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py
index ca9b79b3..917fc184 100644
--- a/src/leap/baseapp/mainwindow.py
+++ b/src/leap/baseapp/mainwindow.py
@@ -1,456 +1,31 @@
 # vim: set fileencoding=utf-8 :
 #!/usr/bin/env python
 import logging
-import time
 logging.basicConfig()
 logger = logging.getLogger(name=__name__)
 logger.setLevel(logging.DEBUG)
 
-from PyQt4.QtGui import (QMainWindow, QWidget, QVBoxLayout, QMessageBox,
-                         QSystemTrayIcon, QGroupBox, QLabel, QPixmap,
-                         QHBoxLayout, QIcon,
-                         QPushButton, QGridLayout, QAction, QMenu,
-                         QTextBrowser, qApp)
-from PyQt4.QtCore import (pyqtSlot, pyqtSignal, QTimer)
+from PyQt4 import QtCore
+from PyQt4 import QtGui
 
-from leap.baseapp.dialogs import ErrorDialog
-from leap.eip import exceptions as eip_exceptions
-from leap.eip.eipconnection import EIPConnection
+from leap.baseapp.eip import EIPConductorApp
+from leap.baseapp.log import LogPane
+from leap.baseapp.systray import StatusAwareTrayIcon
+from leap.baseapp.leap_app import MainWindow
 
 from leap.gui import mainwindow_rc
 
 
-class EIPConductorApp(object):
-
-    def __init__(self, *args, **kwargs):
-        #
-        # conductor is in charge of all
-        # vpn-related configuration / monitoring.
-        # we pass a tuple of signals that will be
-        # triggered when status changes.
-        #
-        opts = kwargs.pop('opts')
-        config_file = getattr(opts, 'config_file', None)
-
-        self.conductor = EIPConnection(
-            watcher_cb=self.newLogLine.emit,
-            config_file=config_file,
-            status_signals=(self.statusChange.emit, ),
-            debug=self.debugmode)
-
-        # XXX remove skip download when sample service is ready
-        self.conductor.run_checks(skip_download=True)
-        self.error_check()
-        if self.conductor.autostart:
-            self.start_or_stopVPN()
-
-    def error_check(self):
-        ####### error checking ################
-        #
-        # bunch of self checks.
-        # XXX move somewhere else alltogether.
-        #
-        if self.conductor.missing_definition is True:
-            dialog = ErrorDialog()
-            dialog.criticalMessage(
-                'The default '
-                'definition.json file cannot be found',
-                'error')
-
-        if self.conductor.missing_provider is True:
-            dialog = ErrorDialog()
-            dialog.criticalMessage(
-                'Missing provider. Add a remote_ip entry '
-                'under section [provider] in eip.cfg',
-                'error')
-
-        if self.conductor.missing_vpn_keyfile is True:
-            dialog = ErrorDialog()
-            dialog.criticalMessage(
-                'Could not find the vpn keys file',
-                'error')
-
-        # ... btw, review pending.
-        # os.kill of subprocess fails if we have
-        # some of this errors.
-
-        if self.conductor.bad_provider is True:
-            dialog = ErrorDialog()
-            dialog.criticalMessage(
-                'Bad provider entry. Check that remote_ip entry '
-                'has an IP under section [provider] in eip.cfg',
-                'error')
-
-        if self.conductor.bad_keyfile_perms is True:
-            dialog = ErrorDialog()
-            dialog.criticalMessage(
-                'The vpn keys file has bad permissions',
-                'error')
-
-        if self.conductor.missing_auth_agent is True:
-            dialog = ErrorDialog()
-            dialog.warningMessage(
-                'We could not find any authentication '
-                'agent in your system.<br/>'
-                'Make sure you have '
-                '<b>polkit-gnome-authentication-agent-1</b> '
-                'running and try again.',
-                'error')
-
-        if self.conductor.missing_pkexec is True:
-            dialog = ErrorDialog()
-            dialog.warningMessage(
-                'We could not find <b>pkexec</b> in your '
-                'system.<br/> Do you want to try '
-                '<b>setuid workaround</b>? '
-                '(<i>DOES NOTHING YET</i>)',
-                'error')
-
-        ############ end error checking ###################
-    @pyqtSlot()
-    def statusUpdate(self):
-        """
-        called on timer tick
-        polls status and updates ui with real time
-        info about transferred bytes / connection state.
-        """
-        # XXX it's too expensive to poll
-        # continously. move to signal events instead.
-
-        if not self.eip_service_started:
-            return
-
-        # XXX remove all access to manager layer
-        # from here.
-        if self.conductor.with_errors:
-            #XXX how to wait on pkexec???
-            #something better that this workaround, plz!!
-            time.sleep(5)
-            print('errors. disconnect.')
-            self.start_or_stopVPN()  # is stop
-
-        state = self.conductor.poll_connection_state()
-        if not state:
-            return
-
-        ts, con_status, ok, ip, remote = state
-        self.set_statusbarMessage(con_status)
-        self.setIconToolTip()
-
-        ts = time.strftime("%a %b %d %X", ts)
-        if self.debugmode:
-            self.updateTS.setText(ts)
-            self.status_label.setText(con_status)
-            self.ip_label.setText(ip)
-            self.remote_label.setText(remote)
-
-        # status i/o
-
-        status = self.conductor.get_status_io()
-        if status and self.debugmode:
-            #XXX move this to systray menu indicators
-            ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read) = status
-            ts = time.strftime("%a %b %d %X", ts)
-            self.updateTS.setText(ts)
-            self.tun_read_bytes.setText(tun_read)
-            self.tun_write_bytes.setText(tun_write)
-
-    @pyqtSlot()
-    def start_or_stopVPN(self):
-        """
-        stub for running child process with vpn
-        """
-        if self.eip_service_started is False:
-            try:
-                self.conductor.connect()
-                # XXX move this to error queue
-            except eip_exceptions.EIPNoCommandError:
-                dialog = ErrorDialog()
-                dialog.warningMessage(
-                    'No suitable openvpn command found. '
-                    '<br/>(Might be a permissions problem)',
-                    'error')
-            if self.debugmode:
-                self.startStopButton.setText('&Disconnect')
-            self.eip_service_started = True
-
-            # XXX what is optimum polling interval?
-            # too little is overkill, too much
-            # will miss transition states..
-
-            self.timer.start(250.0)
-            return
-        if self.eip_service_started is True:
-            self.conductor.disconnect()
-            if self.debugmode:
-                self.startStopButton.setText('&Connect')
-            self.eip_service_started = False
-            self.timer.stop()
-            return
-
-
-class StatusAwareTrayIcon(object):
-
-    def createIconGroupBox(self):
-        """
-        dummy icongroupbox
-        (to be removed from here -- reference only)
-        """
-        icons = {
-            'disconnected': ':/images/conn_error.png',
-            'connecting': ':/images/conn_connecting.png',
-            'connected': ':/images/conn_connected.png'
-        }
-        con_widgets = {
-            'disconnected': QLabel(),
-            'connecting': QLabel(),
-            'connected': QLabel(),
-        }
-        con_widgets['disconnected'].setPixmap(
-            QPixmap(icons['disconnected']))
-        con_widgets['connecting'].setPixmap(
-            QPixmap(icons['connecting']))
-        con_widgets['connected'].setPixmap(
-            QPixmap(icons['connected'])),
-        self.ConnectionWidgets = con_widgets
-
-        con_icons = {
-            'disconnected': QIcon(icons['disconnected']),
-            'connecting': QIcon(icons['connecting']),
-            'connected': QIcon(icons['connected'])
-        }
-        self.Icons = con_icons
-
-        self.statusIconBox = QGroupBox("Connection Status")
-        statusIconLayout = QHBoxLayout()
-        statusIconLayout.addWidget(self.ConnectionWidgets['disconnected'])
-        statusIconLayout.addWidget(self.ConnectionWidgets['connecting'])
-        statusIconLayout.addWidget(self.ConnectionWidgets['connected'])
-        statusIconLayout.itemAt(1).widget().hide()
-        statusIconLayout.itemAt(2).widget().hide()
-        self.statusIconBox.setLayout(statusIconLayout)
-
-    def createTrayIcon(self):
-        """
-        creates the tray icon
-        """
-        self.trayIconMenu = QMenu(self)
-
-        self.trayIconMenu.addAction(self.connectVPNAction)
-        self.trayIconMenu.addAction(self.dis_connectAction)
-        self.trayIconMenu.addSeparator()
-        self.trayIconMenu.addAction(self.minimizeAction)
-        self.trayIconMenu.addAction(self.maximizeAction)
-        self.trayIconMenu.addAction(self.restoreAction)
-        self.trayIconMenu.addSeparator()
-        self.trayIconMenu.addAction(self.quitAction)
-
-        self.trayIcon = QSystemTrayIcon(self)
-        self.setIcon('disconnected')
-        self.trayIcon.setContextMenu(self.trayIconMenu)
-
-    def createActions(self):
-        """
-        creates actions to be binded to tray icon
-        """
-        self.connectVPNAction = QAction("Connect to &VPN", self,
-                                        triggered=self.hide)
-        # XXX change action name on (dis)connect
-        self.dis_connectAction = QAction(
-            "&(Dis)connect", self,
-            triggered=lambda: self.start_or_stopVPN())
-        self.minimizeAction = QAction("Mi&nimize", self,
-                                      triggered=self.hide)
-        self.maximizeAction = QAction("Ma&ximize", self,
-                                      triggered=self.showMaximized)
-        self.restoreAction = QAction("&Restore", self,
-                                     triggered=self.showNormal)
-        self.quitAction = QAction("&Quit", self,
-                                  triggered=self.cleanupAndQuit)
-
-    def setConnWidget(self, icon_name):
-        #print 'changing icon to %s' % icon_name
-        oldlayout = self.statusIconBox.layout()
-
-        # XXX reuse with icons
-        # XXX move states to StateWidget
-        states = {"disconnected": 0,
-                  "connecting": 1,
-                  "connected": 2}
-
-        for i in range(3):
-            oldlayout.itemAt(i).widget().hide()
-        new = states[icon_name]
-        oldlayout.itemAt(new).widget().show()
-
-    def setIcon(self, name):
-        icon = self.Icons.get(name)
-        self.trayIcon.setIcon(icon)
-        self.setWindowIcon(icon)
-
-    def getIcon(self, icon_name):
-        # XXX get from connection dict
-        icons = {'disconnected': 0,
-                 'connecting': 1,
-                 'connected': 2}
-        return icons.get(icon_name, None)
-
-    def setIconToolTip(self):
-        """
-        get readable status and place it on systray tooltip
-        """
-        status = self.conductor.status.get_readable_status()
-        self.trayIcon.setToolTip(status)
-
-    def iconActivated(self, reason):
-        """
-        handles left click, left double click
-        showing the trayicon menu
-        """
-        #XXX there's a bug here!
-        #menu shows on (0,0) corner first time,
-        #until double clicked at least once.
-        if reason in (QSystemTrayIcon.Trigger,
-                      QSystemTrayIcon.DoubleClick):
-            self.trayIconMenu.show()
-
-    @pyqtSlot()
-    def onTimerTick(self):
-        self.statusUpdate()
-
-    @pyqtSlot(object)
-    def onStatusChange(self, status):
-        """
-        slot for status changes. triggers new signals for
-        updating icon, status bar, etc.
-        """
-
-        #print('STATUS CHANGED! (on Qt-land)')
-        #print('%s -> %s' % (status.previous, status.current))
-        icon_name = self.conductor.get_icon_name()
-        self.setIcon(icon_name)
-        #print 'icon = ', icon_name
-
-        # change connection pixmap widget
-        self.setConnWidget(icon_name)
-
-
-class LeapMainWindow(object):
-
-    def createWindowHeader(self):
-        """
-        description lines for main window
-        """
-        #XXX good candidate to refactor out! :)
-        self.headerBox = QGroupBox()
-        self.headerLabel = QLabel("<font size=40><b>E</b>ncryption \
-<b>I</b>nternet <b>P</b>roxy</font>")
-        self.headerLabelSub = QLabel("<i>trust your \
-technolust</i>")
-
-        pixmap = QPixmap(':/images/leapfrog.jpg')
-        frog_lbl = QLabel()
-        frog_lbl.setPixmap(pixmap)
-
-        headerLayout = QHBoxLayout()
-        headerLayout.addWidget(frog_lbl)
-        headerLayout.addWidget(self.headerLabel)
-        headerLayout.addWidget(self.headerLabelSub)
-        headerLayout.addStretch()
-        self.headerBox.setLayout(headerLayout)
-
-    def set_statusbarMessage(self, msg):
-        self.statusBar().showMessage(msg)
-
-    def closeEvent(self, event):
-        """
-        redefines close event (persistent window behaviour)
-        """
-        if self.trayIcon.isVisible() and not self.debugmode:
-            QMessageBox.information(self, "Systray",
-                                    "The program will keep running "
-                                    "in the system tray. To "
-                                    "terminate the program, choose "
-                                    "<b>Quit</b> in the "
-                                    "context menu of the system tray entry.")
-            self.hide()
-            event.ignore()
-        if self.debugmode:
-            self.cleanupAndQuit()
-
-    def cleanupAndQuit(self):
-        """
-        cleans state before shutting down app.
-        """
-        # TODO:make sure to shutdown all child process / threads
-        # in conductor
-        # XXX send signal instead?
-        self.conductor.cleanup()
-        qApp.quit()
-
-
-class LogPane(object):
-
-    def createLogBrowser(self):
-        """
-        creates Browser widget for displaying logs
-        (in debug mode only).
-        """
-        self.loggerBox = QGroupBox()
-        logging_layout = QVBoxLayout()
-        self.logbrowser = QTextBrowser()
-
-        startStopButton = QPushButton("&Connect")
-        #startStopButton.clicked.connect(self.start_or_stopVPN)
-        self.startStopButton = startStopButton
-
-        logging_layout.addWidget(self.logbrowser)
-        logging_layout.addWidget(self.startStopButton)
-        self.loggerBox.setLayout(logging_layout)
-
-        # status box
-
-        self.statusBox = QGroupBox()
-        grid = QGridLayout()
-
-        self.updateTS = QLabel('')
-        self.status_label = QLabel('Disconnected')
-        self.ip_label = QLabel('')
-        self.remote_label = QLabel('')
-
-        tun_read_label = QLabel("tun read")
-        self.tun_read_bytes = QLabel("0")
-        tun_write_label = QLabel("tun write")
-        self.tun_write_bytes = QLabel("0")
-
-        grid.addWidget(self.updateTS, 0, 0)
-        grid.addWidget(self.status_label, 0, 1)
-        grid.addWidget(self.ip_label, 1, 0)
-        grid.addWidget(self.remote_label, 1, 1)
-        grid.addWidget(tun_read_label, 2, 0)
-        grid.addWidget(self.tun_read_bytes, 2, 1)
-        grid.addWidget(tun_write_label, 3, 0)
-        grid.addWidget(self.tun_write_bytes, 3, 1)
-
-        self.statusBox.setLayout(grid)
-
-    @pyqtSlot(str)
-    def onLoggerNewLine(self, line):
-        """
-        simple slot: writes new line to logger Pane.
-        """
-        if self.debugmode:
-            self.logbrowser.append(line[:-1])
-
-
-# XXX
-# main (leave only this here)
-class LeapWindow(QMainWindow, LeapMainWindow, EIPConductorApp,
+class LeapWindow(QtGui.QMainWindow,
+                 MainWindow, EIPConductorApp,
                  StatusAwareTrayIcon,
                  LogPane):
 
-    newLogLine = pyqtSignal([str])
-    statusChange = pyqtSignal([object])
+    # move to log
+    newLogLine = QtCore.pyqtSignal([str])
+
+    # move to icons
+    statusChange = QtCore.pyqtSignal([object])
 
     def __init__(self, opts):
         logger.debug('init leap window')
@@ -459,8 +34,10 @@ class LeapWindow(QMainWindow, LeapMainWindow, EIPConductorApp,
         self.debugmode = getattr(opts, 'debug', False)
         self.eip_service_started = False
 
-        # create timer
-        self.timer = QTimer()
+        # create timer ##############################
+        # move to Icons init??
+        self.timer = QtCore.QTimer()
+        #############################################
 
         if self.debugmode:
             self.createLogBrowser()
@@ -469,22 +46,25 @@ class LeapWindow(QMainWindow, LeapMainWindow, EIPConductorApp,
         # LeapWindow init
         self.createWindowHeader()
 
-        # StatusAwareTrayIcon init
+        # StatusAwareTrayIcon init ###################
         self.createIconGroupBox()
         self.createActions()
         self.createTrayIcon()
+        ##############################################
 
-        widget = QWidget()
+        # move to MainWindow init ####################
+        widget = QtGui.QWidget()
         self.setCentralWidget(widget)
 
         # add widgets to layout
-        mainLayout = QVBoxLayout()
+        mainLayout = QtGui.QVBoxLayout()
         mainLayout.addWidget(self.headerBox)
         mainLayout.addWidget(self.statusIconBox)
         if self.debugmode:
             mainLayout.addWidget(self.statusBox)
             mainLayout.addWidget(self.loggerBox)
         widget.setLayout(mainLayout)
+        ###############################################
 
         # move to icons?
         self.trayIcon.show()
diff --git a/src/leap/baseapp/systray.py b/src/leap/baseapp/systray.py
new file mode 100644
index 00000000..7ef5cb01
--- /dev/null
+++ b/src/leap/baseapp/systray.py
@@ -0,0 +1,150 @@
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+
+from leap.gui import mainwindow_rc
+
+
+class StatusAwareTrayIcon(object):
+
+    def createIconGroupBox(self):
+        """
+        dummy icongroupbox
+        (to be removed from here -- reference only)
+        """
+        icons = {
+            'disconnected': ':/images/conn_error.png',
+            'connecting': ':/images/conn_connecting.png',
+            'connected': ':/images/conn_connected.png'
+        }
+        con_widgets = {
+            'disconnected': QtGui.QLabel(),
+            'connecting': QtGui.QLabel(),
+            'connected': QtGui.QLabel(),
+        }
+        con_widgets['disconnected'].setPixmap(
+            QtGui.QPixmap(icons['disconnected']))
+        con_widgets['connecting'].setPixmap(
+            QtGui.QPixmap(icons['connecting']))
+        con_widgets['connected'].setPixmap(
+            QtGui.QPixmap(icons['connected'])),
+        self.ConnectionWidgets = con_widgets
+
+        con_icons = {
+            'disconnected': QtGui.QIcon(icons['disconnected']),
+            'connecting': QtGui.QIcon(icons['connecting']),
+            'connected': QtGui.QIcon(icons['connected'])
+        }
+        self.Icons = con_icons
+
+        self.statusIconBox = QtGui.QGroupBox("Connection Status")
+        statusIconLayout = QtGui.QHBoxLayout()
+        statusIconLayout.addWidget(self.ConnectionWidgets['disconnected'])
+        statusIconLayout.addWidget(self.ConnectionWidgets['connecting'])
+        statusIconLayout.addWidget(self.ConnectionWidgets['connected'])
+        statusIconLayout.itemAt(1).widget().hide()
+        statusIconLayout.itemAt(2).widget().hide()
+        self.statusIconBox.setLayout(statusIconLayout)
+
+    def createTrayIcon(self):
+        """
+        creates the tray icon
+        """
+        self.trayIconMenu = QtGui.QMenu(self)
+
+        self.trayIconMenu.addAction(self.connectVPNAction)
+        self.trayIconMenu.addAction(self.dis_connectAction)
+        self.trayIconMenu.addSeparator()
+        self.trayIconMenu.addAction(self.minimizeAction)
+        self.trayIconMenu.addAction(self.maximizeAction)
+        self.trayIconMenu.addAction(self.restoreAction)
+        self.trayIconMenu.addSeparator()
+        self.trayIconMenu.addAction(self.quitAction)
+
+        self.trayIcon = QtGui.QSystemTrayIcon(self)
+        self.setIcon('disconnected')
+        self.trayIcon.setContextMenu(self.trayIconMenu)
+
+    def createActions(self):
+        """
+        creates actions to be binded to tray icon
+        """
+        self.connectVPNAction = QtGui.QAction("Connect to &VPN", self,
+                                              triggered=self.hide)
+        # XXX change action name on (dis)connect
+        self.dis_connectAction = QtGui.QAction(
+            "&(Dis)connect", self,
+            triggered=lambda: self.start_or_stopVPN())
+        self.minimizeAction = QtGui.QAction("Mi&nimize", self,
+                                            triggered=self.hide)
+        self.maximizeAction = QtGui.QAction("Ma&ximize", self,
+                                            triggered=self.showMaximized)
+        self.restoreAction = QtGui.QAction("&Restore", self,
+                                           triggered=self.showNormal)
+        self.quitAction = QtGui.QAction("&Quit", self,
+                                        triggered=self.cleanupAndQuit)
+
+    def setConnWidget(self, icon_name):
+        #print 'changing icon to %s' % icon_name
+        oldlayout = self.statusIconBox.layout()
+
+        # XXX reuse with icons
+        # XXX move states to StateWidget
+        states = {"disconnected": 0,
+                  "connecting": 1,
+                  "connected": 2}
+
+        for i in range(3):
+            oldlayout.itemAt(i).widget().hide()
+        new = states[icon_name]
+        oldlayout.itemAt(new).widget().show()
+
+    def setIcon(self, name):
+        icon = self.Icons.get(name)
+        self.trayIcon.setIcon(icon)
+        self.setWindowIcon(icon)
+
+    def getIcon(self, icon_name):
+        # XXX get from connection dict
+        icons = {'disconnected': 0,
+                 'connecting': 1,
+                 'connected': 2}
+        return icons.get(icon_name, None)
+
+    def setIconToolTip(self):
+        """
+        get readable status and place it on systray tooltip
+        """
+        status = self.conductor.status.get_readable_status()
+        self.trayIcon.setToolTip(status)
+
+    def iconActivated(self, reason):
+        """
+        handles left click, left double click
+        showing the trayicon menu
+        """
+        #XXX there's a bug here!
+        #menu shows on (0,0) corner first time,
+        #until double clicked at least once.
+        if reason in (QtGui.QSystemTrayIcon.Trigger,
+                      QtGui.QSystemTrayIcon.DoubleClick):
+            self.trayIconMenu.show()
+
+    @QtCore.pyqtSlot()
+    def onTimerTick(self):
+        self.statusUpdate()
+
+    @QtCore.pyqtSlot(object)
+    def onStatusChange(self, status):
+        """
+        slot for status changes. triggers new signals for
+        updating icon, status bar, etc.
+        """
+
+        #print('STATUS CHANGED! (on Qt-land)')
+        #print('%s -> %s' % (status.previous, status.current))
+        icon_name = self.conductor.get_icon_name()
+        self.setIcon(icon_name)
+        #print 'icon = ', icon_name
+
+        # change connection pixmap widget
+        self.setConnWidget(icon_name)
-- 
cgit v1.2.3


From b0b2b342b698bbe5851e9312cd830938f8d564a5 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 06:01:50 +0900
Subject: further cleaning of main window by moving init functions to their
 base classes.

plus a bit of juggling with order.
---
 src/leap/baseapp/eip.py        | 13 +++++++--
 src/leap/baseapp/leap_app.py   | 22 ++++++++++++++
 src/leap/baseapp/mainwindow.py | 66 ++++++++++--------------------------------
 src/leap/baseapp/systray.py    | 11 +++++++
 4 files changed, 60 insertions(+), 52 deletions(-)

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py
index e8b9fe53..a67fd916 100644
--- a/src/leap/baseapp/eip.py
+++ b/src/leap/baseapp/eip.py
@@ -19,6 +19,8 @@ class EIPConductorApp(object):
         opts = kwargs.pop('opts')
         config_file = getattr(opts, 'config_file', None)
 
+        self.eip_service_started = False
+
         self.conductor = EIPConnection(
             watcher_cb=self.newLogLine.emit,
             config_file=config_file,
@@ -28,8 +30,15 @@ class EIPConductorApp(object):
         # XXX remove skip download when sample service is ready
         self.conductor.run_checks(skip_download=True)
         self.error_check()
-        if self.conductor.autostart:
-            self.start_or_stopVPN()
+
+        # XXX should receive "ready" signal
+        #if self.conductor.autostart:
+            #self.start_or_stopVPN()
+
+        # move to eipconductor init?
+        if self.debugmode:
+            self.startStopButton.clicked.connect(
+                lambda: self.start_or_stopVPN())
 
     def error_check(self):
         ####### error checking ################
diff --git a/src/leap/baseapp/leap_app.py b/src/leap/baseapp/leap_app.py
index fb736ee3..1b4d7747 100644
--- a/src/leap/baseapp/leap_app.py
+++ b/src/leap/baseapp/leap_app.py
@@ -5,6 +5,28 @@ from leap.gui import mainwindow_rc
 
 class MainWindow(object):
 
+    def __init__(self, *args, **kwargs):
+        # XXX set initial visibility
+        # debug = no visible
+
+        widget = QtGui.QWidget()
+        self.setCentralWidget(widget)
+
+        self.createWindowHeader()
+
+        # add widgets to layout
+        mainLayout = QtGui.QVBoxLayout()
+        mainLayout.addWidget(self.headerBox)
+        mainLayout.addWidget(self.statusIconBox)
+        if self.debugmode:
+            mainLayout.addWidget(self.statusBox)
+            mainLayout.addWidget(self.loggerBox)
+        widget.setLayout(mainLayout)
+
+        self.setWindowTitle("LEAP Client")
+        self.resize(400, 300)
+        self.set_statusbarMessage('ready')
+
     def createWindowHeader(self):
         """
         description lines for main window
diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py
index 917fc184..7cd02979 100644
--- a/src/leap/baseapp/mainwindow.py
+++ b/src/leap/baseapp/mainwindow.py
@@ -13,73 +13,39 @@ from leap.baseapp.log import LogPane
 from leap.baseapp.systray import StatusAwareTrayIcon
 from leap.baseapp.leap_app import MainWindow
 
-from leap.gui import mainwindow_rc
-
 
 class LeapWindow(QtGui.QMainWindow,
                  MainWindow, EIPConductorApp,
                  StatusAwareTrayIcon,
                  LogPane):
 
-    # move to log
     newLogLine = QtCore.pyqtSignal([str])
-
-    # move to icons
     statusChange = QtCore.pyqtSignal([object])
 
     def __init__(self, opts):
         logger.debug('init leap window')
-        super(LeapWindow, self).__init__()
-
         self.debugmode = getattr(opts, 'debug', False)
-        self.eip_service_started = False
-
-        # create timer ##############################
-        # move to Icons init??
-        self.timer = QtCore.QTimer()
-        #############################################
 
+        super(LeapWindow, self).__init__()
         if self.debugmode:
             self.createLogBrowser()
         EIPConductorApp.__init__(self, opts=opts)
-
-        # LeapWindow init
-        self.createWindowHeader()
-
-        # StatusAwareTrayIcon init ###################
-        self.createIconGroupBox()
-        self.createActions()
-        self.createTrayIcon()
-        ##############################################
-
-        # move to MainWindow init ####################
-        widget = QtGui.QWidget()
-        self.setCentralWidget(widget)
-
-        # add widgets to layout
-        mainLayout = QtGui.QVBoxLayout()
-        mainLayout.addWidget(self.headerBox)
-        mainLayout.addWidget(self.statusIconBox)
-        if self.debugmode:
-            mainLayout.addWidget(self.statusBox)
-            mainLayout.addWidget(self.loggerBox)
-        widget.setLayout(mainLayout)
-        ###############################################
-
-        # move to icons?
-        self.trayIcon.show()
-        self.setWindowTitle("LEAP Client")
-        self.resize(400, 300)
-        self.set_statusbarMessage('ready')
+        StatusAwareTrayIcon.__init__(self)
+        MainWindow.__init__(self)
 
         # bind signals
         # XXX move to parent classes init??
         self.trayIcon.activated.connect(self.iconActivated)
-        self.newLogLine.connect(lambda line: self.onLoggerNewLine(line))
-        self.statusChange.connect(lambda status: self.onStatusChange(status))
-        self.timer.timeout.connect(lambda: self.onTimerTick())
-
-        # move to eipconductor init?
-        if self.debugmode:
-            self.startStopButton.clicked.connect(
-                lambda: self.start_or_stopVPN())
+        self.newLogLine.connect(
+            lambda line: self.onLoggerNewLine(line))
+        self.statusChange.connect(
+            lambda status: self.onStatusChange(status))
+        self.timer.timeout.connect(
+            lambda: self.onTimerTick())
+
+        # ... all ready. go!
+
+        # could send "ready" signal instead
+        # eipapp should catch that
+        if self.conductor.autostart:
+            self.start_or_stopVPN()
diff --git a/src/leap/baseapp/systray.py b/src/leap/baseapp/systray.py
index 7ef5cb01..249a4f7e 100644
--- a/src/leap/baseapp/systray.py
+++ b/src/leap/baseapp/systray.py
@@ -6,6 +6,17 @@ from leap.gui import mainwindow_rc
 
 class StatusAwareTrayIcon(object):
 
+    def __init__(self, *args, **kwargs):
+        # StatusAwareTrayIcon init ###################
+        self.createIconGroupBox()
+        self.createActions()
+        self.createTrayIcon()
+
+        self.trayIcon.show()
+        ##############################################
+
+        self.timer = QtCore.QTimer()
+
     def createIconGroupBox(self):
         """
         dummy icongroupbox
-- 
cgit v1.2.3


From 1826d9a0d5400c21a3f7af73eda2e843f0639271 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 06:37:45 +0900
Subject: add little docstrings to classes

---
 src/leap/baseapp/eip.py        | 45 ++++++++++++++++++++++++++----------------
 src/leap/baseapp/leap_app.py   |  4 ++++
 src/leap/baseapp/log.py        |  4 ++++
 src/leap/baseapp/mainwindow.py |  6 ++++++
 src/leap/baseapp/systray.py    | 10 +++++++---
 5 files changed, 49 insertions(+), 20 deletions(-)

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py
index a67fd916..6c3249ff 100644
--- a/src/leap/baseapp/eip.py
+++ b/src/leap/baseapp/eip.py
@@ -8,19 +8,25 @@ from leap.eip.eipconnection import EIPConnection
 
 
 class EIPConductorApp(object):
+    """
+    initializes an instance of EIPConnection,
+    gathers errors, and passes status-change signals
+    from Qt land along to the conductor.
+    Connects the eip connect/disconnect logic
+    to the switches in the app (buttons/menu items).
+    """
 
     def __init__(self, *args, **kwargs):
-        #
-        # conductor is in charge of all
-        # vpn-related configuration / monitoring.
-        # we pass a tuple of signals that will be
-        # triggered when status changes.
-        #
         opts = kwargs.pop('opts')
         config_file = getattr(opts, 'config_file', None)
 
         self.eip_service_started = False
 
+        # conductor (eip connection) is in charge of all
+        # vpn-related configuration / monitoring.
+        # we pass a tuple of signals that will be
+        # triggered when status changes.
+
         self.conductor = EIPConnection(
             watcher_cb=self.newLogLine.emit,
             config_file=config_file,
@@ -32,20 +38,18 @@ class EIPConductorApp(object):
         self.error_check()
 
         # XXX should receive "ready" signal
+        # it is called from LeapWindow now.
         #if self.conductor.autostart:
             #self.start_or_stopVPN()
 
-        # move to eipconductor init?
         if self.debugmode:
             self.startStopButton.clicked.connect(
                 lambda: self.start_or_stopVPN())
 
     def error_check(self):
-        ####### error checking ################
-        #
-        # bunch of self checks.
-        # XXX move somewhere else alltogether.
-        #
+
+        # XXX refactor (by #504)
+
         if self.conductor.missing_definition is True:
             dialog = ErrorDialog()
             dialog.criticalMessage(
@@ -105,22 +109,23 @@ class EIPConductorApp(object):
     @QtCore.pyqtSlot()
     def statusUpdate(self):
         """
-        called on timer tick
         polls status and updates ui with real time
         info about transferred bytes / connection state.
+        right now is triggered by a timer tick
+        (timer controlled by StatusAwareTrayIcon class)
         """
-        # XXX it's too expensive to poll
+        # TODO I guess it's too expensive to poll
         # continously. move to signal events instead.
+        # (i.e., subscribe to connection status changes
+        # from openvpn manager)
 
         if not self.eip_service_started:
             return
 
-        # XXX remove all access to manager layer
-        # from here.
         if self.conductor.with_errors:
             #XXX how to wait on pkexec???
             #something better that this workaround, plz!!
-            time.sleep(5)
+            time.sleep(2)
             print('errors. disconnect.')
             self.start_or_stopVPN()  # is stop
 
@@ -173,8 +178,14 @@ class EIPConductorApp(object):
             # too little is overkill, too much
             # will miss transition states..
 
+            # XXX decouple! (timer is init by icons class).
+            # should bring it here?
+            # to its own class?
+
+            # XXX get constant from somewhere else
             self.timer.start(250.0)
             return
+
         if self.eip_service_started is True:
             self.conductor.disconnect()
             if self.debugmode:
diff --git a/src/leap/baseapp/leap_app.py b/src/leap/baseapp/leap_app.py
index 1b4d7747..def95da1 100644
--- a/src/leap/baseapp/leap_app.py
+++ b/src/leap/baseapp/leap_app.py
@@ -4,6 +4,10 @@ from leap.gui import mainwindow_rc
 
 
 class MainWindow(object):
+    """
+    create the main window
+    for leap app
+    """
 
     def __init__(self, *args, **kwargs):
         # XXX set initial visibility
diff --git a/src/leap/baseapp/log.py b/src/leap/baseapp/log.py
index 139de845..0c98eb94 100644
--- a/src/leap/baseapp/log.py
+++ b/src/leap/baseapp/log.py
@@ -3,6 +3,10 @@ from PyQt4 import QtCore
 
 
 class LogPane(object):
+    """
+    a simple log pane
+    that writes new lines as they come
+    """
 
     def createLogBrowser(self):
         """
diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py
index 7cd02979..ac7fe9c4 100644
--- a/src/leap/baseapp/mainwindow.py
+++ b/src/leap/baseapp/mainwindow.py
@@ -18,6 +18,12 @@ class LeapWindow(QtGui.QMainWindow,
                  MainWindow, EIPConductorApp,
                  StatusAwareTrayIcon,
                  LogPane):
+    """
+    main window for the leap app.
+    Initializes all of its base classes
+    We keep here some signal initialization
+    that gets tricky otherwise.
+    """
 
     newLogLine = QtCore.pyqtSignal([str])
     statusChange = QtCore.pyqtSignal([object])
diff --git a/src/leap/baseapp/systray.py b/src/leap/baseapp/systray.py
index 249a4f7e..3fb64db1 100644
--- a/src/leap/baseapp/systray.py
+++ b/src/leap/baseapp/systray.py
@@ -5,16 +5,20 @@ from leap.gui import mainwindow_rc
 
 
 class StatusAwareTrayIcon(object):
+    """
+    a mix of several functions needed
+    to create a systray and make it
+    get updated from conductor status
+    polling.
+    """
 
     def __init__(self, *args, **kwargs):
-        # StatusAwareTrayIcon init ###################
         self.createIconGroupBox()
         self.createActions()
         self.createTrayIcon()
-
         self.trayIcon.show()
-        ##############################################
 
+        # not sure if this really belongs here, but...
         self.timer = QtCore.QTimer()
 
     def createIconGroupBox(self):
-- 
cgit v1.2.3


From 8ef9f6f6f155b4acd0a69f1611058c4f0ba07d42 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 06:58:15 +0900
Subject: refactor icon/iconpath dict

closes #331
---
 src/leap/baseapp/systray.py | 61 ++++++++++++++++++++-------------------------
 1 file changed, 27 insertions(+), 34 deletions(-)

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/systray.py b/src/leap/baseapp/systray.py
index 3fb64db1..f3832473 100644
--- a/src/leap/baseapp/systray.py
+++ b/src/leap/baseapp/systray.py
@@ -11,6 +11,24 @@ class StatusAwareTrayIcon(object):
     get updated from conductor status
     polling.
     """
+    states = {
+        "disconnected": 0,
+        "connecting": 1,
+        "connected": 2}
+
+    iconpath = {
+        "disconnected": ':/images/conn_error.png',
+        "connecting": ':/images/conn_connecting.png',
+        "connected": ':/images/conn_connected.png'}
+
+    Icons = {
+        'disconnected': lambda self: QtGui.QIcon(
+            self.iconpath['disconnected']),
+        'connecting': lambda self: QtGui.QIcon(
+            self.iconpath['connecting']),
+        'connected': lambda self: QtGui.QIcon(
+            self.iconpath['connected'])
+    }
 
     def __init__(self, *args, **kwargs):
         self.createIconGroupBox()
@@ -26,31 +44,22 @@ class StatusAwareTrayIcon(object):
         dummy icongroupbox
         (to be removed from here -- reference only)
         """
-        icons = {
-            'disconnected': ':/images/conn_error.png',
-            'connecting': ':/images/conn_connecting.png',
-            'connected': ':/images/conn_connected.png'
-        }
         con_widgets = {
             'disconnected': QtGui.QLabel(),
             'connecting': QtGui.QLabel(),
             'connected': QtGui.QLabel(),
         }
         con_widgets['disconnected'].setPixmap(
-            QtGui.QPixmap(icons['disconnected']))
+            QtGui.QPixmap(
+                self.iconpath['disconnected']))
         con_widgets['connecting'].setPixmap(
-            QtGui.QPixmap(icons['connecting']))
+            QtGui.QPixmap(
+                self.iconpath['connecting']))
         con_widgets['connected'].setPixmap(
-            QtGui.QPixmap(icons['connected'])),
+            QtGui.QPixmap(
+                self.iconpath['connected'])),
         self.ConnectionWidgets = con_widgets
 
-        con_icons = {
-            'disconnected': QtGui.QIcon(icons['disconnected']),
-            'connecting': QtGui.QIcon(icons['connecting']),
-            'connected': QtGui.QIcon(icons['connected'])
-        }
-        self.Icons = con_icons
-
         self.statusIconBox = QtGui.QGroupBox("Connection Status")
         statusIconLayout = QtGui.QHBoxLayout()
         statusIconLayout.addWidget(self.ConnectionWidgets['disconnected'])
@@ -99,31 +108,20 @@ class StatusAwareTrayIcon(object):
                                         triggered=self.cleanupAndQuit)
 
     def setConnWidget(self, icon_name):
-        #print 'changing icon to %s' % icon_name
         oldlayout = self.statusIconBox.layout()
 
-        # XXX reuse with icons
-        # XXX move states to StateWidget
-        states = {"disconnected": 0,
-                  "connecting": 1,
-                  "connected": 2}
-
         for i in range(3):
             oldlayout.itemAt(i).widget().hide()
-        new = states[icon_name]
+        new = self.states[icon_name]
         oldlayout.itemAt(new).widget().show()
 
     def setIcon(self, name):
-        icon = self.Icons.get(name)
+        icon = self.Icons.get(name)(self)
         self.trayIcon.setIcon(icon)
         self.setWindowIcon(icon)
 
     def getIcon(self, icon_name):
-        # XXX get from connection dict
-        icons = {'disconnected': 0,
-                 'connecting': 1,
-                 'connected': 2}
-        return icons.get(icon_name, None)
+        return self.states.get(icon_name, None)
 
     def setIconToolTip(self):
         """
@@ -154,12 +152,7 @@ class StatusAwareTrayIcon(object):
         slot for status changes. triggers new signals for
         updating icon, status bar, etc.
         """
-
-        #print('STATUS CHANGED! (on Qt-land)')
-        #print('%s -> %s' % (status.previous, status.current))
         icon_name = self.conductor.get_icon_name()
         self.setIcon(icon_name)
-        #print 'icon = ', icon_name
-
         # change connection pixmap widget
         self.setConnWidget(icon_name)
-- 
cgit v1.2.3


From 3b752fcfac7a18891e2f948acae0cb4781678647 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Tue, 4 Sep 2012 07:11:01 +0900
Subject: put timer constant instead of hardcoded value

---
 src/leap/baseapp/constants.py | 1 +
 src/leap/baseapp/eip.py       | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)
 create mode 100644 src/leap/baseapp/constants.py

(limited to 'src/leap/baseapp')

diff --git a/src/leap/baseapp/constants.py b/src/leap/baseapp/constants.py
new file mode 100644
index 00000000..763df23b
--- /dev/null
+++ b/src/leap/baseapp/constants.py
@@ -0,0 +1 @@
+TIMER_MILLISECONDS = 250.0
diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py
index 6c3249ff..029ce0ba 100644
--- a/src/leap/baseapp/eip.py
+++ b/src/leap/baseapp/eip.py
@@ -3,6 +3,7 @@ import time
 from PyQt4 import QtCore
 
 from leap.baseapp.dialogs import ErrorDialog
+from leap.baseapp import constants
 from leap.eip import exceptions as eip_exceptions
 from leap.eip.eipconnection import EIPConnection
 
@@ -182,8 +183,7 @@ class EIPConductorApp(object):
             # should bring it here?
             # to its own class?
 
-            # XXX get constant from somewhere else
-            self.timer.start(250.0)
+            self.timer.start(constants.TIMER_MILLISECONDS)
             return
 
         if self.eip_service_started is True:
-- 
cgit v1.2.3