예제 #1
0
    def __setupUi(self):
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        view = QTreeView(objectName="tool-tree-view")
        view.setUniformRowHeights(True)
        view.setFrameStyle(QTreeView.NoFrame)
        view.setModel(self.__model)
        view.setRootIsDecorated(False)
        view.setHeaderHidden(True)
        view.setItemsExpandable(True)
        view.setEditTriggers(QTreeView.NoEditTriggers)
        view.setItemDelegate(ToolTreeItemDelegate(self))

        view.activated.connect(self.__onActivated)
        view.clicked.connect(self.__onActivated)
        view.entered.connect(self.__onEntered)

        view.installEventFilter(self)

        self.__view = view

        layout.addWidget(view)

        self.setLayout(layout)
    def __init__(self, parent=None) -> None:
        QWidget.__init__(self, parent)

        # Основные компоненты
        # Вывод варианта моделирования в виде иерархического дерева
        variant_tree_view = QTreeView()
        # Не хотим пользователю дать разрешение на его редактирование
        variant_tree_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # Ссылка на экземпляр класса, управляющего заголовком
        header = variant_tree_view.header()
        # Задание режима для изменения размеров секций (автоматически растягивается)
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        # Модель представления данных
        self.model = QStandardItemModel(self)
        variant_tree_view.setModel(self.model)

        # Групбокс с вариантом моделирования
        group_box = QGroupBox("Получившийся вариант моделирования")
        group_box_layout = QVBoxLayout(group_box)
        group_box_layout.addWidget(variant_tree_view)
        # Контейнер с кнопками назад/далее
        control_layout = LayoutWithBackAndNextButtons()

        # Основной контейнер
        main_layout = QVBoxLayout(self)
        main_layout.addWidget(group_box)
        main_layout.addLayout(control_layout)
        # Для удобного доступа
        self.save_file_button = control_layout.next_button
        self.back_button = control_layout.back_button
        # Изменим надпись на кнопке на подходящую
        self.save_file_button.setText("Сохранить вариант моделирования")
예제 #3
0
class GetNodeDialog(QDialog):
    def __init__(self, parent, startnode, currentnode=None):
        QDialog.__init__(self, parent)

        layout = QVBoxLayout(self)
        
        self.treeview = QTreeView(self)
        self.treeview.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tree = TreeWidget(self.treeview)
        self.tree.set_root_node(startnode)
        layout.addWidget(self.treeview)

        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
            Qt.Horizontal, self)
        layout.addWidget(self.buttons)
        self.resize(800, 600)

        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.treeview.activated.connect(self.accept)

        if currentnode:
            self.tree.expand_to_node(currentnode)


    def get_node(self):
        return self.tree.get_current_node()

    @staticmethod
    def getNode(parent, startnode, currentnode=None):
        dialog = GetNodeDialog(parent, startnode, currentnode)
        result = dialog.exec_()
        node = dialog.get_node()
        return node, result == QDialog.Accepted
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QListView")
        self.setFixedWidth(310)
        self.setFixedHeight(200)

        data = [
            {"type": "Sword", "objects": ["Long Sword", "Short Sword"], "picture": "sword.png"},
            {"type": "Shield", "objects": ["Wood Shield", "iron Shied"], "picture": "shield.png"},
        ]

        self.layout = QBoxLayout(QBoxLayout.LeftToRight, self)
        self.setLayout(self.layout)

        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.model = Model(data)
        view.setModel(self.model)
        self.layout.addWidget(view)

        # 그림을 띄울 QLabel 생성
        self.lb = QLabel()
        self.lb.setFixedSize(50, 50)
        self.layout.addWidget(self.lb)

        # 뷰 클릭시 발생하는 시그널
        # 뷰를 클릭하면 QModelIndex를 넘겨준다.
        view.clicked.connect(self.slot_show_picture)
예제 #5
0
파일: views.py 프로젝트: spikespaz/archives
class BinaryDetailsDialog(QDialog):
    def __init__(self, data, *args, title=None, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self._data = data

        if not title:
            self.setWindowTitle(f"{self._data.binaries[0].binary_name} ({self._data.release_name})")

        self.setup_interface()

    def setup_interface(self):
        self.resize(600, 380)

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

        self.details_tree_model = BinaryDetailsTreeModel(self._data)
        self.details_tree_view = QTreeView()

        self.details_tree_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.details_tree_view.setAnimated(True)
        self.details_tree_view.setModel(self.details_tree_model)
        self.details_tree_view.expandAll()
        self.details_tree_view.resizeColumnToContents(0)
        self.details_tree_view.doubleClicked.connect(
            lambda index: QApplication.clipboard().setText(
                self.details_tree_model.data(index, Qt.DisplayRole)
            )
        )

        self.layout.addWidget(self.details_tree_view)
        self.setLayout(self.layout)
예제 #6
0
    def __initFilesView(self, model: QFileSystemModel):
        view = QTreeView()
        view.setEditTriggers(QTreeView.NoEditTriggers)
        view.hideColumn(1)
        view.hideColumn(3)
        view.setGeometry(0, 0, 10, 10)
        view.setModel(model)
        view.setRootIndex(model.index(str(model.rootDirectory())))

        return view
예제 #7
0
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QListView")
        box = QBoxLayout(QBoxLayout.TopToBottom)

        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)

        model = TreeModel(None)

        view.setModel(model)
        box.addWidget(view)
        self.setLayout(box)
def main():
    import sys
    app = QApplication(sys.argv)

    v = QTreeView()
    model = TreeModel(utils.find_data_file('disease_num2name.p'), 'Disease')
    v.setModel(model)
    v.selectionModel().select(
        QItemSelection(model.index(0, 0), model.index(5, 0)),
        QItemSelectionModel.Select)
    v.setSelectionMode(QAbstractItemView.NoSelection)
    v.setEditTriggers(QAbstractItemView.NoEditTriggers)
    v.show()
    app.exec()
예제 #9
0
    def __init__(self, *args):
        super().__init__(*args)

        self.__skip_next_hide = False

        tree_view = QTreeView(self)
        tree_view.setFrameShape(QFrame.NoFrame)
        tree_view.setEditTriggers(tree_view.NoEditTriggers)
        tree_view.setAlternatingRowColors(True)
        tree_view.setSelectionBehavior(tree_view.SelectRows)
        tree_view.setWordWrap(True)
        tree_view.setAllColumnsShowFocus(True)
        tree_view.setHeaderHidden(True)
        self.setView(tree_view)
        self.view().viewport().installEventFilter(self)
예제 #10
0
    def __init__(self, parent=None):
        super(TreeComboBox, self).__init__(parent)

        self.__skip_next_hide = False
        self._last_pick = None

        tree_view = QTreeView(self)
        tree_view.setFrameShape(QFrame.NoFrame)
        tree_view.setEditTriggers(tree_view.NoEditTriggers)
        tree_view.setAlternatingRowColors(True)
        tree_view.setSelectionBehavior(tree_view.SelectRows)
        tree_view.setWordWrap(True)
        tree_view.setAllColumnsShowFocus(True)
        self.setView(tree_view)

        self.view().viewport().installEventFilter(self)
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QTreeView")
        self.setFixedWidth(210)
        self.setFixedHeight(150)

        data = [
            {"type": "Sword", "objects": ["Long Sword", "Short Sword"], "picture": "sword.png"},
            {"type": "Shield", "objects": ["Wood Shield", "iron Shied"], "picture": "shield.png"},
        ]
        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)

        model = Model(data)
        view.setModel(model)
예제 #12
0
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QTreeView")
        self.setFixedWidth(300)
        self.setFixedHeight(700)

        # 데이터
        data = [
            {"type": "Fruit", "objects": ["Apple", "Banana"]},
            {"type": "Vegetable", "objects": ["Carrot", "Tomato"]},
        ]
        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)

        model = Model(data)
        view.setModel(model)
예제 #13
0
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QTreeView")
        self.setFixedWidth(210)
        self.setFixedHeight(150)

        # 데이터
        data = [
            {
                "type": "Fruit",
                "objects": [("Apple", "Red"), ("Banana", "Yellow")]
            },
        ]
        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)

        model = Model(data)
        view.setModel(model)
예제 #14
0
class MetadataList(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self._parent = parent
        #self.resize(100, 100)

        #sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        #sizePolicy.setHorizontalStretch(2)
        #sizePolicy.setVerticalStretch(0)
        #sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        #self.setSizePolicy(sizePolicy)

        self.mdataview = QTreeView()
        self.mdataview.setHeaderHidden(True)
        self.mdataview.setSortingEnabled(True)
        self.mdataview.setAlternatingRowColors(True)
        self.mdataview.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.mdataview.sortByColumn(0, Qt.AscendingOrder)  # Qt.DescendingOrder
        model = QStandardItemModel(0, 2)
        self.mdataview.setModel(model)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.mdataview)
        self.setLayout(layout)
        self.setVisible(True)         

    def setupDataMapper(self, treeview):
        self._dataMapper = treeview.dataMapper
        self._dataMapper.setItemDelegate(MetadataDelegate(self)) # self._parent.parent().parent().db
        self._dataMapper.addMapping(self.mdataview, 1)
        treeview.selectionModel().currentChanged.connect(self.setSelection)

    def setSelection(self, current):
        parent = current.parent()
        self._dataMapper.setRootIndex(parent)
        self._dataMapper.setCurrentModelIndex(current) 

    def clearData(self, layout=None):
        # NOT IMPLEMENTED----------------------------------------------
        if hasattr(self, "_dataMapper"):
            self._dataMapper.clearMapping()
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.setWindowTitle("ItemView QListView")
        box = QBoxLayout(QBoxLayout.TopToBottom)

        # 데이터
        data = [
            {
                "type": "Fruit",
                "objects": [("Apple", "Red"), ("Banana", "Yellow")]},
            {
                "type": "Vegetable",
                "objects": [("Carrot", "Red"), ("Tomato", "Red")]},
        ]
        # QTreeView 생성 및 설정
        view = QTreeView(self)
        view.setEditTriggers(QAbstractItemView.DoubleClicked)
        view.setItemDelegateForColumn(1, ComboBoxDelegate(["Red", "Yellow"]))

        model = Model(data)
        view.setModel(model)

        box.addWidget(view)
        self.setLayout(box)
class DriveAnalysisWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Drive Analysis Tool')
        # self.root_path = os.path.expanduser('~')  # BUG 2018-09-18: No permission to access certain files for os.stat
        self.root_path = os.path.expanduser('~\\Downloads')
        self.threadpool = QThreadPool()
        self.resize_mode = 'dynamic'

        select_btn = QPushButton('Select Folder', self)
        select_btn.setToolTip('Select <b>root folder</b> to simplify.')
        select_btn.clicked.connect(self.show_file_dialog)
        select_btn.resize(select_btn.sizeHint())

        test_btn = QPushButton('Test Scripts', self)
        test_btn.clicked.connect(self.run_tests)
        test_btn.resize(test_btn.sizeHint())

        self.folder_edit = QLabel()
        self.folder_edit.setText(self.root_path)

        self.status_label = QLabel()
        self.status_label.setText('')
        self.status_label.setStyleSheet("color: red;"
                                        "font: bold;")

        ogtree_label = QLabel()
        ogtree_label.setAlignment(Qt.AlignCenter)
        ogtree_label.setText('Original folders data')

        anontree_label = QLabel()
        anontree_label.setAlignment(Qt.AlignCenter)
        anontree_label.setText('Anonymized folders data used for research')

        self.ogtree = QTreeView(self)
        self.ogtree.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.ogmodel = QStandardItemModel()
        self.ogmodel.setHorizontalHeaderLabels(['Folder Name', 'Number of Files'])
        self.ogmodel.itemChanged.connect(self.on_item_change)

        self.anontree = QTreeView(self)
        self.anontree.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.anonmodel = QStandardItemModel()
        self.anonmodel.setHorizontalHeaderLabels(['Folder Name', 'Number of Files'])

        self.dir_dict, self.og_dir_dict = dict(), dict()
        self.build_tree_structure_threaded(self.root_path)

        grid = QGridLayout()
        grid.addWidget(select_btn, 0, 0, 1, 1)
        grid.addWidget(self.folder_edit, 0, 1, 1, 8)
        grid.addWidget(self.status_label, 1, 0, 1, 9)
        grid.addWidget(test_btn, 2, 0, 1, 1)
        grid.addWidget(ogtree_label, 3, 0, 1, 4)
        grid.addWidget(anontree_label, 3, 5, 1, 4)
        grid.addWidget(self.ogtree, 4, 0, 1, 4)
        grid.addWidget(self.anontree, 4, 5, 1, 4)

        self.setLayout(grid)
        self.resize(640, 480)
        self.show()

    def refresh_tree_header(self, tree, resize_mode='dynamic'):
        if resize_mode == 'dynamic':
            tree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
            tree.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
            # tree.header().setSectionResizeMode(2, QHeaderView.ResizeToContents)
        elif resize_mode == 'static':
            tree.header().setSectionResizeMode(0, QHeaderView.Interactive)
            tree.header().setSectionResizeMode(1, QHeaderView.Interactive)
            # tree.header().setSectionResizeMode(2, QHeaderView.Interactive)

    def show_file_dialog(self):
        dirpath = QFileDialog.getExistingDirectory(self, 'Select Folder', self.root_path)
        if dirpath:
            self.root_path = os.path.abspath(dirpath)
            self.folder_edit.setText(self.root_path)
            self.build_tree_structure_threaded(self.root_path, self.prune_thold)

    def build_tree_structure_threaded(self, root_path):
        worker = Worker(self.build_tree_structure, root_path)
        worker.signals.started.connect(self.build_tree_started)
        worker.signals.result.connect(self.build_tree_finished)
        self.threadpool.start(worker)

    def anonymize_tree_structure_threaded(self, root_path, dir_dict, rename_dict, remove_dict):
        worker = Worker(self.anonymize_tree_structure, root_path, dir_dict, rename_dict, remove_dict)
        worker.signals.started.connect(self.anonymize_tree_started)
        worker.signals.result.connect(self.anonymize_tree_finished)
        self.threadpool.start(worker)

    def build_tree_structure(self, root_path):
        # self.slider.setDisabled(True)
        dir_dict = record_stat(root_path)
        og_dir_dict = deepcopy(dir_dict)
        # dir_dict = simplify_tree(root_path, 1, dir_dict, 0.95, self.scale_pruning(prune_thold), print_=False)
        # self.slider.setEnabled(True)
        return og_dir_dict, dir_dict

    def anonymize_tree_structure(self, dir_dict, rename_dict, remove_dict):
        # dir_dict = simplify_tree(root_path, 1, dir_dict, 0.95, self.scale_pruning(prune_thold), print_=False)
        dir_dict = anonymize_stat(dir_dict, rename_dict, remove_dict)
        return dir_dict

    def build_tree_started(self):
        self.status_label.setText('Building tree, please wait...')

    def build_tree_finished(self, result):
        self.og_dir_dict, self.dir_dict = result
        # print(self.og_dir_dict[1],self.og_dir_dict[2], self.og_dir_dict[3])

        self.refresh_treeview(self.ogmodel, self.ogtree, self.og_dir_dict)
        # #BUG 2018-09-18: crashes the interface because i am referring to non-existent dictionary keys
        # (see append_all_children, e.g., dir_dict[dirkey][0])
        # I've updated my dir_dict to use string names instead of integers so append_all_children
        # needs to be updated as well.

        # self.refresh_treeview(self.anonmodel, self.anontree, self.dir_dict)
        self.status_label.setText('')

    def anonymize_tree_started(self):
        self.status_label.setText('Anonymizing tree, please wait...')

    def anonymize_tree_finished(self, dir_dict):
        self.refresh_treeview(self.anonmodel, self.anontree, dir_dict)
        self.status_label.setText('')

    def refresh_treeview(self, model, tree, dir_dict):
        model.removeRow(0)
        parent = model.invisibleRootItem()
        self.append_all_children(1, dir_dict, parent)  # dir_dict key starts at 1 since 0==False
        tree.setModel(model)
        self.refresh_tree_header(tree, self.resize_mode)
        tree.expandToDepth(0)

    def append_all_children(self, dirkey, dir_dict, qitem):
        qitem.setData(dirkey, Qt.UserRole)  # PAUSING HERE FOR NOW 20180918-1254
        print(dirkey, dir_dict[dirkey]['dirname'])
        # print(qitem.data(Qt.UserRole))
        dirname = QStandardItem(dir_dict[dirkey]['dirname'])
        nfiles = QStandardItem(str(dir_dict[dirkey]['nfiles']))
        # dirname.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
        # dirname.setData(QVariant(Qt.Checked), Qt.CheckStateRole)
        dirname.setCheckable(True)
        dirname.setCheckState(Qt.Checked)  # Qt.Checked == 2
        # dirname.setData(QVariant(str(dirkey)), role=Qt.UserRole+1)  # doesn't work
        # qitem.appendRow([QStandardItem(dir_dict[dirkey]['dirname']),
        #                  QStandardItem(str(dir_dict[dirkey]['nfiles']))])
        qitem.appendRow([dirname, nfiles, QStandardItem(str(dirkey))])
        current_row = qitem.rowCount() - 1
        print('Current row: ', current_row)
        print('dirkey for root: ', self.ogmodel.item(0).data(Qt.UserRole), qitem.data(Qt.UserRole))
        children_keys = dir_dict[dirkey]['childkeys']
        children_names = [dir_dict[child]['dirname'].lower() for child in children_keys]
        for child_name, child_key in sorted(zip(children_names, children_keys)):
            self.append_all_children(child_key, dir_dict, qitem.child(current_row))

    def on_item_change(self, qitem):
        # print(type(qitem))
        dirkey = qitem.data(Qt.UserRole)
        print(dirkey)
        # print(qitem.row(), qitem.column())
        # print(qitem.rowCount(), qitem.columnCount())
        # print(qitem.hasChildren())
        # print(qitem.parent())
        # print(qitem.text())
        # if qitem.hasChildren():  # doesn't work
        #     for child_item in qitem.sortChildren():
        #         self.on_item_change(child_item)
        # qitem.index(1, 1).setCheckState(check_state)
        # current_row = qitem.rowCount() - 1
        # print(qitem.sortChildren(1))
        # print(current_row)
        # print(qitem.checkState())

    def run_tests(self):
        print(self.ogtree.model().rowCount())
        for row in range(self.ogmodel.rowCount()):
            print(self.ogmodel.item(row).text(), self.ogmodel.item(row).data(Qt.UserRole))
            print(self.ogmodel.item(row).hasChildren())
