示例#1
0
	def on_about_item(self, event):
		""" Onselect action for 'About'
		"""
		
		dialog = AboutDialog(self.main_window)
		
		dialog.run()
示例#2
0
 def on_about_item_activate(self, widget):
     dialog = AboutDialog(
         "PyGWSvcCtl", 
         "A tool to remotely manage the services on a computer.\n Based on Jelmer Vernooij's original Samba-GTK",
         self.icon_pixbuf)
     dialog.run()
     dialog.hide()
示例#3
0
 def on_about_item_activate(self, widget):
     dialog = AboutDialog(
                          "Main", 
                          "A tool to display other utilities in a simple, unified window.",
                          None
                          )
     dialog.run()
     dialog.hide()
示例#4
0
 def on_about_item_activate(self, widget):
     dialog = AboutDialog(
                          "PyGWSAM", 
                          "A tool to manage accounts on a SAM server.\n Based on Jelmer Vernooij's original Samba-GTK",
                          self.icon_pixbuf
                          )
     dialog.run()
     dialog.hide()
示例#5
0
 def on_about_item_activate(self, widget):
     dialog = AboutDialog(
                          "PyGWCronTab", 
                          "A tool to remotely manage scheduled tasks.\n Based on Jelmer Vernooij's original Samba-GTK",
                          self.icon_pixbuf
                          )
     dialog.run()
     dialog.hide()
示例#6
0
 def on_about_menu_item_activate(self, menuitem, data=None):
     ''' Called when the user clicks the 'About' menu. We create a GtkAboutDialog. 
     This dialog will NOT be modal but will be on top of the main application window.'''
     if self.about_dialog:
         self.about_dialog.present()
         return
     about_dialog=AboutDialog(self)
     self.about_dialog = about_dialog
     about_dialog.show()
示例#7
0
 def init_variable(self):
     self._disk = LanZouCloud()
     self._config = "./config.pkl"
     self._folder_list = {}
     self._file_list = {}
     self._path_list = {}
     self._path_list_old = {}
     self._locs = {}
     self._parent_id = -1  # --> ..
     self._work_name = ""  # share disk rec, not use now
     self._work_id = -1  # disk folder id
     self._old_work_id = self._work_id  # 用于上传完成后判断是否需要更新disk界面
     self.load_settings()
     if os.name == 'nt':
         self._disk.set_rar_tool("./rar.exe")
     else:
         self._disk.set_rar_tool("/usr/bin/rar")
     # 登录器
     self.login_luncher = LoginLuncher(self._disk)
     self.login_luncher.code.connect(self.login_update_ui)
     # 下载器
     self.download_manager = DownloadManager(self._disk)
     self.download_manager.downloaders_msg.connect(self.show_status)
     self.download_manager.download_mgr_msg.connect(self.show_status)
     self.download_manager.finished.connect(
         lambda: self.show_status("所有下载任务已完成!", 7000))
     # 上传器,信号在登录更新界面设置
     self.upload_dialog = UploadDialog()
     self.upload_dialog.new_infos.connect(self.call_upload)
     # 文件描述更新器
     self.desc_fetcher = DescFetcher(self._disk)
     self.desc_fetcher.desc.connect(self.call_update_desc)
     # 设置 tab
     self.tabWidget.setCurrentIndex(0)
     self.tabWidget.removeTab(2)
     self.tabWidget.removeTab(1)
     self.disk_tab.setEnabled(False)
     self.rec_tab.setEnabled(False)
     # 状态栏
     self._msg_label = QLabel()
     self._msg_label.setObjectName("msg_label")
     self.statusbar.addWidget(self._msg_label)
     # 重命名、修改简介与新建文件夹对话框
     self.rename_dialog = RenameDialog()
     self.rename_dialog.out.connect(self.rename_set_desc_and_mkdir)
     # 菜单栏关于
     self.about_dialog = AboutDialog()
     self.about_dialog.set_values(self.__version__)
示例#8
0
 def about(self):
     dialog = AboutDialog(self)
     dialog.open()
