Exemple #1
0
    def __init__(self, arg=None):
        super(Table, self).__init__(arg)
        # 设置窗体的标题和初始大小
        self.setWindowTitle("QTableView 表格视图控件的例子")
        self.resize(600, 300)

        # 准备数据模型,设置数据层次结构为6行5列
        self.model = QStandardItemModel(6, 5)
        # 设置数据栏名称
        self.model.setHorizontalHeaderLabels(['标题1', '标题2', '标题3', '标题4',  '标题5'])

        for row in range(6):
            for column in range(5):
                item = QStandardItem("行 %s, 列 %s" % (row, column ))
                self.model.setItem(row, column, item)

        # 实例化表格视图,设置模型为自定义的模型
        self.tableView = QTableView()
        self.tableView.setModel(self.model)

        ############ 下面代码让表格 100% 的填满窗口
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 局部布局
        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(self.tableView)
        # 全局布局
        wl = QVBoxLayout(self)
        wl.addLayout(vboxLayout)
Exemple #2
0
    def __init__(self):
        super(Exp, self).__init__()
        self.setupUi(self)
        self.__last_pos = self.pos()
        self.__trigger_menu = TriggerMenu(self, EssStandardItem())
        self.__cur_parent = EssStandardItem()

        self.setWindowFlag(Qt.FramelessWindowHint)

        self.__ess_file_model = QStandardItemModel(1, len(ITEM_PROPERTIES))
        self.__ess_file_model.setHorizontalHeaderLabels(ITEM_PROPERTIES)

        update_item_data(
            ItemSettingContext("$/", self.__ess_file_model.setItem))

        self.fileTreeView.setModel(self.__ess_file_model)
        self.fileTreeView.header().resizeSection(0, 300)
        self.fileTreeView.header().resizeSection(1, 120)

        self.resize_t = ResizeType.EITHER

        self.bt_close.clicked.connect(self.close)
        self.bt_copy.clicked.connect(self.on_copy_button_clicked)
        self.bt_copy.mouseDoubleClickEvent = self.on_copy_button_double_clicked

        self.bt_maximize.clicked.connect(self.on_bt_maximize_clicked)
        self.bt_minimize.clicked.connect(self.showMinimized)

        self.fileTreeView.doubleClicked.connect(self.on_item_double_clicked)
        self.fileTreeView.clicked.connect(self.on_item_clicked)
        self.fileTreeView.edit = self.edit
        self.fileTreeView.customContextMenuRequested.connect(
            self.on_item_triggered)

        self.lb_cpath.setText("$/")
Exemple #3
0
 def setup_key_list(self, key_list):
     self.keyListView.setEditTriggers(QAbstractItemView.NoEditTriggers)
     self.list_model = QStandardItemModel(self.keyListView)
     for key in key_list:
         item = self.make_item(key)
         self.list_model.appendRow(item)
     self.keyListView.setModel(self.list_model)
     self.keyListView.setContextMenuPolicy(Qt.CustomContextMenu)
     self.keyListView.customContextMenuRequested[QPoint].connect(
         self.context_menu)
Exemple #4
0
 def dropMimeData(self, data, action, row, column, parent):
     # If any albums were dropped into another album,
     # add all the songs in the dropped album
     # but not the album item itself
     if parent.isValid():
         dummy_model = QStandardItemModel()
         dummy_model.dropMimeData(data, action, 0, 0, QModelIndex())
         indexes = []
         for r in range(dummy_model.rowCount()):
             for c in range(dummy_model.columnCount()):
                 index = dummy_model.index(r, c)
                 # QStandardItemModel doesn't recognize our items as our custom classes
                 # so we have to treat them as QStandardItems
                 item = dummy_model.item(r, c)
                 if item.data(
                         CustomDataRole.ITEMTYPE) == TreeWidgetType.ALBUM:
                     indexes += [
                         child.index() for child in AlbumTreeWidgetItem.
                         getChildrenFromStandardItem(item)
                     ]
                 elif item.data(
                         CustomDataRole.ITEMTYPE) == TreeWidgetType.SONG:
                     indexes.append(index)
         data = dummy_model.mimeData(indexes)
     ret = super().dropMimeData(data, action, row, column, parent)
     return ret
Exemple #5
0
    def __init__(self, parent, rows, selected=None, disabled=None):
        super().__init__(parent)
        self.setWindowTitle("Select XDF Stream")

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(
            ["ID", "Name", "Type", "Channels", "Format", "Sampling Rate"])

        for index, stream in enumerate(rows):
            items = []
            for item in stream:
                tmp = QStandardItem()
                tmp.setData(item, Qt.DisplayRole)
                items.append(tmp)
            for item in items:
                item.setEditable(False)
                if disabled is not None and index in disabled:
                    item.setFlags(Qt.NoItemFlags)
            self.model.appendRow(items)

        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.verticalHeader().setVisible(False)
        self.view.horizontalHeader().setStretchLastSection(True)
        self.view.setShowGrid(False)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        if selected is not None:
            self.view.selectRow(selected)
        self.view.setSortingEnabled(True)
        self.view.sortByColumn(0, Qt.AscendingOrder)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.view)
        hbox = QHBoxLayout()
        self._effective_srate = QCheckBox("Use effective sampling rate")
        self._effective_srate.setChecked(True)
        hbox.addWidget(self._effective_srate)
        self._prefix_markers = QCheckBox("Prefix markers with stream ID")
        self._prefix_markers.setChecked(False)
        if not disabled:
            self._prefix_markers.setEnabled(False)
        hbox.addWidget(self._prefix_markers)
        vbox.addLayout(hbox)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        vbox.addWidget(self.buttonbox)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)

        self.resize(775, 650)
        self.view.setColumnWidth(0, 90)
        self.view.setColumnWidth(1, 200)
        self.view.setColumnWidth(2, 140)
Exemple #6
0
    def initModel(self):
        self.model = QStandardItemModel(0, 6, self)
        self.model.setHeaderData(0, Qt.Horizontal, "Task")
        self.ui.ganttView.setModel(self.model)

        self.l = QWidget(self)
        self.l.setWindowTitle("Legend")
        self.l.show()
        ##self.l.setModel(self.model)

        self.constraintModel = ConstraintModel(self)
        self.ui.ganttView.setConstraintModel(self.constraintModel)
def _create_model(parent, serialized_bookmarks):
    result = QStandardItemModel(0, 1, parent)
    last_folder_item = None
    for entry in serialized_bookmarks:
        if len(entry) == 1:
            last_folder_item = _create_folder_item(entry[0])
            result.appendRow(last_folder_item)
        else:
            url = QUrl.fromUserInput(entry[0])
            title = entry[1]
            icon = QIcon(entry[2]) if len(entry) > 2 and entry[2] else None
            last_folder_item.appendRow(_create_item(url, title, icon))
    return result
def createMailModel(parent):
    model = QStandardItemModel(0, 3, parent)

    model.setHeaderData(0, Qt.Horizontal, "Subject")
    model.setHeaderData(1, Qt.Horizontal, "Sender")
    model.setHeaderData(2, Qt.Horizontal, "Date")

    addMail(model, "Happy New Year!", "Grace K. <*****@*****.**>",
            QDateTime(QDate(2006, 12, 31), QTime(17, 3)))
    addMail(model, "Radically new concept", "Grace K. <*****@*****.**>",
            QDateTime(QDate(2006, 12, 22), QTime(9, 44)))
    addMail(model, "Accounts", "*****@*****.**",
            QDateTime(QDate(2006, 12, 31), QTime(12, 50)))
    addMail(model, "Expenses", "Joe Bloggs <*****@*****.**>",
            QDateTime(QDate(2006, 12, 25), QTime(11, 39)))
    addMail(model, "Re: Expenses", "Andy <*****@*****.**>",
            QDateTime(QDate(2007, 1, 2), QTime(16, 5)))
    addMail(model, "Re: Accounts", "Joe Bloggs <*****@*****.**>",
            QDateTime(QDate(2007, 1, 3), QTime(14, 18)))
    addMail(model, "Re: Accounts", "Andy <*****@*****.**>",
            QDateTime(QDate(2007, 1, 3), QTime(14, 26)))
    addMail(model, "Sports", "Linda Smith <*****@*****.**>",
            QDateTime(QDate(2007, 1, 5), QTime(11, 33)))
    addMail(model, "AW: Sports", "Rolf Newschweinstein <*****@*****.**>",
            QDateTime(QDate(2007, 1, 5), QTime(12, 0)))
    addMail(model, "RE: Sports", "Petra Schmidt <*****@*****.**>",
            QDateTime(QDate(2007, 1, 5), QTime(12, 1)))

    return model
Exemple #9
0
class ChannelPropertiesDialog(QDialog):
    def __init__(self, parent, info, title="Channel Properties"):
        super().__init__(parent)
        self.setWindowTitle(title)

        self.model = QStandardItemModel(info["nchan"], 4)
        self.model.setHorizontalHeaderLabels(["#", "Label", "Type", "Bad"])
        for index, ch in enumerate(info["chs"]):
            item = QStandardItem()
            item.setData(index, Qt.DisplayRole)
            item.setFlags(item.flags() & ~Qt.ItemIsEditable)
            self.model.setItem(index, 0, item)
            self.model.setItem(index, 1, QStandardItem(ch["ch_name"]))
            kind = channel_type(info, index).upper()
            self.model.setItem(index, 2, QStandardItem(str(kind)))
            bad = QStandardItem()
            bad.setData(ch["ch_name"] in info["bads"], Qt.UserRole)
            bad.setCheckable(True)
            bad.setEditable(False)
            checked = ch["ch_name"] in info["bads"]
            bad.setCheckState(Qt.Checked if checked else Qt.Unchecked)
            self.model.setItem(index, 3, bad)

        self.model.itemChanged.connect(bad_changed)
        self.proxymodel = MySortFilterProxyModel()
        self.proxymodel.setDynamicSortFilter(False)
        self.proxymodel.setSourceModel(self.model)

        self.view = QTableView()
        self.view.setModel(self.proxymodel)
        self.view.setItemDelegateForColumn(2, ComboBoxDelegate(self.view))
        self.view.setEditTriggers(QAbstractItemView.AllEditTriggers)
        self.view.verticalHeader().setVisible(False)
        self.view.horizontalHeader().setStretchLastSection(True)
        self.view.setShowGrid(False)
        self.view.setSelectionMode(QAbstractItemView.NoSelection)
        self.view.setSortingEnabled(True)
        self.view.sortByColumn(0, Qt.AscendingOrder)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.view)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        vbox.addWidget(self.buttonbox)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)

        self.resize(475, 650)
        self.view.setColumnWidth(0, 70)
        self.view.setColumnWidth(1, 155)
        self.view.setColumnWidth(2, 90)
Exemple #10
0
def _set_rows(
        model: QtGui.QStandardItemModel,
        columns: Sequence[Column],
        tasks: Iterable[Task]) -> None:
    root_item = model.invisibleRootItem()
    for task in tasks:
        row = _build_row(task, columns)
        root_item.appendRow(row)
    def create_combo_box_items(self):
        model = QStandardItemModel()
        self.ui.combo_classes.setModel(model)
        self.ui.combo_functions.setModel(model)
        for k, v in self.data.items():
            cls = QStandardItem(k)
            model.appendRow(cls)
            for value in v:
                func = QStandardItem(value)
                cls.appendRow(func)

        def update_combo_box(index):
            ind = model.index(index, 0, self.ui.combo_classes.rootModelIndex())
            self.ui.combo_functions.setRootModelIndex(ind)
            self.ui.combo_functions.show()
            self.ui.combo_functions.setCurrentIndex(0)
            self.ui.config_label.setText('')

        self.ui.combo_classes.currentIndexChanged.connect(update_combo_box)
Exemple #12
0
        def __init__(self, *args, **kwargs):

            super().__init__(*args, **kwargs)

            font = QFont('monospace', 8)
            font.setStyleHint(QFont.Monospace)
            self.setFont(font)
            self.setShowGrid(False)
            self.horizontalHeader().hide()
            self.verticalHeader().setSectionResizeMode(
                QtWidgets.QHeaderView.Fixed)
            self.verticalHeader().setHighlightSections(False)
            self.horizontalHeader().setHighlightSections(False)
            self.verticalHeader().setSectionsClickable(False)

            # Don't let the user edit the table cells.
            self.setEditTriggers(self.NoEditTriggers)

            self.setSelectionBehavior(QAbstractItemView.SelectItems)
            self.setSelectionMode(QAbstractItemView.ContiguousSelection)

            self.setModel(QStandardItemModel(1, 33))

            # This will store the raw data that is displayed in the hex view.
            self.hex_data = None

            # Determine how wide ASCII columns should be.
            self.ascii_width = self.fontMetrics().horizontalAdvance('m')

            # HACK: Get how much space a hex item needs by asking temporarily creating one, and then asking Qt,
            # because self.fontMetrics().width('mm') isn't enough, apparently, unlike above.
            self.model().setItem(0, 0, QStandardItem('mm'))
            self.resizeColumnToContents(0)
            self.hex_width = self.visualRect(self.model().createIndex(
                0, 0)).width()

            # Default to 16 hex columns, with 16 ASCII columns, and one separator column, for a total of 33.
            self._set_bytes_per_row(16)

            # HACK: Get how much space is needed for 16 bytes per row by
            # getting the left and right bound of the left-most and right-most items, respectively.
            start = self.visualRect(self.model().createIndex(0, 0)).left()
            end = self.visualRect(self.model().createIndex(0, 32)).right()
            self.full_width = end - start

            # Record the default background color for items, since apparently that's platform dependent.
            # Note: Normally we can only get the default background color if there's actually an item there,
            # but we made one earlier to determine the value for self.hex_width, so we don't need to do it again.
            self.default_background_color = self.model().item(0,
                                                              0).background()

            self.model().setRowCount(0)

            self.selectionModel().selectionChanged.connect(
                self._selection_changed)
