diff options
Diffstat (limited to 'module/gui/MainWindow.py')
-rw-r--r-- | module/gui/MainWindow.py | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/module/gui/MainWindow.py b/module/gui/MainWindow.py new file mode 100644 index 000000000..4ab840fed --- /dev/null +++ b/module/gui/MainWindow.py @@ -0,0 +1,512 @@ +# -*- coding: utf-8 -*- +""" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + @author: mkaay +""" + +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +from module.gui.PackageDock import * +from module.gui.LinkDock import * +from module.gui.CaptchaDock import CaptchaDock +from module.gui.SettingsWidget import SettingsWidget + +from module.gui.Collector import CollectorView, Package, Link +from module.gui.Queue import QueueView +from module.gui.Accounts import AccountView + +class MainWindow(QMainWindow): + def __init__(self, connector): + """ + set up main window + """ + QMainWindow.__init__(self) + #window stuff + self.setWindowTitle(_("pyLoad Client")) + self.setWindowIcon(QIcon("icons/logo.png")) + self.resize(850,500) + + #layout version + self.version = 3 + + #init docks + self.newPackDock = NewPackageDock() + self.addDockWidget(Qt.RightDockWidgetArea, self.newPackDock) + self.connect(self.newPackDock, SIGNAL("done"), self.slotAddPackage) + self.captchaDock = CaptchaDock() + self.addDockWidget(Qt.BottomDockWidgetArea, self.captchaDock) + + #central widget, layout + self.masterlayout = QVBoxLayout() + lw = QWidget() + lw.setLayout(self.masterlayout) + self.setCentralWidget(lw) + + #set menubar and statusbar + self.menubar = self.menuBar() + self.statusbar = self.statusBar() + self.connect(self.statusbar, SIGNAL("showMsg"), self.statusbar.showMessage) + self.serverStatus = QLabel(_("Status: Not Connected")) + self.statusbar.addPermanentWidget(self.serverStatus) + + #menu + self.menus = {} + self.menus["file"] = self.menubar.addMenu(_("File")) + self.menus["connections"] = self.menubar.addMenu(_("Connections")) + + #menu actions + self.mactions = {} + self.mactions["exit"] = QAction(_("Exit"), self.menus["file"]) + self.mactions["manager"] = QAction(_("Connection manager"), self.menus["connections"]) + + #add menu actions + self.menus["file"].addAction(self.mactions["exit"]) + self.menus["connections"].addAction(self.mactions["manager"]) + + #toolbar + self.actions = {} + self.init_toolbar() + + #tabs + self.tabw = QTabWidget() + self.tabs = {} + self.tabs["queue"] = {"w":QWidget()} + self.tabs["collector"] = {"w":QWidget()} + self.tabs["accounts"] = {"w":QWidget()} + self.tabs["settings"] = {} + self.tabs["settings"]["s"] = QScrollArea() + self.tabs["settings"]["w"] = SettingsWidget() + self.tabs["settings"]["s"].setWidgetResizable(True) + self.tabs["settings"]["s"].setWidget(self.tabs["settings"]["w"]) + self.tabs["log"] = {"w":QWidget()} + self.tabw.addTab(self.tabs["queue"]["w"], _("Queue")) + self.tabw.addTab(self.tabs["collector"]["w"], _("Collector")) + self.tabw.addTab(self.tabs["accounts"]["w"], _("Accounts")) + self.tabw.addTab(self.tabs["settings"]["s"], _("Settings")) + self.tabw.addTab(self.tabs["log"]["w"], _("Log")) + + #init tabs + self.init_tabs(connector) + + self.setPriority = Priorty(self) + + #context menus + self.init_context() + + #layout + self.masterlayout.addWidget(self.tabw) + + #signals.. + self.connect(self.mactions["manager"], SIGNAL("triggered()"), self.slotShowConnector) + self.connect(self.mactions["exit"], SIGNAL("triggered()"), self.close) + + self.connect(self.tabs["queue"]["view"], SIGNAL('customContextMenuRequested(const QPoint &)'), self.slotQueueContextMenu) + self.connect(self.tabs["collector"]["package_view"], SIGNAL('customContextMenuRequested(const QPoint &)'), self.slotCollectorContextMenu) + + self.connect(self.tabw, SIGNAL("currentChanged(int)"), self.slotTabChanged) + + self.lastAddedID = None + + def init_toolbar(self): + """ + create toolbar + """ + self.toolbar = self.addToolBar(_("Main Toolbar")) + self.toolbar.setObjectName("Main Toolbar") + self.toolbar.setIconSize(QSize(40,40)) + self.actions["toggle_status"] = self.toolbar.addAction(_("Toggle Pause/Resume")) + pricon = QIcon() + pricon.addFile("icons/toolbar_start.png", QSize(), QIcon.Normal, QIcon.Off) + pricon.addFile("icons/toolbar_pause.png", QSize(), QIcon.Normal, QIcon.On) + self.actions["toggle_status"].setIcon(pricon) + self.actions["toggle_status"].setCheckable(True) + self.actions["status_stop"] = self.toolbar.addAction(QIcon("icons/toolbar_stop.png"), _("Stop")) + self.toolbar.addSeparator() + self.actions["add"] = self.toolbar.addAction(QIcon("icons/toolbar_add.png"), _("Add")) + self.toolbar.addSeparator() + self.actions["clipboard"] = self.toolbar.addAction(QIcon("icons/clipboard.png"), _("Check Clipboard")) + self.actions["clipboard"].setCheckable(True) + + self.connect(self.actions["toggle_status"], SIGNAL("toggled(bool)"), self.slotToggleStatus) + self.connect(self.actions["clipboard"], SIGNAL("toggled(bool)"), self.slotToggleClipboard) + self.connect(self.actions["status_stop"], SIGNAL("triggered()"), self.slotStatusStop) + self.addMenu = QMenu() + packageAction = self.addMenu.addAction(_("Package")) + containerAction = self.addMenu.addAction(_("Container")) + self.connect(self.actions["add"], SIGNAL("triggered()"), self.slotAdd) + self.connect(packageAction, SIGNAL("triggered()"), self.slotShowAddPackage) + self.connect(containerAction, SIGNAL("triggered()"), self.slotShowAddContainer) + + def init_tabs(self, connector): + """ + create tabs + """ + #queue + self.tabs["queue"]["l"] = QGridLayout() + self.tabs["queue"]["w"].setLayout(self.tabs["queue"]["l"]) + self.tabs["queue"]["view"] = QueueView(connector) + self.tabs["queue"]["l"].addWidget(self.tabs["queue"]["view"]) + + #collector + toQueue = QPushButton(_("Push selected packages to queue")) + self.tabs["collector"]["l"] = QGridLayout() + self.tabs["collector"]["w"].setLayout(self.tabs["collector"]["l"]) + self.tabs["collector"]["package_view"] = CollectorView(connector) + self.tabs["collector"]["l"].addWidget(self.tabs["collector"]["package_view"], 0, 0) + self.tabs["collector"]["l"].addWidget(toQueue, 1, 0) + self.connect(toQueue, SIGNAL("clicked()"), self.slotPushPackageToQueue) + self.tabs["collector"]["package_view"].setContextMenuPolicy(Qt.CustomContextMenu) + self.tabs["queue"]["view"].setContextMenuPolicy(Qt.CustomContextMenu) + + #log + self.tabs["log"]["l"] = QGridLayout() + self.tabs["log"]["w"].setLayout(self.tabs["log"]["l"]) + self.tabs["log"]["text"] = QTextEdit() + self.tabs["log"]["text"].logOffset = 0 + self.tabs["log"]["text"].setReadOnly(True) + self.connect(self.tabs["log"]["text"], SIGNAL("append(QString)"), self.tabs["log"]["text"].append) + self.tabs["log"]["l"].addWidget(self.tabs["log"]["text"]) + + #accounts + self.tabs["accounts"]["view"] = AccountView(connector) + self.tabs["accounts"]["w"].setLayout(QHBoxLayout()) + self.tabs["accounts"]["w"].layout().addWidget(self.tabs["accounts"]["view"]) + + def init_context(self): + """ + create context menus + """ + self.activeMenu = None + #queue + self.queueContext = QMenu() + self.queueContext.buttons = {} + self.queueContext.item = (None, None) + self.queueContext.buttons["remove"] = QAction(QIcon("icons/remove_small.png"), _("Remove"), self.queueContext) + self.queueContext.buttons["restart"] = QAction(QIcon("icons/refresh_small.png"), _("Restart"), self.queueContext) + self.queueContext.buttons["pull"] = QAction(QIcon("icons/pull_small.png"), _("Pull out"), self.queueContext) + self.queueContext.buttons["abort"] = QAction(QIcon("icons/abort.png"), _("Abort"), self.queueContext) + self.queueContext.buttons["edit"] = QAction(QIcon("icons/edit_small.png"), _("Edit Name"), self.queueContext) + self.queuePriorityMenu = QMenu(_("Priority")) + self.queuePriorityMenu.actions = {} + self.queuePriorityMenu.actions["veryhigh"] = QAction(_("very high"), self.queuePriorityMenu) + self.queuePriorityMenu.addAction(self.queuePriorityMenu.actions["veryhigh"]) + self.queuePriorityMenu.actions["high"] = QAction(_("high"), self.queuePriorityMenu) + self.queuePriorityMenu.addAction(self.queuePriorityMenu.actions["high"]) + self.queuePriorityMenu.actions["normal"] = QAction(_("normal"), self.queuePriorityMenu) + self.queuePriorityMenu.addAction(self.queuePriorityMenu.actions["normal"]) + self.queuePriorityMenu.actions["low"] = QAction(_("low"), self.queuePriorityMenu) + self.queuePriorityMenu.addAction(self.queuePriorityMenu.actions["low"]) + self.queuePriorityMenu.actions["verylow"] = QAction(_("very low"), self.queuePriorityMenu) + self.queuePriorityMenu.addAction(self.queuePriorityMenu.actions["verylow"]) + self.queueContext.addAction(self.queueContext.buttons["pull"]) + self.queueContext.addAction(self.queueContext.buttons["edit"]) + self.queueContext.addAction(self.queueContext.buttons["remove"]) + self.queueContext.addAction(self.queueContext.buttons["restart"]) + self.queueContext.addAction(self.queueContext.buttons["abort"]) + self.queueContext.addMenu(self.queuePriorityMenu) + self.connect(self.queueContext.buttons["remove"], SIGNAL("triggered()"), self.slotRemoveDownload) + self.connect(self.queueContext.buttons["restart"], SIGNAL("triggered()"), self.slotRestartDownload) + self.connect(self.queueContext.buttons["pull"], SIGNAL("triggered()"), self.slotPullOutPackage) + self.connect(self.queueContext.buttons["abort"], SIGNAL("triggered()"), self.slotAbortDownload) + self.connect(self.queueContext.buttons["edit"], SIGNAL("triggered()"), self.slotEditPackage) + + self.connect(self.queuePriorityMenu.actions["veryhigh"], SIGNAL("triggered()"), self.setPriority.veryHigh) + self.connect(self.queuePriorityMenu.actions["high"], SIGNAL("triggered()"), self.setPriority.high) + self.connect(self.queuePriorityMenu.actions["normal"], SIGNAL("triggered()"), self.setPriority.normal) + self.connect(self.queuePriorityMenu.actions["low"], SIGNAL("triggered()"), self.setPriority.low) + self.connect(self.queuePriorityMenu.actions["verylow"], SIGNAL("triggered()"), self.setPriority.veryLow) + + #collector + self.collectorContext = QMenu() + self.collectorContext.buttons = {} + self.collectorContext.item = (None, None) + self.collectorContext.buttons["remove"] = QAction(QIcon("icons/remove_small.png"), _("Remove"), self.collectorContext) + self.collectorContext.buttons["push"] = QAction(QIcon("icons/push_small.png"), _("Push to queue"), self.collectorContext) + self.collectorContext.buttons["edit"] = QAction(QIcon("icons/edit_small.png"), _("Edit Name"), self.collectorContext) + self.collectorContext.addAction(self.collectorContext.buttons["push"]) + self.collectorContext.addAction(self.collectorContext.buttons["edit"]) + self.collectorContext.addAction(self.collectorContext.buttons["remove"]) + self.connect(self.collectorContext.buttons["remove"], SIGNAL("triggered()"), self.slotRemoveDownload) + self.connect(self.collectorContext.buttons["push"], SIGNAL("triggered()"), self.slotPushPackageToQueue) + self.connect(self.collectorContext.buttons["edit"], SIGNAL("triggered()"), self.slotEditPackage) + + def slotToggleStatus(self, status): + """ + pause/start toggle (toolbar) + """ + self.emit(SIGNAL("setDownloadStatus"), status) + + def slotStatusStop(self): + """ + stop button (toolbar) + """ + self.emit(SIGNAL("stopAllDownloads")) + + def slotAdd(self): + """ + add button (toolbar) + show context menu (choice: links/package) + """ + self.addMenu.exec_(QCursor.pos()) + + def slotShowAddPackage(self): + """ + action from add-menu + show new-package dock + """ + self.tabw.setCurrentIndex(1) + self.newPackDock.show() + + def slotShowAddLinks(self): + """ + action from add-menu + show new-links dock + """ + self.tabw.setCurrentIndex(1) + self.newLinkDock.show() + + def slotShowConnector(self): + """ + connectionmanager action triggered + let main to the stuff + """ + self.emit(SIGNAL("connector")) + + def slotAddPackage(self, name, links): + """ + new package + let main to the stuff + """ + self.emit(SIGNAL("addPackage"), name, links) + + def slotShowAddContainer(self): + """ + action from add-menu + show file selector, emit upload + """ + typeStr = ";;".join([ + _("All Container Types (%s)") % "*.dlc *.ccf *.rsdf *.txt", + _("DLC (%s)") % "*.dlc", + _("CCF (%s)") % "*.ccf", + _("RSDF (%s)") % "*.rsdf", + _("Text Files (%s)") % "*.txt" + ]) + fileNames = QFileDialog.getOpenFileNames(self, _("Open container"), "", typeStr) + for name in fileNames: + self.emit(SIGNAL("addContainer"), str(name)) + + def slotPushPackageToQueue(self): + """ + push collector pack to queue + get child ids + let main to the rest + """ + smodel = self.tabs["collector"]["package_view"].selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + if isinstance(item, Package): + self.emit(SIGNAL("pushPackageToQueue"), item.id) + else: + self.emit(SIGNAL("pushPackageToQueue"), item.package.id) + + def saveWindow(self): + """ + get window state/geometry + pass data to main + """ + state_raw = self.saveState(self.version) + geo_raw = self.saveGeometry() + + state = str(state_raw.toBase64()) + geo = str(geo_raw.toBase64()) + + self.emit(SIGNAL("saveMainWindow"), state, geo) + + def closeEvent(self, event): + """ + somebody wants to close me! + let me first save my state + """ + self.saveWindow() + event.accept() + self.emit(SIGNAL("quit")) + + def restoreWindow(self, state, geo): + """ + restore window state/geometry + """ + state = QByteArray(state) + geo = QByteArray(geo) + + state_raw = QByteArray.fromBase64(state) + geo_raw = QByteArray.fromBase64(geo) + + self.restoreState(state_raw, self.version) + self.restoreGeometry(geo_raw) + + def slotQueueContextMenu(self, pos): + """ + custom context menu in queue view requested + """ + globalPos = self.tabs["queue"]["view"].mapToGlobal(pos) + i = self.tabs["queue"]["view"].indexAt(pos) + if not i: + return + item = i.internalPointer() + menuPos = QCursor.pos() + menuPos.setX(menuPos.x()+2) + self.activeMenu = self.queueContext + showAbort = False + if isinstance(item, Link) and item.data["downloading"]: + showAbort = True + elif isinstance(item, Package): + for child in item.children: + if child.data["downloading"]: + showAbort = True + if showAbort: + self.queueContext.buttons["abort"].setVisible(True) + else: + self.queueContext.buttons["abort"].setVisible(False) + if isinstance(item, Package): + self.queueContext.index = i + self.queueContext.buttons["edit"].setVisible(True) + else: + self.queueContext.index = None + self.queueContext.buttons["edit"].setVisible(False) + self.queueContext.exec_(menuPos) + + def slotCollectorContextMenu(self, pos): + """ + custom context menu in package collector view requested + """ + globalPos = self.tabs["collector"]["package_view"].mapToGlobal(pos) + i = self.tabs["collector"]["package_view"].indexAt(pos) + if not i: + return + item = i.internalPointer() + menuPos = QCursor.pos() + menuPos.setX(menuPos.x()+2) + self.activeMenu = self.collectorContext + if isinstance(item, Package): + self.collectorContext.index = i + self.collectorContext.buttons["edit"].setVisible(True) + else: + self.collectorContext.index = None + self.collectorContext.buttons["edit"].setVisible(False) + self.collectorContext.exec_(menuPos) + + def slotLinkCollectorContextMenu(self, pos): + """ + custom context menu in link collector view requested + """ + pass + + def slotRestartDownload(self): + """ + restart download action is triggered + """ + smodel = self.tabs["queue"]["view"].selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + self.emit(SIGNAL("restartDownload"), item.id, isinstance(item, Package)) + id, isTopLevel = self.queueContext.item + if not id == None: + self.emit(SIGNAL("restartDownload"), id, isTopLevel) + + def slotRemoveDownload(self): + """ + remove download action is triggered + """ + if self.activeMenu == self.queueContext: + view = self.tabs["queue"]["view"] + else: + view = self.tabs["collector"]["package_view"] + smodel = view.selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + self.emit(SIGNAL("removeDownload"), item.id, isinstance(item, Package)) + + def slotToggleClipboard(self, status): + """ + check clipboard (toolbar) + """ + self.emit(SIGNAL("setClipboardStatus"), status) + + def slotEditPackage(self): + if self.activeMenu == self.queueContext: + view = self.tabs["queue"]["view"] + else: + view = self.tabs["collector"]["package_view"] + view.edit(self.activeMenu.index) + + def slotEditCommit(self, editor): + self.emit(SIGNAL("changePackageName"), self.activeMenu.index.internalPointer().id, editor.text()) + + def slotPullOutPackage(self): + """ + pull package out of the queue + """ + smodel = self.tabs["queue"]["view"].selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + if isinstance(item, Package): + self.emit(SIGNAL("pullOutPackage"), item.id) + else: + self.emit(SIGNAL("pullOutPackage"), item.package.id) + + def slotAbortDownload(self): + view = self.tabs["queue"]["view"] + smodel = view.selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + self.emit(SIGNAL("abortDownload"), item.id, isinstance(item, Package)) + + def changeEvent(self, e): + if e.type() == QEvent.WindowStateChange and self.isMinimized(): + e.ignore() + self.hide() + self.emit(SIGNAL("hidden")) + else: + super(MainWindow, self).changeEvent(e) + + def slotTabChanged(self, index): + if index == 2: + self.emit(SIGNAL("reloadAccounts")) + elif index == 3: + self.tabs["settings"]["w"].loadConfig() + +class Priorty(): + def __init__(self, win): + self.w = win + + def setPriority(self, level): + if self.w.activeMenu == self.w.queueContext: + smodel = self.w.tabs["queue"]["view"].selectionModel() + else: + smodel = self.w.tabs["collector"]["package_view"].selectionModel() + for index in smodel.selectedRows(0): + item = index.internalPointer() + pid = item.id if isinstance(item, Package) else item.package.id + self.w.emit(SIGNAL("setPriority"), pid, level) + + def veryHigh(self): self.setPriority(2) + def high(self): self.setPriority(1) + def normal(self): self.setPriority(0) + def low(self): self.setPriority(-1) + def veryLow(self): self.setPriority(-2) + + + |