示例#9
0
class MainWindow(QMainWindow, Ui_MainWindow):
    __version__ = 'v0.0.6'

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.init_variable()
        self.init_workers()
        self.init_menu()
        self.setWindowTitle("蓝奏云客户端 - {}".format(self.__version__))
        self.setWindowIcon(QIcon("./icon/lanzou-logo2.png"))

        self.set_window_at_center()
        self.init_extract_share_ui()
        self.init_disk_ui()
        self.call_login_luncher()

        self.create_left_menus()

        self.setObjectName("MainWindow")

        self.setStyleSheet(qssStyle)
        # self.disk_tab.setStyleSheet("* {background-color: rgba(255, 255, 255, 150);}")
        self.tabWidget.setStyleSheet("QTabBar{ background-color: #AEEEEE; }")

    def init_menu(self):
        self.login.triggered.connect(self.show_login_dialog)  # 登录
        self.login.setIcon(QIcon("./icon/login.ico"))
        self.login.setShortcut("Ctrl+L")
        self.toolbar.addAction(self.login)
        self.logout.triggered.connect(
            lambda: self.logout_worker.set_values(self._disk))  # 登出
        self.logout.setIcon(QIcon("./icon/logout.ico"))
        self.logout.setShortcut("Ctrl+Q")  # 登出快捷键
        self.download.setShortcut("Ctrl+J")  # 以下还未使用
        self.download.setIcon(QIcon("./icon/download.ico"))
        self.download.setEnabled(False)  # 暂时不用
        self.delete.setShortcut("Ctrl+D")
        self.delete.setIcon(QIcon("./icon/delete.ico"))
        self.delete.setEnabled(False)  # 暂时不用
        # self.how.setShortcut("Ctrl+H")
        self.how.setIcon(QIcon("./icon/help.ico"))
        self.how.triggered.connect(self.open_wiki_url)
        # self.about.setShortcut("Ctrl+O")
        self.about.setIcon(QIcon("./icon/about.ico"))
        self.about.triggered.connect(self.about_dialog.exec)
        self.upload.setIcon(QIcon("./icon/upload.ico"))
        self.upload.setShortcut("Ctrl+U")  # 上传快捷键

    def init_variable(self):
        self._disk = LanZouCloud()
        self._config = "./config.pkl"
        self._folder_list = {}
        self._file_list = {}
        self._path_list = {}
        self._path_list_old = {}
        self._locs = {}
        self._parent_id = -1  # --> ..
        self._work_name = ""  # share disk rec, not use now
        self._work_id = -1  # disk folder id
        self._old_work_id = self._work_id  # 用于上传完成后判断是否需要更新disk界面
        self.download_threads = 3  # 同时三个下载任务
        self.load_settings()
        if os.name == 'nt':
            self._disk.set_rar_tool("./rar.exe")
        else:
            self._disk.set_rar_tool("/usr/bin/rar")

    def init_workers(self):
        # 登录器
        self.login_luncher = LoginLuncher(self._disk)
        self.login_luncher.code.connect(self.login_update_ui)
        # 登出器
        self.logout_worker = LogoutWorker()
        self.logout_worker.successed.connect(self.call_logout_update_ui)
        # 下载器
        self.download_manager = DownloadManager()
        self.download_manager.downloaders_msg.connect(self.show_status)
        self.download_manager.download_mgr_msg.connect(self.show_status)
        self.download_manager.finished.connect(
            lambda: self.show_status("所有下载任务已完成!", 7000))
        # 获取更多信息,直链、下载次数等
        self.more_info_worker = GetMoreInfoWorker()
        self.more_info_worker.msg.connect(self.show_status)
        self.more_info_worker.infos.connect(self.show_info_dialog)
        # 登录文件列表更新器
        self.list_refresher = ListRefresher(self._disk)
        self.list_refresher.err_msg.connect(self.show_status)
        self.list_refresher.infos.connect(self.update_lists)
        # 获取所有文件夹fid,并移动
        self.all_folders_worker = GetAllFoldersWorker()
        self.all_folders_worker.msg.connect(self.show_status)
        self.all_folders_worker.infos.connect(self.show_move_file_dialog)
        self.all_folders_worker.moved.connect(
            lambda: self.list_refresher.set_values(self._work_id, False, True,
                                                   False))  # 更新文件列表
        # 重命名、修改简介、新建文件夹
        self.rename_mkdir_worker = RenameMkdirWorker()
        self.rename_mkdir_worker.msg.connect(self.show_status)
        self.rename_mkdir_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 设置文件(夹)提取码
        self.set_pwd_worker = SetPwdWorker()
        self.set_pwd_worker.msg.connect(self.show_status)
        self.set_pwd_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 删除文件(夹)
        self.remove_files_worker = RemoveFilesWorker(self._disk)
        self.remove_files_worker.msg.connect(self.show_status)  # 显示错误提示
        self.remove_files_worker.finished.connect(
            lambda: self.list_refresher.set_values(self._work_id))  # 更新界面
        # 上传器,信号在登录更新界面设置
        self.upload_dialog = UploadDialog()
        self.upload_dialog.new_infos.connect(self.call_upload)
        # 文件描述与提取码更新器
        self.desc_pwd_fetcher = DescPwdFetcher()
        self.desc_pwd_fetcher.desc.connect(self.call_update_desc_pwd)
        self.desc_pwd_fetcher.tasks.connect(
            self.call_download_manager_thread)  # 连接下载管理器线程
        # 设置 tab
        self.tabWidget.setCurrentIndex(0)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        # 状态栏
        self._msg_label = QLabel()
        self._msg_label.setObjectName("msg_label")
        self.statusbar.addWidget(self._msg_label)
        # 重命名、修改简介与新建文件夹对话框
        self.rename_dialog = RenameDialog()
        self.rename_dialog.out.connect(self.call_rename_mkdir_worker)
        # 修改设置 提取码对话框
        self.set_pwd_dialog = SetPwdDialog()
        self.set_pwd_dialog.new_infos.connect(self.set_passwd)
        # 菜单栏关于
        self.about_dialog = AboutDialog()
        self.about_dialog.set_values(self.__version__)

    def show_login_dialog(self):
        """显示登录对话框"""
        login_dialog = LoginDialog(self._config)
        login_dialog.clicked_ok.connect(self.call_login_luncher)
        login_dialog.setWindowModality(Qt.ApplicationModal)
        login_dialog.exec()

    def show_upload_dialog(self):
        """显示上传文件对话框"""
        self.upload_dialog.set_values(list(self._path_list.keys())[-1])
        self.upload_dialog.exec()

    def load_settings(self):
        try:
            with open(self._config, "rb") as _file:
                self.settings = load(_file)
        except Exception:
            dl_path = os.path.dirname(
                os.path.abspath(__file__)) + os.sep + "downloads"
            self.settings = {"user": "", "pwd": "", "path": dl_path}
            with open(self._config, "wb") as _file:
                dump(self.settings, _file)

    def call_download_manager_thread(self, tasks):
        self.download_manager.set_values(tasks, self.settings["path"],
                                         self.download_threads)
        self.download_manager.start()

    def call_downloader(self):
        tab_page = self.tabWidget.currentIndex()
        if tab_page == 0:
            listview = self.table_share
            model = self.model_share
        elif tab_page == 1:
            listview = self.table_disk
            model = self.model_disk
        else:
            return
        infos = []
        _indexes = listview.selectionModel().selection().indexes()
        for i in _indexes:  # 获取所选行号
            info = model.item(i.row(), 0).data()
            if info and info not in infos:
                infos.append(info)
        if not infos:
            return
        self.desc_pwd_fetcher.set_values(self._disk, infos, download=True)

    def call_logout_update_ui(self):
        """菜单栏、工具栏登出"""
        self.toolbar.removeAction(self.logout)
        self.tabWidget.setCurrentIndex(0)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.toolbar.removeAction(self.logout)  # 登出工具
        self.logout.setEnabled(False)
        self.toolbar.removeAction(self.upload)  # 上传文件工具栏
        self.upload.setEnabled(False)
        self.upload.triggered.disconnect(self.show_upload_dialog)

    def login_update_ui(self, success, msg, duration):
        """根据登录是否成功更新UI"""
        if success:
            self.show_status(msg, duration)
            self.tabWidget.insertTab(1, self.disk_tab, "我的蓝奏云")
            self.tabWidget.insertTab(2, self.rec_tab, "回收站")
            self.disk_tab.setEnabled(True)
            self.rec_tab.setEnabled(True)
            # 更新快捷键与工具栏
            self.toolbar.addAction(self.logout)  # 添加登出工具栏
            self.toolbar.addAction(self.upload)  # 添加上传文件工具栏
            # 菜单栏槽
            self.logout.setEnabled(True)
            self.upload.setEnabled(True)
            self.upload.triggered.connect(self.show_upload_dialog)
            # 设置当前显示 tab
            self.tabWidget.setCurrentIndex(1)
            QCoreApplication.processEvents()  # 重绘界面
            # 刷新文件列表
            self.list_refresher.set_values(self._work_id)
        else:
            self.show_status(msg, duration)
            self.tabWidget.setCurrentIndex(0)
            self.tabWidget.removeTab(2)
            self.tabWidget.removeTab(1)
            self.disk_tab.setEnabled(False)
            self.rec_tab.setEnabled(False)
            # 更新快捷键与工具栏
            self.toolbar.removeAction(self.logout)  # 登出工具栏
            self.toolbar.removeAction(self.upload)  # 上传文件工具栏
            self.logout.setEnabled(False)
            self.upload.setEnabled(False)

    def call_login_luncher(self):
        """登录网盘"""
        self.load_settings()
        self.logout_worker.set_values(self._disk, update_ui=False)
        self.toolbar.removeAction(self.logout)
        try:
            username = self.settings["user"]
            password = self.settings["pwd"]
            cookie = self.settings["cookie"]
            self.login_luncher.set_values(username, password, cookie)
            self.login_luncher.start()
        except Exception as exp:
            print(exp)
            pass

    def set_file_icon(self, name):
        suffix = name.split(".")[-1]
        ico_path = "./icon/{}.gif".format(suffix)
        if os.path.isfile(ico_path):
            return QIcon(ico_path)
        else:
            return QIcon("./icon/file.ico")

    def show_file_and_folder_lists(self):
        """显示文件和文件夹列表"""
        self.model_disk.removeRows(0, self.model_disk.rowCount())  # 清理旧的内容
        file_count = len(self._file_list.keys())
        folder_count = len(self._folder_list.keys())
        name_header = [
            "文件夹{}个".format(folder_count),
        ] if folder_count else []
        if file_count:
            name_header.append("文件{}个".format(file_count))
        self.model_disk.setHorizontalHeaderLabels(
            ["/".join(name_header), "大小", "时间"])
        folder_ico = QIcon("./icon/folder.gif")
        pwd_ico = QIcon("./icon/keys.ico")
        # infos: ID/None,文件名,大小,日期,下载次数(dl_count),提取码(pwd),描述(desc),|链接(share-url),直链
        if self._work_id != -1:
            _back = QStandardItem(folder_ico, "..")
            _back.setToolTip("双击返回上层文件夹,选中无效")
            self.model_disk.appendRow(
                [_back, QStandardItem(""),
                 QStandardItem("")])
        for infos in self._folder_list.values():  # 文件夹
            name = QStandardItem(folder_ico, infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico, "") if infos[5] else QStandardItem(
                "")  # 提取码+size
            self.model_disk.appendRow([name, size_, QStandardItem("")])
        for infos in self._file_list.values():  # 文件
            name = QStandardItem(self.set_file_icon(infos[1]), infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico,
                                  infos[2]) if infos[5] else QStandardItem(
                                      infos[2])  # 提取码+size
            self.model_disk.appendRow([name, size_, QStandardItem(infos[3])])
        for row in range(self.model_disk.rowCount()):  # 右对齐
            self.model_disk.item(row, 1).setTextAlignment(Qt.AlignRight
                                                          | Qt.AlignVCenter)
            self.model_disk.item(row, 2).setTextAlignment(Qt.AlignRight
                                                          | Qt.AlignVCenter)

    def update_lists(self, infos):
        if not infos:
            return
        if infos['r']['files']:
            self._file_list = infos['file_list']
        if infos['r']['folders']:
            self._folder_list = infos['folder_list']
        self._path_list = infos['path_list']

        current_folder = list(self._path_list.keys())[-1]
        self._work_id = self._path_list.get(current_folder, -1)
        if infos['r']['fid'] != -1:
            parent_folder_name = list(self._path_list.keys())[-2]
            self._parent_id = self._path_list.get(parent_folder_name, -1)
        self.show_file_and_folder_lists()
        if infos['r']['path']:
            self.show_full_path()

    def config_tableview(self, tab):
        if tab == "share":
            model = self.model_share
            table = self.table_share
        elif tab == "disk":
            model = self.model_disk
            table = self.table_disk

        model.setHorizontalHeaderLabels(["文件名", "大小", "时间"])
        table.setModel(model)
        # 是否显示网格线
        table.setShowGrid(False)
        # 禁止编辑表格
        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 隐藏水平表头
        table.verticalHeader().setVisible(False)
        # 设置表头可以自动排序
        table.setSortingEnabled(True)
        table.setMouseTracking(False)
        # 设置表头的背景色为绿色
        table.horizontalHeader().setStyleSheet(
            "QHeaderView::section{background:lightgray}")
        # 设置 不可选择单个单元格,只可选择一行。
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 设置第二三列的宽度
        table.horizontalHeader().resizeSection(1, 90)
        table.horizontalHeader().resizeSection(2, 80)
        # 设置第一列宽度自动调整,充满屏幕
        table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        table.setContextMenuPolicy(Qt.CustomContextMenu)  # 允许右键产生子菜单
        table.customContextMenuRequested.connect(self.generateMenu)  # 右键菜单

    def create_left_menus(self):
        self.left_menus = QMenu()
        self.left_menu_share_url = self.left_menus.addAction("外链分享地址等")
        self.left_menu_share_url.setIcon(QIcon("./icon/share.ico"))
        self.left_menu_rename_set_desc = self.left_menus.addAction("修改文件夹名与描述")
        self.left_menu_rename_set_desc.setIcon(QIcon("./icon/desc.ico"))
        self.left_menu_set_pwd = self.left_menus.addAction("设置访问密码")
        self.left_menu_set_pwd.setIcon(QIcon("./icon/password.ico"))
        self.left_menu_move = self.left_menus.addAction("移动(支持批量)")
        self.left_menu_move.setIcon(QIcon("./icon/move.ico"))

    def call_rename_mkdir_worker(self, infos):
        """重命名、修改简介与新建文件夹"""
        self.rename_mkdir_worker.set_values(self._disk, infos, self._work_id)

    def set_passwd(self, infos):
        """设置文件(夹)提取码"""
        self.set_pwd_worker.set_values(self._disk, infos, self._work_id)

    def call_mkdir(self):
        """弹出新建文件夹对话框"""
        self.rename_dialog.set_values(None)
        self.rename_dialog.exec()

    def call_remove_files(self):
        indexs = []
        infos = []
        _indexs = self.table_disk.selectionModel().selection().indexes()
        if not _indexs:
            return
        for i in _indexs:  # 获取所选行号
            indexs.append(i.row())
        indexs = set(indexs)
        for index in indexs:
            info = self.model_disk.item(index, 0).data()  # 用于提示删除的文件名
            if info:
                infos.append(info[:3])
        delete_dialog = DeleteDialog(infos)
        delete_dialog.new_infos.connect(self.remove_files_worker.set_values)
        delete_dialog.exec()

    def generateMenu(self, pos):
        """右键菜单"""
        row_nums = self.sender().selectionModel().selection().indexes()
        if not row_nums:  # 如果没有选中行,什么也不做
            return
        _model = self.sender().model()
        infos = []  # 多个选中的行,用于移动文件与...
        for one_row in row_nums:
            one_row_data = _model.item(one_row.row(), 0).data()
            if one_row_data and one_row_data not in infos:  # 删掉 .. 行
                infos.append(one_row_data)
        if not infos:
            return
        info = infos[0]  # 取选中的第一行
        # 通过是否有文件 ID 判断是登录界面还是提取界面
        if info[0]:
            self.left_menu_rename_set_desc.setEnabled(True)
            self.left_menu_set_pwd.setEnabled(True)
            # 通过infos第3个字段 size 判断是否为文件夹,文件夹不能移动,设置不同的显示菜单名
            if info[2]:
                self.left_menu_rename_set_desc.setText("修改文件描述")
                self.left_menu_move.setEnabled(True)
            else:
                self.left_menu_rename_set_desc.setText("修改文件夹名与描述")
                self.left_menu_move.setDisabled(True)
        else:
            self.left_menu_rename_set_desc.setDisabled(True)
            self.left_menu_move.setDisabled(True)
            self.left_menu_set_pwd.setDisabled(True)

        action = self.left_menus.exec_(self.sender().mapToGlobal(pos))
        if action == self.left_menu_share_url:  # 显示详细信息
            # 后台跟新信息,并显示信息对话框
            self.more_info_worker.set_values(info, self._disk)
        elif action == self.left_menu_move:  # 移动文件
            self.all_folders_worker.set_values(self._disk, infos)
        elif action == self.left_menu_set_pwd:  # 修改提取码
            self.desc_pwd_fetcher.set_values(self._disk, [
                info,
            ])  # 兼容下载器,使用列表的列表
            self.set_pwd_dialog.set_values(info)
            self.set_pwd_dialog.exec()
        elif action == self.left_menu_rename_set_desc:  # 重命名与修改描述
            self.desc_pwd_fetcher.set_values(self._disk, [
                info,
            ])  # 兼容下载器,使用列表的列表
            self.rename_dialog.set_values(info)
            self.rename_dialog.exec()

    def call_update_desc_pwd(self, desc, pwd, infos):
        '''更新 desc、pwd'''
        infos[6] = desc
        infos[5] = pwd
        self.rename_dialog.set_values(infos)
        self.set_pwd_dialog.set_values(infos)

    def show_move_file_dialog(self, infos, all_dirs_dict):
        '''显示移动文件对话框'''
        move_file_dialog = MoveFileDialog(infos, all_dirs_dict)
        move_file_dialog.new_infos.connect(
            self.all_folders_worker.move_file)  # 调用移动线程
        move_file_dialog.exec()

    def show_info_dialog(self, infos):
        '''显示更多信息对话框'''
        info_dialog = InfoDialog(infos)
        info_dialog.setWindowModality(Qt.ApplicationModal)  # 窗口前置
        info_dialog.exec()

    def call_change_dir(self, folder_id=-1):
        """按钮调用"""
        def callfunc():
            self.list_refresher.set_values(folder_id)

        return callfunc

    def change_dir(self, dir_name):
        """双击切换工作目录"""
        dir_name = self.model_disk.item(dir_name.row(), 0).text()  # 文件夹名
        if dir_name == "..":  # 返回上级路径
            self.list_refresher.set_values(self._parent_id)
        elif dir_name in self._folder_list.keys():
            folder_id = self._folder_list[dir_name][0]
            self.list_refresher.set_values(folder_id)

    def call_upload(self, infos):
        """上传文件(夹)"""
        self._old_work_id = self._work_id  # 记录上传文件夹id
        self.upload_worker.set_values(self._disk, infos, self._old_work_id)
        self.upload_worker.start()

    def show_full_path(self):
        """路径框显示当前路径"""
        index = 1
        for name in self._path_list_old.items():
            self._locs[index].clicked.disconnect()
            self.disk_loc.removeWidget(self._locs[index])
            self._locs[index].deleteLater()
            self._locs[index] = None
            del self._locs[index]
            index += 1
        index = 1
        for name, fid in self._path_list.items():
            self._locs[index] = QPushButton(name, self.disk_tab)
            self._locs[index].setIcon(QIcon("./icon/folder.gif"))
            self._locs[index].setStyleSheet(
                "QPushButton {border: none; background:transparent;}")
            self.disk_loc.insertWidget(index, self._locs[index])
            self._locs[index].clicked.connect(self.call_change_dir(fid))
            index += 1
        self._path_list_old = self._path_list

    def select_all_btn(self, action="reverse"):
        """默认反转按钮状态"""
        page = self.tabWidget.currentIndex()
        if page == 0:
            btn = self.btn_share_select_all
            table = self.table_share
        elif page == 1:
            btn = self.btn_disk_select_all
            table = self.table_disk
        elif page == 2:
            return
        else:
            return
        if btn.isEnabled():
            if action == "reverse":
                if btn.text() == "全选":
                    table.selectAll()
                    btn.setText("取消")
                    btn.setIcon(QIcon("./icon/select-none.ico"))
                elif btn.text() == "取消":
                    table.clearSelection()
                    btn.setText("全选")
                    btn.setIcon(QIcon("./icon/select-all.ico"))
            elif action == "cancel":  # 点击列表其中一个就表示放弃全选
                btn.setText("全选")
                btn.setIcon(QIcon("./icon/select-all.ico"))
            else:
                table.selectAll()
                btn.setText("取消")
                btn.setIcon(QIcon("./icon/select-none.ico"))

    def finished_upload(self):
        """上传完成调用"""
        if self._old_work_id == self._work_id:
            self.list_refresher.set_values(self._work_id, True, True, False)
        else:
            self._old_work_id = self._work_id
        self.show_status("上传完成!", 7000)

    def init_disk_ui(self):
        self.model_disk = QStandardItemModel(1, 3)
        self.config_tableview("disk")
        self.btn_disk_delete.setIcon(QIcon("./icon/delete.ico"))
        self.btn_disk_dl.setIcon(QIcon("./icon/downloader.ico"))
        self.btn_disk_select_all.setIcon(QIcon("./icon/select-all.ico"))
        self.btn_disk_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
        self.btn_disk_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_disk.clicked.connect(lambda: self.select_all_btn("cancel"))
        self.btn_disk_dl.clicked.connect(self.call_downloader)
        self.btn_disk_mkdir.setIcon(QIcon("./icon/add-folder.ico"))
        self.btn_disk_mkdir.clicked.connect(self.call_mkdir)
        self.btn_disk_delete.clicked.connect(self.call_remove_files)

        self.table_disk.doubleClicked.connect(self.change_dir)
        # 上传器
        self.upload_worker = UploadWorker()
        self.upload_worker.finished.connect(self.finished_upload)
        self.upload_worker.code.connect(self.show_status)

    def show_status(self, msg, duration=0):
        self._msg_label.setText(msg)
        # self.statusbar.showMessage(msg, duration)
        # QCoreApplication.processEvents()  # 重绘界面,在弱网络情况导致程序闪退
        if duration != 0:
            QTimer.singleShot(duration, lambda: self._msg_label.setText(""))

    # shared url
    def call_get_shared_info(self):
        if not self.get_shared_info_thread.isRunning():  # 防止快速多次调用
            self.line_share_url.setEnabled(False)
            self.btn_extract.setEnabled(False)
            text = self.line_share_url.text().strip()
            self.get_shared_info_thread.set_values(text)

    def show_share_url_file_lists(self, infos):
        if infos["code"] == LanZouCloud.SUCCESS:
            file_count = len(infos["info"].keys())
            self.model_share.setHorizontalHeaderLabels(
                ["文件{}个".format(file_count), "大小", "时间"])
            for infos in infos["info"].values():
                name = QStandardItem(self.set_file_icon(infos[1]), infos[1])
                name.setData(infos)
                self.model_share.appendRow(
                    [name,
                     QStandardItem(infos[2]),
                     QStandardItem(infos[3])])
            for r in range(self.model_share.rowCount()):  # 右对齐
                self.model_share.item(r, 1).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
                self.model_share.item(r, 2).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
            self.table_share.setDisabled(False)
            self.btn_share_select_all.setDisabled(False)
            self.btn_share_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
            self.btn_share_dl.setDisabled(False)
        else:
            self.btn_share_select_all.setDisabled(True)
            self.btn_share_select_all.setToolTip("")
            self.btn_share_dl.setDisabled(True)
            self.table_share.setDisabled(True)

    def set_download_path(self):
        """设置下载路径"""
        dl_path = QFileDialog.getExistingDirectory()
        dl_path = os.path.normpath(dl_path)  # windows backslash
        if dl_path == self.settings["path"]:
            return
        if dl_path == "":
            dl_path = os.path.dirname(
                os.path.abspath(__file__)) + os.sep + "downloads"
            up_info = {"path": dl_path}
        else:
            up_info = {"path": dl_path}
        update_settings(self._config, up_info)
        self.load_settings()
        self.line_dl_path.setText(self.settings["path"])

    def init_extract_share_ui(self):
        self.btn_share_select_all.setDisabled(True)
        self.btn_share_dl.setDisabled(True)
        self.table_share.setDisabled(True)
        self.model_share = QStandardItemModel(1, 3)
        self.config_tableview("share")
        # 获取分享链接信息线程
        self.get_shared_info_thread = GetSharedInfo()
        self.get_shared_info_thread.update.connect(
            lambda: self.model_share.removeRows(0, self.model_share.rowCount()
                                                ))  # 清理旧的信息
        self.get_shared_info_thread.msg.connect(self.show_status)  # 提示信息
        self.get_shared_info_thread.infos.connect(
            self.show_share_url_file_lists)  # 内容信息
        self.get_shared_info_thread.finished.connect(
            lambda: self.btn_extract.setEnabled(True))
        self.get_shared_info_thread.finished.connect(
            lambda: self.line_share_url.setEnabled(True))
        # 控件设置
        self.line_share_url.setPlaceholderText(
            "蓝奏云链接,如有提取码,放后面,空格或汉字等分割,回车键提取")
        self.line_share_url.returnPressed.connect(self.call_get_shared_info)
        self.btn_extract.clicked.connect(self.call_get_shared_info)
        self.btn_share_dl.clicked.connect(self.call_downloader)
        self.btn_share_dl.setIcon(QIcon("./icon/downloader.ico"))
        self.btn_share_select_all.setIcon(QIcon("./icon/select-all.ico"))
        self.btn_share_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_share.clicked.connect(
            lambda: self.select_all_btn("cancel"))  # 全选按钮

        # 添加文件下载路径选择器
        self.line_dl_path = MyLineEdit(self.share_tab)
        self.line_dl_path.setObjectName("line_dl_path")
        self.horizontalLayout_share_2.insertWidget(2, self.line_dl_path)
        self.line_dl_path.setText(self.settings["path"])
        self.line_dl_path.clicked.connect(self.set_download_path)

        # QSS
        self.label_share_url.setStyleSheet(
            "#label_share_url {color: rgb(255,255,60);}")
        self.label_dl_path.setStyleSheet(
            "#label_dl_path {color: rgb(255,255,60);}")

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_A:  # Ctrl/Alt + A 全选
            if e.modifiers() and Qt.ControlModifier:
                self.select_all_btn()

    def set_window_at_center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        new_left = int((screen.width() - size.width()) / 2)
        new_top = int((screen.height() - size.height()) / 2)
        self.move(new_left, new_top)

    def open_wiki_url(self):
        # 打开使用说明页面
        url = QUrl('https://github.com/rachpt/lanzou-gui/wiki')
        if not QDesktopServices.openUrl(url):
            self.show_status('Could not open wiki page!', 5000)