예제 #17
0
class OWGeneSets(OWWidget):
    name = "Gene Sets"
    description = ""
    icon = "icons/OWGeneSets.svg"
    priority = 9
    want_main_area = True

    # settings
    selected_organism = Setting(0)
    auto_commit = Setting(True)
    auto_apply = Setting(True)

    gene_col_index = ContextSetting(0)
    use_attr_names = ContextSetting(False)

    class Inputs:
        genes = Input("Genes", Table)

    class Outputs:
        matched_genes = Output("Matched Genes", Table)

    class Information(OWWidget.Information):
        pass

    class Error(OWWidget.Error):
        cant_reach_host = Msg("Host orange.biolab.si is unreachable.")
        cant_load_organisms = Msg(
            "No available organisms, please check your connection.")

    def __init__(self):
        super().__init__()

        # commit
        self.commit_button = None

        # progress bar
        self.progress_bar = None
        self.progress_bar_iterations = None

        # data
        self.input_data = None
        self.tax_id = None
        self.input_genes = None
        self.mapped_genes = None
        self.organisms = list()
        self.input_info = None

        self.column_candidates = []

        # filter
        self.lineEdit_filter = None
        self.search_pattern = ''
        self.organism_select_combobox = None

        # data model view
        self.data_view = None
        self.data_model = None

        # gene matcher NCBI
        self.gene_matcher = None

        # filter proxy model
        self.filter_proxy_model = None

        # hierarchy widget
        self.hierarchy_widget = None
        self.hierarchy_state = None

        # input options
        self.gene_columns = None
        self.gene_column_combobox = None
        self.attr_names_checkbox = None

        # threads
        self.threadpool = QThreadPool(self)
        self.workers = None

        # gui
        self.setup_gui()
        self._get_available_organisms()

        # self.handle_input(self.input_genes)
        # self.on_organism_change()

    def _progress_advance(self):
        # GUI should be updated in main thread. That's why we are calling advance method here
        if self.progress_bar:
            self.progress_bar.advance()

    def _get_selected_organism(self):
        return self.organisms[self.selected_organism]

    def _get_available_organisms(self):
        available_organism = sorted([(tax_id, taxonomy.name(tax_id))
                                     for tax_id in taxonomy.common_taxids()],
                                    key=lambda x: x[1])

        self.organisms = [tax_id[0] for tax_id in available_organism]

        self.organism_select_combobox.addItems(
            [tax_id[1] for tax_id in available_organism])

    def _gene_names_from_table(self):
        """ Extract and return gene names from `Orange.data.Table`.
        """
        self.input_genes = []
        if self.input_data:
            if self.use_attr_names:
                self.input_genes = [
                    str(attr.name).strip()
                    for attr in self.input_data.domain.attributes
                ]
            elif self.gene_columns:
                column = self.gene_columns[self.gene_col_index]
                self.input_genes = [
                    str(e[column]) for e in self.input_data
                    if not np.isnan(e[column])
                ]

    def _update_gene_matcher(self):
        self._gene_names_from_table()
        if self.gene_matcher:
            self.gene_matcher.genes = self.input_genes
            self.gene_matcher.organism = self._get_selected_organism()

    def on_input_option_change(self):
        self._update_gene_matcher()
        self.match_genes()

    @Inputs.genes
    def handle_input(self, data):
        if data:
            self.input_data = data
            self.gene_matcher = gene.GeneMatcher(self._get_selected_organism())

            self.gene_column_combobox.clear()
            self.column_candidates = [
                attr for attr in data.domain.variables + data.domain.metas
                if isinstance(attr, (StringVariable, DiscreteVariable))
            ]

            for var in self.column_candidates:
                self.gene_column_combobox.addItem(*attributeItem(var))

            self.tax_id = str(data_hints.get_hint(self.input_data, TAX_ID))
            self.use_attr_names = data_hints.get_hint(
                self.input_data, GENE_NAME, default=self.use_attr_names)
            self.gene_col_index = min(self.gene_col_index,
                                      len(self.column_candidates) - 1)

            if self.tax_id in self.organisms:
                self.selected_organism = self.organisms.index(self.tax_id)

        self.on_input_option_change()

    def update_info_box(self):
        info_string = ''
        if self.input_genes:
            info_string += '{} unique gene names on input.\n'.format(
                len(self.input_genes))
            mapped = self.gene_matcher.get_known_genes()
            if mapped:
                ratio = (len(mapped) / len(self.input_genes)) * 100
                info_string += '{} ({:.2f}%) gene names matched.\n'.format(
                    len(mapped), ratio)
        else:
            info_string += 'No genes on input.\n'

        self.input_info.setText(info_string)

    def match_genes(self):
        if self.gene_matcher:
            # init progress bar
            self.progress_bar = ProgressBar(self,
                                            iterations=len(
                                                self.gene_matcher.genes))
            # status message
            self.setStatusMessage('gene matcher running')

            worker = Worker(self.gene_matcher.run_matcher,
                            progress_callback=True)
            worker.signals.progress.connect(self._progress_advance)
            worker.signals.finished.connect(self.handle_matcher_results)

            # move download process to worker thread
            self.threadpool.start(worker)

    def handle_matcher_results(self):
        assert threading.current_thread() == threading.main_thread()
        if self.progress_bar:
            self.progress_bar.finish()
            self.setStatusMessage('')

        if self.gene_matcher.map_input_to_ncbi():
            self.download_gene_sets()
            self.update_info_box()
        else:
            # reset gene sets
            self.init_item_model()
            self.update_info_box()

    def on_gene_sets_download(self, result):
        # make sure this happens in the main thread.
        # Qt insists that widgets be created within the GUI(main) thread.
        assert threading.current_thread() == threading.main_thread()
        self.progress_bar.finish()
        self.setStatusMessage('')

        tax_id, sets = result
        self.set_hierarchy_model(self.hierarchy_widget,
                                 *hierarchy_tree(tax_id, sets))

        self.organism_select_combobox.setEnabled(True)  # re-enable combobox

        self.update_info_box()
        self.mapped_genes = self.gene_matcher.map_input_to_ncbi()
        self.workers = defaultdict(list)
        self.progress_bar_iterations = dict()

        for selected_hierarchy in [*self.get_hierarchies()]:
            gene_sets = geneset.load_gene_sets(selected_hierarchy)
            worker = Worker(get_collections,
                            gene_sets,
                            self.mapped_genes,
                            progress_callback=True,
                            partial_result=True)
            worker.signals.error.connect(self.handle_error)
            worker.signals.finished.connect(self.handle_worker_finished)
            worker.signals.progress.connect(self._progress_advance)
            worker.signals.partial_result.connect(self.populate_data_model)
            worker.setAutoDelete(False)

            self.workers[selected_hierarchy] = worker
            self.progress_bar_iterations[selected_hierarchy] = len(gene_sets)

    def handle_worker_finished(self):
        # We check if all workers have completed. If not, continue
        # dirty hax, is this ok?
        if self.progress_bar and self.progress_bar.widget.progressBarValue == 100:
            self.progress_bar.finish()
            self.setStatusMessage('')
            self.hierarchy_widget.setDisabled(False)

            # adjust column width
            for i in range(len(DATA_HEADER_LABELS) - 1):

                self.data_view.resizeColumnToContents(i)

            self.filter_proxy_model.setSourceModel(self.data_model)

    def populate_data_model(self, partial_result):
        assert threading.current_thread() == threading.main_thread()

        if partial_result:
            self.data_model.appendRow(partial_result)

    def set_hierarchy_model(self, model, tax_id, sets):
        # TODO: maybe optimize this code?
        for key, value in sets.items():
            item = QTreeWidgetItem(model, [key])
            item.setFlags(item.flags()
                          & (Qt.ItemIsUserCheckable | ~Qt.ItemIsSelectable
                             | Qt.ItemIsEnabled))
            # item.setDisabled(True)
            item.setData(0, Qt.CheckStateRole, Qt.Unchecked)
            item.setExpanded(True)
            item.tax_id = tax_id
            item.hierarchy = key

            if value:
                item.setFlags(item.flags() | Qt.ItemIsTristate)
                self.set_hierarchy_model(item, tax_id, value)
            else:
                if item.parent():
                    item.hierarchy = ((item.parent().hierarchy, key), tax_id)

            if not item.childCount() and not item.parent():
                item.hierarchy = ((key, ), tax_id)

    def download_gene_sets(self):
        tax_id = self._get_selected_organism()

        self.Error.clear()
        # do not allow user to change organism when download task is running
        self.organism_select_combobox.setEnabled(False)
        # reset hierarchy widget state
        self.hierarchy_widget.clear()
        # clear data view
        self.init_item_model()

        # get all gene sets for selected organism
        gene_sets = geneset.list_all(organism=tax_id)
        # init progress bar
        self.progress_bar = ProgressBar(self, iterations=len(gene_sets) * 100)
        # status message
        self.setStatusMessage('downloading sets')

        worker = Worker(download_gene_sets, gene_sets, progress_callback=True)
        worker.signals.progress.connect(self._progress_advance)
        worker.signals.result.connect(self.on_gene_sets_download)
        worker.signals.error.connect(self.handle_error)

        # move download process to worker thread
        self.threadpool.start(worker)

    def display_gene_sets(self):
        self.init_item_model()
        self.hierarchy_widget.setDisabled(True)

        only_selected_hier = [*self.get_hierarchies(only_selected=True)]

        # init progress bar
        iterations = sum([
            self.progress_bar_iterations[hier] for hier in only_selected_hier
        ])
        self.progress_bar = ProgressBar(self, iterations=iterations)
        self.setStatusMessage('displaying gene sets')

        if not only_selected_hier:
            self.progress_bar.finish()
            self.setStatusMessage('')
            self.hierarchy_widget.setDisabled(False)
            return

        for selected_hierarchy in only_selected_hier:
            self.threadpool.start(self.workers[selected_hierarchy])

    def handle_error(self, ex):
        self.progress_bar.finish()
        self.setStatusMessage('')

        if isinstance(ex, ConnectionError):
            self.organism_select_combobox.setEnabled(
                True)  # re-enable combobox
            self.Error.cant_reach_host()

        print(ex)

    def get_hierarchies(self, **kwargs):
        """ return selected hierarchy
        """
        only_selected = kwargs.get('only_selected', None)

        sets_to_display = list()

        if only_selected:
            iterator = QTreeWidgetItemIterator(self.hierarchy_widget,
                                               QTreeWidgetItemIterator.Checked)
        else:
            iterator = QTreeWidgetItemIterator(self.hierarchy_widget)

        while iterator.value():
            # note: if hierarchy value is not a tuple, then this is just top level qTreeWidgetItem that
            #       holds subcategories. We don't want to display all sets from category
            if type(iterator.value().hierarchy) is not str:

                if not only_selected:
                    sets_to_display.append(iterator.value().hierarchy)
                else:
                    if not iterator.value().isDisabled():
                        sets_to_display.append(iterator.value().hierarchy)

            iterator += 1

        return sets_to_display

    def commit(self):
        selection_model = self.data_view.selectionModel()

        if selection_model:
            # genes_from_set = selection_model.selectedRows(GENES)
            matched_genes = selection_model.selectedRows(MATCHED)

            if matched_genes and self.input_genes:
                genes = [
                    model_index.data(Qt.UserRole)
                    for model_index in matched_genes
                ]
                output_genes = [
                    gene_name for gene_name in list(set.union(*genes))
                ]
                input_to_ncbi = self.gene_matcher.map_input_to_ncbi()
                ncbi_to_input = {
                    ncbi_id: input_name
                    for input_name, ncbi_id in
                    self.gene_matcher.map_input_to_ncbi().items()
                }

                if self.use_attr_names:
                    selected = [
                        self.input_data.domain[ncbi_to_input[output_gene]]
                        for output_gene in output_genes
                    ]
                    domain = Domain(selected,
                                    self.input_data.domain.class_vars,
                                    self.input_data.domain.metas)
                    new_data = self.input_data.from_table(
                        domain, self.input_data)
                    self.Outputs.matched_genes.send(new_data)

                elif self.column_candidates:
                    column = self.column_candidates[self.gene_col_index]
                    selected_rows = []

                    for row_index, row in enumerate(self.input_data):
                        if str(row[column]) in input_to_ncbi.keys(
                        ) and input_to_ncbi[str(row[column])] in output_genes:
                            selected_rows.append(row_index)
                    if selected_rows:
                        selected = self.input_data[selected_rows]
                    else:
                        selected = None
                    self.Outputs.matched_genes.send(selected)

    def setup_gui(self):
        # control area
        info_box = vBox(self.controlArea, 'Input info')
        self.input_info = widgetLabel(info_box)

        organism_box = vBox(self.controlArea, 'Organisms')
        self.organism_select_combobox = comboBox(
            organism_box,
            self,
            'selected_organism',
            callback=self.on_input_option_change)

        # Selection of genes attribute
        box = widgetBox(self.controlArea, 'Gene attribute')
        self.gene_columns = itemmodels.VariableListModel(parent=self)
        self.gene_column_combobox = comboBox(
            box, self, 'gene_col_index', callback=self.on_input_option_change)
        self.gene_column_combobox.setModel(self.gene_columns)

        self.attr_names_checkbox = checkBox(
            box,
            self,
            'use_attr_names',
            'Use attribute names',
            disables=[(-1, self.gene_column_combobox)],
            callback=self.on_input_option_change)

        self.gene_column_combobox.setDisabled(bool(self.use_attr_names))

        hierarchy_box = widgetBox(self.controlArea, "Entity Sets")
        self.hierarchy_widget = QTreeWidget(self)
        self.hierarchy_widget.setEditTriggers(QTreeView.NoEditTriggers)
        self.hierarchy_widget.setHeaderLabels(HIERARCHY_HEADER_LABELS)
        self.hierarchy_widget.itemClicked.connect(self.display_gene_sets)
        hierarchy_box.layout().addWidget(self.hierarchy_widget)

        self.commit_button = auto_commit(self.controlArea,
                                         self,
                                         "auto_commit",
                                         "&Commit",
                                         box=False)

        # rubber(self.controlArea)

        # main area
        self.filter_proxy_model = QSortFilterProxyModel(self.data_view)
        self.filter_proxy_model.setFilterKeyColumn(3)

        self.data_view = QTreeView()
        self.data_view.setModel(self.filter_proxy_model)
        self.data_view.setAlternatingRowColors(True)
        self.data_view.setSortingEnabled(True)
        self.data_view.setSelectionMode(QTreeView.ExtendedSelection)
        self.data_view.setEditTriggers(QTreeView.NoEditTriggers)
        self.data_view.viewport().setMouseTracking(True)
        self.data_view.setItemDelegateForColumn(
            TERM, LinkStyledItemDelegate(self.data_view))

        self.data_view.selectionModel().selectionChanged.connect(self.commit)

        self.lineEdit_filter = lineEdit(self.mainArea, self, 'search_pattern',
                                        'Filter gene sets:')
        self.lineEdit_filter.setPlaceholderText('search pattern ...')
        self.lineEdit_filter.textChanged.connect(
            self.filter_proxy_model.setFilterRegExp)

        self.mainArea.layout().addWidget(self.data_view)

    def init_item_model(self):
        if self.data_model:
            self.data_model.clear()
            self.filter_proxy_model.setSourceModel(None)
        else:
            self.data_model = QStandardItemModel()

        self.data_model.setSortRole(Qt.UserRole)
        self.data_model.setHorizontalHeaderLabels(DATA_HEADER_LABELS)

    def sizeHint(self):
        return QSize(1280, 960)
예제 #18
0
파일: TransCodaEditor.py 프로젝트: ag-sd/py
class EncoderSelector(QComboBox):
    __PATH_SEPARATOR__ = " → "
    _PATH_ROLE = 1
    _DETAILS_ROLE = 2

    class EncoderModel(QStandardItemModel):
        def __init__(self, json_file, disable_selections=False):
            super().__init__()
            self.disable_selections = disable_selections
            self.json_file = json_file
            self.json = None
            self.reload()

        def reload(self):
            with open(self.json_file) as config:
                self.json = json.load(config)
                self.beginResetModel()
                self.clear()
                self._build_descendents(self.invisibleRootItem(), self.json,
                                        self.disable_selections)
                self.endResetModel()

        def get_item(self, model_index):
            item = self.itemFromIndex(model_index)
            if item:
                return item.text()
            return None

        def del_item(self, media_type, encoder_group, name):
            del self.json[media_type][encoder_group][name]
            # Clean up ancestors if they dont have any children
            if len(self.json[media_type][encoder_group].keys()) == 0:
                del self.json[media_type][encoder_group]
            if len(self.json[media_type].keys()) == 0:
                del self.json[media_type]

        def add_item(self, media_type, group, name, extension, executable,
                     command):
            if media_type not in self.json:
                self.json[media_type] = {}
            if group not in self.json[media_type]:
                self.json[media_type][group] = {}
            self.json[media_type][group][name] = {
                "extension": extension,
                "executable": executable,
                "command": command
            }

        def backup_and_save(self):
            # Backup current config
            backup_config_file()
            # Save new config
            with open(self.json_file, "w") as config:
                json.dump(self.json, config, indent=4)
            self.reload()

        @staticmethod
        def _build_descendents(parent, _json, disable_selections):
            encoder_keys = {"extension", "executable", "command"}
            intersection = set(_json.keys()) & encoder_keys
            if not intersection:
                # add node and build further
                for key in _json:
                    section_root = QStandardItem(key)
                    parent.appendRow(section_root)
                    if disable_selections:
                        parent.setSelectable(False)
                    EncoderSelector.EncoderModel._build_descendents(
                        section_root, _json[key], disable_selections)
            else:
                if len(intersection) < 3:
                    raise SyntaxError(
                        f"Missing value(s) {encoder_keys - intersection} in node {parent.text()}"
                    )
                else:
                    path = ""
                    item = parent
                    while item.parent() is not None:
                        path = f"{EncoderSelector.__PATH_SEPARATOR__}{item.text()}" + path
                        item = item.parent()
                    path = f"{item.text()}" + path
                    parent.setData(path,
                                   Qt.UserRole + EncoderSelector._PATH_ROLE)
                    parent.setData(_json,
                                   Qt.UserRole + EncoderSelector._DETAILS_ROLE)

    encoder_changed = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')

    def __init__(self):
        super().__init__()
        self.tree_view = QTreeView(self)
        self.tree_view.setEditTriggers(QTreeView.NoEditTriggers)
        self.tree_view.setSelectionBehavior(QTreeView.SelectRows)
        self.tree_view.setWordWrap(True)
        self.tree_view.setHeaderHidden(True)
        self.setView(self.tree_view)
        self.encoder_model = EncoderSelector.EncoderModel(
            get_config_file(), disable_selections=True)
        self.setModel(self.encoder_model)
        self.refresh_encoders()
        self._selected_encoder = ""

    def paintEvent(self, event):
        style = QApplication.style()
        opt = QStyleOptionComboBox()
        opt.rect = self.rect()
        self.initStyleOption(opt)
        painter = QPainter(self)
        painter.save()
        style.drawComplexControl(QStyle.CC_ComboBox, opt, painter)
        opt.currentText = self._encoder_path()
        style.drawControl(QStyle.CE_ComboBoxLabel, opt, painter)
        painter.restore()

    def hidePopup(self):
        super(EncoderSelector, self).hidePopup()
        selected_index = self.tree_view.selectionModel().currentIndex()
        if selected_index:
            encoder = self.tree_view.model().get_item(selected_index)
            if encoder:
                self._selected_encoder = encoder
                self.encoder_changed.emit(self._encoder_path(),
                                          self._encoder_details())

    def get_encoder(self):
        return self._encoder_path(), self._encoder_details()

    def add_encoder(self, media_type, encoder_group, name, command, executable,
                    extension):
        self.encoder_model.add_item(media_type, encoder_group, name, extension,
                                    executable, command)
        self.encoder_model.backup_and_save()
        self.refresh_encoders()

    def del_encoder(self, media_type, encoder_group, name):
        self.encoder_model.del_item(media_type, encoder_group, name)
        self.encoder_model.backup_and_save()
        self.refresh_encoders()

    def update_encoder(self, media_type, encoder_group, name, command,
                       executable, extension):
        self.encoder_model.del_item(media_type, encoder_group, name)
        self.encoder_model.add_item(media_type, encoder_group, name, extension,
                                    executable, command)
        self.encoder_model.backup_and_save()
        self.refresh_encoders()

    def refresh_encoders(self):
        self.encoder_model.reload()
        self.tree_view.expandAll()

    def select_encoder(self, encoder_name):
        match = self._find_encoder(encoder_name)
        if match:
            self._selected_encoder = encoder_name
        self.encoder_changed.emit(self._encoder_path(),
                                  self._encoder_details())

    def _encoder_path(self):
        if self._selected_encoder:
            match = self._find_encoder(self._selected_encoder)
            if match:
                return match[0].data(Qt.UserRole + self._PATH_ROLE)
        return None

    def _encoder_details(self):
        if self._selected_encoder:
            match = self._find_encoder(self._selected_encoder)
            if match:
                return match[0].data(Qt.UserRole + self._DETAILS_ROLE)
        return None

    def _find_encoder(self, encoder_name):
        return self.model().match(self.model().index(0, 0),
                                  Qt.UserRole + self._PATH_ROLE, encoder_name,
                                  1, Qt.MatchEndsWith | Qt.MatchRecursive)
