Beispiel #1
0
class MainWindow(QMainWindow):
    tsize = (20, 20)

    BG_FREED = QtGui.QColor(255, 255, 153)
    BG_DOWN = QtGui.QColor(146, 208, 80)

    (COLUMN_ID, COLUMN_TITLE, COLUMN_AUTHOR, COLUMN_LINK, COLUMN_PROGRESS) = range(0, 5)
    COLUMNS_WIDTH = [50, 200, 200, 200, 200, 100]

    def __init__(self):
        self.duokan     = Duokan()
        self.conf       = Config()
        self.special    = None
        self.downloader = None
        self.powerOff   = False

        self.tag = MainWindow.__name__
        super( MainWindow, self ).__init__()

        self.ui= Ui_MainWindow()
        self.ui.setupUi(self)
        self.setupPopup()

        self.bindSignal()

    def setupPopup(self):
        self.ui.tableWidget_books.addAction(self.ui.action_list_view_in_browser)
        self.ui.tableWidget_books.addAction(self.ui.action_list_download)
        self.ui.tableWidget_books.addAction(self.ui.action_list_remove)
        self.ui.tableWidget_books.addAction(self.ui.action_list_merge)
        self.ui.tableWidget_books.addAction(self.ui.action_list_crop)
        self.ui.tableWidget_books.addAction(self.ui.action_list_rename)
        self.ui.tableWidget_books.addAction(self.ui.action_list_mark_download)

    def bindSignal(self):
        QtCore.QObject.connect(self, QtCore.SIGNAL("when_information(QString, QString)"), self.do_message)
        QtCore.QObject.connect(self, QtCore.SIGNAL("when_item_progress(QString, QString)"), self.do_itemProgress)
        QtCore.QObject.connect(self, QtCore.SIGNAL("when_add_book(QString, QString, QString, QString, bool, bool)"), self.appendItem)

    def appendItem(self, id, title='', author='', link='', freed=False, done=False):
        row = self.ui.tableWidget_books.rowCount()
        self.when_add_book(row)

        item = QTableWidgetItem(id)
        self.ui.tableWidget_books.setItem(row, MainWindow.COLUMN_ID, item)

        item = QTableWidgetItem(title)
        self.ui.tableWidget_books.setItem(row, MainWindow.COLUMN_TITLE, item)

        item = QTableWidgetItem(author)
        self.ui.tableWidget_books.setItem(row, MainWindow.COLUMN_AUTHOR, item)

        item = QTableWidgetItem(link)
        self.ui.tableWidget_books.setItem(row, MainWindow.COLUMN_LINK, item)

        # item = QTableWidgetItem(progress)
        item = QProgressBar(self)
        item.setRange(0, 100)
        item.setValue(0)
        item.setTextVisible(True)
        item.setMaximumHeight(15)
        item.setTextDirection(QtGui.QProgressBar.TopToBottom)
        self.ui.tableWidget_books.setCellWidget(row, MainWindow.COLUMN_PROGRESS, item)

        if freed:
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).setBackgroundColor(MainWindow.BG_FREED)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).setBackgroundColor(MainWindow.BG_FREED)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_AUTHOR).setBackgroundColor(MainWindow.BG_FREED)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_LINK).setBackgroundColor(MainWindow.BG_FREED)
        if done:
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).setBackgroundColor(MainWindow.BG_DOWN)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).setBackgroundColor(MainWindow.BG_DOWN)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_AUTHOR).setBackgroundColor(MainWindow.BG_DOWN)
            self.ui.tableWidget_books.item(row, MainWindow.COLUMN_LINK).setBackgroundColor(MainWindow.BG_DOWN)

        self.adjustListWidth()

    def adjustListWidth(self):
        self.ui.tableWidget_books.resizeColumnsToContents()

    # set download column progress
    def setProgress(self, row, prog):
        if row >= 0 and row < self.ui.tableWidget_books.rowCount():
            item = self.ui.tableWidget_books.cellWidget(row, MainWindow.COLUMN_PROGRESS)
            item.setValue(prog)

    # for duoSpider
    def cbAddUrl(self, event, url):
        self.when_special_url(url)

    # for duoSpider
    def cbAddBook(self, event, id, title, author, link):
        notFreed = self.duokan.addBook(id, title, author, link)
        download = self.duokan.isDownload(id)
        self.when_add_book_info(id, title, author, link, (not notFreed), download)

    def startDownload(self):
        if self.downloadRow < self.ui.tableWidget_books.rowCount():
            id = _fromQString(self.ui.tableWidget_books.item(self.downloadRow, MainWindow.COLUMN_ID).text())
            proxy = self.conf.getProxy()
            self.downloader = Downloader(id, id, proxy[0], proxy[1], proxy[2])
            self.downloader.bind(Downloader.EVT_START, self.cbStart)
            self.downloader.bind(Downloader.EVT_STOP, self.cbStop)
            self.downloader.bind(Downloader.EVT_LOG, self.cbLog)
            self.downloader.bind(Downloader.EVT_PROG, self.cbProgress)
            self.downloader.start()

    # for downloader
    def cbStart(self, event):
        self.when_itemProgress(self.downloadRow, 100)
        self.when_progress(0)

    # for downloader
    def cbStop(self, event):
        self.when_itemProgress(self.downloadRow, 100)
        self.when_progress(100)
        # self.list.SetItemBackgroundColour(self.downloadIdx, MainWindow.BG_DOWN)

        # start next
        self.downloadRow += 1
        self.startDownload()

        if self.downloadRow >= self.ui.tableWidget_books.rowCount():
            if self.powerOff:
                os.system('shutdown -t 60 -f -s')

    # for downloader
    def cbLog(self, event, str):
        self.when_logging(str)

    # for downloader
    def cbProgress(self, event, prog):
        self.when_progress(prog)