Exemple #13
0
def get_item_by_index(index: EssModelIndex,
                      model: QStandardItemModel) -> EssStandardItem:
    ancestor_indexes = [index]
    while index.parent() != EssModelIndex():
        ancestor_indexes.append(index.parent())
        index = index.parent()
    ancestor_indexes.reverse()
    item = model.invisibleRootItem()
    for ancestor in ancestor_indexes:
        item = item.child(ancestor.row(), ancestor.column())
    return item
Exemple #14
0
 def createProgramsList(self):
     self.programsListModel = QStandardItemModel(0, 1, self)
     self.programsList = QListView()
     self.programsList.setModel(self.programsListModel)
     self.programsListPage = QWidget()
     self.programsListLayout = QVBoxLayout()
     self.programsListButtons = QHBoxLayout()
     self.programsListButtonNew = QPushButton("New")
     self.programsListButtonDelete = QPushButton("Delete")
     self.programsListButtonEdit = QPushButton("Edit")
     self.programsListButtonSet = QPushButton("Set")
     self.programsListButtons.addWidget(self.programsListButtonNew)
     self.programsListButtons.addWidget(self.programsListButtonSet)
     self.programsListButtons.addWidget(self.programsListButtonEdit)
     self.programsListButtons.addWidget(self.programsListButtonDelete)
     self.programsListLayout.addLayout(self.programsListButtons)
     self.programsListLayout.addWidget(self.programsList)
     self.programsListPage.setLayout(self.programsListLayout)
     self.programsListButtonNew.clicked.connect(self.newProgram)
     self.programsListButtonEdit.clicked.connect(self.editProgram)
     self.programsListButtonDelete.clicked.connect(self.deleteProgram)
     self.programsListButtonSet.clicked.connect(self.setProgram)
Exemple #15
0
    def setup_ui(self):
        super(AtlasUI, self).setup_ui()

        image_clear_btn = QPushButton(text="清空")
        image_clear_btn.clicked.connect(self.on_image_clear_btn_clicked)

        image_listview = QListView()
        image_listview.setAcceptDrops(True)
        image_list_model = QStandardItemModel(image_listview)
        image_list_model.itemChanged.connect(self.on_image_changed)
        image_listview.setModel(image_list_model)

        self.main_layout.addWidget(image_clear_btn, 0, 0, 1, 1, QtCore.Qt.AlignLeft)
        self.main_layout.addWidget(image_listview, 1, 0, 1, 1)

        self.image_clear_btn = image_clear_btn
        self.image_listview = image_listview
        self.image_list_model = image_list_model

        self.refresh_images()
Exemple #16
0
 def __init__(self, p):
     super().__init__()
     # enforce monospaced font:
     f = QFont("Monospace")
     f.setPointSize(8)
     self.setFont(f)
     self.setEditTriggers(QTreeView.NoEditTriggers)
     self.setSelectionMode(QTreeView.ExtendedSelection)
     m = QStandardItemModel()
     m.setColumnCount(3)
     m.setHorizontalHeaderLabels(["name", "value", "size"])
     r = m.invisibleRootItem()
     S = self.setup_(p)
     if S:
         r.appendRow(S)
     self.setModel(m)
     self.m = m
     self.setUniformRowHeights(True)
     self.header().setSectionResizeMode(QHeaderView.ResizeToContents)
     self.header().setFont(f)
    def create_itemview_tabwidget(self):
        result = QTabWidget()
        init_widget(result, "bottomLeftTabWidget")
        result.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Ignored)

        tree_view = QTreeView()
        init_widget(tree_view, "treeView")
        filesystem_model = QFileSystemModel(tree_view)
        filesystem_model.setRootPath(QDir.rootPath())
        tree_view.setModel(filesystem_model)

        table_widget = QTableWidget()
        init_widget(table_widget, "tableWidget")
        table_widget.setRowCount(10)
        table_widget.setColumnCount(10)

        list_model = QStandardItemModel(0, 1, result)

        list_model.appendRow(QStandardItem(QIcon(DIR_OPEN_ICON), "Directory"))
        list_model.appendRow(QStandardItem(QIcon(COMPUTER_ICON), "Computer"))

        list_view = QListView()
        init_widget(list_view, "listView")
        list_view.setModel(list_model)

        icon_mode_listview = QListView()
        init_widget(icon_mode_listview, "iconModeListView")

        icon_mode_listview.setViewMode(QListView.IconMode)
        icon_mode_listview.setModel(list_model)

        result.addTab(embed_into_hbox_layout(tree_view), "Tree View")
        result.addTab(embed_into_hbox_layout(table_widget), "Table")
        result.addTab(embed_into_hbox_layout(list_view), "List")
        result.addTab(embed_into_hbox_layout(icon_mode_listview),
                      "Icon Mode List")
        return result
Exemple #18
0
def _set_header(
        model: QtGui.QStandardItemModel,
        columns: Sequence[Column]) -> None:
    header_labels = list([column.name for column in columns])
    model.setHorizontalHeaderLabels(header_labels)
