Пример #1
0
    def _update_checkboxes(self, item: QTreeWidgetItem, column: int):
        if column != 0:
            return

        new_check_state = item.checkState(0)
        self._set_check_state_to_tree(item, new_check_state)

        while True:
            item = item.parent()
            if item is None:
                break

            has_checked_children = False
            has_partially_checked_children = False
            has_unchecked_children = False
            for i in range(item.childCount()):
                state = item.child(i).checkState(0)
                if state == Qt.Checked:
                    has_checked_children = True
                elif state == Qt.PartiallyChecked:
                    has_partially_checked_children = True
                else:
                    has_unchecked_children = True

            if not has_partially_checked_children and not has_unchecked_children:
                new_state = Qt.Checked
            elif has_checked_children or has_partially_checked_children:
                new_state = Qt.PartiallyChecked
            else:
                new_state = Qt.Unchecked
            item.setCheckState(0, new_state)

        self._update_selection_label()
Пример #2
0
    def update(self, *, network: Network, servers: dict, use_tor: bool):
        self.clear()

        # connected servers
        connected_servers_item = QTreeWidgetItem([_("Connected nodes"), ''])
        connected_servers_item.setData(0, self.ITEMTYPE_ROLE,
                                       self.ItemType.TOPLEVEL)
        chains = network.get_blockchains()
        n_chains = len(chains)
        for chain_id, interfaces in chains.items():
            b = blockchain.blockchains.get(chain_id)
            if b is None: continue
            name = b.get_name()
            if n_chains > 1:
                x = QTreeWidgetItem(
                    [name + '@%d' % b.get_max_forkpoint(),
                     '%d' % b.height()])
                x.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CHAIN)
                x.setData(0, self.CHAIN_ID_ROLE, b.get_id())
            else:
                x = connected_servers_item
            for i in interfaces:
                star = ' *' if i == network.interface else ''
                item = QTreeWidgetItem(
                    [f"{i.server.net_addr_str()}" + star,
                     '%d' % i.tip])
                item.setData(0, self.ITEMTYPE_ROLE,
                             self.ItemType.CONNECTED_SERVER)
                item.setData(0, self.SERVER_ADDR_ROLE, i.server)
                item.setToolTip(0, str(i.server))
                x.addChild(item)
            if n_chains > 1:
                connected_servers_item.addChild(x)

        # disconnected servers
        disconnected_servers_item = QTreeWidgetItem(
            [_("Other known servers"), ""])
        disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE,
                                          self.ItemType.TOPLEVEL)
        connected_hosts = set(
            [iface.host for ifaces in chains.values() for iface in ifaces])
        protocol = PREFERRED_NETWORK_PROTOCOL
        for _host, d in sorted(servers.items()):
            if _host in connected_hosts:
                continue
            if _host.endswith('.onion') and not use_tor:
                continue
            port = d.get(protocol)
            if port:
                server = ServerAddr(_host, port, protocol=protocol)
                item = QTreeWidgetItem([server.net_addr_str(), ""])
                item.setData(0, self.ITEMTYPE_ROLE,
                             self.ItemType.DISCONNECTED_SERVER)
                item.setData(0, self.SERVER_ADDR_ROLE, server)
                disconnected_servers_item.addChild(item)

        self.addTopLevelItem(connected_servers_item)
        self.addTopLevelItem(disconnected_servers_item)

        connected_servers_item.setExpanded(True)
        for i in range(connected_servers_item.childCount()):
            connected_servers_item.child(i).setExpanded(True)
        disconnected_servers_item.setExpanded(True)

        # headers
        h = self.header()
        h.setStretchLastSection(False)
        h.setSectionResizeMode(0, QHeaderView.Stretch)
        h.setSectionResizeMode(1, QHeaderView.ResizeToContents)

        super().update()
Пример #3
0
    def addOverlaysToTreeWidget(self, overlayDict, forbiddenOverlays,
                                preSelectedOverlays, singleOverlaySelection):
        self.singleOverlaySelection = singleOverlaySelection
        testItem = QTreeWidgetItem("a")
        for keys in list(overlayDict.keys()):
            if overlayDict[keys] in forbiddenOverlays:
                continue
            else:
                boolStat = False
                split = keys.split("/")
            for i in range(len(split)):
                if len(split) == 1:
                    newItemsChild = OverlayTreeWidgetItem(
                        overlayDict[keys], keys)
                    self.addTopLevelItem(newItemsChild)
                    boolStat = False
                    if overlayDict[keys] in preSelectedOverlays:
                        newItemsChild.setCheckState(0, Qt.Checked)
                    else:
                        newItemsChild.setCheckState(0, Qt.Unchecked)

                elif i + 1 == len(split) and len(split) > 1:
                    newItemsChild = OverlayTreeWidgetItem(
                        overlayDict[keys], keys)
                    testItem.addChild(newItemsChild)
                    if overlayDict[keys] in preSelectedOverlays:
                        newItemsChild.setCheckState(0, Qt.Checked)
                    else:
                        newItemsChild.setCheckState(0, Qt.Unchecked)

                elif self.topLevelItemCount() == 0 and i + 1 < len(split):
                    newItem = QTreeWidgetItem([split[i]])
                    self.addTopLevelItem(newItem)
                    testItem = newItem
                    boolStat = True

                elif self.topLevelItemCount() != 0 and i + 1 < len(split):
                    if boolStat == False:
                        for n in range(self.topLevelItemCount()):
                            if self.topLevelItem(n).text(0) == split[i]:
                                testItem = self.topLevelItem(n)
                                boolStat = True
                                break
                            elif n + 1 == self.topLevelItemCount():
                                newItem = QTreeWidgetItem([split[i]])
                                self.addTopLevelItem(newItem)
                                testItem = newItem
                                boolStat = True

                    elif testItem.childCount() == 0:
                        newItem = QTreeWidgetItem([split[i]])
                        testItem.addChild(newItem)
                        testItem = newItem
                        boolStat = True
                    else:
                        for x in range(testItem.childCount()):
                            if testItem.child(x).text(0) == split[i]:
                                testItem = testItem.child(x)
                                boolStat = True
                                break
                            elif x + 1 == testItem.childCount():
                                newItem = QTreeWidgetItem([split[i]])
                                testItem.addChild(newItem)
                                testItem = newItem
                                boolStat = True
Пример #4
0
class ClientUI(QWidget):
    def __init__(self):
        super().__init__()
        # self.window = QWidget()
        self.resize(1000, 600)
        self.setWindowTitle("拍一拍聊天室")

        # 聊天窗口
        self.messageBrowser = QTextBrowser()

        # 字体选择
        self.fontComboBox = QFontComboBox()
        self.fontComboBox.setObjectName("fontComboBox")
        self.fontComboBox.currentFontChanged.connect(
            self.on_fontComboBox_currentFontChanged)

        # 字体大小
        self.sizeComboBox = QComboBox()
        self.sizeComboBox.setObjectName("SizeComboBox")
        self.sizeComboBox.setCurrentIndex(0)
        for i in range(31):
            self.sizeComboBox.addItem("")
        _translate = QCoreApplication.translate
        self.sizeComboBox.setCurrentText(_translate("Widget", "10"))
        for i in range(31):
            self.sizeComboBox.setItemText(i, _translate("Widget", str(i + 10)))
        self.sizeComboBox.currentIndexChanged.connect(
            self.on_SizeComboBox_currentIndexChanged)

        # 加粗
        self.boldToolBtn = QToolButton()
        self.boldToolBtn.setContextMenuPolicy(Qt.DefaultContextMenu)
        icon = QIcon()
        root = QFileInfo(__file__).absolutePath()  # 获取根目录
        icon.addPixmap(QPixmap(root + "/image/bold.png"), QIcon.Normal,
                       QIcon.Off)
        self.boldToolBtn.setIcon(icon)
        self.boldToolBtn.setIconSize(QSize(22, 22))
        self.boldToolBtn.setCheckable(True)
        self.boldToolBtn.setAutoRaise(True)
        self.boldToolBtn.setObjectName("boldToolBtn")
        self.boldToolBtn.setToolTip(_translate("Widget", "加粗"))
        self.boldToolBtn.setText(_translate("Widget", "..."))
        self.boldToolBtn.clicked.connect(self.on_boldToolBtn_clicked)

        # 斜体
        self.italicToolBtn = QToolButton()
        icon1 = QIcon()
        icon1.addPixmap(QPixmap(root + "/image/italic.png"), QIcon.Normal,
                        QIcon.Off)
        self.italicToolBtn.setIcon(icon1)
        self.italicToolBtn.setIconSize(QSize(22, 22))
        self.italicToolBtn.setCheckable(True)
        self.italicToolBtn.setAutoRaise(True)
        self.italicToolBtn.setObjectName("italicToolBtn")
        self.italicToolBtn.setToolTip(_translate("Widget", "倾斜"))
        self.italicToolBtn.setText(_translate("Widget", "..."))
        self.italicToolBtn.clicked.connect(self.on_italicToolBtn_clicked)

        # 下划线
        self.underlineToolBtn = QToolButton()
        icon2 = QIcon()
        icon2.addPixmap(QPixmap(root + "/image/under.png"), QIcon.Normal,
                        QIcon.Off)
        self.underlineToolBtn.setIcon(icon2)
        self.underlineToolBtn.setIconSize(QSize(22, 22))
        self.underlineToolBtn.setCheckable(True)
        self.underlineToolBtn.setAutoRaise(True)
        self.underlineToolBtn.setObjectName("underlineToolBtn")
        self.underlineToolBtn.setToolTip(_translate("Widget", "下划线"))
        self.underlineToolBtn.setText(_translate("Widget", "..."))
        self.underlineToolBtn.clicked.connect(self.on_underlineToolBtn_clicked)

        # 颜色
        self.colorToolBtn = QToolButton()
        icon3 = QIcon()
        icon3.addPixmap(QPixmap(root + "/image/color.png"), QIcon.Normal,
                        QIcon.Off)
        self.colorToolBtn.setIcon(icon3)
        self.colorToolBtn.setIconSize(QSize(22, 22))
        self.colorToolBtn.setAutoRaise(True)
        self.colorToolBtn.setObjectName("colorToolBtn")
        self.colorToolBtn.setToolTip(_translate("Widget", "更改字体颜色"))
        self.colorToolBtn.setText(_translate("Widget", "..."))
        self.colorToolBtn.clicked.connect(self.on_colorToolBtn_clicked)

        # 聊天记录
        self.saveToolBtn = QToolButton()
        icon4 = QIcon()
        icon4.addPixmap(QPixmap(root + "/image/save.png"), QIcon.Normal,
                        QIcon.Off)
        self.saveToolBtn.setIcon(icon4)
        self.saveToolBtn.setIconSize(QSize(22, 22))
        self.saveToolBtn.setAutoRaise(True)
        self.saveToolBtn.setObjectName("saveToolBtn")
        self.saveToolBtn.setToolTip(_translate("Widget", "保存聊天记录"))
        self.saveToolBtn.setText(_translate("Widget", "..."))
        self.saveToolBtn.clicked.connect(self.on_saveToolBtn_clicked)

        self.clearToolBtn = QToolButton()
        icon5 = QIcon()
        icon5.addPixmap(QPixmap(root + "/image/clear.png"), QIcon.Normal,
                        QIcon.Off)
        self.clearToolBtn.setIcon(icon5)
        self.clearToolBtn.setIconSize(QSize(22, 22))
        self.clearToolBtn.setAutoRaise(True)
        self.clearToolBtn.setObjectName("clearToolBtn")
        self.clearToolBtn.setToolTip(_translate("Widget", "清空聊天记录"))
        self.clearToolBtn.setText(_translate("Widget", "..."))
        self.clearToolBtn.clicked.connect(self.on_clearToolBtn_clicked)

        # 发送按钮
        self.sendButton = QPushButton('发送')
        self.sendButton.clicked.connect(self.sendChatMsg)

        # 发送功能横向布局
        functionboxLayout = QHBoxLayout()
        functionboxLayout.addWidget(self.fontComboBox)
        functionboxLayout.addWidget(self.sizeComboBox)
        functionboxLayout.addWidget(self.boldToolBtn)
        functionboxLayout.addWidget(self.italicToolBtn)
        functionboxLayout.addWidget(self.underlineToolBtn)
        functionboxLayout.addWidget(self.colorToolBtn)
        functionboxLayout.addWidget(self.saveToolBtn)
        functionboxLayout.addWidget(self.clearToolBtn)
        functionboxLayout.addStretch(1)
        functionboxLayout.addWidget(self.sendButton)

        # 输入框
        self.messageEdit = QTextEdit()

        # 左侧竖向布局,三行
        vhoxLayout_left = QVBoxLayout()
        vhoxLayout_left.addWidget(self.messageBrowser)
        vhoxLayout_left.addLayout(functionboxLayout)
        vhoxLayout_left.addWidget(self.messageEdit)
        vhoxLayout_left.setStretch(0, 4)
        vhoxLayout_left.setStretch(1, 1)
        vhoxLayout_left.setStretch(2, 2)

        # 在线用户列表
        self.userView = QTreeWidget()
        self.userView.setHeaderLabels(["用户列表"])
        self.userView_online_node = QTreeWidgetItem(self.userView)
        self.userView_online_node.setText(0, "在线用户")
        self.userView_all_node = QTreeWidgetItem(self.userView)
        self.userView_all_node.setText(0, "所有用户")
        self.userView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.userView.customContextMenuRequested.connect(self.userView_menu)

        # 公共栏Label
        self.announcement_label = QLabel()
        self.announcement_label.setText("公告栏")

        # 公告栏
        self.announcement_edit = QTextEdit()
        self.announcement_edit.setEnabled(False)

        # 左侧竖向布局,一整块
        vhoxLayout_right = QVBoxLayout()
        vhoxLayout_right.addWidget(self.userView)
        vhoxLayout_right.addWidget(self.announcement_label)
        vhoxLayout_right.addWidget(self.announcement_edit)

        # 最大布局,横向两列
        hboxLayout = QHBoxLayout(self)
        hboxLayout.addLayout(vhoxLayout_left)
        hboxLayout.addLayout(vhoxLayout_right)
        hboxLayout.setStretch(0, 3)
        hboxLayout.setStretch(1, 1)

        self.show()

    def update_admin_UI(self):
        self.announcement_edit.setEnabled(True)
        self.announcement_edit.setContextMenuPolicy(Qt.CustomContextMenu)
        self.announcement_edit.customContextMenuRequested.connect(
            lambda: handler.announcement(self.announcement_edit.toPlainText()))

    def userView_menu(self):
        item = self.userView.currentItem()
        menu = QMenu(self.userView)
        if item.parent().text(0) == '在线用户':
            menu.addAction('拍一拍').triggered.connect(
                lambda: handler.pai_yi_pai(myname, item.text(0)))
        elif admin:
            menu.addAction('删除').triggered.connect(
                lambda: handler.delete_user(item.text(0)))
        menu.exec_(QCursor.pos())

    def mergeFormatDocumentOrSelection(self, format):

        cursor = self.messageEdit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.Document)
        cursor.mergeCharFormat(format)
        self.messageEdit.mergeCurrentCharFormat(format)

    def on_fontComboBox_currentFontChanged(self, p0):
        fmt = QTextCharFormat()
        fmt.setFont(p0)
        # fmt.setFontFamily(p0)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    # 字体大小
    def on_SizeComboBox_currentIndexChanged(self, p0):
        fmt = QTextCharFormat()
        p0 += 10
        fmt.setFontPointSize(p0)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    def on_boldToolBtn_clicked(self, checked):
        fmt = QTextCharFormat()
        fmt.setFontWeight(checked and QFont.Bold or QFont.Normal)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    def on_italicToolBtn_clicked(self, checked):
        fmt = QTextCharFormat()
        fmt.setFontItalic(checked)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    def on_underlineToolBtn_clicked(self, checked):
        fmt = QTextCharFormat()
        fmt.setFontUnderline(checked)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    def on_colorToolBtn_clicked(self):
        col = QColorDialog.getColor(self.messageEdit.textColor(), self)
        if not col.isValid():
            return
        fmt = QTextCharFormat()
        fmt.setForeground(col)
        self.mergeFormatDocumentOrSelection(fmt)
        self.messageEdit.setFocus()

    def on_saveToolBtn_clicked(self):
        print(self.messageBrowser.document().isEmpty())
        if self.messageBrowser.document().isEmpty():
            QMessageBox.warning(self, "警告", "聊天记录为空,无法保存!", QMessageBox.Ok)
        else:
            fileName = QFileDialog.getSaveFileName(self, "保存聊天记录", "./聊天记录",
                                                   ("HTML-Files (*.html)"))

            if fileName[0]:
                if self.saveFile(fileName[0]):
                    QMessageBox.information(self, "聊天记录保存", "保存成功!")

    def saveFile(self, fileName):

        SuffixFileName = fileName.split(".")[1]
        if SuffixFileName in ("html"):
            content = self.messageBrowser.toHtml()
        else:
            content = self.messageBrowser.toPlainText()
        try:
            with codecs.open(fileName, 'w', encoding="utf-8") as f:
                f.write(content)
            return True
        except IOError:
            QMessageBox.critical(self, "保存错误", "聊天记录保存失败!")
            return False

    def on_clearToolBtn_clicked(self):
        self.messageBrowser.clear()

    def getMessage(self):
        msg = self.messageEdit.toHtml()
        self.messageEdit.clear()
        self.messageEdit.setFocus()
        return msg

    def sendChatMsg(self):
        sendMsg(ALL_MSG, self.getMessage(), myname)
        self.messageEdit.clear()

    def showMsg(self, msg, name):
        time = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
        if name == '拍拍':
            self.messageBrowser.setTextColor(Qt.darkGreen)
            self.messageBrowser.append("[" + name + "] " + time)
            self.messageBrowser.append(msg)
        elif name != myname:
            self.messageBrowser.setTextColor(Qt.blue)
            self.messageBrowser.append("[" + name + "] " + time)
            self.messageBrowser.append(msg)
        else:
            self.messageBrowser.setTextColor(Qt.red)
            self.messageBrowser.append("[我] " + time)
            self.messageBrowser.append(msg)

    def addUserNode(self, group, name):
        self.userView.expandAll()
        newUser = QTreeWidgetItem(group)
        newUser.setText(0, name)
        newUser.setIcon(0, QIcon('image/user.jpg'))
        if (name == myname):
            newUser.setBackground(0, QColor(255, 0, 0, 100))
        if name == '拍拍':
            newUser.setBackground(0, QColor(0, 255, 0, 100))

    def removeUserNode(self, name):
        n = self.userView_online_node.childCount()
        for i in range(n):
            if self.userView_online_node.child(i).text(0) == name:
                self.userView_online_node.removeChild(
                    self.userView_online_node.child(i))
                break

    def removeAllNode(self, name):
        n = self.userView_all_node.childCount()
        for i in range(n):
            if self.userView_all_node.child(i).text(0) == name:
                self.userView_all_node.removeChild(
                    self.userView_all_node.child(i))
                break

    def userJoin(self, name):
        self.messageBrowser.setTextColor(Qt.gray)
        self.messageBrowser.append('系统消息:' + name + '上线了')
        self.addUserNode(self.userView_online_node, name)

    def userLeft(self, name):
        self.messageBrowser.setTextColor(Qt.gray)
        self.messageBrowser.append('系统消息:' + name + '离开了')
        self.removeUserNode(name)

    def pai_yi_pai(self, name, toname):
        self.messageBrowser.setTextColor(Qt.gray)
        self.messageBrowser.append(name + ' 拍了拍 ' + toname)
        if toname == myname:
            app.alert(self, 2000)

    def setHandler(self, handler):
        self.handler = handler

    def handler(self, msg):
        global admin
        type = msg[0]
        if type == ALL_MSG:
            self.showMsg(msg[1], msg[2])
        elif type == USR_JOIN:
            self.userJoin(msg[1])
        elif type == USR_LEFT:
            self.userLeft(msg[1])
        elif type == USR_LOGIN:
            admin = msg[2]
            if admin:
                self.update_admin_UI()
        elif type == ALL_ONLINE_USR:
            for i in msg[1]:
                self.userJoin(i)
            self.announcement_edit.setText(msg[2])
            for i in msg[3]:
                self.addUserNode(self.userView_all_node, i)
        elif type == PAI_YI_PAI:
            self.pai_yi_pai(msg[1], msg[2])
        elif type == ANNOUNCEMENT:
            self.announcement_edit.setText(msg[1])
        elif type == DELETE_USR:
            self.removeUserNode(msg[1])
            self.removeAllNode(msg[1])