### signals and slots
    # signals
    def when_logging(self, logStr):
        self.emit(QtCore.SIGNAL("when_logging(QString)"), logStr)

    def when_special_url(self, url):
        self.emit(QtCore.SIGNAL("when_special_url(QString)"), url)

    def when_status(self, text):
        self.emit(QtCore.SIGNAL("when_status(QString)"), text)
    def when_add_book(self, row):
        self.emit(QtCore.SIGNAL("when_add_book(int)"), row)

    def when_del_book(self, row):
        self.emit(QtCore.SIGNAL("when_del_book(int)"), row)

    def when_progress(self, prog):
        self.emit(QtCore.SIGNAL("when_progress(int)"), prog)

    # self defined signal##############################################################################################
    def when_information(self, text, title='', info=True):
        self.emit(QtCore.SIGNAL("when_status(QString)"), '%s --> %s' % (title, text))
        if info:
            self.emit(QtCore.SIGNAL("when_information(QString, QString)"), text, title)

    def when_itemProgress(self, row, prog):
        self.emit(QtCore.SIGNAL("when_item_progress(int, int)"), row, prog)

    def when_add_book_info(self, id, title, author, link, freed=False, done=False):
        self.emit(QtCore.SIGNAL("when_add_book(QString, QString, QString, QString, bool, bool)"),
                  _fromUtf8(id), _fromUtf8(title), _fromUtf8(author), _fromUtf8(link), freed, done)

    # slots
    def do_update(self):
        self.when_progress(10)
        proxy = self.conf.getProxy()
        self.special = Special(proxy[0], proxy[1], proxy[2])
        self.special.bind(Special.EVT_FIND_LINK, self.cbAddUrl)
        self.special.bind(Special.EVT_FIND_BOOK, self.cbAddBook)
        self.special.start()
        self.when_progress(100)

    def do_update_stop(self):
        if self.special:
            self.special.stop()
            self.special = None

    def do_download_all(self):
        self.dlgs = []
        for row in range(self.ui.tableWidget_books.rowCount()):
            id    = self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text()
            title = self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).text()
            dlg = DownloaderDlg(self, self.conf, title)
            dlg.setId(id)
            dlg.setName(id)
            dlg.show()
            dlg.resize(640, 200)
            self.dlgs.append(dlg)

        if self.dlgs:
            for i, dlg in enumerate(self.dlgs):
                if i < 5:
                    x = 0
                    y = 190 * i
                else:
                    x = 640
                    y = 190 * (i - 5)
                dlg.resize(640, 190)
                dlg.move(x, y)

    def do_download_stop(self):
        pass

    def do_open_special_in_browser(self):
        self.duokan.openInNewTab(_fromQString(self.ui.lineEdit_specialUrl.text()))

    def do_open_books_folder(self):
        '''open books/new folder'''
        self.duokan.openNewFolder()

    def do_clean_tmp_folder(self):
        self.duokan.cleanTmp()
        self.when_information( 'Finished', 'Clear tmp folder')

    def do_merge_all(self):
        for row in range(self.ui.tableWidget_books.rowCount()):
            id = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            self.duokan.merge(id)
        self.when_information('merge all finished')

    def do_crop_all(self):
        for row in range(self.ui.tableWidget_books.rowCount()):
            id = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            self.duokan.crop(id)
        self.when_information('crop all finished')

    def do_rename_all(self):
        self.duokan.renameAll()
        self.when_information('Finished', 'Rename All')

    def do_done_all(self):
        for row in range(self.ui.tableWidget_books.rowCount()):
            id    = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            title = self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).text()
            self.when_information('Start', 'Merge & Crop & Rename [%s]' % title, False)
            self.duokan.setDownload(id)
            self.duokan.merge(id)
            self.duokan.crop(id)
            self.duokan.rename(id)
            self.when_information('Finished!', 'Merge & Crop & Rename [%s]' % title, False)
        self.when_information('Finished!', 'All Merge & Crop & Rename')

    def do_crop_book(self):
        file_wildcard = "Pdf files (*.pdf)"
        filePath = QFileDialog.getOpenFileName(self, 'Open file to crop', _fromUtf8(os.path.join(os.getcwd(), 'books')), _fromUtf8(file_wildcard))
        if filePath:
            self.duokan.cropSingle(_fromQString(filePath))
            self.when_information( 'Finished!', 'Crop single')

    def do_merge_book(self):
        filePath = QFileDialog.getExistingDirectory(self, 'Open file to crop', _fromUtf8(os.path.join(os.getcwd(), 'tmp')))
        if filePath:
            print _fromQString(filePath)
            self.duokan.mergeSingle(_fromQString(filePath))
            self.when_information('Finished!', 'Merge single')

    def do_crop_4print(self):
        file_wildcard = "Pdf files (*.pdf)"
        filePath = QFileDialog.getOpenFileName(self, 'Open file to crop for printing', _fromUtf8(os.path.join(os.getcwd(), 'books')), _fromUtf8(file_wildcard))
        if filePath:
            self.duokan.crop4Print(_fromQString(filePath))
            self.when_information( 'Finished!', 'Crop for printing')

    def do_crop_4kindle(self):
        file_wildcard = "Pdf files (*.pdf)"
        filePath = QFileDialog.getOpenFileName(self, 'Open file to crop for printing', _fromUtf8(os.path.join(os.getcwd(), 'books')), _fromUtf8(file_wildcard))
        if filePath:
            self.duokan.crop4Kindle(_fromQString(filePath))
            self.when_information( 'Finished!', 'Crop for kindle')

    def do_crop_4nook(self):
        file_wildcard = "Pdf files (*.pdf)"
        filePath = QFileDialog.getOpenFileName(self, 'Open file to crop for printing', _fromUtf8(os.path.join(os.getcwd(), 'books')), _fromUtf8(file_wildcard))
        if filePath:
            self.duokan.crop4Nook(_fromQString(filePath))
            self.when_information('Finished!', 'Crop for nook')

    def on_power_off_setting(self, powerOff):
        self.powerOff = powerOff
        # print powerOff

    def do_destroyed(self):
        print 'destroyed'

    def do_list_view_in_browser(self):
        ''' open link in browser '''
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            url = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_LINK).text())
            self.duokan.openInNewTab(url)

    def do_list_download(self):
        '''download a book'''
        row = self.ui.tableWidget_books.currentRow()
        if row >=0 and row < self.ui.tableWidget_books.rowCount():
            id    = self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text()
            title = self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).text()
            dlg = DownloaderDlg(self, self.conf, title)
            dlg.setId(id)
            dlg.setName(id)
            dlg.show()
        else:
            dlg = DownloaderDlg(self, self.conf)
            dlg.show()

    def do_list_remove(self):
        ''' delete an item '''
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            self.when_del_book(row)

    def do_list_merge(self):
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            id = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            self.duokan.merge(id)
            self.when_information('merge finished')

    def do_list_crop(self):
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            id = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            self.duokan.crop(id)
            self.when_information('crop finished')

    def do_list_rename(self):
        ''' rename a item from id to title '''
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            id    = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            title = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_TITLE).text())
            self.duokan.rename(id, title)
            self.when_information('rename finished')

    def do_list_mark_download(self, row, col):
        row = self.ui.tableWidget_books.currentRow()
        if row != -1:
            id = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_ID).text())
            self.duokan.setDownload(id)

    def do_list_dclick(self, row, col):
        url = _fromQString(self.ui.tableWidget_books.item(row, MainWindow.COLUMN_LINK).text())
        self.duokan.openInNewTab(url)

    # self defined slots ###############################################################################################
    def do_message(self, text, title=''):
        QtGui.QMessageBox.information(self, title, text)

    def do_itemProgress(self, row, prog):
        self.setProgress(row, prog)