Exemple #19
0
    def __init__(self, persepolis_setting):
        super().__init__()
        # MainWindow
        self.persepolis_setting = persepolis_setting

        # add support for other languages
        locale = str(self.persepolis_setting.value('settings/locale'))
        QLocale.setDefault(QLocale(locale))
        self.translator = QTranslator()
        if self.translator.load(':/translations/locales/ui_' + locale, 'ts'):
            QCoreApplication.installTranslator(self.translator)

        # set ui direction
        ui_direction = self.persepolis_setting.value('ui_direction')

        if ui_direction == 'rtl':
            self.setLayoutDirection(Qt.RightToLeft)

        elif ui_direction in 'ltr':
            self.setLayoutDirection(Qt.LeftToRight)

        icons = ':/' + \
            str(self.persepolis_setting.value('settings/icons')) + '/'

        self.setWindowTitle(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "Persepolis Download Manager"))
        self.setWindowIcon(
            QIcon.fromTheme('persepolis', QIcon(':/persepolis.svg')))

        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)

        # enable drag and drop
        self.setAcceptDrops(True)

        # frame
        self.frame = QFrame(self.centralwidget)

        # download_table_horizontalLayout
        download_table_horizontalLayout = QHBoxLayout()
        horizontal_splitter = QSplitter(Qt.Horizontal)

        vertical_splitter = QSplitter(Qt.Vertical)

        # category_tree
        self.category_tree_qwidget = QWidget(self)
        category_tree_verticalLayout = QVBoxLayout()
        self.category_tree = CategoryTreeView(self)
        category_tree_verticalLayout.addWidget(self.category_tree)

        self.category_tree_model = QStandardItemModel()
        self.category_tree.setModel(self.category_tree_model)
        category_table_header = [
            QCoreApplication.translate("mainwindow_ui_tr", 'Category')
        ]

        self.category_tree_model.setHorizontalHeaderLabels(
            category_table_header)
        self.category_tree.header().setStretchLastSection(True)

        self.category_tree.header().setDefaultAlignment(Qt.AlignCenter)

        # queue_panel
        self.queue_panel_widget = QWidget(self)

        queue_panel_verticalLayout_main = QVBoxLayout(self.queue_panel_widget)

        # queue_panel_show_button
        self.queue_panel_show_button = QPushButton(self)

        queue_panel_verticalLayout_main.addWidget(self.queue_panel_show_button)

        # queue_panel_widget_frame
        self.queue_panel_widget_frame = QFrame(self)
        self.queue_panel_widget_frame.setFrameShape(QFrame.StyledPanel)
        self.queue_panel_widget_frame.setFrameShadow(QFrame.Raised)

        queue_panel_verticalLayout_main.addWidget(
            self.queue_panel_widget_frame)

        queue_panel_verticalLayout = QVBoxLayout(self.queue_panel_widget_frame)
        queue_panel_verticalLayout_main.setContentsMargins(50, -1, 50, -1)

        # start_end_frame
        self.start_end_frame = QFrame(self)

        # start time
        start_verticalLayout = QVBoxLayout(self.start_end_frame)
        self.start_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.start_checkBox)

        self.start_frame = QFrame(self)
        self.start_frame.setFrameShape(QFrame.StyledPanel)
        self.start_frame.setFrameShadow(QFrame.Raised)

        start_frame_verticalLayout = QVBoxLayout(self.start_frame)

        self.start_time_qDataTimeEdit = MyQDateTimeEdit(self.start_frame)
        self.start_time_qDataTimeEdit.setDisplayFormat('H:mm')
        start_frame_verticalLayout.addWidget(self.start_time_qDataTimeEdit)

        start_verticalLayout.addWidget(self.start_frame)

        # end time
        self.end_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.end_checkBox)

        self.end_frame = QFrame(self)
        self.end_frame.setFrameShape(QFrame.StyledPanel)
        self.end_frame.setFrameShadow(QFrame.Raised)

        end_frame_verticalLayout = QVBoxLayout(self.end_frame)

        self.end_time_qDateTimeEdit = MyQDateTimeEdit(self.end_frame)
        self.end_time_qDateTimeEdit.setDisplayFormat('H:mm')
        end_frame_verticalLayout.addWidget(self.end_time_qDateTimeEdit)

        start_verticalLayout.addWidget(self.end_frame)

        self.reverse_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.reverse_checkBox)

        queue_panel_verticalLayout.addWidget(self.start_end_frame)

        # limit_after_frame
        self.limit_after_frame = QFrame(self)

        # limit_checkBox
        limit_verticalLayout = QVBoxLayout(self.limit_after_frame)
        self.limit_checkBox = QCheckBox(self)
        limit_verticalLayout.addWidget(self.limit_checkBox)

        # limit_frame
        self.limit_frame = QFrame(self)
        self.limit_frame.setFrameShape(QFrame.StyledPanel)
        self.limit_frame.setFrameShadow(QFrame.Raised)
        limit_verticalLayout.addWidget(self.limit_frame)

        limit_frame_verticalLayout = QVBoxLayout(self.limit_frame)

        # limit_spinBox
        limit_frame_horizontalLayout = QHBoxLayout()
        self.limit_spinBox = QDoubleSpinBox(self)
        self.limit_spinBox.setMinimum(1)
        self.limit_spinBox.setMaximum(1023)
        limit_frame_horizontalLayout.addWidget(self.limit_spinBox)

        # limit_comboBox
        self.limit_comboBox = QComboBox(self)
        self.limit_comboBox.addItem("")
        self.limit_comboBox.addItem("")
        limit_frame_horizontalLayout.addWidget(self.limit_comboBox)
        limit_frame_verticalLayout.addLayout(limit_frame_horizontalLayout)

        # limit_pushButton
        self.limit_pushButton = QPushButton(self)
        limit_frame_verticalLayout.addWidget(self.limit_pushButton)

        # after_checkBox
        self.after_checkBox = QCheckBox(self)
        limit_verticalLayout.addWidget(self.after_checkBox)

        # after_frame
        self.after_frame = QFrame(self)
        self.after_frame.setFrameShape(QFrame.StyledPanel)
        self.after_frame.setFrameShadow(QFrame.Raised)
        limit_verticalLayout.addWidget(self.after_frame)

        after_frame_verticalLayout = QVBoxLayout(self.after_frame)

        # after_comboBox
        self.after_comboBox = QComboBox(self)
        self.after_comboBox.addItem("")

        after_frame_verticalLayout.addWidget(self.after_comboBox)

        # after_pushButton
        self.after_pushButton = QPushButton(self)
        after_frame_verticalLayout.addWidget(self.after_pushButton)

        queue_panel_verticalLayout.addWidget(self.limit_after_frame)
        category_tree_verticalLayout.addWidget(self.queue_panel_widget)

        # keep_awake_checkBox
        self.keep_awake_checkBox = QCheckBox(self)
        queue_panel_verticalLayout.addWidget(self.keep_awake_checkBox)

        self.category_tree_qwidget.setLayout(category_tree_verticalLayout)
        horizontal_splitter.addWidget(self.category_tree_qwidget)

        # download table widget
        self.download_table_content_widget = QWidget(self)
        download_table_content_widget_verticalLayout = QVBoxLayout(
            self.download_table_content_widget)

        # download_table
        self.download_table = DownloadTableWidget(self)
        vertical_splitter.addWidget(self.download_table)

        horizontal_splitter.addWidget(self.download_table_content_widget)

        self.download_table.setColumnCount(13)
        self.download_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.download_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.download_table.verticalHeader().hide()

        # hide column of GID and column of link.
        self.download_table.setColumnHidden(8, True)
        self.download_table.setColumnHidden(9, True)

        download_table_header = [
            QCoreApplication.translate("mainwindow_ui_tr", 'File Name'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Status'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Size'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Downloaded'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Percentage'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Connections'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Transfer Rate'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Estimated Time Left'), 'Gid',
            QCoreApplication.translate("mainwindow_ui_tr", 'Link'),
            QCoreApplication.translate("mainwindow_ui_tr", 'First Try Date'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Last Try Date'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Category')
        ]

        self.download_table.setHorizontalHeaderLabels(download_table_header)

        # fixing the size of download_table when window is Maximized!
        self.download_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Interactive)
        self.download_table.horizontalHeader().setStretchLastSection(True)

        horizontal_splitter.setStretchFactor(0, 3)  # category_tree width
        horizontal_splitter.setStretchFactor(1, 10)  # ratio of tables's width

        # video_finder_widget
        self.video_finder_widget = QWidget(self)
        video_finder_horizontalLayout = QHBoxLayout(self.video_finder_widget)

        self.muxing_pushButton = QPushButton(self)
        self.muxing_pushButton.setIcon(QIcon(icons + 'video_finder'))
        video_finder_horizontalLayout.addWidget(self.muxing_pushButton)
        video_finder_horizontalLayout.addSpacing(20)

        video_audio_verticalLayout = QVBoxLayout()

        self.video_label = QLabel(self)
        video_audio_verticalLayout.addWidget(self.video_label)

        self.audio_label = QLabel(self)
        video_audio_verticalLayout.addWidget(self.audio_label)
        video_finder_horizontalLayout.addLayout(video_audio_verticalLayout)

        status_muxing_verticalLayout = QVBoxLayout()

        self.video_finder_status_label = QLabel(self)
        status_muxing_verticalLayout.addWidget(self.video_finder_status_label)

        self.muxing_status_label = QLabel(self)
        status_muxing_verticalLayout.addWidget(self.muxing_status_label)
        video_finder_horizontalLayout.addLayout(status_muxing_verticalLayout)

        vertical_splitter.addWidget(self.video_finder_widget)

        download_table_content_widget_verticalLayout.addWidget(
            vertical_splitter)

        download_table_horizontalLayout.addWidget(horizontal_splitter)

        self.frame.setLayout(download_table_horizontalLayout)

        self.verticalLayout.addWidget(self.frame)

        self.setCentralWidget(self.centralwidget)

        # menubar
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 600, 24))
        self.setMenuBar(self.menubar)
        fileMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&File'))
        editMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&Edit'))
        viewMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&View'))
        downloadMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&Download'))
        queueMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&Queue'))
        videoFinderMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", 'V&ideo Finder'))
        helpMenu = self.menubar.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", '&Help'))

        # viewMenu submenus
        sortMenu = viewMenu.addMenu(
            QCoreApplication.translate("mainwindow_ui_tr", 'Sort by'))

        # statusbar
        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.statusbar.showMessage(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "Persepolis Download Manager"))

        # toolBar
        self.toolBar2 = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.toolBar2)
        self.toolBar2.setWindowTitle(
            QCoreApplication.translate("mainwindow_ui_tr", 'Menu'))
        self.toolBar2.setFloatable(False)
        self.toolBar2.setMovable(False)

        self.toolBar = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.toolBar)
        self.toolBar.setWindowTitle(
            QCoreApplication.translate("mainwindow_ui_tr", 'Toolbar'))
        self.toolBar.setFloatable(False)
        self.toolBar.setMovable(False)

        #toolBar and menubar and actions
        self.persepolis_setting.beginGroup('settings/shortcuts')

        # videoFinderAddLinkAction
        self.videoFinderAddLinkAction = QAction(
            QIcon(icons + 'video_finder'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Find Video Links...'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Download video or audio from Youtube, Vimeo, etc.'),
            triggered=self.showVideoFinderAddLinkWindow)

        self.videoFinderAddLinkAction_shortcut = QShortcut(
            self.persepolis_setting.value('video_finder_shortcut'), self,
            self.showVideoFinderAddLinkWindow)

        videoFinderMenu.addAction(self.videoFinderAddLinkAction)

        # stopAllAction
        self.stopAllAction = QAction(QIcon(icons + 'stop_all'),
                                     QCoreApplication.translate(
                                         "mainwindow_ui_tr",
                                         'Stop All Active Downloads'),
                                     self,
                                     statusTip='Stop All Active Downloads',
                                     triggered=self.stopAllDownloads)
        downloadMenu.addAction(self.stopAllAction)

        # sort_file_name_Action
        self.sort_file_name_Action = QAction(QCoreApplication.translate(
            "mainwindow_ui_tr", 'File Name'),
                                             self,
                                             triggered=self.sortByName)
        sortMenu.addAction(self.sort_file_name_Action)

        # sort_file_size_Action
        self.sort_file_size_Action = QAction(QCoreApplication.translate(
            "mainwindow_ui_tr", 'File Size'),
                                             self,
                                             triggered=self.sortBySize)
        sortMenu.addAction(self.sort_file_size_Action)

        # sort_first_try_date_Action
        self.sort_first_try_date_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'First Try Date'),
            self,
            triggered=self.sortByFirstTry)
        sortMenu.addAction(self.sort_first_try_date_Action)

        # sort_last_try_date_Action
        self.sort_last_try_date_Action = QAction(QCoreApplication.translate(
            "mainwindow_ui_tr", 'Last Try Date'),
                                                 self,
                                                 triggered=self.sortByLastTry)
        sortMenu.addAction(self.sort_last_try_date_Action)

        # sort_download_status_Action
        self.sort_download_status_Action = QAction(QCoreApplication.translate(
            "mainwindow_ui_tr", 'Download Status'),
                                                   self,
                                                   triggered=self.sortByStatus)
        sortMenu.addAction(self.sort_download_status_Action)

        # trayAction
        self.trayAction = QAction(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Show System Tray Icon'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Show/Hide system tray icon"),
            triggered=self.showTray)
        self.trayAction.setCheckable(True)
        viewMenu.addAction(self.trayAction)

        # showMenuBarAction
        self.showMenuBarAction = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Show Menubar'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Show Menubar'),
            triggered=self.showMenuBar)
        self.showMenuBarAction.setCheckable(True)
        viewMenu.addAction(self.showMenuBarAction)

        # showSidePanelAction
        self.showSidePanelAction = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Show Side Panel'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Show Side Panel'),
            triggered=self.showSidePanel)
        self.showSidePanelAction.setCheckable(True)
        viewMenu.addAction(self.showSidePanelAction)

        # minimizeAction
        self.minimizeAction = QAction(
            QIcon(icons + 'minimize'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Minimize to System Tray'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Minimize to System Tray"),
            triggered=self.minMaxTray)

        self.minimizeAction_shortcut = QShortcut(
            self.persepolis_setting.value('hide_window_shortcut'), self,
            self.minMaxTray)
        viewMenu.addAction(self.minimizeAction)

        # addlinkAction
        self.addlinkAction = QAction(
            QIcon(icons + 'add'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Add New Download Link...'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Add New Download Link"),
            triggered=self.addLinkButtonPressed)

        self.addlinkAction_shortcut = QShortcut(
            self.persepolis_setting.value('add_new_download_shortcut'), self,
            self.addLinkButtonPressed)
        fileMenu.addAction(self.addlinkAction)

        # importText
        self.addtextfileAction = QAction(
            QIcon(icons + 'file'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Import Links from Text File...'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Create a text file and put links in it, line by line!'),
            triggered=self.importText)

        self.addtextfileAction_shortcut = QShortcut(
            self.persepolis_setting.value('import_text_shortcut'), self,
            self.importText)

        fileMenu.addAction(self.addtextfileAction)

        # resumeAction
        self.resumeAction = QAction(
            QIcon(icons + 'play'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Resume Download'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Resume Download"),
            triggered=self.resumeButtonPressed)

        downloadMenu.addAction(self.resumeAction)

        # pauseAction
        self.pauseAction = QAction(
            QIcon(icons + 'pause'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Pause Download'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Pause Download"),
            triggered=self.pauseButtonPressed)

        downloadMenu.addAction(self.pauseAction)

        # stopAction
        self.stopAction = QAction(
            QIcon(icons + 'stop'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Stop Download'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Stop/Cancel Download"),
            triggered=self.stopButtonPressed)

        downloadMenu.addAction(self.stopAction)

        # propertiesAction
        self.propertiesAction = QAction(
            QIcon(icons + 'setting'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Properties'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Properties"),
            triggered=self.propertiesButtonPressed)

        downloadMenu.addAction(self.propertiesAction)

        # progressAction
        self.progressAction = QAction(
            QIcon(icons + 'window'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Progress'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 "Progress"),
            triggered=self.progressButtonPressed)

        downloadMenu.addAction(self.progressAction)

        # openFileAction
        self.openFileAction = QAction(
            QIcon(icons + 'file'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Open File...'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Open File...'),
            triggered=self.openFile)
        fileMenu.addAction(self.openFileAction)

        # openDownloadFolderAction
        self.openDownloadFolderAction = QAction(
            QIcon(icons + 'folder'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Open Download Folder'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Open Download Folder'),
            triggered=self.openDownloadFolder)

        fileMenu.addAction(self.openDownloadFolderAction)

        # openDefaultDownloadFolderAction
        self.openDefaultDownloadFolderAction = QAction(
            QIcon(icons + 'folder'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Open Default Download Folder'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr", 'Open Default Download Folder'),
            triggered=self.openDefaultDownloadFolder)

        fileMenu.addAction(self.openDefaultDownloadFolderAction)

        # exitAction
        self.exitAction = QAction(
            QIcon(icons + 'exit'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Exit'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Exit"),
            triggered=self.closeAction)

        self.exitAction_shortcut = QShortcut(
            self.persepolis_setting.value('quit_shortcut'), self,
            self.closeAction)

        fileMenu.addAction(self.exitAction)

        # clearAction
        self.clearAction = QAction(QIcon(icons + 'multi_remove'),
                                   QCoreApplication.translate(
                                       "mainwindow_ui_tr",
                                       'Clear Download List'),
                                   self,
                                   statusTip=QCoreApplication.translate(
                                       "mainwindow_ui_tr",
                                       'Clear all items in download list'),
                                   triggered=self.clearDownloadList)
        editMenu.addAction(self.clearAction)

        # removeSelectedAction
        self.removeSelectedAction = QAction(
            QIcon(icons + 'remove'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Remove Selected Downloads from List'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr", 'Remove Selected Downloads from List'),
            triggered=self.removeSelected)

        self.removeSelectedAction_shortcut = QShortcut(
            self.persepolis_setting.value('remove_shortcut'), self,
            self.removeSelected)

        editMenu.addAction(self.removeSelectedAction)
        self.removeSelectedAction.setEnabled(False)

        # deleteSelectedAction
        self.deleteSelectedAction = QAction(
            QIcon(icons + 'trash'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Delete Selected Download Files'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr", 'Delete Selected Download Files'),
            triggered=self.deleteSelected)

        self.deleteSelectedAction_shortcut = QShortcut(
            self.persepolis_setting.value('delete_shortcut'), self,
            self.deleteSelected)

        editMenu.addAction(self.deleteSelectedAction)
        self.deleteSelectedAction.setEnabled(False)

        # moveSelectedDownloadsAction
        self.moveSelectedDownloadsAction = QAction(
            QIcon(icons + 'folder'),
            QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Move Selected Download Files to Another Folder...'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Move Selected Download Files to Another Folder'),
            triggered=self.moveSelectedDownloads)

        editMenu.addAction(self.moveSelectedDownloadsAction)
        self.moveSelectedDownloadsAction.setEnabled(False)

        # createQueueAction
        self.createQueueAction = QAction(
            QIcon(icons + 'add_queue'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Create New Queue...'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Create new download queue'),
            triggered=self.createQueue)
        queueMenu.addAction(self.createQueueAction)

        # removeQueueAction
        self.removeQueueAction = QAction(
            QIcon(icons + 'remove_queue'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Remove Queue'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Remove this queue'),
            triggered=self.removeQueue)
        queueMenu.addAction(self.removeQueueAction)

        # startQueueAction
        self.startQueueAction = QAction(
            QIcon(icons + 'start_queue'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Start this queue'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Start Queue'),
            triggered=self.startQueue)

        queueMenu.addAction(self.startQueueAction)

        # stopQueueAction
        self.stopQueueAction = QAction(
            QIcon(icons + 'stop_queue'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Stop this queue'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Stop Queue'),
            triggered=self.stopQueue)

        queueMenu.addAction(self.stopQueueAction)

        # moveUpSelectedAction
        self.moveUpSelectedAction = QAction(
            QIcon(icons + 'multi_up'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Move Selected Items Up'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Move currently selected items up by one row'),
            triggered=self.moveUpSelected)

        self.moveUpSelectedAction_shortcut = QShortcut(
            self.persepolis_setting.value('move_up_selection_shortcut'), self,
            self.moveUpSelected)

        queueMenu.addAction(self.moveUpSelectedAction)

        # moveDownSelectedAction
        self.moveDownSelectedAction = QAction(
            QIcon(icons + 'multi_down'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Move Selected Items Down'),
            self,
            statusTip=QCoreApplication.translate(
                "mainwindow_ui_tr",
                'Move currently selected items down by one row'),
            triggered=self.moveDownSelected)
        self.moveDownSelectedAction_shortcut = QShortcut(
            self.persepolis_setting.value('move_down_selection_shortcut'),
            self, self.moveDownSelected)

        queueMenu.addAction(self.moveDownSelectedAction)

        # preferencesAction
        self.preferencesAction = QAction(
            QIcon(icons + 'preferences'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Preferences'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Preferences'),
            triggered=self.openPreferences,
            menuRole=QAction.MenuRole.PreferencesRole)
        editMenu.addAction(self.preferencesAction)

        # aboutAction
        self.aboutAction = QAction(
            QIcon(icons + 'about'),
            QCoreApplication.translate("mainwindow_ui_tr", 'About'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'About'),
            triggered=self.openAbout,
            menuRole=QAction.MenuRole.AboutRole)
        helpMenu.addAction(self.aboutAction)

        # issueAction
        self.issueAction = QAction(
            QIcon(icons + 'about'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Report an Issue'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Report an issue'),
            triggered=self.reportIssue)
        helpMenu.addAction(self.issueAction)

        # updateAction
        self.updateAction = QAction(
            QIcon(icons + 'about'),
            QCoreApplication.translate("mainwindow_ui_tr",
                                       'Check for Newer Version'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr",
                                                 'Check for newer release'),
            triggered=self.newUpdate)
        helpMenu.addAction(self.updateAction)

        # logAction
        self.logAction = QAction(
            QIcon(icons + 'about'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Show Log File'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'),
            triggered=self.showLog)
        helpMenu.addAction(self.logAction)

        # helpAction
        self.helpAction = QAction(
            QIcon(icons + 'about'),
            QCoreApplication.translate("mainwindow_ui_tr", 'Help'),
            self,
            statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'),
            triggered=self.persepolisHelp)
        helpMenu.addAction(self.helpAction)

        self.persepolis_setting.endGroup()

        self.qmenu = MenuWidget(self)

        self.toolBar2.addWidget(self.qmenu)

        # labels
        self.queue_panel_show_button.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Hide Options"))
        self.start_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Start Time"))

        self.end_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "End Time"))

        self.reverse_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "Download bottom of\n the list first"))

        self.limit_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Limit Speed"))
        self.limit_comboBox.setItemText(0, "KiB/s")
        self.limit_comboBox.setItemText(1, "MiB/s")
        self.limit_pushButton.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Apply"))

        self.after_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "After download"))
        self.after_comboBox.setItemText(
            0, QCoreApplication.translate("mainwindow_ui_tr", "Shut Down"))

        self.keep_awake_checkBox.setText(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "Keep System Awake!"))
        self.keep_awake_checkBox.setToolTip(
            QCoreApplication.translate(
                "mainwindow_ui_tr",
                "<html><head/><body><p>This option will prevent the system from going to sleep.\
            It is necessary if your power manager is suspending the system automatically. </p></body></html>"
            ))

        self.after_pushButton.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Apply"))

        self.muxing_pushButton.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "Start Mixing"))

        self.video_label.setText(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "<b>Video File Status: </b>"))
        self.audio_label.setText(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "<b>Audio File Status: </b>"))

        self.video_finder_status_label.setText(
            QCoreApplication.translate("mainwindow_ui_tr", "<b>Status: </b>"))
        self.muxing_status_label.setText(
            QCoreApplication.translate("mainwindow_ui_tr",
                                       "<b>Mixing status: </b>"))