Пример #5
0
class myGUI(QMainWindow):
    signal_loginSuccess = QtCore.pyqtSignal()
    signal_startShowTree = QtCore.pyqtSignal()
    signal_setStartBackupBtn = QtCore.pyqtSignal(str, bool)
    signal_showUserOptionWindow = QtCore.pyqtSignal()
    signal_showDevOptionWindow = QtCore.pyqtSignal()
    signal_close = QtCore.pyqtSignal()
    signal_appendDownloadList = QtCore.pyqtSignal(dict)
    signal_processbar_value = QtCore.pyqtSignal(int)
    signal_startUpdate = QtCore.pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.config = ConfigParser()
        self.pool = threadpool.ThreadPool(4)
        self.DownloadPool = threadpool.ThreadPool(1)
        self.readSetting()
        string.setLanguage(self.config['User']['language'])
        self.version = 1.21
        self.host = 'https://ilearn2.fcu.edu.tw'
        self.statusbar = self.statusBar()
        self.initUI()
        self.web = iLearnManager(self.host)
        self.init_iLearn()
        self.FileTree = {}
        self.success = 0
        self.failed = 0
        self.fileList = []
        self.retryList = []
        self.failedList = []
        self.retryTimes = 0
        self.nowLoad = 0
        self.retryAfter = 0
        self.initCheckUpdate = False
        self.retryTimer = QtCore.QTimer()
        self.retryTimer.timeout.connect(self.startRetry)
        self.signal_loginSuccess.connect(self.ShowResource)
        self.signal_appendDownloadList.connect(self.appendItemToDownloadList)
        self.signal_processbar_value.connect(self.setProcessBarValue)
        self.signal_startShowTree.connect(self.startShowTree)
        self.signal_setStartBackupBtn.connect(self.setStartBackupBtn)
        self.timer_checkUpdate = QtCore.QTimer()
        self.timer_checkUpdate.timeout.connect(self.checkUpdate)
        self.timer_checkUpdate.start(1000)
        if self.config['dev'].getboolean('autologin') == True:
            self.btn_login.click()

    def closeEvent(self, event):
        self.signal_close.emit()
        self.close()

    def setStatusBarText(self, str):
        self.statusbar.showMessage(str)

    def init_iLearn(self):
        self.web.signal_finishDownload.connect(self.startDownload)
        self.web.signal_setStatusProcessBar.connect(self.setStatusProcessBar)
        self.web.signal_Log.connect(self.print)
        self.web.signal_setStatusBarText.connect(self.setStatusBarText)
        t = Thread(target=self.TestiLearnConnection)
        t.run()

    def setStartBackupBtn(self, text, enabled):
        self.btn_StartBackup.setEnabled(enabled)
        self.btn_StartBackup.setText(text)

    def setStatusProcessBar(self, idx, value):
        if value == -1:
            ProcessBar = QProgressBar()
            self.StatusTable.setCellWidget(idx, 3, ProcessBar)
        elif value == -2:
            if self.retryTimes == 0:
                self.failed += 1
            self.failedList.append(idx)
            self.StatusTable.removeCellWidget(idx, 3)  # 移除進度條之控件
            ErrorIcon = QIcon(":img/DownloadFailed.png")  # 開啟下載失敗之圖案
            item = QTableWidgetItem(ErrorIcon,
                                    string._('Download Falied'))  # 新增顯示失敗的元件
            self.StatusTable.setItem(idx, 3, item)  # 將新元件設定到表格內
            if idx == len(self.fileList) - 1:
                self.signal_processbar_value.emit(idx + 1)
            self.finishDownloadCheck(idx)
        elif value == 101:
            if self.retryTimes != 0:
                self.failed -= 1
            self.success += 1
            self.print(string._('Download file %d finish!') % (idx + 1))
            self.StatusTable.removeCellWidget(idx, 3)
            OkIcon = QIcon(":img/FinishDownload.png")  # 開啟下載完成之圖案
            item = QTableWidgetItem(OkIcon, "OK")  # 新增顯示OK的元件
            self.StatusTable.setItem(idx, 3, item)  # 將新元件設定到表格內
            self.finishDownloadCheck(idx)
        else:
            ProcessBar = self.StatusTable.cellWidget(idx, 3)
            if ProcessBar == None:
                ProcessBar = QProgressBar()
                self.StatusTable.setCellWidget(idx, 3, ProcessBar)
            ProcessBar.setValue(value)

    def finishDownloadCheck(self, idx):
        def checkIsEndElement(idx):
            if self.retryTimes == 0:
                return idx == len(self.fileList) - 1
            else:
                return idx == self.retryList[-1]

        def backupFinish():
            self.signal_processbar_value.emit(self.statusProcessBar.maximum())
            self.signal_setStartBackupBtn.emit(string._('Start Backup'), True)
            QMessageBox.information(
                self, string._("Download finish!"),
                string._("Success:%d\nFailed:%d") %
                (self.success, self.failed))

        if checkIsEndElement(idx):
            if self.retryTimes == self.config['User'].getint('retrytimes'):
                backupFinish()
            else:
                self.signal_processbar_value.emit(
                    self.statusProcessBar.maximum())
                if self.failed == 0:
                    backupFinish()
                else:
                    self.retryAfter = self.config['User'].getint(
                        'secondbetweenretry')
                    self.retryTimer.start(1000)

    def checkUpdate(self):
        try:
            self.timer_checkUpdate.stop()
        except:
            pass
        with open('version.ini', mode='w') as f:
            f.write(str(self.version))
        s = requests.Session()
        versionFile = s.get(
            'https://raw.githubusercontent.com/fcu-d0441320/iLearnBackupTool/master/version.ini'
        )
        version = float(versionFile.text)
        if version > self.version:
            reply = QMessageBox.question(
                self, string._('Find New version'),
                string.
                _('Find New Version:%.1f\nNow Vsrsion:%.1f\nDo you want to update?'
                  ) % (version, self.version),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.setVisible(False)
                self.signal_startUpdate.emit(self.config['User']['language'])
        else:
            if self.initCheckUpdate == False:
                self.initCheckUpdate = True
            else:
                QMessageBox.information(self,
                                        string._('This is the latest version'),
                                        string._('This is the latest version'))
                # QMessageBox().information(self,"有更新版本!","發現有新版本,請前往官網更新,或檢查是否與Updater_GUI.exe放置於相同資料夾!")

    def moveToCenter(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
                  (screen.height() - size.height()) / 2)

    def initUI(self):
        self.resize(800, 600)
        self.setWindowIcon(QIcon(':img/Main_Icon.png'))
        self.moveToCenter()
        self.setWindowTitle(string._('iLearn Backup Tool'))
        self.statusbar.showMessage(string._('Starting Backup Tool...'))
        self.createMenu()
        self.statusProcessBar = QProgressBar()
        self.statusProcessBar.setValue(0)
        self.statusProcessBar.setFormat(string._("Ready..."))
        self.statusbar.addPermanentWidget(self.statusProcessBar)

        self.grid = QGridLayout()
        widget = QWidget()
        self.setCentralWidget(widget)
        widget.setLayout(self.grid)
        self.grid.addWidget(self.createLoginGroup(), 0, 0)
        self.grid.addWidget(self.createSaveGroup(), 1, 0)
        self.grid.addWidget(self.createCourseGroup(), 0, 1, 2, 1)
        self.grid.addWidget(self.createStatusView(), 2, 0, 1, 2)

        self.grid.setColumnStretch(0, 10)
        self.grid.setColumnStretch(1, 20)
        self.grid.setRowStretch(0, 6)
        self.grid.setRowStretch(1, 6)
        self.grid.setRowStretch(2, 10)
        self.web = iLearnManager()

        self.show()

    def createStatusTable(self):
        self.StatusTable = QTableWidget()
        self.StatusTable.setColumnCount(4)
        horizontal_header = [
            string._('File name'),
            string._('Path'),
            string._('iLearn mod'),
            string._('Download status')
        ]
        self.StatusTable.setHorizontalHeaderLabels(horizontal_header)
        self.StatusTable.setEditTriggers(QTableWidget.NoEditTriggers)
        self.StatusTable.setColumnWidth(0, 140)
        self.StatusTable.setColumnWidth(1, 120)
        self.StatusTable.setColumnWidth(2, 120)
        self.StatusTable.setColumnWidth(3, 380)
        return self.StatusTable

    def createLogSpace(self):
        self.LogSpace = QPlainTextEdit()
        self.LogSpace.setReadOnly(True)
        return self.LogSpace

    def print(self, msg):
        self.LogSpace.appendPlainText(
            time.strftime("[%H:%M:%S] ", time.localtime()) + msg)

    def createStatusView(self):
        tabs = QTabWidget()
        tabs.addTab(self.createStatusTable(), string._('Backup status'))
        tabs.addTab(self.createLogSpace(), string._('Log'))
        return tabs

    def createLoginGroup(self):
        groupBox = QGroupBox(string._('Step 1: Login'))
        form = QGridLayout()
        label_NID = QLabel(string._('NID:'))
        self.input_NID = QLineEdit()
        self.input_NID.setText(self.config['dev']['nid'])
        label_Pass = QLabel(string._('Password:'******'dev']['pass'])
        self.input_Pass.setEchoMode(QLineEdit.Password)
        form.addWidget(label_NID, 0, 0)
        form.addWidget(self.input_NID, 0, 1, 1, 2)
        form.addWidget(label_Pass, 1, 0)
        form.addWidget(self.input_Pass, 1, 1, 1, 2)

        self.btn_clean = QPushButton(string._('Clean'), self)
        self.btn_clean.clicked[bool].connect(self.cleanLogin)
        form.addWidget(self.btn_clean, 2, 1)

        self.btn_login = QPushButton(string._('Login'), self)
        self.btn_login.clicked[bool].connect(self.Login)
        form.addWidget(self.btn_login, 2, 2)

        label_iLearnStatus = QLabel(string._('iLearn status:'))
        form.addWidget(label_iLearnStatus, 3, 0)

        self.label_iLearn = QLabel()
        form.addWidget(self.label_iLearn, 3, 1, 1, 2)

        vbox = QVBoxLayout()
        vbox.addLayout(form)
        vbox.addStretch(1)
        groupBox.setLayout(vbox)

        return groupBox

    def cleanLogin(self):
        self.input_NID.setText("")
        self.input_Pass.setText("")

    def createSaveGroup(self):
        groupBox = QGroupBox(string._('Step 3:Select save option'))

        radio1 = QRadioButton(string._('Save as file'))
        radio1.setChecked(True)
        radio2 = QRadioButton(string._('Save as web page'))
        radio2.setEnabled(False)

        self.btn_StartBackup = QPushButton(string._('Start Backup'), self)
        self.btn_StartBackup.setEnabled(False)
        self.btn_StartBackup.clicked[bool].connect(self.StartBackup)
        self.btn_OpenFolder = QPushButton(string._('Open Folder'), self)
        self.btn_OpenFolder.clicked[bool].connect(self.OpenFolder)

        vbox = QVBoxLayout()
        vbox.addWidget(radio1)
        vbox.addWidget(radio2)
        vbox.addWidget(self.btn_StartBackup)
        vbox.addWidget(self.btn_OpenFolder)
        vbox.addStretch(1)
        groupBox.setLayout(vbox)

        if not exists('iLearn'):
            makedirs('iLearn')

        return groupBox

    def OpenFolder(self):
        subprocess.Popen(['explorer', "iLearn"])

    def createCourseGroup(self):
        groupBox = QGroupBox(
            string._('Step 2:Select sourse resource to backup'))

        self.CourseListBox = QVBoxLayout()
        self.CourseListBox.addStretch(1)

        self.CourseTreeList = QTreeWidget()
        self.CourseTreeList.setHeaderHidden(True)
        self.CourseTreeList.setEnabled(False)
        self.CourseTreeList.itemExpanded.connect(self.ExpandCourse)
        self.CourseTreeListRoot = QTreeWidgetItem(self.CourseTreeList)
        self.CourseTreeListRoot.setText(0, string._("All course"))
        self.CourseTreeListRoot.setFlags(self.CourseTreeListRoot.flags()
                                         | QtCore.Qt.ItemIsTristate
                                         | QtCore.Qt.ItemIsUserCheckable)
        self.CourseTreeListRoot.setCheckState(0, QtCore.Qt.Unchecked)

        HLayout = QHBoxLayout()
        HLayout.addWidget(self.CourseTreeList)

        groupBox.setLayout(HLayout)

        return groupBox

    def createMenu(self):
        menubar = self.menuBar()

        fileMenu = menubar.addMenu(string._('File'))
        closeAct = QAction(QIcon(':img/Close_Icon.png'), string._('Quit'),
                           self)
        closeAct.triggered.connect(qApp.quit)
        fileMenu.addAction(closeAct)

        optMenu = menubar.addMenu(string._('Option'))
        DevOptAct = QAction(QIcon(':img/Settings_Icon.png'),
                            string._('Developer options'), self)
        DevOptAct.triggered.connect(self.showDevOption)
        UserOptionAction = QAction(QIcon(':img/Settings_Icon.png'),
                                   string._('Preferences'), self)
        UserOptionAction.triggered.connect(self.showUserOption)
        optMenu.addAction(UserOptionAction)
        optMenu.addAction(DevOptAct)

        helpMenu = menubar.addMenu(string._('Help'))
        helpAct = QAction(QIcon(':img/Help_Icon.png'), string._('Help'), self)
        helpAct.triggered.connect(self.showHelp)
        aboutAct = QAction(QIcon(':img/About_Icon.png'), string._('About'),
                           self)
        aboutAct.triggered.connect(self.showInformation)
        checkUpdateAct = QAction(QIcon(':img/Update_Icon.png'),
                                 string._('Check update'), self)
        checkUpdateAct.triggered.connect(self.checkUpdate)
        helpMenu.addAction(helpAct)
        helpMenu.addAction(checkUpdateAct)
        helpMenu.addAction(aboutAct)

    def showHelp(self):
        subprocess.Popen(
            ["explorer", "http://github.com/fcu-d0441320/iLearnBackupTool"])

    def showUserOption(self):
        self.signal_showUserOptionWindow.emit()

    def showDevOption(self):
        self.signal_showDevOptionWindow.emit()

    def Login(self):
        t = Thread(target=self.__Login)
        t.run()

    def __Login(self):
        self.web.setUser(self.input_NID.text(), self.input_Pass.text())
        self.label_iLearn.setText(
            string._('User %s is signing in...') % self.input_NID.text())
        self.print(
            string._('User %s is signing in...') % self.input_NID.text())
        status, UserName = self.web.Login()
        if status:  # == True
            self.statusbar.showMessage(string._('Sign in success'))
            self.label_iLearn.setText(
                string._('%s sign in sucess') % (UserName))
            self.print(string._('%s sign in sucess') % (UserName))
            self.input_Pass.setEnabled(False)
            self.input_NID.setEnabled(False)
            self.btn_login.setEnabled(False)
            self.btn_clean.setEnabled(False)
            self.signal_loginSuccess.emit()
        else:
            self.statusbar.showMessage(string._('Sign in failed'))
            self.label_iLearn.setText(string._('Sign in failed'))
            self.print(UserName + string._('Sign in failed'))
        self.nowLoad = 0

    def ShowResource(self):
        self.CourseTreeList.setEnabled(True)
        self.courseList = self.web.getCourseList()

        for course in self.courseList:
            courseItem = QTreeWidgetItem(self.CourseTreeListRoot)
            self.CourseTreeListRoot.setExpanded(True)
            courseItem.setFlags(courseItem.flags() | QtCore.Qt.ItemIsTristate
                                | QtCore.Qt.ItemIsUserCheckable)
            courseItem.setText(0, course['title'])
            courseItem.setCheckState(0, QtCore.Qt.Unchecked)
            courseItem.setIcon(0, QIcon(':img/mod.course.jpg'))

            child = QTreeWidgetItem(courseItem)
            child.setFlags(courseItem.flags() | QtCore.Qt.ItemIsUserCheckable)
            child.setText(0, string._('Loading...'))
            child.setCheckState(0, QtCore.Qt.Unchecked)
        self.startBackgroundLoad()

    def ExpandCourse(self, courseItem):
        if courseItem.child(0).text(0) == string._('Loading...'):
            i = 0
            for ele in self.courseList:
                if ele['title'] == courseItem.text(0):
                    break
                else:
                    i += 1
            self.timer = QtCore.QTimer()  # 计时器
            self.timer.timeout.connect(
                partial(self.appedResourceToTree, i, courseItem))
            self.timer.start(10)

    def startBackgroundLoad(self):
        if self.nowLoad < len(self.courseList):
            self.statusProcessBar.setMaximum(len(self.courseList))
            self.statusProcessBar.setFormat(
                string._('Loding course resource') + '(%v/' + '%d)' %
                (len(self.courseList)))

            reqs = threadpool.makeRequests(self.loadFileTreeBackground,
                                           range(len(self.courseList)))
            for req in reqs:
                self.pool.putRequest(req)

    def setProcessBarValue(self, value):
        if value == self.statusProcessBar.maximum():
            self.statusProcessBar.setFormat(string._('Ready...'))
            self.statusProcessBar.setMaximum(100)
            self.statusProcessBar.setValue(0)
        else:
            self.statusProcessBar.setValue(value)

    def startShowTree(self):
        for i, courseItem in [
            (i, self.CourseTreeListRoot.child(i))
                for i in range(self.CourseTreeListRoot.childCount())
        ]:
            if courseItem.child(0).text(0) == string._('Loading...'):
                self.appedResourceToTree(i, courseItem)

    def loadFileTreeBackground(self, index):
        self.signal_processbar_value.emit(index)
        if self.courseList[index]['title'] not in self.FileTree:
            FileList = self.web.getCourseFileList(
                self.courseList[index],
                useRealFileName=self.config['User'].getboolean(
                    'userealfilename'),
                showTime=self.config['dev'].getboolean('showloadtime'))
            if self.courseList[index]['title'] not in self.FileTree:
                self.FileTree[self.courseList[index]['title']] = FileList
        if index == len(self.courseList) - 1:
            self.signal_processbar_value.emit(len(self.courseList))
            self.signal_setStartBackupBtn.emit(string._('Start Backup'), True)
            self.signal_startShowTree.emit()

    def appedResourceToTree(self, i, courseItem):
        course = self.courseList[i]
        try:
            self.timer.stop()
        except:
            pass
        tStart = time.time()
        if course['title'] not in self.FileTree:
            courseFileList = self.web.getCourseFileList(
                course,
                useRealFileName=self.config['User'].getboolean(
                    'userealfilename'),
                showTime=self.config['dev'].getboolean('showloadtime'))
            if course['title'] not in self.FileTree:
                self.FileTree[course['title']] = courseFileList
                self.nowLoad += 1
        else:
            courseFileList = self.FileTree[course['title']]
        checkStatus = courseItem.checkState(0)
        totalFiles = 0
        if len(courseFileList) == 0:
            sectionItem = QTreeWidgetItem(courseItem)
            sectionItem.setFlags(sectionItem.flags() | QtCore.Qt.ItemIsTristate
                                 | QtCore.Qt.ItemIsUserCheckable)
            sectionItem.setText(0,
                                string._('There has no resource to download.'))
            sectionItem.setCheckState(0, checkStatus)
        for section in courseFileList:
            sectionItem = QTreeWidgetItem(courseItem)
            sectionItem.setFlags(sectionItem.flags() | QtCore.Qt.ItemIsTristate
                                 | QtCore.Qt.ItemIsUserCheckable)
            sectionItem.setText(0, section['section'])
            sectionItem.setCheckState(0, checkStatus)
            sectionItem.setIcon(0, QIcon(":img/mod.folder.svg"))
            for recource in section['mods']:
                if recource['mod'] == 'forum':
                    forumItem = QTreeWidgetItem(sectionItem)
                    forumItem.setFlags(forumItem.flags()
                                       | QtCore.Qt.ItemIsTristate
                                       | QtCore.Qt.ItemIsUserCheckable)
                    forumItem.setText(0, recource['name'])
                    forumItem.setCheckState(0, checkStatus)
                    forumItem.setIcon(0, QIcon(":img/mod.discuss.svg"))
                    for topic in recource['data']:
                        topicItem = QTreeWidgetItem(forumItem)
                        topicItem.setFlags(topicItem.flags()
                                           | QtCore.Qt.ItemIsTristate
                                           | QtCore.Qt.ItemIsUserCheckable)
                        topicItem.setText(0, topic['name'])
                        topicItem.setCheckState(0, checkStatus)
                        topicItem.setIcon(0, QIcon(":img/mod.discuss.svg"))
                        totalFiles += 1
                elif recource['mod'] in [
                        'url', 'resource', 'assign', 'page', 'videos'
                ]:
                    recourceItem = QTreeWidgetItem(sectionItem)
                    recourceItem.setFlags(recourceItem.flags()
                                          | QtCore.Qt.ItemIsTristate
                                          | QtCore.Qt.ItemIsUserCheckable)
                    recourceItem.setText(0, recource['name'])
                    recourceItem.setCheckState(0, checkStatus)
                    recourceItem.setIcon(
                        0, QIcon(":img/mod." + recource['mod'] + ".svg"))
                    totalFiles += 1
                elif recource['mod'] == 'folder':
                    folderItem = QTreeWidgetItem(sectionItem)
                    folderItem.setFlags(folderItem.flags()
                                        | QtCore.Qt.ItemIsTristate
                                        | QtCore.Qt.ItemIsUserCheckable)
                    folderItem.setText(0, recource['name'])
                    folderItem.setCheckState(0, checkStatus)
                    folderItem.setIcon(0, QIcon(":img/mod.folder.svg"))
                    for file in recource['data']:
                        fileItem = QTreeWidgetItem(folderItem)
                        fileItem.setFlags(fileItem.flags()
                                          | QtCore.Qt.ItemIsTristate
                                          | QtCore.Qt.ItemIsUserCheckable)
                        fileItem.setText(0, file['name'])
                        fileItem.setCheckState(0, checkStatus)
                        fileItem.setIcon(0, QIcon(":img/mod.resource.svg"))
                        totalFiles += 1
        courseItem.removeChild(courseItem.child(0))
        tStop = time.time()
        if self.config['dev'].getboolean('showloadtime'):
            self.print(
                string._(
                    'Load course %s in %.3f sec, total has %d resource(s)') %
                (courseItem.text(0), tStop - tStart, totalFiles))

    def showFileList(self):
        self.btn_StartBackup.setEnabled(False)
        courseIndex = 0
        for courseItem in [
                self.CourseTreeListRoot.child(i)
                for i in range(self.CourseTreeListRoot.childCount())
        ]:
            courseIndex += 1
            self.signal_processbar_value.emit(courseIndex)
            courseData = self.FileTree[courseItem.text(0)]
            if courseItem.checkState(0) != QtCore.Qt.Unchecked:
                for sectionItem in [
                        courseItem.child(i)
                        for i in range(courseItem.childCount())
                ]:
                    sectionItemName = sectionItem.text(0)
                    if sectionItemName == string._(
                            'There has no resource to download.'):
                        continue
                    sectionData = \
                    [courseData[i] for i in range(len(courseData)) if courseData[i]['section'] == sectionItemName][0]
                    if sectionItem.checkState(0) != QtCore.Qt.Unchecked:
                        for modItem in [
                                sectionItem.child(i)
                                for i in range(sectionItem.childCount())
                        ]:
                            modItemName = modItem.text(0)
                            modData = [
                                sectionData['mods'][i]
                                for i in range(len(sectionData['mods'])) if
                                sectionData['mods'][i]['name'] == modItemName
                            ][0]
                            if modItem.checkState(0) != QtCore.Qt.Unchecked:
                                if modData['mod'] == 'forum':
                                    for topicItem in [
                                            modItem.child(i) for i in range(
                                                modItem.childCount())
                                    ]:
                                        if topicItem.checkState(
                                                0) == QtCore.Qt.Checked:
                                            topicName = topicItem.text(0)
                                            resource = [
                                                modData['data'][i]
                                                for i in range(
                                                    len(modData['data']))
                                                if modData['data'][i]['name']
                                                == topicName
                                            ][0]
                                            self.signal_appendDownloadList.emit(
                                                resource)
                                elif modData['mod'] in [
                                        'resource', 'url', 'assign', 'page',
                                        'videos'
                                ]:
                                    if modItem.checkState(
                                            0) == QtCore.Qt.Checked:
                                        self.signal_appendDownloadList.emit(
                                            modData)
                                elif modData['mod'] == 'folder':
                                    for fileItem in [
                                            modItem.child(i) for i in range(
                                                modItem.childCount())
                                    ]:
                                        if fileItem.checkState(
                                                0) == QtCore.Qt.Checked:
                                            fileName = fileItem.text(0)
                                            resource = [
                                                modData['data'][i]
                                                for i in range(
                                                    len(modData['data']))
                                                if modData['data'][i]['name']
                                                == fileName
                                            ][0]
                                            self.signal_appendDownloadList.emit(
                                                resource)
        self.retryTimes = 0
        self.failedList = []
        self.retryList = []
        self.success = 0
        self.failed = 0
        time.sleep(0.5)
        reqs = threadpool.makeRequests(self.startDownload,
                                       range(len(self.fileList)))
        for req in reqs:
            self.DownloadPool.putRequest(req)
        if len(self.fileList) == 0:
            self.btn_StartBackup.setEnabled(True)
        else:
            self.statusProcessBar.setFormat(
                string._('Downloading...') + "(%v/" +
                "%d)" % len(self.fileList))
            self.statusProcessBar.setMaximum(len(self.fileList))

    def startRetry(self):
        if self.retryAfter == 0:
            self.retryTimes += 1
            self.retryTimer.stop()
            self.retryList = self.failedList
            self.failedList = []
            reqs = threadpool.makeRequests(self.startDownload, self.retryList)
            for req in reqs:
                self.DownloadPool.putRequest(req)
            self.statusProcessBar.setFormat(
                string._('Downloading...') + "(%v/" +
                "%d)" % len(self.retryList))
            self.statusProcessBar.setMaximum(len(self.retryList))
        else:
            self.retryAfter -= 1
            self.signal_setStartBackupBtn.emit(
                string._('Download will retry after %d sec.') %
                self.retryAfter, False)

    def appendItemToDownloadList(self, Item):
        self.fileList.append(Item)
        mod = Item['mod']
        if '/' in mod:
            mod = mod.split('/')[1]
        row_count = self.StatusTable.rowCount()
        self.StatusTable.insertRow(row_count)
        self.StatusTable.setItem(row_count, 0, QTableWidgetItem(Item['name']))
        self.StatusTable.setItem(row_count, 1, QTableWidgetItem(Item['path']))
        self.StatusTable.setItem(
            row_count, 2,
            QTableWidgetItem(QIcon(':img/mod.%s.svg' % mod), Item['mod']))
        self.StatusTable.setItem(row_count, 3, QTableWidgetItem('等待中...'))

    def startDownload(self, idx):
        if idx < len(self.fileList):
            self.btn_StartBackup.setText(
                string._('Downloading...(%d/%d)') % (idx, len(self.fileList)))
            if self.retryTimes != 0:
                indexInRetryList = 0
                for ele in self.retryList:
                    indexInRetryList += 1
                    if ele == idx:
                        break
                self.btn_StartBackup.setText(
                    string._('Downloading...(%d/%d)') %
                    (indexInRetryList, len(self.retryList)))
            self.signal_processbar_value.emit(idx)
            self.print(string._('Start to download %dth file') % (idx + 1))
            self.web.DownloadFile(idx, self.fileList[idx])
            time.sleep(0.5)

    def StartBackup(self):
        self.fileList = []
        self.StatusTable.setRowCount(0)
        self.statusProcessBar.setFormat(
            string._('Loading file list') + "(%v" +
            "/%d)" % self.CourseTreeListRoot.childCount())
        self.statusProcessBar.setMaximum(self.CourseTreeListRoot.childCount())
        self.showFileList()

    def showInformation(self):
        QMessageBox.about(self, string._('About'),
                          string._('tool Information') % self.version)

    def TestiLearnConnection(self):
        self.statusbar.showMessage(
            string._('Testing connection with iLearn2...'))
        self.label_iLearn.setText(string._('Connecting...'))
        if self.web.TestConnection():  # ==Ture
            self.statusbar.showMessage(string._('Connect to iLearn2 success!'))
            self.label_iLearn.setText(string._('Connect success!'))
        else:
            self.statusbar.showMessage(string._('Can not connect to iLearn2!'))
            self.label_iLearn.setText(string._('Connect failed!'))

    def readSetting(self):
        try:
            self.config.read('setting.ini', encoding='utf-8')
            OPTION = self.config.get('User', 'userealfilename')
            OPTION = self.config.get('User', 'language')
            OPTION = self.config.get('User', 'retrytimes')
            OPTION = self.config.get('User', 'secondbetweenretry')
            OPTION = self.config.get('dev', 'nid')
            OPTION = self.config.get('dev', 'pass')
            OPTION = self.config.get('dev', 'showloadtime')
        except:
            self.config['User'] = {}
            self.config['User']['userealfilename'] = 'False'
            self.config['User']['language'] = '繁體中文'
            self.config['dev'] = {}
            self.config['dev']['nid'] = ''
            self.config['dev']['pass'] = ''
            self.config['dev']['autologin'] = '******'
            self.config['dev']['showloadtime'] = 'False'
            self.config['User']['retrytimes'] = '3'
            self.config['User']['secondbetweenretry'] = '5'
            with open('setting.ini', 'w', encoding='utf-8') as configfile:
                self.config.write(configfile)

    def restart(self):
        subprocess.Popen("iLearnBackupTool")
        self.close()
Пример #6
0
 def _set_check_state_to_tree(self, item: QTreeWidgetItem, check_state: Qt.CheckState):
     for i in range(item.childCount()):
         child = item.child(i)
         child.setCheckState(0, check_state)
         self._set_check_state_to_tree(child, check_state)
Пример #7
0
class OutTab(QWidget):
    def __init__(self, parent=None):
        super(OutTab, self).__init__(parent)

        lableFilePath = QLabel("物料文件:")
        self.editFilePath = QLineEdit()
        self.buttonImport = QPushButton("导入")
        self.buttonLocate = QPushButton("定位")
        self.buttonOut = QPushButton("出库")

        lableSapIDList = QLabel("物料列表:")
        self.tree = QTreeWidget()
        self.tree.setColumnCount(3)
        self.tree.setHeaderLabels(['物料ID','标签ID','状态'])

        self.buttonImport.clicked.connect(self.importSapIDs)
        self.buttonLocate.clicked.connect(self.Locate)
        self.buttonOut.clicked.connect(self.removeID)

        mainLayout = QGridLayout()
        mainLayout.addWidget(lableFilePath, 0, 0)
        mainLayout.addWidget(self.editFilePath, 0, 1)
        mainLayout.addWidget(self.buttonImport, 0, 2)
        mainLayout.addWidget(lableSapIDList, 1, 0, Qt.AlignTop)
        mainLayout.addWidget(self.buttonLocate, 1, 2, Qt.AlignTop)
        mainLayout.addWidget(self.buttonOut, 2, 2, Qt.AlignTop)
        mainLayout.addWidget(self.tree, 1, 1, 9, 1 )

        self.setLayout(mainLayout)
        #self.finder = Controler.Controler()

    #从指定的物料清单文件中解析出物料编码列表
    def GetSapIDs(self,strFilePath):
        listID = []
        with open(strFilePath, 'r') as f:
            strAll = f.read()

        listTemp = strAll.split('\n')[3:-2]
        for x in listTemp:
            strID = re.split(r'\s+', x)[2]
            # strID = "".join(list(filter(str.isdigit, strID)))
            listID.append(strID)
        return listID

    #打开物料清单文件,解析后显示在树形控件中
    def importSapIDs(self):
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self,
            "QFileDialog.getOpenFileName()", self.editFilePath.text(),
            "Text Files (*.txt)", options=options)
        if not fileName: return

        self.editFilePath.setText(fileName)
        listID = self.GetSapIDs(fileName)
        iLength = len(listID)
        feeders = Feeders.Feeders()
        self.tree.clear()
        self.root = QTreeWidgetItem(self.tree)
        self.root.setText(0, fileName.split('/')[-1])
        for i in range(iLength):
            SapID = listID[i]
            RfID = feeders.findFeeder(SapID)
            id = QTreeWidgetItem(self.root)
            id.setText(0, SapID)
            id.setText(1, RfID)
            id.setText(2, 'N/A')
            id.setCheckState(0, 0)

        self.tree.expandAll()
        self.tree.resizeColumnToContents(0)
        self.root.sortChildren(1, 0)
        self.AutoSelect()

    def AutoSelect(self):
        for i in range(self.root.childCount()):
            child = self.root.child(i)
            if child.text(1) != 'N/A':
                child.setCheckState(0, 2)

    def Locate(self):
        for i in range(self.root.childCount()):
            child = self.root.child(i)
            if child.checkState(0):
                if child.text(1) == 'N/A':
                    child.setText(2, '无法定位')
                else:
                    child.setText(2, '已定位')
                    child.setSelected(True)
                    QApplication.processEvents()
                    strRfID = child.text(1)
                    #self.finder.FindID(strRfID)
                    time.sleep(0.2)
                    child.setSelected(False)
                    child.setText(2, '待定位')

    def removeID(self):
        flag = True
        while flag == True:
            flag = False
            for i in range(self.root.childCount()):
                child = self.root.child(i)
                if child.checkState(0):
                    feeders = Feeders.Feeders()
                    strRfID = child.text(1)
                    #self.finder.FindID(strRfID, False)
                    self.root.removeChild(child)
                    feeders.remove(strRfID)
                    flag = True
                    break

        self.AutoSelect()