示例#10
0
 def init_workers(self):
     # 登录器
     self.login_luncher = LoginLuncher(self._disk)
     self.login_luncher.code.connect(self.login_update_ui)
     # 登出器
     self.logout_worker = LogoutWorker()
     self.logout_worker.successed.connect(self.call_logout_update_ui)
     # 下载器
     self.download_manager = DownloadManager()
     self.download_manager.downloaders_msg.connect(self.show_status)
     self.download_manager.download_mgr_msg.connect(self.show_status)
     self.download_manager.finished.connect(
         lambda: self.show_status("所有下载任务已完成!", 7000))
     # 获取更多信息,直链、下载次数等
     self.more_info_worker = GetMoreInfoWorker()
     self.more_info_worker.msg.connect(self.show_status)
     self.more_info_worker.infos.connect(self.show_info_dialog)
     # 登录文件列表更新器
     self.list_refresher = ListRefresher(self._disk)
     self.list_refresher.err_msg.connect(self.show_status)
     self.list_refresher.infos.connect(self.update_lists)
     # 获取所有文件夹fid,并移动
     self.all_folders_worker = GetAllFoldersWorker()
     self.all_folders_worker.msg.connect(self.show_status)
     self.all_folders_worker.infos.connect(self.show_move_file_dialog)
     self.all_folders_worker.moved.connect(
         lambda: self.list_refresher.set_values(self._work_id, False, True,
                                                False))  # 更新文件列表
     # 重命名、修改简介、新建文件夹
     self.rename_mkdir_worker = RenameMkdirWorker()
     self.rename_mkdir_worker.msg.connect(self.show_status)
     self.rename_mkdir_worker.update.connect(
         self.list_refresher.set_values)  # 更新界面
     # 设置文件(夹)提取码
     self.set_pwd_worker = SetPwdWorker()
     self.set_pwd_worker.msg.connect(self.show_status)
     self.set_pwd_worker.update.connect(
         self.list_refresher.set_values)  # 更新界面
     # 删除文件(夹)
     self.remove_files_worker = RemoveFilesWorker(self._disk)
     self.remove_files_worker.msg.connect(self.show_status)  # 显示错误提示
     self.remove_files_worker.finished.connect(
         lambda: self.list_refresher.set_values(self._work_id))  # 更新界面
     # 上传器,信号在登录更新界面设置
     self.upload_dialog = UploadDialog()
     self.upload_dialog.new_infos.connect(self.call_upload)
     # 文件描述与提取码更新器
     self.desc_pwd_fetcher = DescPwdFetcher()
     self.desc_pwd_fetcher.desc.connect(self.call_update_desc_pwd)
     self.desc_pwd_fetcher.tasks.connect(
         self.call_download_manager_thread)  # 连接下载管理器线程
     # 设置 tab
     self.tabWidget.setCurrentIndex(0)
     self.tabWidget.removeTab(2)
     self.tabWidget.removeTab(1)
     self.disk_tab.setEnabled(False)
     self.rec_tab.setEnabled(False)
     # 状态栏
     self._msg_label = QLabel()
     self._msg_label.setObjectName("msg_label")
     self.statusbar.addWidget(self._msg_label)
     # 重命名、修改简介与新建文件夹对话框
     self.rename_dialog = RenameDialog()
     self.rename_dialog.out.connect(self.call_rename_mkdir_worker)
     # 修改设置 提取码对话框
     self.set_pwd_dialog = SetPwdDialog()
     self.set_pwd_dialog.new_infos.connect(self.set_passwd)
     # 菜单栏关于
     self.about_dialog = AboutDialog()
     self.about_dialog.set_values(self.__version__)