Exemple #20
0
 def __init__(self, view):
     QStandardItemModel.__init__(self, view)
Exemple #21
0
    def __init__(self, arg=None):
        super(Table, self).__init__(arg)
        # 设置窗体的标题和初始大小
        self.setWindowTitle("QTableView表格视图控件的例子")
        self.resize(500, 300)

        # 准备数据模型,设置数据层次结构为5行4列
        self.model = QStandardItemModel(5, 4)
        # 设置数据栏名称
        self.model.setHorizontalHeaderLabels(['标题1', '标题2', '标题3', '标题4'])

        for row in range(5):
            for column in range(4):
                item = QStandardItem("row %s, column %s" % (row, column))
                self.model.setItem(row, column, item)

        # 实例化表格视图,设置模型为自定义的模型
        self.tableView = QTableView()
        self.tableView.setModel(self.model)

        # 下面代码让表格 100% 的填满窗口
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 下面代码让表格禁止编辑
        self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # 下面代码让表格设置选中背景色
        self.tableView.setStyleSheet("selection-background-color:lightblue;")

        # 下面代码要限定只能选择整行
        # self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置只能选中整行
        # self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)  # 设置只能选中一行

        # 下面代码可以选中表格的多行
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置只能选中整行
        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)  # 设置只能选中多行

        # 下面代码可以打印表格的1行2列数据
        data = self.tableView.model().index(1, 2).data()
        print(data)

        # 下面代码去掉左边表格的行号
        # headerView  = self.tableView.verticalHeader()
        # headerView.setHidden(True)

        # 局部布局
        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(self.tableView)
        self.add_btn = QPushButton("添加记录")
        # 连接信号槽,点击按钮 add_btn 绑定槽事件
        self.add_btn.clicked.connect(self.add_records_btn_click)

        self.del_btn = QPushButton("删除多行记录")
        # 连接信号槽,点击按钮 del_btn 绑定槽事件
        self.del_btn.clicked.connect(self.del_records_btn_click)
        # 局部布局
        hboxLayout = QHBoxLayout()
        hboxLayout.addWidget(self.add_btn)
        hboxLayout.addWidget(self.del_btn)

        # 全局布局
        wl = QVBoxLayout(self)
        wl.addLayout(vboxLayout)
        wl.addLayout(hboxLayout)
Exemple #22
0
class Table(QWidget):

    def __init__(self, arg=None):
        super(Table, self).__init__(arg)
        # 设置窗体的标题和初始大小
        self.setWindowTitle("QTableView表格视图控件的例子")
        self.resize(500, 300)

        # 准备数据模型,设置数据层次结构为5行4列
        self.model = QStandardItemModel(5, 4)
        # 设置数据栏名称
        self.model.setHorizontalHeaderLabels(['标题1', '标题2', '标题3', '标题4'])

        for row in range(5):
            for column in range(4):
                item = QStandardItem("row %s, column %s" % (row, column))
                self.model.setItem(row, column, item)

        # 实例化表格视图,设置模型为自定义的模型
        self.tableView = QTableView()
        self.tableView.setModel(self.model)

        # 下面代码让表格 100% 的填满窗口
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 下面代码让表格禁止编辑
        self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # 下面代码让表格设置选中背景色
        self.tableView.setStyleSheet("selection-background-color:lightblue;")

        # 下面代码要限定只能选择整行
        # self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置只能选中整行
        # self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)  # 设置只能选中一行

        # 下面代码可以选中表格的多行
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置只能选中整行
        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)  # 设置只能选中多行

        # 下面代码可以打印表格的1行2列数据
        data = self.tableView.model().index(1, 2).data()
        print(data)

        # 下面代码去掉左边表格的行号
        # headerView  = self.tableView.verticalHeader()
        # headerView.setHidden(True)

        # 局部布局
        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(self.tableView)
        self.add_btn = QPushButton("添加记录")
        # 连接信号槽,点击按钮 add_btn 绑定槽事件
        self.add_btn.clicked.connect(self.add_records_btn_click)

        self.del_btn = QPushButton("删除多行记录")
        # 连接信号槽,点击按钮 del_btn 绑定槽事件
        self.del_btn.clicked.connect(self.del_records_btn_click)
        # 局部布局
        hboxLayout = QHBoxLayout()
        hboxLayout.addWidget(self.add_btn)
        hboxLayout.addWidget(self.del_btn)

        # 全局布局
        wl = QVBoxLayout(self)
        wl.addLayout(vboxLayout)
        wl.addLayout(hboxLayout)

    # 点击删除按钮响应方法, 删除选中的单行数据
    def del_record_btn_click(self):
        # 第一种方法: 删除单行数据
        indices = self.tableView.selectionModel().selectedRows()
        for index in sorted(indices):
            self.model.removeRow(index.row())

        # 第二种方法: 删除单行数据
        # index = self.tableView.currentIndex()  # 取得当前选中行的index
        # if -1 == index.row():
        #     return
        # self.model.removeRow(index.row())  # 通过index的row()操作得到行数进行删除

    # 点击删除按钮响应方法, 删除选中的多行数据
    def del_records_btn_click(self):
        # 第一种方法:删除多行数据
        index_list = []
        for model_index in self.tableView.selectionModel().selectedRows():
            index = QtCore.QPersistentModelIndex(model_index)
            index_list.append(index)

        if index_list:
            for index in index_list:
                self.model.removeRow(index.row())
        else:
            MessageBox = QMessageBox()
            MessageBox.information(self.tableView, "标题", "没有选中表格中要删除的行")

        # 第二种方法:删除多行数据
        # indexs = self.tableView.selectionModel().selectedRows()
        # temp_list = []  # 创建一个空队列用于存放需要删除的行号
        # for index in indexs:
        #     temp_list.append(index.row())  # 队列中保存需要删除的行号
        # temp_list.sort(key=int, reverse=True)  # 用sort方法将队列进行降序排列
        # print(temp_list)
        #
        # if temp_list:
        #     for i in temp_list:  # 按照队列删除对应的行
        #         self.model.removeRow(i)
        # else:
        #     MessageBox = QMessageBox()
        #     MessageBox.information(self.tableView, "标题", "没有选中表格中要删除的行")

    # 点击添加按钮相应方法,添加数据
    def add_records_btn_click(self):
        self.model.appendRow([
            QStandardItem("row %s, column %s" % (5, 0)),
            QStandardItem("row %s, column %s" % (6, 1)),
            QStandardItem("row %s, column %s" % (7, 2)),
            QStandardItem("row %s, column %s" % (8, 3)),
        ])
Exemple #23
0
## so we can fit more lines into it on the graphicsview
## side.
class MyHeaderView(QHeaderView):
    def __init__(self, parent=None):
        super(MyHeaderView, self).__init__(Qt.Horizontal, parent)

    def sizeHint(self):
        s = super(MyHeaderView, self).sizeHint()
        s.setHeight(s.height() * 3)
        return s


if __name__ == '__main__':
    app = QApplication(sys.argv)

    model = QStandardItemModel(1, 1)
    model.setHeaderData(0, Qt.Horizontal, "Task")

    ## A view with some alternative header labels
    view1 = View()
    grid1 = DateTimeGrid()
    #grid1.setUserDefinedUpperScale(DateTimeScaleFormatter(DateTimeScaleFormatter.Year, "yyyy", "In the year %1.", Qt.AlignLeft))
    #grid1.setUserDefinedLowerScale(DateTimeScaleFormatter(DateTimeScaleFormatter.Month, "MMMM", "In the month %1.", Qt.AlignRight))
    grid1.setScale(DateTimeGrid.ScaleUserDefined)
    grid1.setDayWidth(6.0)
    view1.setGrid(grid1)
    view1.setModel(model)
    view1.show()

    ## A view with header and vertical grid lines for every 10 minutes
    view2 = View()