Пример #8
0
    def add_children(self, top_lvl_wid: QTreeWidgetItem):
        frmMain = self.frmMain
        model = self.enh_model
        idx_NAME = self.get_header_index(HEADER_NAME)
        idx_GEAR_TYPE = self.get_header_index(HEADER_GEAR_TYPE)
        idx_BASE_ITEM_COST = self.get_header_index(HEADER_BASE_ITEM_COST)
        idx_TARGET = self.get_header_index(HEADER_TARGET)
        master_gw = self.itemWidget(top_lvl_wid, idx_NAME)
        this_gear = master_gw.gear
        these_lvls = this_gear.guess_target_lvls(intersect=None, excludes=None)

        prunes = []

        for i in range(0, top_lvl_wid.childCount()):
            child = top_lvl_wid.child(0)
            child_gw: GearWidget = self.itemWidget(child, idx_NAME)
            top_lvl_wid.takeChild(0)

            if not child_gw.chkInclude.isChecked():
                prunes.append(child_gw.gear.enhance_lvl)
            try:
                child_gw.chkInclude.disconnect()
            except TypeError:
                pass

        def chk_click(state):
            spinner = self.sender()
            lvl = spinner.__dict__['lvl']
            if state == Qt.Unchecked:
                try:
                    this_gear.target_lvls.remove(lvl)
                except ValueError:
                    pass
            else:
                if lvl not in this_gear.target_lvls:
                    this_gear.target_lvls.append(lvl)
            #self.model.invalidate_enahce_list()

        for lvl in these_lvls:
            twi = QTreeWidgetItem(top_lvl_wid, [''] * self.columnCount())
            _gear = this_gear.duplicate()
            _gear.set_enhance_lvl(lvl)
            this_check_state = Qt.Unchecked if lvl in prunes or lvl not in this_gear.target_lvls else Qt.Checked
            this_gw = GearWidget(_gear,
                                 model,
                                 edit_able=False,
                                 display_full_name=False,
                                 check_state=this_check_state)
            this_gw.sig_error.connect(self.frmMain.sig_show_message)
            this_gw.sig_layout_changed.connect(
                lambda: self.resizeColumnToContents(0))
            this_gw.chkInclude.__dict__['lvl'] = lvl
            this_gw.chkInclude.stateChanged.connect(chk_click)
            self.setItemWidget(twi, idx_NAME, this_gw)
            top_lvl_wid.addChild(twi)
            gt_txt = master_gw.cmbType.currentText()
            twi.setText(idx_GEAR_TYPE, gt_txt)
            twi.setText(idx_BASE_ITEM_COST, top_lvl_wid.text(2))
            twi.setText(idx_TARGET, _gear.enhance_lvl)
            twi.setForeground(idx_GEAR_TYPE, Qt.black)
            twi.setBackground(idx_GEAR_TYPE,
                              gt_str_to_q_color(gt_txt).lighter())