示例#11
0
class MainWindow(QMainWindow, Ui_MainWindow):
    __version__ = 'v0.1.0'
    if not os.path.isdir("./src") or not os.path.isfile("./src/file.ico"):
        from src import release_src

        os.makedirs("./src", exist_ok=True)
        release_src()

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.init_default_settings()
        self.init_variables()
        self.init_workers()
        self.init_menu()
        self.setWindowTitle("蓝奏云客户端 - {}".format(self.__version__))

        self.set_window_at_center()
        self.init_extract_share_ui()
        self.init_disk_ui()
        self.init_rec_ui()
        self.call_login_luncher()
        self.create_left_menus()

        self.setStyleSheet(qssStyle)
        self.tabWidget.setStyleSheet("QTabBar{ background-color: #AEEEEE; }")
        self.check_update_worker.set_values(self.__version__, False)  # 检测新版

        # 系统托盘
        self.tray = QSystemTrayIcon(QIcon('src/lanzou_logo2.png'), parent=self)
        show_action = QAction("显示窗口", self)
        hide_action = QAction("最小化到托盘", self)
        quit_action = QAction("退出程序", self)
        show_action.triggered.connect(self.show)
        hide_action.triggered.connect(self.hide)
        quit_action.triggered.connect(qApp.quit)
        show_action.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
        hide_action.setIcon(self.style().standardIcon(
            QStyle.SP_TitleBarMinButton))
        quit_action.setIcon(self.style().standardIcon(
            QStyle.SP_TitleBarCloseButton))
        self.tray.activated.connect(self.show)  #托盘点击事件
        tray_menu = QMenu(QApplication.desktop())
        tray_menu.addAction(show_action)
        tray_menu.addAction(hide_action)
        tray_menu.addAction(quit_action)
        self.tray.setContextMenu(tray_menu)
        self.tray.show()

    def init_menu(self):
        self.login.triggered.connect(self.show_login_dialog)  # 登录
        self.login.setIcon(QIcon("./src/login.ico"))
        self.login.setShortcut("Ctrl+L")
        self.toolbar.addAction(self.login)
        self.logout.triggered.connect(
            lambda: self.logout_worker.set_values(self._disk))  # 登出
        self.logout.setIcon(QIcon("./src/logout.ico"))
        self.logout.setShortcut("Ctrl+Q")  # 登出快捷键
        self.download.setShortcut("Ctrl+J")
        self.download.setIcon(QIcon("./src/download.ico"))
        self.download.setEnabled(False)  # 暂时不用
        self.delete.setShortcut("Ctrl+D")
        self.delete.setIcon(QIcon("./src/delete.ico"))
        self.delete.setEnabled(False)  # 暂时不用
        self.how.setShortcut("F1")
        self.how.setIcon(QIcon("./src/help.ico"))
        self.how.triggered.connect(self.open_wiki_url)
        self.about.setShortcut("Ctrl+B")
        self.about.setIcon(QIcon("./src/about.ico"))
        self.about.triggered.connect(self.about_dialog.exec)
        self.upload.setIcon(QIcon("./src/upload.ico"))
        self.upload.setShortcut("Ctrl+U")  # 上传快捷键
        # 添加设置菜单,暂时放这里
        self.setting_menu = QAction(self)  # 设置菜单
        self.setting_menu.setObjectName("setting_menu")
        self.setting_menu.setText("设置")
        self.files.addAction(self.setting_menu)
        self.setting_menu.setIcon(QIcon("./src/settings.ico"))
        self.setting_menu.triggered.connect(self.setting_dialog.open_dialog)
        self.setting_menu.setShortcut("Ctrl+P")  # 设置快捷键
        # tab 切换时更新
        self.tabWidget.currentChanged.connect(self.call_change_tab)

    def init_default_settings(self):
        """初始化默认设置"""
        download_threads = 3  # 同时三个下载任务
        max_size = 100  # 单个文件大小上限 MB
        timeout = 5  # 每个请求的超时 s(不包含下载响应体的用时)
        time_fmt = False  # 是否使用年月日时间格式
        to_tray = False  # 关闭到系统托盘
        dl_path = os.path.dirname(
            os.path.abspath(__file__)) + os.sep + "downloads"
        self._default_settings = {
            "download_threads": download_threads,
            "max_size": max_size,
            "to_tray": to_tray,
            "dl_path": dl_path,
            "timeout": timeout,
            "time_fmt": time_fmt
        }

    def init_variables(self):
        self._disk = LanZouCloud()
        self._config_file = "./config.pkl"
        self._folder_list = {}
        self._file_list = {}
        self._path_list = FolderList()
        self._path_list_old = FolderList()
        self._locs = {}
        self._parent_id = -1  # --> ..
        self._work_name = ""  # share disk rec, not use now
        self._work_id = -1  # disk folder id
        self._old_work_id = self._work_id  # 用于上传完成后判断是否需要更新disk界面
        self.load_settings()

    def update_lanzoucloud_settings(self):
        """更新LanzouCloud实例设置"""
        self._disk.set_timeout(self.configs["settings"]["timeout"])
        self._disk.set_max_size(self.configs["settings"]["max_size"])
        self.download_threads = self.configs["settings"]["download_threads"]
        self.time_fmt = self.configs["settings"]["time_fmt"]  # 时间显示格式
        self.to_tray = self.configs["settings"][
            "to_tray"] if "to_tray" in self.configs["settings"] else False

    def init_workers(self):
        # 登录器
        self.login_luncher = LoginLuncher(self._disk)
        self.login_luncher.code.connect(self.login_update_ui)
        self.login_luncher.update_cookie.connect(self.call_update_cookie)
        # 登出器
        self.logout_worker = LogoutWorker()
        self.logout_worker.successed.connect(self.call_logout_update_ui)
        # 下载器
        self.download_manager = DownloadManager()
        self.download_manager.downloaders_msg.connect(self.show_status)
        self.download_manager.download_mgr_msg.connect(self.show_status)
        self.download_manager.finished.connect(
            lambda: self.show_status("所有下载任务已完成!", 2999))
        # 获取更多信息,直链、下载次数等
        self.info_dialog = InfoDialog()  # 对话框
        self.info_dialog.setWindowModality(Qt.ApplicationModal)  # 窗口前置
        self.more_info_worker = GetMoreInfoWorker()  # 后台更新线程
        self.more_info_worker.msg.connect(self.show_status)
        self.more_info_worker.infos.connect(self.info_dialog.set_values)
        self.more_info_worker.dl_link.connect(
            self.info_dialog.tx_dl_link.setText)
        self.info_dialog.get_dl_link.connect(self.more_info_worker.get_dl_link)
        # 登录文件列表更新器
        self.list_refresher = ListRefresher(self._disk)
        self.list_refresher.err_msg.connect(self.show_status)
        self.list_refresher.infos.connect(self.update_disk_lists)
        self.list_refresher.infos.connect(lambda: self.show_status(""))
        # 获取所有文件夹fid,并移动
        self.all_folders_worker = GetAllFoldersWorker()
        self.all_folders_worker.msg.connect(self.show_status)
        self.all_folders_worker.infos.connect(self.show_move_file_dialog)
        self.all_folders_worker.moved.connect(
            lambda: self.list_refresher.set_values(self._work_id, True, False,
                                                   False))  # 更新文件列表
        # 重命名、修改简介、新建文件夹
        self.rename_mkdir_worker = RenameMkdirWorker()
        self.rename_mkdir_worker.msg.connect(self.show_status)
        self.rename_mkdir_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 设置文件(夹)提取码
        self.set_pwd_worker = SetPwdWorker()
        self.set_pwd_worker.msg.connect(self.show_status)
        self.set_pwd_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 删除文件(夹)
        self.remove_files_worker = RemoveFilesWorker(self._disk)
        self.remove_files_worker.msg.connect(self.show_status)  # 显示错误提示
        self.remove_files_worker.finished.connect(
            lambda: self.list_refresher.set_values(self._work_id))  # 更新界面
        # 上传器,信号在登录更新界面设置
        self.upload_dialog = UploadDialog()
        self.upload_dialog.new_infos.connect(self.call_upload)
        # 文件描述与提取码更新器
        self.desc_pwd_fetcher = DescPwdFetcher()
        self.desc_pwd_fetcher.desc.connect(self.call_update_desc_pwd)
        self.desc_pwd_fetcher.tasks.connect(
            self.call_download_manager_thread)  # 连接下载管理器线程
        # 设置 tab
        self.tabWidget.setCurrentIndex(0)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        # 状态栏
        self._msg_label = QLabel()
        self._msg_movie_lb = QLabel()
        self._msg_movie = QMovie("src/loading_more.gif")
        self._msg_movie.setScaledSize(QSize(24, 24))
        self._msg_movie_lb.setMovie(self._msg_movie)
        self._msg_label.setObjectName("msg_label")
        self._msg_movie_lb.setObjectName("msg_movie_lb")
        self.statusbar.addWidget(self._msg_movie_lb)
        self.statusbar.addWidget(self._msg_label)
        # 重命名、修改简介与新建文件夹对话框
        self.rename_dialog = RenameDialog()
        self.rename_dialog.out.connect(self.call_rename_mkdir_worker)
        # 修改设置 提取码对话框
        self.set_pwd_dialog = SetPwdDialog()
        self.set_pwd_dialog.new_infos.connect(self.set_passwd)
        # 菜单栏关于
        self.about_dialog = AboutDialog()
        self.about_dialog.set_values(self.__version__)

        # 菜单栏设置
        self.setting_dialog = SettingDialog(self._config_file,
                                            self._default_settings)
        self.setting_dialog.saved.connect(
            lambda: self.load_settings(ref_ui=True))
        # 登录回收站信息更新器
        self.get_rec_lists_worker = GetRecListsWorker(self._disk)
        self.get_rec_lists_worker.msg.connect(self.show_status)
        self.get_rec_lists_worker.infos.connect(self.update_rec_lists)
        self.get_rec_lists_worker.folders.connect(
            lambda: self.show_status('', 0))
        self.get_rec_lists_worker.folders.connect(
            self.pop_up_rec_folder_dialog)
        # 回收站操作器
        self.rec_manipulator = RecManipulator(self._disk)
        self.rec_manipulator.msg.connect(self.show_status)
        self.rec_manipulator.successed.connect(self.get_rec_lists_worker.start)
        # 检查软件版本
        self.check_update_worker = CheckUpdateWorker()
        self.about_dialog.check_update.connect(
            self.check_update_worker.set_values)
        self.check_update_worker.infos.connect(self.about_dialog.show_update)
        self.check_update_worker.bg_update_infos.connect(
            self.show_new_version_msg)

    def show_login_dialog(self):
        """显示登录对话框"""
        login_dialog = LoginDialog(self._config_file)
        login_dialog.clicked_ok.connect(self.call_login_luncher)
        login_dialog.setWindowModality(Qt.ApplicationModal)
        login_dialog.exec()

    def show_upload_dialog(self, files):
        """显示上传文件对话框"""
        if len(self._path_list) > 0:
            self.upload_dialog.set_values(self._path_list[-1].name, files)
        else:
            self.show_status("等待文件列表更新...", 2000)

    def show_upload_dialog_menus(self):
        '''菜单栏显示上传对话框槽函数'''
        self.show_upload_dialog(None)

    def load_settings(self, ref_ui=False):
        """加载用户设置"""
        try:
            with open(self._config_file, "rb") as _file:
                self.configs = load(_file)
        except:
            self.configs = {
                "user": "",
                "pwd": "",
                "cookie": "",
                "settings": self._default_settings
            }
            with open(self._config_file, "wb") as _file:
                dump(self.configs, _file)
        # 兼容以前的平配置文件
        if "settings" not in self.configs or not self.configs["settings"]:
            self.configs.update({"settings": self._default_settings})
            update_settings(self._config_file,
                            {"settings": self._default_settings})
        self.update_lanzoucloud_settings()
        if ref_ui and self.tabWidget.currentIndex() == 1:  # 更新文件界面的时间
            self.show_file_and_folder_lists()

    def call_download_manager_thread(self, tasks):
        self.download_manager.set_values(tasks,
                                         self.configs["settings"]["dl_path"],
                                         self.download_threads)
        self.download_manager.start()

    def call_multi_manipulator(self, action):
        """批量操作器"""
        tab_page = self.tabWidget.currentIndex()
        if tab_page == 0:
            listview = self.table_share
            model = self.model_share
        elif tab_page == 1:
            listview = self.table_disk
            model = self.model_disk
        elif tab_page == 2:
            listview = self.table_rec
            model = self.model_rec
        else:
            return
        infos = []
        _indexes = listview.selectionModel().selection().indexes()
        for i in _indexes:  # 获取所选行号
            info = model.item(i.row(), 0).data()
            if info and info not in infos:
                infos.append(info)

        if tab_page == 0 or tab_page == 1:
            if not infos:
                return
            self.desc_pwd_fetcher.set_values(self._disk, infos, download=True)
        elif tab_page == 2:
            if action == "recovery":
                title = "确定恢复选定文件(夹)?"
            elif action == "delete":
                title = "确定彻底删除选定文件(夹)?"
            elif action == "recovery_all":
                title = "确定还原全部文件(夹)?"
                msg = "提示: 恢复回收站中的文件将不可撤销,请确认。"
            elif action == "clean":
                title = "确定清除全部文件(夹)?"
                msg = "提示: 删除回收站中的文件将不可恢复,请确认。"
            if action == "recovery" or action == "delete":
                if not infos:
                    self.show_status("请先选中需要操作的文件!", 2999)
                    return
                msg = "\t\t列表:\n"
                for i in infos:
                    msg += f"{i.time}\t{i.name}\t{i.size}\n"
            message_box = QMessageBox(self)
            message_box.setStyleSheet(btn_style)
            message_box.setWindowTitle(title)
            message_box.setText(msg)
            message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            buttonY = message_box.button(QMessageBox.Yes)
            buttonY.setText('确定')
            buttonN = message_box.button(QMessageBox.No)
            buttonN.setText('取消')
            message_box.exec_()
            if message_box.clickedButton() == buttonY:
                self.rec_manipulator.set_values(infos, action)

    def call_logout_update_ui(self):
        """菜单栏、工具栏登出"""
        self.toolbar.removeAction(self.logout)
        self.tabWidget.setCurrentIndex(0)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.toolbar.removeAction(self.logout)  # 登出工具
        self.logout.setEnabled(False)
        self.toolbar.removeAction(self.upload)  # 上传文件工具栏
        self.upload.setEnabled(False)
        self.upload.triggered.disconnect(self.show_upload_dialog_menus)

    def login_update_ui(self, success, msg, duration):
        """根据登录是否成功更新UI"""
        if success:
            self.show_status(msg, duration)
            self.tabWidget.insertTab(1, self.disk_tab, "我的蓝奏云")
            self.tabWidget.insertTab(2, self.rec_tab, "回收站")
            self.disk_tab.setEnabled(True)
            self.rec_tab.setEnabled(True)
            # 更新快捷键与工具栏
            self.toolbar.addAction(self.logout)  # 添加登出工具栏
            self.toolbar.addAction(self.upload)  # 添加上传文件工具栏
            # 菜单栏槽
            self.logout.setEnabled(True)
            self.upload.setEnabled(True)
            self.upload.triggered.connect(self.show_upload_dialog_menus)
            # 设置当前显示 tab
            self.tabWidget.setCurrentIndex(1)
            QCoreApplication.processEvents()  # 重绘界面
            # 刷新文件列表
            # self.list_refresher.set_values(self._work_id)
        else:
            self.show_status(msg, duration)
            self.tabWidget.setCurrentIndex(0)
            self.tabWidget.removeTab(2)
            self.tabWidget.removeTab(1)
            self.disk_tab.setEnabled(False)
            self.rec_tab.setEnabled(False)
            # 更新快捷键与工具栏
            self.toolbar.removeAction(self.logout)  # 登出工具栏
            self.toolbar.removeAction(self.upload)  # 上传文件工具栏
            self.logout.setEnabled(False)
            self.upload.setEnabled(False)

    def call_login_luncher(self):
        """登录网盘"""
        self.load_settings()
        self.logout_worker.set_values(self._disk, update_ui=False)
        self.toolbar.removeAction(self.logout)
        try:
            username = self.configs["user"]
            password = self.configs["pwd"]
            cookie = self.configs["cookie"]
            self.login_luncher.set_values(username, password, cookie)
            self.login_luncher.start()
        except Exception as exp:
            print(exp)
            pass

    def call_update_cookie(self, cookie):
        """更新cookie至config文件"""
        up_info = {"cookie": cookie}
        update_settings(self._config_file, up_info)

    def show_file_and_folder_lists(self):
        """显示用户文件和文件夹列表"""
        self.model_disk.removeRows(0, self.model_disk.rowCount())  # 清理旧的内容
        file_count = len(self._file_list.keys())
        folder_count = len(self._folder_list.keys())
        name_header = [
            "文件夹{}个".format(folder_count),
        ] if folder_count else []
        if file_count:
            name_header.append("文件{}个".format(file_count))
        self.model_disk.setHorizontalHeaderLabels(
            ["/".join(name_header), "大小", "时间"])
        folder_ico = QIcon("./src/folder.gif")
        pwd_ico = QIcon("./src/keys.ico")
        # infos: ID/None,文件名,大小,日期,下载次数(dl_count),提取码(pwd),描述(desc),|链接(share-url),直链
        if self._work_id != -1:
            _back = QStandardItem(folder_ico, "..")
            _back.setToolTip("双击返回上层文件夹,选中无效")
            self.model_disk.appendRow(
                [_back, QStandardItem(""),
                 QStandardItem("")])
        for infos in self._folder_list.values():  # 文件夹
            name = QStandardItem(folder_ico, infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico, "") if infos[5] else QStandardItem(
                "")  # 提取码+size
            self.model_disk.appendRow([name, size_, QStandardItem("")])
        for infos in self._file_list.values():  # 文件
            name = QStandardItem(set_file_icon(infos[1]), infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico,
                                  infos[2]) if infos[5] else QStandardItem(
                                      infos[2])  # 提取码+size
            time_ = QStandardItem(time_format(
                infos[3])) if self.time_fmt else QStandardItem(infos[3])
            self.model_disk.appendRow([name, size_, time_])
        for row in range(self.model_disk.rowCount()):  # 右对齐
            self.model_disk.item(row, 1).setTextAlignment(Qt.AlignRight
                                                          | Qt.AlignVCenter)
            self.model_disk.item(row, 2).setTextAlignment(Qt.AlignRight
                                                          | Qt.AlignVCenter)

    def update_disk_lists(self, infos):
        """更新用户文件列表"""
        if not infos:
            return
        if infos['r']['files']:
            self._file_list = infos['file_list']
        if infos['r']['folders']:
            self._folder_list = infos['folder_list']
        self._path_list = infos['path_list']

        self._work_id = self._path_list[-1].id
        if infos['r']['fid'] != -1:
            self._parent_id = self._path_list[-2].id
        self.show_file_and_folder_lists()
        if infos['r']['path']:
            self.show_full_path()

    def config_tableview(self, tab):
        """Tab 初始化"""
        if tab == "share":
            model = self.model_share
            table = self.table_share
        elif tab == "disk":
            model = self.model_disk
            table = self.table_disk
        elif tab == "rec":
            model = self.model_rec
            table = self.table_rec

        model.setHorizontalHeaderLabels(["文件名", "大小", "时间"])
        table.setModel(model)
        # 是否显示网格线
        table.setShowGrid(False)
        # 禁止编辑表格
        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 隐藏水平表头
        table.verticalHeader().setVisible(False)
        # 设置表头可以自动排序
        table.setSortingEnabled(True)
        table.setMouseTracking(False)
        # 设置表头的背景色为绿色
        table.horizontalHeader().setStyleSheet(
            "QHeaderView::section{background:lightgray}")
        # 设置 不可选择单个单元格,只可选择一行。
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 设置第二三列的宽度
        table.horizontalHeader().resizeSection(1, 90)
        table.horizontalHeader().resizeSection(2, 80)
        # 设置第一列宽度自动调整,充满屏幕
        table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        if tab != "rec":
            table.setContextMenuPolicy(Qt.CustomContextMenu)  # 允许右键产生子菜单
            table.customContextMenuRequested.connect(self.generateMenu)  # 右键菜单

    def create_left_menus(self):
        self.left_menus = QMenu()
        self.left_menu_share_url = self.left_menus.addAction("外链分享地址等")
        self.left_menu_share_url.setIcon(QIcon("./src/share.ico"))
        self.left_menu_rename_set_desc = self.left_menus.addAction("修改文件夹名与描述")
        self.left_menu_rename_set_desc.setIcon(QIcon("./src/desc.ico"))
        self.left_menu_set_pwd = self.left_menus.addAction("设置访问密码")
        self.left_menu_set_pwd.setIcon(QIcon("./src/password.ico"))
        self.left_menu_move = self.left_menus.addAction("移动(支持批量)")
        self.left_menu_move.setIcon(QIcon("./src/move.ico"))

    def call_rename_mkdir_worker(self, infos):
        """重命名、修改简介与新建文件夹"""
        self.rename_mkdir_worker.set_values(self._disk, infos, self._work_id,
                                            self._folder_list)

    def set_passwd(self, infos):
        """设置文件(夹)提取码"""
        self.set_pwd_worker.set_values(self._disk, infos, self._work_id)

    def call_mkdir(self):
        """弹出新建文件夹对话框"""
        self.rename_dialog.set_values(None)
        self.rename_dialog.exec()

    def call_remove_files(self):
        indexs = []
        infos = []
        _indexs = self.table_disk.selectionModel().selection().indexes()
        if not _indexs:
            return
        for i in _indexs:  # 获取所选行号
            indexs.append(i.row())
        indexs = set(indexs)
        for index in indexs:
            info = self.model_disk.item(index, 0).data()  # 用于提示删除的文件名
            if info:
                infos.append(info[:3])
        delete_dialog = DeleteDialog(infos)
        delete_dialog.new_infos.connect(self.remove_files_worker.set_values)
        delete_dialog.exec()

    def generateMenu(self, pos):
        """右键菜单"""
        row_nums = self.sender().selectionModel().selection().indexes()
        if not row_nums:  # 如果没有选中行,什么也不做
            return
        _model = self.sender().model()
        infos = []  # 多个选中的行,用于移动文件与...
        for one_row in row_nums:
            one_row_data = _model.item(one_row.row(), 0).data()
            if one_row_data and one_row_data not in infos:  # 删掉 .. 行
                infos.append(one_row_data)
        if not infos:
            return
        info = infos[0]  # 取选中的第一行
        # 通过是否有文件 ID 判断是登录界面还是提取界面
        if info[0]:
            self.left_menu_rename_set_desc.setEnabled(True)
            self.left_menu_set_pwd.setEnabled(True)
            # 通过infos第3个字段 size 判断是否为文件夹,文件夹不能移动,设置不同的显示菜单名
            if info[2]:
                self.left_menu_rename_set_desc.setText("修改文件描述")
                self.left_menu_move.setEnabled(True)
            else:
                self.left_menu_rename_set_desc.setText("修改文件夹名与描述")
                self.left_menu_move.setDisabled(True)
        else:
            self.left_menu_rename_set_desc.setDisabled(True)
            self.left_menu_move.setDisabled(True)
            self.left_menu_set_pwd.setDisabled(True)

        action = self.left_menus.exec_(self.sender().mapToGlobal(pos))
        if action == self.left_menu_share_url:  # 显示详细信息
            # 后台跟新信息,并显示信息对话框
            self.more_info_worker.set_values(info, self._disk)
        elif action == self.left_menu_move:  # 移动文件
            self.all_folders_worker.set_values(self._disk, infos)
        elif action == self.left_menu_set_pwd:  # 修改提取码
            self.desc_pwd_fetcher.set_values(self._disk, [
                info,
            ])  # 兼容下载器,使用列表的列表
            self.set_pwd_dialog.set_values(info)
            self.set_pwd_dialog.exec()
        elif action == self.left_menu_rename_set_desc:  # 重命名与修改描述
            self.desc_pwd_fetcher.set_values(self._disk, [
                info,
            ])  # 兼容下载器,使用列表的列表
            self.rename_dialog.set_values(info)
            self.rename_dialog.exec()

    def call_update_desc_pwd(self, desc, pwd, infos):
        '''更新 desc、pwd'''
        infos[6] = desc
        infos[5] = pwd
        self.rename_dialog.set_values(infos)
        self.set_pwd_dialog.set_values(infos)

    def show_move_file_dialog(self, infos, all_dirs_dict):
        '''显示移动文件对话框'''
        move_file_dialog = MoveFileDialog(infos, all_dirs_dict)
        move_file_dialog.new_infos.connect(
            self.all_folders_worker.move_file)  # 调用移动线程
        move_file_dialog.exec()

    def call_change_dir(self, folder_id=-1):
        """顶部路径按钮调用"""
        def callfunc():
            self.list_refresher.set_values(folder_id)

        return callfunc

    def change_dir(self, dir_name):
        """双击切换工作目录"""
        dir_name = self.model_disk.item(dir_name.row(), 0).text()  # 文件夹名
        if dir_name == "..":  # 返回上级路径
            self.list_refresher.set_values(self._parent_id)
        elif dir_name in self._folder_list.keys():
            folder_id = self._folder_list[dir_name][0]
            self.list_refresher.set_values(folder_id)

    def call_upload(self, infos):
        """上传文件(夹)"""
        self._old_work_id = self._work_id  # 记录上传文件夹id
        self.upload_worker.set_values(self._disk, infos, self._old_work_id)
        self.upload_worker.start()

    def show_full_path(self):
        """路径框显示当前路径"""
        index = 1
        for _ in iter(self._path_list_old):
            self._locs[index].clicked.disconnect()
            self.disk_loc.removeWidget(self._locs[index])
            self._locs[index].deleteLater()
            self._locs[index] = None
            del self._locs[index]
            index += 1
        index = 1
        for item in iter(self._path_list):
            self._locs[index] = QPushButton(item.name, self.disk_tab)
            self._locs[index].setToolTip(f"fid:{item.id}")
            self._locs[index].setIcon(QIcon("./src/folder.gif"))
            self._locs[index].setStyleSheet(
                "QPushButton {border:none; background:transparent;}")
            self.disk_loc.insertWidget(index, self._locs[index])
            self._locs[index].clicked.connect(self.call_change_dir(item.id))
            index += 1
        self._path_list_old = self._path_list

    def select_all_btn(self, action="reverse"):
        """默认反转按钮状态"""
        page = self.tabWidget.currentIndex()
        if page == 0:
            btn = self.btn_share_select_all
            table = self.table_share
        elif page == 1:
            btn = self.btn_disk_select_all
            table = self.table_disk
        elif page == 2:
            btn = self.btn_rec_select_all
            table = self.table_rec
        else:
            return
        if btn.isEnabled():
            if action == "reverse":
                if btn.text() == "全选":
                    table.selectAll()
                    btn.setText("取消")
                    btn.setIcon(QIcon("./src/select_none.ico"))
                elif btn.text() == "取消":
                    table.clearSelection()
                    btn.setText("全选")
                    btn.setIcon(QIcon("./src/select_all.ico"))
            elif action == "cancel":  # 点击列表其中一个就表示放弃全选
                btn.setText("全选")
                btn.setIcon(QIcon("./src/select_all.ico"))
            else:
                table.selectAll()
                btn.setText("取消")
                btn.setIcon(QIcon("./src/select_none.ico"))

    def finished_upload(self):
        """上传完成调用"""
        if self._old_work_id == self._work_id:
            self.list_refresher.set_values(self._work_id, True, True, False)
        else:
            self._old_work_id = self._work_id
        self.show_status("上传完成!", 7000)

    # disk tab
    def init_disk_ui(self):
        self.model_disk = QStandardItemModel(1, 3)
        self.config_tableview("disk")
        self.btn_disk_delete.setIcon(QIcon("./src/delete.ico"))
        self.btn_disk_dl.setIcon(QIcon("./src/downloader.ico"))
        self.btn_disk_select_all.setIcon(QIcon("./src/select_all.ico"))
        self.btn_disk_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
        self.btn_disk_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_disk.clicked.connect(lambda: self.select_all_btn("cancel"))
        self.btn_disk_dl.clicked.connect(
            lambda: self.call_multi_manipulator("download"))
        self.btn_disk_mkdir.setIcon(QIcon("./src/add_folder.ico"))
        self.btn_disk_mkdir.clicked.connect(self.call_mkdir)
        self.btn_disk_delete.clicked.connect(self.call_remove_files)
        # 文件拖拽上传
        self.table_disk.drop_files.connect(self.show_upload_dialog)

        self.table_disk.doubleClicked.connect(self.change_dir)
        # 上传器
        self.upload_worker = UploadWorker()
        self.upload_worker.finished.connect(self.finished_upload)
        self.upload_worker.code.connect(self.show_status)

    # rec tab
    def pop_up_rec_folder_dialog(self, files):
        # 弹出回收站文件夹内容对话框
        if files:
            rec_file_dialog = RecFolderDialog(files)
            rec_file_dialog.exec()
        else:
            self.show_status("文件夹为空!", 2999)

    def call_rec_folder_dialog(self, dir_name):
        # 显示弹出对话框
        dir_data = self.model_rec.item(dir_name.row(), 0).data()  # 文件夹信息
        if isinstance(dir_data, RecFolder):
            self.show_status(f"正在获取文件夹 {dir_data.name} 信息,稍后", 10000)
            self.get_rec_lists_worker.set_values(dir_data.id)

    def update_rec_lists(self, dir_lists, file_lists):
        """显示回收站文件和文件夹列表"""
        self.model_rec.removeRows(0, self.model_rec.rowCount())  # 清理旧的内容
        file_count = len(file_lists)
        folder_count = len(dir_lists)
        if ((not dir_lists) and
            (not file_lists)) or (file_count == 0 and folder_count == 0):
            self.show_status("回收站为空!", 4000)
            return
        name_header = [
            "文件夹{}个".format(folder_count),
        ] if folder_count else []
        if file_count:
            name_header.append("文件{}个".format(file_count))
        self.model_rec.setHorizontalHeaderLabels(
            ["/".join(name_header), "大小", "时间"])
        folder_ico = QIcon("./src/folder.gif")

        for item in iter(dir_lists):  # 文件夹
            name = QStandardItem(folder_ico, item.name)
            name.setData(item)
            name.setToolTip("双击查看详情")
            size_ = QStandardItem(item.size)
            time_ = QStandardItem(item.time)
            self.model_rec.appendRow([name, size_, time_])
        for item in iter(file_lists):  # 文件
            name = QStandardItem(set_file_icon(item.name), item.name)
            name.setData(item)
            size_ = QStandardItem(item.size)
            time_ = QStandardItem(item.time)
            self.model_rec.appendRow([name, size_, time_])
        for row in range(self.model_rec.rowCount()):  # 右对齐
            self.model_rec.item(row, 1).setTextAlignment(Qt.AlignRight
                                                         | Qt.AlignVCenter)
            self.model_rec.item(row, 2).setTextAlignment(Qt.AlignRight
                                                         | Qt.AlignVCenter)

    def init_rec_ui(self):
        """回收站ui初始化"""
        self.model_rec = QStandardItemModel(1, 3)
        self.config_tableview("rec")
        self.table_rec.doubleClicked.connect(self.call_rec_folder_dialog)
        self.btn_rec_select_all.setIcon(QIcon("./src/select_all.ico"))
        self.btn_rec_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.btn_rec_delete.clicked.connect(
            lambda: self.call_multi_manipulator("delete"))
        self.btn_recovery.clicked.connect(
            lambda: self.call_multi_manipulator("recovery"))
        self.btn_rec_delete.setToolTip("彻底删除选中文件(夹)")
        self.btn_recovery.setToolTip("恢复选中文件(夹)")
        self.btn_recovery_all.clicked.connect(
            lambda: self.call_multi_manipulator("recovery_all"))
        self.btn_recovery_all.setToolTip("恢复全部")
        self.btn_rec_clean.clicked.connect(
            lambda: self.call_multi_manipulator("clean"))
        self.btn_rec_clean.setToolTip("清理回收站全部")

    # shared url
    def call_get_shared_info(self):
        if not self.get_shared_info_thread.isRunning():  # 防止快速多次调用
            self.line_share_url.setEnabled(False)
            self.btn_extract.setEnabled(False)
            text = self.line_share_url.text().strip()
            self.get_shared_info_thread.set_values(text)

    def show_share_url_file_lists(self, infos):
        if infos["code"] == LanZouCloud.SUCCESS:
            file_count = len(infos["info"].keys())
            self.model_share.setHorizontalHeaderLabels(
                ["文件{}个".format(file_count), "大小", "时间"])
            for infos in infos["info"].values():
                name = QStandardItem(set_file_icon(infos[1]), infos[1])
                name.setData(infos)
                time = QStandardItem(time_format(
                    infos[3])) if self.time_fmt else QStandardItem(infos[3])
                self.model_share.appendRow(
                    [name, QStandardItem(infos[2]), time])
            for r in range(self.model_share.rowCount()):  # 右对齐
                self.model_share.item(r, 1).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
                self.model_share.item(r, 2).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
            self.table_share.setDisabled(False)
            self.btn_share_select_all.setDisabled(False)
            self.btn_share_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
            self.btn_share_dl.setDisabled(False)
        else:
            self.btn_share_select_all.setDisabled(True)
            self.btn_share_select_all.setToolTip("")
            self.btn_share_dl.setDisabled(True)
            self.table_share.setDisabled(True)

    def set_download_path(self):
        """设置下载路径"""
        dl_path = QFileDialog.getExistingDirectory()
        dl_path = os.path.normpath(dl_path)  # windows backslash
        if dl_path == self.configs["settings"]["dl_path"] or dl_path == ".":
            return
        if dl_path == "":
            dl_path = os.path.dirname(
                os.path.abspath(__file__)) + os.sep + "downloads"
            up_info = {"dl_path": dl_path}
        else:
            up_info = {"dl_path": dl_path}
        update_settings(self._config_file, up_info, is_settings=True)
        self.load_settings()
        self.line_dl_path.setText(self.configs["settings"]["dl_path"])

    def init_extract_share_ui(self):
        self.btn_share_select_all.setDisabled(True)
        self.btn_share_dl.setDisabled(True)
        self.table_share.setDisabled(True)
        self.model_share = QStandardItemModel(1, 3)
        self.config_tableview("share")
        # 获取分享链接信息线程
        self.get_shared_info_thread = GetSharedInfo()
        self.get_shared_info_thread.update.connect(
            lambda: self.model_share.removeRows(0, self.model_share.rowCount()
                                                ))  # 清理旧的信息
        self.get_shared_info_thread.msg.connect(self.show_status)  # 提示信息
        self.get_shared_info_thread.infos.connect(
            self.show_share_url_file_lists)  # 内容信息
        self.get_shared_info_thread.finished.connect(
            lambda: self.btn_extract.setEnabled(True))
        self.get_shared_info_thread.finished.connect(
            lambda: self.line_share_url.setEnabled(True))
        # 控件设置
        self.line_share_url.setPlaceholderText(
            "蓝奏云链接,如有提取码,放后面,空格或汉字等分割,回车键提取")
        self.line_share_url.returnPressed.connect(self.call_get_shared_info)
        self.btn_extract.clicked.connect(self.call_get_shared_info)
        self.btn_share_dl.clicked.connect(
            lambda: self.call_multi_manipulator("download"))
        self.btn_share_dl.setIcon(QIcon("./src/downloader.ico"))
        self.btn_share_select_all.setIcon(QIcon("./src/select_all.ico"))
        self.btn_share_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_share.clicked.connect(
            lambda: self.select_all_btn("cancel"))  # 全选按钮

        # 添加文件下载路径选择器
        self.line_dl_path = MyLineEdit(self.share_tab)
        self.line_dl_path.setObjectName("line_dl_path")
        self.horizontalLayout_share_2.insertWidget(2, self.line_dl_path)
        self.line_dl_path.setText(self.configs["settings"]["dl_path"])
        self.line_dl_path.clicked.connect(self.set_download_path)

        # QSS
        self.label_share_url.setStyleSheet(
            "#label_share_url {color: rgb(255,255,60);}")
        self.label_dl_path.setStyleSheet(
            "#label_dl_path {color: rgb(255,255,60);}")

    # others
    def clean_status(self):
        self._msg_label.setText("")
        self._msg_movie_lb.clear()
        self._msg_movie.stop()

    def show_status(self, msg, duration=0):
        self._msg_label.setText(msg)
        if msg and duration >= 3000:
            self._msg_movie_lb.setMovie(self._msg_movie)
            self._msg_movie.start()
        else:
            self._msg_movie_lb.clear()
            self._msg_movie.stop()
        if duration != 0:
            QTimer.singleShot(duration, self.clean_status)

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_A:  # Ctrl/Alt + A 全选
            if e.modifiers() and Qt.ControlModifier:
                self.select_all_btn()
        elif e.key() == Qt.Key_F5:  # 刷新
            if self.tabWidget.currentIndex() == 1:  # disk 界面
                self.show_status("正在更新当前目录...", 10000)
                self.list_refresher.set_values(self._work_id)
            elif self.tabWidget.currentIndex() == 2:  # rec 界面
                self.show_status("正在更新回收站...", 10000)
                self.get_rec_lists_worker.start()

    def call_change_tab(self):
        """切换标签页 动作"""
        tab_index = self.tabWidget.currentIndex()
        if tab_index == 2:
            self.show_status("正在更新回收站...", 10000)
            self.get_rec_lists_worker.start()
        elif tab_index == 1:
            self.show_status("正在更新当前目录...", 10000)
            self.list_refresher.set_values(self._work_id)

    def set_window_at_center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        new_left = int((screen.width() - size.width()) / 2)
        new_top = int((screen.height() - size.height()) / 2)
        self.move(new_left, new_top)

    def open_wiki_url(self):
        # 打开使用说明页面
        url = QUrl('https://github.com/rachpt/lanzou-gui/wiki')
        if not QDesktopServices.openUrl(url):
            self.show_status('Could not open wiki page!', 5000)

    def show_new_version_msg(self, ver, msg):
        message_box = QMessageBox(self)
        message_box.setStyleSheet(btn_style)
        message_box.setWindowTitle(f"检测到新版 {ver}")
        message_box.setText(msg)
        message_box.setStandardButtons(QMessageBox.Close)
        buttonC = message_box.button(QMessageBox.Close)
        buttonC.setText('关闭')
        message_box.exec()

    def closeEvent(self, event):
        if self.to_tray:
            event.ignore()
            self.hide()
            self.tray.showMessage("蓝奏云客户端", "应用已经最小化到托盘,如需退出请右击",
                                  QSystemTrayIcon.Information, 2500)