예제 #19
0
class StandardLibraryPage(QSplitter):
    """ The GUI for the standard library page of a project. """

    # The page's label.
    label = "Standard Library"

    @property
    def project(self):
        """ The project property getter. """

        return self._project

    @project.setter
    def project(self, value):
        """ The project property setter. """

        if self._project != value:
            self._project = value

            self._update_page()

    def __init__(self):
        """ Initialise the page. """

        super().__init__()

        self._project = None

        # Create the page's GUI.
        stdlib_pane = QWidget()
        stdlib_layout = QVBoxLayout()

        self._stdlib_edit = QTreeWidget(
                whatsThis="This shows the packages and modules in the target "
                        "Python version's standard library. Check those "
                        "packages and modules that are explicitly imported by "
                        "the application. A module will be partially checked "
                        "(and automatically included) if another module "
                        "requires it.")
        self._stdlib_edit.setHeaderLabels(["Package"])
        self._stdlib_edit.itemChanged.connect(self._module_changed)

        stdlib_layout.addWidget(self._stdlib_edit)

        stdlib_pane.setLayout(stdlib_layout)
        self.addWidget(stdlib_pane)

        extlib_pane = QWidget()
        extlib_layout = QVBoxLayout()
        extlib_sublayout = QFormLayout()

        self._version_edit = QComboBox(
                whatsThis="Select the target Python version. This will cause "
                        "the standard library package hierarchy to be "
                        "updated.")
        self._version_edit.addItems(get_supported_python_versions())
        self._version_edit.currentIndexChanged.connect(self._version_changed)
        extlib_sublayout.addRow("Target Python version", self._version_edit)

        self._ssl_edit = QCheckBox(
                whatsThis="Enable SSL for the standard library modules "
                        "that have optional support for it.",
                stateChanged=self._ssl_changed)
        extlib_sublayout.addRow("Enable optional SSL support", self._ssl_edit)

        extlib_layout.addLayout(extlib_sublayout)

        plat_gb = QGroupBox("Use standard Python shared library")
        plat_gb_layout = QVBoxLayout()
        self._platform_buttons = []

        for scope, plat, subscopes in PLATFORM_SCOPES:
            plat_cb = QCheckBox(plat,
                    whatsThis="Enable the use of the standard Python shared "
                            "library on {0} rather than a statically compiled "
                            "library.".format(plat),
                    stateChanged=self._platforms_changed)
            plat_cb._scope = scope
            plat_gb_layout.addWidget(plat_cb)
            self._platform_buttons.append(plat_cb)

        plat_gb.setLayout(plat_gb_layout)
        extlib_layout.addWidget(plat_gb)

        self._extlib_edit = QTreeView(
                whatsThis="This is the list of external libraries that must "
                        "be linked with the application. A library will only "
                        "be enabled if a module in the standard library uses "
                        "it. Double-click in the <b>DEFINES</b>, "
                        "<b>INCLUDEPATH</b> and <b>LIBS</b> columns to modify "
                        "the corresponding <tt>qmake</tt> variable as "
                        "required. Values may be prefixed by a platform "
                        "specific <tt>qmake</tt> scope.")
        self._extlib_edit.setRootIsDecorated(False)
        self._extlib_edit.setEditTriggers(
                QTreeView.DoubleClicked|QTreeView.SelectedClicked|
                QTreeView.EditKeyPressed)

        model = QStandardItemModel(self._extlib_edit)
        model.setHorizontalHeaderLabels(
                ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS'))
        model.itemChanged.connect(self._extlib_changed)

        for extlib in external_libraries_metadata:
            name_itm = QStandardItem(extlib.user_name)

            extlib._items = (name_itm, QStandardItem(), QStandardItem(),
                    QStandardItem())

            model.appendRow(extlib._items)

        self._extlib_edit.setModel(model)

        for col in range(3):
            self._extlib_edit.resizeColumnToContents(col)

        extlib_layout.addWidget(self._extlib_edit)

        self._ignore_extlib_changes = False

        extlib_pane.setLayout(extlib_layout)
        self.addWidget(extlib_pane)

    def _update_page(self):
        """ Update the page using the current project. """

        project = self.project

        blocked = self._version_edit.blockSignals(True)
        self._version_edit.setCurrentIndex(
                get_supported_python_version_index(
                        project.python_target_version))
        self._version_edit.blockSignals(blocked)

        blocked = self._ssl_edit.blockSignals(True)
        self._ssl_edit.setCheckState(
                Qt.Checked if project.python_ssl else Qt.Unchecked)
        self._ssl_edit.blockSignals(blocked)

        for plat in self._platform_buttons:
            blocked = plat.blockSignals(True)
            plat.setCheckState(
                    Qt.Checked if plat._scope in project.python_use_platform
                            else Qt.Unchecked)
            plat.blockSignals(blocked)

        self._update_extlib_editor()
        self._update_stdlib_editor()

    def _update_stdlib_editor(self):
        """ Update the standard library module editor. """

        project = self.project
        editor = self._stdlib_edit

        metadata = get_python_metadata(project.python_target_version)

        blocked = editor.blockSignals(True)

        editor.clear()

        def add_module(name, module, parent):
            itm = QTreeWidgetItem(parent, name.split('.')[-1:])
            itm.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
            itm._name = name

            # Handle any sub-modules.
            if module.modules is not None:
                for submodule_name in module.modules:
                    # We assume that a missing sub-module is because it is not
                    # in the current version rather than bad meta-data.
                    submodule = metadata.get(submodule_name)
                    if submodule is not None:
                        add_module(submodule_name, submodule, itm)

        for name, module in metadata.items():
            if not module.internal and '.' not in name:
                add_module(name, module, editor)

        editor.sortItems(0, Qt.AscendingOrder)

        editor.blockSignals(blocked)

        self._set_dependencies()

    def _set_dependencies(self):
        """ Set the dependency information. """

        project = self.project
        editor = self._stdlib_edit

        required_modules, required_libraries = project.get_stdlib_requirements()

        blocked = editor.blockSignals(True)

        it = QTreeWidgetItemIterator(editor)
        itm = it.value()
        while itm is not None:
            external = required_modules.get(itm._name)
            expanded = False
            if external is None:
                state = Qt.Unchecked
            elif external:
                state = Qt.Checked
                expanded = True
            else:
                state = Qt.PartiallyChecked

            itm.setCheckState(0, state)

            # Make sure every explicitly checked item is visible.
            if expanded:
                parent = itm.parent()
                while parent is not None:
                    parent.setExpanded(True)
                    parent = parent.parent()

            it += 1
            itm = it.value()

        editor.blockSignals(blocked)

        model = self._extlib_edit.model()

        # Note that we can't simply block the model's signals as this would
        # interfere with the model/view interactions.
        self._ignore_extlib_changes = True

        for extlib in external_libraries_metadata:
            if extlib.name in required_libraries:
                for idx, itm in enumerate(extlib._items):
                    itm.setFlags(
                            Qt.ItemIsEnabled|Qt.ItemIsEditable if idx != 0
                                    else Qt.ItemIsEnabled)
            else:
                for itm in extlib._items:
                    itm.setFlags(Qt.NoItemFlags)

        self._ignore_extlib_changes = False

    def _update_extlib_editor(self):
        """ Update the external library editor. """

        project = self.project
        model = self._extlib_edit.model()

        blocked = model.blockSignals(True)

        for extlib in external_libraries_metadata:
            _, defs, incp, libs = extlib._items

            for prj_extlib in project.external_libraries:
                if prj_extlib.name == extlib.name:
                    defs.setText(prj_extlib.defines)
                    incp.setText(prj_extlib.includepath)
                    libs.setText(prj_extlib.libs)
                    break
            else:
                defs.setText('')
                incp.setText('')
                libs.setText(extlib.libs)

        model.blockSignals(blocked)

    def _version_changed(self, idx):
        """ Invoked when the target Python version changes. """

        project = self.project

        project.python_target_version = get_supported_python_version(idx)
        self._update_page()

        project.modified = True

    def _ssl_changed(self, state):
        """ Invoked when the SSL support changes. """

        project = self.project

        project.python_ssl = (state == Qt.Checked)
        self._set_dependencies()

        project.modified = True

    def _platforms_changed(self, state):
        """ Invoked when the platforms change. """

        project = self._project

        project.python_use_platform = []

        for plat in self._platform_buttons:
            if plat.checkState() == Qt.Checked:
                project.python_use_platform.append(plat._scope)

        project.modified = True

    def _module_changed(self, itm, col):
        """ Invoked when a standard library module has changed. """

        project = self._project
        name = itm._name

        if name in project.standard_library:
            project.standard_library.remove(name)
        else:
            project.standard_library.append(name)

        self._set_dependencies()

        project.modified = True

    def _extlib_changed(self, itm):
        """ Invoked when an external library has changed. """

        if self._ignore_extlib_changes:
            return

        self._ignore_extlib_changes = True

        project = self.project

        idx = self._extlib_edit.model().indexFromItem(itm)
        extlib = external_libraries_metadata[idx.row()]
        col = idx.column()

        # Get the project entry, creating it if necessary.
        for prj_extlib in project.external_libraries:
            if prj_extlib.name == extlib.name:
                break
        else:
            prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.libs)
            project.external_libraries.append(prj_extlib)

        # Update the project.
        text = itm.text().strip()

        if col == 1:
            prj_extlib.defines = text
        elif col == 2:
            prj_extlib.includepath = text
        elif col == 3:
            if text == '':
                text = extlib.libs
                itm.setText(text)

            prj_extlib.libs = text

        # If the project entry corresponds to the default then remove it.
        if prj_extlib.defines == '' and prj_extlib.includepath == '' and prj_extlib.libs == extlib.libs:
            project.external_libraries.remove(prj_extlib)

        project.modified = True

        self._ignore_extlib_changes = False
예제 #20
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        dockWidget = QDockWidget("Explorer", self)

        self.editor = QPlainTextEdit()
        self.editor.document().setDefaultFont(QFont("monospace"))
        self.editor.zoomIn(2)

        self.explorer = QTreeView()
        self.model = QFileSystemModel(self.explorer)
        self.root = self.model.setRootPath("../..")
        self.explorer.setModel(self.model)
        self.explorer.setRootIndex(self.root)
        self.file_path = None

        # Instances of menus and message
        self.custom_menu = Custom_menu(self, self.explorer, self.model,
                                       self.editor, app)
        self.menu = Menu(self, self.explorer, self.editor, self.model)
        self.message = Message(self)

        # Menu bar
        self.file_menu = self.menuBar().addMenu("&File")
        self.help_menu = self.menuBar().addMenu("&Help")
        self.menu.menu_actions()

        # Other custom tweaks
        self.explorer.setSortingEnabled(True)
        self.explorer.setMinimumWidth(400)
        self.explorer.setContextMenuPolicy(Qt.CustomContextMenu)
        self.resize(1500, 900)

        # Enabling renaming on context menu
        self.model.setReadOnly(False)
        self.explorer.setEditTriggers(self.explorer.NoEditTriggers)

        # Change default explorers column width
        self.header = self.explorer.header()
        self.header.setSectionResizeMode(0, QHeaderView.Interactive)
        self.header.setDefaultSectionSize(200)
        self.header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.header.setSectionResizeMode(2, QHeaderView.ResizeToContents)

        # Setting editor as central widget
        self.setCentralWidget(self.editor)
        self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget)

        # Setting view as widget of dock widget
        dockWidget.setWidget(self.explorer)
        dockWidget.setFloating(False)

        ### Double & right click
        self.explorer.doubleClicked.connect(self.custom_menu.on_double_click)
        self.explorer.customContextMenuRequested.connect(
            self.custom_menu.context_menu)

    def closeEvent(self, e):
        """This function prevents from closing without saving,
		 it works with the "Close" event"""

        if not self.editor.document().isModified():
            return
        answer = self.message.ask_for_confirmation()
        if answer == QMessageBox.Save:
            if not self.menu.save():
                e.ignore()
        elif answer == QMessageBox.Cancel:
            e.ignore()
