예제 #1
0
class ModelNetClients:
    def __init__(self, table_view):
        self._model_net_clients = QStandardItemModel(table_view)
        self._table_view = table_view

    @property
    def list_clients(self):
        return self._model_net_clients

    def _update(self):
        self._table_view.setModel(self._model_net_clients)
        self._table_view.resizeColumnsToContents()
        self._table_view.scrollToBottom()
        self._table_view.selectRow(self._model_net_clients.rowCount() - 1)
        self._table_view.setModel(self._model_net_clients)

    def add_row(self, row_str):
        item = QStandardItem(row_str)
        item.setEditable(False)
        self._model_net_clients.appendRow([item])
        self._update()

    def del_row(self, row_str):
        items = self._model_net_clients.findItems(row_str)
        if items:
             self._model_net_clients.removeRow(items[0].row())
             self._update()

    def clear(self):
        self._model_net_clients.clear()
예제 #2
0
class NameList(QDockWidget):
    def __init__(self, window):
        super(NameList, self).__init__('Current Plots')
        self.namelist_model = QStandardItemModel()
        self.namelist_view = QListView()
        self.namelist_view.setModel(self.namelist_model)
        self.setWidget(self.namelist_view)
        self.window = window
        self.plot_dict = {}

        self.namelist_view.doubleClicked.connect(self.activate_item)
        self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu)
        delete_action = QAction("Delete Selected", self.namelist_view)
        ###
        pause_action = QAction("Stop Script", self.namelist_view)
        delete_action.triggered.connect(self.delete_item)
        pause_action.triggered.connect(self.pause)
        self.namelist_view.addAction(delete_action)
        ###
        self.namelist_view.addAction(pause_action)

    def activate_item(self, index):
        item = self.namelist_model.itemFromIndex(index)
        plot = self.plot_dict[str(item.text())]
        if plot.closed:
            plot.closed = False
            self.window.add_plot(plot)

    def delete_item(self):
        index = self.namelist_view.currentIndex()
        item = self.namelist_model.itemFromIndex(index)
        del self[str(item.text())]

    def pause(self):
        sock = socket.socket()
        sock.connect(('localhost', 9091))
        sock.send(b'stop')
        sock.close()

    def __getitem__(self, item):
        return self.plot_dict[item]

    def __setitem__(self, name, plot):
        model = QStandardItem(name)
        model.setEditable(False)
        self.namelist_model.appendRow(model)
        self.plot_dict[name] = plot

    def __contains__(self, value):
        return value in self.plot_dict

    def __delitem__(self, name):
        self.namelist_model.removeRow(self.namelist_model.findItems(name)[0].index().row())
        self.plot_dict[name].close()
        del self.plot_dict[name]

    def keys(self):
        return list(self.plot_dict.keys());
class TreeView(QTreeView):
    def __init__(self):
        super().__init__()
        self.model = QStandardItemModel(4, 2)
        self.model.setHeaderData(0, Qt.Horizontal, "service")
        self.model.setHeaderData(1, Qt.Horizontal, "Details")
        '''
        item1 = QStandardItem("avahi-daemon")
        item2 = QStandardItem("bluetooth")
        item3 = QStandardItem("crond")
        item4 = QStandardItem("cups")
        item5 = QStandardItem("fifth")

        self.model.setItem(0, 0, item1)
        self.model.setItem(1, 0, item2)
        self.model.setItem(2, 0, item3)
        self.model.setItem(3, 0, item4)
        item4.appendRow(item5)

        parent = QModelIndex()
        for i in range(0, 4):
            parent = self.model.index(0, 0, parent)
            self.model.insertRows(0, 1, parent)
            self.model.insertColumns(0, 1, parent)
            index = self.model.index(0, 0, parent)
            self.model.setData(index, i)
        '''
        self.setModel(self.model)

    def returnTheItems(self):
        return self.model.findItems("*", Qt.MatchWildcard | Qt.MatchRecursive)
        # item1.setIcon()

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            index0 = self.currentIndex()
            print(index0.data().toString())
예제 #4
0
class ComboItemModel(FilterModel):
    """Класс модели для комбобоксов с фильтрацией"""
    def __init__(self, parent=None):
        FilterModel.__init__(self, parent)
        self.parent = parent
        self._model = QStandardItemModel(0, 0)
        self._display = ""
        self.setSourceModel(self._model)
        self.setDynamicSortFilter(True)

    @property
    def display(self) -> str:
        """возвращает имя отображаемого поля"""
        return self._display

    def model(self) -> QStandardItemModel:
        """возвращает модель"""
        return self._model

    def fill(self, rows: list, display: str):
        """заполняет комбобокс элементами из списка"""
        self._display = display
        for _, value in enumerate(rows):
            self._model.appendRow(self.createRow(value))

    def createRow(self, data: dict) -> QStandardItem:
        """создаёт элемент-строку для комбобокса"""
        result = QStandardItem()
        result.setText(data[self._display] if self._display in
                       data else 'Error')
        result.setData(data, Qt.UserRole)
        return result

    def findIndex(self, value) -> int:
        """возвращает индекс элемента содержащего значение"""
        items = self._model.findItems('', Qt.MatchContains)
        if not items:
            return 0
        # функция поиска если value - словарь
        if isinstance(value, dict):
            key = next(iter(value))
            val = value[key]
            func = lambda data: key in data and data[key] == val
        # -/- если value - значение
        else:
            func = lambda data: value in data.values()
        return next((index for index, item in enumerate(items) \
                        if func(item.data(Qt.UserRole))), 0)

    def getItem(self, index=-1) -> QStandardItem:
        """возвращает элемент по индексу"""
        items = self._model.findItems('', Qt.MatchContains)
        if not items:
            return None
        if 0 <= index < self.rowCount():
            items = self._model.findItems('', Qt.MatchContains)
            return items[index]
        index = self.parent.currentIndex()
        return items[index]

    def selectContains(self, value):
        """устанавливает текущим элемент содержащий значение"""
        index = self.findIndex(value)
        self.applyFilter()
        self.select(index)

    def select(self, index):
        """устанавливает текущим элемент по индексу"""
        if self.parent:
            self.parent.setCurrentIndex(index)

    def checkAlreadySelected(self, condition):
        """проверяет выбран ли элемент списка отвечающий условию"""
        if not condition or not self.parent:
            return False
        item = self.parent.currentData()
        if not item:
            return False
        if isinstance(condition, dict):
            key = next(iter(condition))
            return (key in item) and (item[key] == condition[key])
        return condition in item.values()
예제 #5
0
class NameList(QDockWidget):
    def __init__(self, window):
        super(NameList, self).__init__('Current Plots')
        self.namelist_model = QStandardItemModel()
        self.namelist_view = QListView()
        self.namelist_view.setModel(self.namelist_model)
        self.setWidget(self.namelist_view)
        self.window = window
        self.plot_dict = {}

        self.namelist_view.doubleClicked.connect(self.activate_item)
        self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu)
        delete_action = QAction("Delete Selected", self.namelist_view)
        ###
        pause_action = QAction("Stop Script", self.namelist_view)
        delete_action.triggered.connect(self.delete_item)
        pause_action.triggered.connect(self.pause)
        self.namelist_view.addAction(delete_action)
        self.namelist_view.addAction(pause_action)

        open_action = QAction('Open 1D Data', self)
        open_action.triggered.connect(self.open_file_dialog)
        self.namelist_view.addAction(open_action)

        open_action_2 = QAction('Open 2D Data', self)
        open_action_2.triggered.connect(self.open_file_dialog_2)
        self.namelist_view.addAction(open_action_2)

    def open_file_dialog(self, directory='', header=0):
        file_path = self.file_dialog(directory=directory)

        header_array = []
        file_to_read = open(file_path, 'r')
        for i, line in enumerate(file_to_read):
            if i is header: break
            temp = line.split(":")
            header_array.append(temp)
        file_to_read.close()

        temp = np.genfromtxt(file_path,
                             dtype=float,
                             delimiter=',',
                             skip_header=1)
        data = np.transpose(temp)

        name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        pw = self.window.add_new_plot(1, name_plot)
        pw.plot(data[0], data[1], parametric=True, name=file_path, xname='X', xscale ='Arb. U.',\
         yname='Y', yscale ='Arb. u.', scatter='False')

    def open_file_dialog_2(self, directory='', header=0):
        file_path = self.file_dialog(directory=directory)

        header_array = []
        file_to_read = open(file_path, 'r')
        for i, line in enumerate(file_to_read):
            if i is header: break
            temp = line.split(":")
            header_array.append(temp)
        file_to_read.close()

        temp = np.genfromtxt(file_path, dtype=float, delimiter=',')
        data = temp

        name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        pw = self.window.add_new_plot(2, name_plot)
        pw.setAxisLabels(xname='X', xscale ='Arb. U.',yname='X', yscale ='Arb. U.',\
            zname='X', zscale ='Arb. U.')
        pw.setImage(data, axes={'y': 0, 'x': 1})

    def file_dialog(self, directory=''):
        root = tkinter.Tk()
        root.withdraw()

        file_path = filedialog.askopenfilename(**dict(
            initialdir = directory,
            filetypes = [("CSV", "*.csv"), ("TXT", "*.txt"),\
            ("DAT", "*.dat"), ("all", "*.*")],
            title = 'Select file to open')
            )
        return file_path

    def activate_item(self, index):
        item = self.namelist_model.itemFromIndex(index)
        plot = self.plot_dict[str(item.text())]
        if plot.closed:
            plot.closed = False
            self.window.add_plot(plot)

    def delete_item(self):
        index = self.namelist_view.currentIndex()
        item = self.namelist_model.itemFromIndex(index)
        del self[str(item.text())]

    def pause(self):
        sock = socket.socket()
        sock.connect(('localhost', 9091))
        sock.send(b'Script stopped')
        sock.close()

    def __getitem__(self, item):
        return self.plot_dict[item]

    def __setitem__(self, name, plot):
        model = QStandardItem(name)
        model.setEditable(False)
        self.namelist_model.appendRow(model)
        self.plot_dict[name] = plot

    def __contains__(self, value):
        return value in self.plot_dict

    def __delitem__(self, name):
        self.namelist_model.removeRow(
            self.namelist_model.findItems(name)[0].index().row())
        self.plot_dict[name].close()
        del self.plot_dict[name]

    def keys(self):
        return list(self.plot_dict.keys())
예제 #6
0
class PwdManager(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowTitleHint)
        self.setWindowTitle('Password Manager')
        self.setFixedSize(400, 300)
        self.PwdViewer = QListView()
        self.PwdViewer.clicked.connect(self.ClickPwd)
        self.AddButton = QPushButton('Add')
        self.AddButton.clicked.connect(self.AddPwd)
        self.DelButton = QPushButton('Delete')
        self.DelButton.clicked.connect(self.DelPwd)
        self.PwdBox = QLineEdit()
        self.PwdBox.textEdited.connect(self.PwdChanged)

        vbox = QVBoxLayout()
        vbox.addWidget(self.AddButton)
        vbox.addWidget(self.DelButton)
        vbox.addStretch(1)
        hbox = QHBoxLayout()
        hbox.addWidget(self.PwdViewer)
        hbox.addLayout(vbox)
        MainBox = QVBoxLayout()
        MainBox.addWidget(self.PwdBox)
        MainBox.addLayout(hbox)
        self.setLayout(MainBox)

    def showEvent(self, event):
        self.center()
        self.LoadPwdToList()
        if self.Model.rowCount() == 0:
            self.AddPwd()
        self.IsChanged = False

    def closeEvent(self, event):
        self.RemoveEmpty()
        pwdf = open('password.pwd', 'w')
        for index in range(self.Model.rowCount()):
            pwdf.write(self.Model.data(self.Model.index(index, 0)) + '\n')
        pwdf.close()
        if self.IsChanged:
            self.done(1)
        else:
            self.done(0)

    def center(self):
        frameGm = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(
            QApplication.desktop().cursor().pos())
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

    def LoadPwdToList(self):
        if not os.path.exists(r'password.pwd'):
            open("password.pwd", "wb").close()
        pwdf = open('password.pwd', 'r')
        pwdlist = pwdf.read().splitlines()
        pwdf.close()
        self.Model = QStandardItemModel(self.PwdViewer)
        for pwd in pwdlist:
            item = QStandardItem(pwd)
            item.setEditable(False)
            self.Model.appendRow(item)
        self.PwdViewer.setModel(self.Model)
        self.PwdViewer.setCurrentIndex(self.Model.index(0, 0))
        self.GetPwd(self.PwdViewer.currentIndex())

    def ClickPwd(self, index):
        self.RemoveEmpty()
        if self.Model.rowCount() == 0:
            self.AddPwd()
        self.GetPwd(index)

    def GetPwd(self, index):
        self.PwdBox.setText(self.Model.data(index))
        self.PwdBox.setFocus()

    def PwdChanged(self):
        self.IsChanged = True
        self.Model.setData(self.PwdViewer.currentIndex(), self.PwdBox.text())
        if self.PwdBox.text() == '':
            self.DelPwd()

    def DelPwd(self):
        self.Model.removeRow(self.PwdViewer.currentIndex().row())
        self.GetPwd(self.PwdViewer.currentIndex())
        if self.Model.rowCount() == 0:
            self.AddPwd()

    def AddPwd(self):
        item = QStandardItem()
        item.setEditable(False)
        self.Model.appendRow(item)
        self.PwdViewer.setCurrentIndex(
            self.Model.index(self.Model.rowCount() - 1, 0))
        self.GetPwd(self.PwdViewer.currentIndex())

    def RemoveEmpty(self):
        for item in self.Model.findItems('', Qt.MatchFixedString):
            self.Model.removeRow(item.row())
예제 #7
0
파일: bookmarks.py 프로젝트: Ghxst/Dwarf
class BookmarksWidget(QWidget):
    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(BookmarksWidget, self).__init__(parent=parent)

        self._app_window = parent

        if self._app_window.dwarf is None:
            print('BookmarksPanel created before Dwarf exists')
            return

        self.bookmarks = {}

        self._bookmarks_list = DwarfListView()
        self._bookmarks_list.doubleClicked.connect(self._on_double_clicked)
        self._bookmarks_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._bookmarks_list.customContextMenuRequested.connect(
            self._on_contextmenu)

        self._bookmarks_model = QStandardItemModel(0, 2)
        self._bookmarks_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._bookmarks_model.setHeaderData(1, Qt.Horizontal, 'Notes')

        self._bookmarks_list.setModel(self._bookmarks_model)

        self._bookmarks_list.header().setStretchLastSection(False)
        self._bookmarks_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._bookmarks_list.header().setSectionResizeMode(
            1, QHeaderView.Stretch | QHeaderView.Interactive)

        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        v_box.addWidget(self._bookmarks_list)
        #header = QHeaderView(Qt.Horizontal, self)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        self.btn1 = QPushButton(
            QIcon(utils.resource_path('assets/icons/plus.svg')), '')
        self.btn1.setFixedSize(20, 20)
        self.btn1.clicked.connect(lambda: self._create_bookmark(-1))
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(self.btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)
        self.setLayout(v_box)

        self._bold_font = QFont(self._bookmarks_list.font())
        self._bold_font.setBold(True)

        shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_B),
                                       self._app_window, self._create_bookmark)
        shortcut_addnative.setAutoRepeat(False)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def delete_items(self):
        """ Delete selected Items
        """
        index = self._bookmarks_list.selectionModel().currentIndex().row()
        if index != -1:
            self._on_delete_bookmark(index)
            self._bookmarks_model.removeRow(index)

    def clear_list(self):
        """ Clear the List
        """
        # go through all items and tell it gets removed
        for item in range(self._bookmarks_model.rowCount()):
            self._on_delete_bookmark(item)

        if self._bookmarks_model.rowCount() > 0:
            # something was wrong it should be empty
            self._bookmarks_model.removeRows(0,
                                             self._bookmarks_model.rowCount())

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_double_clicked(self, index):
        index = self._bookmarks_list.selectionModel().currentIndex().row()
        if index != -1:
            addr = self._bookmarks_model.item(index, 0).text()
            if addr:
                self._app_window.jump_to_address(addr)

    def _on_contextmenu(self, pos):
        context_menu = QMenu(self)
        index = self._bookmarks_list.indexAt(pos).row()
        if index != -1:
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._bookmarks_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._bookmarks_model.item(index, 0).text()))

            # todo: add hook address menu

            context_menu.addSeparator()
            context_menu.addAction('Edit',
                                   lambda: self._create_bookmark(index=index))
            context_menu.addAction('Delete',
                                   lambda: self._on_delete_bookmark(index))
            context_menu.addSeparator()
            if self._bookmarks_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction('Search',
                                       self._bookmarks_list._on_cm_search)
                context_menu.addSeparator()
        context_menu.addAction('New', self._create_bookmark)
        global_pt = self._bookmarks_list.mapToGlobal(pos)
        context_menu.exec(global_pt)

    # + button
    def _create_bookmark(self, index=-1, ptr=''):
        note = ''

        if ptr == '':
            if isinstance(index, int) and index >= 0:
                ptr = self._bookmarks_model.item(index, 0).text()
                note = self._bookmarks_model.item(index, 1).text()

            ptr, _ = InputDialog.input_pointer(parent=self._app_window,
                                               input_content=ptr)
        else:
            if not isinstance(ptr, int):
                try:
                    if ptr.startswith('0x'):
                        ptr = int(ptr, 16)
                    else:
                        ptr = int(ptr)
                except ValueError:
                    ptr = 0

        if ptr > 0:
            ptr = hex(ptr)
            if self._bookmarks_list.uppercase_hex:
                ptr = ptr.upper().replace('0X', '0x')

            index = self._bookmarks_model.findItems(ptr, Qt.MatchExactly)
            if len(index) > 0:
                index = index[0].row()
                note = self._bookmarks_model.item(index, 1).text()
            else:
                index = -1

            accept, note = InputDialog.input(hint='Insert notes for %s' % ptr,
                                             input_content=note)
            if accept:
                if index < 0:
                    self.insert_bookmark(ptr, note)
                else:
                    item = self._bookmarks_model.item(index, 0)
                    item.setText(ptr)
                    item = self._bookmarks_model.item(index, 1)
                    item.setText(note)

                self.bookmarks[ptr] = note

    def insert_bookmark(self, ptr_as_hex, note):
        if self._bookmarks_list.uppercase_hex:
            ptr_as_hex = ptr_as_hex.upper().replace('0X', '0x')

        self._bookmarks_model.appendRow(
            [QStandardItem(ptr_as_hex),
             QStandardItem(note)])
        self._bookmarks_list.resizeColumnToContents(0)

    # shortcuts/menu
    def _on_delete_bookmark(self, index):
        ptr = self._bookmarks_model.item(index, 0).text()
        del self.bookmarks[ptr]

        self._bookmarks_model.removeRow(index)