示例#12
0
    def init_workers(self):
        # 登录器
        self.login_luncher = LoginLuncher(self._disk)
        self.login_luncher.code.connect(self.login_update_ui)
        self.login_luncher.update_cookie.connect(self.call_update_cookie)
        # 登出器
        self.logout_worker = LogoutWorker()
        self.logout_worker.successed.connect(self.call_logout_update_ui)
        # 下载器
        self.download_manager = DownloadManager()
        self.download_manager.downloaders_msg.connect(self.show_status)
        self.download_manager.download_mgr_msg.connect(self.show_status)
        self.download_manager.finished.connect(
            lambda: self.show_status("所有下载任务已完成!", 2999))
        # 获取更多信息,直链、下载次数等
        self.info_dialog = InfoDialog()  # 对话框
        self.info_dialog.setWindowModality(Qt.ApplicationModal)  # 窗口前置
        self.more_info_worker = GetMoreInfoWorker()  # 后台更新线程
        self.more_info_worker.msg.connect(self.show_status)
        self.more_info_worker.infos.connect(self.info_dialog.set_values)
        self.more_info_worker.dl_link.connect(
            self.info_dialog.tx_dl_link.setText)
        self.info_dialog.get_dl_link.connect(self.more_info_worker.get_dl_link)
        # 登录文件列表更新器
        self.list_refresher = ListRefresher(self._disk)
        self.list_refresher.err_msg.connect(self.show_status)
        self.list_refresher.infos.connect(self.update_disk_lists)
        self.list_refresher.infos.connect(lambda: self.show_status(""))
        # 获取所有文件夹fid,并移动
        self.all_folders_worker = GetAllFoldersWorker()
        self.all_folders_worker.msg.connect(self.show_status)
        self.all_folders_worker.infos.connect(self.show_move_file_dialog)
        self.all_folders_worker.moved.connect(
            lambda: self.list_refresher.set_values(self._work_id, True, False,
                                                   False))  # 更新文件列表
        # 重命名、修改简介、新建文件夹
        self.rename_mkdir_worker = RenameMkdirWorker()
        self.rename_mkdir_worker.msg.connect(self.show_status)
        self.rename_mkdir_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 设置文件(夹)提取码
        self.set_pwd_worker = SetPwdWorker()
        self.set_pwd_worker.msg.connect(self.show_status)
        self.set_pwd_worker.update.connect(
            self.list_refresher.set_values)  # 更新界面
        # 删除文件(夹)
        self.remove_files_worker = RemoveFilesWorker(self._disk)
        self.remove_files_worker.msg.connect(self.show_status)  # 显示错误提示
        self.remove_files_worker.finished.connect(
            lambda: self.list_refresher.set_values(self._work_id))  # 更新界面
        # 上传器,信号在登录更新界面设置
        self.upload_dialog = UploadDialog()
        self.upload_dialog.new_infos.connect(self.call_upload)
        # 文件描述与提取码更新器
        self.desc_pwd_fetcher = DescPwdFetcher()
        self.desc_pwd_fetcher.desc.connect(self.call_update_desc_pwd)
        self.desc_pwd_fetcher.tasks.connect(
            self.call_download_manager_thread)  # 连接下载管理器线程
        # 设置 tab
        self.tabWidget.setCurrentIndex(0)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        # 状态栏
        self._msg_label = QLabel()
        self._msg_movie_lb = QLabel()
        self._msg_movie = QMovie("src/loading_more.gif")
        self._msg_movie.setScaledSize(QSize(24, 24))
        self._msg_movie_lb.setMovie(self._msg_movie)
        self._msg_label.setObjectName("msg_label")
        self._msg_movie_lb.setObjectName("msg_movie_lb")
        self.statusbar.addWidget(self._msg_movie_lb)
        self.statusbar.addWidget(self._msg_label)
        # 重命名、修改简介与新建文件夹对话框
        self.rename_dialog = RenameDialog()
        self.rename_dialog.out.connect(self.call_rename_mkdir_worker)
        # 修改设置 提取码对话框
        self.set_pwd_dialog = SetPwdDialog()
        self.set_pwd_dialog.new_infos.connect(self.set_passwd)
        # 菜单栏关于
        self.about_dialog = AboutDialog()
        self.about_dialog.set_values(self.__version__)

        # 菜单栏设置
        self.setting_dialog = SettingDialog(self._config_file,
                                            self._default_settings)
        self.setting_dialog.saved.connect(
            lambda: self.load_settings(ref_ui=True))
        # 登录回收站信息更新器
        self.get_rec_lists_worker = GetRecListsWorker(self._disk)
        self.get_rec_lists_worker.msg.connect(self.show_status)
        self.get_rec_lists_worker.infos.connect(self.update_rec_lists)
        self.get_rec_lists_worker.folders.connect(
            lambda: self.show_status('', 0))
        self.get_rec_lists_worker.folders.connect(
            self.pop_up_rec_folder_dialog)
        # 回收站操作器
        self.rec_manipulator = RecManipulator(self._disk)
        self.rec_manipulator.msg.connect(self.show_status)
        self.rec_manipulator.successed.connect(self.get_rec_lists_worker.start)
        # 检查软件版本
        self.check_update_worker = CheckUpdateWorker()
        self.about_dialog.check_update.connect(
            self.check_update_worker.set_values)
        self.check_update_worker.infos.connect(self.about_dialog.show_update)
        self.check_update_worker.bg_update_infos.connect(
            self.show_new_version_msg)