예제 #21
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """

    def __init__(self, workspace):
        DockWidget.__init__(self, workspace, "&Opened Files", QIcon(":/enkiicons/filtered.png"), "Alt+O")

        self._workspace = workspace

        self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        self.tvFiles = QTreeView(self)
        self.tvFiles.setHeaderHidden(True)
        self.tvFiles.setEditTriggers(QAbstractItemView.SelectedClicked)
        self.tvFiles.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tvFiles.setDragEnabled(True)
        self.tvFiles.setDragDropMode(QAbstractItemView.InternalMove)
        self.tvFiles.setRootIsDecorated(False)
        self.tvFiles.setTextElideMode(Qt.ElideMiddle)
        self.tvFiles.setUniformRowHeights(True)

        self.tvFiles.customContextMenuRequested.connect(self._onTvFilesCustomContextMenuRequested)

        self.setWidget(self.tvFiles)
        self.setFocusProxy(self.tvFiles)

        self.model = _OpenedFileModel(self)  # Not protected, because used by Configurator
        self.tvFiles.setModel(self.model)
        self.tvFiles.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.tvFiles.setAttribute(Qt.WA_MacSmallSize)

        self._workspace.currentDocumentChanged.connect(self._onCurrentDocumentChanged)

        # disconnected by startModifyModel()
        self.tvFiles.selectionModel().selectionChanged.connect(self._onSelectionModelSelectionChanged)

        self.tvFiles.activated.connect(self._workspace.focusCurrentDocument)

        core.actionManager().addAction("mView/aOpenedFiles", self.showAction())

    def terminate(self):
        """Explicitly called destructor
        """
        core.actionManager().removeAction("mView/aOpenedFiles")

    def startModifyModel(self):
        """Blocks signals from model while it is modified by code
        """
        self.tvFiles.selectionModel().selectionChanged.disconnect(self._onSelectionModelSelectionChanged)

    def finishModifyModel(self):
        """Unblocks signals from model
        """
        self.tvFiles.selectionModel().selectionChanged.connect(self._onSelectionModelSelectionChanged)

    @pyqtSlot(Document, Document)
    def _onCurrentDocumentChanged(self, oldDocument, currentDocument):  # pylint: disable=W0613
        """ Current document has been changed on workspace
        """
        if currentDocument is not None:
            index = self.model.documentIndex(currentDocument)

            self.startModifyModel()
            self.tvFiles.setCurrentIndex(index)
            # scroll the view
            self.tvFiles.scrollTo(index)
            self.finishModifyModel()

    @pyqtSlot(QItemSelection, QItemSelection)
    def _onSelectionModelSelectionChanged(self, selected, deselected):  # pylint: disable=W0613
        """ Item selected in the list. Switch current document
        """
        if not selected.indexes():  # empty list, last file closed
            return

        index = selected.indexes()[0]
        # backup/restore current focused widget as setting active mdi window will steal it
        focusWidget = self.window().focusWidget()

        # set current document
        document = self._workspace.sortedDocuments[index.row()]
        self._workspace.setCurrentDocument(document)

        # restore focus widget
        if focusWidget:
            focusWidget.setFocus()

    @pyqtSlot(QPoint)
    def _onTvFilesCustomContextMenuRequested(self, pos):
        """Connected automatically by uic
        """
        menu = QMenu()

        menu.addAction(core.actionManager().action("mFile/mClose/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mSave/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mReload/aCurrent"))
        menu.addSeparator()
        menu.addAction(core.actionManager().action("mFile/mFileSystem/aRename"))
        toggleExecutableAction = core.actionManager().action("mFile/mFileSystem/aToggleExecutable")
        if toggleExecutableAction:  # not available on Windows
            menu.addAction(toggleExecutableAction)
        core.actionManager().action("mFile/mFileSystem").menu().aboutToShow.emit()  # to update aToggleExecutable

        menu.exec_(self.tvFiles.mapToGlobal(pos))
예제 #22
0
class ZoomerWidget(QWidget):

    def __init__(self, parent=None):
        # super().__init__()
        # self.initUI()
        super(ZoomerWidget, self).__init__(parent)
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.setWindowTitle('GIMZoomer')
        # self.prune_thold = 95  # only use when slider scroll direction is reversed
        self.prune_thold = 4
        # self.root_path = os.path.expanduser('~')
        self.root_path = os.path.expanduser('C:\\Users\\ultra\\Dropbox\\mcgill')
        # self.root_path = os.path.expanduser('C:\\Users\\ultra\\Documents')

        # grid = QGridLayout()
        # grid.setSpacing(10)
        # grid.setColumnStretch(3, 8)

        # self.proc_lbl = QLabel()
        # self.proc_lbl.setAlignment(Qt.AlignCenter)
        # self.proc_mov = QMovie('ajax-loader.gif')
        # self.proc_lbl.setMovie(self.proc_mov)
        # # self.proc_lbl.setText('placeholder')
        # # self.proc_mov.start()

        select_btn = QPushButton('Select Folder', self)
        select_btn.setToolTip('Select <b>root folder</b> to simplify.')
        select_btn.clicked.connect(self.showFileDialog)
        select_btn.resize(select_btn.sizeHint())
        # grid.addWidget(select_btn, 0, 0)

        # self.folder_edit = QLineEdit()
        # self.folder_edit.setReadOnly(True)
        self.folder_edit = QLabel()
        self.folder_edit.setText(self.root_path)
        # grid.addWidget(self.folder_edit, 0, 1)

        self.status_label = QLabel()
        self.status_label.setText('')

        self.slider_label_top = QLabel()
        self.slider_label_top.setAlignment(Qt.AlignCenter)
        # self.slider_label_top.setText('Pruning\nThreshold:\n' + '{:.3f}'.format(self.scalePruning(self.prune_thold)))
        self.slider_label_top.setText('Few important folders')
        # grid.addWidget(self.slider_label_top, 1, 0)

        self.slider_label_btm = QLabel()
        self.slider_label_btm.setAlignment(Qt.AlignCenter)
        self.slider_label_btm.setText('All folders')

        slider = QSlider(Qt.Vertical, self)  # for dynamically changing pruning threshold, default is 0.02
        slider.setValue(self.prune_thold)
        # grid.addWidget(slider, 2, 4, 1, 5)
        slider.setTickPosition(QSlider.TicksBothSides)
        slider.setTickInterval(10)
        slider.valueChanged[int].connect(self.changeValue)
        # slider.setInvertedAppearance(True)

        ogtree_label = QLabel()
        ogtree_label.setAlignment(Qt.AlignCenter)
        ogtree_label.setText('Original Structure')

        tree_label = QLabel()
        tree_label.setAlignment(Qt.AlignCenter)
        tree_label.setText('Pruned Structure\n(Ordered by Folder Importance)')

        self.ogtree = QTreeView(self)
        self.ogtree.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.ogmodel = QStandardItemModel()
        self.ogmodel.setHorizontalHeaderLabels(['Folder Name', 'Accessible Files', 'Number of Files'])
        # self.ogtree.header().setSectionResizeMode(QHeaderView.ResizeToContents)

        self.tree = QTreeView(self)
        self.tree.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Folder Name', 'Accessible Files', 'Number of Files'])
        # self.tree.header().setSectionResizeMode(QHeaderView.ResizeToContents)

        self.dir_dict, self.og_dir_dict = self.buildStructure(self.root_path)
        self.simplifyStructure(self.root_path, self.dir_dict, self.prune_thold)

        grid = QGridLayout()
        grid.addWidget(select_btn, 0, 0, 1, 1)
        grid.addWidget(self.folder_edit, 0, 1, 1, 7)
        grid.addWidget(self.status_label, 0, 8, 1, 1)
        grid.addWidget(ogtree_label, 1, 0, 1, 4)
        grid.addWidget(self.slider_label_top, 1, 4, 1, 1)
        grid.addWidget(tree_label, 1, 5, 1, 4)
        grid.addWidget(self.ogtree, 2, 0, 1, 4)
        grid.addWidget(slider, 2, 4, 1, 1, alignment=Qt.AlignHCenter)
        grid.addWidget(self.tree, 2, 5, 1, 4)
        grid.addWidget(self.slider_label_btm, 3, 4, 1, 1)

        self.setLayout(grid)
        # self.resize(640, 480)
        # self.show()

    def scalePruning(self, prune_thold):
        # # for reversing the slider scroll direction
        # scale_dict = dict(zip(range(100), range(100)[::-1]))
        # return scale_dict[prune_thold] * 0.005
        return prune_thold * 0.005
        # return math.log(prune_thold, 10)/2
        # return math.exp(prune_thold)/math.exp(100)

    def showFileDialog(self):
        dirpath = QFileDialog.getExistingDirectory(self, 'Select Folder', self.root_path)
        if dirpath:
            self.root_path = os.path.abspath(dirpath)
            self.folder_edit.setText(self.root_path)
            self.dir_dict, self.og_dir_dict = self.buildStructure(self.root_path)
            self.simplifyStructure(self.root_path, self.dir_dict, self.prune_thold)

    def changeValue(self, value):
        # print(value)
        self.prune_thold = value
        # self.slider_label.setText('Pruning\nThreshold:\n' + '{:.3f}'.format(self.scalePruning(self.prune_thold)))
        self.dir_dict = deepcopy(self.og_dir_dict)
        self.simplifyStructure(self.root_path, self.dir_dict, self.prune_thold)

    def buildStructure(self, root_path):
        dir_dict = read_and_count(root_path)
        og_dir_dict = deepcopy(dir_dict)
        self.refreshTreeView(self.ogmodel, self.ogtree, og_dir_dict)
        return og_dir_dict, dir_dict

    def simplifyStructure(self, root_path, dir_dict, prune_thold):
        def simplify_started():
            self.status_label.setText('<font color="red">Please wait...</font>')
            self.parent.statusBar().showMessage('Hello World')

        def simplify_finished(returned_dict):
            self.refreshTreeView(self.model, self.tree, returned_dict)
            self.status_label.setText('')
            self.parent.statusBar().showMessage('Goodbye World')

        # [0] directory name, [1] parent key, [2] children keys,
        # [3] names of files found in directory, [4] cumulative count of accessible files
        # root_path = 'C:\\Users\\ultra\\Dropbox\\mcgill'
        # dir_dict = read_and_count(root_path)
        # og_dir_dict = deepcopy(dir_dict)
        # dir_dict = simplify_tree(root_path, 1, dir_dict, 0.95, self.scalePruning(prune_thold), print_=False)
        # self.status_label.setText('<font color="red">Please wait...</font>')
        # self.parent.statusBar().showMessage('Hello World')
        simplify_worker = SimplifyThread(root_path, dir_dict, self.scalePruning(prune_thold))
        simplify_worker.started.connect(simplify_started)
        simplify_worker.finished.connect(simplify_finished)
        simplify_worker.start()
        # print_tree(root_path, dir_dict)

        # self.refreshTreeView(self.model, self.tree, dir_dict)

        # # self.ogmodel.clear()
        # # self.ogmodel.setHorizontalHeaderLabels(['Folder Name', 'Accessible Files', 'Number of Files'])
        # self.ogmodel.removeRow(0)
        # ogparent = self.ogmodel.invisibleRootItem()
        # self.append_all_children(1, og_dir_dict, ogparent)  # dir_dict key starts at 1 since 0==False
        # self.ogtree.setModel(self.ogmodel)
        # self.ogtree.expandAll()
        # self.ogtree.resizeColumnToContents(0)
        # self.ogtree.resizeColumnToContents(1)
        # self.ogtree.resizeColumnToContents(2)

        # # self.model.clear()
        # # self.model.setHorizontalHeaderLabels(['Folder Name', 'Accessible Files', 'Number of Files'])
        # self.model.removeRow(0)
        # parent = self.model.invisibleRootItem()
        # self.append_all_children(1, dir_dict, parent)  # dir_dict key starts at 1 since 0==False
        # self.tree.setModel(self.model)
        # self.tree.expandAll()
        # self.tree.resizeColumnToContents(0)
        # self.tree.resizeColumnToContents(1)
        # self.tree.resizeColumnToContents(2)

        # return dir_dict, og_dir_dict

    def refreshTreeView(self, model, tree, dir_dict):
        model.removeRow(0)
        parent = model.invisibleRootItem()
        self.append_all_children(1, dir_dict, parent)  # dir_dict key starts at 1 since 0==False
        tree.setModel(model)
        # tree.expandAll()
        tree.expandToDepth(0)
        tree.resizeColumnToContents(0)
        tree.resizeColumnToContents(1)
        tree.resizeColumnToContents(2)

    def append_all_children(self, dirkey, dir_dict, qitem):
        qitem.appendRow([QStandardItem(dir_dict[dirkey][0]),
                         QStandardItem(str(dir_dict[dirkey][4])),
                         QStandardItem(str(len(dir_dict[dirkey][3])))])
        current_row = qitem.rowCount()-1
        # for child in sorted(dir_dict[dirkey][2]):
        #     self.append_all_children(child, dir_dict, qitem.child(current_row))
        children_keys = dir_dict[dirkey][2]
        children_names = [dir_dict[child][0].lower() for child in children_keys]
        for child_name, child_key in sorted(zip(children_names, children_keys)):
            self.append_all_children(child_key, dir_dict, qitem.child(current_row))
예제 #23
0
class Installed(preferences.Group):
    """Overview of installed extensions.

    A QTreeView lists the metadata of all installed extensions.
    If the currently selected extension provides a configuration
    widget it is displayed in the bottom group of the page.

    With a checkbox individual extensions can be deactivated.
    Metadata is listed for all *installed* extensions, regardless
    of manual deactivation or load failure.
    """

    def __init__(self, page):
        super(Installed, self).__init__(page)

        layout = QVBoxLayout()
        self.setLayout(layout)

        # This must be called before self.populate() because
        # the data model relies on the labels
        app.translateUI(self)

        self.tree = QTreeView()
        self.name_items = {}
        self._selected_extension = ''
        self.tree.setModel(QStandardItemModel())
        self.tree.model().setColumnCount(2)
        self.tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tree.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tree.setHeaderHidden(True)
        self.tree.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self.tree.selectionModel().selectionChanged.connect(
            self.selection_changed)
        self.populate()
        layout.addWidget(self.tree)

    def translateUI(self):
        self.setTitle(_("Installed Extensions"))
        self.config_labels = {
            'extension-name': _("Name"),
            'maintainers': _("Maintainer(s)"),
            'version': _("Version"),
            'api-version': _("API version"),
            'license': _("License"),
            'short-description': _("Short Description"),
            'description': _("Description"),
            'repository': _("Repository"),
            'website': _("Website"),
            'dependencies': _("Dependencies")
        }

    def loadSettings(self):
        s = QSettings()
        self.setEnabled(self.page().active())
        s.beginGroup("extension-settings/installed")
        inactive = s.value("inactive", [], list)
        for ext in self.name_items.keys():
            self.name_items[ext].setCheckState(
                Qt.Checked if ext not in inactive else Qt.Unchecked)
        self.tree.model().dataChanged.connect(self.page().changed)

    def saveSettings(self):
        s = QSettings()
        s.beginGroup("extension-settings/installed")
        inactive = [ext for ext in self.name_items.keys()
            if self.name_items[ext].checkState() == Qt.Unchecked]
        s.setValue("inactive", inactive)

    def populate(self):
        """Populate the tree view with data from the installed extensions.
        """

        # TODO/Question:
        # Would it make sense to move this to a dedicated model class
        # complementing the FailedModel?

        root = self.tree.model().invisibleRootItem()
        extensions = app.extensions()
        for ext in extensions.installed_extensions():
            ext_infos = extensions.infos(ext)
            display_name = ext_infos.get(ext, ext) if ext_infos else ext.name()
            loaded_extension = extensions.get(ext)
            if loaded_extension:
                display_name += ' ({})'.format(loaded_extension.load_time())

            name_item = QStandardItem(display_name)
            name_item.extension_name = ext
            name_item.setCheckable(True)
            self.name_items[ext] = name_item
            icon = extensions.icon(ext)
            if icon:
                name_item.setIcon(icon)
            root.appendRow([name_item])
            for entry in [
                'extension-name',
                'short-description',
                'description',
                'version',
                'api-version',
                'dependencies',
                'maintainers',
                'repository',
                'website',
                'license'
            ]:
                label_item = QStandardItem('{}:'.format(
                    self.config_labels[entry]))
                label_item.setTextAlignment(Qt.AlignTop)
                bold = QFont()
                bold.setWeight(QFont.Bold)
                label_item.setFont(bold)
                details = ext_infos.get(entry, "") if ext_infos else ""
                if type(details) == list:
                    details = '\n'.join(details)
                details_item = QStandardItem(details)
                details_item.setTextAlignment(Qt.AlignTop)
                if entry == 'api-version':
                    # Check for correct(ly formatted) api-version entry
                    # and highlight it in case of mismatch
                    api_version = appinfo.extension_api
                    if not details:
                        details_item.setFont(bold)
                        details_item.setText(
                            _("Misformat: {api}").format(details))
                    elif not details == api_version:
                            details_item.setFont(bold)
                            details_item.setText('{} ({}: {})'.format(
                                details,
                                appinfo.appname,
                                api_version))
                name_item.appendRow([label_item, details_item])

    def selected_extension(self):
        """Return the (directory) name of the extension that
        is currently selected."""
        return self._selected_extension

    def selection_changed(self, new, old):
        """Show the configuration widget for the selected extension,
        if available."""
        config = self.siblingGroup(Config)
        if new.indexes():
            ext_item = self.tree.model().itemFromIndex(new.indexes()[0])
            # NOTE: This may have to be changed if there should be
            # more complexity in the tree model than now (a selected
            # row is either a top-level row or its immediate child)
            if not hasattr(ext_item, 'extension_name'):
                ext_item = ext_item.parent()
            name = ext_item.extension_name
            if name == self.selected_extension():
                return
        else:
            # If nothing is selected, show the "empty" widget
            name = ""

        config.hide_extension()
        self._selected_extension = name
        config.show_extension(name)
예제 #24
0
class DirectoriesDialog(QMainWindow):
    def __init__(self, app, **kwargs):
        super().__init__(None, **kwargs)
        self.app = app
        self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
        self.recentFolders = Recent(self.app, 'recentFolders')
        self._setupUi()
        self.directoriesModel = DirectoriesModel(self.app.model.directory_tree,
                                                 view=self.treeView)
        self.directoriesDelegate = DirectoriesDelegate()
        self.treeView.setItemDelegate(self.directoriesDelegate)
        self._setupColumns()
        self.app.recentResults.addMenu(self.menuLoadRecent)
        self.app.recentResults.addMenu(self.menuRecentResults)
        self.recentFolders.addMenu(self.menuRecentFolders)
        self._updateAddButton()
        self._updateRemoveButton()
        self._updateLoadResultsButton()
        self._setupBindings()

    def _setupBindings(self):
        self.scanButton.clicked.connect(self.scanButtonClicked)
        self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger)
        self.addFolderButton.clicked.connect(self.actionAddFolder.trigger)
        self.removeFolderButton.clicked.connect(self.removeFolderButtonClicked)
        self.treeView.selectionModel().selectionChanged.connect(
            self.selectionChanged)
        self.app.recentResults.itemsChanged.connect(
            self._updateLoadResultsButton)
        self.recentFolders.itemsChanged.connect(self._updateAddButton)
        self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
        self.directoriesModel.foldersAdded.connect(
            self.directoriesModelAddedFolders)
        self.app.willSavePrefs.connect(self.appWillSavePrefs)

    def _setupActions(self):
        # (name, shortcut, icon, desc, func)
        ACTIONS = [
            ('actionLoadResults', 'Ctrl+L', '', tr("Load Results..."),
             self.loadResultsTriggered),
            ('actionShowResultsWindow', '', '', tr("Results Window"),
             self.app.showResultsWindow),
            ('actionAddFolder', '', '', tr("Add Folder..."),
             self.addFolderTriggered),
        ]
        createActions(ACTIONS, self)

    def _setupMenu(self):
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 42, 22))
        self.menuFile = QMenu(self.menubar)
        self.menuFile.setTitle(tr("File"))
        self.menuView = QMenu(self.menubar)
        self.menuView.setTitle(tr("View"))
        self.menuHelp = QMenu(self.menubar)
        self.menuHelp.setTitle(tr("Help"))
        self.menuLoadRecent = QMenu(self.menuFile)
        self.menuLoadRecent.setTitle(tr("Load Recent Results"))
        self.setMenuBar(self.menubar)

        self.menuFile.addAction(self.actionLoadResults)
        self.menuFile.addAction(self.menuLoadRecent.menuAction())
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionQuit)
        self.menuView.addAction(self.app.actionPreferences)
        self.menuView.addAction(self.actionShowResultsWindow)
        self.menuView.addAction(self.app.actionIgnoreList)
        self.menuHelp.addAction(self.app.actionShowHelp)
        self.menuHelp.addAction(self.app.actionOpenDebugLog)
        self.menuHelp.addAction(self.app.actionAbout)

        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuView.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())

        # Recent folders menu
        self.menuRecentFolders = QMenu()
        self.menuRecentFolders.addAction(self.actionAddFolder)
        self.menuRecentFolders.addSeparator()

        # Recent results menu
        self.menuRecentResults = QMenu()
        self.menuRecentResults.addAction(self.actionLoadResults)
        self.menuRecentResults.addSeparator()

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(420, 338)
        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.promptLabel = QLabel(
            tr("Select folders to scan and press \"Scan\"."),
            self.centralwidget)
        self.verticalLayout.addWidget(self.promptLabel)
        self.treeView = QTreeView(self.centralwidget)
        self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setAcceptDrops(True)
        triggers = QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed\
            |QAbstractItemView.SelectedClicked
        self.treeView.setEditTriggers(triggers)
        self.treeView.setDragDropOverwriteMode(True)
        self.treeView.setDragDropMode(QAbstractItemView.DropOnly)
        self.treeView.setUniformRowHeights(True)
        self.verticalLayout.addWidget(self.treeView)
        self.horizontalLayout = QHBoxLayout()
        self.removeFolderButton = QPushButton(self.centralwidget)
        self.removeFolderButton.setIcon(QIcon(QPixmap(":/minus")))
        self.removeFolderButton.setShortcut("Del")
        self.horizontalLayout.addWidget(self.removeFolderButton)
        self.addFolderButton = QPushButton(self.centralwidget)
        self.addFolderButton.setIcon(QIcon(QPixmap(":/plus")))
        self.horizontalLayout.addWidget(self.addFolderButton)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.loadResultsButton = QPushButton(self.centralwidget)
        self.loadResultsButton.setText(tr("Load Results"))
        self.horizontalLayout.addWidget(self.loadResultsButton)
        self.scanButton = QPushButton(self.centralwidget)
        self.scanButton.setText(tr("Scan"))
        self.scanButton.setDefault(True)
        self.horizontalLayout.addWidget(self.scanButton)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.setCentralWidget(self.centralwidget)

        self._setupActions()
        self._setupMenu()

        if self.app.prefs.directoriesWindowRect is not None:
            self.setGeometry(self.app.prefs.directoriesWindowRect)
        else:
            moveToScreenCenter(self)

    def _setupColumns(self):
        header = self.treeView.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.resizeSection(1, 100)

    def _updateAddButton(self):
        if self.recentFolders.isEmpty():
            self.addFolderButton.setMenu(None)
        else:
            self.addFolderButton.setMenu(self.menuRecentFolders)

    def _updateRemoveButton(self):
        indexes = self.treeView.selectedIndexes()
        if not indexes:
            self.removeFolderButton.setEnabled(False)
            return
        self.removeFolderButton.setEnabled(True)

    def _updateLoadResultsButton(self):
        if self.app.recentResults.isEmpty():
            self.loadResultsButton.setMenu(None)
        else:
            self.loadResultsButton.setMenu(self.menuRecentResults)

    #--- QWidget overrides
    def closeEvent(self, event):
        event.accept()
        if self.app.model.results.is_modified:
            title = tr("Unsaved results")
            msg = tr("You have unsaved results, do you really want to quit?")
            if not self.app.confirm(title, msg):
                event.ignore()
        if event.isAccepted():
            QApplication.quit()

    #--- Events
    def addFolderTriggered(self):
        title = tr("Select a folder to add to the scanning list")
        flags = QFileDialog.ShowDirsOnly
        dirpath = str(
            QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder,
                                             flags))
        if not dirpath:
            return
        self.lastAddedFolder = dirpath
        self.app.model.add_directory(dirpath)
        self.recentFolders.insertItem(dirpath)

    def appWillSavePrefs(self):
        self.app.prefs.directoriesWindowRect = self.geometry()

    def directoriesModelAddedFolders(self, folders):
        for folder in folders:
            self.recentFolders.insertItem(folder)

    def loadResultsTriggered(self):
        title = tr("Select a results file to load")
        files = ';;'.join(
            [tr("dupeGuru Results (*.dupeguru)"),
             tr("All Files (*.*)")])
        destination = QFileDialog.getOpenFileName(self, title, '', files)
        if destination:
            self.app.model.load_from(destination)
            self.app.recentResults.insertItem(destination)

    def removeFolderButtonClicked(self):
        self.directoriesModel.model.remove_selected()

    def scanButtonClicked(self):
        if self.app.model.results.is_modified:
            title = tr("Start a new scan")
            msg = tr(
                "You have unsaved results, do you really want to continue?")
            if not self.app.confirm(title, msg):
                return
        self.app.model.start_scanning()

    def selectionChanged(self, selected, deselected):
        self._updateRemoveButton()
예제 #25
0
class DirectoriesDialog(QMainWindow):
    def __init__(self, app, **kwargs):
        super().__init__(None, **kwargs)
        self.app = app
        self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
        self.recentFolders = Recent(self.app, 'recentFolders')
        self._setupUi()
        self._updateScanTypeList()
        self.directoriesModel = DirectoriesModel(self.app.model.directory_tree, view=self.treeView)
        self.directoriesDelegate = DirectoriesDelegate()
        self.treeView.setItemDelegate(self.directoriesDelegate)
        self._setupColumns()
        self.app.recentResults.addMenu(self.menuLoadRecent)
        self.app.recentResults.addMenu(self.menuRecentResults)
        self.recentFolders.addMenu(self.menuRecentFolders)
        self._updateAddButton()
        self._updateRemoveButton()
        self._updateLoadResultsButton()
        self._updateActionsState()
        self._setupBindings()

    def _setupBindings(self):
        self.appModeRadioBox.itemSelected.connect(self.appModeButtonSelected)
        self.showPreferencesButton.clicked.connect(self.app.actionPreferences.trigger)
        self.scanButton.clicked.connect(self.scanButtonClicked)
        self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger)
        self.addFolderButton.clicked.connect(self.actionAddFolder.trigger)
        self.removeFolderButton.clicked.connect(self.removeFolderButtonClicked)
        self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged)
        self.app.recentResults.itemsChanged.connect(self._updateLoadResultsButton)
        self.recentFolders.itemsChanged.connect(self._updateAddButton)
        self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
        self.directoriesModel.foldersAdded.connect(self.directoriesModelAddedFolders)
        self.app.willSavePrefs.connect(self.appWillSavePrefs)

    def _setupActions(self):
        # (name, shortcut, icon, desc, func)
        ACTIONS = [
            ('actionLoadResults', 'Ctrl+L', '', tr("Load Results..."), self.loadResultsTriggered),
            ('actionShowResultsWindow', '', '', tr("Results Window"), self.app.showResultsWindow),
            ('actionAddFolder', '', '', tr("Add Folder..."), self.addFolderTriggered),
        ]
        createActions(ACTIONS, self)

    def _setupMenu(self):
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 42, 22))
        self.menuFile = QMenu(self.menubar)
        self.menuFile.setTitle(tr("File"))
        self.menuView = QMenu(self.menubar)
        self.menuView.setTitle(tr("View"))
        self.menuHelp = QMenu(self.menubar)
        self.menuHelp.setTitle(tr("Help"))
        self.menuLoadRecent = QMenu(self.menuFile)
        self.menuLoadRecent.setTitle(tr("Load Recent Results"))
        self.setMenuBar(self.menubar)

        self.menuFile.addAction(self.actionLoadResults)
        self.menuFile.addAction(self.menuLoadRecent.menuAction())
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionClearPictureCache)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionQuit)
        self.menuView.addAction(self.app.actionPreferences)
        self.menuView.addAction(self.actionShowResultsWindow)
        self.menuView.addAction(self.app.actionIgnoreList)
        self.menuHelp.addAction(self.app.actionShowHelp)
        self.menuHelp.addAction(self.app.actionOpenDebugLog)
        self.menuHelp.addAction(self.app.actionAbout)

        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuView.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())

        # Recent folders menu
        self.menuRecentFolders = QMenu()
        self.menuRecentFolders.addAction(self.actionAddFolder)
        self.menuRecentFolders.addSeparator()

        # Recent results menu
        self.menuRecentResults = QMenu()
        self.menuRecentResults.addAction(self.actionLoadResults)
        self.menuRecentResults.addSeparator()

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(420, 338)
        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        hl = QHBoxLayout()
        label = QLabel(tr("Application Mode:"), self)
        label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hl.addWidget(label)
        self.appModeRadioBox = RadioBox(
            self,
            items=[tr("Standard"), tr("Music"), tr("Picture")],
            spread=False
        )
        hl.addWidget(self.appModeRadioBox)
        self.verticalLayout.addLayout(hl)
        hl = QHBoxLayout()
        hl.setAlignment(Qt.AlignLeft)
        label = QLabel(tr("Scan Type:"), self)
        label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hl.addWidget(label)
        self.scanTypeComboBox = QComboBox(self)
        self.scanTypeComboBox.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))
        self.scanTypeComboBox.setMaximumWidth(400)
        hl.addWidget(self.scanTypeComboBox)
        self.showPreferencesButton = QPushButton(tr("More Options"), self.centralwidget)
        self.showPreferencesButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hl.addWidget(self.showPreferencesButton)
        self.verticalLayout.addLayout(hl)
        self.promptLabel = QLabel(tr("Select folders to scan and press \"Scan\"."), self.centralwidget)
        self.verticalLayout.addWidget(self.promptLabel)
        self.treeView = QTreeView(self.centralwidget)
        self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setAcceptDrops(True)
        triggers = QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed\
            | QAbstractItemView.SelectedClicked
        self.treeView.setEditTriggers(triggers)
        self.treeView.setDragDropOverwriteMode(True)
        self.treeView.setDragDropMode(QAbstractItemView.DropOnly)
        self.treeView.setUniformRowHeights(True)
        self.verticalLayout.addWidget(self.treeView)
        self.horizontalLayout = QHBoxLayout()
        self.removeFolderButton = QPushButton(self.centralwidget)
        self.removeFolderButton.setIcon(QIcon(QPixmap(":/minus")))
        self.removeFolderButton.setShortcut("Del")
        self.horizontalLayout.addWidget(self.removeFolderButton)
        self.addFolderButton = QPushButton(self.centralwidget)
        self.addFolderButton.setIcon(QIcon(QPixmap(":/plus")))
        self.horizontalLayout.addWidget(self.addFolderButton)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.loadResultsButton = QPushButton(self.centralwidget)
        self.loadResultsButton.setText(tr("Load Results"))
        self.horizontalLayout.addWidget(self.loadResultsButton)
        self.scanButton = QPushButton(self.centralwidget)
        self.scanButton.setText(tr("Scan"))
        self.scanButton.setDefault(True)
        self.horizontalLayout.addWidget(self.scanButton)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.setCentralWidget(self.centralwidget)

        self._setupActions()
        self._setupMenu()

        if self.app.prefs.directoriesWindowRect is not None:
            self.setGeometry(self.app.prefs.directoriesWindowRect)
        else:
            moveToScreenCenter(self)

    def _setupColumns(self):
        header = self.treeView.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.resizeSection(1, 100)

    def _updateActionsState(self):
        self.actionShowResultsWindow.setEnabled(self.app.resultWindow is not None)

    def _updateAddButton(self):
        if self.recentFolders.isEmpty():
            self.addFolderButton.setMenu(None)
        else:
            self.addFolderButton.setMenu(self.menuRecentFolders)

    def _updateRemoveButton(self):
        indexes = self.treeView.selectedIndexes()
        if not indexes:
            self.removeFolderButton.setEnabled(False)
            return
        self.removeFolderButton.setEnabled(True)

    def _updateLoadResultsButton(self):
        if self.app.recentResults.isEmpty():
            self.loadResultsButton.setMenu(None)
        else:
            self.loadResultsButton.setMenu(self.menuRecentResults)

    def _updateScanTypeList(self):
        try:
            self.scanTypeComboBox.currentIndexChanged[int].disconnect(self.scanTypeChanged)
        except TypeError:
            # Not connected, ignore
            pass
        self.scanTypeComboBox.clear()
        scan_options = self.app.model.SCANNER_CLASS.get_scan_options()
        for scan_option in scan_options:
            self.scanTypeComboBox.addItem(scan_option.label)
        SCAN_TYPE_ORDER = [so.scan_type for so in scan_options]
        selected_scan_type = self.app.prefs.get_scan_type(self.app.model.app_mode)
        scan_type_index = SCAN_TYPE_ORDER.index(selected_scan_type)
        self.scanTypeComboBox.setCurrentIndex(scan_type_index)
        self.scanTypeComboBox.currentIndexChanged[int].connect(self.scanTypeChanged)
        self.app._update_options()

    #--- QWidget overrides
    def closeEvent(self, event):
        event.accept()
        if self.app.model.results.is_modified:
            title = tr("Unsaved results")
            msg = tr("You have unsaved results, do you really want to quit?")
            if not self.app.confirm(title, msg):
                event.ignore()
        if event.isAccepted():
            QApplication.quit()

    #--- Events
    def addFolderTriggered(self):
        title = tr("Select a folder to add to the scanning list")
        flags = QFileDialog.ShowDirsOnly
        dirpath = str(QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder, flags))
        if not dirpath:
            return
        self.lastAddedFolder = dirpath
        self.app.model.add_directory(dirpath)
        self.recentFolders.insertItem(dirpath)

    def appModeButtonSelected(self, index):
        if index == 2:
            mode = AppMode.Picture
        elif index == 1:
            mode = AppMode.Music
        else:
            mode = AppMode.Standard
        self.app.model.app_mode = mode
        self._updateScanTypeList()

    def appWillSavePrefs(self):
        self.app.prefs.directoriesWindowRect = self.geometry()

    def directoriesModelAddedFolders(self, folders):
        for folder in folders:
            self.recentFolders.insertItem(folder)

    def loadResultsTriggered(self):
        title = tr("Select a results file to load")
        files = ';;'.join([tr("dupeGuru Results (*.dupeguru)"), tr("All Files (*.*)")])
        destination = QFileDialog.getOpenFileName(self, title, '', files)
        if destination:
            self.app.model.load_from(destination)
            self.app.recentResults.insertItem(destination)

    def removeFolderButtonClicked(self):
        self.directoriesModel.model.remove_selected()

    def scanButtonClicked(self):
        if self.app.model.results.is_modified:
            title = tr("Start a new scan")
            msg = tr("You have unsaved results, do you really want to continue?")
            if not self.app.confirm(title, msg):
                return
        self.app.model.start_scanning()

    def scanTypeChanged(self, index):
        scan_options = self.app.model.SCANNER_CLASS.get_scan_options()
        self.app.prefs.set_scan_type(self.app.model.app_mode, scan_options[index].scan_type)
        self.app._update_options()

    def selectionChanged(self, selected, deselected):
        self._updateRemoveButton()
예제 #26
0
class DirectoriesDialog(QMainWindow):
    def __init__(self, app, **kwargs):
        super().__init__(None, **kwargs)
        self.app = app
        self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
        self.recentFolders = Recent(self.app, "recentFolders")
        self._setupUi()
        self.directoriesModel = DirectoriesModel(self.app.model.directory_tree, view=self.treeView)
        self.directoriesDelegate = DirectoriesDelegate()
        self.treeView.setItemDelegate(self.directoriesDelegate)
        self._setupColumns()
        self.app.recentResults.addMenu(self.menuLoadRecent)
        self.app.recentResults.addMenu(self.menuRecentResults)
        self.recentFolders.addMenu(self.menuRecentFolders)
        self._updateAddButton()
        self._updateRemoveButton()
        self._updateLoadResultsButton()
        self._setupBindings()

    def _setupBindings(self):
        self.scanButton.clicked.connect(self.scanButtonClicked)
        self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger)
        self.addFolderButton.clicked.connect(self.actionAddFolder.trigger)
        self.removeFolderButton.clicked.connect(self.removeFolderButtonClicked)
        self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged)
        self.app.recentResults.itemsChanged.connect(self._updateLoadResultsButton)
        self.recentFolders.itemsChanged.connect(self._updateAddButton)
        self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
        self.directoriesModel.foldersAdded.connect(self.directoriesModelAddedFolders)
        self.app.willSavePrefs.connect(self.appWillSavePrefs)

    def _setupActions(self):
        # (name, shortcut, icon, desc, func)
        ACTIONS = [
            ("actionLoadResults", "Ctrl+L", "", tr("Load Results..."), self.loadResultsTriggered),
            ("actionShowResultsWindow", "", "", tr("Results Window"), self.app.showResultsWindow),
            ("actionAddFolder", "", "", tr("Add Folder..."), self.addFolderTriggered),
        ]
        createActions(ACTIONS, self)

    def _setupMenu(self):
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 42, 22))
        self.menuFile = QMenu(self.menubar)
        self.menuFile.setTitle(tr("File"))
        self.menuView = QMenu(self.menubar)
        self.menuView.setTitle(tr("View"))
        self.menuHelp = QMenu(self.menubar)
        self.menuHelp.setTitle(tr("Help"))
        self.menuLoadRecent = QMenu(self.menuFile)
        self.menuLoadRecent.setTitle(tr("Load Recent Results"))
        self.setMenuBar(self.menubar)

        self.menuFile.addAction(self.actionLoadResults)
        self.menuFile.addAction(self.menuLoadRecent.menuAction())
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionQuit)
        self.menuView.addAction(self.app.actionPreferences)
        self.menuView.addAction(self.actionShowResultsWindow)
        self.menuView.addAction(self.app.actionIgnoreList)
        self.menuHelp.addAction(self.app.actionShowHelp)
        self.menuHelp.addAction(self.app.actionOpenDebugLog)
        self.menuHelp.addAction(self.app.actionAbout)

        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuView.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())

        # Recent folders menu
        self.menuRecentFolders = QMenu()
        self.menuRecentFolders.addAction(self.actionAddFolder)
        self.menuRecentFolders.addSeparator()

        # Recent results menu
        self.menuRecentResults = QMenu()
        self.menuRecentResults.addAction(self.actionLoadResults)
        self.menuRecentResults.addSeparator()

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(420, 338)
        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.promptLabel = QLabel(tr('Select folders to scan and press "Scan".'), self.centralwidget)
        self.verticalLayout.addWidget(self.promptLabel)
        self.treeView = QTreeView(self.centralwidget)
        self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setAcceptDrops(True)
        triggers = (
            QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed | QAbstractItemView.SelectedClicked
        )
        self.treeView.setEditTriggers(triggers)
        self.treeView.setDragDropOverwriteMode(True)
        self.treeView.setDragDropMode(QAbstractItemView.DropOnly)
        self.treeView.setUniformRowHeights(True)
        self.verticalLayout.addWidget(self.treeView)
        self.horizontalLayout = QHBoxLayout()
        self.removeFolderButton = QPushButton(self.centralwidget)
        self.removeFolderButton.setIcon(QIcon(QPixmap(":/minus")))
        self.removeFolderButton.setShortcut("Del")
        self.horizontalLayout.addWidget(self.removeFolderButton)
        self.addFolderButton = QPushButton(self.centralwidget)
        self.addFolderButton.setIcon(QIcon(QPixmap(":/plus")))
        self.horizontalLayout.addWidget(self.addFolderButton)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.loadResultsButton = QPushButton(self.centralwidget)
        self.loadResultsButton.setText(tr("Load Results"))
        self.horizontalLayout.addWidget(self.loadResultsButton)
        self.scanButton = QPushButton(self.centralwidget)
        self.scanButton.setText(tr("Scan"))
        self.scanButton.setDefault(True)
        self.horizontalLayout.addWidget(self.scanButton)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.setCentralWidget(self.centralwidget)

        self._setupActions()
        self._setupMenu()

        if self.app.prefs.directoriesWindowRect is not None:
            self.setGeometry(self.app.prefs.directoriesWindowRect)
        else:
            moveToScreenCenter(self)

    def _setupColumns(self):
        header = self.treeView.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.resizeSection(1, 100)

    def _updateAddButton(self):
        if self.recentFolders.isEmpty():
            self.addFolderButton.setMenu(None)
        else:
            self.addFolderButton.setMenu(self.menuRecentFolders)

    def _updateRemoveButton(self):
        indexes = self.treeView.selectedIndexes()
        if not indexes:
            self.removeFolderButton.setEnabled(False)
            return
        self.removeFolderButton.setEnabled(True)

    def _updateLoadResultsButton(self):
        if self.app.recentResults.isEmpty():
            self.loadResultsButton.setMenu(None)
        else:
            self.loadResultsButton.setMenu(self.menuRecentResults)

    # --- QWidget overrides
    def closeEvent(self, event):
        event.accept()
        if self.app.model.results.is_modified:
            title = tr("Unsaved results")
            msg = tr("You have unsaved results, do you really want to quit?")
            if not self.app.confirm(title, msg):
                event.ignore()
        if event.isAccepted():
            QApplication.quit()

    # --- Events
    def addFolderTriggered(self):
        title = tr("Select a folder to add to the scanning list")
        flags = QFileDialog.ShowDirsOnly
        dirpath = str(QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder, flags))
        if not dirpath:
            return
        self.lastAddedFolder = dirpath
        self.app.model.add_directory(dirpath)
        self.recentFolders.insertItem(dirpath)

    def appWillSavePrefs(self):
        self.app.prefs.directoriesWindowRect = self.geometry()

    def directoriesModelAddedFolders(self, folders):
        for folder in folders:
            self.recentFolders.insertItem(folder)

    def loadResultsTriggered(self):
        title = tr("Select a results file to load")
        files = ";;".join([tr("dupeGuru Results (*.dupeguru)"), tr("All Files (*.*)")])
        destination = QFileDialog.getOpenFileName(self, title, "", files)
        if destination:
            self.app.model.load_from(destination)
            self.app.recentResults.insertItem(destination)

    def removeFolderButtonClicked(self):
        self.directoriesModel.model.remove_selected()

    def scanButtonClicked(self):
        if self.app.model.results.is_modified:
            title = tr("Start a new scan")
            msg = tr("You have unsaved results, do you really want to continue?")
            if not self.app.confirm(title, msg):
                return
        self.app.model.start_scanning()

    def selectionChanged(self, selected, deselected):
        self._updateRemoveButton()
예제 #27
0
class Ui_PoloshirtWindow(QWidget):
    POLOSHİRTID, POLOSHİRTISIM, POLOSHİRTFIYAT, RESIMURL = range(4)

    def setupUi(self, PoloshirtWindow):
        PoloshirtWindow.setObjectName("PoloshirtWindow")
        PoloshirtWindow.resize(997, 704)
        PoloshirtWindow.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.centralwidget = QtWidgets.QWidget(PoloshirtWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(60, 120, 791, 271))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        # bukısım c*k onemlı
        self.treeWidget = QTreeView(self.gridLayoutWidget)

        self.treeWidget.setEditTriggers(
            QtWidgets.QTableWidget.NoEditTriggers)
        # QtWidgets.QAbstractItemView.DoubleClicked | QtWidgets.QAbstractItemView.EditKeyPressed | QtWidgets.QAbstractItemView.SelectedClicked)
        self.treeWidget.setObjectName("treeWidget")
        self.gridLayout.addWidget(self.treeWidget, 0, 0, 2, 1)
        self.gridLayoutWidget_3 = QtWidgets.QWidget(self.centralwidget)
        self.gridLayoutWidget_3.setGeometry(QtCore.QRect(60, 390, 341, 231))
        self.gridLayoutWidget_3.setObjectName("gridLayoutWidget_3")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.gridLayoutWidget_3)
        self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.poloshirtisimlineEdit = QtWidgets.QLineEdit(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.poloshirtisimlineEdit.setFont(font)
        self.poloshirtisimlineEdit.setObjectName("poloshirtisimlineEdit")
        self.gridLayout_3.addWidget(self.poloshirtisimlineEdit, 1, 1, 1, 1)
        self.poloshirtisimlabel = QtWidgets.QLabel(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setFamily("Microsoft Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtisimlabel.setFont(font)
        self.poloshirtisimlabel.setObjectName("poloshirtisimlabel")
        self.gridLayout_3.addWidget(self.poloshirtisimlabel, 1, 0, 1, 1)
        self.poloshirtfyatlabel = QtWidgets.QLabel(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setFamily("Microsoft Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtfyatlabel.setFont(font)
        self.poloshirtfyatlabel.setObjectName("poloshirtfyatlabel")
        self.gridLayout_3.addWidget(self.poloshirtfyatlabel, 2, 0, 1, 1)
        self.poloshirtidlineEdit = QtWidgets.QLineEdit(self.gridLayoutWidget_3)
        self.poloshirtidlineEdit.setEnabled(False)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.poloshirtidlineEdit.setFont(font)
        self.poloshirtidlineEdit.setObjectName("poloshirtidlineEdit")
        self.gridLayout_3.addWidget(self.poloshirtidlineEdit, 0, 1, 1, 1)
        self.poloshirtidlabel = QtWidgets.QLabel(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setFamily("Microsoft Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtidlabel.setFont(font)
        self.poloshirtidlabel.setObjectName("poloshirtidlabel")
        self.gridLayout_3.addWidget(self.poloshirtidlabel, 0, 0, 1, 1)
        self.poloshirtfiyatlineEdit = QtWidgets.QLineEdit(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.poloshirtfiyatlineEdit.setFont(font)
        self.poloshirtfiyatlineEdit.setObjectName("poloshirtfiyatlineEdit")
        self.gridLayout_3.addWidget(self.poloshirtfiyatlineEdit, 2, 1, 1, 1)
        self.poloshirtresimurllineEdit = QtWidgets.QLineEdit(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.poloshirtresimurllineEdit.setFont(font)
        self.poloshirtresimurllineEdit.setObjectName("poloshirtresimurllineEdit")
        self.gridLayout_3.addWidget(self.poloshirtresimurllineEdit, 3, 1, 1, 1)
        self.poloshirtresimurllabel = QtWidgets.QLabel(self.gridLayoutWidget_3)
        font = QtGui.QFont()
        font.setFamily("Microsoft Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtresimurllabel.setFont(font)
        self.poloshirtresimurllabel.setObjectName("poloshirtresimurllabel")
        self.gridLayout_3.addWidget(self.poloshirtresimurllabel, 3, 0, 1, 1)
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(419, 410, 211, 211))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.poloshirteklebuton = QtWidgets.QPushButton(self.verticalLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("MS Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirteklebuton.setFont(font)
        self.poloshirteklebuton.setObjectName("poloshirteklebuton")
        self.verticalLayout.addWidget(self.poloshirteklebuton)
        self.poloshirtduzenlebuton = QtWidgets.QPushButton(self.verticalLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("MS Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtduzenlebuton.setFont(font)
        self.poloshirtduzenlebuton.setObjectName("poloshirtduzenlebuton")
        self.verticalLayout.addWidget(self.poloshirtduzenlebuton)
        self.poloshirtsilbuton = QtWidgets.QPushButton(self.verticalLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("MS Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.poloshirtsilbuton.setFont(font)
        self.poloshirtsilbuton.setObjectName("poloshirtsilbuton")
        self.verticalLayout.addWidget(self.poloshirtsilbuton)
        self.formLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.formLayoutWidget.setGeometry(QtCore.QRect(650, 500, 271, 31))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
        self.formLayout.setContentsMargins(0, 0, 0, 0)
        self.formLayout.setObjectName("formLayout")

        font = QtGui.QFont()
        font.setFamily("MS Sans Serif")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)


        font = QtGui.QFont()
        font.setPointSize(10)


        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(190, 20, 561, 51))
        font = QtGui.QFont()
        font.setFamily("Myanmar Text")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.label.setFrameShadow(QtWidgets.QFrame.Plain)
        self.label.setObjectName("label")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(350, 70, 170, 51))
        font = QtGui.QFont()
        font.setFamily("Myanmar Text")
        font.setPointSize(18)
        font.setBold(True)
        font.setWeight(75)
        self.label_3.setFont(font)
        self.label_3.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.label_3.setFrameShadow(QtWidgets.QFrame.Plain)
        self.label_3.setObjectName("label_3")
        PoloshirtWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(PoloshirtWindow)
        self.statusbar.setObjectName("statusbar")
        PoloshirtWindow.setStatusBar(self.statusbar)
        self.actionPoloshirt = QtWidgets.QAction(PoloshirtWindow)
        self.actionPoloshirt.setObjectName("actionPoloshirt")
        self.actionPoloshirt = QtWidgets.QAction(PoloshirtWindow)
        self.actionPoloshirt.setObjectName("actionPoloshirt")
        self.actionPoloshirt = QtWidgets.QAction(PoloshirtWindow)
        self.actionPoloshirt.setObjectName("actionPoloshirt")
        self.actioncgiyim = QtWidgets.QAction(PoloshirtWindow)
        self.actioncgiyim.setObjectName("actioncgiyim")
        self.retranslateUi(PoloshirtWindow)
        QtCore.QMetaObject.connectSlotsByName(PoloshirtWindow)

        #SORT  SIRALAMA
        self.treeWidget.setSortingEnabled(True)

        #only int
        self.onlyInt = QIntValidator()
        self.poloshirtfiyatlineEdit.setValidator(self.onlyInt)

        # bu kısmı kullan nolur
        model = self.treetablemodelyaratma(self)
        self.treetablemodelyaratma2(model)
        self.treeWidget.setModel(model)

        # Buton clickleri
        self.treeWidget.doubleClicked.connect(self.on_doubleClicked)
        self.poloshirteklebuton.clicked.connect(self.eklebuton)
        self.poloshirtsilbuton.clicked.connect(self.silbuton)
        self.poloshirtduzenlebuton.clicked.connect(self.duzenlebuton)

    def treetablemodelyaratma(self, parent):
        model = QStandardItemModel(0, 4, parent)
        model.setHeaderData(self.POLOSHİRTID, Qt.Horizontal, "Poloshirt id")
        model.setHeaderData(self.POLOSHİRTISIM, Qt.Horizontal, "Poloshirt isim")
        model.setHeaderData(self.POLOSHİRTFIYAT, Qt.Horizontal, "Poloshirt fiyat")
        model.setHeaderData(self.RESIMURL, Qt.Horizontal, "Poloshirt Resimurl")

        return model

    def on_doubleClicked(self, index):
        item = self.treeWidget.currentIndex()
        item2 = item.model().itemFromIndex(index).text()

        self.poloshirtidlineEdit.setText(item2)

        # tabloyu update etme yöntemı
        self.updateview()

    def eklebuton(self):
        if (self.poloshirtfiyatlineEdit.text() =="" or self.poloshirtisimlineEdit.text()=="" or self.poloshirtresimurllineEdit.text()==""):
            return
        else:
            conn = pymysql.connect(host="localhost", user="******", passwd="12345678", db="bilisim_proje_odevi")
            cursor = conn.cursor(pymysql.cursors.DictCursor)

            query = "INSERT INTO `poloshirt` (poloshirt_isim, poloshirt_fiyat,poloshirt_resimurl) VALUES (%s,%s,%s)"

            val = (self.poloshirtisimlineEdit.text(), self.poloshirtfiyatlineEdit.text(), self.poloshirtresimurllineEdit.text())
            cursor.execute(query, val)
            conn.commit()
            # tabloyu update etme yöntemı
            self.updateview()
            self.poloshirtfiyatlineEdit.clear()
            self.poloshirtisimlineEdit.clear()
            self.poloshirtresimurllineEdit.clear()
            self.poloshirtidlineEdit.clear()
    def silbuton(self):
        if (self.poloshirtidlineEdit.text()==""):
            return
        else:

            conn = pymysql.connect(host="localhost", user="******", passwd="12345678", db="bilisim_proje_odevi")
            cursor = conn.cursor(pymysql.cursors.DictCursor)

            query = "DELETE FROM `poloshirt` where id=%s"

            val = (self.poloshirtidlineEdit.text())
            cursor.execute(query,val)
            conn.commit()
            self.updateview()
            self.poloshirtidlineEdit.clear()

    def duzenlebuton(self):
        if (self.poloshirtidlineEdit.text()==""or self.poloshirtfiyatlineEdit.text() == "" or self.poloshirtisimlineEdit.text() == "" or self.poloshirtresimurllineEdit.text() == ""):
            return
        else:
            conn = pymysql.connect(host="localhost", user="******", passwd="12345678", db="bilisim_proje_odevi")
            cursor = conn.cursor(pymysql.cursors.DictCursor)

            query = "UPDATE `poloshirt` SET poloshirt_isim=%s,poloshirt_fiyat=%s,poloshirt_resimurl=%s  where id=%s"

            val = (self.poloshirtisimlineEdit.text(),self.poloshirtfiyatlineEdit.text(),self.poloshirtresimurllineEdit.text(),self.poloshirtidlineEdit.text())
            cursor.execute(query, val)
            conn.commit()
            self.updateview()
            self.poloshirtidlineEdit.clear()
            self.poloshirtfiyatlineEdit.clear()
            self.poloshirtisimlineEdit.clear()
            self.poloshirtresimurllineEdit.clear()
            self.poloshirtidlineEdit.clear()

    def updateview(self):
        model = self.treetablemodelyaratma(self)
        self.treeWidget.setModel(model)
        self.treetablemodelyaratma2(model)

    def treetablemodelyaratma2(self, model):
        conn = pymysql.connect(host="localhost", user="******", passwd="12345678", db="bilisim_proje_odevi")

        cursor = conn.cursor(pymysql.cursors.DictCursor)

        query = "SELECT * FROM `poloshirt`"
        cursor.execute(query)

        data = cursor.fetchall()

        for row in data:
            model.insertRow(0)
            model.setData(model.index(0, self.POLOSHİRTID), row['id'])
            model.setData(model.index(0, self.POLOSHİRTISIM), row['poloshirt_isim'])
            model.setData(model.index(0, self.POLOSHİRTFIYAT), row['poloshirt_fiyat'])
            model.setData(model.index(0, self.RESIMURL), row['poloshirt_resimurl'])

    def retranslateUi(self, PoloshirtWindow):
        _translate = QtCore.QCoreApplication.translate
        PoloshirtWindow.setWindowTitle(_translate("PoloshirtWindow", "Poloshirtwindow"))
        self.poloshirtisimlabel.setText(_translate("PoloshirtWindow", "Poloshirt isim:"))
        self.poloshirtfyatlabel.setText(_translate("PoloshirtWindow", "Poloshirt Fiyat:"))
        self.poloshirtidlabel.setText(_translate("PoloshirtWindow", "ID:"))
        self.poloshirtresimurllabel.setText(_translate("PoloshirtWindow", "Resim_Url"))
        self.poloshirteklebuton.setText(_translate("PoloshirtWindow", "Ekle"))
        self.poloshirtduzenlebuton.setText(_translate("PoloshirtWindow", "Düzenle"))
        self.poloshirtsilbuton.setText(_translate("PoloshirtWindow", "Sil"))

        self.label.setText(_translate("PoloshirtWindow", "TAYFUN TESKTİL ÜRÜN DÜZENLEME"))
        self.label_3.setText(_translate("PoloshirtWindow", "POLOSHİRT"))
        self.actionPoloshirt.setText(_translate("PoloshirtWindow", "Poloshirt"))
        self.actionPoloshirt.setText(_translate("PoloshirtWindow", "Poloshirt"))
        self.actionPoloshirt.setText(_translate("PoloshirtWindow", "Poloshirt"))
        self.actioncgiyim.setText(_translate("PoloshirtWindow", "İcgiyim"))
예제 #28
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """
    def __init__(self, workspace):
        DockWidget.__init__(self, workspace, "&Opened Files",
                            QIcon(":/enkiicons/filtered.png"), "Alt+O")

        self._workspace = workspace

        self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        self.tvFiles = QTreeView(self)
        self.tvFiles.setHeaderHidden(True)
        self.tvFiles.setEditTriggers(QAbstractItemView.SelectedClicked)
        self.tvFiles.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tvFiles.setDragEnabled(True)
        self.tvFiles.setDragDropMode(QAbstractItemView.InternalMove)
        self.tvFiles.setRootIsDecorated(False)
        self.tvFiles.setTextElideMode(Qt.ElideMiddle)
        self.tvFiles.setUniformRowHeights(True)

        self.tvFiles.customContextMenuRequested.connect(
            self._onTvFilesCustomContextMenuRequested)

        self.setWidget(self.tvFiles)
        self.setFocusProxy(self.tvFiles)

        self.model = _OpenedFileModel(
            self)  # Not protected, because used by Configurator
        self.tvFiles.setModel(self.model)
        self.tvFiles.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.tvFiles.setAttribute(Qt.WA_MacSmallSize)

        self._workspace.currentDocumentChanged.connect(
            self._onCurrentDocumentChanged)

        # disconnected by startModifyModel()
        self.tvFiles.selectionModel().selectionChanged.connect(
            self._onSelectionModelSelectionChanged)

        self.tvFiles.activated.connect(self._workspace.focusCurrentDocument)

        core.actionManager().addAction("mView/aOpenedFiles", self.showAction())

    def terminate(self):
        """Explicitly called destructor
        """
        core.actionManager().removeAction("mView/aOpenedFiles")

    def startModifyModel(self):
        """Blocks signals from model while it is modified by code
        """
        self.tvFiles.selectionModel().selectionChanged.disconnect(
            self._onSelectionModelSelectionChanged)

    def finishModifyModel(self):
        """Unblocks signals from model
        """
        self.tvFiles.selectionModel().selectionChanged.connect(
            self._onSelectionModelSelectionChanged)

    @pyqtSlot(Document, Document)
    def _onCurrentDocumentChanged(self, oldDocument, currentDocument):  # pylint: disable=W0613
        """ Current document has been changed on workspace
        """
        if currentDocument is not None:
            index = self.model.documentIndex(currentDocument)

            self.startModifyModel()
            self.tvFiles.setCurrentIndex(index)
            # scroll the view
            self.tvFiles.scrollTo(index)
            self.finishModifyModel()

    @pyqtSlot(QItemSelection, QItemSelection)
    def _onSelectionModelSelectionChanged(self, selected, deselected):  # pylint: disable=W0613
        """ Item selected in the list. Switch current document
        """
        if not selected.indexes():  # empty list, last file closed
            return

        index = selected.indexes()[0]
        # backup/restore current focused widget as setting active mdi window will steal it
        focusWidget = self.window().focusWidget()

        # set current document
        document = self._workspace.sortedDocuments[index.row()]
        self._workspace.setCurrentDocument(document)

        # restore focus widget
        if focusWidget:
            focusWidget.setFocus()

    @pyqtSlot(QPoint)
    def _onTvFilesCustomContextMenuRequested(self, pos):
        """Connected automatically by uic
        """
        menu = QMenu()

        menu.addAction(core.actionManager().action("mFile/mClose/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mSave/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mReload/aCurrent"))
        menu.addSeparator()
        menu.addAction(
            core.actionManager().action("mFile/mFileSystem/aRename"))
        toggleExecutableAction = core.actionManager().action(
            "mFile/mFileSystem/aToggleExecutable")
        if toggleExecutableAction:  # not available on Windows
            menu.addAction(toggleExecutableAction)
        core.actionManager().action("mFile/mFileSystem").menu(
        ).aboutToShow.emit()  # to update aToggleExecutable

        menu.exec_(self.tvFiles.mapToGlobal(pos))
