Example #1
0
    def init(self, first=False):
        """
            set main things up
        """
        self.parser = XMLParser(
            join(self.configdir, "gui.xml"),
            join(self.path, "module", "config", "gui_default.xml"))
        lang = self.parser.xml.elementsByTagName("language").item(
            0).toElement().text()
        if not lang:
            parser = XMLParser(
                join(self.path, "module", "config", "gui_default.xml"))
            lang = parser.xml.elementsByTagName("language").item(
                0).toElement().text()

        gettext.setpaths(
            [join(os.sep, "usr", "share", "pyload", "locale"), None])
        translation = gettext.translation(
            "pyLoadGui",
            join(pypath, "locale"),
            languages=[str(lang), "en"],
            fallback=True,
        )

        install_translation(translation)

        self.connector = Connector()
        self.mainWindow = MainWindow(self.connector)
        self.connWindow = ConnectionManager()
        self.mainloop = self.Loop(self)
        self.connectSignals()

        self.checkClipboard = False
        default = self.refreshConnections()
        self.connData = None
        self.captchaProcessing = False
        self.serverStatus = {"freespace": 0}

        self.core = None  # pyLoadCore if started
        self.connectionLost = False

        if True:  # when used if first, minimizing not working correctly..
            self.tray = TrayIcon()
            self.tray.show()
            self.notification = Notification(self.tray)
            self.connect(self, SIGNAL("showMessage"),
                         self.notification.showMessage)
            self.connect(self.tray.exitAction, SIGNAL("triggered()"),
                         self.slotQuit)
            self.connect(self.tray.showAction, SIGNAL("toggled(bool)"),
                         self.mainWindow.setVisible)
            self.connect(self.mainWindow, SIGNAL("hidden"),
                         self.tray.mainWindowHidden)

        if not first:
            self.connWindow.show()
        else:
            self.connWindow.edit.setData(default)
            data = self.connWindow.edit.getData()
            self.slotConnect(data)
Example #2
0
    def init(self, first=False):
        """
            set main things up
        """
        self.parser = XMLParser(join(self.configdir, "gui.xml"), join(self.path, "module", "config", "gui_default.xml"))
        lang = self.parser.xml.elementsByTagName("language").item(0).toElement().text()
        if not lang:
            parser = XMLParser(join(self.path, "module", "config", "gui_default.xml"))
            lang = parser.xml.elementsByTagName("language").item(0).toElement().text()

        gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None])
        translation = gettext.translation("pyLoadGui", join(pypath, "locale"), languages=[str(lang), "en"], fallback=True)
        try:
            translation.install(unicode=(True if sys.stdout.encoding.lower().startswith("utf") else False))
        except:
            translation.install(unicode=False)


        self.connector = Connector()
        self.mainWindow = MainWindow(self.connector)
        self.connWindow = ConnectionManager()
        self.mainloop = self.Loop(self)
        self.connectSignals()

        self.checkClipboard = False
        default = self.refreshConnections()
        self.connData = None
        self.captchaProcessing = False
        self.serverStatus = {"freespace":0}

        self.core = None # pyLoadCore if started
        self.connectionLost = False

        if True: # when used if first, minimizing not working correctly..
            self.tray = TrayIcon()
            self.tray.show()
            self.notification = Notification(self.tray)
            self.connect(self, SIGNAL("showMessage"), self.notification.showMessage)
            self.connect(self.tray.exitAction, SIGNAL("triggered()"), self.slotQuit)
            self.connect(self.tray.showAction, SIGNAL("toggled(bool)"), self.mainWindow.setVisible)
            self.connect(self.mainWindow, SIGNAL("hidden"), self.tray.mainWindowHidden)

        if not first:
            self.connWindow.show()
        else:
            self.connWindow.edit.setData(default)
            data = self.connWindow.edit.getData()
            self.slotConnect(data)