Exemple #24
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None, flags=Qt.WindowFlags()):
        super(MainWindow, self).__init__(parent, flags)

        self.dayWidth = 70
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.initModel()
        self.initActions()
        self.initItemDelegate()
        self.initGrid()

        leftView = self.ui.ganttView.leftView()
        leftView.setColumnHidden(1, True)
        leftView.setColumnHidden(2, True)
        leftView.setColumnHidden(3, True)
        leftView.setColumnHidden(4, True)
        leftView.setColumnHidden(5, True)
        leftView.header().setStretchLastSection(True)

        self.ui.ganttView.leftView().customContextMenuRequested.connect(
            self.showContextMenu)
        self.ui.ganttView.selectionModel().selectionChanged.connect(
            self.enableActions)
        self.ui.ganttView.graphicsView().clicked.connect(self.slotClicked)
        self.ui.ganttView.graphicsView().qrealClicked.connect(
            self.slotDoubleClicked)

    def initModel(self):
        self.model = QStandardItemModel(0, 6, self)
        self.model.setHeaderData(0, Qt.Horizontal, "Task")
        self.ui.ganttView.setModel(self.model)

        self.l = QWidget(self)
        self.l.setWindowTitle("Legend")
        self.l.show()
        ##self.l.setModel(self.model)

        self.constraintModel = ConstraintModel(self)
        self.ui.ganttView.setConstraintModel(self.constraintModel)

    def initActions(self):
        self.newEntryAction = QAction("New entry", self)
        self.newEntryAction.setShortcut(QKeySequence.New)
        self.newEntryAction.triggered.connect(self.addNewEntry)

        self.removeEntryAction = QAction("Remove entry", self)
        self.removeEntryAction.setShortcut(QKeySequence.Delete)
        self.removeEntryAction.triggered.connect(self.removeEntry)

        self.demoAction = QAction("Demo entry", self)
        self.demoAction.triggered.connect(self.addDemoEntry)

        self.printAction = QAction("Print Preview...", self)
        self.printAction.triggered.connect(self.printPreview)

        self.zoomInAction = QAction("Zoom In", self)
        self.zoomInAction.setShortcut(QKeySequence.ZoomIn)
        self.zoomInAction.triggered.connect(self.zoomIn)

        self.zoomOutAction = QAction("Zoom Out", self)
        self.zoomOutAction.setShortcut(QKeySequence.ZoomOut)
        self.zoomOutAction.triggered.connect(self.zoomOut)

        self.ui.ganttView.leftView().setContextMenuPolicy(Qt.CustomContextMenu)
        self.ui.ganttView.leftView().addAction(self.newEntryAction)
        self.ui.ganttView.leftView().addAction(self.removeEntryAction)

        menuBar = QMenuBar(self)
        self.setMenuBar(menuBar)
        entryMenu = menuBar.addMenu("Entry")
        entryMenu.addAction(self.newEntryAction)
        entryMenu.addAction(self.removeEntryAction)
        entryMenu.addSeparator()
        entryMenu.addAction(self.demoAction)
        entryMenu.addSeparator()
        entryMenu.addAction(self.printAction)

        zoomMenu = menuBar.addMenu("Zoom")
        zoomMenu.addAction(self.zoomInAction)
        zoomMenu.addAction(self.zoomOutAction)

        ##self.enableActions(QItemSelection())

    def initItemDelegate(self):
        delegate = EntryDelegate(self.constraintModel, self)
        self.ui.ganttView.leftView().setItemDelegate(delegate)

    def initGrid(self):
        self.grid = DateTimeGrid()
        self.grid.setDayWidth(self.dayWidth)
        self.ui.ganttView.setGrid(self.grid)

    def showContextMenu(self, pos):
        if not self.ui.ganttView.leftView().indexAt(pos).isValid():
            self.ui.ganttView.selectionModel().clearSelection()

        menu = QMenu(self.ui.ganttView.leftView())
        menu.addAction(self.newEntryAction)
        menu.addAction(self.removeEntryAction)
        menu.exec_(self.ui.ganttView.leftView().viewport().mapToGlobal(pos))

    def enableActions(self, selected):
        if len(selected.indexes()) == 0:
            self.newEntryAction.setEnabled(True)
            self.removeEntryAction.setEnabled(False)
            return

        selectedIndex = selected.indexes()[0]
        dataType = self.model.data(self.model.index(selectedIndex.row(), 1))
        if dataType in [KDGantt.TypeEvent, KDGantt.TypeTask]:
            self.newEntryAction.setEnabled(False)
            self.removeEntryAction.setEnabled(True)
            return

        self.newEntryAction.setEnabled(True)
        self.removeEntryAction.setEnabled(True)

    def addNewEntry(self):
        dialog = EntryDialog(self.model)
        dialog.setWindowTitle("New Entry")
        if dialog.exec_() == QDialog.Rejected:
            dialog = None
            return

        selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes()
        if len(selectedIndexes) > 0:
            parent = selectedIndexes[0]
        else:
            parent = QModelIndex()

        if not self.model.insertRow(self.model.rowCount(parent), parent):
            return

        row = self.model.rowCount(parent) - 1
        if row == 0 and parent.isValid():
            self.model.insertColumns(self.model.columnCount(paren), 5, parent)

        self.model.setData(self.model.index(row, 0, parent), dialog.name())
        self.model.setData(self.model.index(row, 1, parent), dialog.type())
        if dialog.type() != KDGantt.TypeSummary:
            self.model.setData(self.model.index(row, 2, parent),
                               dialog.startDate(), KDGantt.StartTimeRole)
            self.model.setData(self.model.index(row, 3, parent),
                               dialog.endDate(), KDGantt.EndTimeRole)

        self.model.setData(self.model.index(row, 4, parent),
                           dialog.completion())
        self.model.setData(self.model.index(row, 5, parent), dialog.legend())

        self.addConstraint(dialog.depends(), self.model.index(row, 0, parent))
        self.setReadOnly(self.model.index(row, 0, parent), dialog.readOnly())

        dialog = None

    def setReadOnly(self, index, readOnly):
        row = index.row()
        parent = index.parent()

        for column in range(0, 5):
            item = self.model.itemFromIndex(
                self.model.index(row, column, parent))
            flags = None
            if readOnly:
                flags = item.flags() & ~Qt.ItemIsEditable
            else:
                flags = item.flags() | Qt.ItemIsEditable
            item.setFlags(flags)

    def addConstraint(self, index1, index2):
        if not index1.isValid() or not index2.isValid():
            return

        c = Constraint(index1, index2)
        self.ui.ganttView.constraintModel().addConstraint(c)

    def addConstraintFromItem(self, item1, item2):
        self.addConstraint(self.model.indexFromItem(item1),
                           self.model.indexFromItem(item2))

    def removeEntry(self):
        selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes()
        if len(selectedIndexes) > 0:
            index = selectedIndexes[0]
        else:
            index = QModelIndex()

        if not index.isValid():
            return

        self.model.removeRow(index.row(), index.parent())

    def addDemoEntry(self):
        softwareRelease = MyStandardItem("Software Release")
        codeFreeze = MyStandardItem("Code Freeze")
        codeFreeze.setData(KDGantt.TextPositionRole,
                           StyleOptionGanttItem.Right)
        packaging = MyStandardItem("Packaging")
        upload = MyStandardItem("Upload")
        testing = MyStandardItem("Testing")
        updateDocumentation = MyStandardItem("Update Documentation")

        now = QDateTime.currentDateTime()
        softwareRelease.appendRow([
            codeFreeze,
            MyStandardItem(KDGantt.TypeEvent),
            MyStandardItem(now, KDGantt.StartTimeRole)
        ])
        softwareRelease.appendRow([
            packaging,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addDays(5), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(10), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            upload,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(
                now.addDays(10).addSecs(2 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(11), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            testing,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(5), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            updateDocumentation,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(3), KDGantt.EndTimeRole)
        ])
        self.model.appendRow(
            [softwareRelease,
             MyStandardItem(KDGantt.TypeSummary)])
        self.addConstraintFromItem(codeFreeze, packaging)
        self.addConstraintFromItem(codeFreeze, testing)
        self.addConstraintFromItem(codeFreeze, updateDocumentation)
        self.addConstraintFromItem(packaging, upload)
        self.addConstraintFromItem(testing, packaging)
        self.addConstraintFromItem(updateDocumentation, packaging)

    def zoomIn(self):
        self.dayWidth += 10
        if self.dayWidth > 400:
            self.grid.setScale(DateTimeGrid.ScaleHour)
        self.grid.setDayWidth(self.dayWidth)

    def zoomOut(self):
        self.dayWidth -= 10

        if self.dayWidth < 10:
            self.dayWidth = 10

        if self.dayWidth <= 400:
            self.grid.setScale(DateTimeGrid.ScaleDay)

        self.grid.setDayWidth(self.dayWidth)

    def printPreview(self):
        preview = QLabel(self, Qt.Window)
        preview.setAttribute(Qt.WA_DeleteOnClose)
        preview.setScaledContents(True)
        preview.setWindowTitle("Print Preview")
        pix = QPixmap(1000, 300)
        pix.fill(Qt.white)

        p = QPainter(pix)
        p.setRenderHints(QPainter.Antialiasing)
        self.ui.ganttView.print_(p, pix.rect())

        preview.setPixmap(pix)
        preview.show()

    def slotClicked(self, index):
        self.statusBar().showMessage(
            "(%d,%d,_,%s) clicked" %
            (index.row(), index.column(), index.model()))

    def slotDoubleClicked(self, index):
        self.statusBar().showMessage(
            "(%d,%d,_,%s) qreal clicked" %
            (index.row(), index.column(), index.model()))
    if nesting_level == 0:
        return result
    for i in range(num_children):
        child = QStandardItem("Child num {}, nesting Level {}".format(
            i + 1, nesting_level))
        if i == 0:
            child.appendRow(add_child(num_children, nesting_level - 1))
        result.append(child)
    return result


if __name__ == '__main__':
    app = QApplication(sys.argv)
    model_size = 100000
    list = []
    source_model = QStandardItemModel()
    horizontal_header_list = [
        "First Column with spacing", "Second Column with spacing"
    ]
    source_model.setHorizontalHeaderLabels(horizontal_header_list)
    for i in range(model_size):
        first_item = QStandardItem("FancyTextNumber {}".format(i))
        if i == 0:
            first_item.appendRow(add_child(2, 2))
        second_item = QStandardItem("FancyRow2TextNumber {}".format(i))
        if i % 2 == 0:
            first_item.setBackground(Qt.red)
        row = [first_item, second_item]
        source_model.invisibleRootItem().appendRow(row)
        list.append("FancyTextNumber {}".format(i))
Exemple #26
0
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        #self.ui = ()
        self.setupUi(self)

        self.p: QProcess = None

        dirname = r"K:\Media Library"

        processing_dirs = getBaseDirs(dirname)

        s: QtCore.QSize = self.treeView.iconSize()
        self.message(f'size = {s}')
        s = QtCore.QSize(16, 16)  # Set icon sizing here
        self.treeView.setIconSize(s)

        style = QApplication.style()
        self.running_icon = style.standardIcon(QStyle.SP_BrowserReload)
        self.done_icon = style.standardIcon(QStyle.SP_DialogApplyButton)
        self.failed_icon = style.standardIcon(QStyle.SP_MessageBoxCritical)
        self.missing_icon = style.standardIcon(
            QStyle.SP_TitleBarContextHelpButton)
        self.added_icon = style.standardIcon(QStyle.SP_ArrowUp)
        self.warning_icon = style.standardIcon(QStyle.SP_MessageBoxWarning)

        self.checksum_sets = []

        for dirname in processing_dirs:
            self.checksum_sets.append(ChecksumSet(dirname))

        self.updateStats()

        self.populateModel()
        self.treeView.setModel(self.model)
        #   self.treeView.setExpandsOnDoubleClick(True)

        #      for x in self.iterItems(self.model.invisibleRootItem()):
        #    y = x.data(role=DisplayRole)
        #     z = x.data(role=UserRole)
        #    self.message(f'y = {y}, z = {z}')
        #    x.setText('hi')
        #         y = x.data(role=QtCore.Qt.UserRole)
        #        self.message(x.text())

        #        self.message('HI' + y.baseDirname)
        #        self.message('HI' + str(y))

        self.start_process()

    #   model.setHorizontalHeaderLabels(['Title', 'Summary'])
    #   rootItem = model.invisibleRootItem()

    #First top-level row and children
    #   item0 = [QStandardItem('Title0'), QStandardItem('Summary0')]

    #    item00 = [QStandardItem('Title00'), QStandardItem('Summary00')]
    #    item01 = [QStandardItem('Title01'), QStandardItem('Summary01')]
    #   rootItem.appendRow(item0)
    #    item0[0].appendRow(item00)
    #    item0[0].appendRow(item01)

    #Second top-level item and its children
    #    item1 = [QStandardItem('Title1'), QStandardItem('Summary1')]
    #    item10 = [QStandardItem('Title10'), QStandardItem('Summary10')]
    #    item11 = [QStandardItem('Title11'), QStandardItem('Summary11')]
    #    item12 = [QStandardItem('Title12'), QStandardItem('Summary12')]
    #    rootItem.appendRow(item1)
    #    item1[0].appendRow(item10)
    #    item1[0].appendRow(item11)
    #    item1[0].appendRow(item12)

    #Children of item11 (third level items)
    #    item110 = [QStandardItem('Title110'), QStandardItem('Summary110')]
    #    item111 = [QStandardItem('Title111'), QStandardItem('Summary111')]
    #    item11[0].appendRow(item110)
    #    item11[0].appendRow(item111)

    def toast_notification(self, title, text):
        AppID = 'zchecksum'
        XML = ToastNotificationManager.get_template_content(
            ToastTemplateType.TOAST_TEXT02)
        print(XML)
        t = XML.get_elements_by_tag_name("text")
        print(t)
        t[0].append_child(XML.create_text_node(title))
        t[1].append_child(XML.create_text_node(text))
        notifier = ToastNotificationManager.create_toast_notifier(AppID)
        notifier.show(ToastNotification(XML))

    def iterItems(self, root):
        if root is not None:
            for row in range(root.rowCount()):
                row_item = root.child(row, 0)
                if row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        child = row_item.child(childIndex, 1)
                        yield child

    def format_size(self, size):
        if size < 0:
            raise Exception('Unknown file size')

        if size < 1024:
            return f'{size} Bytes'
        elif size < 1024 * 1024:
            size_kb = size / 1024
            return f'{size_kb:.1f} KB'
        elif size < 1024 * 1024 * 1024:
            size_mb = size / 1024 / 1024
            return f'{size_mb:.1f} MB'
        else:
            size_gb = size / 1024 / 1024 / 1024
            return f'{size_gb:.1f} GB'

    def populateModel(self):

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels([
            'Status', 'Directory / Filename', 'File Count', 'Size', 'Checksum',
            'Last Verified'
        ])
        rootItem = self.model.invisibleRootItem()

        for checksum_set in self.checksum_sets:
            last_verified = ''
            status = ''
            if not checksum_set.hasSha512File():
                status = 'New'
            elif checksum_set.has_changes():
                status = "Modified"
                self.toast_notification("Checksum set was modified.",
                                        checksum_set.baseDirname)
            else:
                time_delta = datetime.now(
                ) - checksum_set.sha512File.last_verified
                last_verified = f'{time_delta.days} days ago'
                if time_delta.days > good_days:
                    status = 'Test'
                else:
                    status = 'Good'

            if status == 'Test' or status == 'New' or status == 'Modified':
                item = [
                    QStandardItem(status),
                    QStandardItem(checksum_set.baseDirname),
                    QStandardItem(str(len(checksum_set.filenames))),
                    QStandardItem(''),
                    QStandardItem(''),
                    QStandardItem(last_verified)
                ]
                for filename in checksum_set.filenames:
                    checksum_text = ''
                    file_status = ''
                    if checksum_set.sha512File:
                        checksum = checksum_set.sha512File.findChecksum(
                            filename)
                        if checksum:
                            checksum_text = checksum
                        else:
                            file_status = 'Added'
                    size = Path(checksum_set.baseDirname +
                                filename).stat().st_size
                    size_display = self.format_size(size)
                    #     sz = len(checksum_set.baseDirname) + len(filename)
                    c_item = [
                        QStandardItem(file_status),
                        QStandardItem(filename),
                        QStandardItem(''),
                        QStandardItem(size_display),
                        QStandardItem(checksum_text)
                    ]
                    c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                    if file_status == 'Added':
                        c_item[0].setIcon(self.added_icon)
                    if filename == 'Thumbs.db':
                        c_item[0].setIcon(self.warning_icon)
                    item[0].appendRow(c_item)
                if checksum_set.hasSha512File():
                    for filename in checksum_set.get_missing_from_dir():
                        checksum_text = checksum_set.sha512File.findChecksum(
                            filename)
                        c_item = [
                            QStandardItem('Missing'),
                            QStandardItem(filename),
                            QStandardItem(''),
                            QStandardItem('n/a'),
                            QStandardItem(checksum_text)
                        ]
                        c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                        c_item[0].setIcon(self.missing_icon)
                        item[0].appendRow(c_item)
                rootItem.appendRow(item)

    #    self.showIssues()

    #TODO: FIX, NOT WORKING!
    def showIssues(self):
        self.treeView.expandAll()
        root = self.model.invisibleRootItem()
        if root is not None:
            for row in range(root.rowCount()):
                row_item = root.child(row, 0)
                if row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        child = row_item.child(childIndex, 1)

                        filename = child.text()
                        print(f'f = {filename}, {row_item.index()}')
                        if filename == 'Thumbs.db':
                            self.treeView.setExpanded(row_item.index(), True)
                        #   c_item[0].setIcon(self.warning_icon)
                        #   item[0].setExpanded(True)

    #   self.start_process()

    #   header = self.treeWidget.header()
    #  header

    #    header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
    #    header.setStretchLastSection(False)
    #   header.setSectionResizeMode(5, QtWidgets.QHeaderView.Stretch)

    def updateStats(self):
        new_count = 0
        modified_count = 0
        test_count = 0
        good_count = 0

        #    items = []
        for checksum_set in self.checksum_sets:
            if not checksum_set.hasSha512File():
                new_count += 1
            elif checksum_set.has_changes():
                modified_count += 1
            else:
                time_delta = datetime.now(
                ) - checksum_set.sha512File.last_verified
                if time_delta.days > good_days:
                    test_count += 1
                else:
                    good_count += 1

        self.statusBar().showMessage(
            f'Total sets: {len(self.checksum_sets)} sets.   New sets: {new_count}   Modified sets: {modified_count}   Test sets: {test_count}   Good sets: {good_count}'
        )

    def message(self, s):
        #    self.statusBar().showMessage(s)
        self.listWidget.addItem(s)

    def start_process(self):
        root = self.model.invisibleRootItem()

        started_count = 0

        if root is not None:
            for row in range(root.rowCount()):

                if self.p:
                    break

                row_item = root.child(row, 0)
                #  item = self.model.item(row)
                dir = root.child(row, 1)
                set_status = root.child(row, 0)

                #       self.message(dir.text())
                if (set_status.text() == "New" or set_status.text()
                        == 'Test') and row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        #  status = row_item.child(childIndex, 0)

                        #   self.message(status.text())
                        #          if status.text() == 'New':
                        #              self.message(dir.text())

                        status = row_item.child(childIndex, 0)
                        filename = row_item.child(childIndex, 1)
                        #      self.message(filename.text())
                        #   checksum_item = row_item.child(childIndex, 4)

                        if status.text() != "Done":
                            #      parent = filename.parent()
                            #       self.message("parent " + str(parent))

                            self.run_process(dir.text(), filename.text(),
                                             row_item, childIndex)
                            started_count += 1

                            if self.p:
                                break

        self.message(f'start_process done.  Started {started_count}')

        #  yield child

#     for i in range(self.model.rowCount()):
#                 item = self.model.item(i)

#    root = self.treeWidget.invisibleRootItem()
#    child_count = root.childCount()
#    for i in range(child_count):
#        item = ro
# ot.child(i)
#       url = item.text(0) # text at first (0) column
#        item.setText(1, 'result from %s' % url) # update result column (1)

    def run_process(self, dir, filename, set_item, childIndex):
        if self.p is None:  # No process running.
            self.p_item = dict(set_item=set_item, child_index=childIndex)
            self.p = QProcess(
            )  # Keep a reference to the QProcess (e.g. on self) while it's running.

            #    item
            #       self.p.readyReadStandardOutput.connect(self.handle_stdout)
            self.p.readyReadStandardError.connect(self.handle_stderr)
            self.p.stateChanged.connect(self.handle_state)
            self.p.finished.connect(
                self.process_finished)  # Clean up once complete.

            #   filename = r"J:\Media Library\TV\New\Family Guy\Misc\Family Guy S07E11.avi"

            filepath = dir + filename
            self.message("Executing process for file: " + filepath)

            if Path(filepath).stat().st_size > 0:
                args = ["-hashfile", filepath, "SHA512"]
                self.p.start("certutil", args)
            else:
                # CertUtil cannot compute hashes on empty files
                args = ["zero_sha512.py"]
                self.p.start("python", args)

            status = set_item.child(childIndex, 0)

            status.setIcon(self.running_icon)
            set_item.setIcon(self.running_icon)

            if status.text() == '':
                if set_item.text() != 'Test':
                    set_item.child(childIndex, 0).setText('Running Pass 1/3')
                else:
                    set_item.child(childIndex, 0).setText('Running')
            elif status.text() == 'Running Pass 1/3':
                set_item.child(childIndex, 0).setText('Running Pass 2/3')
            elif status.text() == 'Running Pass 2/3':
                set_item.child(childIndex, 0).setText('Running Pass 3/3')

        else:
            self.message("process already running!")

    def handle_stderr(self):
        data = self.p.readAllStandardError()
        stderr = bytes(data).decode("utf8")
        # Extract progress if it is in the data.
        #     progress = simple_percent_parser(stderr)
        #     if progress:
        #         self.progress.setValue(progress)
        self.message(stderr)

    def handle_stdout(self):
        data = self.p.readAllStandardOutput()
        stdout = bytes(data).decode("utf8")
        self.message(stdout)

    def handle_state(self, state):
        states = {
            QProcess.NotRunning: 'Not running',
            QProcess.Starting: 'Starting',
            QProcess.Running: 'Running',
        }
        state_name = states[state]
        self.message(f"State changed: {state_name}")

    def process_finished(self, exitCode, exitStatus):

        row_item = self.p_item['set_item']
        child_index = self.p_item['child_index']
        status_item = row_item.child(child_index, 0)
        filename_item = row_item.child(child_index, 1)

        try:
            checksum_set = filename_item.data(QtCore.Qt.UserRole)

            if checksum_set is None:
                self.toast_notification(
                    "Checksum set not found.",
                    "No checksum set for file " + filename_item.text())
                raise Exception("No checksum set found")

            self.message(
                f'Process finished. exitCode = {exitCode}, exitStatus = {exitStatus}, baseDirname = {checksum_set.baseDirname}'
            )

            data = self.p.readAllStandardOutput()

            #       stdout = bytes(data)
            #      self.message("normal stdout: " + stdout)
            #  .decode('iso-8859-1').encode('utf8')
            #    stdout = bytes(data).decode("iso-8859-1")
            #try:
            stdout = bytes(data).decode('utf8', 'replace')
            #  except:
            #      stdout = bytes(data).decode('iso-8859-1')

            #   self.message("row_item" + row_item)
            self.message("stdout: " + stdout)

            lines = stdout.splitlines()

            if exitCode != 0 or len(lines) != 3:
                msg = f'Compute SHA512 failed.  stdout: ({stdout})'
                error_message = ''
                if len(lines) > 1 and lines[1].startswith("CertUtil: "):
                    error_message = lines[1][10:]

            #   msg = f'Error: Compute SHA512 failed for file {filename}.  stdout: ({cp.stdout}) stderr: ({cp.stderr})'
        #       print(msg)
                self.toast_notification(
                    'Failed to compute checksum. ' + error_message,
                    filename_item.text())
                raise Exception(msg)

            new_checksum = lines[1].replace(" ", "")

            checksum_item = row_item.child(child_index, 4)

            old_checksum = checksum_item.text()

            if old_checksum == "":
                checksum_item.setText(new_checksum)
            elif new_checksum != old_checksum:
                msg = f'Checksums do not match.'
                self.toast_notification('Checksums mismatch',
                                        filename_item.text())
                raise Exception(msg)

            if status_item.text() == "Running Pass 3/3" or status_item.text(
            ) == 'Running':
                status_item.setText('Done')
                status_item.setIcon(self.done_icon)

        #   checksum = QStandardItem()
        #   row_item.setChild(0, 4, checksum)
        # my_item.setText()

        #  my_item.setText(0, "Done")
        #  self.message("my_item: " + my_item.text(1))

    #     if self.all_files_done_checksum(row_item.parent()):
    #        self.create_sha_file(my_item.parent())

            if self.all_files_done_checksum(row_item):
                row_item.setIcon(self.done_icon)
                row_item.setText("Done")
                if checksum_set.hasSha512File():
                    self.message(
                        f'Updating {checksum_set.baseDirname} checksum file modified date'
                    )
                    checksum_set.update_modified()
                else:
                    self.create_sha_file(row_item)
        except Exception as e:
            status_item.setText("Failed")
            status_item.setIcon(self.failed_icon)
            row_item.setText("Failed")
            row_item.setIcon(self.failed_icon)
            self.message("Error: " + str(e))
        finally:
            self.p = None
            self.start_process()

    def all_files_done_checksum(self, set_item):
        for childIndex in range(set_item.rowCount()):
            status_item = set_item.child(childIndex, 0)
            checksum_item = set_item.child(childIndex, 4)
            filename_item = set_item.child(childIndex, 1)
            self.message(filename_item.text())

            if status_item.text() != 'Done' or checksum_item.text() == '':
                return False

        return True

    def create_sha_file(self, set_item):
        self.message("create_sha_file!!")

        # index = set_item.index()

        #  self.message(f'index = {index}')
        #  dirname = self.model.item(index, 1)

        #   dirname = set_item.data(1)

        dir = self.model.invisibleRootItem().child(set_item.row(), 1)

        dirname = dir.text()
        self.message(
            f'create_sha_file2, dir = {dir.text()}, row = {set_item.row()}, set_item.columnCount = {set_item.columnCount()}'
        )

        shaFile = Sha512(dirname)

        for childIndex in range(set_item.rowCount()):
            checksum_item = set_item.child(childIndex, 4)

            filename_item = set_item.child(childIndex, 1)
            self.message(filename_item.text())

            shaFile.addFileAndChecksum(filename_item.text(),
                                       checksum_item.text())

        shaFile.writeFile()
Exemple #27
0
    def populateModel(self):

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels([
            'Status', 'Directory / Filename', 'File Count', 'Size', 'Checksum',
            'Last Verified'
        ])
        rootItem = self.model.invisibleRootItem()

        for checksum_set in self.checksum_sets:
            last_verified = ''
            status = ''
            if not checksum_set.hasSha512File():
                status = 'New'
            elif checksum_set.has_changes():
                status = "Modified"
                self.toast_notification("Checksum set was modified.",
                                        checksum_set.baseDirname)
            else:
                time_delta = datetime.now(
                ) - checksum_set.sha512File.last_verified
                last_verified = f'{time_delta.days} days ago'
                if time_delta.days > good_days:
                    status = 'Test'
                else:
                    status = 'Good'

            if status == 'Test' or status == 'New' or status == 'Modified':
                item = [
                    QStandardItem(status),
                    QStandardItem(checksum_set.baseDirname),
                    QStandardItem(str(len(checksum_set.filenames))),
                    QStandardItem(''),
                    QStandardItem(''),
                    QStandardItem(last_verified)
                ]
                for filename in checksum_set.filenames:
                    checksum_text = ''
                    file_status = ''
                    if checksum_set.sha512File:
                        checksum = checksum_set.sha512File.findChecksum(
                            filename)
                        if checksum:
                            checksum_text = checksum
                        else:
                            file_status = 'Added'
                    size = Path(checksum_set.baseDirname +
                                filename).stat().st_size
                    size_display = self.format_size(size)
                    #     sz = len(checksum_set.baseDirname) + len(filename)
                    c_item = [
                        QStandardItem(file_status),
                        QStandardItem(filename),
                        QStandardItem(''),
                        QStandardItem(size_display),
                        QStandardItem(checksum_text)
                    ]
                    c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                    if file_status == 'Added':
                        c_item[0].setIcon(self.added_icon)
                    if filename == 'Thumbs.db':
                        c_item[0].setIcon(self.warning_icon)
                    item[0].appendRow(c_item)
                if checksum_set.hasSha512File():
                    for filename in checksum_set.get_missing_from_dir():
                        checksum_text = checksum_set.sha512File.findChecksum(
                            filename)
                        c_item = [
                            QStandardItem('Missing'),
                            QStandardItem(filename),
                            QStandardItem(''),
                            QStandardItem('n/a'),
                            QStandardItem(checksum_text)
                        ]
                        c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                        c_item[0].setIcon(self.missing_icon)
                        item[0].appendRow(c_item)
                rootItem.appendRow(item)
Exemple #28
0
class KeyMgrDialog(QDialog, UIKeyMgrDialog):
    def __init__(self, parent=None, model=True) -> None:
        super().__init__()

        self.parent = parent
        self.setupUi(self)
        self.setWindowTitle('密钥管理')
        self.setModal(model)

        self.key_list = key_cache.get_key_list()
        self.list_model = None
        self.setup_key_list(self.key_list)

        self.tbCreate.clicked.connect(self.create_key_action)
        self.tbCreate.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.tbCreate.setIcon(
            qta.icon('ei.file-new',
                     color=icon_color['color'],
                     color_active=icon_color['active']))

        self.tbAdd.clicked.connect(self.add_key_action)
        self.tbAdd.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.tbAdd.setIcon(
            qta.icon('fa.plus',
                     color=icon_color['color'],
                     color_active=icon_color['active']))

        self.tbRemove.clicked.connect(self.remove_key_action)
        self.tbRemove.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.tbRemove.setIcon(
            qta.icon('fa.minus',
                     color=icon_color['color'],
                     color_active=icon_color['active']))

        add_key_invalidate_callback(self.key_invalidate)

    def setup_key_list(self, key_list):
        self.keyListView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.list_model = QStandardItemModel(self.keyListView)
        for key in key_list:
            item = self.make_item(key)
            self.list_model.appendRow(item)
        self.keyListView.setModel(self.list_model)
        self.keyListView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.keyListView.customContextMenuRequested[QPoint].connect(
            self.context_menu)

    def key_invalidate(self, invalidate_key: Key):
        for i in range(self.list_model.rowCount()):
            key = self.list_model.item(i).data()
            if key.id == invalidate_key.id:
                #self.list_model.item(i).setIcon(qta.icon('fa.warning', color=icon_color))
                self.update_key_icon(self.list_model.item(i))
                return

    def update_key_icon(self, item):
        key = item.data()
        if key.timeout:
            item.setIcon(
                qta.icon('fa.warning',
                         scale_factor=0.8,
                         color=icon_color['color'],
                         color_active=icon_color['active']))
        elif key_cache.is_cur_key(key):
            item.setIcon(
                qta.icon('fa.check',
                         scale_factor=0.8,
                         color=icon_color['color'],
                         color_active=icon_color['active']))
        else:
            item.setIcon(
                QIcon(
                    qta.icon('fa5s.key',
                             scale_factor=0.7,
                             color=icon_color['color'],
                             color_active=icon_color['active'])))

    def make_item(self, key):
        item = QStandardItem(key.name)
        item.setData(key)
        #item.setIcon(QIcon(qta.icon('fa5s.key', color=icon_color)))
        self.update_key_icon(item)
        return item

    def get_selected_item(self):
        selected = self.keyListView.selectedIndexes()
        if not selected:
            return

        index = selected[0]
        item = self.list_model.item(index.row())
        return item

    def context_menu(self, point):

        selected = self.keyListView.selectedIndexes()
        if not selected:
            return

        index = selected[0]
        item = self.list_model.item(index.row())
        key = item.data()

        pop_menu = QMenu()

        _set_default_key_action = pop_menu.addAction(
            qta.icon('fa.check',
                     color=icon_color['color'],
                     color_active=icon_color['active']), '设为默认')
        if key_cache.is_cur_key(key) or key.timeout:
            _set_default_key_action.setEnabled(False)

        pop_menu.addSeparator()
        _encrypt_files_action = pop_menu.addAction(
            qta.icon('ei.lock',
                     color=icon_color['color'],
                     color_active=icon_color['active']), "加密文件")
        _decrypt_files_action = pop_menu.addAction(
            qta.icon('ei.unlock',
                     color=icon_color['color'],
                     color_active=icon_color['active']), "解密文件")
        pop_menu.addSeparator()

        _reload_key_action = pop_menu.addAction(
            qta.icon('fa.refresh',
                     color=icon_color['color'],
                     color_active=icon_color['active']), "重新加载")
        _reload_key_action.setEnabled(key.timeout)

        selected_action = pop_menu.exec_(QCursor.pos())
        if selected_action == _encrypt_files_action:
            self.encrypt_files_action()
        elif selected_action == _set_default_key_action:
            self.set_default_key_action()
        elif selected_action == _reload_key_action:
            self.reload_key_action()
        elif selected_action == _decrypt_files_action:
            self.decrypt_files_action()

    def set_default_key_action(self, item=None):

        item = self.get_selected_item()
        self._set_default_key(item)
        for i in range(self.list_model.rowCount()):
            self.update_key_icon(self.list_model.item(i))
            #self.list_model.item(i).setIcon(qta.icon('fa5s.key', color=icon_color))

    def create_key_action(self):
        dialog = KeyCreateDialog(parent=self)
        dialog.activateWindow()
        dialog.exec()
        key = dialog.key
        if key is None:
            return
        item = self.make_item(key)
        self._add_key(item, key)

    def _add_key(self, item, key):
        self.list_model.appendRow(item)
        key_cache.add_key(key)

    def _remove_key(self, index):
        self.list_model.removeRow(index)
        key_cache.remove_key(index)

    def _set_default_key(self, item):
        key_cache.set_current_key(item.data())
        self.update_key_icon(item)

    def add_key_action(self):
        file_name, _ = QFileDialog.getOpenFileName(self, '选择密钥文件')

        if len(file_name.strip()) == 0:
            return

        password = None
        if Key.need_password(file_name):
            ok_pressed = True
            while ok_pressed:
                password, ok_pressed = QInputDialog.getText(
                    self, "需要密码", "输入密码:", QLineEdit.Password, "")
                if ok_pressed:
                    illegal, msg = Key.is_password_illegal(password)
                    if illegal:
                        QMessageBox.information(self, '错误', msg)
                        continue
                    break
                else:
                    return

        key = Key()
        try:
            key.load(file_name, password)
        except Exception as e:
            QMessageBox.critical(self, '错误', '不是有效的密钥文件<br/>' + str(e))
            return

        row_len = self.list_model.rowCount()
        for i in range(0, row_len):
            item: QStandardItem = self.list_model.item(i, 0)
            k: Key = item.data()
            if k.id == key.id:
                QMessageBox.information(self, '信息', '相同的密钥已经加载')
                return

        item = self.make_item(key)
        self._add_key(item, key)

        return

    def remove_key_action(self):
        selected = self.keyListView.selectedIndexes()
        if not selected:
            return
        index = selected[0]
        self._remove_key(index.row())
        QMessageBox.information(self, '信息', '密钥已经移除')

    def encrypt_files_action(self):
        item = self.get_selected_item()
        key = item.data()
        ef_dialog = EncryptFileDialog(self)
        ef_dialog.set_key(key)
        ef_dialog.exec()

    def decrypt_files_action(self):
        item = self.get_selected_item()
        key = item.data()
        ef_dialog = EncryptFileDialog(
            self,
            win_title='解密文件',
            before_process=is_encrypt_data,
            processor=decrypt_data,
            success_msg='解密完成',
            select_file_dlg_title='选择需要解密的文件',
        )
        ef_dialog.set_key(key)
        ef_dialog.exec()

    def reload_key_action(self):
        item = self.get_selected_item()
        key: Key = item.data()
        password = None
        if Key.need_password(key.path):
            ok_pressed = True
            while ok_pressed:
                password, ok_pressed = QInputDialog.getText(
                    self, "需要密码", "输入密码:", QLineEdit.Password, "")
                if ok_pressed:
                    illegal, msg = Key.is_password_illegal(password)
                    if illegal:
                        QMessageBox.information(self, '错误', msg)
                        continue
                    break
                else:
                    return

        try:
            key.load(key.path, password)
        except Exception as e:
            QMessageBox.critical(self, '错误', '不是有效的密钥文件<br/>' + str(e))
            return

        self.update_key_icon(item)
Exemple #29
0
class App(QMainWindow):
    def __init__(self):
        super(App, self).__init__()

        self.treeView = None
        self.model = None
        self.pattern_delegate = None
        self.callee_delegate = None
        self.sig_trie = None

        self.searchResults = None
        self.searchIndex = -1
        self.findNextAction = None
        self.findPrevAction = None

        # these two maps are used to make the hyperlinks work
        # mapping from href to FunctionNode
        self.hrefs_to_funcs = {}
        # mapping from FunctionNode to tree view element (QStandardItem)
        self.func_node_items = {}

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('Signature Explorer')
        self.resize(1000, 640)
        app_icon = QIcon()
        app_icon.addFile('icon.ico', QSize(48, 48))
        self.setWindowIcon(app_icon)

        self.pattern_delegate = PatternDelegate()
        self.callee_delegate = CalleesDelegate()

        self.treeView = TrieView()
        # self.treeView.setAlternatingRowColors(True)

        self.model = QStandardItemModel(0, 7, self.treeView)
        self.model.setHeaderData(0, Qt.Horizontal, 'Signature')
        self.model.setHeaderData(1, Qt.Horizontal, 'Function')
        self.model.setHeaderData(2, Qt.Horizontal, 'Callees')
        self.model.setHeaderData(3, Qt.Horizontal, 'Offset Extra Pattern')
        self.model.setHeaderData(4, Qt.Horizontal, 'Extra Pattern')
        self.model.setHeaderData(5, Qt.Horizontal, 'Source Binary')
        self.model.setHeaderData(6, Qt.Horizontal, 'ID')
        self.treeView.setModel(self.model)

        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setColumnWidth(0, 400)
        self.treeView.setColumnWidth(1, 200)
        self.treeView.setColumnWidth(2, 250)
        self.treeView.setColumnWidth(3, 25)
        self.treeView.setColumnWidth(4, 100)
        self.treeView.setColumnWidth(5, 200)
        self.treeView.setColumnWidth(6, 75)
        self.treeView.setItemDelegateForColumn(0, self.pattern_delegate)
        self.treeView.setItemDelegateForColumn(2, self.callee_delegate)
        self.treeView.setItemDelegateForColumn(4, self.pattern_delegate)
        self.treeView.horizontalScrollBar().setEnabled(True)
        self.treeView.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.treeView.linkActivated.connect(self.on_func_link_clicked)
        # self.treeView.expanded.connect(lambda x: self.treeView.resizeColumnToContents(1))
        # self.treeView.collapsed.connect(lambda x: self.treeView.resizeColumnToContents(1))

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.treeView)

        panel = QWidget()
        panel.setLayout(main_layout)
        self.setCentralWidget(panel)

        menuBar = self.menuBar()

        fileMenu = QMenu("File")
        openAction = QAction("&Open", self)
        openAction.setShortcuts(QKeySequence.Open)
        openAction.triggered.connect(self.open_file)
        fileMenu.addAction(openAction)

        closeAction = QAction("&Close", self)
        closeAction.setShortcuts(QKeySequence.Close)
        closeAction.triggered.connect(self.close_file)
        fileMenu.addAction(closeAction)

        saveAsAction = QAction("Save As...", self)
        saveAsAction.setShortcuts(QKeySequence.Save)
        saveAsAction.triggered.connect(self.save_as)
        fileMenu.addAction(saveAsAction)

        menuBar.addMenu(fileMenu)

        editMenu = QMenu("Edit")

        findAction = QAction("&Find", self)
        findAction.setShortcuts(QKeySequence.Find)
        findAction.triggered.connect(self.search)
        editMenu.addAction(findAction)

        self.findNextAction = QAction("&Find Next", self)
        self.findNextAction.setShortcuts(QKeySequence.FindNext)
        self.findNextAction.triggered.connect(self.select_next)
        self.findNextAction.setEnabled(False)
        editMenu.addAction(self.findNextAction)

        self.findPrevAction = QAction("&Find Prev", self)
        self.findPrevAction.setShortcuts(QKeySequence.FindPrevious)
        self.findPrevAction.triggered.connect(self.select_prev)
        self.findPrevAction.setEnabled(False)
        editMenu.addAction(self.findPrevAction)

        menuBar.addMenu(editMenu)

        viewMenu = QMenu("View")

        expandAction = QAction("&Expand All", self)
        expandAction.triggered.connect(self.treeView.expandAll)
        viewMenu.addAction(expandAction)

        collapseAction = QAction("&Collapse All", self)
        collapseAction.triggered.connect(self.treeView.collapseAll)
        viewMenu.addAction(collapseAction)

        menuBar.addMenu(viewMenu)

    def search(self):
        query_string, ok = QInputDialog.getText(self, 'Find in Trie',
                                                'Function name')
        if not ok or not query_string:
            return

        self.searchResults = self.model.findItems(
            query_string, Qt.MatchContains | Qt.MatchRecursive, 1)

        if self.searchResults:
            self.findNextAction.setEnabled(True)
            self.findPrevAction.setEnabled(True)
            self.searchIndex = 0
            self.select_next()
        else:
            self.findNextAction.setEnabled(False)
            self.findPrevAction.setEnabled(False)
            self.searchIndex = -1
            QMessageBox.warning(self, 'Find in Trie', 'No results found')

    def select_next(self):
        next_item = self.searchResults[self.searchIndex]
        self.searchIndex = (self.searchIndex + 1) % len(self.searchResults)
        self.select_tree_item(next_item)

    def select_prev(self):
        prev_item = self.searchResults[self.searchIndex]
        self.searchIndex = (self.searchIndex - 1) % len(self.searchResults)
        self.select_tree_item(prev_item)

    def select_tree_item(self, item):
        path = []
        while item:
            path.insert(0, self.model.indexFromItem(item))
            item = item.parent()
        # print(path)
        for index in path:
            self.treeView.setExpanded(index, True)
        self.treeView.selectionModel().select(
            path[-1],
            QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
        self.treeView.scrollTo(path[-1])

    def close_file(self):
        self.model.removeRows(0, self.model.rowCount())
        self.sig_trie = None
        self.hrefs_to_funcs = {}
        self.func_node_items = {}

    def open_file(self):
        sig_filter = 'Signature library (*.sig)'
        json_zlib_filter = 'Compressed JSON signature library (*.json.zlib)'
        json_filter = 'JSON signature library (*.json)'
        pkl_filter = 'Pickled signature library (*.pkl)'
        fname, filter = QFileDialog.getOpenFileName(self,
                                                    'Open file',
                                                    filter=';;'.join([
                                                        sig_filter,
                                                        json_zlib_filter,
                                                        json_filter, pkl_filter
                                                    ]))
        if filter and fname:
            print('Opening signature library %s' % (fname, ))

        if filter == json_zlib_filter:
            with open(fname, 'rb') as f:
                json_trie = zlib.decompress(f.read()).decode('utf-8')
            sig_trie = sig_serialize_json.deserialize(json.loads(json_trie))
        elif filter == json_filter:
            with open(fname, 'r') as f:
                json_trie = f.read()
            sig_trie = sig_serialize_json.deserialize(json.loads(json_trie))
        elif filter == sig_filter:
            with open(fname, 'rb') as f:
                fb_trie = f.read()
            sig_trie = sig_serialize_fb.SignatureLibraryReader().deserialize(
                fb_trie)
        elif filter == pkl_filter:
            with open(fname, 'rb') as f:
                sig_trie = pickle.load(f)
        else:
            return

        self.open_trie(sig_trie, os.path.basename(fname))

    def save_as(self):
        sig_filter = 'Signature library (*.sig)'
        json_zlib_filter = 'Compressed JSON signature library (*.json.zlib)'
        json_filter = 'JSON signature library (*.json)'
        pkl_filter = 'Pickled signature library (*.pkl)'
        fname, filter = QFileDialog.getSaveFileName(self,
                                                    'Open file',
                                                    filter=';;'.join([
                                                        sig_filter,
                                                        json_zlib_filter,
                                                        json_filter, pkl_filter
                                                    ]))

        if filter == json_zlib_filter:
            with open(fname, 'wb') as f:
                f.write(
                    zlib.compress(
                        sig_serialize_json.serialize(
                            self.sig_trie).encode('utf-8')))
        elif filter == json_filter:
            with open(fname, 'w') as f:
                json.dump(sig_serialize_json.serialize(self.sig_trie),
                          f,
                          indent=4)
        elif filter == sig_filter:
            with open(fname, 'wb') as f:
                f.write(sig_serialize_fb.SignatureLibraryWriter().serialize(
                    self.sig_trie))
        elif filter == pkl_filter:
            with open(fname, 'wb') as f:
                pickle.dump(self.sig_trie, f)
        else:
            return
        print('Saved as ' + fname)

    @staticmethod
    def generate_href(func):
        return str(id(func))

    def get_func_name(self, func_node):
        if func_node is None:
            return '<missing>'
        else:
            return '<a href="' + self.generate_href(
                func_node) + '">' + func_node.name + '</a>'

    # handles when the user clicks on a hyperlink to a function node
    def on_func_link_clicked(self, link):
        print('Hyperlink clicked: ' + link)
        self.select_tree_item(self.func_node_items[self.hrefs_to_funcs[link]])

    # Generate treeview row for function (leaf) node in the trie
    def add_func_node(self, parent, pattern_col_item, func):
        self.hrefs_to_funcs[self.generate_href(func)] = func
        self.func_node_items[func] = pattern_col_item

        if not func.callees: func.callees = {}
        callees_text = '<br />'.join([
            str(k) + ': ' + self.get_func_name(v)
            for k, v in func.callees.items()
        ])
        callees_item = QStandardItem(callees_text)
        cols = [
            pattern_col_item,
            QStandardItem(func.name), callees_item,
            QStandardItem(str(func.pattern_offset) if func.pattern else ''),
            QStandardItem(str(func.pattern) if func.pattern else ''),
            QStandardItem(func.source_binary),
            QStandardItem(self.generate_href(func))
        ]
        boldface = cols[1].font()
        boldface.setBold(True)
        cols[1].setFont(boldface)
        parent.appendRow(cols)

    # Recursively add rows for this trie node and its children
    def add_trie_node(self, parent, pattern_text, node):
        left_item = QStandardItem(pattern_text)

        if not node.value:  # Stem node
            parent.appendRow([left_item, QStandardItem('')])
        else:  # Leaf node
            self.add_func_node(parent, left_item, node.value[0])
            for func in node.value[1:]:
                self.add_func_node(parent, QStandardItem(''), func)

        pairs = map(lambda node: (str(node.pattern), node),
                    node.children.values())
        pairs = sorted(pairs, key=lambda kv: kv[0].replace('?', '\xff'))
        for text, child in pairs:
            self.add_trie_node(left_item, text, child)
        return left_item

    # Add bridge nodes to a special node at the root
    def add_bridge_nodes(self, parent, sig_trie):
        bridge_item = QStandardItem('(bridge)')
        parent.appendRow([bridge_item, QStandardItem('')])

        def visit(func, visited):
            if func is None or func in visited: return
            visited.add(func)
            if func.is_bridge:
                self.add_func_node(bridge_item, QStandardItem(''), func)
            for callee in func.callees.values():
                visit(callee, visited)

        visited = set()
        for func in sig_trie.all_values():
            visit(func, visited)

    def open_trie(self, sig_trie, filename):
        self.close_file()
        self.sig_trie = sig_trie
        root_node = self.add_trie_node(self.model, filename, sig_trie)
        self.add_bridge_nodes(root_node, sig_trie)
Exemple #30
0
    def init_ui(self):
        self.setWindowTitle('Signature Explorer')
        self.resize(1000, 640)
        app_icon = QIcon()
        app_icon.addFile('icon.ico', QSize(48, 48))
        self.setWindowIcon(app_icon)

        self.pattern_delegate = PatternDelegate()
        self.callee_delegate = CalleesDelegate()

        self.treeView = TrieView()
        # self.treeView.setAlternatingRowColors(True)

        self.model = QStandardItemModel(0, 7, self.treeView)
        self.model.setHeaderData(0, Qt.Horizontal, 'Signature')
        self.model.setHeaderData(1, Qt.Horizontal, 'Function')
        self.model.setHeaderData(2, Qt.Horizontal, 'Callees')
        self.model.setHeaderData(3, Qt.Horizontal, 'Offset Extra Pattern')
        self.model.setHeaderData(4, Qt.Horizontal, 'Extra Pattern')
        self.model.setHeaderData(5, Qt.Horizontal, 'Source Binary')
        self.model.setHeaderData(6, Qt.Horizontal, 'ID')
        self.treeView.setModel(self.model)

        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setColumnWidth(0, 400)
        self.treeView.setColumnWidth(1, 200)
        self.treeView.setColumnWidth(2, 250)
        self.treeView.setColumnWidth(3, 25)
        self.treeView.setColumnWidth(4, 100)
        self.treeView.setColumnWidth(5, 200)
        self.treeView.setColumnWidth(6, 75)
        self.treeView.setItemDelegateForColumn(0, self.pattern_delegate)
        self.treeView.setItemDelegateForColumn(2, self.callee_delegate)
        self.treeView.setItemDelegateForColumn(4, self.pattern_delegate)
        self.treeView.horizontalScrollBar().setEnabled(True)
        self.treeView.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.treeView.linkActivated.connect(self.on_func_link_clicked)
        # self.treeView.expanded.connect(lambda x: self.treeView.resizeColumnToContents(1))
        # self.treeView.collapsed.connect(lambda x: self.treeView.resizeColumnToContents(1))

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.treeView)

        panel = QWidget()
        panel.setLayout(main_layout)
        self.setCentralWidget(panel)

        menuBar = self.menuBar()

        fileMenu = QMenu("File")
        openAction = QAction("&Open", self)
        openAction.setShortcuts(QKeySequence.Open)
        openAction.triggered.connect(self.open_file)
        fileMenu.addAction(openAction)

        closeAction = QAction("&Close", self)
        closeAction.setShortcuts(QKeySequence.Close)
        closeAction.triggered.connect(self.close_file)
        fileMenu.addAction(closeAction)

        saveAsAction = QAction("Save As...", self)
        saveAsAction.setShortcuts(QKeySequence.Save)
        saveAsAction.triggered.connect(self.save_as)
        fileMenu.addAction(saveAsAction)

        menuBar.addMenu(fileMenu)

        editMenu = QMenu("Edit")

        findAction = QAction("&Find", self)
        findAction.setShortcuts(QKeySequence.Find)
        findAction.triggered.connect(self.search)
        editMenu.addAction(findAction)

        self.findNextAction = QAction("&Find Next", self)
        self.findNextAction.setShortcuts(QKeySequence.FindNext)
        self.findNextAction.triggered.connect(self.select_next)
        self.findNextAction.setEnabled(False)
        editMenu.addAction(self.findNextAction)

        self.findPrevAction = QAction("&Find Prev", self)
        self.findPrevAction.setShortcuts(QKeySequence.FindPrevious)
        self.findPrevAction.triggered.connect(self.select_prev)
        self.findPrevAction.setEnabled(False)
        editMenu.addAction(self.findPrevAction)

        menuBar.addMenu(editMenu)

        viewMenu = QMenu("View")

        expandAction = QAction("&Expand All", self)
        expandAction.triggered.connect(self.treeView.expandAll)
        viewMenu.addAction(expandAction)

        collapseAction = QAction("&Collapse All", self)
        collapseAction.triggered.connect(self.treeView.collapseAll)
        viewMenu.addAction(collapseAction)

        menuBar.addMenu(viewMenu)