Esempio n. 1
0
class DownloaderDialog(JDialog):
    def __init__(self):
        super().__init__()
        self.setWindowIcon(QIcon('GUI\jinndl.ico'))
        self.setInitialSize(800, 800)

        self.initUi()
        self.setActions()

    def initUi(self):
        self.setWindowTitle("Download Jinn")
        self.windowLayout = QVBoxLayout(self)

        # Advanced options
        # Stored in a QFrame, this is hidden or shown by self.btnAdvancedOptions
        self.topBar = QHBoxLayout()
        self.btnAdvancedOptions = QPushButton("Show advanced options")

        self.comboBranch = LabelledComboBox("Choose branch:")
        self.comboBranch.cb.addItems(["HJinn", "LJinn", "master"])
        self.advancedOptionsLayout = QHBoxLayout()
        self.advancedOptionsLayout.addWidget(self.comboBranch)

        self.advancedOptionsFrame = QFrame()
        self.advancedOptionsFrame.setHidden(True)
        self.advancedOptionsFrame.setLayout(self.advancedOptionsLayout)
        self.topBar.addWidget(self.btnAdvancedOptions)
        self.topBar.addWidget(self.advancedOptionsFrame)

        self.updateLog = JTextEdit(
            "Press 'Download' below to download the latest Jinn code to the USB memory stick"
        )

        self.statusLayout = QVBoxLayout()
        self.statusLayout.addWidget(self.updateLog)

        self.btnDownload = JPushButton("Download")
        self.btnCancel = JCancelButton("Cancel")
        self.buttonBtm = QHBoxLayout()
        self.buttonBtm.addWidget(self.btnDownload)
        self.buttonBtm.addWidget(self.btnCancel)

        self.windowLayout.addLayout(self.topBar)
        self.windowLayout.addLayout(self.statusLayout)
        self.windowLayout.addLayout(self.buttonBtm)

    def setActions(self):
        self.btnAdvancedOptions.clicked.connect(self.showAdvancedOptions)
        self.btnDownload.clicked.connect(self.doDownload)
        self.btnCancel.clicked.connect(self.reject)

    def showAdvancedOptions(self):
        if self.advancedOptionsFrame.isHidden():
            self.advancedOptionsFrame.show()
            self.btnAdvancedOptions.setText("Hide advanced options")
        else:
            self.advancedOptionsFrame.hide()
            self.btnAdvancedOptions.setText("Show advanced options")

    def getBranch(self):
        return self.comboBranch.cb.currentText()

    def doDownload(self):
        branch = self.getBranch()
        updateVariables = UpdateVariables(branch)
        try:
            cwd = os.getcwd()
            dirname = os.path.basename(cwd)
            if dirname.upper() == updateVariables.codeDir.upper():
                raise Exception(
                    "This script must not be run with the current directory being \"{}\""
                    ", because it needs to replace that directory".format(cwd))

            # compute the root directory (`Jinn`) via where this script is being run from
            stdOut = setRootDir()

            updateJTextEdit(self.updateLog, stdOut)
            # download the zip file from github to the `Jinn` directory
            downloadZipFile(self.updateLog, updateVariables)

            # extract from the zip file to create `Jinn-master` directory in `Jinn` directory
            extractFromZipFile(self.updateLog, updateVariables)

            updateJTextEdit(
                self.updateLog,
                "Finished downloading and extracting latest Jinn code. Please insert the USB into your "
                "work computer and run the installer.")
        except Exception as ex:
            raise ex
        InfoMsgBox(
            "Finished",
            "Download has finished. You can now close the downloader and remove the USB stick. To continue "
            "upgrading Jinn plug this USB stick into your work PC and run the 'Jinn updater' shortcut",
            "Download finished").exec()
Esempio n. 2
0
class Filter:
    locks = dict()

    def __init__(self, filter_content):
        self.filter_content = filter_content
        self.filter = dict()
        self.frame = QFrame()
        self.frame.setObjectName("Filter_frame")
        self.frame.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        actual_layout = QVBoxLayout()
        widget_frame = QFrame()
        self.layout = QVBoxLayout()
        widget_frame.setLayout(self.layout)
        actual_layout.addWidget(widget_frame)
        actual_layout.addStretch(1)
        self.filter_names = []
        self.frame.setLayout(actual_layout)
        self.frame.setHidden(True)

    def add_range(self, name, capitalize=False):
        min_input = QLineEdit()
        max_input = QLineEdit()
        min_input.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        min_input.setMaximumWidth(50)
        max_input.setMaximumWidth(50)
        if capitalize:
            name = name.capitalize()
        title = QLabel(name)
        dash = QLabel("-")
        frame = QFrame()
        layout = QHBoxLayout()
        layout.addWidget(min_input)
        layout.addStretch(0)
        layout.addWidget(dash)
        layout.addStretch(0)
        layout.addWidget(max_input)
        frame.setLayout(layout)
        # frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.layout.addWidget(title)
        self.layout.addWidget(frame)

        min_input.textChanged.connect(
            lambda: self.set_range_filter(name, min_input, max_input))
        max_input.textChanged.connect(
            lambda: self.set_range_filter(name, min_input, max_input))

    def set_range_filter(self, name, min_input, max_input):
        name = name.lower()
        minimum = -9001
        maximum = 9001
        try:
            minimum = int(min_input.text())
        except:
            pass
        try:
            maximum = int(max_input.text())
        except:
            pass

        if minimum == -9001 and maximum == 9001:
            if name in self.filter.keys():
                del self.filter[name]
        else:
            self.filter[name] = [minimum, maximum]
        self.filter_content()

    def add_dropdown(self,
                     name,
                     options,
                     suboptions=None,
                     default=None,
                     alphabetical=True):
        if alphabetical:
            options.sort()
        combo_box = QComboBox()
        combo_box.addItem("Any")
        combo_box.addItems(options)
        if suboptions is not None:
            sub_combo_box = QComboBox()
            sub_combo_box.setHidden(True)
        else:
            sub_combo_box = None
        label = QLabel(name)
        self.filter_names.append(name)
        self.layout.addWidget(label)
        self.layout.addWidget(combo_box)
        if suboptions is not None:
            self.layout.addWidget(sub_combo_box)
            sub_combo_box.currentIndexChanged.connect(
                lambda: self.set_sub_filters(name, combo_box, sub_combo_box))
        combo_box.currentIndexChanged.connect(lambda: self.set_filters(
            name, combo_box, sub_combo_box, suboptions))

        if default is not None:
            index = combo_box.findText(default, QtCore.Qt.MatchFixedString)
            if index >= 0:
                combo_box.setCurrentIndex(index)

    def set_sub_filters(self, name, combo_box, sub_combo_box):
        name = name.lower()
        main = combo_box.currentText().lower()
        sub = sub_combo_box.currentText().lower()
        if sub == "any":
            self.filter[name] = main + ".*"
        else:
            self.filter[name] = main + ".*(\ \(|\,\ )(" + sub + ").*"
        self.filter_content()

    def set_filters(self,
                    name,
                    combo_box,
                    sub_combo_box=None,
                    suboptions=None):
        main = combo_box.currentText()
        sub_cond = sub_combo_box is not None
        if sub_cond:
            sub = sub_combo_box.currentText()

        name = name.lower()
        if main == "Any" and name in self.filter.keys():
            del self.filter[name]
            if sub_cond:
                sub_combo_box.setHidden(True)
        else:
            if sub_cond:
                if main in suboptions.keys():
                    _suboptions = [
                        subopt for subopt in suboptions[main]
                        if subopt != "Any"
                    ]  # remove Any as suboption
                    sub_combo_box.setHidden(False)
                    sub_combo_box.clear()
                    sub_combo_box.addItem("Any")
                    sub_combo_box.addItems(_suboptions)
                else:
                    sub_combo_box.clear()
                    sub_combo_box.setHidden(True)
            self.filter[name] = main + ".*"
        # print(self.filter[name])
        self.filter_content()

    def lock(self, attr, value):
        self.locks[attr] = value

    def get_frame(self):
        return self.frame

    def toggle_hidden(self):
        if self.frame.isHidden():
            self.frame.setHidden(False)
        else:
            self.frame.setHidden(True)

    def evaluate_filter(self, entry):
        cond = True
        for key, arg in self.locks.items():
            if not hasattr(entry, key) or getattr(entry, key) != arg:
                return False
        for key, arg in self.filter.items():
            if not hasattr(entry, key):
                # print("Wrong filter key passed to entry in SearchableTable")
                return False
            attr = getattr(entry, key)
            if type(arg) is str and type(
                    attr
            ) is str:  # single attribute, single argument. Easy as pie
                p = re.compile('{}'.format(arg), re.IGNORECASE)
                cond = cond and (p.match(attr))
            elif type(
                    attr
            ) is list:  # single argument, multiple attributes, eval individually for each element
                p = re.compile('{}'.format(arg), re.IGNORECASE)
                cond = cond and any([p.match(_attr) for _attr in attr])
            elif type(
                    arg
            ) is list:  # numerical range, must be inbetween two values
                if attr is None or None in arg:
                    continue
                attr = eval("float({})".format(attr))
                cond = cond and (arg[0] <= attr <= arg[1])

        return cond

    def clear_filters(self):
        for i in reversed(range(self.layout.count())):
            self.layout.removeItem(self.layout.itemAt(i))
        self.filter = dict()