Пример #9
0
class DeviceDialog(QDialog, Ui_DeviceDialog):
    """
        Function and Event handling class for the Ui_DeviceDialog.
    """
    qtcb_enumerate = pyqtSignal(str, str, str, type((0,)), type((0,)), int, int)
    qtcb_connected = pyqtSignal(int)

    def __init__(self, parent):
        QDialog.__init__(self, parent, get_modeless_dialog_flags())

        self._logger_window = parent

        self.device_name_by_device_identifier = {}

        for display_name, device_spec in device_specs.items():
            self.device_name_by_device_identifier[device_spec['class'].DEVICE_IDENTIFIER] = display_name

        self.qtcb_enumerate.connect(self.cb_enumerate)
        self.qtcb_connected.connect(self.cb_connected)

        self.host = None
        self.port = None
        self.secret = None

        self.ipcon = IPConnection()
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
                                     self.qtcb_connected.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
                                     self.qtcb_enumerate.emit)

        self.setupUi(self)

        self.btn_add_device.clicked.connect(self.btn_add_device_clicked)
        self.btn_refresh.clicked.connect(self.btn_refresh_clicked)
        self.btn_close.clicked.connect(self.btn_close_clicked)
        self.tree_widget.itemActivated.connect(self.add_item)

        self.connected_uids = []
        self.available_item = QTreeWidgetItem(['No devices available'])
        self.supported_item = QTreeWidgetItem(['Supported devices'])

        self.tree_widget.addTopLevelItem(self.available_item)
        self.tree_widget.addTopLevelItem(self.supported_item)

        for device_name in device_specs:
            self.supported_item.addChild(QTreeWidgetItem([device_name]))

        self.supported_item.sortChildren(0, Qt.AscendingOrder)
        self.supported_item.setExpanded(True)

    def cb_connected(self, connect_reason):
        self.tree_widget.clearSelection()
        self.available_item.takeChildren()
        self.available_item.setExpanded(True)
        self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port))

        self.connected_uids = []

        if self.secret != None:
            self.ipcon.set_auto_reconnect(False) # don't auto-reconnect on authentication error

            try:
                self.ipcon.authenticate(self.secret)
            except:
                try:
                    self.ipcon.disconnect()
                except:
                    pass

                if connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
                    extra = ' after auto-reconnect'
                else:
                    extra = ''

                self.available_item.setText(0, 'Could not authenticate' + extra)
                return

            self.ipcon.set_auto_reconnect(True)

        try:
            self.ipcon.enumerate()
        except:
            pass

    def cb_enumerate(self, uid, connected_uid, position,
                     hardware_version, firmware_version,
                     device_identifier, enumeration_type):
        if enumeration_type in [IPConnection.ENUMERATION_TYPE_AVAILABLE,
                                IPConnection.ENUMERATION_TYPE_CONNECTED]:
            if uid not in self.connected_uids:
                display_name = self.device_name_by_device_identifier.get(device_identifier)

                if display_name != None:
                    self.connected_uids.append(uid)
                    self.available_item.addChild(QTreeWidgetItem(['{0} [{1}]'.format(display_name, uid)]))
                    self.available_item.setText(0, 'Devices available at {0}:{1}'.format(self.host, self.port))
                    self.available_item.sortChildren(0, Qt.AscendingOrder)
        else:
            if uid in self.connected_uids:
                self.connected_uids.remove(uid)

            for i in range(self.available_item.childCount()):
                child = self.available_item.child(i)

                if '[{0}]'.format(uid) in child.text(0):
                    self.available_item.takeChild(i)
                    break

            if self.available_item.childCount() == 0:
                self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port))

    def btn_add_device_clicked(self):
        for item in self.tree_widget.selectedItems():
            if item == self.available_item or item == self.supported_item:
                continue

            self._logger_window.add_device_to_tree(self.create_device_config(item.text(0)))

    def btn_refresh_clicked(self):
        try:
            self.ipcon.disconnect()
        except:
            pass

        self.tree_widget.clearSelection()
        self.available_item.takeChildren()
        self.available_item.setExpanded(True)

        self.connected_uids = []
        self.host = self._logger_window.combo_host.currentText()
        self.port = self._logger_window.spin_port.value()
        if self._logger_window.check_authentication.isChecked():
            self.secret = self._logger_window.edit_secret.text()

            try:
                self.secret.encode('ascii')
            except:
                self.secret = None
                self.available_item.setText(0, 'Authentication secret cannot contain non-ASCII characters')
                return
        else:
            self.secret = None

        try:
            self.ipcon.connect(self.host, self.port)
            self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port))
        except:
            self.available_item.setText(0, 'Could not connect to {0}:{1}'.format(self.host, self.port))

    def btn_close_clicked(self):
        self.close()

    def add_item(self, item):
        if item == self.available_item or item == self.supported_item:
            return

        self._logger_window.add_device_to_tree(self.create_device_config(item.text(0)))

    def create_device_config(self, item_text):
        name, uid = Utilities.parse_device_name(item_text) # FIXME
        device_spec = device_specs[name]

        if uid == None: # FIXME
            uid = ''

        device = {
            'host': 'default',
            'name': name,
            'uid': uid,
            'values': {},
            'options': {}
        }

        for value_spec in device_spec['values']:
            device['values'][value_spec['name']] = {'interval': 0}

            if value_spec['subvalues'] != None:
                device['values'][value_spec['name']]['subvalues'] = {}

                for subvalue_name in value_spec['subvalues']:
                    device['values'][value_spec['name']]['subvalues'][subvalue_name] = True

        if device_spec['options'] != None:
            for option_spec in device_spec['options']:
                device['options'][option_spec['name']] = {'value': option_spec['default']}

        return device