예제 #8
0
class HooksWidget(QWidget):
    """ HooksPanel

        Signals:
            onShowMemoryRequest(str) - ptr
            onHookChanged(str) - ptr
            onHookRemoved(str) - ptr
    """

    onHookChanged = pyqtSignal(str, name='onHookChanged')
    onHookRemoved = pyqtSignal(str, name='onHookRemoved')

    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(HooksWidget, self).__init__(parent=parent)

        self._app_window = parent

        if self._app_window.dwarf is None:
            print('HooksPanel created before Dwarf exists')
            return

        # connect to dwarf
        self._app_window.dwarf.onAddJavaHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddNativeHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddNativeOnLoadHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddJavaOnLoadHook.connect(self._on_add_hook)
        self._app_window.dwarf.onHitNativeOnLoad.connect(
            self._on_hit_native_on_load)
        self._app_window.dwarf.onHitJavaOnLoad.connect(
            self._on_hit_java_on_load)
        self._app_window.dwarf.onDeleteHook.connect(self._on_hook_deleted)

        self._hooks_list = DwarfListView()
        self._hooks_list.doubleClicked.connect(self._on_double_clicked)
        self._hooks_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._hooks_list.customContextMenuRequested.connect(
            self._on_context_menu)
        self._hooks_model = QStandardItemModel(0, 5)

        self._hooks_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._hooks_model.setHeaderData(1, Qt.Horizontal, 'T')
        self._hooks_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)
        self._hooks_model.setHeaderData(2, Qt.Horizontal, 'Input')
        self._hooks_model.setHeaderData(3, Qt.Horizontal, '{}')
        self._hooks_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)
        self._hooks_model.setHeaderData(4, Qt.Horizontal, '<>')
        self._hooks_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)

        self._hooks_list.setModel(self._hooks_model)

        self._hooks_list.header().setStretchLastSection(False)
        self._hooks_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._hooks_list.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self._hooks_list.header().setSectionResizeMode(2, QHeaderView.Stretch)
        self._hooks_list.header().setSectionResizeMode(
            3, QHeaderView.ResizeToContents)
        self._hooks_list.header().setSectionResizeMode(
            4, QHeaderView.ResizeToContents)

        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        v_box.addWidget(self._hooks_list)
        #header = QHeaderView(Qt.Horizontal, self)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        self.btn1 = QPushButton(
            QIcon(utils.resource_path('assets/icons/plus.svg')), '')
        self.btn1.setFixedSize(20, 20)
        self.btn1.clicked.connect(self._on_additem_clicked)
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(self.btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)
        self.setLayout(v_box)

        self._bold_font = QFont(self._hooks_list.font())
        self._bold_font.setBold(True)

        shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_N),
                                       self._app_window, self._on_addnative)
        shortcut_addnative.setAutoRepeat(False)

        shortcut_addjava = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J),
                                     self._app_window, self._on_addjava)
        shortcut_addjava.setAutoRepeat(False)

        shortcut_add_native_on_load = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window,
            self._on_add_native_on_load)
        shortcut_add_native_on_load.setAutoRepeat(False)

        # new menu
        self.new_menu = QMenu('New')
        self.new_menu.addAction('Native', self._on_addnative)
        self.new_menu.addAction('Java', self._on_addjava)
        self.new_menu.addAction('Module loading', self._on_add_native_on_load)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def delete_items(self):
        """ Delete selected Items
        """
        index = self._hooks_list.selectionModel().currentIndex().row()
        if index != -1:
            self._on_delete_hook(index)
            self._hooks_model.removeRow(index)

    def clear_list(self):
        """ Clear the List
        """
        # go through all items and tell it gets removed
        for item in range(self._hooks_model.rowCount()):
            self._on_delete_hook(item)

        if self._hooks_model.rowCount() > 0:
            # something was wrong it should be empty
            self._hooks_model.removeRows(0, self._hooks_model.rowCount())

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_add_hook(self, hook):
        type_ = QStandardItem()
        type_.setFont(self._bold_font)
        type_.setTextAlignment(Qt.AlignCenter)
        if hook.hook_type == HOOK_NATIVE:
            type_.setText('N')
            type_.setToolTip('Native hook')
        elif hook.hook_type == HOOK_JAVA:
            type_.setText('J')
            type_.setToolTip('Java hook')
        elif hook.hook_type == HOOK_ONLOAD:
            type_.setText('O')
            type_.setToolTip('On load hook')
        else:
            type_.setText('U')
            type_.setToolTip('Unknown Type')

        addr = QStandardItem()

        if hook.hook_type == HOOK_JAVA:
            parts = hook.get_input().split('.')
            addr.setText('.'.join(parts[:len(parts) - 1]))
        else:
            str_fmt = '0x{0:x}'
            if self._hooks_list.uppercase_hex:
                str_fmt = '0x{0:X}'
            # addr.setTextAlignment(Qt.AlignCenter)
            addr.setText(str_fmt.format(hook.get_ptr()))

        inp = QStandardItem()
        inp_text = hook.get_input()
        if hook.hook_type == HOOK_JAVA:
            parts = inp_text.split('.')
            inp_text = parts[len(parts) - 1]
        # if len(inp_text) > 15:
        #    inp_text = inp_text[:15] + '...'
        #    inp.setToolTip(hook.get_input())
        inp.setText(inp_text)
        inp.setData(hook.get_input(), Qt.UserRole + 2)
        inp.setToolTip(hook.get_input())

        logic = QStandardItem()
        logic.setTextAlignment(Qt.AlignCenter)
        logic.setFont(self._bold_font)
        if hook.logic and hook.logic != 'null' and hook.logic != 'undefined':
            logic.setText('ƒ')
            logic.setToolTip(hook.logic)
            logic.setData(hook.logic, Qt.UserRole + 2)

        condition = QStandardItem()
        condition.setTextAlignment(Qt.AlignCenter)
        condition.setFont(self._bold_font)
        if hook.condition and hook.condition != 'null' and hook.condition != 'undefined':
            condition.setText('ƒ')
            condition.setToolTip(hook.condition)
            condition.setData(hook.condition, Qt.UserRole + 2)

        self._hooks_model.appendRow([addr, type_, inp, logic, condition])

    def _on_hit_native_on_load(self, data):
        items = self._hooks_model.findItems(data[1]['module'], Qt.MatchExactly,
                                            2)
        if len(items) > 0:
            self._hooks_model.item(items[0].row(),
                                   0).setText(data[1]['moduleBase'])

    def _on_hit_java_on_load(self, data):
        items = self._hooks_model.findItems(data[0], Qt.MatchExactly, 2)
        if len(items) > 0:
            pass

    def _on_double_clicked(self, model_index):
        item = self._hooks_model.itemFromIndex(model_index)
        if model_index.column() == 3 and item.text() == 'ƒ':
            self._on_modify_logic(model_index.row())
        elif model_index.column() == 4 and item.text() == 'ƒ':
            self._on_modify_condition(model_index.row())
        else:
            self._app_window.jump_to_address(self._hooks_model.item(
                model_index.row(), 0).text(),
                                             view=1)

    def _on_context_menu(self, pos):
        context_menu = QMenu(self)
        context_menu.addMenu(self.new_menu)

        context_menu.addSeparator()
        index = self._hooks_list.indexAt(pos).row()
        if index != -1:
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._hooks_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._hooks_model.item(index, 0).text()))
            context_menu.addSeparator()
            context_menu.addAction('Edit Logic',
                                   lambda: self._on_modify_logic(index))
            context_menu.addAction('Edit Condition',
                                   lambda: self._on_modify_condition(index))
            context_menu.addSeparator()
            context_menu.addAction('Delete Hook',
                                   lambda: self._on_delete_hook(index))

            if self._hooks_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction('Search',
                                       self._hooks_list._on_cm_search)

        # show context menu
        global_pt = self._hooks_list.mapToGlobal(pos)
        context_menu.exec(global_pt)

    def _on_modify_logic(self, num_row):
        item = self._hooks_model.item(num_row, 3)
        data = item.data(Qt.UserRole + 2)
        if data is None:
            data = ''
        ptr = self._hooks_model.item(num_row, 0).text()
        accept, input_ = InputMultilineDialog().input('Insert logic for %s' %
                                                      ptr,
                                                      input_content=data)
        if accept:
            what = utils.parse_ptr(ptr)
            if what == 0:
                what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            if self._app_window.dwarf.dwarf_api(
                    'setHookLogic', [what, input_.replace('\n', '')]):
                item.setData(input_, Qt.UserRole + 2)
                if not item.text():
                    item.setText('ƒ')
                item.setToolTip(input_)
                self.onHookChanged.emit(ptr)

    def _on_modify_condition(self, num_row):
        item = self._hooks_model.item(num_row, 4)
        data = item.data(Qt.UserRole + 2)
        if data is None:
            data = ''
        ptr = self._hooks_model.item(num_row, 0).text()
        accept, input_ = InputDialog().input(self._app_window,
                                             'Insert condition for %s' % ptr,
                                             input_content=data)
        if accept:
            what = utils.parse_ptr(ptr)
            if what == 0:
                what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            if self._app_window.dwarf.dwarf_api('setHookCondition',
                                                [what, input_]):
                item.setData(input_, Qt.UserRole + 2)
                if not item.text():
                    item.setText('ƒ')
                item.setToolTip(input_)
                self.onHookChanged.emit(ptr)

    # + button
    def _on_additem_clicked(self):
        self.new_menu.exec_(QCursor.pos())

    # shortcuts/menu
    def _on_addnative(self):
        self._app_window.dwarf.hook_native()

    def _on_addjava(self):
        self._app_window.dwarf.hook_java()

    def _on_add_native_on_load(self):
        self._app_window.dwarf.hook_native_on_load()

    def _on_add_java_on_load(self):
        self._app_window.dwarf.hook_java_on_load()

    def _on_delete_hook(self, num_row):
        hook_type = self._hooks_model.item(num_row, 1).text()
        if hook_type == 'N':
            ptr = self._hooks_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('deleteHook', ptr)
            self.onHookRemoved.emit(str(ptr))
        elif hook_type == 'J':
            input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            self._app_window.dwarf.dwarf_api('deleteHook', input_)
        elif hook_type == 'O':
            input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            self._app_window.dwarf.dwarf_api('deleteHook', input_)
        elif hook_type == 'U':
            ptr = self._hooks_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('deleteHook', ptr)
            self.onHookRemoved.emit(str(ptr))

    def _on_hook_deleted(self, parts):
        _msg, _type, _val = parts

        additional = None

        if _type == 'java' or _type == 'java_on_load':
            _val = _val.split('.')
            str_frmt = '.'.join(_val[:-1])
            additional = _val[-1]
            item_index = 0
        elif _type == 'native_on_load':
            str_frmt = _val
            item_index = 2
        else:
            _ptr = utils.parse_ptr(_val)
            if self._hooks_list._uppercase_hex:
                str_frmt = '0x{0:X}'.format(_ptr)
            else:
                str_frmt = '0x{0:x}'.format(_ptr)
            item_index = 0

        for _item in range(self._hooks_model.rowCount()):
            item = self._hooks_model.item(_item, item_index)

            if item is None:
                continue

            if str_frmt == item.text():
                if additional is not None:
                    if additional == self._hooks_model.item(_item, 2).text():
                        self._hooks_model.removeRow(_item)
                else:
                    self._hooks_model.removeRow(_item)
예제 #9
0
class ClientGui(QWidget):
    def __init__(self):
        self.service_msg_deq = []  # очередь сервисных сообщений, очищать!
        self.icon_user = QIcon("user.svg")
        self.icon_new_msg = QIcon("message.svg")
        super().__init__()

        self.get_login_dialog()

    def initUI(self):

        # Кнопки: добавить/удалить контакты в контакт лист
        self.button_add_contact = QPushButton('add', self)
        self.button_add_contact.clicked.connect(self.add_contact)
        self.button_del_contact = QPushButton('del', self)
        self.button_del_contact.clicked.connect(self.del_contact)
        self.button_settings = QPushButton('men', self)
        self.button_settings.setEnabled(False)  # не работает
        self.button_connect = QPushButton('conn', self)
        self.button_connect.setEnabled(False)  # не работает

        self.box_button = QHBoxLayout()
        self.box_button.addWidget(self.button_add_contact)
        self.box_button.addWidget(self.button_del_contact)
        self.box_button.addWidget(self.button_settings)
        self.box_button.addWidget(self.button_connect)

        # создаю модель для листа контактов, подключаю отображение
        cl = bd_client_app.BDContacts().get_contacts()
        self.model_cl = QStandardItemModel()
        for user in cl:
            row = QStandardItem(self.icon_user, user)
            self.model_cl.appendRow(row)

        self.contact_list = QListView()
        self.contact_list.setModel(self.model_cl)
        self.contact_list.setSelectionMode(QListView.SingleSelection)
        self.contact_list.setEditTriggers(QListView.NoEditTriggers)
        self.contact_list.clicked.connect(self.select_conlist)

        # строка и кнопка отправки сообщений
        qButton = QPushButton('>>', self)
        qButton.clicked.connect(self.send_click)
        self.sendBox = QLineEdit(self)
        self.sendBox.returnPressed.connect(self.send_click)

        self.messageBox = QStackedWidget()
        # два словаря, в первом: логин ключ виджет значение, второй наоборот
        self.messageBox_dict_ctw = {}
        self.messageBox_dict_wtc = {}
        for user in cl:
            self.messageBox_dict_ctw[user] = QListWidget()
            self.messageBox_dict_wtc[self.messageBox_dict_ctw[user]] = user
            self.messageBox.addWidget(self.messageBox_dict_ctw[user])

        grid = QGridLayout()
        # строка, столбец, растянуть на строк, растянуть на столбцов
        grid.addWidget(self.contact_list, 0, 0, 2, 3)
        grid.addLayout(self.box_button, 2, 0)
        grid.addWidget(self.messageBox, 0, 3, 2, 3)
        grid.addWidget(self.sendBox, 2, 3, 1, 2)
        grid.addWidget(qButton, 2, 5)

        grid.setSpacing(5)
        grid.setColumnMinimumWidth(3, 200)
        grid.setColumnStretch(3, 10)
        self.setLayout(grid)

        self.resize(800, 300)
        self.center()
        self.setWindowTitle('Avocado')
        self.setWindowIcon(QIcon('icon.svg'))
        self.show()

    def initThreads(self):
        self.print_thread = ClientThreads(self.client, self)
        self.print_thread.print_signal.connect(self.add_message)
        self.print_thread.start()

    def get_login_dialog(self):

        text, ok = QInputDialog.getText(self, 'Login', 'Connect with login:')
        self.login_name = str(text)

        if ok:
            self.service_msg_deq.clear()  # жду свой ответ

            self.init_client()
            self.initThreads()

            # while not self.service_msg_deq:
            #     print(self.service_msg_deq)
            #     pass  # жду ответ
            # if self.service_msg_deq[0] is True:
            time.sleep(1)
            self.initUI()
            # else:
            #     self.exit()
        else:
            self.exit()

    def init_client(self):
        self.client = client.Client(self.login_name, "localhost", 7777)
        self.client.start_th_gui_client()

    def center(self):
        # центрирую окно
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    @pyqtSlot()
    def send_click(self):
        text_to_send = self.sendBox.text()
        if text_to_send.rstrip():
            self.messageBox.currentWidget().addItem("<< " + text_to_send)
            self.client.inp_queue.put(text_to_send)
        self.sendBox.clear()

    @pyqtSlot(QModelIndex)
    def select_conlist(self, curr):
        self.messageBox.setCurrentIndex(curr.row())
        self.model_cl.itemFromIndex(curr).setIcon(self.icon_user)
        self.client.to_user = self.messageBox_dict_wtc[
            self.messageBox.currentWidget()]

    @pyqtSlot(tuple)
    def add_message(self, message):
        msg = message[0]
        from_u = message[1]

        try:
            client_widget = self.messageBox_dict_ctw[from_u]
        except KeyError:
            mesg_con_log.error("Message from user from not in contact list:")
            mesg_con_log.error("%s, %s" % (from_u, msg))
        else:
            client_widget.addItem(">> " + msg)
            message_from = self.model_cl.findItems(from_u)[0]
            if self.contact_list.currentIndex() != self.model_cl.indexFromItem(
                    message_from):
                message_from.setIcon(self.icon_new_msg)

    @pyqtSlot()
    def del_contact(self):
        user = self.client.to_user
        self.client.inp_queue.put("del_contact " + user)
        self.messageBox.removeWidget(self.messageBox_dict_ctw[user])
        self.model_cl.takeRow(
            self.model_cl.indexFromItem(
                self.model_cl.findItems(user)[0]).row())

    @pyqtSlot()
    def add_contact(self):
        user = self.sendBox.text()
        self.service_msg_deq.clear()  # жду свой ответ
        self.client.inp_queue.put("add_contact " + user)

        while not self.service_msg_deq:
            pass  # жду ответ

        if self.service_msg_deq[0] is True:
            row = QStandardItem(self.icon_user, user)
            self.model_cl.appendRow(row)

            self.messageBox_dict_ctw[user] = QListWidget()
            self.messageBox_dict_wtc[self.messageBox_dict_ctw[user]] = user
            self.messageBox.addWidget(self.messageBox_dict_ctw[user])
        else:
            pass

        self.sendBox.clear()