예제 #29
0
class OperacaoLogistica(QDialog):
    #TODO: Acertar formatação na listagem de items por SIMAFIC
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowMinMaxButtonsHint
                            | Qt.WindowCloseButtonHint)
        self.setWindowTitle('Operação Logística')
        self.setMinimumSize(QSize(h_size, v_size))
        self.setWindowIcon(QIcon(main_icon))

        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)

        #Pedido Input Field
        self.proxy_list_result_id = QSortFilterProxyModel()
        self.numero_pedido = QLineEdit(self)
        self.numero_pedido.setPlaceholderText("Insira o Número do Pedido")
        self.numero_pedido.textChanged.connect(
            lambda wildcard: self.proxy_list_result_id.setFilterWildcard(
                wildcard))

        #Voltar Btn
        self.voltar_btn = QPushButton(self)
        #self.voltar_btn.setStyleSheet('background-color: rgb(0,0,255); color: #fff')
        self.voltar_btn.setText('Voltar')
        self.voltar_btn.clicked.connect(self.goMainWindow)
        self.close()

        #Adicionar Cores no StyleSheet
        colors = ['##393318', '  ##fff']
        self.pedidos = services.get_all_pedidos()
        self.item_result = None
        self.item_escolhido = None

        self.id_pedido_list = QListView()
        self.simafics_do_id = QListWidget()
        #self.simafics_do_id.setHidden(True)
        self.createPedidoIdList()

        self.id_pedido_list.clicked.connect(
            lambda id_pedido: self.createListaSimafics(id_pedido))
        self.simafics_do_id.itemDoubleClicked.connect(
            lambda pedido: self.simaficSelecionado(pedido))

        self.pedidos_label = QLabel()
        self.pedidos_label.setBuddy(self.id_pedido_list)
        self.simafic_label = QLabel()
        self.simafic_label.setBuddy(self.simafics_do_id)

        self.itensTree = PedidoItensTree()
        self.treeItensTV = QTreeView()
        self.treeItensTV.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.treeItensTV.setAlternatingRowColors(True)
        self.treeItensTV.setRootIsDecorated(True)
        self.treeItensTV.doubleClicked.connect(self.simaficSelecionado)
        self.treeItensTV.setColumnHidden(8, True)

        if len(self.pedidos) <= 0:
            self.pedidos_label.setText(
                "É necessário adicionar um pedido na tela de cadastro.")
            self.pedidos_label.setStyleSheet("QLabel { color: red; }")
        else:
            self.pedidos_label.setText("Listagem de Pedidos:")
            self.pedidos_label.setStyleSheet("QLabel { color: black; }")
            self.simafic_label.setText(
                "Selecione um pedido para ver a listagem de Itens por SIMAFIC:"
            )
            self.simafic_label.setStyleSheet("QLabel { color: red; }")

        layout = QGridLayout()
        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 4)
        layout.addWidget(self.numero_pedido, 0, 0)
        layout.addWidget(self.voltar_btn, 0, 1)
        layout.addWidget(self.pedidos_label, 1, 0)
        layout.addWidget(self.simafic_label, 1, 1)
        layout.addWidget(self.id_pedido_list, 2, 0)
        layout.addWidget(self.treeItensTV, 2, 1)
        #layout.addWidget(self.simafics_do_id, 2,1)
        self.setLayout(layout)

    def createPedidoIdList(self):
        print('def createPedidoIdList(self):')
        onlyids = set()
        pedidosbyid = []
        pedidosCompletos = []
        self.proxy_list_result_id = QSortFilterProxyModel()
        for obj in self.pedidos:
            if obj.id_pedido not in onlyids:
                pedidosbyid.append(obj)
                onlyids.add(obj.id_pedido)

        self.pedidoId_model = QStringListModel(onlyids, self)
        self.proxy_list_result_id.setSourceModel(self.pedidoId_model)
        self.id_pedido_list.setModel(self.proxy_list_result_id)
        self.id_pedido_list.setAlternatingRowColors(True)
        self.id_pedido_list.setEditTriggers(QAbstractItemView.NoEditTriggers)

    def createListaSimafics(self, id_pedido):

        pedido = id_pedido.data()
        self.pedidosModel = self.itensTree.createPedidosModel(self.itensTree)
        self.treeItensTV.setModel(self.pedidosModel)
        print('def listaSimafics(self, id_pedido): {id_pedido}'.format(
            id_pedido=pedido))
        self.item_result = None
        self.item_result = [x for x in self.pedidos if x.id_pedido == pedido]
        self.simafics_do_id.clear()
        self.pedidosModel.beginResetModel
        self.pedidosModel.modelReset
        self.pedidosModel.endResetModel

        for idx, item in enumerate(self.item_result):
            print(item)
            self.itensTree.addItens(
                self.pedidosModel, item.cod_simafic, item.desc,
                item.qty_scanneada, item.qty_total, item.nome_responsavel,
                item.id_caixa, item.time_updated.strftime("%d/%m/%y %H:%M:%S"),
                item.id_pedido, item)

        self.simafic_label.setText(
            "Listagem de Itens do pedido {} por SIMAFIC:".format(pedido))
        self.simafic_label.setStyleSheet("QLabel { color: black; }")

        #self.simafics_do_id.setHidden(False)

    def simaficSelecionado(self, item):
        print(item.column(), item.row())
        simafic_escolhido = self.treeItensTV.model().index(item.row(),
                                                           0).data()
        id_pedido = self.treeItensTV.model().index(item.row(), 7).data()
        self.item_escolhido = [
            x for x in self.item_result
            if x.cod_simafic == simafic_escolhido and x.id_pedido == id_pedido
        ]
        self.cams = ItemScanner(self.item_escolhido[0])
        self.cams.show()
        self.close()

    def goMainWindow(self):
        self.cams = mainView
        self.cams.show()
        self.close()

    def goScan(self):
        self.cams = ItemScanner("Eu sou o Pedido", "Eu sou o Simafic",
                                "Eu sou a Descrição", "300")
        self.cams.show()
        self.close()