示例#13
0
 def about(self, widget):
     if not self.aboutdialog:
         self.aboutdialog = AboutDialog(self.mainwin)
     self.aboutdialog.run()
示例#14
0
 def about(self):
     dialog = AboutDialog(self)
     dialog.open()
示例#15
0
 def _about(self):
     """Open about dialog.
     """
     about = AboutDialog(self.parent)    # Opens dialog near main window
     about.exec_()
     del about
示例#16
0
 def ShowAboutDialog(self):
     dialog = AboutDialog(self._view)
     dialog.Center()
     dialog.ShowModal()
     dialog.Destroy()
示例#17
0
class MainWindow(QMainWindow, Ui_MainWindow):
    __version__ = 'v0.0.5'

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.init_variable()
        self.init_menu()
        self.setWindowTitle("蓝奏云客户端 - {}".format(self.__version__))
        self.setWindowIcon(QIcon("./icon/lanzou-logo2.png"))

        self.set_window_at_center()
        self.init_extract_share_ui()
        self.init_disk_ui()
        self.call_login_luncher()

        self.create_left_menus()

        # print(QApplication.style().objectName())
        self.setObjectName("MainWindow")

        self.setStyleSheet(qssStyle)
        # self.disk_tab.setStyleSheet("* {background-color: rgba(255, 255, 255, 150);}")
        self.tabWidget.setStyleSheet("QTabBar{ background-color: #AEEEEE; }")

    def init_menu(self):
        self.login.triggered.connect(self.show_login_dialog)  # 登录
        self.login.setIcon(QIcon("./icon/login.ico"))
        self.login.setShortcut("Ctrl+L")
        self.toolbar.addAction(self.login)
        self.logout.triggered.connect(self.call_logout)  # 登出
        self.logout.setIcon(QIcon("./icon/logout.ico"))
        self.logout.setShortcut("Ctrl+Q")  # 登出快捷键
        self.download.setShortcut("Ctrl+J")  # 以下还未使用
        self.download.setIcon(QIcon("./icon/download.ico"))
        self.delete.setShortcut("Ctrl+D")
        self.delete.setIcon(QIcon("./icon/delete.ico"))
        # self.how.setShortcut("Ctrl+H")
        self.how.setIcon(QIcon("./icon/help.ico"))
        self.how.triggered.connect(self.open_wiki_url)
        # self.about.setShortcut("Ctrl+O")
        self.about.setIcon(QIcon("./icon/about.ico"))
        self.about.triggered.connect(self.about_dialog.exec)
        self.upload.setIcon(QIcon("./icon/upload.ico"))
        self.upload.setShortcut("Ctrl+U")  # 上传快捷键

    def init_variable(self):
        self._disk = LanZouCloud()
        self._config = "./config.pkl"
        self._folder_list = {}
        self._file_list = {}
        self._path_list = {}
        self._path_list_old = {}
        self._locs = {}
        self._parent_id = -1  # --> ..
        self._work_name = ""  # share disk rec, not use now
        self._work_id = -1  # disk folder id
        self._old_work_id = self._work_id  # 用于上传完成后判断是否需要更新disk界面
        self.load_settings()
        if os.name == 'nt':
            self._disk.set_rar_tool("./rar.exe")
        else:
            self._disk.set_rar_tool("/usr/bin/rar")
        # 登录器
        self.login_luncher = LoginLuncher(self._disk)
        self.login_luncher.code.connect(self.login_update_ui)
        # 下载器
        self.download_manager = DownloadManager(self._disk)
        self.download_manager.downloaders_msg.connect(self.show_status)
        self.download_manager.download_mgr_msg.connect(self.show_status)
        self.download_manager.finished.connect(
            lambda: self.show_status("所有下载任务已完成!", 7000))
        # 上传器,信号在登录更新界面设置
        self.upload_dialog = UploadDialog()
        self.upload_dialog.new_infos.connect(self.call_upload)
        # 文件描述更新器
        self.desc_fetcher = DescFetcher(self._disk)
        self.desc_fetcher.desc.connect(self.call_update_desc)
        # 设置 tab
        self.tabWidget.setCurrentIndex(0)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        # 状态栏
        self._msg_label = QLabel()
        self._msg_label.setObjectName("msg_label")
        self.statusbar.addWidget(self._msg_label)
        # 重命名、修改简介与新建文件夹对话框
        self.rename_dialog = RenameDialog()
        self.rename_dialog.out.connect(self.rename_set_desc_and_mkdir)
        # 菜单栏关于
        self.about_dialog = AboutDialog()
        self.about_dialog.set_values(self.__version__)

    def show_login_dialog(self):
        """显示登录对话框"""
        login_dialog = LoginDialog(self._config)
        login_dialog.clicked_ok.connect(self.call_login_luncher)
        login_dialog.setWindowModality(Qt.ApplicationModal)
        login_dialog.exec()

    def show_upload_dialog(self):
        """显示上传文件对话框"""
        self.upload_dialog.set_values(list(self._path_list.keys())[-1])
        self.upload_dialog.exec()

    def load_settings(self):
        try:
            with open(self._config, "rb") as _file:
                self.settings = load(_file)
        except Exception:
            dl_path = os.path.dirname(
                os.path.abspath(__file__)) + os.sep + "downloads"
            self.settings = {"user": "", "pwd": "", "path": dl_path}
            with open(self._config, "wb") as _file:
                dump(self.settings, _file)

    def call_downloader(self):
        tab_page = self.tabWidget.currentIndex()
        if tab_page == 0:
            listview = self.table_share
            model = self.model_share
        elif tab_page == 1:
            listview = self.table_disk
            model = self.model_disk
        indexes = []
        tasks = []
        _indexes = listview.selectionModel().selection().indexes()
        for i in _indexes:  # 获取所选行号
            indexes.append(i.row())
        indexes = set(indexes)
        save_path = self.settings["path"]
        for index in indexes:
            infos = model.item(index, 0).data()
            if not infos:
                continue
            # 查询 分享链接 以及 提取码
            if infos[0]:  # 从 disk 运行
                if infos[2]:  # 文件
                    _info = self._disk.get_share_info(infos[0], is_file=True)
                else:  # 文件夹
                    _info = self._disk.get_share_info(infos[0], is_file=False)
                infos[5] = _info['pwd']  # 将bool值改成 字符串
                infos.append(_info['url'])
            tasks.append([infos[1], infos[7], infos[5], save_path])
        self.download_manager.set_values(tasks, 3)
        self.download_manager.start()

    def call_logout(self):
        """菜单栏、工具栏登出"""
        self._disk.logout()
        self.toolbar.removeAction(self.logout)
        self.tabWidget.setCurrentIndex(0)
        self.disk_tab.setEnabled(False)
        self.rec_tab.setEnabled(False)
        self.tabWidget.removeTab(2)
        self.tabWidget.removeTab(1)
        self.toolbar.removeAction(self.logout)  # 登出工具
        self.logout.setEnabled(False)
        self.toolbar.removeAction(self.upload)  # 上传文件工具栏
        self.upload.setEnabled(False)
        self.upload.triggered.disconnect(self.show_upload_dialog)
        self.statusbar.showMessage("已经退出登录!", 4000)

    def login_update_ui(self, success, msg, duration):
        """根据登录是否成功更新UI"""
        if success:
            self.show_status(msg, duration)
            self.tabWidget.insertTab(1, self.disk_tab, "我的蓝奏云")
            self.tabWidget.insertTab(2, self.rec_tab, "回收站")
            self.disk_tab.setEnabled(True)
            self.rec_tab.setEnabled(True)
            # 更新快捷键与工具栏
            self.toolbar.addAction(self.logout)  # 添加登出工具栏
            self.toolbar.addAction(self.upload)  # 添加上传文件工具栏
            # 菜单栏槽
            self.logout.setEnabled(True)
            self.upload.setEnabled(True)
            self.upload.triggered.connect(self.show_upload_dialog)
            # 设置当前显示 tab
            self.tabWidget.setCurrentIndex(1)
            QCoreApplication.processEvents()  # 重绘界面
            # 刷新文件列表
            self.refresh_dir(self._work_id)
        else:
            self.show_status(msg, duration)
            self.tabWidget.setCurrentIndex(0)
            self.tabWidget.removeTab(2)
            self.tabWidget.removeTab(1)
            self.disk_tab.setEnabled(False)
            self.rec_tab.setEnabled(False)
            # 更新快捷键与工具栏
            self.toolbar.removeAction(self.logout)  # 登出工具栏
            self.toolbar.removeAction(self.upload)  # 上传文件工具栏
            self.logout.setEnabled(False)
            self.upload.setEnabled(False)

    def call_login_luncher(self):
        """登录网盘"""
        self.load_settings()
        self._disk.logout()
        self.toolbar.removeAction(self.logout)
        try:
            username = self.settings["user"]
            password = self.settings["pwd"]
            cookie = self.settings["cookie"]
            self.login_luncher.set_values(username, password, cookie)
            self.login_luncher.start()
        except Exception as exp:
            print(exp)
            pass

    def set_file_icon(self, name):
        suffix = name.split(".")[-1]
        ico_path = "./icon/{}.gif".format(suffix)
        if os.path.isfile(ico_path):
            return QIcon(ico_path)
        else:
            return QIcon("./icon/file.ico")

    def show_file_and_folder_lists(self):
        """显示文件和文件夹列表"""
        self.model_disk.removeRows(0, self.model_disk.rowCount())  # 清理旧的内容
        file_count = len(self._file_list.keys())
        folder_count = len(self._folder_list.keys())
        name_header = [
            "文件夹{}个".format(folder_count),
        ] if folder_count else []
        if file_count:
            name_header.append("文件{}个".format(file_count))
        self.model_disk.setHorizontalHeaderLabels(
            ["/".join(name_header), "大小", "时间"])
        folder_ico = QIcon("./icon/folder.gif")
        pwd_ico = QIcon("./icon/keys.ico")
        # infos: ID/None,文件名,大小,日期,下载次数(dl_count),提取码(pwd),描述(desc),|链接(share-url),直链
        if self._work_id != -1:
            _back = QStandardItem(folder_ico, "..")
            _back.setToolTip("双击返回上层文件夹,选中无效")
            self.model_disk.appendRow(
                [_back, QStandardItem(""),
                 QStandardItem("")])
        for infos in self._folder_list.values():  # 文件夹
            name = QStandardItem(folder_ico, infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico, "") if infos[5] else QStandardItem(
                "")  # 提取码+size
            self.model_disk.appendRow([name, size_, QStandardItem("")])
        for infos in self._file_list.values():  # 文件
            name = QStandardItem(self.set_file_icon(infos[1]), infos[1])
            name.setData(infos)
            tips = ""
            if infos[5] is not False:
                tips = "有提取码"
                if infos[6] is not False:
                    tips = tips + ",描述:" + str(infos[6])
            elif infos[6] is not False:
                tips = "描述:" + str(infos[6])
            name.setToolTip(tips)
            size_ = QStandardItem(pwd_ico,
                                  infos[2]) if infos[5] else QStandardItem(
                                      infos[2])  # 提取码+size
            self.model_disk.appendRow([name, size_, QStandardItem(infos[3])])
        for r in range(self.model_disk.rowCount()):  # 右对齐
            self.model_disk.item(r, 1).setTextAlignment(Qt.AlignRight
                                                        | Qt.AlignVCenter)
            self.model_disk.item(r, 2).setTextAlignment(Qt.AlignRight
                                                        | Qt.AlignVCenter)

    def refresh_dir(self,
                    folder_id=-1,
                    r_files=True,
                    r_folders=True,
                    r_path=True):
        """更新目录列表,包括列表和路径指示器"""
        if r_files:
            info = {
                i['name']: [
                    i['id'], i['name'], i['size'], i['time'], i['downs'],
                    i['has_pwd'], i['has_des']
                ]
                for i in self._disk.get_file_list(folder_id)
            }
            self._file_list = {
                key: info.get(key)
                for key in sorted(info.keys())
            }  # {name-[id,...]}
        if r_folders:
            info = {
                i['name']:
                [i['id'], i['name'], "", "", "", i['has_pwd'], i['desc']]
                for i in self._disk.get_dir_list(folder_id)
            }
            self._folder_list = {
                key: info.get(key)
                for key in sorted(info.keys())
            }  # {name-[id,...]}
        self._path_list = self._disk.get_full_path(folder_id)
        current_folder = list(self._path_list.keys())[-1]
        self._work_id = self._path_list.get(current_folder, -1)
        if folder_id != -1:
            parent_folder_name = list(self._path_list.keys())[-2]
            self._parent_id = self._path_list.get(parent_folder_name, -1)
        self.show_file_and_folder_lists()
        if r_path:
            self.show_full_path()

    def config_tableview(self, tab):
        if tab == "share":
            model = self.model_share
            table = self.table_share
        elif tab == "disk":
            model = self.model_disk
            table = self.table_disk

        model.setHorizontalHeaderLabels(["文件名", "大小", "时间"])
        table.setModel(model)
        # 是否显示网格线
        table.setShowGrid(False)
        # 禁止编辑表格
        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 隐藏水平表头
        table.verticalHeader().setVisible(False)
        # 设置表头可以自动排序
        table.setSortingEnabled(True)
        table.setMouseTracking(False)
        # 设置表头的背景色为绿色
        table.horizontalHeader().setStyleSheet(
            "QHeaderView::section{background:lightgray}")
        # 设置 不可选择单个单元格,只可选择一行。
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 设置第二三列的宽度
        table.horizontalHeader().resizeSection(1, 90)
        table.horizontalHeader().resizeSection(2, 80)
        # 设置第一列宽度自动调整,充满屏幕
        table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        table.setContextMenuPolicy(Qt.CustomContextMenu)  # 允许右键产生子菜单
        table.customContextMenuRequested.connect(self.generateMenu)  # 右键菜单

    def create_left_menus(self):
        self.left_menus = QMenu()
        self.left_menu_share_url = self.left_menus.addAction("外链分享地址")
        self.left_menu_share_url.setIcon(QIcon("./icon/share.ico"))
        self.left_menu_rename_set_desc = self.left_menus.addAction("修改文件夹名与描述")
        self.left_menu_rename_set_desc.setIcon(QIcon("./icon/desc.ico"))
        self.left_menu_set_pwd = self.left_menus.addAction("设置访问密码")
        self.left_menu_set_pwd.setIcon(QIcon("./icon/password.ico"))
        self.left_menu_move = self.left_menus.addAction("移动")
        self.left_menu_move.setIcon(QIcon("./icon/move.ico"))

    def rename_set_desc_and_mkdir(self, infos):
        """重命名、修改简介与新建文件夹"""
        action = infos[0]
        fid = infos[1]
        new_name = infos[2]
        new_desc = infos[3]
        if not fid:  # 新建文件夹
            fid = self._work_id
            if new_name in self._folder_list.keys():
                self.statusbar.showMessage("文件夹已存在:{}".format(new_name), 7000)
            else:
                res = self._disk.mkdir(self._work_id, new_name, new_desc)
                if res == LanZouCloud.MKDIR_ERROR:
                    self.statusbar.showMessage("创建文件夹失败:{}".format(new_name),
                                               7000)
                else:
                    sleep(1.5)  # 暂停一下,否则无法获取新建的文件夹
                    self.statusbar.showMessage("成功创建文件夹:{}".format(new_name),
                                               7000)
                    # 此处仅更新文件夹,并显示
                    self.refresh_dir(self._work_id, False, True, False)
        else:  # 重命名、修改简介
            if action == "file":  # 修改文件描述
                res = self._disk.set_desc(fid, str(new_desc), is_file=True)
            else:  # 修改文件夹,action == "folder"
                _res = self._disk.get_share_info(fid, is_file=False)
                if _res['code'] == LanZouCloud.SUCCESS:
                    res = self._disk._set_dir_info(fid, str(new_name),
                                                   str(new_desc))
                else:
                    res = _res['code']
            if res == LanZouCloud.SUCCESS:
                self.statusbar.showMessage("修改成功!", 4000)
            elif res == LanZouCloud.FAILED:
                self.statusbar.showMessage("失败:发生错误!", 4000)
            if action == "file":  # 只更新文件列表
                self.refresh_dir(self._work_id,
                                 r_files=True,
                                 r_folders=False,
                                 r_path=False)
            else:  # 只更新文件夹列表
                self.refresh_dir(self._work_id,
                                 r_files=False,
                                 r_folders=True,
                                 r_path=False)

    def set_passwd(self, infos):
        """设置文件(夹)提取码"""
        fid = infos[0]
        if not fid:
            print("ERROR : 文件(夹)不存在:{}".format(infos[0]))
            return None
        new_pass = infos[1]
        if 2 <= len(new_pass) <= 6 or new_pass == "":
            if infos[2]:
                is_file = True
            else:
                is_file = False
            res = self._disk.set_passwd(fid, new_pass, is_file)
            if res == LanZouCloud.SUCCESS:
                self.statusbar.showMessage("提取码变更成功!♬", 3000)
            elif res == LanZouCloud.NETWORK_ERROR:
                self.statusbar.showMessage("网络错误,稍后重试!☒", 4000)
            else:
                self.statusbar.showMessage("提取码变更失败❀╳❀:{}".format(res), 4000)
            self.refresh_dir(self._work_id,
                             r_files=is_file,
                             r_folders=not is_file,
                             r_path=False)
        else:
            self.statusbar.showMessage("提取码为2-6位字符,关闭请输入空!", 4000)

    def move_file(self, info):
        """移动文件至新的文件夹"""
        file_id = info[0]
        folder_id = info[1]
        if self._disk.move_file(file_id, folder_id) == LanZouCloud.SUCCESS:
            # 此处仅更新文件夹,并显示
            self.refresh_dir(self._work_id, False, True, False)
            self.statusbar.showMessage("{} 移动成功!".format(info[2]), 4000)
        else:
            self.statusbar.showMessage("移动文件{}失败!".format(info[2]), 4000)

    def call_mkdir(self):
        """弹出新建文件夹对话框"""
        self.rename_dialog.set_values(None)
        self.rename_dialog.exec()

    def remove_files(self, infos):
        if not infos:
            return
        for i in infos:
            if i[1]:
                is_file = True
            else:
                is_file = False
            self._disk.delete(i[0], is_file)
        self.refresh_dir(self._work_id)

    def call_remove_files(self):
        indexs = []
        infos = []
        _indexs = self.table_disk.selectionModel().selection().indexes()
        if not _indexs:
            return
        for i in _indexs:  # 获取所选行号
            indexs.append(i.row())
        indexs = set(indexs)
        for index in indexs:
            info = self.model_disk.item(index, 0).data()  # 用于提示删除的文件名
            if info:
                infos.append(info[:3])
        delete_dialog = DeleteDialog(infos)
        delete_dialog.new_infos.connect(self.remove_files)
        delete_dialog.exec()

    def generateMenu(self, pos):
        """右键菜单"""
        row_num = self.sender().selectionModel().selection().indexes()
        if not row_num:  # 如果没有选中行,什么也不做
            return
        # row_num = row_num[0].row()
        _model = self.sender().model()
        infos = _model.item(row_num[0].row(), 0).data()
        if not infos:
            return
        # 通过是否有文件 ID 判断是登录界面还是提取界面
        if infos[0]:
            self.left_menu_rename_set_desc.setEnabled(True)
            self.left_menu_set_pwd.setEnabled(True)
            # 通过infos第3个字段 size 判断是否为文件夹,文件夹不能移动,设置不同的显示菜单名
            if infos[2]:
                self.left_menu_rename_set_desc.setText("修改文件描述")
                self.left_menu_move.setEnabled(True)
            else:
                self.left_menu_rename_set_desc.setText("修改文件夹名与描述")
                self.left_menu_move.setDisabled(True)
        else:
            self.left_menu_rename_set_desc.setDisabled(True)
            self.left_menu_move.setDisabled(True)
            self.left_menu_set_pwd.setDisabled(True)

        action = self.left_menus.exec_(self.sender().mapToGlobal(pos))
        infos = self.get_more_infomation(infos)  # 点击菜单项后更新信息
        if action == self.left_menu_share_url:
            info_dialog = InfoDialog(infos)
            info_dialog.setWindowModality(Qt.ApplicationModal)
            info_dialog.exec()
        elif action == self.left_menu_move:
            all_dirs_dict = self._disk.get_folder_id_list()
            move_file_dialog = MoveFileDialog(infos, all_dirs_dict)
            move_file_dialog.new_infos.connect(self.move_file)
            move_file_dialog.exec()
        elif action == self.left_menu_set_pwd:
            set_pwd_dialog = SetPwdDialog(infos)
            set_pwd_dialog.new_infos.connect(self.set_passwd)
            set_pwd_dialog.exec()
        elif action == self.left_menu_rename_set_desc:
            self.desc_fetcher.set_values(infos)
            self.desc_fetcher.start()  # 启动后台更新描述
            self.rename_dialog.set_values(infos)
            self.rename_dialog.exec()

    def call_update_desc(self, desc, infos):
        infos[6] = desc  # 更新 desc
        self.rename_dialog.set_values(infos)

    def get_more_infomation(self, infos):
        """获取文件直链、文件(夹)提取码描述"""
        if self._work_name == "Recovery":
            print("ERROR : 回收站模式下无法使用此操作")
            return None
        # infos: ID/None,文件名,大小,日期,下载次数(dl_count),提取码(pwd),描述(desc),|链接(share-url),直链
        if infos[0]:  # 从 disk 运行
            if infos[2]:  # 文件
                _info = self._disk.get_share_info(infos[0], is_file=True)
            else:  # 文件夹
                _info = self._disk.get_share_info(infos[0], is_file=False)
            infos[5] = _info['pwd']
            infos.append(_info['url'])
        if infos[2]:  # 文件
            res = self._disk.get_file_info_by_url(infos[-1], infos[5])
            if res["code"] == LanZouCloud.SUCCESS:
                infos.append("{}".format(res["durl"] or "无"))  # 下载直链
            elif res["code"] == LanZouCloud.NETWORK_ERROR:
                infos.append("网络错误!获取失败")  # 下载直链
            else:
                infos.append("其它错误!")  # 下载直链
        else:
            infos.append("无")  # 下载直链
        infos[5] = infos[5] or "无"  # 提取码
        return infos

    def chang_dir(self, dir_name):
        """双击切换工作目录"""
        dir_name = self.model_disk.item(dir_name.row(), 0).text()  # 文件夹名
        if self._work_name == "Recovery" and dir_name not in [".", ".."]:
            return None
        if dir_name == "..":  # 返回上级路径
            self.refresh_dir(self._parent_id)
        elif dir_name in self._folder_list.keys():
            folder_id = self._folder_list[dir_name][0]
            self.refresh_dir(folder_id)
        else:
            self.show_status("ERROR : 该文件夹不存在: {}".format(dir_name))

    def call_change_dir(self, folder_id=-1):
        """按钮调用"""
        def callfunc():
            self.refresh_dir(folder_id)

        return callfunc

    def call_upload(self, infos):
        """上传文件(夹)"""
        if self._work_name == 'Recovery':
            print('ERROR : 回收站模式下无法使用此操作')
            return None
        self._old_work_id = self._work_id  # 记录上传文件夹id
        self.upload_worker.set_values(self._disk, infos, self._old_work_id)
        self.upload_worker.start()

    def show_full_path(self):
        """路径框显示当前路径"""
        index = 1
        for name in self._path_list_old.items():
            self._locs[index].clicked.disconnect()
            self.disk_loc.removeWidget(self._locs[index])
            self._locs[index].deleteLater()
            self._locs[index] = None
            del self._locs[index]
            index += 1
        index = 1
        for name, id in self._path_list.items():
            self._locs[index] = QPushButton(name, self.disk_tab)
            self._locs[index].setIcon(QIcon("./icon/folder.gif"))
            self._locs[index].setStyleSheet(
                "QPushButton {border: none; background:transparent;}")
            self.disk_loc.insertWidget(index, self._locs[index])
            self._locs[index].clicked.connect(self.call_change_dir(id))
            index += 1
        self._path_list_old = self._path_list

    def select_all_btn(self, action="reverse"):
        """默认反转按钮状态"""
        page = self.tabWidget.currentIndex()
        if page == 0:
            btn = self.btn_share_select_all
            table = self.table_share
        elif page == 1:
            btn = self.btn_disk_select_all
            table = self.table_disk
        elif page == 2:
            return
        else:
            return
        if btn.isEnabled():
            if action == "reverse":
                if btn.text() == "全选":
                    table.selectAll()
                    btn.setText("取消")
                    btn.setIcon(QIcon("./icon/select-none.ico"))
                elif btn.text() == "取消":
                    table.clearSelection()
                    btn.setText("全选")
                    btn.setIcon(QIcon("./icon/select-all.ico"))
            elif action == "cancel":  # 点击列表其中一个就表示放弃全选
                btn.setText("全选")
                btn.setIcon(QIcon("./icon/select-all.ico"))
            else:
                table.selectAll()
                btn.setText("取消")
                btn.setIcon(QIcon("./icon/select-none.ico"))

    def finished_upload(self):
        """上传完成调用"""
        if self._old_work_id == self._work_id:
            self.refresh_dir(self._work_id, True, True, False)
        else:
            self._old_work_id = self._work_id
        self.show_status("上传完成!", 7000)

    def init_disk_ui(self):
        self.model_disk = QStandardItemModel(1, 3)
        self.config_tableview("disk")
        self.btn_disk_delete.setIcon(QIcon("./icon/delete.ico"))
        self.btn_disk_dl.setIcon(QIcon("./icon/downloader.ico"))
        self.btn_disk_select_all.setIcon(QIcon("./icon/select-all.ico"))
        self.btn_disk_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
        self.btn_disk_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_disk.clicked.connect(lambda: self.select_all_btn("cancel"))
        self.btn_disk_dl.clicked.connect(self.call_downloader)
        self.btn_disk_mkdir.setIcon(QIcon("./icon/add-folder.ico"))
        self.btn_disk_mkdir.clicked.connect(self.call_mkdir)
        self.btn_disk_delete.clicked.connect(self.call_remove_files)

        self.table_disk.doubleClicked.connect(self.chang_dir)
        # 上传器
        self.upload_worker = UploadWorker()
        self.upload_worker.finished.connect(self.finished_upload)
        self.upload_worker.code.connect(self.show_status)

    def show_status(self, msg, duration=0):
        self._msg_label.setText(msg)
        # self.statusbar.showMessage(msg, duration)
        QCoreApplication.processEvents()  # 重绘界面
        if duration != 0:
            QTimer.singleShot(duration, lambda: self._msg_label.setText(""))

    # shared url
    def call_get_shared_info_worker(self):
        line_share_text = self.line_share_url.text().strip()
        pat = r"(https?://(www\.)?lanzous.com/[bi][a-z0-9]+)[^0-9a-z]*([a-z0-9]+)?"
        for share_url, _, pwd in re.findall(pat, line_share_text):
            pass
        if self._disk.is_file_url(share_url):  # 链接为文件
            is_file = True
            is_folder = False
            self.show_status("正在获取文件链接信息……")
        elif self._disk.is_folder_url(share_url):  # 链接为文件夹
            is_folder = True
            is_file = False
            self.show_status("正在获取文件夹链接信息,可能需要几秒钟,请稍后……")
        else:
            self.show_status("{} 为非法链接!".format(share_url))
            self.btn_extract.setEnabled(True)
            self.line_share_url.setEnabled(True)
            return
        self.model_share.removeRows(0, self.model_share.rowCount())
        QCoreApplication.processEvents()  # 重绘界面

        self.get_shared_info_thread.set_values(self._disk, share_url, pwd,
                                               is_file, is_folder)
        self.get_shared_info_thread.start()

    def call_get_shared_info(self):
        if not self.get_shared_info_thread.isRunning():  # 防止阻塞主进程
            self.line_share_url.setEnabled(False)
            self.btn_extract.setEnabled(False)
            self.call_get_shared_info_worker()

    def show_share_url_file_lists(self, infos):
        if infos["code"] == LanZouCloud.SUCCESS:
            file_count = len(infos["info"].keys())
            self.model_share.setHorizontalHeaderLabels(
                ["文件{}个".format(file_count), "大小", "时间"])
            for infos in infos["info"].values():
                name = QStandardItem(self.set_file_icon(infos[1]), infos[1])
                name.setData(infos)
                self.model_share.appendRow(
                    [name,
                     QStandardItem(infos[2]),
                     QStandardItem(infos[3])])
            for r in range(self.model_share.rowCount()):  # 右对齐
                self.model_share.item(r, 1).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
                self.model_share.item(r, 2).setTextAlignment(Qt.AlignRight
                                                             | Qt.AlignVCenter)
            self.table_share.setDisabled(False)
            self.btn_share_select_all.setDisabled(False)
            self.btn_share_select_all.setToolTip("按下 Ctrl/Alt + A 全选或则取消全选")
            self.btn_share_dl.setDisabled(False)
        else:
            self.btn_share_select_all.setDisabled(True)
            self.btn_share_select_all.setToolTip("")
            self.btn_share_dl.setDisabled(True)
            self.table_share.setDisabled(True)

    def set_download_path(self):
        """设置下载路径"""
        dl_path = QFileDialog.getExistingDirectory()
        if dl_path == self.settings["path"]:
            return
        if dl_path == "":
            dl_path = os.path.dirname(
                os.path.abspath(__file__)) + os.sep + "downloads"
            up_info = {"path": dl_path}
        else:
            up_info = {"path": dl_path}
        update_settings(self._config, up_info)
        self.load_settings()
        self.line_dl_path.setText(self.settings["path"])

    def init_extract_share_ui(self):
        self.btn_share_select_all.setDisabled(True)
        self.btn_share_dl.setDisabled(True)
        self.table_share.setDisabled(True)
        self.model_share = QStandardItemModel(1, 3)
        self.config_tableview("share")
        self.get_shared_info_thread = GetSharedInfo()
        self.get_shared_info_thread.code.connect(self.show_status)  # 状态码
        self.get_shared_info_thread.infos.connect(
            self.show_share_url_file_lists)  # 信息
        self.get_shared_info_thread.finished.connect(
            lambda: self.btn_extract.setEnabled(True))
        self.get_shared_info_thread.finished.connect(
            lambda: self.line_share_url.setEnabled(True))
        self.line_share_url.setPlaceholderText(
            "蓝奏云链接,如有提取码,放后面,空格或汉字等分割,回车键提取")
        self.line_share_url.returnPressed.connect(self.call_get_shared_info)
        self.btn_extract.clicked.connect(self.call_get_shared_info)
        self.btn_share_dl.clicked.connect(self.call_downloader)
        self.btn_share_dl.setIcon(QIcon("./icon/downloader.ico"))
        self.btn_share_select_all.setIcon(QIcon("./icon/select-all.ico"))
        self.btn_share_select_all.clicked.connect(
            lambda: self.select_all_btn("reverse"))
        self.table_share.clicked.connect(lambda: self.select_all_btn("cancel"))

        # 添加文件下载路径选择器
        self.line_dl_path = MyLineEdit(self.share_tab)
        self.line_dl_path.setObjectName("line_dl_path")
        self.horizontalLayout_share_2.insertWidget(2, self.line_dl_path)
        self.line_dl_path.setText(self.settings["path"])
        self.line_dl_path.clicked.connect(self.set_download_path)

        # QSS
        self.label_share_url.setStyleSheet(
            "#label_share_url {color: rgb(255,255,60);}")
        self.label_dl_path.setStyleSheet(
            "#label_dl_path {color: rgb(255,255,60);}")

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_A:  # Ctrl/Alt + A 全选
            if e.modifiers() and Qt.ControlModifier:
                self.select_all_btn()

    def set_window_at_center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        new_left = int((screen.width() - size.width()) / 2)
        new_top = int((screen.height() - size.height()) / 2)
        self.move(new_left, new_top)

    def open_wiki_url(self):
        # 打开使用说明页面
        url = QUrl('https://github.com/rachpt/lanzou-gui/wiki')
        if not QDesktopServices.openUrl(url):
            self.show_status('Could not open wiki page!', 5000)