Пример #10
0
class MainDialog(QDialog, FORM_CLASS):
    """The main dialog of QGIS2Web plugin."""
    items = {}

    def __init__(self, iface, parent=None):
        super(MainDialog, self).__init__(parent)
        QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface

        self.previewUrl = None
        self.layer_search_combo = None
        self.exporter_combo = None

        self.feedback = FeedbackDialog(self)
        self.feedback.setModal(True)

        stgs = QSettings()

        self.restoreGeometry(stgs.value("qgis2web/MainDialogGeometry",
                                        QByteArray(), type=QByteArray))

        self.verticalLayout_2.addStretch()
        self.horizontalLayout_6.addStretch()
        if stgs.value("qgis2web/previewOnStartup", Qt.Checked) == Qt.Checked:
            self.previewOnStartup.setCheckState(Qt.Checked)
        else:
            self.previewOnStartup.setCheckState(Qt.Unchecked)
        if (stgs.value("qgis2web/closeFeedbackOnSuccess", Qt.Checked) ==
                Qt.Checked):
            self.closeFeedbackOnSuccess.setCheckState(Qt.Checked)
        else:
            self.closeFeedbackOnSuccess.setCheckState(Qt.Unchecked)
        self.previewFeatureLimit.setText(
            stgs.value("qgis2web/previewFeatureLimit", "1000"))

        self.appearanceParams.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.preview = None
        if webkit_available:
            widget = QWebView()
            self.preview = widget
            try:
                # if os.environ["TRAVIS"]:
                self.preview.setPage(WebPage())
            except:
                print("Failed to set custom webpage")
            webview = self.preview.page()
            webview.setNetworkAccessManager(QgsNetworkAccessManager.instance())
            self.preview.settings().setAttribute(
                QWebSettings.DeveloperExtrasEnabled, True)
            self.preview.settings().setAttribute(
                QWebSettings.DnsPrefetchEnabled, True)
        else:
            widget = QTextBrowser()
            widget.setText(self.tr('Preview is not available since QtWebKit '
                                   'dependency is missing on your system'))
        self.right_layout.insertWidget(0, widget)
        self.populateConfigParams(self)
        self.populate_layers_and_groups(self)
        self.populateLayerSearch()

        writer = WRITER_REGISTRY.createWriterFromProject()
        self.setStateToWriter(writer)

        self.exporter = EXPORTER_REGISTRY.createFromProject()
        self.exporter_combo.setCurrentIndex(
            self.exporter_combo.findText(self.exporter.name()))
        self.exporter_combo.currentIndexChanged.connect(
            self.exporterTypeChanged)

        self.toggleOptions()
        if webkit_available:
            if self.previewOnStartup.checkState() == Qt.Checked:
                self.autoUpdatePreview()
            self.buttonPreview.clicked.connect(self.previewMap)
        else:
            self.buttonPreview.setDisabled(True)
        QgsProject.instance().cleared.connect(self.reject)
        self.layersTree.model().dataChanged.connect(self.populateLayerSearch)
        self.ol3.clicked.connect(self.changeFormat)
        self.leaflet.clicked.connect(self.changeFormat)
        self.buttonExport.clicked.connect(self.saveMap)
        helpText = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                "helpFile.md")
        self.helpField.setSource(QUrl.fromLocalFile(helpText))
        if webkit_available:
            self.devConsole = QWebInspector(self.preview)
            self.devConsole.setFixedHeight(0)
            self.devConsole.setObjectName("devConsole")
            self.devConsole.setPage(self.preview.page())
            self.devConsole.hide()
            self.right_layout.insertWidget(1, self.devConsole)
        self.filter = devToggleFilter()
        self.filter.devToggle.connect(self.showHideDevConsole)
        self.installEventFilter(self.filter)
        self.setModal(False)

    @pyqtSlot(bool)
    def showHideDevConsole(self, visible):
        self.devConsole.setVisible(visible)

    def changeFormat(self):
        self.autoUpdatePreview()
        self.toggleOptions()

    def exporterTypeChanged(self):
        new_exporter_name = self.exporter_combo.currentText()
        try:
            self.exporter = [
                e for e in EXPORTER_REGISTRY.getExporters()
                if e.name() == new_exporter_name][0]()
        except:
            pass

    def currentMapFormat(self):
        """
        Returns the currently selected map writer type
        """
        return self.getWriterFactory().type()

    def getWriterFactory(self):
        """
        Returns a factory to create the currently selected map writer
        """
        if self.mapFormat.checkedButton() == self.ol3:
            return OpenLayersWriter
        elif self.mapFormat.checkedButton() == self.leaflet:
            return LeafletWriter

    def createWriter(self):
        """
        Creates a writer object reflecting the current settings
        in the dialog
        """
        writer = self.getWriterFactory()()
        (writer.layers, writer.groups, writer.popup,
         writer.visible, writer.json,
         writer.cluster, writer.getFeatureInfo) = self.getLayersAndGroups()
        writer.params = self.getParameters()
        return writer

    def showErrorMessage(self, error):
        """
        Shows an error message in the preview window
        """
        html = "<html>"
        html += "<head></head>"
        html += "<style>body {font-family: sans-serif;}</style>"
        html += "<body><h1>Error</h1>"
        html += "<p>qgis2web produced an error:</p><code>"
        html += error
        html += "</code></body></html>"
        if self.preview:
            self.preview.setHtml(html)

    def showFeedbackMessage(self, title, message):
        """
        Shows a feedback message in the preview window
        """
        html = "<html>"
        html += "<head></head>"
        html += "<style>body {font-family: sans-serif;}</style>"
        html += "<body><h1>{}</h1>".format(title)
        html += "<p>{}</p>".format(message)
        html += "</body></html>"
        if self.preview:
            self.preview.setHtml(html)

    def toggleOptions(self):
        currentWriter = self.getWriterFactory()
        for param, value in specificParams.items():
            treeParam = self.appearanceParams.findItems(param,
                                                        (Qt.MatchExactly |
                                                         Qt.MatchRecursive))[0]
            if currentWriter == OpenLayersWriter:
                if value == "OL3":
                    treeParam.setDisabled(False)
                else:
                    treeParam.setDisabled(True)
            else:
                if value == "OL3":
                    treeParam.setDisabled(True)
                else:
                    treeParam.setDisabled(False)
        for option, value in specificOptions.items():
            treeOptions = self.layersTree.findItems(option,
                                                    (Qt.MatchExactly |
                                                     Qt.MatchRecursive))
            for treeOption in treeOptions:
                if currentWriter == OpenLayersWriter:
                    if value == "OL3":
                        treeOption.setDisabled(False)
                    else:
                        treeOption.setDisabled(True)
                else:
                    if value == "OL3":
                        treeOption.setDisabled(True)
                    else:
                        treeOption.setDisabled(False)

    def createPreview(self):
        writer = self.createWriter()
        return writer.write(self.iface,
                            dest_folder=utils.tempFolder()).index_file

    def shouldAutoPreview(self):
        """
        Returns a tuple, with a bool for whether the preview should
        automatically be generated, and a string for explanations
        as to why the preview cannot be automatically generated
        """
        writer = self.createWriter()
        total_features = 0
        for layer in writer.layers:
            if isinstance(layer, QgsVectorLayer):
                total_features += layer.featureCount()

        if total_features > int(self.previewFeatureLimit.text()):
            # Too many features => too slow!
            return (False, self.tr('<p>A large number of features are '
                                   'present in the map. Generating the '
                                   'preview may take some time.</p>'
                                   '<p>Click Update Preview to generate the '
                                   'preview anyway.</p>'))

        return (True, None)

    def autoUpdatePreview(self):
        """
        Triggered when a preview will be automatically generated, i.e.
        not as a result of the user manually clicking the
        Update Preview button.
        """
        (auto_preview, message) = self.shouldAutoPreview()
        if not auto_preview:
            self.showFeedbackMessage(self.tr('Preview Map'), message)
        else:
            self.previewMap()

    def previewMap(self):
        preview_file = self.createPreview()
        self.loadPreviewFile(preview_file)

    def saveMap(self):
        writer = self.createWriter()
        write_folder = self.exporter.exportDirectory()
        if not write_folder:
            return

        self.feedback.reset()
        self.feedback.show()
        results = writer.write(self.iface,
                               dest_folder=write_folder,
                               feedback=self.feedback)
        self.feedback.showFeedback('Success')
        if self.closeFeedbackOnSuccess.checkState() == Qt.Checked:
            self.feedback.close()
        result = self.exporter.postProcess(results, feedback=self.feedback)
        if result and (not os.environ.get('CI') and
                       not os.environ.get('TRAVIS')):
            webbrowser.open_new_tab(self.exporter.destinationUrl())

    def populate_layers_and_groups(self, dlg):
        """Populate layers on QGIS into our layers and group tree view."""
        root_node = QgsProject.instance().layerTreeRoot()
        tree_groups = []
        tree_layers = root_node.findLayers()
        self.layers_item = QTreeWidgetItem()
        self.layers_item.setText(0, "Layers and Groups")
        self.layersTree.setColumnCount(3)

        for tree_layer in tree_layers:
            layer = tree_layer.layer()
            if (layer.type() != QgsMapLayer.PluginLayer and
                    layer.customProperty("ol_layer_type") is None):
                try:
                    if layer.type() == QgsMapLayer.VectorLayer:
                        testDump = layer.renderer().dump()
                    layer_parent = tree_layer.parent()
                    if layer_parent.parent() is None:
                        item = TreeLayerItem(self.iface, layer,
                                             self.layersTree, dlg)
                        self.layers_item.addChild(item)
                    else:
                        if layer_parent not in tree_groups:
                            tree_groups.append(layer_parent)
                except:
                    QgsMessageLog.logMessage(traceback.format_exc(),
                                             "qgis2web",
                                             level=Qgis.Critical)

        for tree_group in tree_groups:
            group_name = tree_group.name()
            group_layers = [
                tree_layer.layer() for tree_layer in tree_group.findLayers()]
            item = TreeGroupItem(group_name, group_layers, self.layersTree)
            self.layers_item.addChild(item)

        self.layersTree.addTopLevelItem(self.layers_item)
        self.layersTree.expandAll()
        self.layersTree.resizeColumnToContents(0)
        self.layersTree.resizeColumnToContents(1)
        for i in range(self.layers_item.childCount()):
            item = self.layers_item.child(i)
            if item.checkState(0) != Qt.Checked:
                item.setExpanded(False)

    def populateLayerSearch(self):
        self.layer_search_combo.clear()
        self.layer_search_combo.addItem("None")
        (layers, groups, popup, visible,
         json, cluster, getFeatureInfo) = self.getLayersAndGroups()
        for count, layer in enumerate(layers):
            if layer.type() == layer.VectorLayer:
                options = []
                fields = layer.fields()
                for f in fields:
                    fieldIndex = fields.indexFromName(unicode(f.name()))
                    editorWidget = layer.editorWidgetSetup(fieldIndex).type()
                    if editorWidget == 'Hidden':
                        continue
                    options.append(unicode(f.name()))
                for option in options:
                    displayStr = unicode(layer.name() + ": " + option)
                    self.layer_search_combo.insertItem(0, displayStr)
                    sln = utils.safeName(layer.name())
                    self.layer_search_combo.setItemData(
                        self.layer_search_combo.findText(displayStr),
                        sln + "_" + unicode(count))

    def configureExporter(self):
        self.exporter.configure()

    def populateConfigParams(self, dlg):
        """ Populates the dialog with option items and widgets """
        self.items = defaultdict(dict)
        tree = dlg.appearanceParams

        configure_export_action = QAction('...', self)
        configure_export_action.triggered.connect(self.configureExporter)

        params = getParams(configure_exporter_action=configure_export_action)
        for group, settings in params.items():
            if group != "Data export":
                item = QTreeWidgetItem()
                item.setText(0, group)
                for param, value in settings.items():
                    subitem = self.createOptionItem(tree_widget=tree,
                                                    parent_item=item,
                                                    parameter=param,
                                                    default_value=value)
                    item.addChild(subitem)
                    self.items[group][param] = subitem
                self.appearanceParams.addTopLevelItem(item)
                item.sortChildren(0, Qt.AscendingOrder)
        self.appearanceParams.expandAll()
        self.appearanceParams.resizeColumnToContents(0)
        self.appearanceParams.resizeColumnToContents(1)
        self.layer_search_combo.removeItem(1)

        # configure export params in separate tab
        exportTree = dlg.exportParams
        for group, settings in params.items():
            if group == "Data export":
                item = QTreeWidgetItem()
                item.setText(0, group)
                for param, value in settings.items():
                    subitem = self.createOptionItem(tree_widget=exportTree,
                                                    parent_item=item,
                                                    parameter=param,
                                                    default_value=value)
                    item.addChild(subitem)
                    self.items[group][param] = subitem
                self.exportParams.addTopLevelItem(item)
                item.sortChildren(0, Qt.AscendingOrder)
        self.exportParams.expandAll()
        self.exportParams.resizeColumnToContents(0)
        self.exportParams.resizeColumnToContents(1)

    def createOptionItem(self, tree_widget, parent_item,
                         parameter, default_value):
        """create the tree item corresponding to an option parameter"""
        action = None
        if isinstance(default_value, dict):
            action = default_value['action']
            default_value = default_value['option']

        subitem = TreeSettingItem(parent_item, tree_widget,
                                  parameter, default_value, action)
        if parameter == 'Layer search':
            self.layer_search_combo = subitem.combo
        elif parameter == 'Exporter':
            self.exporter_combo = subitem.combo

        return subitem

    def setStateToWriter(self, writer):
        """
        Sets the dialog state to match the specified writer
        """
        self.selectMapFormat(writer)
        self.setStateToParams(writer.params)

    def setStateToParams(self, params):
        """
        Sets the dialog state to match the specified parameters
        """
        for group, settings in self.items.items():
            for param, item in settings.items():
                value = params[group][param]
                item.setValue(value)

    def selectMapFormat(self, writer):
        """
        Updates dialog state to match the specified writer format
        """
        self.ol3.setChecked(isinstance(writer, OpenLayersWriter))
        self.leaflet.setChecked(isinstance(writer, LeafletWriter))

    def loadPreviewFile(self, file):
        """
        Loads a web based preview from a local file path
        """
        self.previewUrl = QUrl.fromLocalFile(file)
        if self.preview:
            self.preview.settings().clearMemoryCaches()
            self.preview.setUrl(self.previewUrl)

    def getParameters(self):
        parameters = defaultdict(dict)
        for group, settings in self.items.items():
            for param, item in settings.items():
                if param in ('Widget Icon', 'Widget Background'):
                    parameters[group][param] = item._value.color().name()
                else:
                    parameters[group][param] = item.value()
                    if param == "Layer search":
                        parameters["Appearance"]["Search layer"] = (
                            self.layer_search_combo.itemData(
                                self.layer_search_combo.currentIndex()))

        return parameters

    def saveParameters(self):
        """
        Saves current dialog state to project
        """
        WRITER_REGISTRY.saveWriterToProject(self.createWriter())
        EXPORTER_REGISTRY.writeToProject(self.exporter)

    def getLayersAndGroups(self):
        layers = []
        groups = {}
        popup = []
        visible = []
        json = []
        cluster = []
        getFeatureInfo = []
        for i in range(self.layers_item.childCount()):
            item = self.layers_item.child(i)
            if isinstance(item, TreeLayerItem):
                if item.checkState(0) == Qt.Checked:
                    layers.append(item.layer)
                    popup.append(item.popup)
                    visible.append(item.visible)
                    json.append(item.json)
                    cluster.append(item.cluster)
                    getFeatureInfo.append(item.getFeatureInfo)
            else:
                group = item.name
                groupLayers = []
                if item.checkState(0) != Qt.Checked:
                    continue
                for layer in item.layers:
                    groupLayers.append(layer)
                    layers.append(layer)
                    popup.append({})
                    if item.visible:
                        visible.append(True)
                    else:
                        visible.append(False)
                    if hasattr(item, "json") and item.json:
                        json.append(True)
                    else:
                        json.append(False)
                    if hasattr(item, "cluster") and item.cluster:
                        cluster.append(True)
                    else:
                        cluster.append(False)
                    if hasattr(item, "getFeatureInfo") and item.getFeatureInfo:
                        getFeatureInfo.append(True)
                    else:
                        getFeatureInfo.append(False)
                groups[group] = groupLayers[::-1]

        return (layers[::-1],
                groups,
                popup[::-1],
                visible[::-1],
                json[::-1],
                cluster[::-1],
                getFeatureInfo[::-1])

    def reject(self):
        self.saveParameters()
        (layers, groups, popup, visible,
         json, cluster, getFeatureInfo) = self.getLayersAndGroups()
        try:
            for layer, pop, vis in zip(layers, popup, visible):
                attrDict = {}
                for attr in pop:
                    attrDict['attr'] = pop[attr]
                    layer.setCustomProperty("qgis2web/popup/" + attr,
                                            pop[attr])
                layer.setCustomProperty("qgis2web/Visible", vis)
        except:
            pass

        QSettings().setValue(
            "qgis2web/MainDialogGeometry", self.saveGeometry())

        QSettings().setValue("qgis2web/previewOnStartup",
                             self.previewOnStartup.checkState())
        QSettings().setValue("qgis2web/closeFeedbackOnSuccess",
                             self.closeFeedbackOnSuccess.checkState())
        QSettings().setValue("qgis2web/previewFeatureLimit",
                             self.previewFeatureLimit.text())

        QDialog.close(self)

    def closeEvent(self, event):
        if self.devConsole or self.devConsole.isVisible() and self.preview:
            del self.devConsole
            del self.preview

        self.reject()
        event.accept()