class kdDesktopAssistant(QMainWindow):

    def __init__(self):
        super().__init__()
        loadUi(get_file_realpath("kdDesktopAssistant.ui"), self)
        icon = QIcon(get_file_realpath('data/image/logo.png'))
        self.setWindowIcon(icon)
        self.setWindowFlag(Qt.FramelessWindowHint)
        
#         self.setStyleSheet("#MainWindow{border-image:url("+get_file_realpath("data/image/S60922-232113.jpg").replace("\\","/") +");}")
        self.gl_apps.setAlignment(Qt.AlignTop)
        
#         右键菜单设置
        self.pop_menu = QMenu()
#         TODO 待实现的右键功能:QAction("导出配置"),QAction("导入配置")
        self.pop_menu_item = [QAction("新增启动项"),QAction("新增桌面"),QAction("设置背景图片"),QAction("修改桌面"),QAction("删除桌面"),QAction("设置为主桌面"),QAction("小程序模式"),QAction("退出")]
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested[QPoint].connect(self.handle_pop_menu)
        
#         系统托盘
        sys_tray = QSystemTrayIcon(self)
        self.sys_tray = sys_tray
        sys_tray.setIcon(icon)
        sys_tray.activated.connect(self.sys_tray_handler)
        sys_tray_menu = QMenu()
        sys_tray_menu.menu_items   =[ QAction("退出",self,triggered=sys.exit)]
        sys_tray.setContextMenu(sys_tray_menu)
        sys_tray.show()

        self.session_bt_size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.session_btn_size = QSize(100, 25)
#         初始化桌面
        print(QDesktopWidget().screenGeometry().height())
        print(self.gl_apps.geometry().height())
        self.vetical_widget_number = math.floor((QDesktopWidget().screenGeometry().height() - 150) / get_option_int("item_size"))
        self.home_session = get_option_value("home_session")
        self.init_session()
        
#         初始化对话框对象
        self.dl_launch_item_detail = dl_launch_item_detail()
        self.session = session()
        self.wg_catelog = QFrame()
        self.wg_catelog.setWindowFlags(Qt.Popup)
        self.gl_catelog = QGridLayout()
        self.wg_catelog.setLayout(self.gl_catelog)
#         self.gl_catelog.setWindowOpacity(0.5)
#         self.wg_catelog.setAttribute(Qt.WA_TranslucentBackground,True )
        self.wg_catelog.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool)
        self.wg_catelog.setAutoFillBackground(True)
        
#         self.wg_catelog.setStyleSheet("background-image:url("+get_file_realpath("data/image/bg_catelog.gif") + ");background-size:cover;}")
        p = QPalette()
        p.setBrush(QPalette.Background, QBrush(QPixmap(get_file_realpath("data/image/bg_catelog.jpg"))))
        self.wg_catelog.setPalette(p)
#         op = QGraphicsOpacityEffect()  
#         op.setOpacity(0.9)    
#         self.wg_catelog.setGraphicsEffect(op)  
#         self.wg_catelog.setStyleSheet("QWidget#wg_catelog{background-color:#99cc99;}")
    def remove_item(self,item):
        item.setParent(None)
        self.gl_apps.removeWidget(item)
        del item
    def edit_lauchn_item(self,item, widget):
        self.dl_launch_item_detail.set_item(item)
        promt_info = "修改"
        if self.dl_launch_item_detail.exec_():
            if not item:
                item = {}
                item["id"] = None
                promt_info = "新增"
                
            item["ico"] = self.dl_launch_item_detail.ico_path
            item["name"] = self.dl_launch_item_detail.le_name.text()
            item["url"] = self.dl_launch_item_detail.le_url.text().strip()
            item["type"] = self.dl_launch_item_detail.bg_type.checkedButton().type
            item["session_id"] = self.cur_session["id"]
            try :
                if item["id"]:
                    app_data.update_launch_item(item)
                    widget.update_item(item)
                else:
                    app_data.insert_launch_item(item)
                    self.add_launch_item(item)
                QMessageBox.information(None, promt_info + "启动项",  promt_info + "启动项成功" , QMessageBox.Yes)
            except Exception as e:
                QMessageBox.warning(None, promt_info + "启动项失败",   str(e), QMessageBox.Yes)
                raise e
    def edit_session(self,item):
        self.session.set_session(item)
        promt_info = "修改"
        if self.session.exec_():
            if not item:
                item = {}
                item["id"] = None
                promt_info = "新增"
                item["type"] = 0
                item["color"] = None
                
            item["name"] = self.session.le_name.text()
            item["picture"] = self.session.le_picture.text()
            try :
                if item["id"]:
                    app_data.update_session(item)
                    self.setStyleSheet("#MainWindow{border-image:url("+item["picture"] + ");}")
    #                 widget.update_item(item)
                else:
                    app_data.insert_session_item(item)
                    self.add_session(item)
                QMessageBox.information(None, promt_info + "桌面",  promt_info + "桌面成功" , QMessageBox.Yes)
            except Exception as e:
                QMessageBox.warning(None, promt_info + "桌面失败",   str(e), QMessageBox.Yes)
                raise e
    def add_launch_item(self,item):
        li = launch_item(item)
        li.del_item_signal.connect(self.remove_item)
        li.edit_item_signal.connect(self.edit_lauchn_item)
        li.click_catelog_signal.connect(self.on_catelog_clicked)
        li.repaint_session_signal.connect(self.repaint_session)
        self.gl_apps.addWidget(li, self.row, self.col, 1, 1)
        self.row += 1
        if self.row >= self.vetical_widget_number:
            self.row = 0
            self.col += 1
    def repaint_session(self):
        self.init_launch_items(self.cur_session)
    def on_catelog_clicked(self,catelog_id):