Beispiel #2
0
class MainWindow(wx.Frame):
    tsize = (20, 20)

    BG_FREED = wx.Colour(255, 255, 153)
    BG_DOWN = wx.Colour(146, 208, 80)

    (
        ID_MENUITEM_FETCH,
        ID_MENUITEM_DOWNLOAD_ALL,
        ID_MENUITEM_OPEN_IN_BROWER,
        ID_MENUITEM_OPEN_NEW,
        ID_MENUITEM_SHUTDOWN,
        ID_MENUITEM_CLEAN_TMP,
        ID_MENUITEM_RENAME_ALL,
        ID_MENUITEM_MERGE_SINGLE,
        ID_MENUITEM_CROP_SINGLE,
        ID_MENUITEM_CROP_4_PRINT,
        ID_MENUITEM_CROP_4_KINDLE,
        ID_MENUITEM_DOWN,
        ID_MENUITEM_VIEW,
        ID_MENUITEM_REMOVE,
        ID_MENUITEM_MERGE,
        ID_MENUITEM_CROP,
        ID_MENUITEM_RENAME,
        ID_LIST,
        ID_TOOL_FETCH,
        ID_TOOL_OPEN,
        ID_TOOL_DOWN,
    ) = range(0, 21)

    COLUMNS = ["#", "ID", "TITLE", "AUTHOR", "LINK", "PROGRESS"]
    (COLUMN_NUM, COLUMN_ID, COLUMN_TITLE, COLUMN_AUTHOR, COLUMN_LINK, COLUMN_PROGRESS) = range(0, 6)
    COLUMNS_WIDTH = [50, 200, 200, 200, 200, 100]

    def __init__(self, tt):
        self.duokan = Duokan()
        self.conf = Config()

        self.MENUBAR = [
            (
                "&File",
                (
                    ("&Fetch", "", MainWindow.ID_MENUITEM_FETCH, self.onUpdate),
                    ("&Download all", "", MainWindow.ID_MENUITEM_DOWNLOAD_ALL, self.onDownloadAll),
                    ("", "", "", ""),
                    ("&Open in brower", "", MainWindow.ID_MENUITEM_OPEN_IN_BROWER, self.onBrowser),
                    ("&Open download folder", "", MainWindow.ID_MENUITEM_OPEN_NEW, self.onOpenNewFolder),
                    ("", "", "", ""),
                    ("Shutdown after finish", "", MainWindow.ID_MENUITEM_SHUTDOWN, self.menuShutdown, wx.ITEM_CHECK),
                ),
            ),
            (
                "&Edit",
                (
                    ("&Clean tmp folder", "", MainWindow.ID_MENUITEM_CLEAN_TMP, self.onCleanTmp),
                    ("&Rename all", "", MainWindow.ID_MENUITEM_RENAME_ALL, self.onRenameAll),
                    ("", "", "", ""),
                    ("&Merge", "", MainWindow.ID_MENUITEM_MERGE_SINGLE, self.onMergeSingle),
                    ("&Crop", "", MainWindow.ID_MENUITEM_CROP_SINGLE, self.onCropSingle),
                    ("Crop for &printing", "", MainWindow.ID_MENUITEM_CROP_4_PRINT, self.onCrop4Print),
                    ("Crop for &kindle", "", MainWindow.ID_MENUITEM_CROP_4_KINDLE, self.onCrop4Kindle),
                ),
            ),
        ]

        self.POPMENU = [
            (MainWindow.ID_MENUITEM_DOWN, "Download", self.onDownloadItem, MainWindow.ID_LIST),
            (MainWindow.ID_MENUITEM_VIEW, "View in browser", self.onBrowserItem, MainWindow.ID_LIST),
            (MainWindow.ID_MENUITEM_REMOVE, "Remove", self.onRemoveItem, MainWindow.ID_LIST),
            (MainWindow.ID_MENUITEM_MERGE, "Merge", self.onMergeItem, MainWindow.ID_LIST),
            (MainWindow.ID_MENUITEM_CROP, "Crop", self.onCropItem, MainWindow.ID_LIST),
            (MainWindow.ID_MENUITEM_RENAME, "Rename", self.onRenameItem, MainWindow.ID_LIST),
        ]

        self.TOOLBAR = [
            (
                MainWindow.ID_TOOL_FETCH,
                "Fetch",
                wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_BUTTON, MainWindow.tsize),
                self.onUpdate,
            ),
            (
                MainWindow.ID_TOOL_OPEN,
                "View in browser",
                wx.ArtProvider.GetBitmap(wx.ART_FIND, wx.ART_BUTTON, MainWindow.tsize),
                self.onBrowser,
            ),
            (
                MainWindow.ID_TOOL_DOWN,
                "Download all",
                wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, wx.ART_BUTTON, MainWindow.tsize),
                self.onDownloadAll,
            ),
        ]

        wx.Frame.__init__(self, None, title=tt, size=(1020, 800))

        self.menubar = self.createMenubar()
        self.CreateStatusBar()
        self.createPopmenu()
        self.toolbar = self.createToolBar()

        # panel######################################
        panel = wx.Panel(self)

        lblUrl = wx.StaticText(panel, -1, "Special URL: ", style=1)
        self.teUrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER)

        hbox = wx.BoxSizer()
        hbox.Add(lblUrl, proportion=0, flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=5)
        hbox.Add(self.teUrl, proportion=1, flag=wx.EXPAND)

        self.gauge = wx.Gauge(panel, -1, 100, style=wx.GA_PROGRESSBAR)
        self.list = wx.ListCtrl(
            panel, MainWindow.ID_LIST, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_HRULES | wx.LC_VRULES
        )
        self.teInfo = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.HSCROLL)

        for i in range(len(MainWindow.COLUMNS)):
            self.list.InsertColumn(i, MainWindow.COLUMNS[i], width=MainWindow.COLUMNS_WIDTH[i])

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.gauge, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.list, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.teInfo, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, border=5)

        panel.SetSizer(vbox)

        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onDownloadItem, id=MainWindow.ID_LIST)
        self.Bind(wx.EVT_CONTEXT_MENU, self.onShowPopup, id=MainWindow.ID_LIST)

        self.downloadIdx = 0

        # self.redir = RedirectText(self)
        # sys.stdout = self.redir

        self.Centre()

    def createMenubar(self):
        menuBar = wx.MenuBar()
        for eachMenu in self.MENUBAR:
            label = eachMenu[0]
            items = eachMenu[1]
            menuBar.Append(self.createMenuItems(items), label)
        self.SetMenuBar(menuBar)
        return menuBar

    def createMenuItems(self, menuData):
        menu = wx.Menu()
        for item in menuData:
            if len(item) == 2:
                label = item[0]
                subMenu = self.createMenuItems(item[1])
                menu.AppendMenu(wx.ID_ANY, label, subMenu)
            else:
                label = item[0]
                help = item[1]
                id = item[2]
                handler = item[3]
                if len(item) > 4:
                    kind = item[4]
                else:
                    kind = wx.ITEM_NORMAL

                if label:
                    menu.Append(id, label, help, kind=kind)
                    self.Bind(wx.EVT_MENU, handler, id=id)
                else:
                    menu.AppendSeparator()
        return menu

    def createPopmenu(self):
        self.popupmenu = wx.Menu()
        for item in self.POPMENU:
            self.popupmenu.Append(item[0], item[1])
            self.Bind(wx.EVT_MENU, item[2], id=item[0], id2=item[3])
        return self.popupmenu

    def createToolBar(self):
        toolbar = self.CreateToolBar()
        for item in self.TOOLBAR:
            toolbar.AddLabelTool(item[0], item[1], item[2])
            self.Bind(wx.EVT_TOOL, item[3], id=item[0])
        toolbar.Realize()
        return toolbar

    def appendItem(self, id, title="", author="", link="", freed=False, done=False, progress="=========="):
        newIdx = self.list.GetItemCount()
        self.list.InsertStringItem(newIdx, "%d" % (newIdx + 1))
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_ID, id)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_TITLE, title)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_AUTHOR, author)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_LINK, link)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_PROGRESS, progress)

        if freed:
            self.list.SetItemBackgroundColour(newIdx, MainWindow.BG_FREED)
        if done:
            self.list.SetItemBackgroundColour(newIdx, MainWindow.BG_DOWN)

        self.adjustListWidth()

    def adjustListWidth(self):
        self.list.SetColumnWidth(MainWindow.COLUMN_NUM, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_ID, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_TITLE, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_AUTHOR, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_LINK, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_PROGRESS, wx.LIST_AUTOSIZE)

    # set download column progress
    def setProgress(self, idx, prog):
        if idx < self.list.GetItemCount():
            ppp = ""
            prog /= 10
            for i in range(prog):
                ppp += ">"
            for i in range(10 - prog):
                ppp += "="
            self.list.SetStringItem(idx, MainWindow.COLUMN_PROGRESS, ppp)

    def setUrl(self, url):
        self.teUrl.SetValue(url)

    def addLog(self, log):
        self.teInfo.AppendText(log)
        pass

    def onKeyDown(self, event):
        self.onUpdate(event)

    def onUpdate(self, event):
        self.gauge.SetValue(10)
        proxy = self.conf.getProxy()
        special = Special(proxy[0], proxy[1], proxy[2])
        special.bind(Special.EVT_FIND_LINK, self.cbAddUrl)
        special.bind(Special.EVT_FIND_BOOK, self.cbAddBook)
        special.start()
        self.gauge.SetValue(100)

    def onBrowser(self, event):
        self.duokan.openInNewTab(self.teUrl.GetValue())

    def onOpenNewFolder(self, event):
        self.duokan.openNewFolder()

    def menuShutdown(self, event):
        print self.menubar.IsChecked(MainWindow.ID_MENUITEM_SHUTDOWN)

    def onDownloadAll(self, event):
        self.downloadIdx = 0
        self.startDownload()

    def onCleanTmp(self, event):
        self.duokan.cleanTmp()
        ux.showMsg(self, "Finished", "Clear tmp folder")

    def onRenameAll(self, event):
        self.duokan.renameAll()
        ux.showMsg(self, "Finished", "Rename All")

    def onMergeSingle(self, event):
        # file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showDirDlg(self, "Open dir to merge", os.path.join(os.getcwd(), "tmp"))
        if ret and filePath:
            self.duokan.mergeSingle(filePath)
            ux.showMsg(self, "Finished!", "Merge single")

    def onCropSingle(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(self, "Open file to crop", os.path.join(os.getcwd(), "books"), file_wildcard)
        if ret and filePath:
            self.duokan.cropSingle(filePath)
            ux.showMsg(self, "Finished!", "Crop single")

    def onCrop4Print(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(
            self, "Open file to crop for printing", os.path.join(os.getcwd(), "books"), file_wildcard
        )
        if ret and filePath:
            self.duokan.crop4Print(filePath)
            ux.showMsg(self, "Finished!", "Crop for printing")

    def onCrop4Kindle(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(
            self, "Open file to crop for printing", os.path.join(os.getcwd(), "books"), file_wildcard
        )
        if ret and filePath:
            self.duokan.crop4Kindle(filePath)
            ux.showMsg(self, "Finished!", "Crop for kindle")

    # download a book
    def onDownloadItem(self, event):
        idx = self.list.GetFocusedItem()
        id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
        title = self.list.GetItemText(idx, MainWindow.COLUMN_TITLE)
        win = DownloaderWnd(self.conf, title)
        win.setId(id)
        win.setName(id)
        win.Show(True)

    # show popup menu
    def onShowPopup(self, event):
        if self.list.GetFirstSelected() != -1:
            pos = event.GetPosition()
            pos = self.list.ScreenToClient(pos)
            self.list.PopupMenu(self.popupmenu, pos)

    # open link in browser
    def onBrowserItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            url = self.list.GetItemText(idx, MainWindow.COLUMN_LINK)
            self.duokan.openInNewTab(url)

    # rename a item from id to title
    def onRenameItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            title = self.list.GetItemText(idx, MainWindow.COLUMN_TITLE)
            self.duokan.rename(id, title)

    # delete an item
    def onRemoveItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            self.list.DeleteItem(idx)

    def onCropItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            self.duokan.crop(id)

    def onMergeItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            self.duokan.merge(id)

    def startDownload(self):
        if self.downloadIdx < self.list.GetItemCount():
            id = self.list.GetItemText(self.downloadIdx, MainWindow.COLUMN_ID)
            proxy = self.conf.getProxy()
            self.down = Downloader(id, id, proxy[0], proxy[1], proxy[2])
            self.down.bind(Downloader.EVT_START, self.cbStart)
            self.down.bind(Downloader.EVT_STOP, self.cbStop)
            self.down.bind(Downloader.EVT_LOG, self.cbLog)
            self.down.bind(Downloader.EVT_PROG, self.cbProgress)
            self.down.start()

    # for downloader
    def cbStart(self, event):
        wx.CallAfter(self.setProgress, self.downloadIdx, 0)

    # for downloader
    def cbStop(self, event):
        wx.CallAfter(self.setProgress, self.downloadIdx, 100)
        wx.CallAfter(self.gauge.SetValue, 100)
        self.list.SetItemBackgroundColour(self.downloadIdx, MainWindow.BG_DOWN)

        # rename
        id = self.list.GetItemText(self.downloadIdx, MainWindow.COLUMN_ID)
        title = self.list.GetItemText(self.downloadIdx, MainWindow.COLUMN_TITLE)
        self.duokan.rename(id, title)

        # start next
        self.downloadIdx += 1
        self.startDownload()

        if self.downloadIdx >= self.list.GetItemCount():
            if self.menubar.IsChecked(MainWindow.ID_MENUITEM_SHUTDOWN):
                os.system("shutdown -t 60 -f -s")

    # for downloader
    def cbLog(self, event, str):
        wx.CallAfter(self.addLog, str)
        print str

    # for downloader
    def cbProgress(self, event, prog):
        # itemCount = self.list.GetItemCount()
        # wx.CallAfter(self.setProgress, self.downloadIdx, prog)
        wx.CallAfter(self.gauge.SetValue, prog)

    # for duoSpider
    def cbAddUrl(self, event, url):
        wx.CallAfter(self.setUrl, url)

    # for duoSpider
    def cbAddBook(self, event, id, title, author, link):
        notFreed = self.duokan.addBook(id, title, author, link)
        download = self.duokan.isDownload(id)
        wx.CallAfter(self.appendItem, id, title, author, link, (not notFreed), download)
Beispiel #3
0
class MainWindow(wx.Frame):
    tsize = (20, 20)

    BG_FREED = wx.Colour(255, 255, 153)
    BG_DOWN = wx.Colour(146, 208, 80)

    (ID_MENUITEM_FETCH, ID_MENUITEM_DOWNLOAD_ALL, ID_MENUITEM_OPEN_IN_BROWER,
     ID_MENUITEM_OPEN_NEW, ID_MENUITEM_SHUTDOWN, ID_MENUITEM_CLEAN_TMP,
     ID_MENUITEM_RENAME_ALL, ID_MENUITEM_MERGE_SINGLE, ID_MENUITEM_CROP_SINGLE,
     ID_MENUITEM_CROP_4_PRINT, ID_MENUITEM_CROP_4_KINDLE, ID_MENUITEM_DOWN,
     ID_MENUITEM_VIEW, ID_MENUITEM_REMOVE, ID_MENUITEM_MERGE, ID_MENUITEM_CROP,
     ID_MENUITEM_RENAME, ID_LIST, ID_TOOL_FETCH, ID_TOOL_OPEN,
     ID_TOOL_DOWN) = range(0, 21)

    COLUMNS = ['#', 'ID', 'TITLE', 'AUTHOR', 'LINK', 'PROGRESS']
    (COLUMN_NUM, COLUMN_ID, COLUMN_TITLE, COLUMN_AUTHOR, COLUMN_LINK,
     COLUMN_PROGRESS) = range(0, 6)
    COLUMNS_WIDTH = [50, 200, 200, 200, 200, 100]

    def __init__(self, tt):
        self.duokan = Duokan()
        self.conf = Config()

        self.MENUBAR = [
            ('&File', (
                ('&Fetch', '', MainWindow.ID_MENUITEM_FETCH, self.onUpdate),
                ('&Download all', '', MainWindow.ID_MENUITEM_DOWNLOAD_ALL,
                 self.onDownloadAll),
                ("", '', '', ""),
                ('&Open in brower', '', MainWindow.ID_MENUITEM_OPEN_IN_BROWER,
                 self.onBrowser),
                ('&Open download folder', '', MainWindow.ID_MENUITEM_OPEN_NEW,
                 self.onOpenNewFolder),
                ("", '', '', ""),
                ('Shutdown after finish', '', MainWindow.ID_MENUITEM_SHUTDOWN,
                 self.menuShutdown, wx.ITEM_CHECK),
            )),
            ('&Edit',
             (('&Clean tmp folder', '', MainWindow.ID_MENUITEM_CLEAN_TMP,
               self.onCleanTmp),
              ('&Rename all', '', MainWindow.ID_MENUITEM_RENAME_ALL,
               self.onRenameAll), ("", "", '', ""),
              ('&Merge', '', MainWindow.ID_MENUITEM_MERGE_SINGLE,
               self.onMergeSingle), ('&Crop', '',
                                     MainWindow.ID_MENUITEM_CROP_SINGLE,
                                     self.onCropSingle),
              ('Crop for &printing', '', MainWindow.ID_MENUITEM_CROP_4_PRINT,
               self.onCrop4Print), ('Crop for &kindle', '',
                                    MainWindow.ID_MENUITEM_CROP_4_KINDLE,
                                    self.onCrop4Kindle)))
        ]

        self.POPMENU = [(MainWindow.ID_MENUITEM_DOWN, 'Download',
                         self.onDownloadItem, MainWindow.ID_LIST),
                        (MainWindow.ID_MENUITEM_VIEW, 'View in browser',
                         self.onBrowserItem, MainWindow.ID_LIST),
                        (MainWindow.ID_MENUITEM_REMOVE, 'Remove',
                         self.onRemoveItem, MainWindow.ID_LIST),
                        (MainWindow.ID_MENUITEM_MERGE, 'Merge',
                         self.onMergeItem, MainWindow.ID_LIST),
                        (MainWindow.ID_MENUITEM_CROP, 'Crop', self.onCropItem,
                         MainWindow.ID_LIST),
                        (MainWindow.ID_MENUITEM_RENAME, 'Rename',
                         self.onRenameItem, MainWindow.ID_LIST)]

        self.TOOLBAR = [
            (MainWindow.ID_TOOL_FETCH, 'Fetch',
             wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_BUTTON,
                                      MainWindow.tsize), self.onUpdate),
            (MainWindow.ID_TOOL_OPEN, 'View in browser',
             wx.ArtProvider.GetBitmap(wx.ART_FIND, wx.ART_BUTTON,
                                      MainWindow.tsize), self.onBrowser),
            (MainWindow.ID_TOOL_DOWN, 'Download all',
             wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, wx.ART_BUTTON,
                                      MainWindow.tsize), self.onDownloadAll)
        ]

        wx.Frame.__init__(self, None, title=tt, size=(1020, 800))

        self.menubar = self.createMenubar()
        self.CreateStatusBar()
        self.createPopmenu()
        self.toolbar = self.createToolBar()

        #panel######################################
        panel = wx.Panel(self)

        lblUrl = wx.StaticText(panel, -1, "Special URL: ", style=1)
        self.teUrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER)

        hbox = wx.BoxSizer()
        hbox.Add(lblUrl,
                 proportion=0,
                 flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL,
                 border=5)
        hbox.Add(self.teUrl, proportion=1, flag=wx.EXPAND)

        self.gauge = wx.Gauge(panel, -1, 100, style=wx.GA_PROGRESSBAR)
        self.list = wx.ListCtrl(panel,
                                MainWindow.ID_LIST,
                                style=wx.LC_REPORT | wx.LC_SINGLE_SEL
                                | wx.LC_HRULES | wx.LC_VRULES)
        self.teInfo = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.HSCROLL)

        for i in range(len(MainWindow.COLUMNS)):
            self.list.InsertColumn(i,
                                   MainWindow.COLUMNS[i],
                                   width=MainWindow.COLUMNS_WIDTH[i])

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.gauge, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.list, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.teInfo,
                 proportion=1,
                 flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT,
                 border=5)

        panel.SetSizer(vbox)

        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED,
                  self.onDownloadItem,
                  id=MainWindow.ID_LIST)
        self.Bind(wx.EVT_CONTEXT_MENU, self.onShowPopup, id=MainWindow.ID_LIST)

        self.downloadIdx = 0

        # self.redir = RedirectText(self)
        # sys.stdout = self.redir

        self.Centre()

    def createMenubar(self):
        menuBar = wx.MenuBar()
        for eachMenu in self.MENUBAR:
            label = eachMenu[0]
            items = eachMenu[1]
            menuBar.Append(self.createMenuItems(items), label)
        self.SetMenuBar(menuBar)
        return menuBar

    def createMenuItems(self, menuData):
        menu = wx.Menu()
        for item in menuData:
            if len(item) == 2:
                label = item[0]
                subMenu = self.createMenuItems(item[1])
                menu.AppendMenu(wx.ID_ANY, label, subMenu)
            else:
                label = item[0]
                help = item[1]
                id = item[2]
                handler = item[3]
                if len(item) > 4:
                    kind = item[4]
                else:
                    kind = wx.ITEM_NORMAL

                if label:
                    menu.Append(id, label, help, kind=kind)
                    self.Bind(wx.EVT_MENU, handler, id=id)
                else:
                    menu.AppendSeparator()
        return menu

    def createPopmenu(self):
        self.popupmenu = wx.Menu()
        for item in self.POPMENU:
            self.popupmenu.Append(item[0], item[1])
            self.Bind(wx.EVT_MENU, item[2], id=item[0], id2=item[3])
        return self.popupmenu

    def createToolBar(self):
        toolbar = self.CreateToolBar()
        for item in self.TOOLBAR:
            toolbar.AddLabelTool(item[0], item[1], item[2])
            self.Bind(wx.EVT_TOOL, item[3], id=item[0])
        toolbar.Realize()
        return toolbar

    def appendItem(self,
                   id,
                   title='',
                   author='',
                   link='',
                   freed=False,
                   done=False,
                   progress='=========='):
        newIdx = self.list.GetItemCount()
        self.list.InsertStringItem(newIdx, '%d' % (newIdx + 1))
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_ID, id)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_TITLE, title)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_AUTHOR, author)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_LINK, link)
        self.list.SetStringItem(newIdx, MainWindow.COLUMN_PROGRESS, progress)

        if freed:
            self.list.SetItemBackgroundColour(newIdx, MainWindow.BG_FREED)
        if done:
            self.list.SetItemBackgroundColour(newIdx, MainWindow.BG_DOWN)

        self.adjustListWidth()

    def adjustListWidth(self):
        self.list.SetColumnWidth(MainWindow.COLUMN_NUM, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_ID, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_TITLE, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_AUTHOR, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_LINK, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(MainWindow.COLUMN_PROGRESS, wx.LIST_AUTOSIZE)

    # set download column progress
    def setProgress(self, idx, prog):
        if idx < self.list.GetItemCount():
            ppp = ''
            prog /= 10
            for i in range(prog):
                ppp += '>'
            for i in range(10 - prog):
                ppp += '='
            self.list.SetStringItem(idx, MainWindow.COLUMN_PROGRESS, ppp)

    def setUrl(self, url):
        self.teUrl.SetValue(url)

    def addLog(self, log):
        self.teInfo.AppendText(log)
        pass

    def onKeyDown(self, event):
        self.onUpdate(event)

    def onUpdate(self, event):
        self.gauge.SetValue(10)
        proxy = self.conf.getProxy()
        special = Special(proxy[0], proxy[1], proxy[2])
        special.bind(Special.EVT_FIND_LINK, self.cbAddUrl)
        special.bind(Special.EVT_FIND_BOOK, self.cbAddBook)
        special.start()
        self.gauge.SetValue(100)

    def onBrowser(self, event):
        self.duokan.openInNewTab(self.teUrl.GetValue())

    def onOpenNewFolder(self, event):
        self.duokan.openNewFolder()

    def menuShutdown(self, event):
        print self.menubar.IsChecked(MainWindow.ID_MENUITEM_SHUTDOWN)

    def onDownloadAll(self, event):
        self.downloadIdx = 0
        self.startDownload()

    def onCleanTmp(self, event):
        self.duokan.cleanTmp()
        ux.showMsg(self, 'Finished', 'Clear tmp folder')

    def onRenameAll(self, event):
        self.duokan.renameAll()
        ux.showMsg(self, 'Finished', 'Rename All')

    def onMergeSingle(self, event):
        # file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showDirDlg(self, 'Open dir to merge',
                                      os.path.join(os.getcwd(), 'tmp'))
        if ret and filePath:
            self.duokan.mergeSingle(filePath)
            ux.showMsg(self, 'Finished!', 'Merge single')

    def onCropSingle(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(self, 'Open file to crop',
                                       os.path.join(os.getcwd(), 'books'),
                                       file_wildcard)
        if ret and filePath:
            self.duokan.cropSingle(filePath)
            ux.showMsg(self, 'Finished!', 'Crop single')

    def onCrop4Print(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(self, 'Open file to crop for printing',
                                       os.path.join(os.getcwd(), 'books'),
                                       file_wildcard)
        if ret and filePath:
            self.duokan.crop4Print(filePath)
            ux.showMsg(self, 'Finished!', 'Crop for printing')

    def onCrop4Kindle(self, event):
        file_wildcard = "Pdf files(*.pdf)|*.pdf"
        ret, filePath = ux.showFileDlg(self, 'Open file to crop for printing',
                                       os.path.join(os.getcwd(), 'books'),
                                       file_wildcard)
        if ret and filePath:
            self.duokan.crop4Kindle(filePath)
            ux.showMsg(self, 'Finished!', 'Crop for kindle')

    # download a book
    def onDownloadItem(self, event):
        idx = self.list.GetFocusedItem()
        id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
        title = self.list.GetItemText(idx, MainWindow.COLUMN_TITLE)
        win = DownloaderWnd(self.conf, title)
        win.setId(id)
        win.setName(id)
        win.Show(True)

    # show popup menu
    def onShowPopup(self, event):
        if self.list.GetFirstSelected() != -1:
            pos = event.GetPosition()
            pos = self.list.ScreenToClient(pos)
            self.list.PopupMenu(self.popupmenu, pos)

    # open link in browser
    def onBrowserItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            url = self.list.GetItemText(idx, MainWindow.COLUMN_LINK)
            self.duokan.openInNewTab(url)

    # rename a item from id to title
    def onRenameItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            title = self.list.GetItemText(idx, MainWindow.COLUMN_TITLE)
            self.duokan.rename(id, title)

    # delete an item
    def onRemoveItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            self.list.DeleteItem(idx)

    def onCropItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            self.duokan.crop(id)

    def onMergeItem(self, event):
        idx = self.list.GetFirstSelected()
        if idx != -1:
            id = self.list.GetItemText(idx, MainWindow.COLUMN_ID)
            self.duokan.merge(id)

    def startDownload(self):
        if self.downloadIdx < self.list.GetItemCount():
            id = self.list.GetItemText(self.downloadIdx, MainWindow.COLUMN_ID)
            proxy = self.conf.getProxy()
            self.down = Downloader(id, id, proxy[0], proxy[1], proxy[2])
            self.down.bind(Downloader.EVT_START, self.cbStart)
            self.down.bind(Downloader.EVT_STOP, self.cbStop)
            self.down.bind(Downloader.EVT_LOG, self.cbLog)
            self.down.bind(Downloader.EVT_PROG, self.cbProgress)
            self.down.start()

    # for downloader
    def cbStart(self, event):
        wx.CallAfter(self.setProgress, self.downloadIdx, 0)

    # for downloader
    def cbStop(self, event):
        wx.CallAfter(self.setProgress, self.downloadIdx, 100)
        wx.CallAfter(self.gauge.SetValue, 100)
        self.list.SetItemBackgroundColour(self.downloadIdx, MainWindow.BG_DOWN)

        # rename
        id = self.list.GetItemText(self.downloadIdx, MainWindow.COLUMN_ID)
        title = self.list.GetItemText(self.downloadIdx,
                                      MainWindow.COLUMN_TITLE)
        self.duokan.rename(id, title)

        # start next
        self.downloadIdx += 1
        self.startDownload()

        if self.downloadIdx >= self.list.GetItemCount():
            if self.menubar.IsChecked(MainWindow.ID_MENUITEM_SHUTDOWN):
                os.system('shutdown -t 60 -f -s')

    # for downloader
    def cbLog(self, event, str):
        wx.CallAfter(self.addLog, str)
        print str

    # for downloader
    def cbProgress(self, event, prog):
        # itemCount = self.list.GetItemCount()
        # wx.CallAfter(self.setProgress, self.downloadIdx, prog)
        wx.CallAfter(self.gauge.SetValue, prog)

    # for duoSpider
    def cbAddUrl(self, event, url):
        wx.CallAfter(self.setUrl, url)

    # for duoSpider
    def cbAddBook(self, event, id, title, author, link):
        notFreed = self.duokan.addBook(id, title, author, link)
        download = self.duokan.isDownload(id)
        wx.CallAfter(self.appendItem, id, title, author, link, (not notFreed),
                     download)