modified COSE fatte
[stack/code/dboxswitch.git] / gui.py
diff --git a/gui.py b/gui.py
old mode 100755 (executable)
new mode 100644 (file)
index c9bd3d5..363904d
--- a/gui.py
+++ b/gui.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 # -*- coding: utf-8 -*-
 
 """
@@ -34,12 +33,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 """
 import sys
 import os
-from PyQt4 import QtGui
+from PyQt4 import QtGui, QtCore
+from PyQt4.QtCore import SIGNAL
+from qmenutooltip import QMenuToolTip
 
 from apperror import AppError
+from settings import appconf
 
 class Gui(QtGui.QDialog):
     def __init__(self, prManager):
+        """ Gui init, an QApplication is created and stored here, also a main window and a trayIcon
+        are created.
+        Default actions are builded and profile manager stored from argument (instance of ProfHandler """
+
         self.app = QtGui.QApplication(sys.argv)
     
         #check if system tray is avaiable on the system
@@ -52,37 +58,196 @@ class Gui(QtGui.QDialog):
     
         super(Gui, self).__init__()
 
+        self.profiles = []
+
         self.createActions()
         self.createTrayIcon()
+        self.createMainDialog()
 
         self.trayIcon.show()
-
-        self.setWindowTitle("Profile manager / Dboxswitch - dropbox profile switcher")
-        self.resize(400, 300)
-
         self.profileManager = prManager
 
+    def main(self): 
+        """ Like Gtk application this main executes the app, thi is somewhat writed for
+        compatibility in porting the app """
 
-
-    def main(self):
         sys.exit(self.app.exec_())
 
     def closeEvent(self, event):
+        """ Handle application closing """
+
         if self.trayIcon.isVisible():
             self.hide()
             event.ignore()
 
     def createActions(self):
+        """ Create actions for the various components """
+
         self.manageprofiles = QtGui.QAction("Manage &Profiles", self,
-                triggered=self.hide)
+                triggered=self.show)
         self.quitAction = QtGui.QAction("&Quit", self,
                 triggered=QtGui.qApp.quit)
 
+        #profile manager component
+        self.addProfileAction = QtGui.QAction("  Add &Profile  ", self,
+                triggered=self.addProfile)
+
+    def createMainDialog(self):    
+        """ Build the main dialog layout """ 
+        
+        self.setWindowTitle("Profile manager / Dboxswitch - dropbox profile switcher")
+        #add a default action to create a profile
+        self.addButton = QtGui.QPushButton(QtGui.QIcon(appconf.addpicon), 
+                    "Add Profile")
+        self.addButton.clicked.connect(self.addProfile)
+        self.addButton.setVisible(False)
+
+        self.la            = QtGui.QFormLayout()
+
+        self.la.addRow(self.addButton)
+        self.la.sizePolicy = QtGui.QSizePolicy.Minimum
+        self.la.setVerticalSpacing(15)
+        self.la.setHorizontalSpacing(15)
+        self.formGroupBox = QtGui.QGroupBox("Manage profiles:")
+        self.formGroupBox.setLayout(self.la)
+        mainLayout = QtGui.QVBoxLayout()
+        mainLayout.addWidget(self.formGroupBox)
+        self.setLayout(mainLayout)
+
+
+    def show(self):
+        """ Show the main dialog for dealing with profiles """
+
+        profiles = self.profileManager.getProfilesList()
+
+        for pr in profiles:
+            prname = self.profileManager.getBaseProfileName(pr)
+            delButton = QtGui.QToolButton()
+            label     = QtGui.QLabel(prname)
+            self.la.addRow(label, delButton)
+            delAction = QtGui.QAction(QtGui.QIcon(appconf.delpicon),"Delete", self,
+                triggered=self.deleteProfileAction(prname, (label, delButton)))
+            delButton.setDefaultAction(delAction)
+            self.profiles.append((label, delButton))
+
+        #if profiles was empty
+        if len(profiles) == 0:
+            self.addButton.setVisible(True)
+        else:
+            self.addButton.setVisible(False)
+
+        super(Gui, self).show()
+
+    def hide(self):
+        """ Hides the main dialog """
+        
+        #Hides all the profiles in the Dialog
+        #User can deal with profiles like removing the dir manually
+
+        for ws in self.profiles:
+            for w in ws:
+                w.setVisible(False)
+                w.setParent(None)
+        super(Gui, self).hide()
+
     def createTrayIcon(self):