#         清空layout上的组件
        if not self.wg_catelog.isHidden():
            self.wg_catelog.hide()
            return
        count = self.gl_catelog.count()
        for i in reversed(range(count)) :
            self.gl_catelog.itemAt(i).widget().setParent(None)
            
        item_list = app_data.get_launch_item_list_by_catelog(catelog_id)
        if not item_list :
            return
        max_column =  math.floor(len(item_list) ** 0.5)
        row, col = 1, 0
        for i in item_list :
            item_dict = app_data.tuple2dict_launch_item(i)
            li = launch_item(item_dict)
            li.del_item_signal.connect(self.remove_item)
            li.edit_item_signal.connect(self.edit_lauchn_item)
            li.click_catelog_signal.connect(self.on_catelog_clicked)
            self.gl_apps.addWidget(li, self.row, self.col, 1, 1)
            self.gl_catelog.addWidget(li)
            
#         p = QCursor.pos()
#         if p.y() > self.gl_apps.geometry().height() /2 :
#             self.wg_catelog.move(p.x() + 10,p.y() - self.wg_catelog.geometry().height())
#         else :
#             self.wg_catelog.move(p.x() + 10,p.y()+10)
            
        self.wg_catelog.show()
#         self.wg_catelog.active()
            
    def init_launch_items(self,item):
#         高亮当前桌面的按钮
        count = self.hl_session.count()
        for i in reversed(range(count)) :
            self.hl_session.itemAt(i).widget().setStyleSheet("QPushButton{background-color:#FFFFFF}")
        self.cur_pb_session.setStyleSheet("QPushButton{background-color:#FF9900}")
        
        self.row = 0
        self.col = 0
        
#         清空gridlayout上的所有组件
        count = self.gl_apps.count()
        print("gl_apps:" , count)
#         一个老外给的方法,很棒。https://stackoverflow.com/questions/4528347/clear-all-widgets-in-a-layout-in-pyqt
        for i in reversed(range(count)) :
            self.gl_apps.itemAt(i).widget().setParent(None)
        
#         设置背景图片    
        session_id = item["id"]
        picture = item["picture"]
        if picture :
            self.setStyleSheet("#MainWindow{background-image:url("+picture + ");background-size:cover;}")

        if not session_id :
            return
#         初始化启动项
        self.item_list = app_data.get_launch_item_list(session_id)
        for item in self.item_list:
            item_dict = app_data.tuple2dict_launch_item(item)
            self.add_launch_item(item_dict)
        
    def init_session(self):
#         清空旧的桌面按钮
        count = self.hl_session.count()
        for i in reversed(range(count)) :
            self.hl_session.itemAt(i).widget().setParent(None)
        self.session_list = app_data.get_session_list()
        initedSession = False
        first_pb_session = None
        for item in self.session_list:
            item_dict = app_data.tuple2dict_session(item)
            pb_session = self.add_session(item_dict)
            if not first_pb_session:
                first_pb_session = pb_session
            if item_dict["name"] == self.home_session :
                initedSession = True
                self.cur_pb_session = pb_session
                self.init_launch_items(item_dict)
                self.cur_session = item_dict
            
#       默认桌面未初始化,默认初始化第一个桌面
        if not initedSession and len(self.session_list) > 0:
            item = self.session_list[0]
            item_dict = app_data.tuple2dict_session(item)
            self.cur_pb_session = first_pb_session
            self.init_launch_items(item_dict)
            self.cur_session = item_dict
                
    def add_session(self,item):
#         新建桌面按钮
        pb_session = QPushButton(item["name"])
        pb_session.setSizePolicy(self.session_bt_size_policy)
        pb_session.setMaximumSize(self.session_btn_size)
#         设置桌面按钮为半透明
        op = QGraphicsOpacityEffect()  
        op.setOpacity(0.9)    
        pb_session.setGraphicsEffect(op)  
        pb_session.setAutoFillBackground(True)