Пример #11
0
    def __init__(self, dialog):
        super(Shortcuts, self).__init__(dialog)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.scheme = SchemeSelector(self)
        layout.addWidget(self.scheme)
        self.searchEntry = LineEdit()
        self.searchEntry.setPlaceholderText(_("Search..."))
        layout.addWidget(self.searchEntry)
        self.tree = QTreeWidget(self)
        self.tree.setHeaderLabels([_("Command"), _("Shortcut")])
        self.tree.setRootIsDecorated(False)
        self.tree.setColumnCount(2)
        self.tree.setAllColumnsShowFocus(True)
        self.tree.setAnimated(True)
        layout.addWidget(self.tree)

        self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '')
        layout.addWidget(self.edit)

        # signals
        self.searchEntry.textChanged.connect(self.updateFilter)
        self.scheme.currentChanged.connect(self.slotSchemeChanged)
        self.scheme.changed.connect(self.changed)
        self.tree.currentItemChanged.connect(self.slotCurrentItemChanged)
        self.tree.itemDoubleClicked.connect(self.editCurrentItem)
        self.edit.clicked.connect(self.editCurrentItem)

        # make a dict of all actions with the actions as key and the names as
        # value, with the collection prepended (for loading/saving)
        win = dialog.parent()
        allactions = {}
        for collection in actioncollectionmanager.manager(win).actionCollections():
            for name, action in collection.actions().items():
                allactions[action] = (collection, name)

        # keep a list of actions not in the menu structure
        left = list(allactions.keys())

        def add_actions(menuitem, actions):
            """Add actions to a QTreeWidgetItem."""
            for a in actions:
                if a.menu():
                    item = build_menu_item(a)
                    if item.childCount():
                        menuitem.addChild(item)
                elif a in left:
                    left.remove(a)
                    menuitem.addChild(ShortcutItem(a, *allactions[a]))
            menuitem.setFlags(Qt.ItemIsEnabled) # disable selection

        def build_menu_item(action):
            """Return a QTreeWidgetItem with children for all the actions in the submenu."""
            menuitem = QTreeWidgetItem()
            text = qutil.removeAccelerator(action.text())
            menuitem.setText(0, _("Menu {name}").format(name=text))
            add_actions(menuitem, action.menu().actions())
            return menuitem

        # present the actions nicely ordered as in the menus
        for a in win.menuBar().actions():
            menuitem = build_menu_item(a)
            if menuitem.childCount():
                self.tree.addTopLevelItem(menuitem)

        # sort leftover actions
        left.sort(key=lambda i: i.text())

        # show actions that are left, grouped by collection
        titlegroups = {}
        for a in left[:]: # copy
            collection, name = allactions[a]
            if collection.title():
                titlegroups.setdefault(collection.title(), []).append(a)
                left.remove(a)
        for title in sorted(titlegroups):
            item = QTreeWidgetItem(["{0}:".format(title)])
            for a in titlegroups[title]:
                item.addChild(ShortcutItem(a, *allactions[a]))
            self.tree.addTopLevelItem(item)
            item.setFlags(Qt.ItemIsEnabled) # disable selection

        # show other actions that were not in the menus
        item = QTreeWidgetItem([_("Other commands:")])
        for a in left:
            if a.text() and not a.menu():
                item.addChild(ShortcutItem(a, *allactions[a]))
        if item.childCount():
            self.tree.addTopLevelItem(item)
            item.setFlags(Qt.ItemIsEnabled) # disable selection

        self.tree.expandAll()

        item = self.tree.topLevelItem(0).child(0)
        if _lastaction:
            # find the previously selected item
            for i in self.items():
                if i.name == _lastaction:
                    item = i
                    break
        self.tree.setCurrentItem(item)
        self.tree.resizeColumnToContents(0)