예제 #10
0
class TreeWidget(QTreeView):
    """ Displays objects as an object tree """
    def __init__(self, parent):
        super(TreeWidget, self).__init__(parent)
        self.parent = parent

        # add menu
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.open_menu)

        self.model = QStandardItemModel()
        self.setModel(self.model)
        self.model.setHorizontalHeaderLabels(["Objects"])
        self.model.itemChanged.connect(self.edit_name)

    def edit_name(self, item):
        """ Makes the name of the item in the tree matches the object name """
        obj = item.data()
        if obj:
            obj.name = item.text()

    def addItem(self, item, header, mainheader=None, editable=True):
        """ Adds item to tree """
        if mainheader is None:
            finds = self.model.findItems(header)
            if not finds:
                itemheader = QStandardItem(header)
                self.model.appendRow(itemheader)
            else:
                itemheader = finds[0]
        else:
            finds = self.model.findItems(mainheader)
            if not finds:
                raise Exception('main header %s does not exist' % mainheader)
            main_itemheader = finds[0]

            for i in range(main_itemheader.rowCount()):
                itemheader = main_itemheader.child(i, 0)
                if itemheader:
                    if header is itemheader.data():
                        break

        standardItem = QStandardItem(item.name)
        standardItem.setEditable(editable)
        standardItem.setData(item)
        itemheader.appendRow(standardItem)

    def open_menu(self, position):  # pragma: no cover
        """ Activates when right click in tree """
        index = self.selectedIndexes()

        if not index:
            return
        item = self.model.itemFromIndex(index[0])
        obj = item.data()

        if hasattr(obj, 'menu'):
            menu = obj.menu
            menu.exec_(self.viewport().mapToGlobal(position))
            return menu

    def remove_item(self, data):
        """ removes an item from the modal list """
        removed = False
        # check each header for a match
        for i in range(self.model.rowCount()):
            header = self.model.item(i)
            for i in range(header.rowCount()):
                item = header.child(i, 0)
                if item:
                    if data is item.data():
                        item.setData(None)
                        header.removeRow(i)
                        removed = removed or True
                        break

                if item.hasChildren():
                    for j in range(item.rowCount()):
                        subitem = item.child(j, 0)
                        if data is subitem.data():
                            subitem.setData(None)
                            item.removeRow(j)
                            removed = removed or True
                            break

            # remove empty headers
            if not header.rowCount():
                self.model.removeRow(header.row())
                break

        return removed