Example #3
0
class main(QObject):
    def __init__(self):
        """
            main setup
        """
        QObject.__init__(self)
        self.app = QApplication(sys.argv)
        self.path = pypath
        self.homedir = abspath("")

        self.configdir = ""

        self.init(True)

    def init(self, first=False):
        """
            set main things up
        """
        self.parser = XMLParser(
            join(self.configdir, "gui.xml"),
            join(self.path, "module", "config", "gui_default.xml"))
        lang = self.parser.xml.elementsByTagName("language").item(
            0).toElement().text()
        if not lang:
            parser = XMLParser(
                join(self.path, "module", "config", "gui_default.xml"))
            lang = parser.xml.elementsByTagName("language").item(
                0).toElement().text()

        gettext.setpaths(
            [join(os.sep, "usr", "share", "pyload", "locale"), None])
        translation = gettext.translation(
            "pyLoadGui",
            join(pypath, "locale"),
            languages=[str(lang), "en"],
            fallback=True,
        )

        install_translation(translation)

        self.connector = Connector()
        self.mainWindow = MainWindow(self.connector)
        self.connWindow = ConnectionManager()
        self.mainloop = self.Loop(self)
        self.connectSignals()

        self.checkClipboard = False
        default = self.refreshConnections()
        self.connData = None
        self.captchaProcessing = False
        self.serverStatus = {"freespace": 0}

        self.core = None  # pyLoadCore if started
        self.connectionLost = False

        if True:  # when used if first, minimizing not working correctly..
            self.tray = TrayIcon()
            self.tray.show()
            self.notification = Notification(self.tray)
            self.connect(self, SIGNAL("showMessage"),
                         self.notification.showMessage)
            self.connect(self.tray.exitAction, SIGNAL("triggered()"),
                         self.slotQuit)
            self.connect(self.tray.showAction, SIGNAL("toggled(bool)"),
                         self.mainWindow.setVisible)
            self.connect(self.mainWindow, SIGNAL("hidden"),
                         self.tray.mainWindowHidden)

        if not first:
            self.connWindow.show()
        else:
            self.connWindow.edit.setData(default)
            data = self.connWindow.edit.getData()
            self.slotConnect(data)

    def startMain(self):
        """
            start all refresh threads and show main window
        """
        if not self.connector.connectProxy():
            self.init()
            return
        self.connect(self.connector, SIGNAL("connectionLost"),
                     self.slotConnectionLost)
        self.restoreMainWindow()
        self.mainWindow.show()
        self.initQueue()
        self.initPackageCollector()
        self.mainloop.start()
        self.clipboard = self.app.clipboard()
        self.connect(self.clipboard, SIGNAL('dataChanged()'),
                     self.slotClipboardChange)
        self.mainWindow.actions["clipboard"].setChecked(self.checkClipboard)

        self.mainWindow.tabs["settings"]["w"].setConnector(self.connector)
        self.mainWindow.tabs["settings"]["w"].loadConfig()
        self.tray.showAction.setDisabled(False)

    def stopMain(self):
        """
            stop all refresh threads and hide main window
        """
        self.tray.showAction.setDisabled(True)
        self.disconnect(self.clipboard, SIGNAL('dataChanged()'),
                        self.slotClipboardChange)
        self.disconnect(self.connector, SIGNAL("connectionLost"),
                        self.slotConnectionLost)
        self.mainloop.stop()
        self.mainWindow.saveWindow()
        self.mainWindow.hide()
        self.queue.stop()

    def connectSignals(self):
        """
            signal and slot stuff, yay!
        """
        self.connect(self.connector, SIGNAL("errorBox"), self.slotErrorBox)
        self.connect(self.connWindow, SIGNAL("saveConnection"),
                     self.slotSaveConnection)
        self.connect(self.connWindow, SIGNAL("removeConnection"),
                     self.slotRemoveConnection)
        self.connect(self.connWindow, SIGNAL("connect"), self.slotConnect)
        self.connect(self.mainWindow, SIGNAL("connector"),
                     self.slotShowConnector)
        self.connect(self.mainWindow, SIGNAL("addPackage"),
                     self.slotAddPackage)
        self.connect(self.mainWindow, SIGNAL("setDownloadStatus"),
                     self.slotSetDownloadStatus)
        self.connect(self.mainWindow, SIGNAL("saveMainWindow"),
                     self.slotSaveMainWindow)
        self.connect(self.mainWindow, SIGNAL("pushPackageToQueue"),
                     self.slotPushPackageToQueue)
        self.connect(self.mainWindow, SIGNAL("restartDownload"),
                     self.slotRestartDownload)
        self.connect(self.mainWindow, SIGNAL("removeDownload"),
                     self.slotRemoveDownload)
        self.connect(self.mainWindow, SIGNAL("abortDownload"),
                     self.slotAbortDownload)
        self.connect(self.mainWindow, SIGNAL("addContainer"),
                     self.slotAddContainer)
        self.connect(self.mainWindow, SIGNAL("stopAllDownloads"),
                     self.slotStopAllDownloads)
        self.connect(self.mainWindow, SIGNAL("setClipboardStatus"),
                     self.slotSetClipboardStatus)
        self.connect(self.mainWindow, SIGNAL("changePackageName"),
                     self.slotChangePackageName)
        self.connect(self.mainWindow, SIGNAL("pullOutPackage"),
                     self.slotPullOutPackage)
        self.connect(self.mainWindow, SIGNAL("refreshStatus"),
                     self.slotRefreshStatus)
        self.connect(self.mainWindow, SIGNAL("reloadAccounts"),
                     self.slotReloadAccounts)
        self.connect(self.mainWindow, SIGNAL("Quit"), self.slotQuit)

        self.connect(self.mainWindow.mactions["exit"], SIGNAL("triggered()"),
                     self.slotQuit)
        self.connect(self.mainWindow.captchaDock, SIGNAL("done"),
                     self.slotCaptchaDone)

    def slotShowConnector(self):
        """
            emitted from main window (menu)
            hide the main window and show connection manager
            (to switch to other core)
        """
        self.quitInternal()
        self.stopMain()
        self.init()

    #def quit(self): #not used anymore?
    #    """
    #        quit gui
    #    """
    #    self.app.quit()

    def loop(self):
        """
            start application loop
        """
        sys.exit(self.app.exec_())

    def slotErrorBox(self, msg):
        """
            display a nice error box
        """
        msgb = QMessageBox(QMessageBox.Warning, "Error", msg)
        msgb.exec_()

    def initPackageCollector(self):
        """
            init the package collector view
            * columns
            * selection
            * refresh thread
            * drag'n'drop
        """
        view = self.mainWindow.tabs["collector"]["package_view"]
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)

        def dropEvent(klass, event):
            event.setDropAction(Qt.CopyAction)
            event.accept()
            view = event.source()
            if view == klass:
                items = view.selectedItems()
                for item in items:
                    if not hasattr(item.parent(), "getPackData"):
                        continue
                    target = view.itemAt(event.pos())
                    if not hasattr(target, "getPackData"):
                        target = target.parent()
                    klass.emit(SIGNAL("droppedToPack"),
                               target.getPackData()["id"],
                               item.getFileData()["id"])
                event.ignore()
                return
            items = view.selectedItems()
            for item in items:
                row = view.indexOfTopLevelItem(item)
                view.takeTopLevelItem(row)

        def dragEvent(klass, event):
            #view = event.source()
            #dragOkay = False
            #items = view.selectedItems()
            #for item in items:
            #    if hasattr(item, "_data"):
            #        if item._data["id"] == "fixed" or item.parent()._data["id"] == "fixed":
            #            dragOkay = True
            #    else:
            #        dragOkay = True
            #if dragOkay:
            event.accept()
            #else:
            #    event.ignore()

        view.dropEvent = dropEvent
        view.dragEnterEvent = dragEvent
        view.setDragEnabled(True)
        view.setDragDropMode(QAbstractItemView.DragDrop)
        view.setDropIndicatorShown(True)
        view.setDragDropOverwriteMode(True)
        view.connect(view, SIGNAL("droppedToPack"), self.slotAddFileToPackage)
        #self.packageCollector = PackageCollector(view, self.connector)
        self.packageCollector = view.model()

    def initQueue(self):
        """
            init the queue view
            * columns
            * progressbar
        """
        view = self.mainWindow.tabs["queue"]["view"]
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.queue = view.model()
        self.connect(self.queue, SIGNAL("updateCount"), self.slotUpdateCount)
        overview = self.mainWindow.tabs["overview"]["view"].model()
        overview.queue = self.queue
        self.connect(self.queue, SIGNAL("updateCount"), overview.queueChanged)
        self.queue.start()

    def slotUpdateCount(self, pc, fc):
        self.mainWindow.packageCount.setText("%i" % pc)
        self.mainWindow.fileCount.setText("%i" % fc)

    def refreshServerStatus(self):
        """
            refresh server status and overall speed in the status bar
        """
        s = self.connector.statusServer()
        if s.pause:
            self.mainWindow.status.setText(_("paused"))
        else:
            self.mainWindow.status.setText(_("running"))
        self.mainWindow.speed.setText(formatSpeed(s.speed))
        self.mainWindow.space.setText(
            formatSize(self.serverStatus["freespace"]))
        self.mainWindow.actions["toggle_status"].setChecked(not s.pause)

    def refreshLog(self):
        """
            update log window
        """
        offset = self.mainWindow.tabs["log"]["text"].logOffset
        lines = self.connector.getLog(offset)
        if not lines:
            return
        self.mainWindow.tabs["log"]["text"].logOffset += len(lines)
        for line in lines:
            self.mainWindow.tabs["log"]["text"].emit(SIGNAL("append(QString)"),
                                                     line.strip("\n"))
        cursor = self.mainWindow.tabs["log"]["text"].textCursor()
        cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
        self.mainWindow.tabs["log"]["text"].setTextCursor(cursor)

    def getConnections(self):
        """
            parse all connections in the config file
        """
        connectionsNode = self.parser.xml.elementsByTagName(
            "connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        ret = []
        for conn in connections:
            data = {}
            data["type"] = conn.attribute("type", "remote")
            data["default"] = conn.attribute("default", "False")
            data["id"] = conn.attribute("id", uuid().hex)
            if data["default"] == "True":
                data["default"] = True
            else:
                data["default"] = False
            subs = self.parser.parseNode(conn, "dict")
            if "name" not in subs:
                data["name"] = _("Unnamed")
            else:
                data["name"] = subs["name"].text()
            if data["type"] == "remote":
                if "server" not in subs:
                    continue
                else:
                    data["host"] = subs["server"].text()
                    data["user"] = subs["server"].attribute("user", "admin")
                    data["port"] = int(subs["server"].attribute(
                        "port", "7227"))
                    data["password"] = subs["server"].attribute("password", "")
            ret.append(data)
        return ret

    def slotSaveConnection(self, data):
        """
            save connection to config file
        """
        connectionsNode = self.parser.xml.elementsByTagName(
            "connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        connNode = self.parser.xml.createElement("connection")
        connNode.setAttribute("default", str(data["default"]))
        connNode.setAttribute("type", data["type"])
        connNode.setAttribute("id", data["id"])
        nameNode = self.parser.xml.createElement("name")
        nameText = self.parser.xml.createTextNode(data["name"])
        nameNode.appendChild(nameText)
        connNode.appendChild(nameNode)
        if data["type"] == "remote":
            serverNode = self.parser.xml.createElement("server")
            serverNode.setAttribute("user", data["user"])
            serverNode.setAttribute("port", data["port"])
            serverNode.setAttribute("password", data["password"])
            hostText = self.parser.xml.createTextNode(data["host"])
            serverNode.appendChild(hostText)
            connNode.appendChild(serverNode)
        found = False
        for c in connections:
            cid = c.attribute("id", "None")
            if str(cid) == str(data["id"]):
                found = c
                break
        if found:
            connectionsNode.replaceChild(connNode, found)
        else:
            connectionsNode.appendChild(connNode)
        self.parser.saveData()
        self.refreshConnections()

    def slotRemoveConnection(self, data):
        """
            remove connection from config file
        """
        connectionsNode = self.parser.xml.elementsByTagName(
            "connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        found = False
        for c in connections:
            cid = c.attribute("id", "None")
            if str(cid) == str(data["id"]):
                found = c
                break
        if found:
            connectionsNode.removeChild(found)
        self.parser.saveData()
        self.refreshConnections()

    def slotConnect(self, data):
        """
            connect to a core
            if connection is local, parse the core config file for data
            if internal, start pyLoadCore
            set up connector, show main window
        """
        self.connWindow.hide()
        if data["type"] not in ("remote", "internal"):

            coreparser = ConfigParser(self.configdir)
            if not coreparser.config:
                self.connector.setConnectionData("127.0.0.1", 7227,
                                                 "anonymous", "anonymous",
                                                 False)
            else:
                self.connector.setConnectionData(
                    "127.0.0.1", coreparser.get("remote", "port"), "anonymous",
                    "anonymous")

        elif data["type"] == "remote":
            self.connector.setConnectionData(data["host"], data["port"],
                                             data["user"], data["password"])

        elif data["type"] == "internal":
            from pyLoadCore import Core
            from module.ConfigParser import ConfigParser as CoreConfig

            if not self.core:

                config = CoreConfig(
                )  #create so at least default config exists
                self.core = Core()
                self.core.startedInGui = True
                thread.start_new_thread(self.core.start, (False, False))
                while not self.core.running:
                    sleep(0.5)

                self.connector.proxy = self.core.api
                self.connector.internal = True

                #self.connector.setConnectionData("127.0.0.1", config.get("remote","port"), "anonymous", "anonymous")

        self.startMain()


#        try:
#            host = data["host"]
#        except:
#            host = "127.0.0.1"

    def refreshConnections(self):
        """
            reload connetions and display them
        """
        self.parser.loadData()
        conns = self.getConnections()
        self.connWindow.emit(SIGNAL("setConnections"), conns)
        for conn in conns:
            if conn["default"]:
                return conn
        return None

    def slotSetDownloadStatus(self, status):
        """
            toolbar start/pause slot
        """
        if status:
            self.connector.unpauseServer()
        else:
            self.connector.pauseServer()

    def slotAddPackage(self, name, links, password=None):
        """
            emitted from main window
            add package to the collector
        """
        pack = self.connector.addPackage(name, links, Destination.Collector)
        if password:
            data = {"password": password}
            self.connector.setPackageData(pack, data)

    def slotAddFileToPackage(self, pid, fid):  #TODO deprecated? gets called
        """
            emitted from collector view after a drop action
        """
        #self.connector.addFileToPackage(fid, pid)
        pass

    def slotAddContainer(self, path):
        """
            emitted from main window
            add container
        """
        filename = basename(path)
        #type = "".join(filename.split(".")[-1])
        fh = open(path, "r")
        content = fh.read()
        fh.close()
        self.connector.uploadContainer(filename, content)

    def slotSaveMainWindow(self, state, geo):
        """
            save the window geometry and toolbar/dock position to config file
        """
        mainWindowNode = self.parser.xml.elementsByTagName("mainWindow").item(
            0)
        if mainWindowNode.isNull():
            mainWindowNode = self.parser.xml.createElement("mainWindow")
            self.parser.root.appendChild(mainWindowNode)
        stateNode = mainWindowNode.toElement().elementsByTagName("state").item(
            0)
        geoNode = mainWindowNode.toElement().elementsByTagName(
            "geometry").item(0)
        newStateNode = self.parser.xml.createTextNode(state)
        newGeoNode = self.parser.xml.createTextNode(geo)

        stateNode.removeChild(stateNode.firstChild())
        geoNode.removeChild(geoNode.firstChild())
        stateNode.appendChild(newStateNode)
        geoNode.appendChild(newGeoNode)

        self.parser.saveData()

    def restoreMainWindow(self):
        """
            load and restore main window geometry and toolbar/dock position from config
        """
        mainWindowNode = self.parser.xml.elementsByTagName("mainWindow").item(
            0)
        if mainWindowNode.isNull():
            return
        nodes = self.parser.parseNode(mainWindowNode, "dict")

        state = str(nodes["state"].text())
        geo = str(nodes["geometry"].text())

        self.mainWindow.restoreWindow(state, geo)
        self.mainWindow.captchaDock.hide()

    def slotPushPackageToQueue(self, id):
        """
            emitted from main window
            push the collector package to queue
        """
        self.connector.pushToQueue(id)

    def slotRestartDownload(self, id, isPack):
        """
            emitted from main window
            restart download
        """
        if isPack:
            self.connector.restartPackage(id)
        else:
            self.connector.restartFile(id)

    def slotRefreshStatus(self, id):
        """
            emitted from main window
            refresh download status
        """
        self.connector.recheckPackage(id)

    def slotRemoveDownload(self, id, isPack):
        """
            emitted from main window
            remove download
        """
        if isPack:
            self.connector.deletePackages([id])
        else:
            self.connector.deleteFiles([id])

    def slotAbortDownload(self, id, isPack):
        """
            emitted from main window
            remove download
        """
        if isPack:
            data = self.connector.getFileOrder(id)  #less data to transmit
            self.connector.stopDownloads(data.values())
        else:
            self.connector.stopDownloads([id])

    def slotStopAllDownloads(self):
        """
            emitted from main window
            stop all running downloads
        """
        self.connector.stopAllDownloads()

    def slotClipboardChange(self):
        """
            called if clipboard changes
        """
        if self.checkClipboard:
            text = self.clipboard.text()
            pattern = re.compile(
                r"(http|https|ftp)://[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?/.*)?"
            )
            matches = pattern.finditer(text)

            # thanks to: jmansour //#139
            links = [str(match.group(0)) for match in matches]
            if len(links) == 0:
                return

            filenames = [link.rpartition("/")[2] for link in links]

            packagename = commonprefix(filenames)
            if len(packagename) == 0:
                packagename = filenames[0]

            self.slotAddPackage(packagename, links)

    def slotSetClipboardStatus(self, status):
        """
            set clipboard checking
        """
        self.checkClipboard = status

    def slotChangePackageName(self, pid, name):
        """
            package name edit finished
        """
        self.connector.setPackageName(pid, str(name))

    def slotPullOutPackage(self, pid):
        """
            pull package out of the queue
        """
        self.connector.pullFromQueue(pid)

    def checkCaptcha(self):
        if self.connector.isCaptchaWaiting(
        ) and self.mainWindow.captchaDock.isFree():
            t = self.connector.getCaptchaTask(False)
            self.mainWindow.show()
            self.mainWindow.raise_()
            self.mainWindow.activateWindow()
            self.mainWindow.captchaDock.emit(SIGNAL("setTask"), t.tid,
                                             b64decode(t.data), t.type)
        elif not self.mainWindow.captchaDock.isFree():
            status = self.connector.getCaptchaTaskStatus(
                self.mainWindow.captchaDock.currentID)
            if not (status == "user" or status == "shared-user"):
                self.mainWindow.captchaDock.hide()
                self.mainWindow.captchaDock.processing = False
                self.mainWindow.captchaDock.currentID = None

    def slotCaptchaDone(self, cid, result):
        self.connector.setCaptchaResult(cid, str(result))

    def pullEvents(self):
        events = self.connector.getEvents(self.connector.connectionID)
        if not events:
            return
        for event in events:
            if event.eventname == "account":
                self.mainWindow.emit(SIGNAL("reloadAccounts"), False)
            elif event.eventname == "config":
                pass
            elif event.destination == Destination.Queue:
                self.queue.addEvent(event)
                try:
                    if event.eventname == "update" and event.type == ElementType.File:
                        info = self.connector.getFileData(event.id)
                        if info.statusmsg == "finished":
                            self.emit(
                                SIGNAL("showMessage"),
                                _("Finished downloading of '%s'") % info.name)
                        elif info.statusmsg == "failed":
                            self.emit(
                                SIGNAL("showMessage"),
                                _("Failed downloading '%s'!") % info.name)
                    if event.event == "insert" and event.type == ElementType.File:
                        info = self.connector.getLinkInfo(event[3])
                        self.emit(SIGNAL("showMessage"),
                                  _("Added '%s' to queue") % info.name)
                except:
                    print("can't send notification")
            elif event.destination == Destination.Collector:
                self.packageCollector.addEvent(event)

    def slotReloadAccounts(self, force=False):
        self.mainWindow.tabs["accounts"]["view"].model().reloadData(force)

    def slotQuit(self):
        self.tray.hide()
        self.quitInternal()
        self.app.quit()

    def quitInternal(self):
        if self.core:
            self.core.api.kill()
            for i in range(10):
                if self.core.shuttedDown:
                    break
                sleep(0.5)

    def slotConnectionLost(self):
        if not self.connectionLost:
            self.connectionLost = True
            m = QMessageBox(QMessageBox.Critical, _("Connection lost"),
                            _("Lost connection to the core!"), QMessageBox.Ok)
            m.exec_()
            self.slotQuit()

    class Loop():
        def __init__(self, parent):
            self.parent = parent
            self.timer = QTimer()
            self.timer.connect(self.timer, SIGNAL("timeout()"), self.update)
            self.lastSpaceCheck = 0

        def start(self):
            self.update()
            self.timer.start(1000)

        def update(self):
            """
                methods to call
            """
            self.parent.refreshServerStatus()
            if self.lastSpaceCheck + 5 < time():
                self.lastSpaceCheck = time()
                self.parent.serverStatus[
                    "freespace"] = self.parent.connector.freeSpace()
            self.parent.refreshLog()
            self.parent.checkCaptcha()
            self.parent.pullEvents()

        def stop(self):
            self.timer.stop()
Example #4
0
class main(QObject):
    def __init__(self):
        """
            main setup
        """
        QObject.__init__(self)
        self.app = QApplication(sys.argv)
        self.path = pypath
        self.homedir = abspath("")

        self.configdir = ""

        self.init(True)

    def init(self, first=False):
        """
            set main things up
        """
        self.parser = XMLParser(join(self.configdir, "gui.xml"), join(self.path, "module", "config", "gui_default.xml"))
        lang = self.parser.xml.elementsByTagName("language").item(0).toElement().text()
        if not lang:
            parser = XMLParser(join(self.path, "module", "config", "gui_default.xml"))
            lang = parser.xml.elementsByTagName("language").item(0).toElement().text()

        gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None])
        translation = gettext.translation("pyLoadGui", join(pypath, "locale"), languages=[str(lang), "en"], fallback=True)
        try:
            translation.install(unicode=(True if sys.stdout.encoding.lower().startswith("utf") else False))
        except:
            translation.install(unicode=False)


        self.connector = Connector()
        self.mainWindow = MainWindow(self.connector)
        self.connWindow = ConnectionManager()
        self.mainloop = self.Loop(self)
        self.connectSignals()

        self.checkClipboard = False
        default = self.refreshConnections()
        self.connData = None
        self.captchaProcessing = False
        self.serverStatus = {"freespace":0}

        self.core = None # pyLoadCore if started
        self.connectionLost = False

        if True: # when used if first, minimizing not working correctly..
            self.tray = TrayIcon()
            self.tray.show()
            self.notification = Notification(self.tray)
            self.connect(self, SIGNAL("showMessage"), self.notification.showMessage)
            self.connect(self.tray.exitAction, SIGNAL("triggered()"), self.slotQuit)
            self.connect(self.tray.showAction, SIGNAL("toggled(bool)"), self.mainWindow.setVisible)
            self.connect(self.mainWindow, SIGNAL("hidden"), self.tray.mainWindowHidden)

        if not first:
            self.connWindow.show()
        else:
            self.connWindow.edit.setData(default)
            data = self.connWindow.edit.getData()
            self.slotConnect(data)

    def startMain(self):
        """
            start all refresh threads and show main window
        """
        if not self.connector.connectProxy():
            self.init()
            return
        self.connect(self.connector, SIGNAL("connectionLost"), self.slotConnectionLost)
        self.restoreMainWindow()
        self.mainWindow.show()
        self.initQueue()
        self.initPackageCollector()
        self.mainloop.start()
        self.clipboard = self.app.clipboard()
        self.connect(self.clipboard, SIGNAL('dataChanged()'), self.slotClipboardChange)
        self.mainWindow.actions["clipboard"].setChecked(self.checkClipboard)

        self.mainWindow.tabs["settings"]["w"].setConnector(self.connector)
        self.mainWindow.tabs["settings"]["w"].loadConfig()
        self.tray.showAction.setDisabled(False)

    def stopMain(self):
        """
            stop all refresh threads and hide main window
        """
        self.tray.showAction.setDisabled(True)
        self.disconnect(self.clipboard, SIGNAL('dataChanged()'), self.slotClipboardChange)
        self.disconnect(self.connector, SIGNAL("connectionLost"), self.slotConnectionLost)
        self.mainloop.stop()
        self.mainWindow.saveWindow()
        self.mainWindow.hide()
        self.queue.stop()

    def connectSignals(self):
        """
            signal and slot stuff, yay!
        """
        self.connect(self.connector, SIGNAL("errorBox"), self.slotErrorBox)
        self.connect(self.connWindow, SIGNAL("saveConnection"), self.slotSaveConnection)
        self.connect(self.connWindow, SIGNAL("removeConnection"), self.slotRemoveConnection)
        self.connect(self.connWindow, SIGNAL("connect"), self.slotConnect)
        self.connect(self.mainWindow, SIGNAL("connector"), self.slotShowConnector)
        self.connect(self.mainWindow, SIGNAL("addPackage"), self.slotAddPackage)
        self.connect(self.mainWindow, SIGNAL("setDownloadStatus"), self.slotSetDownloadStatus)
        self.connect(self.mainWindow, SIGNAL("saveMainWindow"), self.slotSaveMainWindow)
        self.connect(self.mainWindow, SIGNAL("pushPackageToQueue"), self.slotPushPackageToQueue)
        self.connect(self.mainWindow, SIGNAL("restartDownload"), self.slotRestartDownload)
        self.connect(self.mainWindow, SIGNAL("removeDownload"), self.slotRemoveDownload)
        self.connect(self.mainWindow, SIGNAL("abortDownload"), self.slotAbortDownload)
        self.connect(self.mainWindow, SIGNAL("addContainer"), self.slotAddContainer)
        self.connect(self.mainWindow, SIGNAL("stopAllDownloads"), self.slotStopAllDownloads)
        self.connect(self.mainWindow, SIGNAL("setClipboardStatus"), self.slotSetClipboardStatus)
        self.connect(self.mainWindow, SIGNAL("changePackageName"), self.slotChangePackageName)
        self.connect(self.mainWindow, SIGNAL("pullOutPackage"), self.slotPullOutPackage)
        self.connect(self.mainWindow, SIGNAL("refreshStatus"), self.slotRefreshStatus)
        self.connect(self.mainWindow, SIGNAL("reloadAccounts"), self.slotReloadAccounts)
        self.connect(self.mainWindow, SIGNAL("Quit"), self.slotQuit)

        self.connect(self.mainWindow.mactions["exit"], SIGNAL("triggered()"), self.slotQuit)
        self.connect(self.mainWindow.captchaDock, SIGNAL("done"), self.slotCaptchaDone)

    def slotShowConnector(self):
        """
            emitted from main window (menu)
            hide the main window and show connection manager
            (to switch to other core)
        """
        self.quitInternal()
        self.stopMain()
        self.init()

    #def quit(self): #not used anymore?
    #    """
    #        quit gui
    #    """
    #    self.app.quit()

    def loop(self):
        """
            start application loop
        """
        sys.exit(self.app.exec_())

    def slotErrorBox(self, msg):
        """
            display a nice error box
        """
        msgb = QMessageBox(QMessageBox.Warning, "Error", msg)
        msgb.exec_()

    def initPackageCollector(self):
        """
            init the package collector view
            * columns
            * selection
            * refresh thread
            * drag'n'drop
        """
        view = self.mainWindow.tabs["collector"]["package_view"]
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        def dropEvent(klass, event):
            event.setDropAction(Qt.CopyAction)
            event.accept()
            view = event.source()
            if view == klass:
                items = view.selectedItems()
                for item in items:
                    if not hasattr(item.parent(), "getPackData"):
                        continue
                    target = view.itemAt(event.pos())
                    if not hasattr(target, "getPackData"):
                        target = target.parent()
                    klass.emit(SIGNAL("droppedToPack"), target.getPackData()["id"], item.getFileData()["id"])
                event.ignore()
                return
            items = view.selectedItems()
            for item in items:
                row = view.indexOfTopLevelItem(item)
                view.takeTopLevelItem(row)
        def dragEvent(klass, event):
            #view = event.source()
            #dragOkay = False
            #items = view.selectedItems()
            #for item in items:
            #    if hasattr(item, "_data"):
            #        if item._data["id"] == "fixed" or item.parent()._data["id"] == "fixed":
            #            dragOkay = True
            #    else:
            #        dragOkay = True
            #if dragOkay:
            event.accept()
            #else:
            #    event.ignore()
        view.dropEvent = dropEvent
        view.dragEnterEvent = dragEvent
        view.setDragEnabled(True)
        view.setDragDropMode(QAbstractItemView.DragDrop)
        view.setDropIndicatorShown(True)
        view.setDragDropOverwriteMode(True)
        view.connect(view, SIGNAL("droppedToPack"), self.slotAddFileToPackage)
        #self.packageCollector = PackageCollector(view, self.connector)
        self.packageCollector = view.model()

    def initQueue(self):
        """
            init the queue view
            * columns
            * progressbar
        """
        view = self.mainWindow.tabs["queue"]["view"]
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.queue = view.model()
        self.connect(self.queue, SIGNAL("updateCount"), self.slotUpdateCount)
        overview = self.mainWindow.tabs["overview"]["view"].model()
        overview.queue = self.queue
        self.connect(self.queue, SIGNAL("updateCount"), overview.queueChanged)
        self.queue.start()
    
    def slotUpdateCount(self, pc, fc):
        self.mainWindow.packageCount.setText("%i" % pc)
        self.mainWindow.fileCount.setText("%i" % fc)
    
    def refreshServerStatus(self):
        """
            refresh server status and overall speed in the status bar
        """
        s = self.connector.statusServer()
        if s.pause:
            self.mainWindow.status.setText(_("paused"))
        else:
            self.mainWindow.status.setText(_("running"))
        self.mainWindow.speed.setText(formatSpeed(s.speed))
        self.mainWindow.space.setText(formatSize(self.serverStatus["freespace"]))
        self.mainWindow.actions["toggle_status"].setChecked(not s.pause)

    def refreshLog(self):
        """
            update log window
        """
        offset = self.mainWindow.tabs["log"]["text"].logOffset
        lines = self.connector.getLog(offset)
        if not lines:
            return
        self.mainWindow.tabs["log"]["text"].logOffset += len(lines)
        for line in lines:
            self.mainWindow.tabs["log"]["text"].emit(SIGNAL("append(QString)"), line.strip("\n"))
        cursor = self.mainWindow.tabs["log"]["text"].textCursor()
        cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
        self.mainWindow.tabs["log"]["text"].setTextCursor(cursor)

    def getConnections(self):
        """
            parse all connections in the config file
        """
        connectionsNode = self.parser.xml.elementsByTagName("connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        ret = []
        for conn in connections:
            data = {}
            data["type"] = conn.attribute("type", "remote")
            data["default"] = conn.attribute("default", "False")
            data["id"] = conn.attribute("id", uuid().hex)
            if data["default"] == "True":
                data["default"] = True
            else:
                data["default"] = False
            subs = self.parser.parseNode(conn, "dict")
            if not subs.has_key("name"):
                data["name"] = _("Unnamed")
            else:
                data["name"] = subs["name"].text()
            if data["type"] == "remote":
                if not subs.has_key("server"):
                    continue
                else:
                    data["host"] = subs["server"].text()
                    data["user"] = subs["server"].attribute("user", "admin")
                    data["port"] = int(subs["server"].attribute("port", "7227"))
                    data["password"] = subs["server"].attribute("password", "")
            ret.append(data)
        return ret

    def slotSaveConnection(self, data):
        """
            save connection to config file
        """
        connectionsNode = self.parser.xml.elementsByTagName("connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        connNode = self.parser.xml.createElement("connection")
        connNode.setAttribute("default", str(data["default"]))
        connNode.setAttribute("type", data["type"])
        connNode.setAttribute("id", data["id"])
        nameNode = self.parser.xml.createElement("name")
        nameText = self.parser.xml.createTextNode(data["name"])
        nameNode.appendChild(nameText)
        connNode.appendChild(nameNode)
        if data["type"] == "remote":
            serverNode = self.parser.xml.createElement("server")
            serverNode.setAttribute("user", data["user"])
            serverNode.setAttribute("port", data["port"])
            serverNode.setAttribute("password", data["password"])
            hostText = self.parser.xml.createTextNode(data["host"])
            serverNode.appendChild(hostText)
            connNode.appendChild(serverNode)
        found = False
        for c in connections:
            cid = c.attribute("id", "None")
            if str(cid) == str(data["id"]):
                found = c
                break
        if found:
            connectionsNode.replaceChild(connNode, found)
        else:
            connectionsNode.appendChild(connNode)
        self.parser.saveData()
        self.refreshConnections()

    def slotRemoveConnection(self, data):
        """
            remove connection from config file
        """
        connectionsNode = self.parser.xml.elementsByTagName("connections").item(0)
        if connectionsNode.isNull():
            raise Exception("null")
        connections = self.parser.parseNode(connectionsNode)
        found = False
        for c in connections:
            cid = c.attribute("id", "None")
            if str(cid) == str(data["id"]):
                found = c
                break
        if found:
            connectionsNode.removeChild(found)
        self.parser.saveData()
        self.refreshConnections()

    def slotConnect(self, data):
        """
            connect to a core
            if connection is local, parse the core config file for data
            if internal, start pyLoadCore
            set up connector, show main window
        """
        self.connWindow.hide()
        if data["type"] not in ("remote","internal"):

            coreparser = ConfigParser(self.configdir)
            if not coreparser.config:
                self.connector.setConnectionData("127.0.0.1", 7227, "anonymous", "anonymous", False)
            else:
                self.connector.setConnectionData("127.0.0.1", coreparser.get("remote","port"), "anonymous", "anonymous")

        elif data["type"] == "remote":
            self.connector.setConnectionData(data["host"], data["port"], data["user"], data["password"])

        elif data["type"] == "internal":
            from pyLoadCore import Core
            from module.ConfigParser import ConfigParser as CoreConfig
            import thread

            if not self.core:

                config = CoreConfig() #create so at least default config exists
                self.core = Core()
                self.core.startedInGui = True
                thread.start_new_thread(self.core.start, (False, False))
                while not self.core.running:
                    sleep(0.5)
                    
                self.connector.proxy = self.core.api
                self.connector.internal = True

                #self.connector.setConnectionData("127.0.0.1", config.get("remote","port"), "anonymous", "anonymous")
        
        self.startMain()
#        try:
#            host = data["host"]
#        except:
#            host = "127.0.0.1"

    def refreshConnections(self):
        """
            reload connetions and display them
        """
        self.parser.loadData()
        conns = self.getConnections()
        self.connWindow.emit(SIGNAL("setConnections"), conns)
        for conn in conns:
            if conn["default"]:
                return conn
        return None

    def slotSetDownloadStatus(self, status):
        """
            toolbar start/pause slot
        """
        if status:
            self.connector.unpauseServer()
        else:
            self.connector.pauseServer()

    def slotAddPackage(self, name, links, password=None):
        """
            emitted from main window
            add package to the collector
        """
        pack = self.connector.addPackage(name, links, Destination.Collector)
        if password:
            data = {"password": password}
            self.connector.setPackageData(pack, data)

    def slotAddFileToPackage(self, pid, fid): #TODO deprecated? gets called
        """
            emitted from collector view after a drop action
        """
        #self.connector.addFileToPackage(fid, pid)
        pass

    def slotAddContainer(self, path):
        """
            emitted from main window
            add container
        """
        filename = basename(path)
        #type = "".join(filename.split(".")[-1])
        fh = open(path, "r")
        content = fh.read()
        fh.close()
        self.connector.uploadContainer(filename, content)

    def slotSaveMainWindow(self, state, geo):
        """
            save the window geometry and toolbar/dock position to config file
        """
        mainWindowNode = self.parser.xml.elementsByTagName("mainWindow").item(0)
        if mainWindowNode.isNull():
            mainWindowNode = self.parser.xml.createElement("mainWindow")
            self.parser.root.appendChild(mainWindowNode)
        stateNode = mainWindowNode.toElement().elementsByTagName("state").item(0)
        geoNode = mainWindowNode.toElement().elementsByTagName("geometry").item(0)
        newStateNode = self.parser.xml.createTextNode(state)
        newGeoNode = self.parser.xml.createTextNode(geo)

        stateNode.removeChild(stateNode.firstChild())
        geoNode.removeChild(geoNode.firstChild())
        stateNode.appendChild(newStateNode)
        geoNode.appendChild(newGeoNode)

        self.parser.saveData()

    def restoreMainWindow(self):
        """
            load and restore main window geometry and toolbar/dock position from config
        """
        mainWindowNode = self.parser.xml.elementsByTagName("mainWindow").item(0)
        if mainWindowNode.isNull():
            return
        nodes = self.parser.parseNode(mainWindowNode, "dict")

        state = str(nodes["state"].text())
        geo = str(nodes["geometry"].text())

        self.mainWindow.restoreWindow(state, geo)
        self.mainWindow.captchaDock.hide()

    def slotPushPackageToQueue(self, id):
        """
            emitted from main window
            push the collector package to queue
        """
        self.connector.pushToQueue(id)

    def slotRestartDownload(self, id, isPack):
        """
            emitted from main window
            restart download
        """
        if isPack:
            self.connector.restartPackage(id)
        else:
            self.connector.restartFile(id)

    def slotRefreshStatus(self, id):
        """
            emitted from main window
            refresh download status
        """
        self.connector.recheckPackage(id)

    def slotRemoveDownload(self, id, isPack):
        """
            emitted from main window
            remove download
        """
        if isPack:
            self.connector.deletePackages([id])
        else:
            self.connector.deleteFiles([id])

    def slotAbortDownload(self, id, isPack):
        """
            emitted from main window
            remove download
        """
        if isPack:
            data = self.connector.getFileOrder(id) #less data to transmit
            self.connector.stopDownloads(data.values())
        else:
            self.connector.stopDownloads([id])

    def slotStopAllDownloads(self):
        """
            emitted from main window
            stop all running downloads
        """
        self.connector.stopAllDownloads()

    def slotClipboardChange(self):
        """
            called if clipboard changes
        """
        if self.checkClipboard:
            text = self.clipboard.text()
            pattern = re.compile(r"(http|https|ftp)://[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?/.*)?")
            matches = pattern.finditer(text)
            
            # thanks to: jmansour //#139
            links = [str(match.group(0)) for match in matches]
            if len(links) == 0:
                return
                
            filenames = [link.rpartition("/")[2] for link in links]
            
            packagename = commonprefix(filenames)
            if len(packagename) == 0:
                packagename = filenames[0]

            self.slotAddPackage(packagename, links)

    def slotSetClipboardStatus(self, status):
        """
            set clipboard checking
        """
        self.checkClipboard = status

    def slotChangePackageName(self, pid, name):
        """
            package name edit finished
        """
        self.connector.setPackageName(pid, str(name))

    def slotPullOutPackage(self, pid):
        """
            pull package out of the queue
        """
        self.connector.pullFromQueue(pid)

    def checkCaptcha(self):
        if self.connector.isCaptchaWaiting() and self.mainWindow.captchaDock.isFree():
            t = self.connector.getCaptchaTask(False)
            self.mainWindow.show()
            self.mainWindow.raise_()
            self.mainWindow.activateWindow()
            self.mainWindow.captchaDock.emit(SIGNAL("setTask"), t.tid, b64decode(t.data), t.type)
        elif not self.mainWindow.captchaDock.isFree():
            status = self.connector.getCaptchaTaskStatus(self.mainWindow.captchaDock.currentID)
            if not (status == "user" or status == "shared-user"):
                self.mainWindow.captchaDock.hide()
                self.mainWindow.captchaDock.processing = False
                self.mainWindow.captchaDock.currentID = None

    def slotCaptchaDone(self, cid, result):
        self.connector.setCaptchaResult(cid, str(result))

    def pullEvents(self):
        events = self.connector.getEvents(self.connector.connectionID)
        if not events:
            return
        for event in events:
            if event.eventname == "account":
                self.mainWindow.emit(SIGNAL("reloadAccounts"), False)
            elif event.eventname == "config":
                pass
            elif event.destination == Destination.Queue:
                self.queue.addEvent(event)
                try:
                    if event.eventname == "update" and event.type == ElementType.File:
                        info = self.connector.getFileData(event.id)
                        if info.statusmsg == "finished":
                            self.emit(SIGNAL("showMessage"), _("Finished downloading of '%s'") % info.name)
                        elif info.statusmsg == "failed":
                            self.emit(SIGNAL("showMessage"), _("Failed downloading '%s'!") % info.name)
                    if event.event == "insert" and event.type == ElementType.File:
                        info = self.connector.getLinkInfo(event[3])
                        self.emit(SIGNAL("showMessage"), _("Added '%s' to queue") % info.name)
                except:
                    print "can't send notification"
            elif event.destination == Destination.Collector:
                self.packageCollector.addEvent(event)

    def slotReloadAccounts(self, force=False):
        self.mainWindow.tabs["accounts"]["view"].model().reloadData(force)

    def slotQuit(self):
        self.tray.hide()
        self.quitInternal()
        self.app.quit()

    def quitInternal(self):
        if self.core:
            self.core.api.kill()
            for i in range(10):
                if self.core.shuttedDown:
                    break
                sleep(0.5)
    
    def slotConnectionLost(self):
        if not self.connectionLost:
            self.connectionLost = True
            m = QMessageBox(QMessageBox.Critical, _("Connection lost"), _("Lost connection to the core!"), QMessageBox.Ok)
            m.exec_()
            self.slotQuit()
    
    class Loop():
        def __init__(self, parent):
            self.parent = parent
            self.timer = QTimer()
            self.timer.connect(self.timer, SIGNAL("timeout()"), self.update)
            self.lastSpaceCheck = 0

        def start(self):
            self.update()
            self.timer.start(1000)

        def update(self):
            """
                methods to call
            """
            self.parent.refreshServerStatus()
            if self.lastSpaceCheck + 5 < time():
                self.lastSpaceCheck = time()
                self.parent.serverStatus["freespace"] = self.parent.connector.freeSpace()
            self.parent.refreshLog()
            self.parent.checkCaptcha()
            self.parent.pullEvents()

        def stop(self):
            self.timer.stop()