Пример #12
0
 def __init__(self, dialog):
     super(Shortcuts, self).__init__(dialog)
     
     layout = QVBoxLayout()
     layout.setContentsMargins(0, 0, 0, 0)
     self.setLayout(layout)
     
     self.scheme = SchemeSelector(self)
     layout.addWidget(self.scheme)
     self.tree = QTreeWidget(self)
     self.tree.setHeaderLabels([_("Command"), _("Shortcut")])
     self.tree.setRootIsDecorated(False)
     self.tree.setColumnCount(2)
     self.tree.setAllColumnsShowFocus(True)
     self.tree.setAnimated(True)
     layout.addWidget(self.tree)
     
     self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '')
     layout.addWidget(self.edit)
     
     # signals
     self.scheme.currentChanged.connect(self.slotSchemeChanged)
     self.scheme.changed.connect(self.changed)
     self.tree.currentItemChanged.connect(self.slotCurrentItemChanged)
     self.tree.itemDoubleClicked.connect(self.editCurrentItem)
     self.edit.clicked.connect(self.editCurrentItem)
     
     # make a dict of all actions with the actions as key and the names as
     # value, with the collection prepended (for loading/saving)
     win = dialog.parent()
     allactions = {}
     for collection in actioncollectionmanager.manager(win).actionCollections():
         for name, action in collection.actions().items():
             allactions[action] = (collection, name)
     
     # keep a list of actions not in the menu structure
     left = list(allactions.keys())
     
     def add_actions(menuitem, actions):
         """Add actions to a QTreeWidgetItem."""
         for a in actions:
             if a.menu():
                 item = build_menu_item(a)
                 if item.childCount():
                     menuitem.addChild(item)
             elif a in left:
                 left.remove(a)
                 menuitem.addChild(ShortcutItem(a, *allactions[a]))
         menuitem.setFlags(Qt.ItemIsEnabled) # disable selection
         
     def build_menu_item(action):
         """Return a QTreeWidgetItem with children for all the actions in the submenu."""
         menuitem = QTreeWidgetItem()
         text = qutil.removeAccelerator(action.text())
         menuitem.setText(0, _("Menu {name}").format(name=text))
         add_actions(menuitem, action.menu().actions())
         return menuitem
     
     # present the actions nicely ordered as in the menus
     for a in win.menuBar().actions():
         menuitem = build_menu_item(a)
         if menuitem.childCount():
             self.tree.addTopLevelItem(menuitem)
     
     # sort leftover actions
     left.sort(key=lambda i: i.text())
     
     # show actions that are left, grouped by collection
     titlegroups = {}
     for a in left[:]: # copy
         collection, name = allactions[a]
         if collection.title():
             titlegroups.setdefault(collection.title(), []).append(a)
             left.remove(a)
     for title in sorted(titlegroups):
         item = QTreeWidgetItem(["{0}:".format(title)])
         for a in titlegroups[title]:
             item.addChild(ShortcutItem(a, *allactions[a]))
         self.tree.addTopLevelItem(item)
         item.setFlags(Qt.ItemIsEnabled) # disable selection
         
     # show other actions that were not in the menus
     item = QTreeWidgetItem([_("Other commands:")])
     for a in left:
         if a.text() and not a.menu():
             item.addChild(ShortcutItem(a, *allactions[a]))
     if item.childCount():
         self.tree.addTopLevelItem(item)
         item.setFlags(Qt.ItemIsEnabled) # disable selection
     
     self.tree.expandAll()
     
     item = self.tree.topLevelItem(0).child(0)
     if _lastaction:
         # find the previously selected item
         for i in self.items():
             if i.name == _lastaction:
                 item = i
                 break
     self.tree.setCurrentItem(item)
     self.tree.resizeColumnToContents(0)
Пример #13
0
 def childrens(self, item: QTreeWidgetItem):
     """Iterates through toplevelitems and returns them."""
     for i in range(item.childCount()):
         yield item.child(i)
Пример #14
0
class MainDialog(QDialog, Ui_MainDialog):

    """The main dialog of QGIS2Web plugin."""
    items = {}

    def __init__(self, iface):
        QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface

        self.previewUrl = None
        self.layer_search_combo = None
        self.exporter_combo = None

        self.feedback = FeedbackDialog(self)
        self.feedback.setModal(True)

        stgs = QSettings()

        self.restoreGeometry(stgs.value("qgis2web/MainDialogGeometry",
                                        QByteArray(), type=QByteArray))

        if stgs.value("qgis2web/previewOnStartup", Qt.Checked) == Qt.Checked:
            self.previewOnStartup.setCheckState(Qt.Checked)
        else:
            self.previewOnStartup.setCheckState(Qt.Unchecked)
        if (stgs.value("qgis2web/closeFeedbackOnSuccess", Qt.Checked) ==
                Qt.Checked):
            self.closeFeedbackOnSuccess.setCheckState(Qt.Checked)
        else:
            self.closeFeedbackOnSuccess.setCheckState(Qt.Unchecked)
        self.previewFeatureLimit.setText(
            stgs.value("qgis2web/previewFeatureLimit", "1000"))

        self.paramsTreeOL.setSelectionMode(QAbstractItemView.SingleSelection)
        self.preview = None
        if webkit_available:
            widget = QWebView()
            self.preview = widget
            try:
                # if os.environ["TRAVIS"]:
                self.preview.setPage(WebPage())
            except:
                print("Failed to set custom webpage")
            webview = self.preview.page()
            webview.setNetworkAccessManager(QgsNetworkAccessManager.instance())
            self.preview.settings().setAttribute(
                QWebSettings.DeveloperExtrasEnabled, True)
        else:
            widget = QTextBrowser()
            widget.setText(self.tr('Preview is not available since QtWebKit '
                                   'dependency is missing on your system'))
        self.right_layout.insertWidget(0, widget)
        self.populateConfigParams(self)
        self.populate_layers_and_groups(self)
        self.populateLayerSearch()

        writer = WRITER_REGISTRY.createWriterFromProject()
        self.setStateToWriter(writer)

        self.exporter = EXPORTER_REGISTRY.createFromProject()
        self.exporter_combo.setCurrentIndex(
            self.exporter_combo.findText(self.exporter.name()))
        self.exporter_combo.currentIndexChanged.connect(
            self.exporterTypeChanged)

        self.toggleOptions()
        if webkit_available:
            if self.previewOnStartup.checkState() == Qt.Checked:
                self.autoUpdatePreview()
            self.buttonPreview.clicked.connect(self.previewMap)
        else:
            self.buttonPreview.setDisabled(True)
        self.layersTree.model().dataChanged.connect(self.populateLayerSearch)
        self.ol3.clicked.connect(self.changeFormat)
        self.leaflet.clicked.connect(self.changeFormat)
        self.buttonExport.clicked.connect(self.saveMap)
        helpText = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                "helpFile.md")
        self.helpField.setSource(QUrl.fromLocalFile(helpText))
        if webkit_available:
            self.devConsole = QWebInspector(self.verticalLayoutWidget_2)
            self.devConsole.setFixedHeight(0)
            self.devConsole.setObjectName("devConsole")
            self.devConsole.setPage(self.preview.page())
            self.devConsole.hide()
            self.right_layout.insertWidget(1, self.devConsole)
        self.filter = devToggleFilter()
        self.filter.devToggle.connect(self.showHideDevConsole)
        self.installEventFilter(self.filter)
        self.setModal(False)

    @pyqtSlot(bool)
    def showHideDevConsole(self, visible):
        self.devConsole.setVisible(visible)

    def changeFormat(self):
        self.autoUpdatePreview()
        self.toggleOptions()

    def exporterTypeChanged(self):
        new_exporter_name = self.exporter_combo.currentText()
        try:
            self.exporter = [
                e for e in EXPORTER_REGISTRY.getExporters()
                if e.name() == new_exporter_name][0]()
        except:
            pass

    def currentMapFormat(self):
        """
        Returns the currently selected map writer type
        """
        return self.getWriterFactory().type()

    def getWriterFactory(self):
        """
        Returns a factory to create the currently selected map writer
        """
        if self.mapFormat.checkedButton() == self.ol3:
            return OpenLayersWriter
        elif self.mapFormat.checkedButton() == self.leaflet:
            return LeafletWriter

    def createWriter(self):
        """
        Creates a writer object reflecting the current settings
        in the dialog
        """
        writer = self.getWriterFactory()()
        (writer.layers, writer.groups, writer.popup,
         writer.visible, writer.json,
         writer.cluster, writer.getFeatureInfo) = self.getLayersAndGroups()
        writer.params = self.getParameters()
        return writer

    def showErrorMessage(self, error):
        """
        Shows an error message in the preview window
        """
        html = "<html>"
        html += "<head></head>"
        html += "<style>body {font-family: sans-serif;}</style>"
        html += "<body><h1>Error</h1>"
        html += "<p>qgis2web produced an error:</p><code>"
        html += error
        html += "</code></body></html>"
        if self.preview:
            self.preview.setHtml(html)

    def showFeedbackMessage(self, title, message):
        """
        Shows a feedback message in the preview window
        """
        html = "<html>"
        html += "<head></head>"
        html += "<style>body {font-family: sans-serif;}</style>"
        html += "<body><h1>{}</h1>".format(title)
        html += "<p>{}</p>".format(message)
        html += "</body></html>"
        if self.preview:
            self.preview.setHtml(html)

    def toggleOptions(self):
        currentWriter = self.getWriterFactory()
        for param, value in specificParams.items():
            treeParam = self.paramsTreeOL.findItems(param,
                                                    (Qt.MatchExactly |
                                                     Qt.MatchRecursive))[0]
            if currentWriter == OpenLayersWriter:
                if value == "OL3":
                    treeParam.setDisabled(False)
                else:
                    treeParam.setDisabled(True)
            else:
                if value == "OL3":
                    treeParam.setDisabled(True)
                else:
                    treeParam.setDisabled(False)
        for option, value in specificOptions.items():
            treeOptions = self.layersTree.findItems(option,
                                                    (Qt.MatchExactly |
                                                     Qt.MatchRecursive))
            for treeOption in treeOptions:
                if currentWriter == OpenLayersWriter:
                    if value == "OL3":
                        treeOption.setDisabled(False)
                    else:
                        treeOption.setDisabled(True)
                else:
                    if value == "OL3":
                        treeOption.setDisabled(True)
                    else:
                        treeOption.setDisabled(False)

    def createPreview(self):
        writer = self.createWriter()
        return writer.write(self.iface,
                            dest_folder=utils.tempFolder()).index_file

    def shouldAutoPreview(self):
        """
        Returns a tuple, with a bool for whether the preview should
        automatically be generated, and a string for explanations
        as to why the preview cannot be automatically generated
        """
        writer = self.createWriter()
        total_features = 0
        for layer in writer.layers:
            if isinstance(layer, QgsVectorLayer):
                total_features += layer.featureCount()

        if total_features > int(self.previewFeatureLimit.text()):
            # Too many features => too slow!
            return (False, self.tr('<p>A large number of features are '
                                   'present in the map. Generating the '
                                   'preview may take some time.</p>'
                                   '<p>Click Update Preview to generate the '
                                   'preview anyway.</p>'))

        return (True, None)

    def autoUpdatePreview(self):
        """
        Triggered when a preview will be automatically generated, i.e.
        not as a result of the user manually clicking the
        Update Preview button.
        """
        (auto_preview, message) = self.shouldAutoPreview()
        if not auto_preview:
            self.showFeedbackMessage(self.tr('Preview Map'), message)
        else:
            self.previewMap()

    def previewMap(self):
        preview_file = self.createPreview()
        self.loadPreviewFile(preview_file)

    def saveMap(self):
        writer = self.createWriter()
        write_folder = self.exporter.exportDirectory()
        if not write_folder:
            return

        self.feedback.reset()
        self.feedback.show()
        results = writer.write(self.iface,
                               dest_folder=write_folder,
                               feedback=self.feedback)
        self.feedback.showFeedback('Success')
        if self.closeFeedbackOnSuccess.checkState() == Qt.Checked:
            self.feedback.close()
        result = self.exporter.postProcess(results, feedback=self.feedback)
        if result and (not os.environ.get('CI') and
                       not os.environ.get('TRAVIS')):
            webbrowser.open_new_tab(self.exporter.destinationUrl())

    def populate_layers_and_groups(self, dlg):
        """Populate layers on QGIS into our layers and group tree view."""
        root_node = QgsProject.instance().layerTreeRoot()
        tree_groups = []
        tree_layers = root_node.findLayers()
        self.layers_item = QTreeWidgetItem()
        self.layers_item.setText(0, "Layers and Groups")
        self.layersTree.setColumnCount(3)

        for tree_layer in tree_layers:
            layer = tree_layer.layer()
            if (layer.type() != QgsMapLayer.PluginLayer and
                    layer.customProperty("ol_layer_type") is None):
                try:
                    if layer.type() == QgsMapLayer.VectorLayer:
                        testDump = layer.renderer().dump()
                    layer_parent = tree_layer.parent()
                    if layer_parent.parent() is None:
                        item = TreeLayerItem(self.iface, layer,
                                             self.layersTree, dlg)
                        self.layers_item.addChild(item)
                    else:
                        if layer_parent not in tree_groups:
                            tree_groups.append(layer_parent)
                except:
                    QgsMessageLog.logMessage(traceback.format_exc(),
                                             "qgis2web",
                                             level=Qgis.Critical)

        for tree_group in tree_groups:
            group_name = tree_group.name()
            group_layers = [
                tree_layer.layer() for tree_layer in tree_group.findLayers()]
            item = TreeGroupItem(group_name, group_layers, self.layersTree)
            self.layers_item.addChild(item)

        self.layersTree.addTopLevelItem(self.layers_item)
        self.layersTree.expandAll()
        self.layersTree.resizeColumnToContents(0)
        self.layersTree.resizeColumnToContents(1)
        for i in range(self.layers_item.childCount()):
            item = self.layers_item.child(i)
            if item.checkState(0) != Qt.Checked:
                item.setExpanded(False)

    def populateLayerSearch(self):
        self.layer_search_combo.clear()
        self.layer_search_combo.addItem("None")
        (layers, groups, popup, visible,
         json, cluster, getFeatureInfo) = self.getLayersAndGroups()
        for count, layer in enumerate(layers):
            if layer.type() == layer.VectorLayer:
                options = []
                fields = layer.fields()
                for f in fields:
                    fieldIndex = fields.indexFromName(unicode(f.name()))
                    editorWidget = layer.editorWidgetSetup(fieldIndex).type()
                    if editorWidget == 'Hidden':
                        continue
                    options.append(unicode(f.name()))
                for option in options:
                    displayStr = unicode(layer.name() + ": " + option)
                    self.layer_search_combo.insertItem(0, displayStr)
                    sln = utils.safeName(layer.name())
                    self.layer_search_combo.setItemData(
                        self.layer_search_combo.findText(displayStr),
                        sln + "_" + unicode(count))

    def configureExporter(self):
        self.exporter.configure()

    def populateConfigParams(self, dlg):
        """ Populates the dialog with option items and widgets """
        self.items = defaultdict(dict)
        tree = dlg.paramsTreeOL

        configure_export_action = QAction('...', self)
        configure_export_action.triggered.connect(self.configureExporter)

        params = getParams(configure_exporter_action=configure_export_action)
        for group, settings in params.items():
            item = QTreeWidgetItem()
            item.setText(0, group)
            for param, value in settings.items():
                subitem = self.createOptionItem(tree_widget=tree,
                                                parent_item=item,
                                                parameter=param,
                                                default_value=value)
                item.addChild(subitem)
                self.items[group][param] = subitem
            self.paramsTreeOL.addTopLevelItem(item)
            item.sortChildren(0, Qt.AscendingOrder)
        self.paramsTreeOL.expandAll()
        self.paramsTreeOL.resizeColumnToContents(0)
        self.paramsTreeOL.resizeColumnToContents(1)
        self.layer_search_combo.removeItem(1)

    def createOptionItem(self, tree_widget, parent_item,
                         parameter, default_value):
        """create the tree item corresponding to an option parameter"""
        action = None
        if isinstance(default_value, dict):
            action = default_value['action']
            default_value = default_value['option']

        subitem = TreeSettingItem(parent_item, tree_widget,
                                  parameter, default_value, action)
        if parameter == 'Layer search':
            self.layer_search_combo = subitem.combo
        elif parameter == 'Exporter':
            self.exporter_combo = subitem.combo

        return subitem

    def setStateToWriter(self, writer):
        """
        Sets the dialog state to match the specified writer
        """
        self.selectMapFormat(writer)
        self.setStateToParams(writer.params)

    def setStateToParams(self, params):
        """
        Sets the dialog state to match the specified parameters
        """
        for group, settings in self.items.items():
            for param, item in settings.items():
                value = params[group][param]
                item.setValue(value)

    def selectMapFormat(self, writer):
        """
        Updates dialog state to match the specified writer format
        """
        self.ol3.setChecked(isinstance(writer, OpenLayersWriter))
        self.leaflet.setChecked(isinstance(writer, LeafletWriter))

    def loadPreviewFile(self, file):
        """
        Loads a web based preview from a local file path
        """
        self.previewUrl = QUrl.fromLocalFile(file)
        if self.preview:
            self.preview.settings().clearMemoryCaches()
            self.preview.setUrl(self.previewUrl)

    def getParameters(self):
        parameters = defaultdict(dict)
        for group, settings in self.items.items():
            for param, item in settings.items():
                parameters[group][param] = item.value()
                if param == "Layer search":
                    parameters["Appearance"]["Search layer"] = (
                        self.layer_search_combo.itemData(
                            self.layer_search_combo.currentIndex()))
        return parameters

    def saveParameters(self):
        """
        Saves current dialog state to project
        """
        WRITER_REGISTRY.saveWriterToProject(self.createWriter())
        EXPORTER_REGISTRY.writeToProject(self.exporter)

    def getLayersAndGroups(self):
        layers = []
        groups = {}
        popup = []
        visible = []
        json = []
        cluster = []
        getFeatureInfo = []
        for i in range(self.layers_item.childCount()):
            item = self.layers_item.child(i)
            if isinstance(item, TreeLayerItem):
                if item.checkState(0) == Qt.Checked:
                    layers.append(item.layer)
                    popup.append(item.popup)
                    visible.append(item.visible)
                    json.append(item.json)
                    cluster.append(item.cluster)
                    getFeatureInfo.append(item.getFeatureInfo)
            else:
                group = item.name
                groupLayers = []
                if item.checkState(0) != Qt.Checked:
                    continue
                for layer in item.layers:
                    groupLayers.append(layer)
                    layers.append(layer)
                    popup.append({})
                    if item.visible:
                        visible.append(True)
                    else:
                        visible.append(False)
                    if hasattr(item, "json") and item.json:
                        json.append(True)
                    else:
                        json.append(False)
                    if hasattr(item, "cluster") and item.cluster:
                        cluster.append(True)
                    else:
                        cluster.append(False)
                    if hasattr(item, "getFeatureInfo") and item.getFeatureInfo:
                        getFeatureInfo.append(True)
                    else:
                        getFeatureInfo.append(False)
                groups[group] = groupLayers[::-1]

        return (layers[::-1],
                groups,
                popup[::-1],
                visible[::-1],
                json[::-1],
                cluster[::-1],
                getFeatureInfo[::-1])

    def reject(self):
        self.saveParameters()
        (layers, groups, popup, visible,
         json, cluster, getFeatureInfo) = self.getLayersAndGroups()
        for layer, pop, vis in zip(layers, popup, visible):
            attrDict = {}
            for attr in pop:
                attrDict['attr'] = pop[attr]
                layer.setCustomProperty("qgis2web/popup/" + attr, pop[attr])
            layer.setCustomProperty("qgis2web/Visible", vis)

        QSettings().setValue(
            "qgis2web/MainDialogGeometry", self.saveGeometry())

        QSettings().setValue("qgis2web/previewOnStartup",
                             self.previewOnStartup.checkState())
        QSettings().setValue("qgis2web/closeFeedbackOnSuccess",
                             self.closeFeedbackOnSuccess.checkState())
        QSettings().setValue("qgis2web/previewFeatureLimit",
                             self.previewFeatureLimit.text())

        QDialog.close(self)

    def closeEvent(self, event):
        if self.devConsole or self.devConsole.isVisible() and self.preview:
            del self.devConsole
            del self.preview

        self.reject()
        event.accept()