class ProjectStatusDialog(QDialog):

    icons = {
        'added': 'images/FA_icons/plus.svg',
        'removed': 'images/FA_icons/trash.svg',
        'updated': 'images/FA_icons/edit.svg',
        'renamed': 'images/FA_icons/edit.svg',
        'table': 'images/FA_icons/table.svg'
    }

    def __init__(self,
                 pull_changes,
                 push_changes,
                 push_changes_summary,
                 has_write_permissions,
                 parent=None):
        super(ProjectStatusDialog, self).__init__(parent)

        self.setWindowTitle("Project status")
        self.table = QTreeView()
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(["Status"])
        self.table.setModel(self.model)

        self.add_content(pull_changes, 'Server changes', True)
        self.add_content(push_changes, 'Local changes', False,
                         push_changes_summary)
        self.table.expandAll()

        box = QDialogButtonBox(
            QDialogButtonBox.Ok,
            centerButtons=True,
        )
        box.accepted.connect(self.accept)
        box.rejected.connect(self.reject)

        lay = QVBoxLayout(self)
        lay.addWidget(self.table)
        has_files_to_replace = any([
            "diff" not in file and is_versioned_file(file['path'])
            for file in push_changes["updated"]
        ])
        info_text = self._get_info_text(has_files_to_replace,
                                        has_write_permissions)
        if info_text:
            text_box = QLabel()
            text_box.setWordWrap(True)
            text_box.setText(info_text)
            lay.addWidget(text_box)
        lay.addWidget(box, Qt.AlignCenter)

        self.resize(640, 640)

    def _get_info_text(self, has_files_to_replace, has_write_permissions):
        msg = ""
        if not has_write_permissions:
            msg += f"WARNING: You don't have writing permissions to this project. Changes won't be synced!\n"

        if has_files_to_replace:
            msg += f"\nWARNING: Unable to compare some of the modified files with their server version - " \
                   f"their history will be lost if uploaded."
        return msg

    def add_content(self, changes, root_text, is_server, changes_summary={}):
        """
        Adds rows with changes info
        :param changes: Dict of added/removed/updated/renamed changes
        :param root_text: Text for the root item
        :param is_server: True if changes are related to server file changes
        :param changes_summary: If given and non empty, extra rows are added from geodiff summary.
        :return:
        """
        if all(not changes[k] for k in changes):
            return

        root_item = QStandardItem(root_text)
        self.model.appendRow(root_item)
        for category in changes:
            for file in changes[category]:
                path = file['path']
                item = self._get_icon_item(category, path)
                if is_versioned_file(path):
                    if path in changes_summary:
                        for sub_item in self._versioned_file_summary_items(
                                changes_summary[path]['geodiff_summary']):
                            item.appendRow(sub_item)
                    elif not is_server:
                        item.appendRow(
                            QStandardItem("Unable to detect changes"))
                root_item.appendRow(item)

    def _versioned_file_summary_items(self, geodiff_summary):
        items = []
        for s in geodiff_summary:
            table_name_item = self._get_icon_item('table', s['table'])
            for row in self._table_summary_items(s):
                table_name_item.appendRow(row)
            items.append(table_name_item)

        return items

    def _table_summary_items(self, summary):
        return [
            QStandardItem("{}: {}".format(k, summary[k])) for k in summary
            if k != 'table'
        ]

    def _get_icon_item(self, key, text):
        path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                            self.icons[key])
        item = QStandardItem(text)
        item.setIcon(QIcon(path))
        return item