示例#18
0
 def __about_menu_item_activate(self, menu_item):
     """Show the about dialog."""
     ad = AboutDialog()
     ad.run()
示例#19
0
class UICallbacks:
    tmpconfpath = os.path.expanduser("~/.hatari/.tmp.cfg")
    def __init__(self):
        # Hatari and configuration
        self.hatari = Hatari()
        error = self.hatari.is_compatible()
        if error:
            ErrorDialog(None).run(error)
            sys.exit(-1)
            
        self.config = HatariConfigMapping(self.hatari)
        try:
            self.config.validate()
        except (KeyError, AttributeError):
            NoteDialog(None).run("Loading Hatari configuration failed!\nRetrying after saving Hatari configuration.")
            self.hatari.save_config()
            self.config = HatariConfigMapping(self.hatari)
            self.config.validate()
        
        # windows are created when needed
        self.mainwin = None
        self.hatariwin = None
        self.debugui = None
        self.panels = {}

        # dialogs are created when needed
        self.aboutdialog = None
        self.inputdialog = None
        self.tracedialog = None
        self.resetdialog = None
        self.quitdialog = None
        self.killdialog = None

        self.floppydialog = None
        self.harddiskdialog = None
        self.displaydialog = None
        self.joystickdialog = None
        self.machinedialog = None
        self.peripheraldialog = None
        self.sounddialog = None
        self.pathdialog = None
        
        # used by run()
        self.memstate = None
        self.floppy = None
        self.io_id = None

        # TODO: Hatari UI own configuration settings save/load
        self.tracepoints = None

    def _reset_config_dialogs(self):
        self.floppydialog = None
        self.harddiskdialog = None
        self.displaydialog = None
        self.joystickdialog = None
        self.machinedialog = None
        self.peripheraldialog = None
        self.sounddialog = None
        self.pathdialog = None
        
    # ---------- create UI ----------------
    def create_ui(self, accelgroup, menu, toolbars, fullscreen, embed):
        "create_ui(menu, toolbars, fullscreen, embed)"
        # add horizontal elements
        hbox = gtk.HBox()
        if toolbars["left"]:
            hbox.pack_start(toolbars["left"], False, True)
        if embed:
            self._add_uisocket(hbox)
        if toolbars["right"]:
            hbox.pack_start(toolbars["right"], False, True)
        # add vertical elements
        vbox = gtk.VBox()
        if menu:
            vbox.add(menu)
        if toolbars["top"]:
            vbox.pack_start(toolbars["top"], False, True)
        vbox.add(hbox)
        if toolbars["bottom"]:
            vbox.pack_start(toolbars["bottom"], False, True)
        # put them to main window
        mainwin = gtk.Window(gtk.WINDOW_TOPLEVEL)
        mainwin.set_title("%s %s" % (UInfo.name, UInfo.version))
        mainwin.set_icon_from_file(UInfo.icon)
        if accelgroup:
            mainwin.add_accel_group(accelgroup)
        if fullscreen:
            mainwin.fullscreen()
        mainwin.add(vbox)
        mainwin.show_all()
        # for run and quit callbacks
        self.killdialog = KillDialog(mainwin)
        mainwin.connect("delete_event", self.quit)
        self.mainwin = mainwin
    
    def _add_uisocket(self, box):
        # add Hatari parent container to given box
        socket = gtk.Socket()
        # without this, closing Hatari would remove the socket widget
        socket.connect("plug-removed", lambda obj: True)
        socket.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
        socket.set_events(gtk.gdk.ALL_EVENTS_MASK)
        socket.set_flags(gtk.CAN_FOCUS)
        # set max Hatari window size = desktop size
        self.config.set_desktop_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
        # set initial embedded hatari size
        width, height = self.config.get_window_size()
        socket.set_size_request(width, height)
        # no resizing for the Hatari window
        box.pack_start(socket, False, False)
        self.hatariwin = socket

    # ------- run callback -----------
    def _socket_cb(self, fd, event):
        if event != gobject.IO_IN:
            # hatari process died, make sure Hatari instance notices
            self.hatari.kill()
            return False
        width, height = self.hatari.get_embed_info()
        print("New size = %d x %d" % (width, height))
        oldwidth, oldheight = self.hatariwin.get_size_request()
        self.hatariwin.set_size_request(width, height)
        if width < oldwidth or height < oldheight:
            # force also mainwin smaller (it automatically grows)
            self.mainwin.resize(width, height)
        return True
    
    def run(self, widget = None):
        if not self.killdialog.run(self.hatari):
            return
        if self.io_id:
            gobject.source_remove(self.io_id)
        args = ["--configfile"]
        # whether to use Hatari config or unsaved Hatari UI config?
        if self.config.is_changed():
            args += [self.config.save_tmp(self.tmpconfpath)]
        else:
            args += [self.config.get_path()]
        if self.memstate:
            args += self.memstate
        # only way to change boot order is to specify disk on command line
        if self.floppy:
            args += self.floppy
        if self.hatariwin:
            size = self.hatariwin.window.get_size()
            self.hatari.run(args, self.hatariwin.window)
            # get notifications of Hatari window size changes
            self.hatari.enable_embed_info()
            socket = self.hatari.get_control_socket().fileno()
            events = gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR
            self.io_id = gobject.io_add_watch(socket, events, self._socket_cb)
            # all keyboard events should go to Hatari window
            self.hatariwin.grab_focus()
        else:
            self.hatari.run(args)

    def set_floppy(self, floppy):
        self.floppy = floppy

    # ------- quit callback -----------
    def quit(self, widget, arg = None):
        # due to Gtk API, needs to return True when *not* quitting
        if not self.killdialog.run(self.hatari):
            return True
        if self.io_id:
            gobject.source_remove(self.io_id)
        if self.config.is_changed():
            if not self.quitdialog:
                self.quitdialog = QuitSaveDialog(self.mainwin)
            if not self.quitdialog.run(self.config):
                return True
        gtk.main_quit()
        if os.path.exists(self.tmpconfpath):
            os.unlink(self.tmpconfpath)
        # continue to mainwin destroy if called by delete_event
        return False

    # ------- pause callback -----------
    def pause(self, widget):
        if widget.get_active():
            self.hatari.pause()
        else:
            self.hatari.unpause()

    # dialogs
    # ------- reset callback -----------
    def reset(self, widget):
        if not self.resetdialog:
            self.resetdialog = ResetDialog(self.mainwin)
        self.resetdialog.run(self.hatari)

    # ------- about callback -----------
    def about(self, widget):
        if not self.aboutdialog:
            self.aboutdialog = AboutDialog(self.mainwin)
        self.aboutdialog.run()

    # ------- input callback -----------
    def inputs(self, widget):
        if not self.inputdialog:
            self.inputdialog = InputDialog(self.mainwin)
        self.inputdialog.run(self.hatari)

    # ------- floppydisk callback -----------
    def floppydisk(self, widget):
        if not self.floppydialog:
            self.floppydialog = FloppyDialog(self.mainwin)
        self.floppydialog.run(self.config)

    # ------- harddisk callback -----------
    def harddisk(self, widget):
        if not self.harddiskdialog:
            self.harddiskdialog = HardDiskDialog(self.mainwin)
        self.harddiskdialog.run(self.config)

    # ------- display callback -----------
    def display(self, widget):
        if not self.displaydialog:
            self.displaydialog = DisplayDialog(self.mainwin)
        self.displaydialog.run(self.config)

    # ------- joystick callback -----------
    def joystick(self, widget):
        if not self.joystickdialog:
            self.joystickdialog = JoystickDialog(self.mainwin)
        self.joystickdialog.run(self.config)

    # ------- machine callback -----------
    def machine(self, widget):
        if not self.machinedialog:
            self.machinedialog = MachineDialog(self.mainwin)
        if self.machinedialog.run(self.config):
            self.hatari.trigger_shortcut("coldreset")

    # ------- peripheral callback -----------
    def peripheral(self, widget):
        if not self.peripheraldialog:
            self.peripheraldialog = PeripheralDialog(self.mainwin)
        self.peripheraldialog.run(self.config)

    # ------- sound callback -----------
    def sound(self, widget):
        if not self.sounddialog:
            self.sounddialog = SoundDialog(self.mainwin)
        self.sounddialog.run(self.config)

    # ------- path callback -----------
    def path(self, widget):
        if not self.pathdialog:
            self.pathdialog = PathDialog(self.mainwin)
        self.pathdialog.run(self.config)

    # ------- debug callback -----------
    def debugger(self, widget):
        if not self.debugui:
            self.debugui = HatariDebugUI(self.hatari)
        self.debugui.show()

    # ------- trace callback -----------
    def trace(self, widget):
        if not self.tracedialog:
            self.tracedialog = TraceDialog(self.mainwin)
        self.tracepoints = self.tracedialog.run(self.hatari, self.tracepoints)

    # ------ snapshot load/save callbacks ---------
    def load(self, widget):
        path = os.path.expanduser("~/.hatari/hatari.sav")
        filename = get_open_filename("Select snapshot", self.mainwin, path)
        if filename:
            self.memstate = ["--memstate", filename]
            self.run()
            return True
        return False

    def save(self, widget):
        self.hatari.trigger_shortcut("savemem")

    # ------ config load/save callbacks ---------
    def config_load(self, widget):
        path = self.config.get_path()
        filename = get_open_filename("Select configuration file", self.mainwin, path)
        if filename:
            self.hatari.change_option("--configfile %s" % filename)
            self.config.load(filename)
            self._reset_config_dialogs()
            return True
        return False

    def config_save(self, widget):
        path = self.config.get_path()
        filename = get_save_filename("Save configuration as...", self.mainwin, path)
        if filename:
            self.config.save_as(filename)
            return True
        return False

    # ------- fast forward callback -----------
    def set_fastforward(self, widget):
        self.config.set_fastforward(widget.get_active())

    def get_fastforward(self):
        return self.config.get_fastforward()

    # ------- fullscreen callback -----------
    def set_fullscreen(self, widget):
        # if user can select this, Hatari isn't in fullscreen
        self.hatari.change_option("--fullscreen")

    # ------- screenshot callback -----------
    def screenshot(self, widget):
        self.hatari.trigger_shortcut("screenshot")

    # ------- record callbacks -----------
    def recanim(self, widget):
        self.hatari.trigger_shortcut("recanim")

    def recsound(self, widget):
        self.hatari.trigger_shortcut("recsound")

    # ------- insert key special callback -----------
    def keypress(self, widget, code):
        self.hatari.insert_event("keypress %s" % code)

    def textinsert(self, widget, text):
        HatariTextInsert(self.hatari, text)

    # ------- panel callback -----------
    def panel(self, action, box):
        title = action.get_name()
        if title not in self.panels:
            window = gtk.Window(gtk.WINDOW_TOPLEVEL)
            window.set_transient_for(self.mainwin)
            window.set_icon_from_file(UInfo.icon)
            window.set_title(title)
            window.add(box)
            window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
            window.connect("delete_event", window_hide_cb)
            self.panels[title] = window
        else:
            window = self.panels[title]
        window.show_all()
        window.deiconify()
示例#20
0
 def on_about_button_press(self, instance):
     dlg = AboutDialog()
     dlg.open()