Пример #15
0
 def _remove_all_children(self, parent: QTreeWidgetItem):
     while parent.childCount() > 0:
         parent.removeChild(parent.child(0))
Пример #16
0
class RestoreDialog(widgets.dialog.Dialog):
    def __init__(self, parent=None):
        super(RestoreDialog, self).__init__(parent)
        self.messageLabel().setWordWrap(True)
        userguide.addButton(self.buttonBox(), "snippets")
        self.tree = QTreeWidget(headerHidden=True, rootIsDecorated=False)
        self.setMainWidget(self.tree)
        
        self.deletedItem = QTreeWidgetItem(self.tree)
        self.deletedItem.setFlags(Qt.ItemIsUserCheckable)
        self.changedItem = QTreeWidgetItem(self.tree)
        self.changedItem.setFlags(Qt.ItemIsUserCheckable)
        self.tree.itemChanged.connect(self.slotItemChanged)
        
        app.translateUI(self)
        app.languageChanged.connect(self.populate)
        self.accepted.connect(self.updateSnippets)
        qutil.saveDialogSize(self, "snippettool/restoredialog/size")
    
    def translateUI(self):
        self.setWindowTitle(
            app.caption(_("dialog title", "Restore Built-in Snippets")))
        self.setMessage(_(
            "This dialog allows you to recover built-in snippets that have "
            "been changed or deleted. Check the snippets you want to recover "
            "and click the button \"Restore Checked Snippets.\""))
        self.button("ok").setText(_("Restore Checked Snippets"))
        self.deletedItem.setText(0, _("Deleted Snippets"))
        self.changedItem.setText(0, _("Changed Snippets"))
        
    def populate(self):
        """Puts the deleted/changed snippets in the tree."""
        self.deletedItem.takeChildren()
        self.deletedItem.setExpanded(True)
        self.deletedItem.setCheckState(0, Qt.Unchecked)
        self.changedItem.takeChildren()
        self.changedItem.setExpanded(True)
        self.changedItem.setCheckState(0, Qt.Unchecked)
        
        builtins = list(builtin.builtin_snippets)
        builtins.sort(key = snippets.title)
        
        names = frozenset(snippets.names())
        
        for name in builtins:
            if name in names:
                if snippets.isoriginal(name):
                    continue
                parent = self.changedItem
            else:
                parent = self.deletedItem
            
            item = QTreeWidgetItem(parent)
            item.name = name
            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            item.setCheckState(0, Qt.Unchecked)
            item.setText(0, snippets.title(name))
        
        self.deletedItem.setDisabled(self.deletedItem.childCount() == 0)
        self.changedItem.setDisabled(self.changedItem.childCount() == 0)
        self.checkOkButton()
    
    def slotItemChanged(self, item):
        if item in (self.deletedItem, self.changedItem):
            for i in range(item.childCount()):
                item.child(i).setCheckState(0, item.checkState(0))
        self.checkOkButton()
        
    def checkedSnippets(self):
        """Yields the names of the checked snippets."""
        for parent in (self.deletedItem, self.changedItem):
            for i in range(parent.childCount()):
                child = parent.child(i)
                if child.checkState(0) == Qt.Checked:
                    yield child.name
    
    def updateSnippets(self):
        """Restores the checked snippets."""
        collection = self.parent().parent().snippetActions
        for name in self.checkedSnippets():
            collection.restoreDefaultShortcuts(name)
            model.model().saveSnippet(name, None, None)

    def checkOkButton(self):
        """Enables the OK button if there are selected snippets."""
        self.button("ok").setEnabled(any(self.checkedSnippets()))
Пример #17
0
 def addOverlaysToTreeWidget(self, overlayDict, forbiddenOverlays, preSelectedOverlays, singleOverlaySelection):
     self.singleOverlaySelection = singleOverlaySelection
     testItem = QTreeWidgetItem("a")
     for keys in list(overlayDict.keys()):
         if overlayDict[keys] in forbiddenOverlays:
             continue
         else:
             boolStat = False
             split = keys.split("/")
         for i in range(len(split)):
             if len(split) == 1:
                 newItemsChild = OverlayTreeWidgetItem(overlayDict[keys], keys)
                 self.addTopLevelItem(newItemsChild)                   
                 boolStat = False
                 if overlayDict[keys] in preSelectedOverlays:
                     newItemsChild.setCheckState(0, Qt.Checked)
                 else:
                     newItemsChild.setCheckState(0, Qt.Unchecked)
                 
             elif i+1 == len(split) and len(split) > 1:
                 newItemsChild = OverlayTreeWidgetItem(overlayDict[keys], keys)
                 testItem.addChild(newItemsChild)
                 if overlayDict[keys] in preSelectedOverlays:
                     newItemsChild.setCheckState(0, Qt.Checked)
                 else:
                     newItemsChild.setCheckState(0, Qt.Unchecked)
                 
             elif self.topLevelItemCount() == 0 and i+1 < len(split):
                 newItem = QTreeWidgetItem([split[i]])
                 self.addTopLevelItem(newItem)
                 testItem = newItem
                 boolStat = True
                 
             elif self.topLevelItemCount() != 0 and i+1 < len(split):
                 if boolStat == False:
                     for n in range(self.topLevelItemCount()):
                         if self.topLevelItem(n).text(0) == split[i]:
                             testItem = self.topLevelItem(n)
                             boolStat = True
                             break
                         elif n+1 == self.topLevelItemCount():
                             newItem = QTreeWidgetItem([split[i]])
                             self.addTopLevelItem(newItem)
                             testItem = newItem
                             boolStat = True
                     
                 elif testItem.childCount() == 0:
                     newItem = QTreeWidgetItem([split[i]])
                     testItem.addChild(newItem)
                     testItem = newItem
                     boolStat = True
                 else:
                     for x in range(testItem.childCount()):
                         if testItem.child(x).text(0) == split[i]:
                             testItem = testItem.child(x)
                             boolStat = True
                             break
                         elif x+1 == testItem.childCount():
                             newItem = QTreeWidgetItem([split[i]])
                             testItem.addChild(newItem)
                             testItem = newItem
                             boolStat = True