Initial commit (Vesion 0.1)
[tablet-suite] / src / backup / pcsbackupmanagerui.py
diff --git a/src/backup/pcsbackupmanagerui.py b/src/backup/pcsbackupmanagerui.py
new file mode 100644 (file)
index 0000000..2fdc32b
--- /dev/null
@@ -0,0 +1,502 @@
+# Software License: GPL
+
+import os
+import sys
+
+from functools import partial
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from ui.pcsuiutils import *
+from ui.tsuigeneralmethods import *
+from ui.pcsapp import PcsApp
+from backup.pcsbackuputils import *
+
+from pcsbackuplistui import PCSBackupListUi
+from pcspcbackupmanager import PcsPcBackupManager
+from pcsdevicebackupmanager import PcsDeviceBackupManager
+from pcsprogressdialog import PcsProgressDialog
+from style.styleTabletSuite import *
+
+COPY_BUTTON_ID = 0
+DELETE_BUTTON_ID = 1
+RENAME_BUTTON_ID = 2
+VIEW_BUTTON_ID = 3
+_home_dir = os.path.expanduser("~")
+_default_dir = _home_dir + "/.pcsuite/Backup"
+
+
+class PcsBackupManagerUi(QDialog):
+    
+    ''' Class that calls a Backup Pc Suite application
+        with a Table Viewer'''
+
+    def __init__(self, deviceInfo, windowManager, parent=None):
+        QDialog.__init__(self, parent)
+        self.deviceInfo = deviceInfo
+        self.windowManager = windowManager
+        
+        self.setWindowIcon(QIcon(BACKUP_IMAGE))
+        self.setWindowTitle("%s Backup Manager" % APPLICATION_NAME)
+        self.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
+        self._home_dir = os.path.expanduser("~")
+        self._default_dir = _home_dir + "/.pcsuite/Backup"
+        self.copyPath = self._default_dir
+        self.name_change = None
+        self._setupUi()
+        
+    def _setupUi(self):
+        # Creates the lists
+        self.pcBackupManager = PcsPcBackupManager()
+        self.deviceBackupManager = PcsDeviceBackupManager(self.deviceInfo)
+
+        self.pcListView = PCSBackupListUi(self.pcBackupManager)
+        self.pcListView.setObjectName("ListView")
+        # "Update pc list view"
+        pcListViewSelectionModel = self.pcListView.selectionModel()
+        self.connect(pcListViewSelectionModel, 
+                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
+                     self._updateButtonsState)
+        self.pcListView.updateBackupList()
+        
+        self.deviceListView = PCSBackupListUi(self.deviceBackupManager)
+        self.deviceListView.setObjectName("ListView")
+        deviceListViewSelectionModel = self.deviceListView.selectionModel()
+        self.connect(deviceListViewSelectionModel, 
+                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), 
+                     self._updateButtonsState)
+        # "Update device List view"
+        self.deviceListView.updateBackupList()
+        
+        layout = QVBoxLayout()
+        menuLayout = self._menuButtons()
+        layout.addLayout(menuLayout, Qt.AlignTop)
+        wayLayout = self._wayLayout()
+        layout.addLayout(wayLayout, Qt.AlignLeft)
+        layout.addItem(QSpacerItem(0,3))
+        layout.addLayout(self._centerLayout(), Qt.AlignTop)
+
+        layout.addItem(QSpacerItem(0,15))
+        informationLayout = self._createInformationsLabel()
+        layout.addLayout(informationLayout)
+        layout.addItem(QSpacerItem(0,2))
+        self.setLayout(layout)
+    
+    def _centerLayout(self):
+        # Creates the tabs
+        layout = QVBoxLayout()
+        tabLayout = QVBoxLayout()
+        tab = QTabBar()
+        tab.setObjectName("managerTabs")
+        self.tabBar = QTabWidget()
+        self.tabBar.setTabBar(tab)
+        self.tabBar.setAttribute(Qt.WA_NoSystemBackground)
+        self.tabBar.setObjectName("tabBar")
+        self.tabBar.addTab(self.pcListView, "PC Backups")
+        self.tabBar.addTab(self.deviceListView, "Device Backups")
+        self.connect(self.tabBar, SIGNAL("currentChanged(int)"), self._updateButtonsState)
+        tabLayout.addWidget(self.tabBar)
+        layout.addLayout(tabLayout)
+        #Spacer
+        layout.addItem(QSpacerItem(0,5))        
+        # Creates the buttons
+        buttonBox = QHBoxLayout()
+        self._buttonCopy = QPushButton("Copy")
+        self._buttonCopy.setDisabled(True)
+        self._buttonCopy.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        buttonBox.addWidget(self._buttonCopy)
+        self.connect (self._buttonCopy, SIGNAL("clicked()"), self._doCopyBackup)
+        
+        self._buttonDelete = QPushButton("Delete")
+        self._buttonDelete.setDisabled(True)
+        buttonBox.addWidget(self._buttonDelete)
+        self._buttonDelete.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect (self._buttonDelete, SIGNAL("clicked()"), self._doDeleteBackup)
+        
+        self._buttonRename = QPushButton("Rename")
+        self._buttonRename.setDisabled(True)
+        buttonBox.addWidget(self._buttonRename)
+        self._buttonRename.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect (self._buttonRename, SIGNAL("clicked()"), self._doRenameBackup)
+        
+        self._buttonView = QPushButton("View")
+        self._buttonView.setDisabled(True)
+        buttonBox.addWidget(self._buttonView)
+        self._buttonView.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect (self._buttonView, SIGNAL("clicked()"), self._doViewBackup)
+        
+        self._buttonUpdate = QPushButton("Update")
+        self._buttonUpdate.setDisabled(False)
+        self._buttonUpdate.setVisible(False)
+        buttonBox.addWidget(self._buttonUpdate)
+        self._buttonUpdate.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect (self._buttonUpdate, SIGNAL("clicked()"), self._doUpdateList)
+        
+        layout.addLayout(buttonBox)
+        return layout
+        
+    def _menuButtons(self):
+        infList = [("New Backup", SMALL_ICON_NEW_BACKUP_STYLE, self._newBackupDialog), 
+                   ("Manage Backup", SMALL_ICON_MANAGER_BACKUP_STYLE_SELECTED),
+                   ("Restore Backup", SMALL_ICON_RESTORE_BACKUP_STYLE, self._restoreDialog)]
+        
+        buttonsLayout = QHBoxLayout()
+        for i in range(3):
+            but = QPushButton(infList[i][0])
+            but.setStyleSheet(infList[i][1])
+            if i <> 1:
+                buttonsLayout.addWidget(but, Qt.AlignLeft)
+                self.connect(but, SIGNAL("clicked()"), infList[i][2])
+            else:
+                buttonsLayout.addWidget(but)
+        buttonsLayout.setMargin(0)
+        return buttonsLayout    
+    
+    def _newBackupDialog(self):
+        if(self.deviceInfo and self.deviceInfo.ip != None):
+            newBackup = self.windowManager.getNewBackup()
+            centralize(newBackup)
+            newBackup.setGeometry(self.geometry())
+            newBackup.show()
+            self.close()
+        else:
+            self._showNoDeviceFoundMessage()
+    
+    def _restoreDialog(self):
+        if(self.deviceInfo and self.deviceInfo.ip != None):
+            restoreBackup = self.windowManager.getRestoreBackup()
+            centralize(restoreBackup)
+            restoreBackup.setGeometry(self.geometry())
+            restoreBackup.show()
+            self.close()
+        else:
+            self._showNoDeviceFoundMessage()
+    
+    def _wayLayout(self):
+        self.barLayout = QHBoxLayout()
+        self.barLayout.setMargin(0)
+        spc = QSpacerItem(8, 0)
+        self.barLayout.addItem(spc)
+        main = QLabel("<font style='color: #333333'; size=2>Main</font>")
+        restore = QLabel("<font style='color: #FFFFFF'; size=2> Manage backups</font>")
+        spc = QSpacerItem(2, 0)
+        widgetList = [main, self._arrow(), restore]
+        
+        for widget in widgetList:
+            self.barLayout.addWidget(widget, Qt.AlignLeft)
+            self.barLayout.addItem(spc)
+                    
+        self.barLayout.addItem(QSpacerItem(300, 0))
+        return self.barLayout
+    
+    def _arrow(self):
+        label = QLabel()
+        label.setPixmap(QPixmap(BLACK_ARROW))
+        return label
+    
+    def _createInformationsLabel(self):
+        hLay = QHBoxLayout()
+        
+        self.infLabel = QLabel("<font style='color:"\
+                             "#333333'; size=2>"\
+                             "Select the backup you wish to manipulate.</font>")
+        iconAlert = QLabel()
+        hLay.setMargin(0)
+        iconAlert.setPixmap(QPixmap(ICON_ALERT))
+        spc = QSpacerItem(15, 0)
+        hLay.addItem(spc)
+        hLay.addWidget(iconAlert)
+        hLay.addWidget(self.infLabel, Qt.AlignLeft)
+        
+        return hLay
+    
+    def _doUpdateList(self):
+        self._currentBackupList().updateBackupList()
+        self._updateButtonsState(0)
+    
+    def _execCopyDialogToDevice(self):
+        self._copyDialogToDevice = QDialog(self, Qt.FramelessWindowHint)
+        self._copyDialogToDevice.setObjectName("copyDialogToDevice")
+        
+        self.rb1 = QRadioButton()
+        self.rb1.setText("External Memory Card")
+        self.rb2 = QRadioButton()
+        self.rb2.setText("Internal Memory Card")
+        
+        layout = QVBoxLayout()
+        layout.addWidget(self.rb1)
+        layout.addWidget(self.rb2)
+        
+        buttonCopy = QPushButton("Copy")
+        buttonCopy.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect(buttonCopy, SIGNAL("clicked()"), self._doCopyToDevice)
+        buttonCancel = QPushButton("Cancel")
+        buttonCancel.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect(buttonCancel, SIGNAL("clicked()"), self._copyDialogToDevice.close)
+        
+        hlay = QHBoxLayout()
+        hlay.addWidget(buttonCancel)
+        hlay.addWidget(buttonCopy)
+        layout.addLayout(hlay)
+        self._copyDialogToDevice.setLayout(layout)
+        self._copyDialogToDevice.exec_()
+    
+    def _execCopyDialogFromDevice(self):
+        self._copyDialogFromDevice = QDialog(self, Qt.FramelessWindowHint)
+        self._copyDialogFromDevice.setObjectName("copyDialogFromDevice")
+        
+        hLayout = QHBoxLayout()
+        hLayout.setMargin(0)
+        self.textField = QLineEdit(self)
+        buttonOpen = QPushButton()
+        buttonOpen.setObjectName("buttonBrowse")
+        self.connect(buttonOpen, SIGNAL("clicked()"), self._doBrowse)
+        copyPath = str(self._default_dir)
+        self.textField.setReadOnly(True)
+        self.textField.setText(self._default_dir)
+        hLayout.addWidget(self.textField)
+        hLayout.addWidget(buttonOpen)
+        
+        message = QLabel("<font style='color: #333333'; size=2> Backup copy destination: </font>")
+        message.setFixedHeight(15)
+        
+        layout = QVBoxLayout()
+        layout.addWidget(message)
+        layout.addLayout(hLayout)
+        
+        buttonCopy = QPushButton("Copy")
+        buttonCopy.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect(buttonCopy, SIGNAL("clicked()"), self._doCopyFromDevice)
+        buttonCancel = QPushButton("Cancel")
+        buttonCancel.setStyleSheet(DEFAULT_BUTTON_STYLE)
+        self.connect(buttonCancel, SIGNAL("clicked()"), self._copyDialogFromDevice.close)
+        
+        hlay = QHBoxLayout()
+        hlay.addWidget(buttonCancel)
+        hlay.addWidget(buttonCopy)
+        layout.addLayout(hlay)
+        self._copyDialogFromDevice.setLayout(layout)
+        self._copyDialogFromDevice.exec_()
+    
+    def _doCopyBackup(self):
+        if self.tabBar.currentIndex() == 0:
+            self._execCopyDialogToDevice()
+        else:
+            self._execCopyDialogFromDevice()
+    
+    def doCopy(self, device_ip, backupName, ret, destinationPath):
+        self.copyThread = CopyBackupThread(self, device_ip, backupName, ret, destinationPath)
+        self.copyThread.start()
+        self._runCopyProgress()
+        
+        self.connect(self.copyThread, SIGNAL("openFileError"), self._onOpenFileError)
+        self.connect(self.copyThread, SIGNAL("copyProgress"), self._updateProgress)
+        self.connect(self.copyThread, SIGNAL("copyDone"), self._onCopyDone)
+    
+    def _doCopyToDevice(self):
+        self._copyDialogToDevice.close()
+        ret = 1
+        if self.rb1.isChecked():
+            ret = 0
+        selectedBackupList = self._currentBackupList().getSelectedBackupList()
+        for backup in selectedBackupList: 
+            self.doCopy(self.deviceInfo.ip, str(backup).strip(), ret, "")
+        
+    def _doCopyFromDevice(self):
+        self._copyDialogFromDevice.close()
+        if self.copyPath != "":
+            selectedBackupList = self._currentBackupList().getSelectedBackupList()
+            self.name_change = False
+            for backup in selectedBackupList:
+                self.pcBackupManager.loadBackups()
+                self.correct_name = self.pcBackupManager._verify_backup_name(str(backup).strip())
+                self.doCopy(self.deviceInfo.ip, str(backup).strip(), 0, self.copyPath)
+                if self.correct_name != backup:
+                    self.name_change = True
+
+    def _showMessageCopyBackupDone(self):
+        if self.name_change == None or not self.name_change:
+            QMessageBox.information(self, "Copy Backup", "Backup(s) copied")
+        else:
+            QMessageBox.information(sopenFileErrorelf, "Copy Backup",
+                                    "Backup copied with name: %s" % self.correct_name)
+        
+    def _doBrowse(self):
+        pathDialog = QFileDialog()
+        prompt = "Select the folder you wish to copy your backup(s):"
+        self.copyPath = pathDialog.getExistingDirectory(self, prompt, self._home_dir)
+        if(self.copyPath != ""):
+            self.textField.setText(self.copyPath)
+
+    def _doRenameBackup(self):
+        res = False
+        (newName, ok) = QInputDialog.getText(self, "Rename Backup", "New Backup Name:",
+                                             QLineEdit.Normal, QString(),  
+                                             Qt.FramelessWindowHint)
+        if ok:
+            if newName:
+                newName = QString(str(newName).strip())
+            if not newName.isEmpty():
+                list = self._currentBackupList()
+                res = list.renameSelectedBackup(newName)
+            if res:
+                showMessageBox("Backup Renamed", "")
+            else:
+                showMessageBox("Error while renaming the backup", "")
+
+    def _doDeleteBackup(self):
+        
+        dialog = QMessageBox()
+        dialog.setText("Remove selected backup?")
+        dialog.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
+        dialog.setWindowFlags(Qt.FramelessWindowHint)
+        dialog.setStyleSheet(MESSAGE_BOX_DEFAULT)
+        ret = dialog.exec_()
+        if ret == QMessageBox.Yes:
+            list = self._currentBackupList()
+            list.removeSelectedBackups()
+            showMessageBox("Backup Removed", "")
+
+    def _currentBackupList(self):
+        if self.tabBar.currentIndex() == 0:
+            self._buttonRename.setVisible(True)
+            self._buttonDelete.setVisible(True)
+            self._buttonView.setVisible(True)
+            self._buttonUpdate.setVisible(False)
+            return self.pcListView
+        else:
+            self._buttonUpdate.setVisible(True)
+            self._buttonRename.setVisible(False)
+            self._buttonDelete.setVisible(False)
+            self._buttonView.setVisible(False)
+            return self.deviceListView
+
+    def _updateButtonsState(self, index):
+        list = self._currentBackupList()
+        selectionModel = list.selectionModel()
+        indexList = selectionModel.selectedRows()
+        
+        if len(indexList) != 1:
+            self._buttonRename.setDisabled(True)
+            self._buttonView.setDisabled(True)
+            self._buttonCopy.setDisabled(True)
+        else:
+            self._buttonRename.setEnabled(True)
+            self._buttonView.setEnabled(True)
+            self._buttonCopy.setEnabled(True)
+        
+        if len(indexList) == 0:
+            self._buttonDelete.setDisabled(True)
+#            self._buttonCopy.setDisabled(True)
+        else:
+            self._buttonDelete.setEnabled(True)
+#            self._buttonCopy.setEnabled(True)             
+        
+  
+    def _doViewBackup(self):
+        list = self._currentBackupList()
+        backupManager = list.getBackupManager()
+        backupName = (str(list.getSelectedBackup())).strip()
+        if backupName == None:
+            return False
+        
+        dialog = QDialog(self, Qt.FramelessWindowHint)
+        dialog.setObjectName("viewDialog")
+        dialog.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
+        dialog.setWindowTitle("Backup Files")
+        dialog.setWindowIcon(QIcon(BACKUP_IMAGE))
+        
+        layout = QVBoxLayout()
+        listWidget = QListWidget()
+        listWidget.setObjectName("viewList")
+        listWidget.setDragDropMode(QAbstractItemView.NoDragDrop)
+        
+        try:
+            backupContentList = backupManager.listBackupContent(backupName)
+        except IOError:
+            showMessageBox(self.openFileError, "Error while opening file")
+            return False
+
+        for backupContent in backupContentList:
+            backup_button = QListWidgetItem()
+            backup_button.setText(backupContent)
+            listWidget.addItem(backup_button)
+        
+        okButton = QPushButton("OK")
+        okButton.setStyleSheet(SMALL_DEFAULT_BUTTON_STYLE)
+        visible = partial(dialog.setVisible, False)
+        self.connect(okButton, SIGNAL("clicked()"), visible)
+        hLay = QHBoxLayout()
+        hLay.addItem(QSpacerItem(200,0))
+        hLay.addWidget(okButton)
+        
+        layout.addWidget(listWidget)
+        layout.addLayout(hLay)
+        dialog.setLayout(layout)
+        dialog.show()
+    
+    def _runCopyProgress(self):
+        self._progressDialog = PcsProgressDialog(self)
+        self._progressDialog.setAction("copy")
+        self.connect(self._progressDialog.cancelButton, SIGNAL("clicked()"),
+                      self._onCopyCancel)
+        self._progressDialog.show()
+    
+    def _updateProgress(self, information):
+        progress, self.numberOfFiles, self.totalSize = information
+        self._progressDialog.setProgress(progress)
+    
+    def _onCopyDone(self):
+        self._progressDialog.updateInfo(self.totalSize, self.numberOfFiles)
+        self._progressDialog.progressDone()
+        self.pcListView.updateBackupList()
+    
+    def _onCopyCancel(self):
+        if self.tabBar.currentIndex() == 0:
+            self.pcBackupManager.setCopyInProgress(False)
+        else:
+            self.deviceBackupManager.setCopyInProgress(False)
+        self._progressDialog.progressCanceled()
+        
+    def _onOpenFileError(self):
+        self._progressDialog.close()
+        showMessageBox(OPEN_FILE_ERROR, OPEN_FILE_ERROR_TITLE)
+        
+        
+        
+class CopyBackupThread(QThread):
+    def __init__(self, manager, deviceIp, backupName, ret, destinationPath ):
+        QThread.__init__(self)
+        self.uiManager = manager
+        self.deviceIp = deviceIp
+        self.backupName = backupName
+        self.memoryCard = ret
+        self.destinationPath = destinationPath
+        self.connect(self.uiManager.pcBackupManager, SIGNAL("copyProgress"), 
+                     self.reEmit)
+        self.connect(self.uiManager.deviceBackupManager, SIGNAL("copyProgress"),
+                      self.reEmit)
+        
+    def reEmit(self, inf):
+        self.emit(SIGNAL("copyProgress"), inf)
+    
+    def run(self):
+        try:
+            if self.uiManager.tabBar.currentIndex() == 0:
+                manager = self.uiManager.pcBackupManager
+                manager.copyBackupToDevice(self.deviceIp, self.backupName, 
+                                            self.memoryCard)
+            else:
+                manager = self.uiManager.deviceBackupManager
+                manager.copyBackupFromDevice(self.backupName, 
+                                             self.destinationPath)
+        
+        except IOError:
+            self.emit(SIGNAL("openFileError"))
+            return
+        self.emit(SIGNAL("copyDone"))
+        
+        
+        
+