예제 #31
0
class DataViewer(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMinimumSize(500, 400)
        main_layout = QHBoxLayout()
        main_layout.setSpacing(5)
        self.setLayout(main_layout)

        control_column = QVBoxLayout()
        main_layout.addLayout(control_column, stretch=1)

        refresh_button = QPushButton('🔄 Refresh')
        refresh_button.setFont(cn.EMOJI_FONT)
        refresh_button.clicked.connect(self.refresh_list)
        control_column.addWidget(refresh_button)

        self.gesture_tree_view = QTreeView()
        self.gesture_tree_view.setMinimumWidth(250)
        self.gesture_tree_view.header().hide()
        self.gesture_tree_view.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        self.gesture_tree_view.clicked.connect(self.show_selected)
        self.gesture_tree_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.gesture_tree_view.customContextMenuRequested.connect(
            self.gesture_context_menu)

        self.gesture_model = QStandardItemModel()
        self.gesture_tree_view.setModel(self.gesture_model)
        self.gesture_tree_view.setAnimated(True)
        control_column.addWidget(self.gesture_tree_view)

        self.displayed_gestures_layout = QVBoxLayout()

        display_column = QVBoxLayout()

        close_all_button = QPushButton('❌ Close all opened')
        close_all_button.setFont(cn.EMOJI_FONT)

        def close_all_displayed_gestures():
            for i in range(self.displayed_gestures_layout.count()):
                self.displayed_gestures_layout.itemAt(i).widget().close()

        close_all_button.clicked.connect(close_all_displayed_gestures)

        control_column.addWidget(close_all_button)
        display_column.addLayout(
            VerticalScrollableExtension(self.displayed_gestures_layout))
        main_layout.addLayout(display_column, stretch=2)

        self.refresh_list()

    def refresh_list(self):
        gestures = sorted(os.listdir(cn.DATA_FOLDER))

        gesture_tree = {}
        for gesture in gestures:
            parts = gesture.split(cn.FILE_NAME_SEPARATOR)
            if parts[0] == cn.SESSION_PREFIX:
                continue

            if len(parts) < 3 or parts[0] != cn.GESTURE_PREFIX:
                logger.debug(f'Skipping file {gesture}, unknown naming.')
                continue

            index = int(parts[1])
            if index < 0 or index >= len(cn.GESTURES):
                logger.debug(f'Invalid index on {gesture}, skipping.')
                continue

            gesture = cn.GESTURES[index]
            parts[1] = str(gesture)

            current_node = gesture_tree
            for part in parts[1:]:
                current_node = current_node.setdefault(part, {})

        self.gesture_model.clear()
        root = self.gesture_model.invisibleRootItem()

        def add_tree(tree: dict, node: QStandardItem):
            for item in tree:
                child_node = QStandardItem(item)
                node.appendRow(child_node)
                add_tree(tree[item], child_node)

        add_tree(gesture_tree, root)

    @staticmethod
    def get_filename(model_index):
        name = []
        node = model_index
        while node.isValid():
            name.append(node.data())
            node = node.parent()
        name.append(cn.GESTURE_PREFIX)

        # TODO this could be nicer
        for i, gesture_spec in enumerate(cn.GESTURES):
            if str(gesture_spec) == name[-2]:
                name[-2] = str(i)
        return cn.FILE_NAME_SEPARATOR.join(name[::-1])

    def show_selected(self, model_index):
        is_leaf = not model_index.child(0, 0).isValid()
        if not is_leaf:
            self.gesture_tree_view.setExpanded(
                model_index,
                not self.gesture_tree_view.isExpanded(model_index))
            return

        filename = DataViewer.get_filename(model_index)
        selected_file = cn.DATA_FOLDER / filename
        data = np.load(selected_file)

        signal_widget = StaticSignalWidget()
        signal_widget.plot_data(data)
        widget = NamedExtension(filename, signal_widget)
        widget = BlinkExtension(widget)
        widget = ClosableExtension(widget)
        widget.setMinimumWidth(600)
        widget.setFixedHeight(200)

        self.displayed_gestures_layout.addWidget(widget)

    def gesture_context_menu(self, point):
        model_index = self.gesture_tree_view.indexAt(point)
        is_leaf = not model_index.child(0, 0).isValid()
        if not is_leaf:
            self.gesture_tree_view.setExpanded(
                model_index,
                not self.gesture_tree_view.isExpanded(model_index))
            return

        menu = QMenu()

        def move_dialog():
            Renamer(DataViewer.get_filename(model_index)).exec()

        menu.addAction('Move', move_dialog)

        def trash_and_remove_from_tree():
            if Renamer.trash_gesture(DataViewer.get_filename(model_index)):
                self.gesture_model.removeRow(model_index.row(),
                                             model_index.parent())

        menu.addAction('Trash', trash_and_remove_from_tree)
        menu.exec(QCursor.pos())
class _PlatformGui(QWidget):
    """ The platform-specific GUI. """
    def __init__(self, platform_name):
        """ Initialise the object. """

        super().__init__()

        self._project = None
        self._platform_name = platform_name

        self._ignore_extlib_changes = False

        layout = QVBoxLayout()

        self._pyshlib_cb = QCheckBox(
            "Use standard Python shared library",
            whatsThis="Use the standard Python shared library rather than "
            "a statically compiled library.",
            stateChanged=self._pyshlib_changed)
        layout.addWidget(self._pyshlib_cb)

        self._extlib_edit = QTreeView(
            whatsThis="This is the list of external libraries that must "
            "be linked with the application for this platform. A "
            "library will only be enabled if a module in the "
            "standard library uses it. Double-click in the "
            "<b>DEFINES</b>, <b>INCLUDEPATH</b> and <b>LIBS</b> "
            "columns to modify the corresponding <tt>qmake</tt> "
            "variable as required.")
        self._extlib_edit.setRootIsDecorated(False)
        self._extlib_edit.setEditTriggers(QTreeView.DoubleClicked
                                          | QTreeView.SelectedClicked
                                          | QTreeView.EditKeyPressed)

        model = QStandardItemModel(self._extlib_edit)
        model.setHorizontalHeaderLabels(
            ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS'))
        model.itemChanged.connect(self._extlib_changed)

        model._items = {}

        for extlib in external_libraries_metadata:
            name_itm = QStandardItem(extlib.user_name)

            items = (name_itm, QStandardItem(), QStandardItem(),
                     QStandardItem())

            model.appendRow(items)

            model._items[extlib.name] = items

        self._extlib_edit.setModel(model)

        for col in range(3):
            self._extlib_edit.resizeColumnToContents(col)

        layout.addWidget(self._extlib_edit)

        self.setLayout(layout)

    def update_from_project(self, project):
        """ Update the GUI to reflect the current state of the project. """

        self._project = project

        platform_name = self._platform_name

        # Update the shared library state.
        blocked = self._pyshlib_cb.blockSignals(True)
        self._pyshlib_cb.setCheckState(Qt.Checked if platform_name in project.
                                       python_use_platform else Qt.Unchecked)
        self._pyshlib_cb.blockSignals(blocked)

        # Update the external libraries.
        model = self._extlib_edit.model()

        blocked = model.blockSignals(True)

        external_libs = project.external_libraries.get(platform_name, [])

        for extlib in external_libraries_metadata:
            _, defs, incp, libs = model._items[extlib.name]

            for prj_extlib in external_libs:
                if prj_extlib.name == extlib.name:
                    defs.setText(prj_extlib.defines)
                    incp.setText(prj_extlib.includepath)
                    libs.setText(prj_extlib.libs)
                    break
            else:
                defs.setText(extlib.defines)
                incp.setText(extlib.includepath)
                libs.setText(extlib.get_libs(platform_name))

        model.blockSignals(blocked)

    def update_from_required_libraries(self, required_libraries):
        """ Update the GUI as the required external libraries changes. """

        items = self._extlib_edit.model()._items

        # Note that we can't simply block the model's signals as this would
        # interfere with the model/view interactions.
        self._ignore_extlib_changes = True

        for extlib in external_libraries_metadata:
            if extlib.name in required_libraries:
                for idx, itm in enumerate(items[extlib.name]):
                    itm.setFlags(
                        Qt.ItemIsEnabled
                        | Qt.ItemIsEditable if idx != 0 else Qt.ItemIsEnabled)
            else:
                for itm in items[extlib.name]:
                    itm.setFlags(Qt.NoItemFlags)

        self._ignore_extlib_changes = False

    def _pyshlib_changed(self, state):
        """ Invoked when the shared library state changes. """

        project = self._project
        platform_name = self._platform_name

        if state == Qt.Checked:
            project.python_use_platform.append(platform_name)
        else:
            project.python_use_platform.remove(platform_name)

        project.modified = True

    def _extlib_changed(self, itm):
        """ Invoked when an external library has changed. """

        if self._ignore_extlib_changes:
            return

        self._ignore_extlib_changes = True

        project = self._project
        platform_name = self._platform_name

        idx = self._extlib_edit.model().indexFromItem(itm)
        extlib = external_libraries_metadata[idx.row()]
        col = idx.column()

        # Get the project entry, creating it if necessary.
        external_libs = project.external_libraries.get(platform_name, [])

        for prj_extlib in external_libs:
            if prj_extlib.name == extlib.name:
                break
        else:
            prj_extlib = ExternalLibrary(extlib.name, '', '',
                                         extlib.get_libs(platform_name))
            external_libs.append(prj_extlib)
            project.external_libraries[platform_name] = external_libs

        # Update the project.
        text = itm.text().strip()

        if col == 1:
            prj_extlib.defines = text
        elif col == 2:
            prj_extlib.includepath = text
        elif col == 3:
            prj_extlib.libs = text

        # If the project entry corresponds to the default then remove it.
        if prj_extlib.defines == extlib.defines and prj_extlib.includepath == extlib.includepath and prj_extlib.libs == extlib.get_libs(
                platform_name):
            external_libs.remove(prj_extlib)
            if len(external_libs) == 0:
                del project.external_libraries[platform_name]

        project.modified = True

        self._ignore_extlib_changes = False
예제 #33
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """

    def __init__(self, workspace):
        DockWidget.__init__(self, workspace, "&Opened Files", QIcon(":/enkiicons/filtered.png"), "Alt+O")

        self._workspace = workspace

        self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        self.tvFiles = QTreeView(self)
        self.tvFiles.setHeaderHidden(True)
        self.tvFiles.setEditTriggers(QAbstractItemView.SelectedClicked)
        self.tvFiles.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tvFiles.setDragEnabled(True)
        self.tvFiles.setDragDropMode(QAbstractItemView.InternalMove)
        self.tvFiles.setRootIsDecorated(False)
        self.tvFiles.setTextElideMode(Qt.ElideMiddle)
        self.tvFiles.setUniformRowHeights(True)

        self.tvFiles.customContextMenuRequested.connect(self._onTvFilesCustomContextMenuRequested)

        self.setWidget(self.tvFiles)
        self.setFocusProxy(self.tvFiles)

        self.model = _OpenedFileModel(self)  # Not protected, because used by Configurator
        self.tvFiles.setModel(self.model)
        self.tvFiles.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.tvFiles.setAttribute(Qt.WA_MacSmallSize)

        self._workspace.currentDocumentChanged.connect(self._onCurrentDocumentChanged)

        # disconnected by startModifyModel()
        self.tvFiles.selectionModel().selectionChanged.connect(self._onSelectionModelSelectionChanged)

        self.tvFiles.activated.connect(self._workspace.focusCurrentDocument)

        core.actionManager().addAction("mView/aOpenedFiles", self.showAction())

        # Add auto-hide capability.
        self._waitForCtrlRelease = False
        core.actionManager().action("mNavigation/aNext").triggered.connect(
          self._setWaitForCtrlRelease)
        core.actionManager().action("mNavigation/aPrevious").triggered.connect(
          self._setWaitForCtrlRelease)
        QApplication.instance().installEventFilter(self)

    def terminate(self):
        """Explicitly called destructor
        """
        core.actionManager().removeAction("mView/aOpenedFiles")
        QApplication.instance().removeEventFilter(self)

    def startModifyModel(self):
        """Blocks signals from model while it is modified by code
        """
        self.tvFiles.selectionModel().selectionChanged.disconnect(self._onSelectionModelSelectionChanged)

    def finishModifyModel(self):
        """Unblocks signals from model
        """
        self.tvFiles.selectionModel().selectionChanged.connect(self._onSelectionModelSelectionChanged)

    @pyqtSlot(Document, Document)
    def _onCurrentDocumentChanged(self, oldDocument, currentDocument):  # pylint: disable=W0613
        """ Current document has been changed on workspace
        """
        if currentDocument is not None:
            index = self.model.documentIndex(currentDocument)

            self.startModifyModel()
            self.tvFiles.setCurrentIndex(index)
            # scroll the view
            self.tvFiles.scrollTo(index)
            self.finishModifyModel()

    @pyqtSlot(QItemSelection, QItemSelection)
    def _onSelectionModelSelectionChanged(self, selected, deselected):  # pylint: disable=W0613
        """ Item selected in the list. Switch current document
        """
        if not selected.indexes():  # empty list, last file closed
            return

        index = selected.indexes()[0]
        # backup/restore current focused widget as setting active mdi window will steal it
        focusWidget = self.window().focusWidget()

        # set current document
        document = self._workspace.sortedDocuments[index.row()]
        self._workspace.setCurrentDocument(document)

        # restore focus widget
        if focusWidget:
            focusWidget.setFocus()

    @pyqtSlot(QPoint)
    def _onTvFilesCustomContextMenuRequested(self, pos):
        """Connected automatically by uic
        """
        menu = QMenu()

        menu.addAction(core.actionManager().action("mFile/mClose/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mSave/aCurrent"))
        menu.addAction(core.actionManager().action("mFile/mReload/aCurrent"))
        menu.addSeparator()
        menu.addAction(core.actionManager().action("mFile/mFileSystem/aRename"))
        toggleExecutableAction = core.actionManager().action("mFile/mFileSystem/aToggleExecutable")
        if toggleExecutableAction:  # not available on Windows
            menu.addAction(toggleExecutableAction)
        core.actionManager().action("mFile/mFileSystem").menu().aboutToShow.emit()  # to update aToggleExecutable

        menu.exec_(self.tvFiles.mapToGlobal(pos))

    def _setWaitForCtrlRelease(self):
        # We can't see actual Ctrl+PgUp/PgDn keypresses, since these get eaten
        # by the QAction and don't even show up in the event filter below. We
        # want to avoid waiting for a Ctrl release if the menu item brought us
        # here. As a workaround, check that Ctrl is pressed. If so, it's
        # unlikely to be the menu item.
        if QApplication.instance().keyboardModifiers() & Qt.ControlModifier:
            self._waitForCtrlRelease = True
            self.show()
        else:
            # If this was a menu selection, then update the MRU list. We can't
            # do this now, since the current document hasn't been changed yet.
            QTimer.singleShot(0, self.model.sortDocuments)

    def eventFilter(self, obj, event):
        """An event filter that looks for ctrl key releases and focus out
           events."""
        # Wait for the user to release the Ctrl key.
        if ( self._waitForCtrlRelease and event.type() == QEvent.KeyRelease and
          event.key() == Qt.Key_Control and
          event.modifiers() == Qt.NoModifier):
            self.model.sortDocuments()
            self._waitForCtrlRelease = False
            if not self.isPinned():
                self.hide()
        # Look for a focus out event sent by the containing widget's focus
        # proxy.
        if event.type() == QEvent.FocusOut and obj == self.focusProxy():
            self.model.sortDocuments()
        return QObject.eventFilter(self, obj, event)
예제 #34
0
class DirectoriesDialog(QMainWindow):
    def __init__(self, app, **kwargs):
        super().__init__(None, **kwargs)
        self.app = app
        self.specific_actions = set()
        self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
        self.recentFolders = Recent(self.app, "recentFolders")
        self._setupUi()
        self._updateScanTypeList()
        self.directoriesModel = DirectoriesModel(self.app.model.directory_tree,
                                                 view=self.treeView)
        self.directoriesDelegate = DirectoriesDelegate()
        self.treeView.setItemDelegate(self.directoriesDelegate)
        self._setupColumns()
        self.app.recentResults.addMenu(self.menuLoadRecent)
        self.app.recentResults.addMenu(self.menuRecentResults)
        self.recentFolders.addMenu(self.menuRecentFolders)
        self._updateAddButton()
        self._updateRemoveButton()
        self._updateLoadResultsButton()
        self._updateActionsState()
        self._setupBindings()

    def _setupBindings(self):
        self.appModeRadioBox.itemSelected.connect(self.appModeButtonSelected)
        self.showPreferencesButton.clicked.connect(
            self.app.actionPreferences.trigger)
        self.scanButton.clicked.connect(self.scanButtonClicked)
        self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger)
        self.addFolderButton.clicked.connect(self.actionAddFolder.trigger)
        self.removeFolderButton.clicked.connect(self.removeFolderButtonClicked)
        self.treeView.selectionModel().selectionChanged.connect(
            self.selectionChanged)
        self.app.recentResults.itemsChanged.connect(
            self._updateLoadResultsButton)
        self.recentFolders.itemsChanged.connect(self._updateAddButton)
        self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
        self.directoriesModel.foldersAdded.connect(
            self.directoriesModelAddedFolders)
        self.app.willSavePrefs.connect(self.appWillSavePrefs)

    def _setupActions(self):
        # (name, shortcut, icon, desc, func)
        ACTIONS = [
            (
                "actionLoadResults",
                "Ctrl+L",
                "",
                tr("Load Results..."),
                self.loadResultsTriggered,
            ),
            (
                "actionShowResultsWindow",
                "",
                "",
                tr("Scan Results"),
                self.app.showResultsWindow,
            ),
            ("actionAddFolder", "", "", tr("Add Folder..."),
             self.addFolderTriggered),
            ("actionLoadDirectories", "", "", tr("Load Directories..."),
             self.loadDirectoriesTriggered),
            ("actionSaveDirectories", "", "", tr("Save Directories..."),
             self.saveDirectoriesTriggered),
        ]
        createActions(ACTIONS, self)
        if self.app.use_tabs:
            # Keep track of actions which should only be accessible from this window
            self.specific_actions.add(self.actionLoadDirectories)
            self.specific_actions.add(self.actionSaveDirectories)

    def _setupMenu(self):
        if not self.app.use_tabs:
            # we are our own QMainWindow, we need our own menu bar
            self.menubar = QMenuBar(self)
            self.menubar.setGeometry(QRect(0, 0, 42, 22))
            self.menuFile = QMenu(self.menubar)
            self.menuFile.setTitle(tr("File"))
            self.menuView = QMenu(self.menubar)
            self.menuView.setTitle(tr("View"))
            self.menuHelp = QMenu(self.menubar)
            self.menuHelp.setTitle(tr("Help"))
            self.setMenuBar(self.menubar)
            menubar = self.menubar
        else:
            # we are part of a tab widget, we populate its window's menubar instead
            self.menuFile = self.app.main_window.menuFile
            self.menuView = self.app.main_window.menuView
            self.menuHelp = self.app.main_window.menuHelp
            menubar = self.app.main_window.menubar

        self.menuLoadRecent = QMenu(self.menuFile)
        self.menuLoadRecent.setTitle(tr("Load Recent Results"))

        self.menuFile.addAction(self.actionLoadResults)
        self.menuFile.addAction(self.menuLoadRecent.menuAction())
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionClearPictureCache)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionLoadDirectories)
        self.menuFile.addAction(self.actionSaveDirectories)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.app.actionQuit)

        self.menuView.addAction(self.app.actionDirectoriesWindow)
        self.menuView.addAction(self.actionShowResultsWindow)
        self.menuView.addAction(self.app.actionIgnoreList)
        self.menuView.addSeparator()
        self.menuView.addAction(self.app.actionPreferences)

        self.menuHelp.addAction(self.app.actionShowHelp)
        self.menuHelp.addAction(self.app.actionOpenDebugLog)
        self.menuHelp.addAction(self.app.actionAbout)

        menubar.addAction(self.menuFile.menuAction())
        menubar.addAction(self.menuView.menuAction())
        menubar.addAction(self.menuHelp.menuAction())

        # Recent folders menu
        self.menuRecentFolders = QMenu()
        self.menuRecentFolders.addAction(self.actionAddFolder)
        self.menuRecentFolders.addSeparator()

        # Recent results menu
        self.menuRecentResults = QMenu()
        self.menuRecentResults.addAction(self.actionLoadResults)
        self.menuRecentResults.addSeparator()

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(420, 338)
        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(4, 0, 4, 0)
        self.verticalLayout.setSpacing(0)
        hl = QHBoxLayout()
        label = QLabel(tr("Application Mode:"), self)
        label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hl.addWidget(label)
        self.appModeRadioBox = RadioBox(
            self,
            items=[tr("Standard"), tr("Music"),
                   tr("Picture")],
            spread=False)
        hl.addWidget(self.appModeRadioBox)
        self.verticalLayout.addLayout(hl)
        hl = QHBoxLayout()
        hl.setAlignment(Qt.AlignLeft)
        label = QLabel(tr("Scan Type:"), self)
        label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hl.addWidget(label)
        self.scanTypeComboBox = QComboBox(self)
        self.scanTypeComboBox.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))
        self.scanTypeComboBox.setMaximumWidth(400)
        hl.addWidget(self.scanTypeComboBox)
        self.showPreferencesButton = QPushButton(tr("More Options"),
                                                 self.centralwidget)
        self.showPreferencesButton.setSizePolicy(QSizePolicy.Fixed,
                                                 QSizePolicy.Fixed)
        hl.addWidget(self.showPreferencesButton)
        self.verticalLayout.addLayout(hl)
        self.promptLabel = QLabel(
            tr('Select folders to scan and press "Scan".'), self.centralwidget)
        self.verticalLayout.addWidget(self.promptLabel)
        self.treeView = QTreeView(self.centralwidget)
        self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setAcceptDrops(True)
        triggers = (QAbstractItemView.DoubleClicked
                    | QAbstractItemView.EditKeyPressed
                    | QAbstractItemView.SelectedClicked)
        self.treeView.setEditTriggers(triggers)
        self.treeView.setDragDropOverwriteMode(True)
        self.treeView.setDragDropMode(QAbstractItemView.DropOnly)
        self.treeView.setUniformRowHeights(True)
        self.verticalLayout.addWidget(self.treeView)
        self.horizontalLayout = QHBoxLayout()
        self.removeFolderButton = QPushButton(self.centralwidget)
        self.removeFolderButton.setIcon(QIcon(QPixmap(":/minus")))
        self.removeFolderButton.setShortcut("Del")
        self.horizontalLayout.addWidget(self.removeFolderButton)
        self.addFolderButton = QPushButton(self.centralwidget)
        self.addFolderButton.setIcon(QIcon(QPixmap(":/plus")))
        self.horizontalLayout.addWidget(self.addFolderButton)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.loadResultsButton = QPushButton(self.centralwidget)
        self.loadResultsButton.setText(tr("Load Results"))
        self.horizontalLayout.addWidget(self.loadResultsButton)
        self.scanButton = QPushButton(self.centralwidget)
        self.scanButton.setText(tr("Scan"))
        self.scanButton.setDefault(True)
        self.horizontalLayout.addWidget(self.scanButton)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.setCentralWidget(self.centralwidget)

        self._setupActions()
        self._setupMenu()

        if self.app.prefs.directoriesWindowRect is not None:
            self.setGeometry(self.app.prefs.directoriesWindowRect)
        else:
            moveToScreenCenter(self)

    def _setupColumns(self):
        header = self.treeView.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.resizeSection(1, 100)

    def _updateActionsState(self):
        self.actionShowResultsWindow.setEnabled(
            self.app.resultWindow is not None)

    def _updateAddButton(self):
        if self.recentFolders.isEmpty():
            self.addFolderButton.setMenu(None)
        else:
            self.addFolderButton.setMenu(self.menuRecentFolders)

    def _updateRemoveButton(self):
        indexes = self.treeView.selectedIndexes()
        if not indexes:
            self.removeFolderButton.setEnabled(False)
            return
        self.removeFolderButton.setEnabled(True)

    def _updateLoadResultsButton(self):
        if self.app.recentResults.isEmpty():
            self.loadResultsButton.setMenu(None)
        else:
            self.loadResultsButton.setMenu(self.menuRecentResults)

    def _updateScanTypeList(self):
        try:
            self.scanTypeComboBox.currentIndexChanged[int].disconnect(
                self.scanTypeChanged)
        except TypeError:
            # Not connected, ignore
            pass
        self.scanTypeComboBox.clear()
        scan_options = self.app.model.SCANNER_CLASS.get_scan_options()
        for scan_option in scan_options:
            self.scanTypeComboBox.addItem(scan_option.label)
        SCAN_TYPE_ORDER = [so.scan_type for so in scan_options]
        selected_scan_type = self.app.prefs.get_scan_type(
            self.app.model.app_mode)
        scan_type_index = SCAN_TYPE_ORDER.index(selected_scan_type)
        self.scanTypeComboBox.setCurrentIndex(scan_type_index)
        self.scanTypeComboBox.currentIndexChanged[int].connect(
            self.scanTypeChanged)
        self.app._update_options()

    # --- QWidget overrides
    def closeEvent(self, event):
        event.accept()
        if self.app.model.results.is_modified:
            title = tr("Unsaved results")
            msg = tr("You have unsaved results, do you really want to quit?")
            if not self.app.confirm(title, msg):
                event.ignore()
        if event.isAccepted():
            self.app.shutdown()

    # --- Events
    def addFolderTriggered(self):
        title = tr("Select a folder to add to the scanning list")
        flags = QFileDialog.ShowDirsOnly
        dirpath = str(
            QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder,
                                             flags))
        if not dirpath:
            return
        self.lastAddedFolder = dirpath
        self.app.model.add_directory(dirpath)
        self.recentFolders.insertItem(dirpath)

    def appModeButtonSelected(self, index):
        if index == 2:
            mode = AppMode.Picture
        elif index == 1:
            mode = AppMode.Music
        else:
            mode = AppMode.Standard
        self.app.model.app_mode = mode
        self._updateScanTypeList()

    def appWillSavePrefs(self):
        self.app.prefs.directoriesWindowRect = self.geometry()

    def directoriesModelAddedFolders(self, folders):
        for folder in folders:
            self.recentFolders.insertItem(folder)

    def loadResultsTriggered(self):
        title = tr("Select a results file to load")
        files = ";;".join(
            [tr("dupeGuru Results (*.dupeguru)"),
             tr("All Files (*.*)")])
        destination = QFileDialog.getOpenFileName(self, title, "", files)[0]
        if destination:
            self.app.model.load_from(destination)
            self.app.recentResults.insertItem(destination)

    def loadDirectoriesTriggered(self):
        title = tr("Select a directories file to load")
        files = ";;".join(
            [tr("dupeGuru Results (*.dupegurudirs)"),
             tr("All Files (*.*)")])
        destination = QFileDialog.getOpenFileName(self, title, "", files)[0]
        if destination:
            self.app.model.load_directories(destination)

    def removeFolderButtonClicked(self):
        self.directoriesModel.model.remove_selected()

    def saveDirectoriesTriggered(self):
        title = tr("Select a file to save your directories to")
        files = tr("dupeGuru Directories (*.dupegurudirs)")
        destination, chosen_filter = QFileDialog.getSaveFileName(
            self, title, "", files)
        if destination:
            if not destination.endswith(".dupegurudirs"):
                destination = "{}.dupegurudirs".format(destination)
            self.app.model.save_directories_as(destination)

    def scanButtonClicked(self):
        if self.app.model.results.is_modified:
            title = tr("Start a new scan")
            msg = tr(
                "You have unsaved results, do you really want to continue?")
            if not self.app.confirm(title, msg):
                return
        self.app.model.start_scanning()

    def scanTypeChanged(self, index):
        scan_options = self.app.model.SCANNER_CLASS.get_scan_options()
        self.app.prefs.set_scan_type(self.app.model.app_mode,
                                     scan_options[index].scan_type)
        self.app._update_options()

    def selectionChanged(self, selected, deselected):
        self._updateRemoveButton()
예제 #35
0
class ChessClaimView(QMainWindow):
    """ The main window of the application.
    Attributes:
        rowCount(int): The number of the row the TreeView Table has.
        iconsSize(int): The recommended size of the icons.
        mac_notification: Notification for macOS
        win_notification: Notification for windows OS
    """
    def __init__(self):
        super().__init__()

        self.resize(720, 275)
        self.iconsSize = 16
        self.setWindowTitle('Chess Claim Tool')
        self.center()

        self.rowCount = 0

        if (platform.system() == "Darwin"):
            from MacNotification import Notification
            self.mac_notification = Notification()
        elif (platform.system() == "Windows"):
            from win10toast import ToastNotifier
            self.win_notification = ToastNotifier()

    def center(self):
        """ Centers the window on the screen """
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2,
            (screen.height()-size.height())/2)

    def set_GUI(self):
        """ Initialize GUI components. """

        # Create the Menu
        self.livePgnOption = QAction('Live PGN',self)
        self.livePgnOption.setCheckable(True)
        aboutAction = QAction('About',self)

        menubar = self.menuBar()

        optionsMenu = menubar.addMenu('&Options')
        optionsMenu.addAction(self.livePgnOption)

        aboutMenu = menubar.addMenu('&Help')
        aboutMenu.addAction(aboutAction)

        aboutAction.triggered.connect(self.slots.on_about_clicked)

        # Create the Claims Table (TreeView)
        self.claimsTable = QTreeView()
        self.claimsTable.setFocusPolicy(Qt.NoFocus)
        self.claimsTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.claimsTable.header().setDefaultAlignment(Qt.AlignCenter)
        self.claimsTable.setSortingEnabled(True)
        self.claimsTable.doubleClicked.connect(self.open_game)

        # Create the Claims Model
        self.claimsTableModel = QStandardItemModel()
        labels = ["#","Timestamp","Type","Board","Players","Move"]
        self.claimsTableModel.setHorizontalHeaderLabels(labels)
        self.claimsTable.setModel(self.claimsTableModel)

        # Create the Scan & Stop Button Box
        self.buttonBox = ButtonBox(self)

        # Create the Sources Button
        sourcesButton = QPushButton("Add Sources")
        sourcesButton.setObjectName("sources")
        sourcesButton.clicked.connect(self.slots.on_sourcesButton_clicked)

        # Create the Status Bar
        self.pixmapCheck = QPixmap(resource_path("check_icon.png"))
        self.pixmapError = QPixmap(resource_path("error_icon.png"))

        self.sourceLabel = QLabel()
        self.sourceLabel.setObjectName("source-label")
        self.sourceImage = QLabel()
        self.sourceImage.setObjectName("source-image")
        self.downloadLabel = QLabel()
        self.downloadLabel.setObjectName("download-label")
        self.downloadImage = QLabel()
        self.downloadImage.setObjectName("download-image")
        self.scanningLabel = QLabel()
        self.scanningLabel.setObjectName("scanning")
        self.spinnerLabel = QLabel()
        self.spinnerLabel.setVisible(False)
        self.spinnerLabel.setObjectName("spinner")

        self.spinner = QMovie(resource_path("spinner.gif"))
        self.spinner.setScaledSize(QSize(self.iconsSize, self.iconsSize))
        self.spinnerLabel.setMovie(self.spinner)
        self.spinner.start()

        self.statusBar = QStatusBar()
        self.statusBar.setSizeGripEnabled(False)

        self.statusBar.addWidget(self.sourceLabel)
        self.statusBar.addWidget(self.sourceImage)
        self.statusBar.addWidget(self.downloadLabel)
        self.statusBar.addWidget(self.downloadImage)
        self.statusBar.addWidget(self.scanningLabel)
        self.statusBar.addWidget(self.spinnerLabel)
        self.statusBar.addPermanentWidget(sourcesButton)
        self.statusBar.setContentsMargins(10,5,9,5)

        # Container Layout for the Central Widget
        containerLayout = QVBoxLayout()
        containerLayout.setSpacing(0)
        containerLayout.addWidget(self.claimsTable)
        containerLayout.addWidget(self.buttonBox)

        # Central Widget
        containerWidget = QWidget()
        containerWidget.setLayout(containerLayout)

        self.setCentralWidget(containerWidget)
        self.setStatusBar(self.statusBar)

    def open_game(self):
        """ TODO: Double click should open a window to replay the game."""
        pass

    def resize_claimsTable(self):
        """ Resize the table (if needed) after the insertion of a new element"""
        for index in range(0,6):
            self.claimsTable.resizeColumnToContents(index)

    def set_slots(self, slots):
        """ Connect the Slots """
        self.slots = slots

    def add_to_table(self,type,bo_number,players,move):
        """ Add new row to the claimsTable
        Args:
            type: The type of the draw (3 Fold Repetition, 5 Fold Repetition,
                                        50 Moves Rule, 75 Moves Rule).
            bo_number: The number of the boards, if this information is available.
            players: The name of the players.
            move: With which move the draw is valid.
        """

        # Before insertion, remove rows as descripted in the remove_rows function
        self.remove_rows(type,players)

        timestamp = str(datetime.now().strftime('%H:%M:%S'))
        row = []
        items = [str(self.rowCount+1),timestamp,type,bo_number,players,move]

        """ Convert each item(str) to QStandardItem, make the necessary stylistic
        additions and append it to row."""

        for index in range(len(items)):
            standardItem = QStandardItem(items[index])
            standardItem.setTextAlignment(Qt.AlignCenter)

            if(index == 2):
                font = standardItem.font()
                font.setBold(True)
                standardItem.setFont(font)

            if (items[index] == "5 Fold Repetition" or items[index] == "75 Moves Rule"):
                standardItem.setData(QColor(255,0,0), Qt.ForegroundRole)

            row.append(standardItem)

        self.claimsTableModel.appendRow(row)
        self.rowCount = self.rowCount+1

        # After the insertion resize the table
        self.resize_claimsTable()

        # Always the last row(the bottom of the table) should be visible.
        self.claimsTable.scrollToBottom()

        #Send Notification
        self.notify(type,players,move)

    def notify(self,type,players,move):
        """ Send notification depending on the OS.
        Args:
            type: The type of the draw (3 Fold Repetition, 5 Fold Repetition,
                                        50 Moves Rule, 75 Moves Rule).
            players: The names of the players.
            move: With which move the draw is valid.
        """
        if (platform.system() == "Darwin"):
            self.mac_notification.clearNotifications()
            self.mac_notification.notify(type,players,move)
        elif(platform.system() == "Windows"):
                self.win_notification.show_toast(type,
                                   players+"\n"+move,
                                   icon_path=resource_path("logo.ico"),
                                   duration=5,
                                   threaded=True)

    def remove_from_table(self,index):
        """ Remove element from the claimsTable.
        Args:
            index: The index of the row we want to remove. First row has index=0.
        """
        self.claimsTableModel.removeRow(index)

    def remove_rows(self,type,players):
        """ Removes a existing row from the Claims Table when same players made
        the same type of draw with a new move - or they made 5 Fold Repetition
        over the 3 Fold or 75 Moves Rule over 50 moves Rule.

        Args:
            type: The type of the draw (3 Fold Repetition, 5 Fold Repetition,
                                        50 Moves Rule, 75 Moves Rule).
            players: The names of the players.
        """
        for index in range(self.rowCount):

            try:
                modelType = self.claimsTableModel.item(index,2).text()
                modelPlayers = self.claimsTableModel.item(index,4).text()
            except AttributeError:
                modelType = ""
                modelPlayers = ""

            if (modelType == type and modelPlayers == players):
                self.remove_from_table(index)
                self.rowCount = self.rowCount - 1
                break
            elif (type == "5 Fold Repetition" and modelType == "3 Fold Repetition" and modelPlayers == players) :
                self.remove_from_table(index)
                self.rowCount = self.rowCount - 1
                break
            elif (type == "75 Moves Rule" and modelType == "50 Moves Rule" and modelPlayers == players):
                self.remove_from_table(index)
                self.rowCount = self.rowCount - 1
                break

    def clear_table(self):
        """ Clear all the elements off the Claims Table and resets the rowCount. """
        for index in range(self.rowCount):
            self.claimsTableModel.removeRow(0)
        self.rowCount = 0

    def set_sources_status(self,status,validSources=None):
        """ Adds the sourcess in the statusBar.
        Args:
            status(str): The status of the validity of the sources.
                "ok": At least one source is valid.
                "error": None of the sources are valid.
            validSources(list): The list of valid sources, if there is any.
                This list is used here to display the ToolTip.
        """
        self.sourceLabel.setText("Sources:")

        # Set the ToolTip if there are sources.
        try:
            text = ""
            for index in range(len(validSources)):
                if (index == len(validSources) - 1):
                    number = str(index+1)
                    text = text+number+") "+validSources[index].get_value()
                else:
                    number = str(index+1)
                    text = text+number+") "+validSources[index].get_value()+"\n"
            self.sourceLabel.setToolTip(text)
        except TypeError:
            pass

        if (status == "ok"):
            self.sourceImage.setPixmap(self.pixmapCheck.scaled(self.iconsSize,self.iconsSize,transformMode=Qt.SmoothTransformation))
        else:
            self.sourceImage.setPixmap(self.pixmapError.scaled(self.iconsSize,self.iconsSize,transformMode=Qt.SmoothTransformation))

    def set_download_status(self,status):
        """ Adds download status in the statusBar.
        Args:
            status(str): The status of the download(s).
                "ok": The download of the sources is successful.
                "error": The download of the sources failed.
                "stop": The download process stopped.
        """
        timestamp = str(datetime.now().strftime('%H:%M:%S'))
        self.downloadLabel.setText(timestamp+" Download:")
        if (status == "ok"):
            self.downloadImage.setPixmap(self.pixmapCheck.scaled(self.iconsSize,self.iconsSize,transformMode=Qt.SmoothTransformation))
        elif (status == "error"):
            self.downloadImage.setPixmap(self.pixmapError.scaled(self.iconsSize,self.iconsSize,transformMode=Qt.SmoothTransformation))
        elif (status == "stop"):
            self.downloadImage.clear()
            self.downloadLabel.clear()

    def set_scan_status(self,status):
        """ Adds the scan status in the statusBar.
        Args:
            status(str): The status of the scan process.
                "active": The scan process is active.
                "error": The scan process waits for a new file.
                "stop": The scan process stopped.
        """
        if (status == "wait"):
            self.scanningLabel.setText("Scan: Waiting")
            self.spinnerLabel.setVisible(False)
        elif (status == "active"):
            self.scanningLabel.setText("Scanning...")
            self.spinnerLabel.setVisible(True)
        elif (status == "stop"):
            self.scanningLabel.clear()
            self.spinnerLabel.setVisible(False)

    def change_scanButton_text(self,status):
        """ Changes the text of the scanButton depending on the status of the application.
        Args:
            status(str): The status of the scan process.
                "active": The scan process is active.
                "wait": The scan process is being terminated
                "stop": The scan process stopped.
        """
        if (status == "active"):
            self.buttonBox.scanButton.setText("Scanning PGN...")
        elif (status == "stop"):
            self.buttonBox.scanButton.setText("Start Scan")
        elif(status == "wait"):
            self.buttonBox.scanButton.setText("Please Wait")

    def enable_buttons(self):
        self.buttonBox.scanButton.setEnabled(True)
        self.buttonBox.stopButton.setEnabled(True)

    def disable_buttons(self):
        self.buttonBox.scanButton.setEnabled(False)
        self.buttonBox.stopButton.setEnabled(False)

    def enable_statusBar(self):
        """ Show download and scan status messages - if they were previously
        hidden (by disable_statusBar) - from the statusBar."""
        self.downloadLabel.setVisible(True)
        self.scanningLabel.setVisible(True)
        self.downloadImage.setVisible(True)

    def disable_statusBar(self):
        """ Hide download and scan status messages from the statusBar. """
        self.downloadLabel.setVisible(False)
        self.downloadImage.setVisible(False)
        self.scanningLabel.setVisible(False)
        self.spinnerLabel.setVisible(False)

    def closeEvent(self,event):
        """ Reimplement the close button
        If the program is actively scanning a pgn a warning dialog shall be raised
        in order to make sure that the user didn't clicked the close Button accidentally.
        Args:
            event: The exit QEvent.
        """
        try:
            if (self.slots.scanWorker.isRunning):
                exitDialog = QMessageBox()
                exitDialog.setWindowTitle("Warning")
                exitDialog.setText("Scanning in Progress")
                exitDialog.setInformativeText("Do you want to quit?")
                exitDialog.setIcon(exitDialog.Warning)
                exitDialog.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
                exitDialog.setDefaultButton(QMessageBox.Cancel)
                replay = exitDialog.exec()

                if replay == QMessageBox.Yes:
                    event.accept()
                else:
                    event.ignore()
        except:
            event.accept()

    def load_warning(self):
        """ Displays a Warning Dialog.
        trigger:
            User clicked the "Start Scanning" Button without any valid pgn source.
        """
        warningDialog = QMessageBox()
        warningDialog.setIcon(warningDialog.Warning)
        warningDialog.setWindowTitle("Warning")
        warningDialog.setText("PGN File(s) Not Found")
        warningDialog.setInformativeText("Please enter at least one valid PGN source.")
        warningDialog.exec()

    def load_about_dialog(self):
        """ Displays the About Dialog."""
        self.aboutDialog = AboutDialog()
        self.aboutDialog.set_GUI()
        self.aboutDialog.show()
예제 #36
0
class LeftSideBar(QWidget):

    treeViewSelectionChanged = pyqtSignal(QModelIndex, QModelIndex)
    treeViewDoubleClicked = pyqtSignal(QModelIndex)

    addPlaylistRequested = pyqtSignal()
    removePlaylistRequested = pyqtSignal(UUID)
    addToPlaylistRequested = pyqtSignal(UUID)

    playlistAdded = pyqtSignal(UUID)
    playlistRenamed = pyqtSignal(UUID, str)

    def __init__(self, tree_items, parent=None):
        super(LeftSideBar, self).__init__(parent)
        self._tree_items = tree_items
        self._restoreSettings()

        self._setTreeView()
        self._setAlbumCoverBox()

        self._renderUI()

        self.setMinimumWidth(FRONT_COVER_MIN_WIDTH)
        self.setMaximumWidth(FRONT_COVER_MAX_WIDTH)

    def _restoreSettings(self):
        pass

    def _setTreeView(self):
        self.treeModel = TreeModel()

        self.treeModel.addTopLevelItems(self._tree_items.keys())

        self.leftBarView = QTreeView()
        self.leftBarView.setModel(self.treeModel)
        self.leftBarView.setHeaderHidden(True)
        self.leftBarView.setRootIsDecorated(False)
        self.leftBarView.setItemsExpandable(False)
        self.leftBarView.setMouseTracking(True)
        self.leftBarView.expandAll()
        self.leftBarView.setFocusPolicy(Qt.NoFocus)
        self.leftBarView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.leftBarView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.leftBarView.setEditTriggers(QAbstractItemView.SelectedClicked)

        self.leftBarView.selectionModel().currentRowChanged.connect(
            lambda c, p: self.treeViewSelectionChanged.emit(c, p))

        self.leftBarView.selectionModel().setCurrentIndex(
            self.leftBarView.model().index(
                0, 0, self.leftBarView.model().index(0, 0)),
            QItemSelectionModel.Select)

        self.leftBarView.doubleClicked.connect(
            lambda i: self.treeViewDoubleClicked.emit(i))

        delegate = LeftSideBarDelegate(self.leftBarView)
        self.leftBarView.setItemDelegate(delegate)
        delegate.addPlaylistRequested.connect(
            lambda: self.addPlaylistRequested.emit())
        delegate.removePlaylistRequested.connect(
            lambda i: self.removePlaylistRequested.emit(
                self.__getUuidFromIndex(i)))
        delegate.addToPlaylistRequested.connect(
            lambda i:
            self.addToPlaylistRequested.emit(self.__getUuidFromIndex(i)))
        delegate.editingFinished.connect(self._onRenamed)

    def _onRenamed(self, index, text):
        self.playlistRenamed.emit(
            self.__getUuidFromIndex(index),
            text)

    @property
    def model(self):
        return self.treeModel

    def _setAlbumCoverBox(self):
        self.albumCoverBox = CoverArtBox()

    def _renderUI(self):
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.addWidget(self.leftBarView)
        self.layout.addWidget(self.albumCoverBox)
        self.setLayout(self.layout)

    @QtCore.pyqtSlot(str, str, bytes)
    def changeCoverArtBoxInformation(self, title, artist, cover):
        self.albumCoverBox.setCoverArtBox(title, artist, cover)

    @QtCore.pyqtSlot(UUID, str, int, int)
    def addPlaylistEntry(self, uuid, name, row=0, column=0):
        model = self.model
        parent = model.getTopLevelIndex('PLAYLISTS')
        if model.insertPlaylistEntry(row, name, uuid, parent):
            self.playlistAdded.emit(uuid)

        child = model.index(row, column, parent)
        self.leftBarView.selectionModel().setCurrentIndex(
            child, QItemSelectionModel.SelectCurrent)
        self.leftBarView.edit(child)

    @QtCore.pyqtSlot(UUID, int, int)
    def createDefaults(self, uuid, row=0, column=0):
        model = self.model
        parent = model.getTopLevelIndex('LIBRARY')
        model.insertPlaylistEntry(row, 'Songs', uuid, parent)

    def __getUuidFromIndex(self, index):
        model = self.model
        uuid = model.getItemUuid(index)
        return uuid

    def __getIndexFromUuid(self, uuid):
        model = self.model
        row = model.getIndexFromUuid(uuid)
        return row

    @QtCore.pyqtSlot(UUID)
    def removePlaylistEntry(self, uuid):
        model = self.model
        row = self.__getIndexFromUuid(uuid)
        parent = model.getTopLevelIndex('PLAYLISTS')

        if not model.removeRow(row, parent):
            return None
class ProjectStatusDialog(QDialog):

    icons = {
        "added": "images/FA_icons/plus.svg",
        "removed": "images/FA_icons/trash.svg",
        "updated": "images/FA_icons/edit.svg",
        "renamed": "images/FA_icons/edit.svg",
        "table": "images/FA_icons/table.svg",
    }

    def __init__(
        self, pull_changes, push_changes, push_changes_summary, has_write_permissions, validation_results,
            mergin_project=None, parent=None
    ):
        super(ProjectStatusDialog, self).__init__(parent)
        self.validation_results = validation_results
        self.setWindowTitle("Project status")
        self.table = QTreeView()
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(["Status"])
        self.table.setModel(self.model)
        self.mp = mergin_project

        self.check_any_changes(pull_changes, push_changes)
        self.add_content(pull_changes, "Server changes", True)
        self.add_content(push_changes, "Local changes", False, push_changes_summary)
        self.table.expandAll()

        main_lout = QVBoxLayout(self)
        self.tabs = QTabWidget()
        main_lout.addWidget(self.tabs)
        self.status_tab = QWidget()
        self.valid_tab = QWidget()
        self.tabs.addTab(self.status_tab, "Status")
        self.tabs.addTab(self.valid_tab, "Validation results")

        status_lay = QVBoxLayout(self.status_tab)
        status_lay.addWidget(self.table)
        has_files_to_replace = any(
            ["diff" not in file and is_versioned_file(file["path"]) for file in push_changes["updated"]]
        )
        info_text = self._get_info_text(has_files_to_replace, has_write_permissions)
        if info_text:
            text_box = QLabel()
            text_box.setWordWrap(True)
            text_box.setText(info_text)
            status_lay.addWidget(text_box)

        box = QDialogButtonBox(QDialogButtonBox.Ok, centerButtons=True,)
        box.accepted.connect(self.accept)
        box.rejected.connect(self.reject)
        main_lout.addWidget(box, Qt.AlignCenter)

        self.valid_view = QTreeView()
        self.valid_view.setStyleSheet("QTreeView::item { padding: 5px }")
        self.valid_model = QStandardItemModel()
        self.show_validation_results()

        self.resize(640, 640)

    def _get_info_text(self, has_files_to_replace, has_write_permissions):
        msg = ""
        if not has_write_permissions:
            msg += f"WARNING: You don't have writing permissions to this project. Changes won't be synced!\n"

        if has_files_to_replace:
            msg += (
                f"\nWARNING: Unable to compare some of the modified files with their server version - "
                f"their history will be lost if uploaded."
            )
        return msg

    def check_any_changes(self, pull_changes, push_changes):
        if not sum(len(v) for v in list(pull_changes.values()) + list(push_changes.values())):
            root_item = QStandardItem("No changes")
            self.model.appendRow(root_item)

    def add_content(self, changes, root_text, is_server, changes_summary={}):
        """
        Adds rows with changes info
        :param changes: Dict of added/removed/updated/renamed changes
        :param root_text: Text for the root item
        :param is_server: True if changes are related to server file changes
        :param changes_summary: If given and non empty, extra rows are added from geodiff summary.
        :return:
        """
        if all(not changes[k] for k in changes):
            return

        root_item = QStandardItem(root_text)
        self.model.appendRow(root_item)
        for category in changes:
            for file in changes[category]:
                path = file["path"]
                item = self._get_icon_item(category, path)
                if is_versioned_file(path):
                    if path in changes_summary:
                        for sub_item in self._versioned_file_summary_items(changes_summary[path]["geodiff_summary"]):
                            item.appendRow(sub_item)
                    elif not is_server and category != "added":
                        item.appendRow(QStandardItem("Unable to detect changes"))
                        msg = f"Mergin plugin: Unable to detect changes for {path}"
                        QgsApplication.messageLog().logMessage(msg)
                        if self.mp is not None:
                            self.mp.log.warning(msg)
                root_item.appendRow(item)

    def _versioned_file_summary_items(self, geodiff_summary):
        items = []
        for s in geodiff_summary:
            table_name_item = self._get_icon_item("table", s["table"])
            for row in self._table_summary_items(s):
                table_name_item.appendRow(row)
            items.append(table_name_item)

        return items

    def _table_summary_items(self, summary):
        return [QStandardItem("{}: {}".format(k, summary[k])) for k in summary if k != "table"]

    def _get_icon_item(self, key, text):
        path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.icons[key])
        item = QStandardItem(text)
        item.setIcon(QIcon(path))
        return item

    def show_validation_results(self):
        lout = QVBoxLayout(self.valid_tab)
        lout.addWidget(self.valid_view)
        self.valid_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.valid_model.setHorizontalHeaderLabels(["Validation results"])
        self.valid_view.setModel(self.valid_model)

        map_layers = QgsProject.instance().mapLayers()
        for issues_data in sorted(self.validation_results):
            level, issue = issues_data
            layer_ids = self.validation_results[issues_data]
            issue_item = QStandardItem(issue)
            for lid in sorted(layer_ids, key=lambda x: map_layers[x].name()):
                layer = map_layers[lid]
                lyr_item = QStandardItem(f"- {layer.name()}")
                lyr_item.setToolTip(layer.publicSource())
                issue_item.appendRow(lyr_item)
            self.valid_model.appendRow(issue_item)

        self.valid_view.expandAll()