+         """ Builds a new tray icon with a context menu and an action for the profile manager menu """
+
+         #context menu build, right click
          self.trayIconMenu = QtGui.QMenu(self)
          self.trayIconMenu.addAction(self.manageprofiles)
          self.trayIconMenu.addSeparator()
          self.trayIconMenu.addAction(self.quitAction)
 
-         self.trayIcon = QtGui.QSystemTrayIcon(self)
+         #create the tray with an incon
+         self.trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon(appconf.icon), self.app)
+         #attach a context menu for the right click to the tray
          self.trayIcon.setContextMenu(self.trayIconMenu)
+         #baloon on hover for the tray
+         self.trayIcon.setToolTip(appconf.appname+" "+appconf.appversion+"\nRight Click to manage profiles.")
+         #left click profiles show for the tray
+         self.trayIcon.activated.connect(self.showTrayProfiles)
+
+
+    def showTrayProfiles(self,reason):
+        """ Pops up a system tray profile Manager with a list of activable profiles and an 
+        action to add a new One """
+
+        if reason in (QtGui.QSystemTrayIcon.Trigger, QtGui.QSystemTrayIcon.DoubleClick):
+            self.menuProfiles = QMenuToolTip()
+            self.menuProfiles.setTitle("Profiles")
+            QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus, False)
+
+            #Get profiles from the ProfHandler embedded in the gui
+            profiles = self.profileManager.getProfilesList()
+
+            for prpath in profiles:
+                pr = self.profileManager.getBaseProfileName(prpath)
+                receiver = self.activateProfileAction(prpath)
+                menuItem_Profile = self.menuProfiles.addAction(pr)
+                if self.profileManager.isCurrentProfile(prpath):
+                    menuItem_Profile.setIcon(QtGui.QIcon(appconf.cpicon))
+                 
+                #Using lambda function to pass additional arguments to the function, in this case the path of the profile
+                self.connect(menuItem_Profile, SIGNAL('triggered()'), receiver)
+                #set menu item ToolTip
+                menuItem_Profile.setToolTip("Activate profile: "+pr)
+
+                self.menuProfiles.addAction(menuItem_Profile)
+
+            self.menuProfiles.addSeparator()
+            #action and menu item for adding a New Profile
+            self.menuProfiles.addAction(self.addProfileAction)
+
+            self.menuProfiles.activateWindow()
+            self.menuProfiles.popup(QtGui.QCursor.pos())
+
+    def activateProfileAction(self, pr):
+        """ Returns a callable to be passed as an action for the switching profile mechanism 
+        to self.connect(menuItem_Profile... 
+        It compiles a function with a profile name as argument and also handle the displaying of errors."""
+
+        def f():
+            try:
+                self.profileManager.activateProfile(pr)
+            except AppError, e:
+                self.showError(str(e))
+        return f
+
+    def deleteProfileAction(self, pr, prWidgets):
+        """ Returns a callable to be passed as an action for the profile manager mechanism 
+        to self.connect(menuItem_Profile... 
+        It compiles a function with a profile name as argument and also handle the displaying of errors."""
+
+        def f():
+            try:
+                self.profileManager.delProfile(pr)
+                for w in prWidgets:
+                    w.setParent(None)
+                    w.setVisible(False)
+            except AppError, e:
+                self.showError(str(e))
+        return f
+
+
+    def addProfile(self):
+        """ Gui frontend to add a new Profile, it requests the user a profile name 
+        through a QInputDialog and creates a new profile with the help of the ProfHandler embedded in the Gui """
+
+        self.setWindowTitle("Add New Profile - Dboxswitch - dropbox profile switcher")
+        self.resize(300, 100)
+        text, ok = QtGui.QInputDialog.getText(self, 'Input Dialog', 
+                            'Enter profile name:')
+        if ok:
+            try:
+                self.profileManager.addProfile(unicode(text))
+            except AppError, e:
+                self.showError(str(e))
+
+    def showError(self, err):
+        """ Display an error message through a QErrorMessage """
+
+        self.setWindowTitle("Error - Dboxswitch - dropbox profile switcher")
+        self.resize(200, 100)
+        err = QtGui.QErrorMessage.showMessage(QtGui.QErrorMessage.qtHandler(), "Error: "+err)