#         TODO 待删除
#         pb_session.session_id = item["id"]
#         pb_session.picture = item["picture"]
        pb_session.item = item
        pb_session.clicked.connect(self.on_pb_session_clicked)
        self.hl_session.addWidget(pb_session)
        return pb_session
    def on_pb_session_clicked(self):
        sender = self.sender()
        self.cur_session = sender.item

        
        self.cur_pb_session = sender
        self.init_launch_items(self.cur_session)
    def handle_pop_menu(self):
        action = self.pop_menu.exec_(self.pop_menu_item,QCursor.pos())
        if action:
            action_text = action.text()
            if action_text == "新增启动项" :
                self.edit_lauchn_item(None,None)
            elif action_text == "新增桌面" :
                if self.session.exec_() :
                    session_item = {}
                    session_item["name"] = self.session.le_name.text()
                    session_item["picture"] = self.session.le_picture.text()
                    session_item["type"] = 0
                    session_item["color"] = None
                    session_item["id"] = app_data.insert_session_item(session_item)
                    print(session_item)
                    pb_session = self.add_session(session_item)
                    self.init_launch_items(session_item)
                    self.cur_session = session_item
                    QMessageBox.information(self, "新增桌面", "新增桌面成功")
            elif action_text in ( "设置背景图片","修改桌面") :
                self.edit_session(self.cur_session)
            elif action_text == "设置为主桌面" :
                set_home_session(self.cur_session["name"])
                QMessageBox.information(self, "主桌面设置", "设置为主桌面成功")
            elif action_text == "小程序模式" :
                web_as_application = get_option_boolean("web_as_application")
                set_web_mode(not web_as_application)
                if not web_as_application:
                    QMessageBox.information(self, "启动小程序模式", "每个网页将作为一个应用程序打开")
                else :
                    QMessageBox.information(self, "关闭小程序模式", "每个网页将作为一个标签也打开")
                    QMessageBox.information(self, "关闭小程序模式", "每个网页将作为一个标签也打开")
            elif action_text == "退出" :
                sys.exit()
            elif action_text == "删除桌面" :
                reply = QMessageBox.warning(self, "确认删除桌面?", "该桌面的所有启动项都会被删除,并不可还原,确认删除?",QMessageBox.Yes | QMessageBox.No)
                if reply == QMessageBox.Yes :
                    app_data.delete_session(self.cur_session["id"])
                    self.init_session()
                    QMessageBox.information(self, "删除桌面", "删除桌面成功",QMessageBox.Ok)
            
            
                    
                
                
    def toggle_window_status(self):
        if self.isHidden() :
            self.showMaximized()
            self.activateWindow()
        else :
            self.hide()
    def sys_tray_handler(self,reason):
        if reason ==  2 or reason == 3 :
            self.toggle_window_status()
        elif reason == 1 :
            menu = self.sender().contextMenu()
            menu.exec_(menu.menu_items,QCursor.pos()) 
        else :
            sys.exit()
    def closeEvent(self,event):
        self.hide()
        self.sys_tray.show()
        event.ignore()
    def mouseReleaseEvent(self,event):
        print("on mouseReleaseEvent")
        self.wg_catelog.hide()
        
    def keyReleaseEvent(self,event):
        key = event.key()
        if event.modifiers()== Qt.ControlModifier and key == Qt.Key_V :
            clipboard = QApplication.clipboard()
            mimeData = clipboard.mimeData()
            if mimeData.hasText():
                print("准备粘贴:" + clipboard.text())
                path = clipboard.text()
                item = {}
                if  not path.startswith("file") :
                    item = self.dl_launch_item_detail.get_url_info(path)
                    item["session_id"] = self.cur_session["id"]
                    item["id"] = app_data.insert_launch_item(item)
                    self.add_launch_item(item)
                    return
                
                path = path.replace("file:///","")
                if os.name == "posix" :
                    path = "/" + path
                provider = QFileIconProvider()
                fi = QFileInfo(path)
                icon = provider.icon(fi)
#                     t = icon.pixmap().toImage().text()
                save_path = join(config_dir ,"data/image/sysico",splitext(path)[0]+".ico")
                print("save_path:" + save_path)
                icon.pixmap(48).save(save_path)
                t = icon.name()
                t1 = icon.themeName()
                t2 = icon.themeSearchPaths()
                print("icon path:" + t+"," + t1,t2)
                if not icon.isNull() :
                    item["ico"] = save_path
                item["name"] = basename(path)
                item["url"] = path
                item["type"] = 2
                if not self.cur_session["id"]:
                    QMessageBox.information(self, "新桌面", "新桌面需重启后才能添加启动项")
                    return
                item["session_id"] = self.cur_session["id"]
                print("add other launch item:" ,item)
                item["id"] = app_data.insert_launch_item(item)
                print(item)
                self.add_launch_item(item)