예제 #11
0
class RemoteTree(QObject):
    def __init__(self, tv: QTreeView, fv: FileView, clnt_socket: ClntSocket):
        super(RemoteTree, self).__init__()
        self.tv = tv
        self.fv = fv
        self.clnt_socket = clnt_socket
        self.remote_model = QStandardItemModel(self)
        self.tv.header().hide()
        self.tv.setModel(self.remote_model)
        self.clnt_list = list()
        self.tv.clicked.connect(self.item_click)
        self.tv.expanded.connect(self.item_expand)

        self.rt_model = QStandardItemModel(self)
        self.rt_model.setColumnCount(4)
        self.rt_model.setHeaderData(0, Qt.Horizontal, "Name")
        self.rt_model.setHeaderData(1, Qt.Horizontal, "Size")
        self.rt_model.setHeaderData(2, Qt.Horizontal, "Type")
        self.rt_model.setHeaderData(3, Qt.Horizontal, "Date Modified")

    def tree_view_update(self, msg):
        print("get a signal: ", msg)
        if msg[0] == HW_DATA_TYPE_LOGIN:
            name_list = list()
            cid_list = list()
            for i in msg[2]:
                name_list.append(i["name"])
                cid_list.append(i["cid"])
                self.clnt_list.append(i)
            self.children_item_update(self.remote_model, name_list)
            for cid in cid_list:
                self.clnt_socket.hw_cmd_list("tree", cid, "/")

        elif msg[0] == HW_DATA_TYPE_CMD:
            if msg[2] == "tree":
                # recved_data = [data_type, cid, act["cmd"], act["path"], act["list"]]
                root_item = self.remote_model.findItems(self.get_name_by_cid(msg[1]))[0]
                print("dest device item: ", root_item.text())  # dell
                tail_item = root_item
                if msg[3] is not "/":
                    tail_item = self.get_item_by_path(msg[3], root_item)
                print("tail item: ", tail_item.text())
                self.children_item_update(tail_item, msg[4])

    @staticmethod
    def children_item_update(item, name_list):
        item_type = type(item)

        children_item = list()
        if item_type == QStandardItemModel:
            children_item = item.findItems("", Qt.MatchContains)
        else:
            print("start update item: ", item.text())
            row_cnt = item.rowCount()
            for i in range(row_cnt):
                ic = item.child(i)
                if ic is None:
                    print("child item is None???")
                    continue
                children_item.append(ic)

        children = list()
        for child in children_item:
            child_name = child.text()
            children.append(child_name)
        print("children: ", children)

        for name in children:
            if name not in name_list:
                child_index = children.index(name)
                # print("child name: %s, index: %d" % (name, child_index))
                if item_type == QStandardItemModel:
                    item.takeChild(item.child(child_index))
                else:
                    item.takeChild(child_index)
        for name in name_list:
            if name not in children:
                item.appendRow(QStandardItem(QFileIconProvider().icon(QFileIconProvider.Folder), name))
        print("children item update done")

    def get_item_by_path(self, path: str, item: QStandardItem):
        item_name_list = path.strip('/').split('/')
        des_item = item
        for i in item_name_list:
            des_item = self.get_item_by_name(i, des_item)
            if des_item is None:
                return None
        return des_item

    @staticmethod
    def get_item_by_name(name: str, item: QStandardItem):
        cnt = item.rowCount()
        for i in range(cnt):
            if item.child(i).text() == name:
                return item.child(i)
        return None

    @staticmethod
    def get_full_path(item: QStandardItem):
        full_path = "/" + item.text() + "/"
        pitem = item
        while True:
            pitem = pitem.parent()
            if pitem is None:
                break
            full_path = "/" + pitem.text() + full_path
        return full_path

    def get_cid_by_name(self, name: str):
        for c in self.clnt_list:
            if c["name"] == name:
                return c["cid"]
        return 0

    def get_name_by_cid(self, cid: int):
        for c in self.clnt_list:
            if c["cid"] == cid:
                return c["name"]
        return None

    def item_click(self, index):
        if self.fv.item_model is not self.rt_model:
            self.fv.item_model = self.rt_model
            self.fv.file_tv.setModel(self.rt_model)
        item = self.remote_model.itemFromIndex(index)
        full_path = self.get_full_path(item)
        print("ls path: ", full_path)
        path_info = full_path.split('/', 2)
        print("clnt: %s, path: %s, path len: %d" % (path_info[1], path_info[2], len(path_info)))
        abs_path = "/" if len(path_info[2]) == 0 else path_info[2]
        self.clnt_socket.hw_cmd_list("ls", self.get_cid_by_name(path_info[1]), abs_path)

    def item_expand(self, index):
        item = self.remote_model.itemFromIndex(index)
        for ic in range(item.rowCount()):
            full_path = self.get_full_path(item.child(ic))
            print("expand path: ", full_path)
            path_info = full_path.split('/', 2)
            print("clnt: %s, path: %s, path len: %d" % (path_info[1], path_info[2], len(path_info)))
            abs_path = "/" if len(path_info[2]) == 0 else path_info[2]
            cid = self.get_cid_by_name(path_info[1])
            print("expand get tree list, abs path: %s, clint: %s, cid: %d" % (abs_path, path_info[1], cid))
            self.clnt_socket.hw_cmd_list("tree", cid, abs_path)

        '''
class FaceDataSet(QMainWindow):
    faceDB = FaceDB()
    count = 0
    addToDatasetEnabled = False
    isOpenFaceDataAdded = False
    faceDetector = None
    openFaceImg = None
    capture = None
    face_id = None
    faceDetectionEnabled = True
    folderName = None
    folderPath = None

    def __init__(self):
        super(FaceDataSet, self).__init__()
        loadUi('01_data_entry.ui', self)
        self.faceDetector = cv2.CascadeClassifier(
            'haarcascade_frontalface_default.xml')
        self.addToDatasetButton.clicked.connect(self.detect_webcam_face)

        self.student_list_model = QStandardItemModel(self.studentListView)
        self.studentListView.setModel(self.student_list_model)
        self.studentListView.selectionModel().selectionChanged.connect(
            self.listview_change)
        self.tabWidget.currentChanged.connect(self.tab_change)

        self.load_course_students()
        self.reset_counters()

        self.courseComboBox.currentIndexChanged.connect(self.combo_change)
        self.combo_change(0)
        self.updateDatabaseButton.clicked.connect(self.button_clicked)

        self.timer = QTimer(self)
        self.start_web_cam()

    def load_course_students(self):
        # ALL COURSES
        data = self.faceDB.query_all_courses()
        for row in data:
            item_string = row[0] + "-" + row[1]
            self.courseComboBox.addItem(item_string)

        # ALL_STUDENTS
        data = self.faceDB.query_all_student_no_images()
        for row in data:
            item_string = row[0] + "-" + row[1]
            item = QStandardItem(item_string)
            item.setCheckable(True)
            item.setSelectable(False)
            self.student_list_model.appendRow(item)

    def reset_counters(self):
        self.count = 0
        self.addToDatasetEnabled = False
        self.isOpenFaceDataAdded = False
        self.openFaceImg = None
        self.face_id = ""

    def detect_webcam_face(self):
        self.reset_counters()

        self.face_id = self.studentIDText.text()
        self.folderName = "user" + self.face_id
        self.folderPath = os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            "dataset/" + self.folderName)
        if not os.path.exists(self.folderPath):
            os.makedirs(self.folderPath)

        self.addToDatasetButton.setText("Progress")
        self.addDatasetStatus.clear()
        self.pictureLabel.clear()
        QApplication.processEvents()

        self.addToDatasetEnabled = True

    def start_web_cam(self):
        self.capture = cv2.VideoCapture(0)
        self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)

        self.timer.timeout.connect(self.update_frame)
        self.timer.start(5)

    def update_frame(self):
        ret, image = self.capture.read()
        image = cv2.flip(image, 1)

        if self.faceDetectionEnabled:
            detected_image = self.detect_face(image)
            self.display_image(detected_image)
        else:
            self.display_image(image, 1)

    def detect_face(self, img):
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = self.faceDetector.detectMultiScale(gray,
                                                   1.2,
                                                   5,
                                                   minSize=(90, 90))

        for (x, y, w, h) in faces:
            if self.addToDatasetEnabled:
                self.count += 1
                if not self.isOpenFaceDataAdded:
                    y0 = max(y - 120, 0)
                    y1 = min(y + h + 80, 480)
                    x0 = max(x - 80, 0)
                    x1 = min(x + 80 + w, 640)
                    self.openFaceImg = img[y0:y1, x0:x1]
                    cv2.imwrite(
                        self.folderPath + "/User." + self.face_id + ".0.jpg",
                        self.openFaceImg)
                    self.isOpenFaceDataAdded = True
                    self.add_data_to_db()
                    self.addDatasetStatus.setText("Dataset Added")
                    image_path = QImage(self.folderPath + "/User." +
                                        self.face_id + ".0.jpg")
                    self.pictureLabel.setPixmap(QPixmap.fromImage(image_path))
                    self.pictureLabel.setScaledContents(True)
                    self.addToDatasetEnabled = False
                    self.addToDatasetButton.setText("Add to Dataset")

            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)

        return img

    def get_image(self, img):
        qformat = QImage.Format_Indexed8
        if len(img.shape) == 3:  # [0]rows, [1]=cols [2]=channels
            if img.shape[2] == 4:
                qformat = QImage.Format_RGBA8888
            else:
                qformat = QImage.Format_RGB888
        out_image = QImage(img, img.shape[1], img.shape[0], img.strides[0],
                           qformat)
        # BGB>>RGB
        out_image = out_image.rgbSwapped()
        return out_image

    def display_image(self, img):
        out_image = self.get_image(img)

        self.webCamLabel.setPixmap(QPixmap.fromImage(out_image))
        self.webCamLabel.setScaledContents(True)

    def stop_web_cam(self):
        self.timer.stop()
        self.capture = None

    def add_data_to_db(self):
        student_name = self.studentNameText.text()
        student_email = self.studentEmailText.text()

        # ADD to MYSQL
        self.faceDB.insert_student(
            self.face_id, student_name, student_email,
            (self.folderPath + "/User." + self.face_id + ".0.jpg"))
        item = QStandardItem(self.face_id + '-' + student_name)
        item.setCheckable(True)
        item.setSelectable(False)
        self.student_list_model.insertRow(0, item)

    def tab_change(self, i):
        if i == 0:
            self.start_web_cam()
        else:
            self.stop_web_cam()

        self.updateDatabaseStatus.clear()

    def combo_change(self, i):
        # COURSES-STUDENTS
        course_id = str(self.courseComboBox.currentText()).split('-', 1)[0]

        for index in range(self.student_list_model.rowCount()):
            item = self.student_list_model.item(index)
            item.setCheckState(Qt.Unchecked)

        data = self.faceDB.query_course_students(course_id)
        for row in data:
            for item in self.student_list_model.findItems(
                    row[1], Qt.MatchStartsWith):
                item.setCheckState(Qt.Checked)

        self.updateDatabaseStatus.clear()

    def button_clicked(self):
        self.updateDatabaseStatus.setText('')
        self.updateDatabaseButton.setText('Progress..')
        QApplication.processEvents()
        # REMOVE COURSES-STUDENTS
        course_id = str(self.courseComboBox.currentText()).split('-', 1)[0]
        self.faceDB.delete_course_students(course_id)

        # ADD NEW COURSES-STUDENTS
        data_tuple_list = []
        for index in range(self.student_list_model.rowCount()):
            item = self.student_list_model.item(index)
            if item.checkState() == Qt.Checked:
                student_id = str(item.text()).split('-', 1)[0]
                data_tuple_list.append((course_id, student_id))
        self.faceDB.insert_course_students(data_tuple_list)

        self.updateDatabaseStatus.setText('Database Updated')
        self.updateDatabaseButton.setText('Update Database')

    def listview_change(self):
        self.updateDatabaseStatus.clear()
        self.updateDatabaseStatus.repaint()
예제 #13
0
class TreeView(QTreeView):
    def __init__(self, *args, **kwargs):
        super(TreeView, self).__init__(*args, **kwargs)
        self._initModel()
        self._initSignals()

    def _initModel(self):
        """设置目录树Model"""
        self._dmodel = QStandardItemModel(self)
        self._fmodel = SortFilterModel(self)
        self._fmodel.setSourceModel(self._dmodel)
        self.setModel(self._fmodel)

    def _initSignals(self):
        Signals.itemJumped.connect(self.onItemJumped)
        Signals.filterChanged.connect(self._fmodel.setFilterRegExp)
        self.clicked.connect(self.onClicked)
        self.doubleClicked.connect(self.onDoubleClicked)

    def rootItem(self):
        """得到根节点Item"""
        return self._dmodel.invisibleRootItem()

    def findItems(self, name):
        """根据名字查找item
        :param name:
        """
        return self._dmodel.findItems(name)

    def onItemJumped(self, name):
        items = self.findItems(name)
        if not items:
            return
        index = self._fmodel.mapFromSource(self._dmodel.indexFromItem(
            items[0]))
        self.setCurrentIndex(index)
        self.expand(index)
        #         # 显示readme
        Signals.urlLoaded.emit(name)

    def listSubDir(self, pitem, path):
        """遍历子目录
        :param item:    上级Item
        :param path:    目录
        """
        paths = os.listdir(path)
        files = []
        for name in paths:
            spath = os.path.join(path, name)
            if not os.path.isfile(spath):
                continue
            spath = os.path.splitext(spath)
            if len(spath) == 0:
                continue
            if spath[1] == '.py' and spath[0].endswith('__init__') == False:
                files.append(name)

        # 已经存在的item
        existsItems = [pitem.child(i).text() for i in range(pitem.rowCount())]

        for name in files:
            if name in existsItems:
                continue
            file = os.path.join(path, name).replace('\\', '/')
            item = QStandardItem(name)
            # 添加自定义的数据
            item.setData(False, Constants.RoleRoot)  # 不是根目录
            item.setData(file, Constants.RolePath)
            try:
                item.setData(
                    open(file, 'rb').read().decode(errors='ignore'),
                    Constants.RoleCode)
            except Exception as e:
                AppLog.warn('read file({}) code error: {}'.format(
                    file, str(e)))
            pitem.appendRow(item)

    def initCatalog(self):
        """初始化本地仓库结构树
        """
        AppLog.debug('')
        if not os.path.exists(Constants.DirProjects):
            return
        pitem = self._dmodel.invisibleRootItem()
        # 只遍历根目录
        for name in os.listdir(Constants.DirProjects):
            file = os.path.join(Constants.DirProjects, name).replace('\\', '/')
            if os.path.isfile(file):  # 跳过文件
                continue
            if name.startswith(
                    '.') or name == 'Donate' or name == 'Test':  # 不显示.开头的文件夹
                continue
            items = self.findItems(name)
            if items:
                item = items[0]
            else:
                item = QStandardItem(name)
                # 添加自定义的数据
                # 用于绘制进度条的item标识
                item.setData(True, Constants.RoleRoot)
                # 目录或者文件的绝对路径
                item.setData(
                    os.path.abspath(os.path.join(Constants.DirProjects, name)),
                    Constants.RolePath)
                pitem.appendRow(item)
            # 遍历子目录
            self.listSubDir(item, file)
        # 排序
        self._fmodel.sort(0, Qt.AscendingOrder)

    def onClicked(self, modelIndex):
        """Item单击
        :param modelIndex:        此处是代理模型中的QModelIndex, 并不是真实的
        """
        root = modelIndex.data(Constants.RoleRoot)
        path = modelIndex.data(Constants.RolePath)
        code = modelIndex.data(Constants.RoleCode)
        AppLog.debug('is root: {}'.format(root))
        AppLog.debug('path: {}'.format(path))
        if not root and os.path.isfile(path) and code:
            # 右侧显示代码
            Signals.showCoded.emit(code)
        if root and os.path.isdir(path):
            if self.isExpanded(modelIndex):
                self.collapse(modelIndex)
            else:
                self.expand(modelIndex)
            # 显示readme
            Signals.showReadmed.emit(os.path.join(path, 'README.md'))

    def onDoubleClicked(self, modelIndex):
        """Item双击
        :param modelIndex:        此处是代理模型中的QModelIndex, 并不是真实的
        """
        root = modelIndex.data(Constants.RoleRoot)
        path = modelIndex.data(Constants.RolePath)
        AppLog.debug('is root: {}'.format(root))
        AppLog.debug('path: {}'.format(path))
        if not root and os.path.isfile(path):
            # 运行代码
            Signals.runExampled.emit(path)
#         if root and os.path.isdir(path):
#             # 显示readme
#             Signals.showReadmed.emit(os.path.join(path, 'README.md'))

    def enterEvent(self, event):
        super(TreeView, self).enterEvent(event)
        # 鼠标进入显示滚动条
        self.verticalScrollBar().setVisible(True)

    def leaveEvent(self, event):
        super(TreeView, self).leaveEvent(event)
        # 鼠标离开隐藏滚动条
        self.verticalScrollBar().setVisible(False)
예제 #14
0
파일: QtRights.py 프로젝트: GrandG/Workshop
class RightsDialog(QDialog, Ui_Dialog):
    """Rights Management Dialog."""

    def __init__(self, Dialog):
        """参数: lst (list) 为左侧表, tableMapping (dict)为右侧表格."""
        super(RightsDialog, self).__init__()
        super().setupUi(Dialog)

        # select rights role list from database
        self.rightsList = self.getRightsList()

        # 初始化权限名称
        self.comboBox.addItem('<请选择权限名称>')
        if self.rightsList:
            for i in self.rightsList:
                self.comboBox.addItem(i)
        # 是否选中权限名称
        self.selectedCombo = ''

        # TODO (miles-20170502): 是否需要枚举所有 action?
        sql = 'select distinct ActionName from u_right_action'
        self.allAction = getData(sql, 'ActionName')
        # self.allAction = [
        #     'A_SaveNewTask',
        #     'A_EditTask',
        #     'A_ViewTask',
        #     'A_DeleteTask',
        #     'A_ChangeUser',
        #     'A_TB',
        #     'A_SB',
        #     'A_EmailServer',
        #     'A_UserManager',
        #     'A_EditUser',
        #     'A_RightControl',
        #     'A_CloseFunc',
        #     'A_Exit',
        #     'A_About',
        #     'A_ViewAllTask',
        #     'A_RuleQuery'
        # ]

        # role's action -> list
        self.currentAction = []

        # 新选的 action -> list
        self.checkedAction = []
        # 新取消的 action -> list
        self.uncheckedAction = []

        # action 列表
        self.listModel = QStandardItemModel()
        self.leftListView.setModel(self.listModel)
        # 初始化 action 列表
        self.initListView()

        # comboBox binding
        self.comboBox.activated[str].connect(self.onComboActivated)

        # listModel Checkbox binding
        self.listModel.itemChanged.connect(self.onListModelChanged)

        # exitButton
        self.exitButton.clicked.connect(self.clickExitButton)

        # delButton
        self.submitButton.clicked.connect(self.clickSubmitButton)

    @staticmethod
    def getRightsList() -> list:
        """获取权限名称列表."""
        sql = 'select * from general_info where type="U_RIGHT"'
        return getData(sql, 'name')

    def initListView(self):
        """初始化 action 列表."""
        if self.allAction:
            for i in self.allAction:
                item = QStandardItem(i)
                item.setCheckable(True)
                self.listModel.appendRow(item)

    def updateListView(self):
        """更新 action 列表."""
        self.listModel.clear()
        self.initListView()
        for text in self.currentAction:
            items = self.listModel.findItems(text, Qt.MatchExactly)
            for item in items:
                item.setCheckState(Qt.Checked)

    @staticmethod
    def clickExitButton():
        """退出."""
        app.quit()

    def clickSubmitButton(self):
        """提交数据."""

        # 未选择权限
        if self.selectedCombo not in self.rightsList:
            if (QMessageBox.warning(
                    self, '警告: ', '请选择权限名称!',
                    QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok):
                return

        # 不更改数据管理员的 action
        elif self.selectedCombo == '数据管理员':
            if (QMessageBox.warning(
                    self, '警告: ', '请选择权限名称!',
                    QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok):
                return
        else:
            ret = QMessageBox.question(
                self, '确认', '是否提交数据?',
                QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
                QMessageBox.Save)
            if ret == QMessageBox.Save:
                for i in self.checkedAction:
                    sql = 'insert into u_right_action ' \
                        '(RightName, ActionName) values ("{}", "{}")'
                    g_DB.Execute(sql.format(self.selectedCombo, i))
                for i in self.uncheckedAction:
                    sql = 'delete from u_right_action where RightName="{}" ' \
                          'and ActionName="{}"'
                    g_DB.Execute(sql.format(self.selectedCombo, i))
                g_DB.commit()
                QMessageBox.warning(self, '成功', '提交成功')
                self.checkedAction = []
                self.uncheckedAction = []
                # app.quit()
            elif ret == QMessageBox.Discard:
                self.checkedAction = []
                self.uncheckedAction = []
                self.updateListView()
                return
            elif ret == QMessageBox.Cancel:
                return

    def onComboActivated(self, text):
        """选定权限角色时, 更新 action 列表."""
        sql = 'select * from u_right_action where RightName="{}"'.format(text)
        self.currentAction = getData(sql, 'ActionName')
        self.checkedAction = []
        self.uncheckedAction = []
        self.selectedCombo = text
        self.updateListView()

    def onListModelChanged(self, item):
        """更改新选择和新取消列表."""

        if item.checkState():
            # 添加新选择的 action
            if item.text() not in self.currentAction:
                self.checkedAction.append(item.text())

            # 从新取消的 action 中删除, 防止重复勾选与取消
            if item.text() in self.uncheckedAction:
                self.uncheckedAction.remove(item.text())
        else:
            # 添加新取消的 action
            if item.text() in self.currentAction:
                self.uncheckedAction.append(item.text())

            # 从新选 action 中删除, 防止重复勾选与取消
            if item.text() in self.checkedAction:
                self.checkedAction.remove(item.text())
예제 #15
0
class IsosViewer(QMainWindow, mageiaSyncUI.Ui_mainWindow):
    #   Display the main window
    def __init__(self, parent=None):
        super(IsosViewer, self).__init__(parent)
        self.setupUi(self)
        self.connectActions()
        self.IprogressBar.setMinimum(0)
        self.IprogressBar.setMaximum(100)
        self.IprogressBar.setValue(0)
        self.IprogressBar.setEnabled(False)
        self.selectAllState=True
        self.stop.setEnabled(False)
        self.destination=''
        self.rsyncThread = mageiaSyncExt.syncThread(self)    # create a thread to launch rsync
        self.rsyncThread.progressSignal.connect(self.setProgress)
        self.rsyncThread.speedSignal.connect(self.setSpeed)
        self.rsyncThread.sizeSignal.connect(self.setSize)
        self.rsyncThread.remainSignal.connect(self.setRemain)
        self.rsyncThread.endSignal.connect(self.syncEnd)
        self.rsyncThread.lvM.connect(self.lvMessage)
        self.rsyncThread.checkSignal.connect(self.checks)
        self.checkThreads=[]    #   A list of thread for each iso

 #      Model for list view in a table
        self.model = QStandardItemModel(0, 6, self)
        headers=[self.tr("Directory"),self.tr("Name"),self.tr("Size"),self.tr("Date"),"SHA1","MD5"]
        i=0
        for label in headers:
            self.model.setHeaderData(i, QtCore.Qt.Horizontal,label )
            i+=1

#       settings for the list view
        self.localList.setModel(self.model)
        self.localList.setColumnWidth(0,220)
        self.localList.setColumnWidth(1,220)
        self.localList.horizontalHeader().setStretchLastSection(True)
        # settings for local iso names management
        self.localListNames=[]

    def multiSelect(self):
    #   allows to select multiple lines in remote ISOs list
        self.listIsos.setSelectionMode(2)

    def add(self, iso):
    #   Add an remote ISO in list
         self.listIsos.addItem(iso)

    def localAdd(self, path,iso,isoSize):
        #   Add an entry in local ISOs list, with indications about checking
        itemPath=QStandardItem(path)
        itemIso=QStandardItem(iso)
        if isoSize==0:
            itemSize=QStandardItem('--')
        else:
            formatedSize='{:n}'.format(isoSize).replace(","," ")
            itemSize=QStandardItem(formatedSize)
        itemSize.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter)
        itemDate=QStandardItem("--/--/--")
        itemDate.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter)
        itemCheck1=QStandardItem("--")
        itemCheck1.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter)
        itemCheck5=QStandardItem("--")
        itemCheck5.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter)
        self.model.appendRow([itemPath,itemIso,itemSize,itemDate, itemCheck1, itemCheck5,])
        self.localListNames.append([path,iso])

    def setProgress(self, value):
        #   Update the progress bar
        self.IprogressBar.setValue(value)

    def setSpeed(self, value):
        #   Update the speed field
        self.speedLCD.display(value)

    def setSize(self, size):
        #   Update the size field
        self.Lsize.setText(size+self.tr(" bytes"))

    def setRemain(self,remainTime):
        content=QtCore.QTime.fromString(remainTime,"h:mm:ss")
        self.timeRemaining.setTime(content)

    def manualChecks(self):
        for iso in self.listIsos.selectedItems():
            path,name=iso.text().split('/')
            try:
                #   Look for ISO in local list
                item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0]
            except:
                #   Remote ISO is not yet in local directory. We add it in localList and create the directory
                self.localAdd(path,name,0)
                basedir=QtCore.QDir(self.destination)
                basedir.mkdir(path)
                item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0]
            row=self.model.indexFromItem(item).row()
            self.checks(row)

    def checks(self,isoIndex):
        #   processes a checking for each iso
        #   launches a thread for each iso
        newThread=mageiaSyncExt.checkThread(self)
        self.checkThreads.append(newThread)
        self.checkThreads[-1].setup(self.destination,
            self.model.data(self.model.index(isoIndex,0)) ,
            self.model.data(self.model.index(isoIndex,1)),
            isoIndex)
        self.checkThreads[-1].md5Signal.connect(self.md5Check)
        self.checkThreads[-1].sha1Signal.connect(self.sha1Check)
        self.checkThreads[-1].dateSignal.connect(self.dateCheck)
        self.checkThreads[-1].sizeFinalSignal.connect(self.sizeUpdate)
        self.checkThreads[-1].checkStartSignal.connect(self.checkStart)
        self.checkThreads[-1].start()

    def checkStart(self,isoIndex):
        #   the function indicates that checking is in progress
        #   the hundred contains index of the value to check, the minor value contains the row
        col=(int)(isoIndex/100)
        row=isoIndex-col*100
        self.model.setData(self.model.index(row, col, QtCore.QModelIndex()), self.tr("Checking"))

    def md5Check(self,check):
        if check>=128:
            val=self.tr("OK")
            row=check-128
        else:
            val=self.tr("Failed")
            row=check
        self.model.setData(self.model.index(row, 5, QtCore.QModelIndex()), val)

    def sha1Check(self,check):
        if check>=128:
            val=self.tr("OK")
            row=check-128
        else:
            val=self.tr("Failed")
            row=check
        self.model.setData(self.model.index(row, 4, QtCore.QModelIndex()), val)

    def dateCheck(self,check):
        if check>=128:
            val=self.tr("OK")
            row=check-128
        else:
            val=self.tr("Failed")
            row=check
        self.model.setData(self.model.index(row, 3, QtCore.QModelIndex()), val)

    def sizeUpdate(self,signal,isoSize):
        col=(int)(signal/100)
        row=signal-col*100
        self.model.setData(self.model.index(row, col, QtCore.QModelIndex()), isoSize)

    def syncEnd(self, rc):
        if rc==1:
            self.lvMessage(self.tr("Command rsync not found"))
        elif rc==2:
            self.lvMessage(self.tr("Error in rsync parameters"))
        elif rc==3:
            self.lvMessage(self.tr("Unknown error in rsync"))
        self.IprogressBar.setEnabled(False)
        self.syncGo.setEnabled(True)
        self.listIsos.setEnabled(True)
        self.selectAll.setEnabled(True)
        self.stop.setEnabled(False)

    def prefsInit(self):
    #   Load the parameters at first
        params=QtCore.QSettings("Mageia","mageiaSync")
        paramRelease=""
        try:
            paramRelease=params.value("release", type="QString")
            #   the parameters already initialised?
        except:
            pass
        if paramRelease =="":
            # Values are not yet set
            self.pd0=prefsDialog0()
            self.pd0.user.setFocus()
            answer=self.pd0.exec_()
            if answer:
                #   Update params
                self.user=self.pd0.user.text()
                self.password=self.pd0.password.text()
                self.location=self.pd0.location.text()
                params=QtCore.QSettings("Mageia","mageiaSync")
                params.setValue("user",self.user)
                params.setValue("password",self.password)
                params.setValue("location",self.location)
            else:
                pass
#                answer=QDialogButtonBox(QDialogButtonBox.Ok)
                # the user must set values or default values
            self.pd0.close()
            self.pd=prefsDialog()
            if self.password !="":
                code,list=mageiaSyncExt.findRelease('rsync://'+self.user+'@bcd.mageia.org/isos/',self.password)
                if code==0:
                    for item in list:
                        self.pd.release.addItem(item)
            self.pd.password.setText(self.password)
            self.pd.user.setText(self.user)
            self.pd.location.setText(self.location)
            self.pd.selectDest.setText(QtCore.QDir.currentPath())
            self.pd.release.setFocus()
            answer=self.pd.exec_()
            if answer:
                #   Update params
                self.user=self.pd.user.text()
                self.password=self.pd.password.text()
                self.location=self.pd.location.text()
                params=QtCore.QSettings("Mageia","mageiaSync")
                self.release= self.pd.release.currentText()
                self.destination=self.pd.selectDest.text()
                self.bwl=self.pd.bwl.value()
                params.setValue("release", self.release)
                params.setValue("user",self.user)
                params.setValue("password",self.password)
                params.setValue("location",self.location)
                params.setValue("destination",self.destination)
                params.setValue("bwl",str(self.bwl))
            else:
                pass
#                answer=QDialogButtonBox(QDialogButtonBox.Ok)
                print(self.tr("the user must set values or default values"))
            self.pd.close()
        else:
            self.release=params.value("release", type="QString")
            self.user=params.value("user", type="QString")
            self.location=params.value("location", type="QString")
            self.password=params.value("password", type="QString")
            self.destination=params.value("destination", type="QString")
            self.bwl=params.value("bwl",type=int)
        self.localDirLabel.setText(self.tr("Local directory: ")+self.destination)
        if self.location !="":
            self.remoteDirLabel.setText(self.tr("Remote directory: ")+self.location)

    def selectDestination(self):
        #   dialog box to select the destination (local directory)
        directory = QFileDialog.getExistingDirectory(self, self.tr('Select a directory'),'~/')
        isosSync.destination = directory
        self.pd.selectDest.setText(isosSync.destination)


    def selectAllIsos(self):
        #   Select or unselect the ISOs in remote list
        if self.selectAllState :
            for i in range(self.listIsos.count()):
                self.listIsos.item(i).setSelected(True)
            self.selectAll.setText(self.tr("Unselect &All"))
        else:
            for i in range(self.listIsos.count()):
                self.listIsos.item(i).setSelected(False)
            self.selectAll.setText(self.tr("Select &All"))
        self.selectAllState=not self.selectAllState

    def connectActions(self):
        self.actionQuit.triggered.connect(app.quit)
        self.quit.clicked.connect(app.quit)
        self.actionRename.triggered.connect(self.rename)
        self.actionUpdate.triggered.connect(self.updateList)
        self.actionCheck.triggered.connect(self.manualChecks)
        self.actionPreferences.triggered.connect(self.prefs)
        self.syncGo.clicked.connect(self.launchSync)
        self.selectAll.clicked.connect(self.selectAllIsos)

    def updateList(self):
        # From the menu entry
        self.lw = LogWindow()
        self.lw.show()
        self.listIsos.clear()
        self.model.removeRows(0,self.model.rowCount())
        if self.location  == "" :
            self.nameWithPath='rsync://'+self.user+'@bcd.mageia.org/isos/'+self.release+'/'
#            print self.nameWithPath
        else:
            self.nameWithPath=self.location+'/'
        self.lvMessage(self.tr("Source: ")+self.nameWithPath)
        self.fillList = mageiaSyncExt.findIsos()
        self.fillList.setup(self.nameWithPath, self.password,self.destination)
        self.fillList.endSignal.connect(self.closeFill)
        self.fillList.start()
        # Reset the button
        self.selectAll.setText(self.tr("Select &All"))
        self.selectAllState=True

    def lvMessage( self,message):
        #   Add a line in the logview
        self.lvText.append(message)

    def renameDir(self):
        #   Choose the directory where isos are stored
        directory = QFileDialog.getExistingDirectory(self, self.tr('Select a directory'),self.destination)
        self.rd.chooseDir.setText(directory)

    def rename(self):
        #   rename old isos and directories to a new release
        self.rd=renameDialog()
        loc=[]
        loc=self.location.split('/')
        self.rd.oldRelease.setText(loc[-1])
        self.rd.chooseDir.setText(self.destination)
        answer=self.rd.exec_()
        if answer:
            returnMsg=mageiaSyncExt.rename(self.rd.chooseDir.text(),self.rd.oldRelease.text(),str(self.rd.newRelease.text()))
            self.lvMessage(returnMsg)
        self.rd.close()

    def prefs(self):
        # From the menu entry
        self.pd=prefsDialog()
        self.pd.release.addItem(self.release)
        self.pd.password.setText(self.password)
        self.pd.user.setText(self.user)
        self.pd.location.setText(self.location)
        self.pd.selectDest.setText(self.destination)
        self.pd.bwl.setValue(self.bwl)
        params=QtCore.QSettings("Mageia","mageiaSync")
        answer=self.pd.exec_()
        if answer:
            params.setValue("release", self.pd.release.currentText())
            params.setValue("user",self.pd.user.text())
            params.setValue("password",self.pd.password.text())
            params.setValue("location",self.pd.location.text())
            params.setValue("destination",self.pd.selectDest.text())
            params.setValue("bwl",str(self.pd.bwl.value()))
        self.prefsInit()
        self.pd.close()


    def launchSync(self):
        self.IprogressBar.setEnabled(True)
        self.stop.setEnabled(True)
        self.syncGo.setEnabled(False)
        self.listIsos.setEnabled(False)
        self.selectAll.setEnabled(False)
        # Connect the button Stop
        self.stop.clicked.connect(self.stopSync)
        self.rsyncThread.params(self.password, self.bwl)
        for iso in self.listIsos.selectedItems():
            path,name=iso.text().split('/')
            try:
                #   Look for ISO in local list
                item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0]
            except:
                #   Remote ISO is not yet in local directory. We add it in localList and create the directory
                self.localAdd(path,name,0)
                basedir=QtCore.QDir(self.destination)
                basedir.mkdir(path)
                item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0]
            row=self.model.indexFromItem(item).row()
            if self.location  == "" :
                self.nameWithPath='rsync://'+self.user+'@bcd.mageia.org/isos/'+self.release+'/'+path
            else:
                self.nameWithPath=self.location+path
            if (not str(path).endswith('/')):
                    self.nameWithPath+='/'
            self.rsyncThread.setup(self.nameWithPath, self.destination+'/'+path+'/',row)
        self.rsyncThread.start()             # start the thread
        # Pour les tests uniquement
            #rsync://[email protected]/isos/$release/
        #self.nameWithPath='rsync://ftp5.gwdg.de/pub/linux/mageia/iso/4.1/Mageia-4.1-LiveCD-GNOME-en-i586-CD/'

    def closeFill(self,code):
        if code==0: #   list returned
            list=self.fillList.getList()
            for iso in list:
                self.add(iso)
        elif code==1:
            self.lvMessage(self.tr("Command rsync not found"))
        elif code==2:
            self.lvMessage(self.tr("Error in rsync parameters"))
        elif code==3:
            self.lvMessage(self.tr("Unknown error in rsync"))
        list=self.fillList.getList()

        list=self.fillList.getLocal()
        for path,iso,isoSize in list:
            self.localAdd(path,iso, isoSize)
        self.fillList.quit()
        self.lw.hide()

    def stopSync(self):
        self.rsyncThread.stop()
        self.IprogressBar.setEnabled(False)
        self.stop.setEnabled(False)
        self.syncGo.setEnabled(True)
        self.listIsos.setEnabled(True)
        self.selectAll.setEnabled(True)


    def main(self):
        self.show()
        #   Load or look for intitial parameters
        self.prefsInit()
        # look for Isos list and add it to the isoSync list. Update preferences
        self.updateList()
        self.multiSelect()

    def close(self):
        self.rsyncThread.stop()
        exit(0)
예제 #16
0
class MysqlModel:
    def __init__(self, host, user, password, port=3306, charset='utf8mb4'):
        self.schema_model = QStandardItemModel()
        self.table_info_model = QStandardItemModel()
        self.data_model = QStandardItemModel()
        self.host = host
        self.user = user
        self.password = password
        self.port = port
        self.charset = charset
        self.db_icon = icon_font.icon('database')
        self.table_icon = icon_font.icon('table')
        self.connection = None
        self.init_connection()

    def init_connection(self):
        self.connection = pymysql.connect(host=self.host,
                                          port=self.port,
                                          user=self.user,
                                          password=self.password,
                                          charset=self.charset,
                                          database='test',
                                          autocommit=True)
        with self.connection.cursor() as cursor:
            cursor.execute('USE `information_schema`')
            cursor.execute(
                'SELECT `TABLE_SCHEMA`, `TABLE_NAME` FROM `information_schema`.`TABLES`;'
            )
            res = cursor.fetchall()

        for r in res:
            db_name = r[0]
            table_name = r[1]
            db_item = self.schema_model.findItems(db_name)
            if len(db_item) > 0:
                table_item = QStandardItem(table_name)
                table_item.setIcon(self.table_icon)
                table_item.setEditable(False)
                table_item.setFont(QFont("微软雅黑"))
                db_item[0].appendRow(table_item)
            else:
                db_item = QStandardItem(db_name)
                db_item.setEditable(False)
                db_item.setIcon(self.db_icon)
                db_item.setFont(QFont("微软雅黑"))
                table_item = QStandardItem(table_name)
                table_item.setIcon(self.table_icon)
                table_item.setEditable(False)
                table_item.setFont(QFont("微软雅黑"))
                db_item.appendRow(table_item)
                self.schema_model.appendRow(db_item)

    def show_table_data(self, db_name, table_name, overview_filter=None):
        self.data_model.clear()
        with self.connection.cursor() as cursor:
            cursor.execute('use %s' % db_name)
            cursor.execute('desc `%s`.`%s`;' % (db_name, table_name))
            desc_table_res = cursor.fetchall()
            select_fields = []
            for index, r in enumerate(desc_table_res):
                print(r)
                self.data_model.setHorizontalHeaderItem(
                    index, QStandardItem(r[0]))
                if r[1] == 'text':
                    select_fields.append('LEFT(`%s`, 128)' % r[0])
                else:
                    select_fields.append('`%s`' % r[0])
            if overview_filter is None or overview_filter == '':
                cursor.execute('select %s from `%s` limit 1000' %
                               (', '.join(select_fields), table_name))
            else:
                cursor.execute(
                    'select %s from `%s` where %s limit 1000' %
                    (', '.join(select_fields), table_name, overview_filter))
            select_res = cursor.fetchall()
            for row_index, row_data in enumerate(select_res):
                for col_index, r in enumerate(row_data):
                    # print(type(r))
                    if r is None:
                        self.data_model.setItem(row_index, col_index,
                                                QStandardItem('NULL'))
                        self.data_model.item(row_index,
                                             col_index).setForeground(
                                                 QBrush(QColor(225, 225, 225)))
                    elif isinstance(r, int):
                        self.data_model.setItem(row_index, col_index,
                                                QStandardItem(str(r)))
                        self.data_model.item(row_index,
                                             col_index).setForeground(
                                                 QBrush(QColor(10, 20, 225)))
                        self.data_model.item(
                            row_index,
                            col_index).setTextAlignment(Qt.AlignVCenter
                                                        | Qt.AlignRight)
                    else:
                        self.data_model.setItem(row_index, col_index,
                                                QStandardItem(str(r)))
                        self.data_model.item(row_index,
                                             col_index).setForeground(
                                                 QBrush(QColor(80, 80, 80)))
                    self.data_model.item(row_index,
                                         col_index).setFont(QFont("微软雅黑"))

    def add_db(self):
        self.model.appendRow(QStandardItem('new db'))

    # def __parse_create_table(self, sql):
    #     sql = sql.replace('\n', ' ')
    #     print(sql)
    #     parten = re.compile('^CREATE\s+TABLE\s+`(.+?)`\s+\((\s+`(.+?)`.+){1,}\).*')
    #     match = parten.match(sql)
    #     print(match)
    #     if match:
    #         print(match.groups())

    def __del__(self):
        print("close connection===")
        if self.connection:
            self.connection.close()
예제 #17
0
class MainWindow(QMainWindow):
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    MAIN_UI_FILE = os.path.join(BASE_DIR, "main.ui")
    NEW_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_popup.ui")
    NEW_DISH_MULTI_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                                "new_dish_multi_popup.ui")
    NEW_DISH_DATA_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                               "new_dish_data_popup.ui")
    MODIFY_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "modify_dish_popup.ui")
    DB_FILE = os.path.join(BASE_DIR, "restaurant.db")

    def __init__(self):
        super(MainWindow, self).__init__()
        # Initialize variable
        self.db_connection = None
        self.new_dish_popup = QWidget()
        self.new_dish_multi_popup = QWidget()
        self.new_dish_data_popup = QWidget()
        self.modify_dish_popup = QWidget()
        self.dish_table_model = QStandardItemModel(0, 6)
        self.dish_table_proxy = TableFilter()
        self.dish_data_table_model = QStandardItemModel(0, 6)
        self.dish_data_table_proxy = TableFilter()
        self.graph_chart = None
        self.graph_series = {}

        # Load UI designs
        uic.loadUi(self.MAIN_UI_FILE, self)
        uic.loadUi(self.NEW_DISH_POPUP_UI_FILE, self.new_dish_popup)
        uic.loadUi(self.NEW_DISH_MULTI_POPUP_UI_FILE,
                   self.new_dish_multi_popup)
        uic.loadUi(self.NEW_DISH_DATA_POPUP_UI_FILE, self.new_dish_data_popup)
        uic.loadUi(self.MODIFY_DISH_POPUP_UI_FILE, self.modify_dish_popup)
        self.init_dish_table()
        self.init_dish_data_table()
        self.init_graph()

        # Connect to database
        self.init_db_connection()

        # MainWindow Bind action triggers
        self.action_new_dish.triggered.connect(self.show_new_dish_popup)
        self.action_new_dish_multi.triggered.connect(
            self.show_new_dish_multi_popup)
        self.action_new_data_multi.triggered.connect(
            lambda: self.modify_new_dish_data_popup_table(show=True))
        self.tabWidget.currentChanged.connect(self.update_graph)

        # Dish Table filter bind
        self.dish_lineEdit.textChanged.connect(
            lambda text, col_idx=1: self.dish_table_proxy.set_col_regex_filter(
                col_idx, text))
        self.lower_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))

        # Dish Data Table filter bind
        self.lower_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, date, -1))
        self.higher_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, -1, date))
        self.data_lineEdit.textChanged.connect(
            lambda text, col_idx=2: self.dish_data_table_proxy.
            set_col_regex_filter(col_idx, text))
        self.lower_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.data_all_check_checkBox.stateChanged.connect(
            lambda state, col_idx=5: self.data_table_check_state(
                state, col_idx))
        self.dish_data_table_model.itemChanged.connect(self.update_series)

        # Popup bind action triggers
        self.new_dish_popup.create_new_dish_btn.clicked.connect(
            self.create_new_dish)
        self.new_dish_multi_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_multi)
        self.new_dish_data_popup.dateEdit.dateChanged.connect(
            self.modify_new_dish_data_popup_table)
        self.new_dish_data_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_data)

        # Get current dishes
        self.load_dish_table()
        self.load_dish_data_table()
        self.new_dish_data_popup.dateEdit.setDate(QtCore.QDate.currentDate())

    def init_dish_table(self):
        self.dish_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        # Set Header data and stretch
        for col, col_name in enumerate(
            ["ID", "菜品", "价格", "近7天总售出", "操作", "备注"]):
            self.dish_table_model.setHeaderData(col, Qt.Horizontal, col_name,
                                                Qt.DisplayRole)
        self.dish_table_proxy.setSourceModel(self.dish_table_model)
        self.dish_tableView.setModel(self.dish_table_proxy)
        self.dish_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Regex"), (2, "Number"), (3, "Number"),
                              (5, "Regex")]:
            self.dish_table_proxy.filter_method[col] = method

    def init_dish_data_table(self):
        self.data_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        for col, col_name in enumerate(
            ["Dish_ID", "日期", "菜品", "价格", "售出", "选择"]):
            self.dish_data_table_model.setHeaderData(col, Qt.Horizontal,
                                                     col_name, Qt.DisplayRole)
        self.dish_data_table_proxy.setSourceModel(self.dish_data_table_model)
        self.data_tableView.setModel(self.dish_data_table_proxy)
        self.data_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Date"), (2, "Regex"), (3, "Number"),
                              (4, "Number")]:
            self.dish_data_table_proxy.filter_method[col] = method

    def init_graph(self):
        self.graph_chart = QChart(title="售出图")
        self.graph_chart.legend().setVisible(True)
        self.graph_chart.setAcceptHoverEvents(True)

        graph_view = QChartView(self.graph_chart)
        graph_view.setRenderHint(QPainter.Antialiasing)
        self.gridLayout_5.addWidget(graph_view)

    def init_db_connection(self):
        self.db_connection = sqlite3.connect(self.DB_FILE)
        cursor = self.db_connection.cursor()
        # check create table if not exist
        sql_create_dish_table = """ CREATE TABLE IF NOT EXISTS dish (
                                        id integer PRIMARY KEY,
                                        name text NOT NULL,
                                        price numeric Not NULL,
                                        remarks text,
                                        UNIQUE (name, price)
                                    ); """
        sql_create_dish_data_table = """ CREATE TABLE IF NOT EXISTS dish_data (
                                            dish_id integer NOT NULL REFERENCES dish(id) ON DELETE CASCADE,
                                            date date,
                                            sell_num integer DEFAULT 0,
                                            PRIMARY KEY (dish_id, date),
                                            CONSTRAINT dish_fk 
                                                FOREIGN KEY (dish_id) 
                                                REFERENCES dish (id) ON DELETE CASCADE 
                                        ); """
        sql_trigger = """
            CREATE TRIGGER IF NOT EXISTS place_holder_data
            AFTER INSERT ON dish
            BEGIN
                INSERT INTO dish_data (dish_id, date, sell_num) VALUES(new.id, null, 0);
            END;
        """
        cursor.execute(sql_create_dish_table)
        cursor.execute(sql_create_dish_data_table)
        cursor.execute("PRAGMA FOREIGN_KEYS = on")
        cursor.execute(sql_trigger)

        cursor.close()

    def load_dish_table(self):
        today = datetime.today()
        sql_select_query = """
            SELECT dish.id, dish.name, dish.price, COALESCE(SUM(dish_data.sell_num), 0), dish.remarks
            FROM dish LEFT JOIN dish_data 
            ON dish.id = dish_data.dish_id
            WHERE dish_data.date IS NULL OR dish_data.date BETWEEN date('{}') and date('{}')
            GROUP BY dish.id
            ORDER BY dish.name, dish.price;""".format(
            (today - timedelta(days=7)).strftime("%Y-%m-%d"),
            today.strftime("%Y-%m-%d"))
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_table_model.appendRow(create_dish_table_row(*record))
        cursor.close()
        self.dish_tableView.setItemDelegateForColumn(
            4,
            DishTableDelegateCell(self.show_modify_dish_popup,
                                  self.delete_dish, self.dish_tableView))

    def load_dish_data_table(self):
        sql_select_query = """
            SELECT dish_data.dish_id, dish_data.date, dish.name, dish.price, dish_data.sell_num
            FROM dish_data LEFT JOIN dish  
            ON dish_data.dish_id = dish.id
            WHERE dish_data.date IS NOT NULL
            ORDER BY dish_data.date DESC, dish.name, dish.price, dish_data.sell_num;"""
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(*record))
        cursor.close()
        self.lower_data_dateEdit.setDate(QDate.currentDate().addDays(-7))
        self.higher_data_dateEdit.setDate(QDate.currentDate())
        self.data_tableView.setItemDelegateForColumn(
            5, DishDataTableDelegateCell(self.data_tableView))

    def data_table_check_state(self, state, col):
        for row in range(self.dish_data_table_proxy.rowCount()):
            index = self.dish_data_table_proxy.mapToSource(
                self.dish_data_table_proxy.index(row, col))
            if index.isValid():
                self.dish_data_table_model.setData(index, str(state),
                                                   Qt.DisplayRole)

    def show_new_dish_popup(self):
        # Move popup to center
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.new_dish_popup.move(
            global_point - QtCore.QPoint(self.new_dish_popup.width() // 2,
                                         self.new_dish_popup.height() // 2))
        self.new_dish_popup.show()

    def show_new_dish_multi_popup(self):
        file_name = QFileDialog().getOpenFileName(None, "选择文件", "",
                                                  self.tr("CSV文件 (*.csv)"))[0]
        self.new_dish_multi_popup.tableWidget.setRowCount(0)
        if file_name:
            with open(file_name, "r") as file:
                csv_reader = csv.reader(file, delimiter=",")
                for idx, row_data in enumerate(csv_reader):
                    if len(row_data) == 2:
                        name, price = row_data
                        remark = ""
                    elif len(row_data) == 3:
                        name, price, remark = row_data
                    else:
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('格式为"菜品 价格"或者"菜品 价格 备注"\n第{}行输入有误'.format(
                                idx)))
                        return
                    self.new_dish_multi_popup.tableWidget.insertRow(
                        self.new_dish_multi_popup.tableWidget.rowCount())
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 0, QTableWidgetItem(name))
                    price_type = str_type(price)
                    if price_type == str or (isinstance(
                            price_type, (float, int)) and float(price) < 0):
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('第{}行价格输入有误'.format(idx + 1)))
                        return
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 1,
                        QTableWidgetItem("{:.2f}".format(float(price))))
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 2, QTableWidgetItem(remark))
            self.new_dish_multi_popup.show()

    def modify_new_dish_data_popup_table(self, *args, show=False):
        sql_select_query = """
                    SELECT id, name, price, dish_data.sell_num
                    FROM dish LEFT JOIN dish_data
                    ON dish.id=dish_data.dish_id
                    WHERE dish_data.date IS NULL OR dish_data.date = date('{}')
                    GROUP BY id, name, price
                    ORDER BY dish.name, dish.price;""".format(
            self.new_dish_data_popup.dateEdit.date().toString("yyyy-MM-dd"))

        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        self.new_dish_data_popup.tableWidget.setRowCount(len(records))
        self.new_dish_data_popup.tableWidget.setColumnHidden(0, True)
        for row_idx, record in enumerate(records):
            dish_id, name, price, sell_num = record
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 0, QTableWidgetItem(str(dish_id)))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 1, QTableWidgetItem(name))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 2, QTableWidgetItem("{:.2f}".format(price)))
            spin_box = QSpinBox()
            spin_box.setMaximum(9999)
            spin_box.setValue(sell_num)
            self.new_dish_data_popup.tableWidget.setCellWidget(
                row_idx, 3, spin_box)
        cursor.close()
        if show:
            self.new_dish_data_popup.show()

    def create_new_dish(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ INSERT INTO dish(name, price, remarks)
                         VALUES(?,?,?)"""
        dish_name = self.new_dish_popup.dish_name.text()
        dish_price = self.new_dish_popup.dish_price.value()
        dish_remark = self.new_dish_popup.dish_remark.toPlainText()
        try:
            cursor.execute(sql_insert, (dish_name, dish_price, dish_remark))
            new_dish_id = cursor.lastrowid
            cursor.close()
            self.db_connection.commit()
            # Update dish table and dish comboBox in UI
            self.dish_table_model.appendRow(
                create_dish_table_row(new_dish_id, dish_name, dish_price, 0,
                                      dish_remark))
            self.new_dish_popup.hide()
        except sqlite3.Error:
            cursor.close()
            QMessageBox.warning(self, "菜品价格重复", self.tr('菜品价格组合重复,请检查'))

    def create_new_dish_multi(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT INTO dish(name, price, remarks)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_multi_popup.tableWidget.rowCount()):
            dish_name = self.new_dish_multi_popup.tableWidget.item(row,
                                                                   0).text()
            dish_price = float(
                self.new_dish_multi_popup.tableWidget.item(row, 1).text())
            dish_remark = self.new_dish_multi_popup.tableWidget.item(row,
                                                                     2).text()
            try:
                cursor.execute(sql_insert,
                               (dish_name, dish_price, dish_remark))
                new_dish_id = cursor.lastrowid
                self.dish_table_model.appendRow(
                    create_dish_table_row(new_dish_id, dish_name, dish_price,
                                          0, dish_remark))
            except sqlite3.Error:
                cursor.close()
                QMessageBox.warning(
                    self, "菜品价格重复",
                    self.tr('前{}行已插入。\n第{}行菜品价格组合重复,请检查'.format(row, row + 1)))
                return
        cursor.close()
        self.db_connection.commit()
        self.new_dish_multi_popup.hide()

    def create_new_dish_data(self):
        current_date = self.new_dish_data_popup.dateEdit.date().toString(
            "yyyy-MM-dd")
        table_filter = TableFilter()
        table_filter.setSourceModel(self.dish_data_table_model)
        table_filter.set_col_regex_filter(1, current_date)
        for row in range(table_filter.rowCount()):
            index = table_filter.mapToSource(table_filter.index(0, 1))
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())
        del table_filter
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT OR REPLACE INTO dish_data(dish_id, date, sell_num)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_data_popup.tableWidget.rowCount()):
            dish_id = int(
                self.new_dish_data_popup.tableWidget.item(row, 0).text())
            name = self.new_dish_data_popup.tableWidget.item(row, 1).text()
            price = float(
                self.new_dish_data_popup.tableWidget.item(row, 2).text())
            sell_num = self.new_dish_data_popup.tableWidget.cellWidget(
                row, 3).value()
            cursor.execute(sql_insert, (dish_id, current_date, sell_num))
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(dish_id, current_date, name, price,
                                           sell_num))
        cursor.close()
        self.db_connection.commit()
        self.new_dish_data_popup.hide()

    def delete_dish(self, dish_id):
        cursor = self.db_connection.cursor()
        sql_delete = """ DELETE FROM dish WHERE id=?"""
        cursor.execute(sql_delete, tuple([dish_id]))
        cursor.close()
        self.db_connection.commit()

        # Update dish table and dish comboBox in UI
        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())

        for row in self.dish_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_table_model.removeRow(index.row())

    def show_modify_dish_popup(self, dish_id):
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.modify_dish_popup.move(
            global_point - QtCore.QPoint(self.modify_dish_popup.width() // 2,
                                         self.modify_dish_popup.height() // 2))
        # Find the row and get necessary info
        index = self.dish_table_model.match(self.dish_table_model.index(0, 0),
                                            Qt.DisplayRole, str(dish_id))
        if index:
            row_idx = index[0]
            dish_name = self.dish_table_model.data(row_idx.siblingAtColumn(1))
            dish_price = self.dish_table_model.data(row_idx.siblingAtColumn(2))
            dish_remark = self.dish_table_model.data(
                row_idx.siblingAtColumn(5))
            self.modify_dish_popup.dish_name.setText(dish_name)
            self.modify_dish_popup.dish_price.setValue(float(dish_price))
            self.modify_dish_popup.dish_remark.setText(dish_remark)

            try:
                self.modify_dish_popup.modify_dish_btn.clicked.disconnect()
            except TypeError:
                pass
            self.modify_dish_popup.modify_dish_btn.clicked.connect(
                lambda: self.modify_dish(row_idx, dish_id))
            self.modify_dish_popup.show()

    def modify_dish(self, row, dish_id):
        cursor = self.db_connection.cursor()
        sql_update = """ UPDATE dish
                         SET name = ?, price = ?, remarks = ?
                         WHERE id=?"""
        dish_name = self.modify_dish_popup.dish_name.text()
        dish_price = self.modify_dish_popup.dish_price.value()
        dish_remark = self.modify_dish_popup.dish_remark.toPlainText()
        cursor.execute(sql_update,
                       (dish_name, dish_price, dish_remark, dish_id))
        cursor.close()
        self.db_connection.commit()
        self.modify_dish_popup.hide()

        # Update dish table and dish comboBox in UI
        old_name = self.dish_table_model.data(row.siblingAtColumn(1))
        old_price = self.dish_table_model.data(row.siblingAtColumn(2))
        sell_num = self.dish_table_model.data(row.siblingAtColumn(3))
        row_idx = row.row()
        self.dish_table_model.removeRow(row_idx)
        self.dish_table_model.insertRow(
            row_idx,
            create_dish_table_row(dish_id, dish_name, dish_price, sell_num,
                                  dish_remark))

        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.setData(index.siblingAtColumn(2),
                                                   dish_name)
                self.dish_data_table_model.setData(index.siblingAtColumn(3),
                                                   "{:.2f}".format(dish_price))
        old_key = old_name + '(' + old_price + ')'
        if old_key in self.graph_line_series:
            self.graph_line_series[dish_name + '(' + str(dish_price) +
                                   ')'] = self.graph_line_series[old_key]
            del self.graph_line_series[old_key]

    def update_series(self, item: QStandardItem):
        if item.column() == 5:  # check for checkbox column
            item_idx = item.index()
            date = self.dish_data_table_model.data(item_idx.siblingAtColumn(1))
            dish_name = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(2))
            dish_price = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(3))
            sell_num = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(4))
            set_name = dish_name + "(" + dish_price + ")"
            key = str(
                QDateTime(QDate.fromString(date,
                                           "yyyy-MM-dd")).toSecsSinceEpoch())
            if key not in self.graph_series:
                self.graph_series[key] = {}

            if int(item.text()) == 0:
                if set_name in self.graph_series[key]:
                    del self.graph_series[key][set_name]
                if not self.graph_series[key]:
                    del self.graph_series[key]
            else:
                self.graph_series[key][set_name] = int(sell_num)

    def update_graph(self, index):
        if index == 2:
            self.graph_chart.removeAllSeries()

            axis_x = QBarCategoryAxis()
            axis_x.setTitleText("日期")
            if self.graph_chart.axisX():
                self.graph_chart.removeAxis(self.graph_chart.axisX())
            self.graph_chart.addAxis(axis_x, Qt.AlignBottom)

            axis_y = QValueAxis()
            axis_y.setLabelFormat("%i")
            axis_y.setTitleText("售出量")
            if self.graph_chart.axisY():
                self.graph_chart.removeAxis(self.graph_chart.axisY())
            self.graph_chart.addAxis(axis_y, Qt.AlignLeft)

            max_num = 0
            total_date = 0
            set_dict = {}
            for key, data in sorted(self.graph_series.items(),
                                    key=lambda i: int(i[0])):
                axis_x.append(
                    QDateTime.fromSecsSinceEpoch(
                        int(key)).toString("yyyy年MM月dd日"))
                for set_name, value in data.items():
                    if set_name not in set_dict:
                        set_dict[set_name] = QBarSet(set_name)
                        for _ in range(total_date):
                            set_dict[set_name].append(0)
                    set_dict[set_name].append(value)
                    max_num = max(max_num, value)
                total_date += 1
                for _, bar_set in set_dict.items():
                    if bar_set.count() < total_date:
                        bar_set.append(0)
            bar_series = QBarSeries()
            for _, bar_set in set_dict.items():
                bar_series.append(bar_set)
            bar_series.hovered.connect(self.graph_tooltip)
            axis_y.setMax(max_num + 1)
            axis_y.setMin(0)
            self.graph_chart.addSeries(bar_series)
            bar_series.attachAxis(axis_x)
            bar_series.attachAxis(axis_y)

    def graph_tooltip(self, status, index, bar_set: QBarSet):
        if status:
            QToolTip.showText(
                QCursor.pos(),
                "{}\n日期: {}\n售出: {}".format(bar_set.label(),
                                            self.graph_chart.axisX().at(index),
                                            int(bar_set.at(index))))
예제 #18
0
class Table(QWidget):
    def __init__(self):
        super(Table, self).__init__()
        self.setWindowTitle('TableView示例')
        self.resize(600, 600)
        self.model = QStandardItemModel(4, 4)
        '''
        QStandardItemModel:'Q标准化模型'类提供了一个用于存储定制数据的通用模型。 
        'Q标准化模型'可以作为标准Qt数据类型的存储库。
        它是模型/视图类之一,也是Qt模型/视图框架的一部分。 
        'Q标准化模型'提供了一种经典的基于项目的方法来处理模型。
        'Q标准化模型'提供了Q标准化模型中的项目。 
        'Q标准化模型'实现了QAbstractItemModel接口,这意味着该模型可以用于提供支持该接口
        的任何视图中的数据(如QListView、QTableView和QTreeView,以及自定义的类型)。

        当您需要一个列表或树时,通常会创建一个空的'q标准化模型',
        并使用appendRow()将项目添加到模型中,并使用item()来访问项目。
        如果您的模型代表一个表,那么您通常将表的维度传递给'q标准化模型'构造函数,
        并使用setItem()将条目放置到表中。您还可以使用setRowCount()和setColumnCount()来改变模型的维度。
        要插入项,请使用insertRow()或insertColumn(),并删除项目,使用removeRow()或removeColumn()。
        '''
        tableTittleList = ['行数', '针数', '次数', '收针']
        self.model.setHorizontalHeaderLabels(tableTittleList)
        dataList = [
            '5', '7', 'dd', '90', '34', '', '1', '33', '45', '31', '34', '12',
            '89', '12', '1', '513'
        ]

        for [n, (i, j)] in enumerate([(i, j) for i in range(4)
                                      for j in range(4)]):
            item = QStandardItem(dataList[n])
            self.model.setItem(i, j, item)

        self.tabletView = QTableView()
        self.tabletView.setModel(self.model)
        # 设置tableView的最后一列会跟随窗口水平伸缩
        self.tabletView.horizontalHeader().setStretchLastSection(True)
        # 设置tableView的所有列都会跟谁窗口伸缩
        self.tabletView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        self.stateLabel = QLabel('Size:(0x0),Mouse:(0,0)')
        self.setStateLabel()

        self.tabletView.clicked.connect(self.setStateLabel)

        # 添加一些按钮:删除行,插入行,清空行,
        delBtn = QPushButton('删除')
        insertRowBtn = QPushButton('插入')
        clrBtn = QPushButton('清除')

        # 添加2个lineEdit和一个btn 用来查询用户指定的位置的数据
        rowLine = QLineEdit()
        colLine = QLineEdit()
        findBtn = QPushButton('查询')
        # 创建一个整数验证器,用来限制输入的数据为0~300的整数
        intValidator = QIntValidator()
        intValidator.setRange(0, 300)
        # 添加信号槽
        rowLine.setValidator(intValidator)
        colLine.setValidator(intValidator)
        rowLine.setPlaceholderText('输入查询的行数')
        colLine.setPlaceholderText('输入要查询的列数')
        findBtn.clicked.connect(
            lambda: self.findData(int(rowLine.text()), int(colLine.text())))

        # 为按钮添加信号槽
        delBtn.clicked.connect(self.removeRow)
        insertRowBtn.clicked.connect(self.insertRow)
        clrBtn.clicked.connect(self.clearSelectedItem)

        btnGridLayout = QGridLayout()
        btnGridLayout.addWidget(delBtn, 0, 0)
        btnGridLayout.addWidget(insertRowBtn, 0, 1)
        btnGridLayout.addWidget(clrBtn, 0, 2)
        btnGridLayout.addWidget(rowLine, 1, 0)
        btnGridLayout.addWidget(colLine, 1, 1)
        btnGridLayout.addWidget(findBtn, 1, 2)

        # 创建查询框和查询按钮
        searchLine = QLineEdit()
        columnNumLine = QLineEdit()
        searchBtn = QPushButton('搜索')
        columnNumLine.setValidator(intValidator)
        # 为搜索按钮添加槽
        searchBtn.clicked.connect(
            lambda: self.searchData(searchLine.text(), columnNumLine.text()))

        btnGridLayout.addWidget(searchLine, 2, 0)
        btnGridLayout.addWidget(columnNumLine, 2, 1)
        btnGridLayout.addWidget(searchBtn, 2, 2)

        layout = QVBoxLayout()
        layout.addWidget(self.tabletView)
        layout.addLayout(btnGridLayout)
        layout.addWidget(self.stateLabel)
        self.setLayout(layout)

    def setStateLabel(self, p_arg):
        print(p_arg)
        '''获取当前tableView的大小和鼠标点击的位置,以及选择和框选区大小'''
        selectedIndexes = self.tabletView.selectedIndexes()

        stateList = [
            self.model.rowCount(),
            self.model.columnCount(),
            self.tabletView.currentIndex().row(),
            self.tabletView.currentIndex().column()
        ]
        self.stateLabel.setText(
            'Size:(%dx%d),Mouse:(%d,%d)' %
            (stateList[0], stateList[1], stateList[2] + 1, stateList[3] + 1))
        print(stateList)

    def insertRow(self):
        if self.model.rowCount() < 300:
            if self.model.rowCount() == 0:
                self.model.setItem(0, QStandardItem(''))
            else:
                self.model.insertRow(self.tabletView.currentIndex().row())
            print('rowCount = ', self.model.rowCount())
        else:
            QMessageBox.warning(self, '停止', '最大支持300行数据!')

        self.setStateLabel()

    def removeRow(self):
        indexes = self.tabletView.selectedIndexes()
        rowIndexList = []
        for index in indexes:
            rowIndexList.append(index.row())
        rowIndexSet = set(rowIndexList)
        print(len(indexes), len(rowIndexList), len(rowIndexSet))
        self.model.removeRows(self.tabletView.currentIndex().row(),
                              len(rowIndexSet))
        self.setStateLabel()

    def findData(self, n_row, n_col):
        print('开始查询第{0}行,第{1}列的数据...'.format(n_row, n_col))
        index = self.model.index(n_row - 1, n_col - 1)
        # 检查输入的数据是否超出表格范围,并检查表格内容是否为空
        if (n_row - 1) > self.model.rowCount():
            QMessageBox.critical(self, '错误', '输入的行数超过表格最大行数')
        elif (n_col - 1) > self.model.columnCount():
            QMessageBox.critical(self, '错误', '输入的列数超过表格最大列数')
        else:
            data = self.model.data(index)
            if data:
                QMessageBox.information(
                    self, '查询',
                    '({0},{1})位置处的数值是{2}'.format(n_row, n_col, data))
            else:
                QMessageBox.information(
                    self, '查询',
                    '({0},{1})位置处的数值是{2}'.format(n_row, n_col, '空的'))

    def searchData(self, data, column_num):
        # 用来在指定的column_num列找那个查找有没有data的item
        # 如果找到,返回其行数, 如果找不到,告知找不到
        column_num = int(column_num)

        dataItem = QStandardItem(data)
        indexList = self.model.findItems(data, column=column_num - 1)
        list = []
        for i in range(len(indexList)):
            list.append(indexList[i].row())
        if len(list) == 0:
            QMessageBox.information(
                self, '找不到', '在第{0}列中找不到\n任何值是{1}元素'.format(column_num, data))
        else:
            for i in range(len(list)):
                list[i] = list[i] + 1
            dlgText = """在第{0}列中找到了值是'{1}'的元素共<font color = red>{2}</font>个,分别在第{3}列""".format(
                column_num, data, len(list), list)
            QMessageBox.information(self, '找到了', dlgText)

    def clearSelectedItem(self):
        indexes = self.tabletView.selectedIndexes()
        for index in indexes:
            self.model.setItem(index.row(), index.column(), QStandardItem(''))
예제 #19
0
파일: breakpoints.py 프로젝트: iGio90/Dwarf
class BreakpointsWidget(QWidget):
    """ BreakpointsWidget

        Signals:
            onBreakpointChanged(str) - ptr
            onBreakpointRemoved(str) - ptr
    """

    onBreakpointChanged = pyqtSignal(str, name='onBreakpointChanged')
    onBreakpointsRemoved = pyqtSignal(str, name='onBreakpointRemoved')

    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(BreakpointsWidget, self).__init__(parent=parent)

        self._app_window = parent

        if self._app_window.dwarf is None:
            print('BreakpointsWidget created before Dwarf exists')
            return

        # connect to dwarf
        self._app_window.dwarf.onApplyContext.connect(self._on_apply_context)
        self._app_window.dwarf.onAddJavaBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddObjCBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddNativeBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddModuleInitializationBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddJavaClassInitializationBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onHitModuleInitializationBreakpoint.connect(
            self._on_hit_module_initialization_breakpoint)
        self._app_window.dwarf.onHitJavaClassInitializationBreakpoint.connect(
            self._on_hit_java_class_initialization_breakpoint)
        self._app_window.dwarf.onDeleteBreakpoint.connect(
            self._on_breakpoint_deleted)

        self._breakpoints_list = DwarfListView()
        self._breakpoints_list.doubleClicked.connect(self._on_double_clicked)
        self._breakpoints_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._breakpoints_list.customContextMenuRequested.connect(
            self._on_context_menu)
        self._breakpoints_model = QStandardItemModel(0, 3)

        self._breakpoints_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._breakpoints_model.setHeaderData(1, Qt.Horizontal, 'T')
        self._breakpoints_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._breakpoints_model.setHeaderData(2, Qt.Horizontal, '<>')
        self._breakpoints_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)

        self._breakpoints_list.setModel(self._breakpoints_model)

        self._breakpoints_list.header().setStretchLastSection(False)
        self._breakpoints_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._breakpoints_list.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self._breakpoints_list.header().setSectionResizeMode(
            2, QHeaderView.ResizeToContents)

        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        v_box.addWidget(self._breakpoints_list)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        self.btn1 = QPushButton(
            QIcon(utils.resource_path('assets/icons/plus.svg')), '')
        self.btn1.setFixedSize(20, 20)
        self.btn1.clicked.connect(self._on_add_item_clicked)
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(self.btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)
        self.setLayout(v_box)

        self._bold_font = QFont(self._breakpoints_list.font())
        self._bold_font.setBold(True)

        shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_N),
                                       self._app_window,
                                       self._on_add_native_breakpoint)
        shortcut_addnative.setAutoRepeat(False)

        shortcut_addjava = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J),
                                     self._app_window,
                                     self._on_add_java_breakpoint)
        shortcut_addjava.setAutoRepeat(False)

        shortcut_add_native_onload = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window,
            self._on_add_module_initialization_breakpoint)
        shortcut_add_native_onload.setAutoRepeat(False)

        # new menu
        self.new_menu = QMenu('New')
        self.new_menu.addAction('Native', self._on_add_native_breakpoint)
        self.new_menu.addAction('Module initialization',
                                self._on_add_module_initialization_breakpoint)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def delete_items(self):
        """ Delete selected Items
        """
        index = self._breakpoints_list.selectionModel().currentIndex().row()
        if index != -1:
            self._on_delete_breakpoint(index)
            self._breakpoints_model.removeRow(index)

    def clear_list(self):
        """ Clear the List
        """
        # go through all items and tell it gets removed
        for item in range(self._breakpoints_model.rowCount()):
            self._on_delete_breakpoint(item)

        if self._breakpoints_model.rowCount() > 0:
            # something was wrong it should be empty
            self._breakpoints_model.removeRows(
                0, self._breakpoints_model.rowCount())

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_apply_context(self, context):
        if context['reason'] == -1:
            if self._app_window.dwarf.java_available:
                self.new_menu.addAction('Java', self._on_add_java_breakpoint)
                self.new_menu.addAction(
                    'Java class initialization',
                    self._on_add_java_class_initialization_breakpoint)

    def _on_add_breakpoint(self, breakpoint):
        type_ = QStandardItem()
        type_.setFont(self._bold_font)
        type_.setTextAlignment(Qt.AlignCenter)
        if breakpoint.breakpoint_type == BREAKPOINT_NATIVE:
            type_.setText('N')
            type_.setToolTip('Native breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_JAVA:
            type_.setText('J')
            type_.setToolTip('Java breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_INITIALIZATION:
            type_.setText('C')
            type_.setToolTip('Initialization breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_OBJC:
            type_.setText('O')
            type_.setToolTip('ObjC breakpoint')
        else:
            type_.setText('U')
            type_.setToolTip('Unknown Type')

        addr = QStandardItem()

        if breakpoint.breakpoint_type == BREAKPOINT_JAVA:
            addr.setText(breakpoint.get_target())
        elif breakpoint.breakpoint_type == BREAKPOINT_OBJC:
            addr.setText(breakpoint.get_target())
        elif breakpoint.breakpoint_type == BREAKPOINT_INITIALIZATION:
            addr.setText(breakpoint.get_target())
            addr.setData(breakpoint.debug_symbol, Qt.UserRole + 2)
        else:
            str_fmt = '0x{0:x}'
            if self._breakpoints_list.uppercase_hex:
                str_fmt = '0x{0:X}'
            # addr.setTextAlignment(Qt.AlignCenter)
            addr.setText(str_fmt.format(breakpoint.get_target()))

        condition = QStandardItem()
        condition.setTextAlignment(Qt.AlignCenter)
        condition.setFont(self._bold_font)
        if breakpoint.condition and breakpoint.condition != 'null' and breakpoint.condition != 'undefined':
            condition.setText('ƒ')
            condition.setToolTip(breakpoint.condition)
            condition.setData(breakpoint.condition, Qt.UserRole + 2)

        self._breakpoints_model.appendRow([addr, type_, condition])
        self._breakpoints_list.resizeColumnToContents(0)

    def _on_hit_module_initialization_breakpoint(self, data):
        items = self._breakpoints_model.findItems(data[1]['module'],
                                                  Qt.MatchExactly, 2)
        if len(items) > 0:
            self._breakpoints_model.item(items[0].row(),
                                         0).setText(data[1]['moduleBase'])

    def _on_hit_java_class_initialization_breakpoint(self, data):
        items = self._breakpoints_model.findItems(data[0], Qt.MatchExactly, 2)
        if len(items) > 0:
            pass

    def _on_double_clicked(self, model_index):
        item = self._breakpoints_model.itemFromIndex(model_index)
        if model_index.column() == 2 and item.text() == 'ƒ':
            self._on_modify_condition(model_index.row())
        else:
            self._app_window.jump_to_address(self._breakpoints_model.item(
                model_index.row(), 0).text(),
                                             view=1)

    def _on_context_menu(self, pos):
        context_menu = QMenu(self)
        context_menu.addMenu(self.new_menu)

        context_menu.addSeparator()
        index = self._breakpoints_list.indexAt(pos).row()
        if index != -1:
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._breakpoints_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._breakpoints_model.item(index, 0).text()))
            context_menu.addSeparator()
            context_menu.addAction('Edit Condition',
                                   lambda: self._on_modify_condition(index))
            context_menu.addSeparator()
            context_menu.addAction('Delete Breakpoint',
                                   lambda: self._on_delete_breakpoint(index))

            if self._breakpoints_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction('Search',
                                       self._breakpoints_list._on_cm_search)

        # show context menu
        global_pt = self._breakpoints_list.mapToGlobal(pos)
        context_menu.exec(global_pt)

    def _on_modify_condition(self, num_row):
        item = self._breakpoints_model.item(num_row, 2)
        data = item.data(Qt.UserRole + 2)
        if data is None:
            data = ''
        ptr = self._breakpoints_model.item(num_row, 0).text()
        accept, input_ = InputMultilineDialog().input(
            'Condition for breakpoint %s' % ptr, input_content=data)
        if accept:
            what = utils.parse_ptr(ptr)
            if what == 0:
                what = self._breakpoints_model.item(num_row,
                                                    2).data(Qt.UserRole + 2)
            if self._app_window.dwarf.dwarf_api(
                    'setBreakpointCondition',
                [what, input_.replace('\n', '')]):
                item.setData(input_, Qt.UserRole + 2)
                if not item.text():
                    item.setText('ƒ')
                item.setToolTip(input_)
                self.onBreakpointChanged.emit(ptr)

    # + button
    def _on_add_item_clicked(self):
        self.new_menu.exec_(QCursor.pos())

    # shortcuts/menu
    def _on_add_native_breakpoint(self):
        self._app_window.dwarf.breakpoint_native()

    def _on_add_java_breakpoint(self):
        self._app_window.dwarf.breakpoint_java()

    def _on_add_module_initialization_breakpoint(self):
        self._app_window.dwarf.breakpoint_module_initialization()

    def _on_add_java_class_initialization_breakpoint(self):
        self._app_window.dwarf.breakpoint_java_class_initialization()

    def _on_delete_breakpoint(self, num_row):
        breakpoint_type = self._breakpoints_model.item(num_row, 1).text()
        if breakpoint_type == 'N':
            ptr = self._breakpoints_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('removeBreakpoint', ptr)
            self.onBreakpointRemoved.emit(str(ptr))
        elif breakpoint_type == 'J':
            target = self._breakpoints_model.item(num_row, 0).text()
            self._app_window.dwarf.dwarf_api('removeBreakpoint', target)
        elif breakpoint_type == 'O':
            target = self._breakpoints_model.item(num_row, 0).text()
            self._app_window.dwarf.dwarf_api('removeBreakpoint', target)
        elif breakpoint_type == 'C':
            item = self._breakpoints_model.item(num_row, 0)
            target = item.text()
            is_native = item.data(Qt.UserRole + 2) is None
            if is_native:
                self._app_window.dwarf.dwarf_api(
                    'removeModuleInitializationBreakpoint', target)
            else:
                self._app_window.dwarf.dwarf_api(
                    'removeJavaClassInitializationBreakpoint', target)
        elif breakpoint_type == 'U':
            ptr = self._breakpoints_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('removeBreakpoint', ptr)
            self.onBreakpointRemoved.emit(str(ptr))

    def _on_breakpoint_deleted(self, parts):
        _msg, _type, _val = parts

        additional = None

        if _type == 'objc' or _type == 'java' or _type == 'java_class_initialization':
            str_frmt = _val
            item_index = 0
        elif _type == 'module_initialization':
            str_frmt = _val
            item_index = 0
        else:
            _ptr = utils.parse_ptr(_val)
            if self._breakpoints_list._uppercase_hex:
                str_frmt = '0x{0:X}'.format(_ptr)
            else:
                str_frmt = '0x{0:x}'.format(_ptr)
            item_index = 0

        for _item in range(self._breakpoints_model.rowCount()):
            item = self._breakpoints_model.item(_item, item_index)

            if item is None:
                continue

            if str_frmt == item.text():
                if additional is not None:
                    if additional == self._breakpoints_model.item(_item,
                                                                  2).text():
                        self._breakpoints_model.removeRow(_item)
                else:
                    self._breakpoints_model.removeRow(_item)
예제 #20
0
class Explorer(QWidget):
    """
    This class implements the diagram predicate node explorer.
    """
    def __init__(self, mainwindow):
        """
        Initialize the Explorer.
        :type mainwindow: MainWindow
        """
        super().__init__(mainwindow)
        self.expanded = {}
        self.searched = {}
        self.scrolled = {}
        self.mainview = None
        self.iconA = QIcon(':/icons/treeview-icon-attribute')
        self.iconC = QIcon(':/icons/treeview-icon-concept')
        self.iconD = QIcon(':/icons/treeview-icon-datarange')
        self.iconI = QIcon(':/icons/treeview-icon-instance')
        self.iconR = QIcon(':/icons/treeview-icon-role')
        self.iconV = QIcon(':/icons/treeview-icon-value')
        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QStandardItemModel(self)
        self.proxy = QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.view = ExplorerView(mainwindow, self)
        self.view.setModel(self.proxy)
        self.mainLayout = QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.view)
        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)
        self.setMinimumHeight(160)

        connect(self.view.doubleClicked, self.itemDoubleClicked)
        connect(self.view.pressed, self.itemPressed)
        connect(self.view.collapsed, self.itemCollapsed)
        connect(self.view.expanded, self.itemExpanded)
        connect(self.search.textChanged, self.filterItem)

    ####################################################################################################################
    #                                                                                                                  #
    #   EVENTS                                                                                                         #
    #                                                                                                                  #
    ####################################################################################################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QStyleOption()
        option.initFrom(self)
        painter = QPainter(self)
        style = self.style()
        style.drawPrimitive(QStyle.PE_Widget, option, painter, self)

    ####################################################################################################################
    #                                                                                                                  #
    #   SLOTS                                                                                                          #
    #                                                                                                                  #
    ####################################################################################################################

    @pyqtSlot('QGraphicsItem')
    def add(self, item):
        """
        Add a node in the tree view.
        :type item: AbstractItem
        """
        if item.node and item.predicate:
            parent = self.parentFor(item)
            if not parent:
                parent = ParentItem(item)
                parent.setIcon(self.iconFor(item))
                self.model.appendRow(parent)
                self.proxy.sort(0, Qt.AscendingOrder)
            child = ChildItem(item)
            child.setData(item)
            parent.appendRow(child)
            self.proxy.sort(0, Qt.AscendingOrder)

    @pyqtSlot(str)
    def filterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        if self.mainview:
            self.proxy.setFilterFixedString(key)
            self.proxy.sort(Qt.AscendingOrder)
            self.searched[self.mainview] = key

    @pyqtSlot('QModelIndex')
    def itemCollapsed(self, index):
        """
        Executed when an item in the tree view is collapsed.
        :type index: QModelIndex
        """
        if self.mainview:
            if self.mainview in self.expanded:
                item = self.model.itemFromIndex(self.proxy.mapToSource(index))
                expanded = self.expanded[self.mainview]
                expanded.remove(item.text())

    @pyqtSlot('QModelIndex')
    def itemDoubleClicked(self, index):
        """
        Executed when an item in the tree view is double clicked.
        :type index: QModelIndex
        """
        item = self.model.itemFromIndex(self.proxy.mapToSource(index))
        node = item.data()
        if node:
            self.selectNode(node)
            self.focusNode(node)

    @pyqtSlot('QModelIndex')
    def itemExpanded(self, index):
        """
        Executed when an item in the tree view is expanded.
        :type index: QModelIndex
        """
        if self.mainview:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if self.mainview not in self.expanded:
                self.expanded[self.mainview] = set()
            expanded = self.expanded[self.mainview]
            expanded.add(item.text())

    @pyqtSlot('QModelIndex')
    def itemPressed(self, index):
        """
        Executed when an item in the tree view is clicked.
        :type index: QModelIndex
        """
        item = self.model.itemFromIndex(self.proxy.mapToSource(index))
        node = item.data()
        if node:
            self.selectNode(node)

    @pyqtSlot('QGraphicsItem')
    def remove(self, item):
        """
        Remove a node from the tree view.
        :type item: AbstractItem
        """
        if item.node and item.predicate:
            parent = self.parentFor(item)
            if parent:
                child = self.childFor(parent, item)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    ####################################################################################################################
    #                                                                                                                  #
    #   AUXILIARY METHODS                                                                                              #
    #                                                                                                                  #
    ####################################################################################################################

    @staticmethod
    def childFor(parent, node):
        """
        Search the item representing this node among parent children.
        :type parent: QStandardItem
        :type node: AbstractNode
        """
        key = ChildItem.key(node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QStandardItem
        """
        key = ParentItem.key(node)
        for i in self.model.findItems(key, Qt.MatchExactly):
            n = i.child(0).data()
            if node.item is n.item:
                return i
        return None

    ####################################################################################################################
    #                                                                                                                  #
    #   INTERFACE                                                                                                      #
    #                                                                                                                  #
    ####################################################################################################################

    def browse(self, view):
        """
        Set the widget to inspect the given view.
        :type view: MainView
        """
        self.reset()
        self.mainview = view

        if self.mainview:

            scene = self.mainview.scene()
            connect(scene.index.sgnItemAdded, self.add)
            connect(scene.index.sgnItemRemoved, self.remove)

            for item in scene.index.nodes():
                self.add(item)

            if self.mainview in self.expanded:
                expanded = self.expanded[self.mainview]
                for i in range(self.model.rowCount()):
                    item = self.model.item(i)
                    index = self.proxy.mapFromSource(
                        self.model.indexFromItem(item))
                    self.view.setExpanded(index, item.text() in expanded)

            key = ''
            if self.mainview in self.searched:
                key = self.searched[self.mainview]
            self.search.setText(key)

            if self.mainview in self.scrolled:
                rect = self.rect()
                item = first(self.model.findItems(
                    self.scrolled[self.mainview]))
                for i in range(self.model.rowCount()):
                    self.view.scrollTo(
                        self.proxy.mapFromSource(
                            self.model.indexFromItem(self.model.item(i))))
                    index = self.proxy.mapToSource(
                        self.view.indexAt(rect.topLeft()))
                    if self.model.itemFromIndex(index) is item:
                        break

    def reset(self):
        """
        Clear the widget from inspecting the current view.
        """
        if self.mainview:

            rect = self.rect()
            item = self.model.itemFromIndex(
                self.proxy.mapToSource(self.view.indexAt(rect.topLeft())))
            if item:
                node = item.data()
                key = ParentItem.key(node) if node else item.text()
                self.scrolled[self.mainview] = key
            else:
                self.scrolled.pop(self.mainview, None)

            try:
                scene = self.mainview.scene()
                disconnect(scene.index.sgnItemAdded, self.add)
                disconnect(scene.index.sgnItemRemoved, self.remove)
            except RuntimeError:
                pass
            finally:
                self.mainview = None

        self.model.clear()

    def flush(self, view):
        """
        Flush the cache of the given mainview.
        :type view: MainView
        """
        self.expanded.pop(view, None)
        self.searched.pop(view, None)
        self.scrolled.pop(view, None)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.item is Item.AttributeNode:
            return self.iconA
        if node.item is Item.ConceptNode:
            return self.iconC
        if node.item is Item.ValueDomainNode:
            return self.iconD
        if node.item is Item.ValueRestrictionNode:
            return self.iconD
        if node.item is Item.IndividualNode:
            if node.identity is Identity.Instance:
                return self.iconI
            if node.identity is Identity.Value:
                return self.iconV
        if node.item is Item.RoleNode:
            return self.iconR

    def focusNode(self, node):
        """
        Focus the given node in the main view.
        :type node: AbstractNode
        """
        if self.mainview:
            self.mainview.centerOn(node)

    def selectNode(self, node):
        """
        Select the given node in the main view.
        :type node: AbstractNode
        """
        if self.mainview:
            scene = self.mainview.scene()
            scene.clearSelection()
            node.setSelected(True)
예제 #21
0
class OlsDialog(QDialog):
    """Dialog to search the OLS for an ontology

    The OlsDialog uses threads to connect to the Ontology Lookup Service,
    and search for a query, get results, and get informations about 
    ontologies. 

    Selected ontology is returned as a json serialized dict.
    """

    SigSearchCompleted = pyqtSignal('QString')

    def __init__(self, parent=None, allow_onto=False):
        super(OlsDialog, self).__init__(parent)

        self.ui = Ui_Ols()
        self.ui.setupUi(self)
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)

        self.onto = {}
        self.ontothreads = {}
        self.allow_onto = allow_onto
        self.entry = None

        self.ui.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(
            self.accept)
        self.ui.buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(
            self.reject)

        self.ui.searchButton.clicked.connect(self.search)
        self.ui.queryLine.setFocus()

    def search(self):
        """Launch the OlsSearchThread"""
        self.searcher = OlsSearcher(self.ui.queryLine.text())
        self.searcher.Finished.connect(self.updateSearchResults)
        self.searcher.start()

    def updateSearchResults(self, jresults):
        """Update TreeView with search results."""

        self.model = QStandardItemModel()
        self.orderedResults = {}

        if jresults:

            self.results = json.loads(jresults)

            for result in self.results:
                prefix = result['ontology_prefix']

                # Create a new node & append it to StandardItemModel
                # if the ontology of the result is not already in StandardItemModel
                if not self.model.findItems(prefix):
                    node = QStandardItem(prefix)
                    self.model.appendRow(node)

                # Look for details of that new ontology if that ontology is not
                # already memo table and not other OlsOntologist is querying
                # informations about that ontology
                if prefix not in self.ontothreads and prefix not in self.onto:
                    thread = OlsOntologist(prefix)
                    thread.Finished.connect(self._memo_onto)
                    thread.start()
                    self.ontothreads[prefix] = thread

                # Add the entry to its ontology node
                result['tag'] = result['short_form'].replace(
                    '_', ':') + ' - ' + result['label']
                self.model.findItems(prefix)[0].appendRow(
                    QStandardItem(result['tag']))

        self.model.sort(0)
        self.ui.ontoTree.setModel(self.model)
        #self.ui.ontoTree.expandAll()
        self.model.setHorizontalHeaderLabels(["Object"])
        self.ui.ontoTree.selectionModel().selectionChanged.connect(
            lambda selection: self.updateInterface(selection.indexes()[0]))
        self.ui.ontoTree.clicked.connect(self.updateInterface)
        self.ui.ontoTree.doubleClicked.connect(self.onDoubleClick)

    def _getResultFromIndex(self, index):
        """Iterate on self.results to get the right entry"""
        crawler = self.model.itemFromIndex(index)
        self.entry = None
        for x in self.results:
            if x['tag'] == crawler.text():
                self.entry = x
        return crawler.text()

    def updateInterface(self, index):
        """Update the interface fields with the value from the TreeView"""

        if index:
            tag = self._getResultFromIndex(index)

            # selection is an ontology
            if self.entry is None:

                if not self.allow_onto:
                    self.ui.buttonBox.button(
                        QDialogButtonBox.Ok).setEnabled(False)

                # information about ontology is present in memoization table
                if tag in self.onto.keys():

                    self.entry = self.onto[tag]
                    self.ui.value.setPlainText(self.entry['title'])
                    self.ui.prefix.setText(self.entry['preferredPrefix'])
                    self.ui.iri.setPlainText(self.entry['id'])
                    self.ui.description.setPlainText(self.entry['description'])

                # No information is to be found
                else:
                    self.ui.value.setPlainText("")
                    self.ui.prefix.setText("")
                    self.ui.iri.setPlainText("")
                    self.ui.description.setPlainText("")

                self.ui.prefix.setText(tag)
                self.ui.type.setText('Ontology')

            # selection is a class
            else:

                self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)

                self.ui.value.setPlainText(self.entry['label'])
                self.ui.prefix.setText(self.entry['ontology_prefix'])
                self.ui.iri.setPlainText(self.entry['iri'])
                self.ui.type.setText('Class')

                self.ui.description.setPlainText(
                    self.entry['description'][0] if 'description' in
                    self.entry else '')

    def onDoubleClick(self, index):
        """Return class when double clicked"""
        self._getResultFromIndex(index)
        if self.entry is not None:
            self.accept()

    def _memo_onto(self, prefix, jsonconfig):
        self.onto[prefix] = json.loads(jsonconfig)
예제 #22
0
class GeneralView(QWidget):
    def __init__(self, parent=None):
        super().__init__()

        self.ui = Ui_AggrPortfolioView()
        self.ui.setupUi(self)

        self.ui.treeView.setRootIsDecorated(True)
        self.ui.treeView.setAlternatingRowColors(True)

        self.model = QStandardItemModel(0, 3, self)
        self.ui.treeView.setModel(self.model)

        self.model.setHorizontalHeaderLabels(
            ['Exchange', 'Volume', 'Totla in'])

        # balance = [ {'exchange':'binance', 'account': 'xxx1', 'symbol':'BTC', 'balance':{'total':234} },
        #             {'exchange':'binance', 'account': 'xxx1', 'symbol':'ETH', 'balance':{'total':15} },
        #             {'exchange':'kraken', 'account': 'xxx1', 'symbol':'ETH', 'balance':{'total':115} }, ]

        # for i in balance:
        #     self.update_tree(i)

        self.ui.treeView.expandAll()

    #@pyqtSlot()
    def on_click(self):
        pass

    @pyqtSlot(str)
    def slot_update_tree(self, balance):

        #print(balance)
        balance = json.loads(balance)

        # parent1 = QStandardItem('binance')
        # currency1 = QStandardItem('BTC')
        # parent1.appendRow(currency1)

        # currency2 = QStandardItem('ETH')
        # parent1.appendRow(currency2)
        # self.model.appendRow(parent1)

        exchange = self.model.findItems(balance['exchange'])

        if exchange:

            all_currency = exchange[0].rowCount()
            new_currency = True
            print(all_currency)

            for c in range(all_currency):
                curency = exchange[0].itme(0, 0)

                if curency.text() == balance['symbol']:
                    new_currency = False

                    for i in range(curency.columnCount()):
                        print(curency.text(), curency.item(0, i).text())
                        #print('update:', exchange[0].text(), curency.text() )

                    print(curency.text(),
                          curency.model().item(0, 0).text(),
                          curency.rowCount(), curency.columnCount())
                    curency.takeChild(0,
                                      1).setText(balance['balance']['total'])

                    break

            if new_currency:

                name = QStandardItem(balance['symbol'])
                total = QStandardItem(str(balance['balance']['total']))
                exchange[0].appendRow([name, total])

        else:

            parent1 = QStandardItem(balance['exchange'])

            child1 = QStandardItem(balance['symbol'])
            child2 = QStandardItem(str(balance['balance']['total']))

            parent1.appendRow([child1, child2])

            self.model.appendRow(parent1)
예제 #23
0
class FieldView(QWidget):

    keywordHighlight = pyqtSignal(str)

    # tabledChanged = pyqtSignal()

    def __init__(self, cols: dict, items: [dict], parent=None, undoStack=None):

        super(FieldView, self).__init__(parent)
        self.buffer = None
        self.cols = cols
        self.items = items
        self.table = TableView(self)
        self.model = QStandardItemModel()
        self.undoStack = undoStack
        self.table.setUndoStack(self.undoStack)
        self.table.setModel(self.model)
        # self.table.setWordWrap(True)
        self.entry = QLineEdit(self)
        self.entry.setClearButtonEnabled(True)
        self.entry.setPlaceholderText('Filter table by ...')
        self.entry.setMinimumWidth(300)
        self.entry.setMinimumHeight(35)
        self.caption = QLabel('')
        # self.hidden_rows = []
        # self.valid_index = []
        self.col_resize = []
        self.is_reserve_show = QCheckBox(self)
        self.linting_en = QCheckBox(self)
        self.linting_en.setCheckState(Qt.Checked)

        hbox = QHBoxLayout()
        hbox.addWidget(self.is_reserve_show)
        hbox.addWidget(QLabel("Show RESERVED"))
        hbox.addWidget(self.linting_en)
        hbox.addWidget(QLabel("Linting"))
        hbox.addWidget(self.entry)
        hbox.addStretch(1)
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.caption)
        vbox.addWidget(self.table)
        self.setLayout(vbox)

        self.entry.textChanged.connect(self.tableFilter)
        self.is_reserve_show.stateChanged.connect(self.show_reserved)
        self.table.deleteKeyPress.connect(self.dataBeforeChangedEvent)
        self.table.replaceSignal.connect(self.dataBeforeChangedEvent)
        self.create_ui()

    def show_reserved(self):
        if self.is_reserve_show.checkState() == Qt.Checked:
            for row in range(self.model.rowCount()):
                for col in range(self.model.columnCount()):
                    item = self.model.item(row, col)
                    if item.data(Qt.UserRole) == 'reserved':
                        item.setData('', Qt.UserRole)
        else:
            for row in range(self.model.rowCount()):
                field = list(self.cols.keys()).index('Field')
                item = self.model.item(row, field)
                if item.text().lower() == 'reserved':
                    for col in range(self.model.columnCount()):
                        cell = self.model.item(row, col)
                        cell.setData('reserved', Qt.UserRole)

    def dataBeforeChangedEvent(self, index: QModelIndex, new: str, old: str):
        if not index.isValid():
            return
        row = index.row()
        col = index.column()
        selected_indexes = self.table.selectedIndexes()
        indexes = []
        oldText = []
        for selected_index in selected_indexes:
            if selected_index.column() != index.column():
                continue
            indexes.append(selected_index)
            oldText.append(selected_index.data())
        cmd = DataChanged(widget=self.model,
                          newtext=new,
                          oldtext=oldText,
                          index=indexes,
                          description=f'Table Data changed at ({row}, {col})',
                          obj=self.items)
        self.undoStack.push(cmd)

    def chgRowHeight(self, index: QModelIndex, size: QSizeF):
        if not index.isValid():
            return
        row = index.row()
        self.table.setRowHeight(row, size.height())

    def create_ui(self, items: list = None):
        self.create_actions()
        self.create_cols()
        self.create_rows(items)

    def create_rows(self, items: list = None, caption=None):
        if items is not None:
            self.items = items
        if caption is not None:
            self.caption.setText(caption)
        self.table.resetMatches()
        self.model.removeRows(0, self.model.rowCount())

        for row, item in enumerate(self.items):
            is_reserved = (item.get('Field', '').lower() == 'reserved') & \
                          (self.is_reserve_show.checkState() == Qt.Unchecked)
            rows = []
            for col in self.cols.keys():
                cell = QStandardItem(str(item[col]))
                if is_reserved:
                    cell.setData('reserved', Qt.UserRole)
                rows.append(cell)
            self.model.appendRow(rows)

            # to adjust row size which is better than resizeRowToContents
            # use self.chgRowHeight to adjust base on QTextEdit height
            # the sizeHint in QStyledItemDelegate cannot get correct height
            # due to text wrap
            for col in self.col_resize:
                self.table.openPersistentEditor(self.model.index(row, col))
                self.table.closePersistentEditor(self.model.index(row, col))

        if self.entry.text().strip() != "":
            self.tableFilter()

    def create_cols(self):
        self.model.setHorizontalHeaderLabels(self.cols.keys())
        # self.model.head
        for col, config in enumerate(self.cols.values()):
            widget = config.get('widget', None)
            width = config.get('width', None)
            resize = config.get('resize', None)
            if width:
                self.table.setColumnWidth(col, width)
            if resize:
                self.table.horizontalHeader().setSectionResizeMode(
                    col, QHeaderView.Stretch)
                self.col_resize.append(col)

            if widget == "list":
                items = config.get('items', [])
                delegate = TableListViewDelegate(self.table, items)

            elif widget == 'textEdit':
                delegate = TableTextEditDelegate(self.table)
                delegate.sizeChanged.connect(self.chgRowHeight)

            else:
                validator = config.get('type', None)
                items = config.get('items', None)
                delegate = TableLineEditDelegate(
                    self.table,
                    items,
                    validator,
                    minValue=config.get('minValue', 0),
                    maxValue=config.get('maxValue', 31))

            self.table.setItemDelegateForColumn(col, delegate)
            delegate.dataBeforeChanged.connect(self.dataBeforeChangedEvent)
            self.keywordHighlight.connect(delegate.setKeyword)

    def create_actions(self):
        for config in field_contextmenu:
            sc = config.get('shortcut', None)
            if sc is None:
                continue
            label = config.get('label')
            qaction = QAction(label, self.table)
            # func = actions.pop()
            func = getattr(self, config.get('action'))
            qaction.setShortcut(sc)
            qaction.setShortcutContext(Qt.WidgetWithChildrenShortcut)
            qaction.triggered.connect(func)
            self.addAction(qaction)

    def tableFilter(self):
        text = self.entry.text().strip()
        self.keywordHighlight.emit(text)
        self.table.matches.clear()
        for row in range(self.model.rowCount()):
            self.table.hideRow(row)
        for col in range(self.model.columnCount()):
            matches = self.model.findItems(
                text,
                Qt.MatchContains,
                column=col,
            )
            for match in matches:
                self.table.showRow(match.row())
            self.table.matches.extend(matches)

    def contextMenuEvent(self, event: QContextMenuEvent):

        actions = {}
        menu = QMenu(self.table)
        for config in field_contextmenu:
            label = config.get('label')
            buffer = config.get('buffer', False)
            action = menu.addAction(label)
            icon = config.get('icon', None)
            if buffer and self.buffer is None:
                action.setEnabled(False)
            if icon:
                action.setIcon(qta.icon(icon, color='gray'))
            sc = config.get('shortcut', None)
            func = getattr(self, config.get('action'))
            if sc:
                action.setShortcut(sc)
            actions[action] = func

        action = menu.exec_(self.mapToGlobal(event.pos()))
        func = actions.get(action)
        if callable(func):
            func()

    def iterSelectedRows(self):
        indexes = self.table.selectedIndexes()
        for i in range(0, len(indexes), len(self.cols.keys())):
            yield indexes[i].row()

    @property
    def selectedRows(self):
        indexes = self.table.selectedIndexes()
        rows = []
        for i in range(0, len(indexes), len(self.cols.keys())):
            rows.append(indexes[i].row())
        return rows

    def iterRowValues(self):
        # if headers is None:
        headers = self.cols.keys()
        for row in range(self.model.rowCount()):
            yield row, {
                header: self.model.item(row, col).text().strip()
                for col, header in enumerate(headers)
            }

    def searchAndReplace(self):
        self.table.dialog.show()

    def remove(self):
        if not self.items:
            return
        items = {}
        for row in sorted(self.selectedRows):
            # self.model.removeRow(row)
            rows = []
            for col in range(len(self.cols.keys())):
                rows.append(self.model.item(row, col).text())
            items[row] = rows
        if not items:
            return
        cmd = TableRemoveCommand(description='remove command',
                                 widget=self.table,
                                 items=items,
                                 obj=self.items)
        # self.table.selectRow(rows[-1])
        self.undoStack.push(cmd)

    def copy(self):
        values = []
        for row in self.iterSelectedRows():
            rows = {}
            for col, header in enumerate(self.cols.keys()):
                rows[header] = self.model.item(row, col).text()
            values.append(rows)
        self.buffer = values

    def cut(self):
        self.copy()
        self.remove()

    def insertRow(self, row, item):

        cmd = TableInsertCommand(widget=self.table,
                                 row=row,
                                 description='Insert table',
                                 items=[
                                     str(
                                         item.get(col,
                                                  config.get('default', '')))
                                     for col, config in self.cols.items()
                                 ],
                                 obj=self.items)
        self.undoStack.push(cmd)

    def append_new(self):
        row = self.table.currentRow
        col = list(self.cols.keys()).index('LSB')
        index = self.model.index(row, col)
        if not index.isValid():
            lsb = 31
        else:
            lsb = int(index.data()) - 1
        if lsb < 0:
            lsb = 0
        new = {"MSB": lsb, "LSB": lsb}
        self.insertRow(row + 1, item={**new_field, **new})

    def append_copy(self):
        if self.buffer is None:
            return
        row = self.table.currentRow + 1
        for item in reversed(self.buffer):
            self.insertRow(row, item=copy.deepcopy(item))

    def prepend_new(self):
        row = self.table.currentRow
        col = list(self.cols.keys()).index('MSB')
        index = self.model.index(row, col)
        if not index.isValid():
            msb = 31
            row = 0
        else:
            msb = int(index.data()) + 1
        if msb > 31:
            msb = 31
        new = {"MSB": msb, "LSB": msb}
        self.insertRow(row, item={**new_field, **new})

    def prepend_copy(self):
        if self.buffer is None:
            return
        row = self.table.currentRow
        if row < 0:
            row = 0
        for item in reversed(self.buffer):
            self.insertRow(row, item=copy.deepcopy(item))

    def linting(self) -> (bool, str):
        msg = str()
        if not self.items or (self.linting_en.checkState() == Qt.Unchecked):
            return True, msg
        success = False
        msb = int(self.cols.get('MSB').get('maxValue', 31))
        run = None
        try:
            for row, values in self.iterRowValues():
                row += 1
                run = row
                for header, config in self.cols.items():
                    require = config.get('require', True)
                    value = values.get(header, '')
                    if require:
                        if value == '':
                            msg = f'Value Error at Row: {row}, column: {header}\n' \
                                f'This entry cannot be empty'
                            success = False
                            break
                    if header == "MSB":
                        value = int(value)
                        lsb = int(values.get('LSB', msb))
                        success = (value == msb) & (msb >= lsb)
                        msb = lsb - 1
                        if self.model.rowCount() == row and success:
                            success = lsb == int(
                                self.cols.get('LSB').get('minValue', 0))
                        if not success:
                            msg = f'Index Error at Row: {row}\n' \
                                f'Please Check MSB or LSB value'
                            break
                if not success:
                    break
        except Exception as e:
            return False, f"Something went wrong when handle Row: {row}\nError message: {str(e)}"
        if run is None:
            msg = 'Fields cannot be empty.\n'
        return success, msg

    def reserved(self):
        max_value = int(self.cols.get('MSB').get('maxValue', 31))
        min_value = int(self.cols.get('LSB').get('minValue', 0))
        reserves = {}
        for row, values in self.iterRowValues():
            msb = int(values['MSB'])
            lsb = int(values['LSB'])
            if msb != max_value:
                reserves[row] = {
                    **reserve_field,
                    **dict(MSB=max_value, LSB=msb + 1)
                }
            max_value = lsb - 1
        if max_value >= 0:
            reserves[self.model.rowCount()] = {
                **reserve_field,
                **dict(MSB=max_value, LSB=min_value)
            }

        for row in sorted(reserves.keys(), reverse=True):
            self.insertRow(row, reserves[row])

    # def saveTable(self):
    #
    #     self.items.clear()
    #     for row, values in self.iterRowValues():
    #         self.items.append(values)
    #     self.tableSaved.emit()

    # def checkTableChanged(self):
    #     if len(self.items) != self.model.rowCount():
    #         return True
    #     else:
    #         for row, values in self.iterRowValues():
    #             old = self.items[row]
    #             if old != values:
    #                 return True
    #         else:
    #             return False

    def setFocus(self, r=None):
        self.table.setFocus()