Esempio n. 4
0
class DMTool(QMainWindow):
    SEARCH_BOX_WIDTH = 200

    def __init__(self, db_path, validate_views=False):
        super().__init__()
        self._database_path = db_path
        sys.excepthook = self.excepthook
        self.settings = dict({"query_srd": True})
        self.load_meta()
        self._setup_ui()
        self._setup_menu()
        self.bind_signals()
        self.load_session()
        self._display_ui()
        if validate_views:
            self.validate_views()

    def _setup_ui(self):
        """
        Layout is a windowLayout with a horizontal box on the left and a tab widget on the right
        :return:
        """
        self.setStyleSheet(
            open(os.path.join("assets", "styles", "default.css")).read())
        self.setWindowIcon(QIcon(os.path.join('assets', 'tear.png')))
        self.setWindowTitle("RainyDM")
        self.setGeometry(100, 100, 1280, 720)
        self.window_frame = QFrame()
        self.window_layout = QHBoxLayout()
        # Left side tab
        self.tab_widget = QTabWidget()

        # Viewers
        # - monster viewer
        monster_button_bar = QFrame()
        monster_button_bar_layout = QHBoxLayout()
        monster_button_bar.setLayout(monster_button_bar_layout)
        self.monster_viewer = MonsterViewer(monster_button_bar, self.system)
        monster_viewer_frame_layout = QVBoxLayout()
        self.monster_viewer_frame = QFrame()
        self.monster_viewer_frame.setLayout(monster_viewer_frame_layout)
        self.monster_viewer_frame.layout().setContentsMargins(0, 0, 0, 0)
        self.monster_viewer_frame.setFrameStyle(0)

        # - spell viewer
        self.spell_viewer = SpellViewer(self.system)

        # - item viewer
        self.item_viewer = ItemViewer(self.system)

        # Text box
        self.text_box = QTextEdit()
        self.text_box.setObjectName("OutputField")
        self.text_box.setReadOnly(True)
        self.text_box.setFontPointSize(10)

        ## Tables
        # Spell Table
        self.spell_table_widget = SpellTableWidget(self, self.spell_viewer)

        # Monster table
        self.monster_table_widget = MonsterTableWidget(self,
                                                       self.monster_viewer)

        # Item table
        self.item_table_widget = ItemTableWidget(self, self.item_viewer)
        self.item_table_widget.layout().addWidget(self.item_viewer)

        self.load_resources(self._database_path)

        # Loot Generator Widget
        self.lootViewer = ItemViewer(self.system)
        self.loot_widget = TreasureHoardTab(self, self.item_viewer,
                                            self.item_table_widget)

        # Initiative list
        self.encounterWidget = EncounterWidget(self.monster_viewer)

        # bookmark
        self.bookmark_widget = BookmarkWidget(self.monster_table_widget,
                                              self.monster_viewer,
                                              self.spell_table_widget,
                                              self.spell_viewer)

        encounter_frame = QFrame()
        encounter_layout = QVBoxLayout()
        encounter_layout.addWidget(self.encounterWidget)
        encounter_layout.addWidget(self.bookmark_widget)
        encounter_frame.setLayout(encounter_layout)

        # player tab
        player_table_frame = QFrame()
        player_table_layout = QVBoxLayout()
        encounter_button_layout = QHBoxLayout()
        self.add_player_button = QPushButton("Add Player")
        self.add_player_button.setSizePolicy(QSizePolicy.Minimum,
                                             QSizePolicy.Minimum)
        self.playerWidget = PlayerTable()
        encounter_button_layout.addWidget(self.add_player_button)
        encounter_button_layout.addStretch(0)
        player_table_layout.addWidget(self.playerWidget)
        player_table_layout.addLayout(encounter_button_layout)
        player_table_frame.setLayout(player_table_layout)

        self.monster_viewer_bar = QFrame()
        self.monster_viewer_bar.setContentsMargins(0, 0, 0, 0)

        monster_viewer_frame_layout.addWidget(self.monster_viewer)
        monster_viewer_frame_layout.addWidget(monster_button_bar)
        monster_viewer_frame_layout.addWidget(self.monster_viewer_bar)
        monster_viewer_frame_layout.setStretch(3, 1)
        monster_viewer_frame_layout.setStretch(0, 2)

        middle_frame_layout = QVBoxLayout()
        self.middle_frame = QTabWidget()
        self.middle_frame.setLayout(middle_frame_layout)
        self.middle_frame.setContentsMargins(0, 0, 0, 0)

        layout = QHBoxLayout()
        monster_plaintext_button = QPushButton("Copy plaintext to clipboard")
        monster_plaintext_button.clicked.connect(
            self.copy_plaintext_monster_to_clipboard)
        layout.addWidget(monster_plaintext_button)
        self.monster_viewer_bar.setLayout(layout)

        # middle_frame_layout.addWidget(self.spell_viewer)
        middle_frame_layout.setStretch(0, 2)
        middle_frame_layout.setContentsMargins(0, 0, 0, 0)

        # Leftmost tab
        self.tab_widget.addTab(encounter_frame, "Encounter")
        self.tab_widget.addTab(player_table_frame, "Players")
        self.tab_widget.addTab(self.loot_widget, "Loot")

        # Center tab
        self.middle_frame.addTab(self.monster_table_widget, "Monster")
        self.middle_frame.addTab(self.spell_table_widget, "Spell")
        self.middle_frame.addTab(self.item_table_widget, "Item")
        self.middle_frame.addTab(self.text_box, "Text Box")

        # Right frame
        self.right_tab = QTabWidget()
        self.right_tab.addTab(self.monster_viewer_frame, "Monster")
        self.right_tab.addTab(self.spell_viewer, "Spell")
        self.right_tab.addTab(self.item_viewer, "Item")

        self.window_layout.addWidget(self.tab_widget)
        self.window_layout.addWidget(self.middle_frame)
        self.window_layout.addWidget(self.right_tab)
        self._set_widget_stretch(GlobalParameters.MAIN_TOOL_POSITION,
                                 GlobalParameters.MAIN_TOOL_STRETCH)
        self._set_widget_stretch(GlobalParameters.MIDDLE_FRAME_POSITION, 0)
        self._set_widget_stretch(GlobalParameters.RIGHT_FRAME_POSITION,
                                 GlobalParameters.RIGHT_FRAME_STRETCH)

        self.monster_viewer_bar.setHidden(True)

        self.window_frame.setLayout(self.window_layout)

    def _setup_menu(self):
        ### Menubar
        menu = self.menuBar()
        version = menu.addMenu("Version")
        # button_3_5 = QAction("3.5 Edition", self)
        # button_3_5.setStatusTip("3.5 Edition")
        # version.addAction(button_3_5)
        button_5 = QAction("5th Edition", self)
        button_5.setStatusTip("5th Edition")
        version.addAction(button_5)
        button_5.triggered.connect(lambda: self.change_version(System.DnD5e))
        button_sw5e = QAction("SW 5th Edition", self)
        button_sw5e.setStatusTip("SW 5th Edition")
        version.addAction(button_sw5e)
        button_sw5e.triggered.connect(lambda: self.change_version(System.SW5e))
        # button_3_5.triggered.connect(lambda: self.change_version("3.5"))

        experimental = menu.addMenu("Experimental")
        button_plain_text = QAction("Plain text monsters",
                                    self,
                                    checkable=True)
        button_plain_text.setStatusTip("Plain text monsters")
        button_plain_text.triggered.connect(self.toggle_monster_bar)
        # raise_exception = QAction("Raise Exception", self)
        # raise_exception.setStatusTip("Raise an Exception")
        # raise_exception.triggered.connect(self.raise_exception)
        self.edit_entries_action = QAction("Edit Entries",
                                           self,
                                           checkable=True)
        self.edit_entries_action.setStatusTip("Enable edit data entries")
        # development
        self.edit_entries_action.setChecked(True)  # default ON
        self.enable_edit_data_entries()
        ##
        self.edit_entries_action.triggered.connect(
            self.enable_edit_data_entries)

        experimental.addAction(button_plain_text)
        experimental.addAction(self.edit_entries_action)
        # experimental.addAction(raise_exception)

        self.window_frame.setLayout(self.window_layout)

    # def raise_exception(self):
    #     raise EnvironmentError("Forced an exception")

    def enable_edit_data_entries(self):
        cond = self.edit_entries_action.isChecked()
        self.monster_table_widget.EDITABLE = False  # not for monsters
        self.spell_table_widget.EDITABLE = cond
        self.item_table_widget.EDITABLE = cond

    def bind_signals(self):
        self.encounterWidget.add_players_button.clicked.connect(
            self.addPlayersToCombat)
        self.encounterWidget.sort_init_button.clicked.connect(
            self.sort_init_handle)
        self.encounterWidget.roll_init_button.clicked.connect(
            self.roll_init_handle)
        self.encounterWidget.save_encounter_button.clicked.connect(
            self.encounterWidget.save)
        self.encounterWidget.load_encounter_button.clicked.connect(
            lambda: self.encounterWidget.load(self.monster_table_widget))
        self.encounterWidget.clear_encounter_button.clicked.connect(
            self.clear_encounter_handle)
        self.bookmark_widget.clear_bookmark_button.clicked.connect(
            self.clear_bookmark_handle)
        self.bookmark_widget.toggle_bookmark_button.clicked.connect(
            self.toggle_bookmark_handle)

        self.add_player_button.clicked.connect(self.add_player)
        sNexus.attackSignal.connect(self.attackSlot)
        sNexus.addSpellsSignal.connect(self.addSpellsToBookmark)
        sNexus.printSignal.connect(self.print)
        sNexus.addMonstersToEncounter.connect(
            self.encounterWidget.addMonsterToEncounter)
        sNexus.setWidgetStretch.connect(self._set_widget_stretch)
        sNexus.viewerSelectChanged.connect(self.viewer_select_changed)

    def _display_ui(self):
        self.setCentralWidget(self.window_frame)

    def _set_widget_stretch(self, widget, stretch):
        self.window_layout.setStretch(widget, stretch)

    def toggle_monster_bar(self):
        if self.monster_viewer_bar.isHidden():
            self.monster_viewer_bar.setHidden(False)
        else:
            self.monster_viewer_bar.setHidden(True)

    def copy_plaintext_monster_to_clipboard(self):
        pyperclip.copy(html2text.html2text(self.monster_viewer.html))

    def viewer_select_changed(self, idx):
        self.right_tab.setCurrentIndex(idx)

    def change_version(self, version):
        if self.system == version:
            return
        self.system = version
        self.clear_bookmark_handle()
        self.clear_encounter_handle()

        self.monster_table_widget.table.clear()
        self.spell_table_widget.table.clear()
        self.item_table_widget.table.clear()

        self.monster_table_widget.filter.clear_filters()

        self.load_resources(self._database_path)

    def addMonsterToBookmark(self, monster):
        row_position = self.bookmark_widget.monster_bookmark.rowCount()
        self.bookmark_widget.monster_bookmark.insertRow(row_position)
        if type(monster) == list:
            for itt, value in enumerate(monster):
                self.bookmark_widget.monster_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        else:
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(monster.name)))
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(monster.index)))

    def addSpellsToBookmark(self, spells):
        for spell in spells:
            _spell = self.spell_table_widget.find_entry('name', spell)
            self.add_to_bookmark_spell(_spell)

    def add_to_bookmark_spell(self, spell):
        row_position = self.bookmark_widget.spell_bookmark.rowCount()
        self.bookmark_widget.spell_bookmark.insertRow(row_position)
        if type(spell) == list:
            for itt, value in enumerate(spell):
                self.bookmark_widget.spell_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        elif spell is not None:
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(spell.name)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(spell.index)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 2, QTableWidgetItem(str(spell.level)))

    def load_resources(self, database_path):
        self.db = RainyDatabase(database_path, system=self.system)
        self.item_table_widget.set_entries(self.db.get_items())
        self.item_table_widget.fill_table()
        self.item_table_widget.define_filters(self.system)
        self.monster_table_widget.set_entries(self.db.get_monsters())
        self.monster_table_widget.fill_table()
        self.monster_table_widget.define_filters(self.system)
        # self.spell_table_widget.load_all("./spell", "{}/{}/Spells/".format(resource_path, self.version), spell_cls)
        self.spell_table_widget.set_entries(self.db.get_spells())
        self.spell_table_widget.fill_table()
        self.spell_table_widget.define_filters(self.system)

    def add_player(self, player=None):
        self.playerWidget.add(PlayerFrame(self.playerWidget))

    def addPlayersToCombat(self):
        encounterWidget = self.encounterWidget
        characterNames = encounterWidget.getCharacterNames()
        # Get active players

        for entry in self.playerWidget.m_widgetList:
            # character in encounter, and should be
            if entry.getCharacter().getCharName(
            ) in characterNames and entry.isEnabled():
                # print("Character in encounter, and should be")
                encounterWidget.update_character(entry.getCharacter())

            # character in encounter, but shouldn't be
            elif entry.getCharacter().getCharName(
            ) in characterNames and not entry.isEnabled():
                # print("Character in enocunter, shouldn't be")
                # print(entry.getCharacter().getCharName(), entry.isEnabled())
                encounterWidget.remove_character(entry.getCharacter())

            # character not in encounter, but should be
            elif entry.getCharacter().getCharName(
            ) not in characterNames and entry.isEnabled():
                # print("Character not in encounter, should be")
                encounterWidget.addPlayerToEncounter(entry.getCharacter())

            # character not in encounter, and shouldn't be
            else:
                pass

    def sort_init_handle(self):
        self.encounterWidget.sortInitiative()

    def roll_init_handle(self):
        self.encounterWidget.rollInitiative()

    def clear_encounter_handle(self):
        self.encounterWidget.clear()

    def clear_bookmark_handle(self):
        self.bookmark_widget.monster_bookmark.clear()
        self.bookmark_widget.monster_bookmark.setRowCount(0)
        self.bookmark_widget.spell_bookmark.clear()
        self.bookmark_widget.spell_bookmark.setRowCount(0)

    def toggle_bookmark_handle(self):
        self.bookmark_widget.toggle_hide()

    def print(self, s):
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)
        self.text_box.append(s)

    def print_attack(self, monster_name, attack):
        attack = attack.strip(" ")
        comp = attack.split("|")
        if attack == "":
            s = "{} used an action".format(monster_name)
        else:
            s = "{} uses {} -- ".format(monster_name, comp[0])

            if comp[1] not in [
                    "", " "
            ]:  # this means there's an attack roll and a damage roll
                attack_roll = roll_function("1d20+" + comp[1])
                s = s + "{}({}) to hit".format(attack_roll,
                                               attack_roll - int(comp[1]))
            damage_roll = roll_function(comp[2])
            if damage_roll is not None:
                if type(damage_roll) is list:
                    halved = [max(1, int(dr / 2)) for dr in damage_roll]
                else:
                    # print("\trainydm - print_attack: \"{}\"".format(damage_roll))
                    halved = max(1, int(damage_roll / 2))
                s = s + " -- for {} ({} halved)".format(
                    str(damage_roll), str(halved))
        self.print(s)

    def extract_and_add_spellbook(self, monster):
        spells = monster.extract_spellbook()
        if spells is not None:
            for spell in spells:
                spell_entry = self.spell_table_widget.find_entry("name", spell)
                if spell_entry is not None:
                    self.add_to_bookmark_spell(spell_entry)
                else:
                    print("Failed to locate spell for", monster.name,
                          "with spellname {}".format(spell))

    def load_meta(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")

        meta_path = os.path.join("metadata", "meta.txt")
        if os.path.exists(meta_path):
            with open(meta_path, "r") as f:
                meta_dict = json.load(f)
                self.system = System.from_plaintext(meta_dict['system'])
                self.settings = meta_dict['settings']
        else:
            self.system = System.DnD5e

    def load_session(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")
        if os.path.exists("metadata/session.txt"):
            with open("metadata/session.txt", "r") as f:
                meta_dict = eval(f.read())
                for monster_tuple in meta_dict['bookmark_meta']:
                    self.addMonsterToBookmark(monster_tuple)

                for player in meta_dict['player_meta']:
                    player_dict = json.loads(player)
                    self.playerWidget.add(
                        PlayerFrame(self.playerWidget,
                                    charName=player_dict["characterName"],
                                    playerName=player_dict["playerName"],
                                    init=player_dict["initiative"],
                                    perception=player_dict["perception"],
                                    insight=player_dict["insight"],
                                    isEnabled=player_dict["isEnabled"]))

                for entry in meta_dict['initiative_meta']:
                    entry_dict = json.loads(entry)
                    if entry_dict["type"] == "Monster":
                        self.encounterWidget.add(
                            MonsterWidget(self.monster_table_widget.find_entry(
                                "name", entry_dict["monster"]),
                                          self.encounterWidget,
                                          viewer=self.monster_viewer,
                                          init=entry_dict["init"],
                                          hp=entry_dict["hp"]))
                    elif entry_dict["type"] == "Player":
                        self.encounterWidget.add(
                            PlayerWidget(
                                self.encounterWidget,
                                self.playerWidget.findCharacterByName(
                                    entry_dict["name"])))

    def closeEvent(self, event):
        bookmark_meta = self.bookmark_widget.monster_bookmark.jsonlify()
        initiative_meta = self.encounterWidget.jsonlify()
        player_meta = self.playerWidget.jsonlify()

        with open("metadata/session.txt", "w") as f:
            json.dump(
                dict(bookmark_meta=bookmark_meta,
                     initiative_meta=initiative_meta,
                     player_meta=player_meta), f)

        with open("metadata/meta.txt", "w") as f:
            json.dump(
                dict(system=System.to_plaintext(self.system),
                     settings=self.settings), f)

    # SLOTS
    @pyqtSlot(str, str)
    def attackSlot(self, name, attack):
        self.print_attack(name, attack)
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)

    def excepthook(self, type, value, tb):
        box = QMessageBox()
        box.setWindowTitle("Oof!")
        box.setText("RainyDM has crashed!")
        box.setIcon(QMessageBox.Critical)
        details = "".join(traceback.format_exception(type, value, tb))
        box.setDetailedText(details)

        spacer = QSpacerItem(500, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
        box.layout().addItem(spacer,
                             box.layout().rowCount(), 0, 1,
                             box.layout().columnCount())

        box.exec_()
        old_excepthook(type, value, tb)
        self.close()

    def validate_views(self):
        for spell in self.db.get_spells().values():
            self.spell_viewer.draw_view(spell)
        for monster in self.db.get_monsters().values():
            self.monster_viewer.draw_view(monster)
        for item in self.db.get_items().values():
            self.item_viewer.draw_view(item)
Esempio n. 5
0
class UpdaterDialog(JDialog):
    def __init__(self):
        super().__init__()

        self.setInitialSize(800, 800)
        self.initUi()
        self.setActions()

    def initUi(self):
        self.setWindowTitle("Update Jinn")

        self.windowLayout = QVBoxLayout(self)
        self.topBar = QHBoxLayout()
        self.middleLayout = QHBoxLayout()
        self.advancedOptionsLayout = QVBoxLayout()
        self.advancedButtonLayout = QHBoxLayout()
        self.buttonBtm = QHBoxLayout()

        self.advancedOptionsFrame = QFrame()
        self.advancedOptionsFrame.setHidden(True)

        self.updateLog = JTextEdit(
            "Use this on your work PC. Press 'Update' to copy the Jinn code on this USB stick to "
            "this PC. The old code will be saved incase it is needed.")
        self.updateLog.setReadOnly(True)

        self.btnAdvancedOptions = JPushButton("Show advanced options")
        self.btnLocateJinn = JPushButton("Locate Jinn installation")
        self.btnUpdate = JPushButton("Update")
        self.btnCreateShortcut = JPushButton("Create desktop shortcut")
        self.btnCancel = JCancelButton("Cancel")

        self.codeDir = DirectorySelector(caption="Select Code directory")
        self.codeDir.leDirname.setText("C:/Jinn/Code")

        self.advancedOptionsLayout.addWidget(self.codeDir)
        self.advancedButtonLayout.addWidget(self.btnCreateShortcut)
        self.advancedButtonLayout.addWidget(self.btnLocateJinn)
        self.advancedOptionsLayout.addLayout(self.advancedButtonLayout)
        self.advancedOptionsFrame.setLayout(self.advancedOptionsLayout)

        self.buttonBtm.addWidget(self.btnUpdate)
        self.buttonBtm.addWidget(self.btnCancel)

        self.topBar.addWidget(self.btnAdvancedOptions)
        self.middleLayout.addWidget(self.advancedOptionsFrame)

        self.windowLayout.addLayout(self.topBar)

        self.windowLayout.addLayout(self.middleLayout)
        self.windowLayout.addStretch()
        self.windowLayout.addWidget(self.updateLog)
        self.windowLayout.addLayout(self.buttonBtm)

    def setActions(self):
        self.btnLocateJinn.clicked.connect(self.locateCodeFolder)
        self.btnUpdate.clicked.connect(self.updateCode)
        self.btnCreateShortcut.clicked.connect(self.createShortcut)
        self.btnCancel.clicked.connect(self.reject)
        self.btnAdvancedOptions.clicked.connect(self.showAdvancedOptions)

    def showAdvancedOptions(self):
        if self.advancedOptionsFrame.isHidden():
            self.advancedOptionsFrame.show()
            self.btnAdvancedOptions.setText("Hide advanced options")
        else:
            self.advancedOptionsFrame.hide()
            self.btnAdvancedOptions.setText("Show advanced options")

    def createShortcut(self):
        path = self.codeDir.leDirname.text()
        try:
            print("Attempting shortcut to path variable 'python3'")
            createShortcut(path, 'python3')
        except:
            print("'python3' failed using 'python'")
            createShortcut(path, 'python')

    def locateCodeFolder(self):
        root = "C:\\"
        pattern = '..\Jinn\Code\home.py'
        # Want to find all Jinn\Code paths
        # Performs a walk through operating system paths and looks for the match "Jinn\Code"
        # Potential for failure if user has multiple Jinns for some reason
        try:
            possibleDirs = []
            for path, dirs, files in os.walk(os.path.abspath(root)):
                if pathlib.PurePath(path).match('*/Jinn/Code'):
                    possibleDirs.append(path)

            print(possibleDirs)
        except Exception as ex:
            raise ex

        if len(possibleDirs) > 1:
            multipleJinnDialog = MultipleJinnDialog(possibleDirs)
            with multipleJinnDialog.delayedDeleteOnClose():
                multipleJinnDialog.exec()
                path = multipleJinnDialog.getPath()
        else:
            path = possibleDirs[0]

        self.codeDir.leDirname.setText(str(path))

    def updateCode(self):
        updateVariables = UpdateVariables()
        # Rename old code directory and then move new code and rename it
        codeDirPath = self.codeDir.leDirname.text()
        codeDirPath = os.path.abspath(codeDirPath)
        oldCodeFolder = updateVariables.getOldCodeDirWithDateTime()

        jinnDirPath = os.path.join(codeDirPath, "..")

        codeDirAlreadyExists = os.path.exists(codeDirPath)
        if codeDirAlreadyExists:
            updateJTextEdit(
                self.updateLog,
                "Rename existing \"{}\" directory to \"{}\", and ".format(
                    codeDirPath, oldCodeFolder))
        updateJTextEdit(
            self.updateLog,
            "Rename \"{}\" to \"{}\"\n".format(codeDirPath,
                                               updateVariables.codeDir))
        # rename existing `Code` directory to `OldCode`
        if codeDirAlreadyExists:
            oldCodeDirPath = os.path.join(jinnDirPath, oldCodeFolder)
            updateJTextEdit(
                self.updateLog,
                "Renaming \"{}\" to \"{}\"\n".format(codeDirPath,
                                                     oldCodeDirPath))
            os.rename(codeDirPath, oldCodeDirPath)
            # rename directory from extracted zip file to `Code`
            updateJTextEdit(
                self.updateLog,
                "Renaming \"{}\" to \"{}\"\n".format(codeDirPath, codeDirPath))
        # Old code folder is renamed. Now we need to move the newCode and rename it
        # New code is in UpdateVariables.getPath(newCode), unfortunately there is an unknown folder name here from Git
        # First work out the Git hub zip extracted name
        gitFolder = getImmediateSubdirectories(
            updateVariables.getPath(updateVariables.codeDir))[0]
        print(gitFolder)
        newCode = os.path.join(
            updateVariables.getPath(updateVariables.codeDir), gitFolder)
        try:
            os.chdir(newCode)
            shutil.copytree(newCode, codeDirPath)
            dialog = InfoMsgBox(
                "Update Finished",
                "Update finished with no faults. Code has been updated to the USB "
                "copy", "Finished")
            dialog.exec()
        except Exception as e:
            raise e
Esempio n. 6
0
class Tablewidget(QTableWidget):
    def __init__(self,parent):
        super().__init__()
        self.setParent(parent)
        self.frontandnextFlag = []
        self.pat = re.compile(r"<font style='background-color:red;'>(.*?)</font>")
        self.searchbox = QFrame(self)
        self.searchbox.setGeometry(10,50,330,30)
        # self.searchbox.setFrameRect(QRect(10,10,10,10))
        self.searchbox.setStyleSheet("border-radius:2px;background-color:rgb(200,200,200)")
        self.searchbox.setHidden(True)

        self.searchtextbox = QLineEdit(self.searchbox)
        self.searchtextbox.setGeometry(0,0,210,30)
        self.searchtextbox.setStyleSheet("border:none")

        #文本显示框
        self.textwindow = QTextEdit(self)
        self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100)
        self.textwindow.setVisible(False)
        self.textwindow_text = None
        #搜索窗口
        self.search = QPushButton("", self.searchbox)
        self.search.setIcon(QIcon("./pic/search.ico"))
        self.search.setGeometry(210, 0, 30, 30)
        self.search.setStyleSheet("border:none")
        self.search.clicked.connect(self.searchdata)

        self.front  =   QPushButton("",self.searchbox)
        self.front.setIcon(QIcon("./pic/front.ico"))
        self.front.setGeometry(240,0,30,30)
        self.front.setStyleSheet("border:none")
        self.front.clicked.connect(lambda: self.frontandnextpress(-1))

        self.next   =   QPushButton("", self.searchbox)
        self.next.setIcon(QIcon("./pic/next.ico"))
        self.next.setGeometry(270,0,30,30)
        self.next.setStyleSheet("border:none")
        self.next.clicked.connect(lambda: self.frontandnextpress(1))

        self.clo = QPushButton("", self.searchbox)
        self.clo.setIcon(QIcon("./pic/close.ico"))
        self.clo.setGeometry(300, 0, 30, 30)
        self.clo.setStyleSheet("border:none")
        self.clo.clicked.connect(self.searchboxclo)

        self.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        # 设置垂直方向滑块像素移动
        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        # 设置水平方向滑块像素移动
        self.setEditTriggers(QAbstractItemView.NoEditTriggers | QAbstractItemView.DoubleClicked)
        # 设置表格不可编辑
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        # 设置启用右键策略

    def showdata(self, data):
        self.setRowCount(len(data[0]) - 1)
        self.setColumnCount(len(data))
        for i in range(0, len(data)):  # 总列数,显示所有数据
            self.setHorizontalHeaderItem(i, QTableWidgetItem(data[i][0]))
            for j in range(1, len(data[0])):  # 总数据行数
                ss = QTableWidgetItem(data[i][j])
                self.setItem(j - 1, i, ss)
                ss.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)  # 设置所有单元格对齐方式

    def keyPressEvent(self, QkeyEvent):
        if QkeyEvent.key() == Qt.Key_F:
            if QApplication.keyboardModifiers() == Qt.ControlModifier:
                self.searchbox.show()
                self.searchbox.setHidden(False)
                self.searchtextbox.setFocus()
        elif QkeyEvent.key() == Qt.Key_Escape:
            if self.searchbox.isHidden():
                self.textwindow.setHidden(True)
            else:
                self.searchbox.setHidden(True)
                self.textwindow.setHidden(True)
        elif QkeyEvent.key() == Qt.Key_F2:
            self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100)
            detail = JSONEncoder().encode(self.textwindow_text)
            detail = json.loads(detail)
            self.textwindow.setText(json.dumps(detail, indent=5, ensure_ascii=False))
            self.textwindow.setHidden(False)


    def searchdata(self):
        self.frontandnextFlag = []
        global  pressFlag
        pressFlag = -1
        findtext = ""
        # if self.searchtextbox.text() == "":
        #     return
        # else:
        try:
            findtext = self.searchtextbox.text().split()[0]
        except IndexError:
            findtext = "$@##$$@!!"  #如果为空,标记特殊寻找字符,找不到将Qlabel替换为字符串
        for a in range(self.rowCount()):
            for b in range(self.columnCount()):
                if isinstance(type(self.item(a,b)),type(None)) and isinstance(type(self.cellWidget(a,b)),type(None)):
                    pass
                else:

                    if isinstance(type(self.cellWidget(a,b)),type(QLabel)):
                        if "<font style" in self.cellWidget(a,b).text():
                            d = self.cancelCssFormat(self.cellWidget(a,b).text())
                            celltext = self.cellWidget(a,b).text().replace(
                                "<font style='background-color:red;'>{}</font>".format(d),
                                d)
                            if findtext in celltext:
                                self.cellWidget(a,b).setText(self.setStrkeyColor(celltext,findtext))
                                self.frontandnextFlag.append([a,b])
                            else:
                                self.removeCellWidget(a,b)
                                celltext = celltext.replace("<br>", "\n")
                                self.setItem(a,b,QTableWidgetItem(celltext))
                        else:
                            celltext = self.cellWidget(a,b).text()
                            celltext = celltext.replace("<br>", "\n")
                            self.removeCellWidget(a,b)
                            self.setItem(a,b,QTableWidgetItem(celltext))
                    elif isinstance(type(self.item(a, b)), type(QTableWidgetItem)):
                        if findtext in self.item(a,b).text():
                            celltext = self.item(a,b).text().replace("\n","<br>")
                            celltext = self.setStrkeyColor(celltext,findtext)
                            lab = QLabel(celltext,self)
                            self.setCellWidget(a,b,lab)
                            self.setItem(a,b,QTableWidgetItem(""))
                            self.frontandnextFlag.append([a, b])
                            # print(a,b,type(self.cellWidget(a,b)),type(self.item(a,b)),"\n",lab.text())
                        else:
                            pass
                    else:
                        pass

    def setStrkeyColor(self,strdata,key):
        needstr = strdata.replace(key,"<font style='background-color:red;'>{}</font>".format(key))
        return needstr

    def cancelCssFormat(self,strdata):
        return self.pat.search(strdata).group(1)

    def stecellbackcolor(self,a,b,color=QColor(200,200,200)):
        self.item(a,b).setBackground(QColor(color))

    def searchboxclo(self):
        self.searchtextbox.clear()
        self.searchbox.close()

    def frontandnextpress(self,k):
        global pressFlag
        pressFlag += k
        if pressFlag >= 0 and pressFlag < len(self.frontandnextFlag):
            self.setCurrentCell(self.frontandnextFlag[pressFlag][0],self.frontandnextFlag[pressFlag][1])
        else:
            pressFlag = -1