예제 #1
0
class ParameterWindow(QMainWindow):
    def __init__(self, dplugin, api, pl_win_name = '',parent = None):
        QMainWindow.__init__(self, parent)

        # Build the tree for the parameters
        self.parameterTree = QTreeView(self)
        self.parameterTree.setObjectName("parameterTree")
        # Add it as the central widget
        self.setCentralWidget(self.parameterTree)
        # Add the DParameterTreeModel to the parameter tree
        self.dparameterModel = DParameterTreeModel()
        self.dparameterModel.setHorizontalHeaderLabels(['Name',''])
        self.parameterTree.setModel(self.dparameterModel)
        self.parameterTree.setUniformRowHeights(True)
        # connect the callback function for value changes
        self.dparameterModel.dataChanged.connect(self.data_changed_parameter_model)

        self.dpluign_object = dplugin
        self.api = api

        self.setWindowTitle(pl_win_name+' Parameter')



    def show_paramters(self, para_list):
        """
        Shows the list of parameters and values in the parameter window
        :param para_list:
        :return:
        """
        for dparameter_name in sorted(para_list):
            dparameter = para_list[dparameter_name]
            dparameter_item = DParameterTreeItem(dparameter)
            self.dparameterModel.appendRow(dparameter_item)
            self.parameterTree.resizeColumnToContents(0)
            self.parameterTree.resizeColumnToContents(1)
        self.parameterTree.expandAll()

        fh = self.parameterTree.fontMetrics().height()

        if len(para_list.keys()) > 8:
            self.setFixedHeight(fh*9+fh+25)
        else:
             self.setFixedHeight(fh*len(para_list.keys())+fh+fh+25)




    def data_changed_parameter_model(self, index, n):
        """
        This function is called when a dparameter value is changed by editing the 'value'-column.

        :param index: Index of current changed dparameter
        :param n: None
        :return:
        """

        dparameter = self.parameterTree.model().data(index, Qt.UserRole)

        self.api.do_set_parameter(self.dpluign_object.id, dparameter.name, dparameter.value)
예제 #2
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)
예제 #3
0
 def __init__(self, model):
     super().__init__()
     self.setWindowTitle("Treeview for nested dict/list")
     self.setGeometry(300, 300, 600, 800)
     tree_view = QTreeView()
     tree_view.setModel(model)
     tree_view.expandAll()
     tree_view.resizeColumnToContents(0)
     self.setCentralWidget(tree_view)
예제 #4
0
class ItemsView(QDockWidget):
    def __init__(self, title, parent, items):
        super().__init__(title, parent)
        self.setFloating(False)
        self.set_items(items)

    def set_items(self, items):
        self.items = items
        self.itemsTree = QTreeView()
        self.itemsTree.setHeaderHidden(True)

        treeModel = QStandardItemModel()
        rootNode = treeModel.invisibleRootItem()

        groups = {}
        for item in items:
            category = item['data']['category']
            node = self.__get_node(item['name'])
            if (category not in groups):
                groups[category] = self.__get_node(category)
            groups[category].appendRow(node)

        for key in groups:
            rootNode.appendRow(groups[key])

        self.itemsTree.setModel(treeModel)
        self.itemsTree.expandAll()
        self.setWidget(self.itemsTree)

    def set_on_item_selected(self, method):
        self.itemsTree.selectionModel().selectionChanged.connect(
            lambda: method(self.__get_selected_item()))

    def __get_selected_item(self):
        current = self.itemsTree.currentIndex()
        found_item = None
        if (current.parent() != None):
            for item in self.items:
                if (item['name'] == current.data()):
                    found_item = item
        return found_item

    def __get_node(self, title):
        node = QStandardItem()
        node.setEditable(False)
        node.setText(title)
        return node
예제 #5
0
class ReqTreeView(QWidget):
    def __init__(self):
        QWidget.__init__(self)

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

        self.nodes = {}
        self.tree_view = QTreeView()
        self.tree_view.header().close()
        self.root = QStandardItemModel()
        self.tree_view.setModel(self.root)
        self.layout().addWidget(self.tree_view)

    @pyqtSlot(HTTPRequest)
    def add_request_item(self, req):
        path_parts = req.url.geturl(False).split("/")
        path_parts = path_parts[1:]
        path_parts = ["/" + p for p in path_parts]
        path_parts = [req.dest_host] + path_parts
        if path_parts[0] not in self.nodes:
            item = PathNodeItem(path_parts[0], path_parts[0])
            item.setFlags(item.flags() ^ Qt.ItemIsEditable)
            self.nodes[path_parts[0]] = item
            self.root.appendRow(item)
        else:
            item = self.nodes[path_parts[0]]
        item.add_child_path(path_parts[1:])

    @pyqtSlot(list)
    def set_requests(self, reqs):
        self.clear()
        for req in reqs:
            if _include_req(req):
                self.add_request_item(req)
        self.tree_view.expandAll()

    def clear(self):
        self.nodes = {}
        self.root = QStandardItemModel()
        self.tree_view.setModel(self.root)
예제 #6
0
    def showVideoInfoDialog(self, outjson):
        """ Show Video Information Dialog """
        view = QTreeView()
        model = QJsonModel()
        view.setModel(model)
        model.loadJsonFromConsole(outjson)

        self.VideoInfoDialog = QDialog(self)
        self.VideoInfoDialog.setWindowTitle("Video Information : " +
                                            self.fileName)
        self.VideoInfoDialog.setWindowIcon(
            QIcon(":/imgFMV/images/video_information.png"))

        self.verticalLayout = QVBoxLayout(self.VideoInfoDialog)
        self.verticalLayout.addWidget(view)
        view.expandAll()
        view.header().setSectionResizeMode(QHeaderView.ResizeToContents)

        self.VideoInfoDialog.setWindowFlags(Qt.Window
                                            | Qt.WindowCloseButtonHint)
        self.VideoInfoDialog.setObjectName("VideoInfoDialog")
        self.VideoInfoDialog.resize(500, 400)
        self.VideoInfoDialog.show()
예제 #7
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self._app = QApplication.instance()
        self._lineEdit = None
        self.create_menu()
        self._completer = TreeModelCompleter(None, self)
        self._completer.setModel(self.model_from_file("./treemodel.txt"))
        self._completer.set_separator(".")
        self._completer.highlighted[QModelIndex].connect(self.highlight)

        central_widget = QWidget()
        model_label = QLabel()
        model_label.setText("Tree Model<br>(Double click items to edit)")
        mode_label = QLabel()
        mode_label.setText("Completion Mode")
        self._mode_combo = QComboBox()
        self._mode_combo.addItem(tr("Inline"))
        self._mode_combo.addItem(tr("Filtered Popup"))
        self._mode_combo.addItem(tr("Unfiltered Popup"))
        self._mode_combo.setCurrentIndex(1)

        case_label = QLabel()
        case_label.setText(tr("Case Sensitivity"))
        self._case_combo = QComboBox()
        self._case_combo.addItem(tr("Case Insensitive"))
        self._case_combo.addItem(tr("Case Sensitive"))
        self._case_combo.setCurrentIndex(0)

        separator_label = QLabel()
        separator_label.setText(tr("Tree Separator"))

        separator_line_edit = QLineEdit()
        separator_line_edit.setText(self._completer.separator())
        separator_line_edit.textChanged.connect(self._completer.set_separator)

        wrap_check_box = QCheckBox()
        wrap_check_box.setText(tr("Wrap around completions"))
        wrap_check_box.setChecked(self._completer.wrapAround())
        wrap_check_box.clicked.connect(self._completer.setWrapAround)

        self._contents_label = QLabel()
        self._contents_label.setSizePolicy(QSizePolicy.Fixed,
                                           QSizePolicy.Fixed)
        separator_line_edit.textChanged.connect(self.update_contents_label)

        self._tree_view = QTreeView()
        self._tree_view.setModel(self._completer.model())
        self._tree_view.header().hide()
        self._tree_view.expandAll()

        self._mode_combo.activated.connect(self.change_mode)
        self._case_combo.activated.connect(self.change_case)

        self._line_edit = QLineEdit()
        self._line_edit.setCompleter(self._completer)

        layout = QGridLayout()
        layout.addWidget(model_label, 0,
                         0), layout.addWidget(self._tree_view, 0, 1)
        layout.addWidget(mode_label, 1,
                         0), layout.addWidget(self._mode_combo, 1, 1)
        layout.addWidget(case_label, 2,
                         0), layout.addWidget(self._case_combo, 2, 1)
        layout.addWidget(separator_label, 3,
                         0), layout.addWidget(separator_line_edit, 3, 1)
        layout.addWidget(wrap_check_box, 4, 0)
        layout.addWidget(self._contents_label, 5, 0, 1, 2)
        layout.addWidget(self._line_edit, 6, 0, 1, 2)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        self.change_case(self._case_combo.currentIndex())
        self.change_mode(self._mode_combo.currentIndex())

        self.setWindowTitle(tr("Tree Model Completer"))
        self._line_edit.setFocus()

    def create_menu(self):
        exit_action = QAction(tr("Exit"), self)
        about_act = QAction(tr("About"), self)
        about_qt_act = QAction(tr("About Qt"), self)

        exit_action.triggered.connect(QApplication.instance().quit)
        about_act.triggered.connect(self.about)
        about_qt_act.triggered.connect(QApplication.instance().aboutQt)

        file_menu = self.menuBar().addMenu(tr("File"))
        file_menu.addAction(exit_action)

        help_menu = self.menuBar().addMenu(tr("About"))
        help_menu.addAction(about_act)
        help_menu.addAction(about_qt_act)

    def change_mode(self, index):
        modes = (QCompleter.InlineCompletion, QCompleter.PopupCompletion,
                 QCompleter.UnfilteredPopupCompletion)
        self._completer.setCompletionMode(modes[index])

    def model_from_file(self, file_name):
        # file = QFile(file_name)
        # if not file.open(QFile.ReadOnly):
        #     return QStringListModel(self._completer)
        QApplication.instance().setOverrideCursor(QCursor(Qt.WaitCursor))
        model = QStandardItemModel(self._completer)
        parents = [model.invisibleRootItem()]

        with open(file_name) as file:
            pat = re.compile("^\\s+")
            for line in file:
                if not line:
                    continue
                trimmed_line = line.strip()
                if not trimmed_line:
                    continue
                match = pat.match(line)
                if not match:
                    level = 0
                else:
                    length = match.end() - match.start()
                    if line.startswith("\t"):
                        level = length
                    else:
                        level = length // 4

                while len(parents) < level + 2:
                    parents.append(None)

                item = QStandardItem()
                item.setText(trimmed_line)
                parents[level].appendRow(item)
                parents[level + 1] = item
        QApplication.instance().restoreOverrideCursor()
        return model

    @pyqtSlot(QModelIndex)
    def highlight(self, index):
        proxy = self._completer.completionModel()
        source_index = proxy.mapToSource(index)
        self._tree_view.selectionModel().select(
            source_index,
            QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
        self._tree_view.scrollTo(source_index)

    def about(self):
        QMessageBox.about(
            self, tr("About"),
            tr("This example demonstrates how to use a QCompleter with a custom tree datamodel."
               ))

    def change_case(self, cs):
        self._completer.setCaseSensitivity(
            Qt.CaseSensitive if cs else Qt.CaseInsensitive)

    def update_contents_label(self, sep):
        self._contents_label.setText(
            "Type path from datamodel above with items at each level separated by a '%s'"
            % sep)
예제 #8
0
class FinderBox(QComboBox):

    running = False
    to_finish = 0

    search_started = pyqtSignal()
    search_finished = pyqtSignal()

    def __init__(self, finders, iface, parent=None):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        self.rubber = QgsRubberBand(self.mapCanvas)
        self.rubber.setColor(QColor(255, 255, 50, 200))
        self.rubber.setIcon(self.rubber.ICON_CIRCLE)
        self.rubber.setIconSize(15)
        self.rubber.setWidth(4)
        self.rubber.setBrushStyle(Qt.NoBrush)

        QComboBox.__init__(self, parent)
        self.setEditable(True)
        self.setInsertPolicy(QComboBox.InsertAtTop)
        self.setMinimumHeight(27)
        self.setSizePolicy(QSizePolicy.Expanding,
                           QSizePolicy.Fixed)

        self.insertSeparator(0)
        self.lineEdit().returnPressed.connect(self.search)

        self.result_view = QTreeView()
        self.result_view.setHeaderHidden(True)
        self.result_view.setMinimumHeight(300)
        self.result_view.activated.connect(self.itemActivated)
        self.result_view.pressed.connect(self.itemPressed)
        self.setView(self.result_view)

        self.result_model = ResultModel(self)
        self.setModel(self.result_model)

        self.finders = finders
        for finder in self.finders.values():
            finder.result_found.connect(self.result_found)
            finder.limit_reached.connect(self.limit_reached)
            finder.finished.connect(self.finished)

        self.clearButton = QPushButton(self)
        self.clearButton.setIcon(QIcon(":/plugins/quickfinder/icons/draft.svg"))
        self.clearButton.setText('')
        self.clearButton.setFlat(True)
        self.clearButton.setCursor(QCursor(Qt.ArrowCursor))
        self.clearButton.setStyleSheet('border: 0px; padding: 0px;')
        self.clearButton.clicked.connect(self.clear)

        layout = QHBoxLayout(self)
        self.setLayout(layout)
        layout.addStretch()
        layout.addWidget(self.clearButton)
        layout.addSpacing(20)

        button_size = self.clearButton.sizeHint()
        # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
        padding = button_size.width()  # + frameWidth + 1
        self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding)

    def __del__(self):
        if self.rubber:
            self.iface.mapCanvas().scene().removeItem(self.rubber)
            del self.rubber

    def clearSelection(self):
        self.result_model.setSelected(None, self.result_view.palette())
        self.rubber.reset()

    def clear(self):
        self.clearSelection()
        self.result_model.clearResults()
        self.lineEdit().setText('')

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.clearSelection()
        QComboBox.keyPressEvent(self, event)

    def search(self):
        if self.running:
            return

        to_find = self.lineEdit().text()
        if not to_find or to_find == '':
            return

        self.running = True
        self.search_started.emit()

        self.clearSelection()
        self.result_model.clearResults()
        self.result_model.truncateHistory(MySettings().value("historyLength"))
        self.result_model.setLoading(True)
        self.showPopup()

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

        self.finders_to_start = []
        for finder in self.finders.values():
            if finder.activated():
                self.finders_to_start.append(finder)

        bbox = self.mapCanvas.fullExtent()

        while len(self.finders_to_start) > 0:
            finder = self.finders_to_start[0]
            self.finders_to_start.remove(finder)
            self.result_model.addResult(finder.name)
            finder.start(to_find, bbox=bbox)

        # For case there is no finder activated
        self.finished(None)

    def stop(self):
        self.finders_to_start = []
        for finder in self.finders.values():
            if finder.is_running():
                finder.stop()
        self.finished(None)

    def result_found(self, finder, layername, value, geometry, srid):
        self.result_model.addResult(finder.name, layername, value, geometry, srid)
        self.result_view.expandAll()

    def limit_reached(self, finder, layername):
        self.result_model.addEllipsys(finder.name, layername)

    def finished(self, finder):
        if len(self.finders_to_start) > 0:
            return
        for finder in self.finders.values():
            if finder.is_running():
                return

        self.running = False
        self.search_finished.emit()

        self.result_model.setLoading(False)

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

    def itemActivated(self, index):
        item = self.result_model.itemFromIndex(index)
        self.showItem(item)

    def itemPressed(self, index):
        item = self.result_model.itemFromIndex(index)
        if QApplication.mouseButtons() == Qt.LeftButton:
            self.showItem(item)

    def showItem(self, item):
        if isinstance(item, ResultItem):
            self.result_model.setSelected(item, self.result_view.palette())
            geometry = self.transform_geom(item)
            self.rubber.reset(geometry.type())
            self.rubber.setToGeometry(geometry, None)
            self.zoom_to_rubberband()
            return

        if isinstance(item, GroupItem):
            child = item.child(0)
            if isinstance(child, ResultItem):
                self.result_model.setSelected(item, self.result_view.palette())
                self.rubber.reset(child.geometry.type())
                for i in range(0, item.rowCount()):
                    geometry = self.transform_geom(item.child(i))
                    self.rubber.addGeometry(geometry, None)
                self.zoom_to_rubberband()
            return

        if item.__class__.__name__ == 'QStandardItem':
            self.clearSelection()

    def transform_geom(self, item):
        src_crs = QgsCoordinateReferenceSystem()
        src_crs.createFromSrid(item.srid)
        dest_crs = self.mapCanvas.mapRenderer().destinationCrs()
        geom = QgsGeometry(item.geometry)
        geom.transform(QgsCoordinateTransform(src_crs, dest_crs))
        return geom

    def zoom_to_rubberband(self):
        geom = self.rubber.asGeometry()
        if geom:
            rect = geom.boundingBox()
            rect.scale(1.5)
            self.mapCanvas.setExtent(rect)
            self.mapCanvas.refresh()
예제 #9
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
예제 #10
0
class FileTreeView(QWidget):
    on_menu_select = pyqtSignal(str, dict)

    def __init__(self):
        super().__init__()
        self.list_file = []
        self.get_data_file()

        v_box = QVBoxLayout()
        v_box.addLayout(self.finder())
        v_box.addWidget(self.tree_view())
        self.setLayout(v_box)

    def finder(self):
        w_find = QLineEdit()
        w_find.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))

        w_find_button = QPushButton()
        w_find_button.setText("Find")
        w_find_button.setFixedWidth(50)

        h_box = QHBoxLayout()
        h_box.addWidget(w_find)
        h_box.addWidget(w_find_button, 1)
        return h_box

    def get_data_file(self):
        self.list_file = self.create_list(get_data_folder())

    def create_list(self, dir):
        lst = os.listdir(path=dir)
        list_file = []
        for f in lst:
            path = dir + "\\" + f
            file = {}
            if os.path.isdir(path):
                file["dir"] = dir
                file["name"] = f
                file["isDir"] = True
                file["child"] = self.create_list(path)
            else:
                file["dir"] = dir
                file["name"] = f
                file["isDir"] = False

            list_file.append(file)
        return list_file

    def tree_view(self):
        self.tree = QTreeView()
        self.tree.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))

        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.openMenu)

        self.model = QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['List API'])
        self.tree.header().setDefaultSectionSize(180)
        self.tree.setModel(self.model)
        self.import_data(self.model.invisibleRootItem(), self.list_file)
        self.tree.expandAll()

        return self.tree

    def import_data(self, parent_item, list):
        for i in list:
            if i["isDir"]:
                item = QStandardItem(i["name"])
                item.setEditable(False)
                item.setIcon(QIcon(get_icon_link("folder_yellow.svg")))
                item.setData(i)
                parent_item.appendRow(item)
                self.import_data(item, i["child"])
            else:
                item = QStandardItem(i["name"])
                item.setEditable(False)
                item.setIcon(QIcon(get_icon_link("text_snippet.svg")))
                item.setData(i)
                parent_item.appendRow(item)

    def openMenu(self, position):
        indexes = self.tree.selectedIndexes()
        level = 0
        data = {}
        if len(indexes) > 0:
            index = indexes[0]
            item = self.model.itemFromIndex(index)
            data = item.data()
            if data['isDir']:
                level = 1
            else:
                level = 2

        menu = QMenu()
        menu.setStyleSheet(open('stylesheet/default.qss').read())

        # Create preference action
        rename_action = QAction(QIcon(get_icon_link('edit.svg')), '&Rename',
                                self)
        rename_action.setStatusTip('Rename')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        new_action = QAction(QIcon(get_icon_link('create_new_folder.svg')),
                             '&New Folder', self)
        new_action.setStatusTip('New Folder')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        refresh_action = QAction(QIcon(get_icon_link('refresh.svg')),
                                 '&Refresh', self)
        refresh_action.setStatusTip('Refresh')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        delete_action = QAction(QIcon(get_icon_link('delete_forever.svg')),
                                '&Delete', self)
        delete_action.setStatusTip('Delete')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        open_action = QAction(QIcon(get_icon_link('open_in_new.svg')), '&Open',
                              self)
        open_action.setStatusTip('Open file')
        # open_action.triggered.connect(self.open_file)

        # Create preference action
        expand_action = QAction(QIcon(), '&Expand', self)
        expand_action.setStatusTip('Expand')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        collapse_action = QAction(QIcon(), '&Collapse', self)
        collapse_action.setStatusTip('Collapse')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        copy_action = QAction(QIcon(get_icon_link('content_copy.svg')),
                              '&Copy', self)
        copy_action.setStatusTip('Copy')
        # exitAction.triggered.connect(self.exitCall)

        # Create preference action
        move_action = QAction(QIcon(get_icon_link('zoom_out_map.svg')),
                              '&Move', self)
        move_action.setStatusTip('Move')
        # exitAction.triggered.connect(self.exitCall)

        if level == 1:
            menu.addAction(rename_action)
            menu.addAction(new_action)
            menu.addSeparator()
            menu.addAction(refresh_action)
            menu.addAction(expand_action)
            menu.addAction(collapse_action)
            menu.addSeparator()
            menu.addAction(delete_action)
        elif level == 2:
            menu.addAction(open_action)
            menu.addAction(refresh_action)
            menu.addSeparator()
            menu.addAction(rename_action)
            menu.addAction(copy_action)
            menu.addAction(move_action)
            menu.addSeparator()
            menu.addAction(delete_action)
        else:
            menu.addAction(new_action)
            menu.addAction(refresh_action)

        action = menu.exec_(self.tree.viewport().mapToGlobal(position))
        if action == open_action:
            self.on_menu_select.emit("open", data)
예제 #11
0
class LootWizard(QMainWindow):

	def __init__(self):
		super (LootWizard, self).__init__()
		self.hide()
		self._upToDateMessage = 'is up-to-date'
		self.initUI()

	def kill_on_init(self):
		QTimer.singleShot(0, app.quit)

	def initUI(self):
		data_found = False
		try:
			self.__getFileinfo(sys.argv[1])
		except (IndexError, FileNotFoundError):
			directory = QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0]
			directory += "/My Games/Path of Exile"
			fname = QFileDialog.getOpenFileName(None, 'Open file', directory)
			if fname[0]:
				try:
					self.__getFileinfo(fname[0])
				except FileNotFoundError:
					pass
				else:
					data_found = True
		else:
			data_found = True
		if not data_found:
			self.kill_on_init()
		else:
			self.initWindowUI()

	def initWindowUI(self):
		self.resetButton = QPushButton("Reset")
		self.resetButton.setEnabled(False)
		self.resetButton.clicked.connect(self.reset)
		self.orphanButton = SquareButton("+")
		self.orphanButton.hide()
		self.overwriteButton = QPushButton("Overwrite")
		self.overwriteButton.setStyleSheet("background-color: #EFC795")
		self.overwriteButton.setEnabled(False)
		self.overwriteButton.clicked.connect(self.overwrite)
		self.forceCheckBox = QCheckBox("&Always inherit")
		self.forceCheckBox.setToolTip('Smartblocks inherit from virtual blockgroups.<br/>Check me to change from a <b>smartblock</b> parent.')
		self.forceCheckBox.hide()
		hbox = QHBoxLayout()
		hbox2 = QHBoxLayout()
		hbox2.addWidget(self.forceCheckBox)
		hbox.addLayout(hbox2)
		hbox.addWidget(self.orphanButton)
		hbox.addStretch(1)
		hbox.addWidget(self.overwriteButton)
		hbox.addWidget(self.resetButton)
		vbox = QVBoxLayout()
		self.setWindowTitle('Loot Wizard')
		self.view = QTreeView()
		self.setCentralWidget(QWidget())
		self.scrollLayout = QFormLayout()
		self.scrollWidget = QWidget()
		self.scrollWidget.setLayout(self.scrollLayout)
		self.orphanDialog = OrphanDialog(self)
		self.orphanButton.clicked.connect(self.openOrphans)
		vbox.addWidget(self.view)
		vbox.addLayout(hbox)
		self.scrollLayout.addRow(self.view)
		self.centralWidget().setLayout(vbox)
		self.model = SmartblockModel(self.file_content, self)
		self.statusBar().showMessage(self.file_info.fileName() + ' ' + self._upToDateMessage)
		self.forceCheckBox.stateChanged.connect(self.switchforce)
		self.view.setModel(self.model)
		self.view.expandAll()
		self.view.setAlternatingRowColors(True)
		self.resize(300, 600)
		self.show()

	def inform(self, flag, external_call = False, end_process = False):
		reset_flag = False # hidden first
		if flag:
			if external_call:
				message = 'has non-updated changes'
			else:
				message = 'has changed'
				reset_flag = True
		else:
			if end_process:
				message = 'is saved'
			else:
				message = self._upToDateMessage
		self.statusBar().showMessage(self.file_info.fileName() + ' ' + message)
		self.resetButton.setEnabled(reset_flag)
		self.overwriteButton.setEnabled(flag)

	def displayOrphan(self, display = True):
		# self.displayButton(self.orphanButton, display)
		pass

	def displayInheritance(self, display = True):
		self.displayButton(self.forceCheckBox, display)

	def displayButton(self, btn, display = True):
		if display:
			btn.show()
		else:
			btn.hide()

	def switchforce(self, state):
		self.model.forceInheritance = state == Qt.Checked

	def overwrite(self):
		self.overwriteButton.setEnabled(False)
		self.resetButton.setEnabled(False) # TODO: disable from elsewhere ?!
		if self.model.save(self.file_info.absoluteFilePath()):
			self.inform(False, False, True)

	def reset(self):
		self.model.resetStatus()

	def __getFileinfo(self, filename):
		self.file_content = ''.join(fileinput.input(filename))
		self.file_info = QFileInfo(filename)

	def openOrphans(self):
		self.orphanDialog.show()
예제 #12
0
class FinderBox(QComboBox):

    running = False
    to_finish = 0

    search_started = pyqtSignal()
    search_finished = pyqtSignal()

    def __init__(self, finders, iface, parent=None):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        self.rubber = QgsRubberBand(self.mapCanvas)
        self.rubber.setColor(QColor(255, 255, 50, 200))
        self.rubber.setIcon(self.rubber.ICON_CIRCLE)
        self.rubber.setIconSize(15)
        self.rubber.setWidth(4)
        self.rubber.setBrushStyle(Qt.NoBrush)

        QComboBox.__init__(self, parent)
        self.setEditable(True)
        self.setInsertPolicy(QComboBox.InsertAtTop)
        self.setMinimumHeight(27)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        self.insertSeparator(0)
        self.lineEdit().returnPressed.connect(self.search)

        self.result_view = QTreeView()
        self.result_view.setHeaderHidden(True)
        self.result_view.setMinimumHeight(300)
        self.result_view.activated.connect(self.itemActivated)
        self.result_view.pressed.connect(self.itemPressed)
        self.setView(self.result_view)

        self.result_model = ResultModel(self)
        self.setModel(self.result_model)

        self.finders = finders
        for finder in self.finders.values():
            finder.result_found.connect(self.result_found)
            finder.limit_reached.connect(self.limit_reached)
            finder.finished.connect(self.finished)

        self.clearButton = QPushButton(self)
        self.clearButton.setIcon(
            QIcon(":/plugins/quickfinder/icons/draft.svg"))
        self.clearButton.setText('')
        self.clearButton.setFlat(True)
        self.clearButton.setCursor(QCursor(Qt.ArrowCursor))
        self.clearButton.setStyleSheet('border: 0px; padding: 0px;')
        self.clearButton.clicked.connect(self.clear)

        layout = QHBoxLayout(self)
        self.setLayout(layout)
        layout.addStretch()
        layout.addWidget(self.clearButton)
        layout.addSpacing(20)

        button_size = self.clearButton.sizeHint()
        # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
        padding = button_size.width()  # + frameWidth + 1
        self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' %
                                      padding)

    def __del__(self):
        if self.rubber:
            self.iface.mapCanvas().scene().removeItem(self.rubber)
            del self.rubber

    def clearSelection(self):
        self.result_model.setSelected(None, self.result_view.palette())
        self.rubber.reset()

    def clear(self):
        self.clearSelection()
        self.result_model.clearResults()
        self.lineEdit().setText('')

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.clearSelection()
        QComboBox.keyPressEvent(self, event)

    def search(self):
        if self.running:
            return

        to_find = self.lineEdit().text()
        if not to_find or to_find == '':
            return

        self.running = True
        self.search_started.emit()

        self.clearSelection()
        self.result_model.clearResults()
        self.result_model.truncateHistory(MySettings().value("historyLength"))
        self.result_model.setLoading(True)
        self.showPopup()

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

        self.finders_to_start = []
        for finder in self.finders.values():
            if finder.activated():
                self.finders_to_start.append(finder)

        bbox = self.mapCanvas.fullExtent()

        while len(self.finders_to_start) > 0:
            finder = self.finders_to_start[0]
            self.finders_to_start.remove(finder)
            self.result_model.addResult(finder.name)
            finder.start(to_find, bbox=bbox)

        # For case there is no finder activated
        self.finished(None)

    def stop(self):
        self.finders_to_start = []
        for finder in self.finders.values():
            if finder.is_running():
                finder.stop()
        self.finished(None)

    def result_found(self, finder, layername, value, geometry, srid):
        self.result_model.addResult(finder.name, layername, value, geometry,
                                    srid)
        self.result_view.expandAll()

    def limit_reached(self, finder, layername):
        self.result_model.addEllipsys(finder.name, layername)

    def finished(self, finder):
        if len(self.finders_to_start) > 0:
            return
        for finder in self.finders.values():
            if finder.is_running():
                return

        self.running = False
        self.search_finished.emit()

        self.result_model.setLoading(False)

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

    def itemActivated(self, index):
        item = self.result_model.itemFromIndex(index)
        self.showItem(item)

    def itemPressed(self, index):
        item = self.result_model.itemFromIndex(index)
        if QApplication.mouseButtons() == Qt.LeftButton:
            self.showItem(item)

    def showItem(self, item):
        if isinstance(item, ResultItem):
            self.result_model.setSelected(item, self.result_view.palette())
            geometry = self.transform_geom(item)
            self.rubber.reset(geometry.type())
            self.rubber.setToGeometry(geometry, None)
            self.zoom_to_rubberband()
            return

        if isinstance(item, GroupItem):
            child = item.child(0)
            if isinstance(child, ResultItem):
                self.result_model.setSelected(item, self.result_view.palette())
                self.rubber.reset(child.geometry.type())
                for i in range(0, item.rowCount()):
                    geometry = self.transform_geom(item.child(i))
                    self.rubber.addGeometry(geometry, None)
                self.zoom_to_rubberband()
            return

        if item.__class__.__name__ == 'QStandardItem':
            self.clearSelection()

    def transform_geom(self, item):
        src_crs = QgsCoordinateReferenceSystem()
        src_crs.createFromSrid(item.srid)
        dest_crs = self.mapCanvas.mapRenderer().destinationCrs()
        geom = QgsGeometry(item.geometry)
        geom.transform(QgsCoordinateTransform(src_crs, dest_crs))
        return geom

    def zoom_to_rubberband(self):
        geom = self.rubber.asGeometry()
        if geom:
            rect = geom.boundingBox()
            rect.scale(1.5)
            self.mapCanvas.setExtent(rect)
            self.mapCanvas.refresh()
예제 #13
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)
예제 #14
0
파일: dock.py 프로젝트: gpa14/enki
class NavigatorDock(DockWidget):

    def __init__(self):
        DockWidget.__init__(self, core.mainWindow(), '&Navigator', QIcon(':/enkiicons/goto.png'), "Alt+N")

        self._tags = []

        self._tree = QTreeView(self)
        self._tree.installEventFilter(self)
        self._tree.setHeaderHidden(True)
        self.setFocusProxy(self._tree)

        self._filterEdit = LineEdit(self)
        self._filterEdit.setClearButtonVisible(True)
        self._filterEdit.textEdited.connect(self._applyFilter)
        self._filterEdit.clearButtonClicked.connect(self._applyFilter)
        self._filterEdit.clearButtonClicked.connect(self._tree.setFocus)
        self._filterEdit.clearButtonClicked.connect(self._hideFilter)
        self._filterEdit.installEventFilter(self)

        self._displayWidget = QWidget(self)
        layout = QVBoxLayout(self._displayWidget)
        layout.addWidget(self._tree)
        layout.addWidget(self._filterEdit)
        layout.setContentsMargins(0, 0, 0, 0)

        self.setWidget(self._displayWidget)

        self._tagModel = _TagModel(self._tree)
        self._tagModel.jumpToTagDone.connect(self._hideFilter)

        self._tree.setModel(self._tagModel)
        self._tree.activated.connect(self._tagModel.onActivated)
        self._tree.clicked.connect(self._tagModel.onActivated)
        self._tagModel.modelAboutToBeReset.connect(self._onModelAboutToBeReset)
        self._tagModel.modelReset.connect(self._onModelReset)
        self._currentTagPath = None

        self._errorLabel = None

        self._installed = False

    def term(self):
        self._tagModel.term()

    def install(self):
        if not self._installed:
            core.mainWindow().addDockWidget(Qt.RightDockWidgetArea, self)
            core.actionManager().addAction("mView/aNavigator", self.showAction())
            self._installed = True

    def remove(self):
        if self._installed:
            core.mainWindow().removeDockWidget(self)
            core.actionManager().removeAction("mView/aNavigator")
            self.hide()
            self._installed = False

    def setTags(self, tags):
        self._tags = tags
        self._setFilteredTags(tags)
        self._hideFilter()

        if self.widget() is not self._displayWidget:
            self.setWidget(self._displayWidget)
            self._displayWidget.show()
        if self._errorLabel is not None:
            self._errorLabel.hide()

    def _setFilteredTags(self, tags):
        self._tagModel.setTags(tags)

    def onError(self, error):
        self._displayWidget.hide()
        if self._errorLabel is None:
            self._errorLabel = QLabel(self)
            self._errorLabel.setWordWrap(True)

        self._errorLabel.setText(error)

        if not self.widget() is self._errorLabel:
            self.setWidget(self._errorLabel)
            self._errorLabel.show()
            self._displayWidget.hide()

    def _onModelAboutToBeReset(self):
        currIndex = self._tree.currentIndex()
        self._currentTagPath = self._tagModel.tagPathForIndex(currIndex) if currIndex.isValid() else None

    def _onModelReset(self):
        self._tree.expandAll()

        # restore current item
        if self._currentTagPath is not None:
            index = self._tagModel.indexForTagPath(self._currentTagPath)
            if index.isValid():
                self._tree.setCurrentIndex(index)

    def eventFilter(self, object_, event):
        if object_ is self._tree:
            if event.type() == QEvent.KeyPress:
                if event.key() == Qt.Key_Backspace:
                    if event.modifiers() == Qt.ControlModifier:
                        self._onTreeCtrlBackspace()
                    else:
                        self._onTreeBackspace()
                    return True
                elif event.text() and \
                        (event.text().isalnum() or event.text() == '_'):
                    self._onTreeTextTyped(event.text())
                    return True
        elif object_ is self._filterEdit:
            if event.type() == QEvent.KeyPress:
                if event.key() in (Qt.Key_Up, Qt.Key_Down):
                    self._tree.setFocus()
                    self._tree.event(event)
                    return True
                elif event.key() in (Qt.Key_Enter, Qt.Key_Return):
                    currIndex = self._tree.currentIndex()
                    if currIndex.isValid():
                        self._tagModel.onActivated(currIndex)

        return DockWidget.eventFilter(self, object_, event)

    def _hideFilter(self):
        hadText = self._filterEdit.text() != ''
        self._filterEdit.clear()
        self._filterEdit.hide()
        if hadText:
            self._applyFilter()

    def _applyFilter(self):
        text = self._filterEdit.text()
        if text:
            if not text.startswith('*'):
                text = '*' + text
            if not text.endswith('*'):
                text = text + '*'

            wildcard = text.lower()

            filteredTags = _filterTags(wildcard, self._tags)

            self._setFilteredTags(filteredTags)
            self._tree.expandAll()
            if filteredTags:
                firstMatchingTag = _findFirstMatching(wildcard, filteredTags)
                path = _tagPath(firstMatchingTag)
                index = self._tagModel.indexForTagPath(path)
                self._tree.setCurrentIndex(index)
        else:
            self._setFilteredTags(self._tags)

        if text:
            self._filterEdit.show()
        elif not self._filterEdit.hasFocus():
            self._hideFilter()

    def _onTreeTextTyped(self, text):
        self._filterEdit.setText(self._filterEdit.text() + text)
        self._applyFilter()

    def _onTreeBackspace(self):
        text = self._filterEdit.text()
        if text:
            self._filterEdit.setText(text[:-1])
            self._applyFilter()

    def _onTreeCtrlBackspace(self):
        self._hideFilter()
        self._applyFilter()
예제 #15
0
class StatsGui(QWidget):
    ''' 
    This class accepts a glue data collection object, and builds an interactive window
    to display basic statistics (e.g. mean, median, mode) about each dataset
    '''

    released = QtCore.pyqtSignal(object)

    def __init__(self, dc):

        # Initialize the object as a QWidget
        QWidget.__init__(self)

        #Save the datacollection object as an attribute of class StatsGui
        self.dc = dc

        #Set the title of the main GUI window
        self.setWindowTitle('Statistics')

        # Set up dicts for row indices
        self.subset_dict = dict()
        self.component_dict = dict()

        self.selected_dict = dict()
        self.selected_indices = []

        #Set up tree view and fix it to the top half of the window
        self.treeview = QTreeView(self)

        # Set the default clicking behavior to be row selection
        self.treeview.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Set up expand all, collapse all, select all and deselect all buttons

        # Layout for expand/collapse/select/deselect
        layout_left_options = QHBoxLayout()

        self.expand_data = QToolButton(self)
        self.expand_data.setText("Expand all data and subsets")
        self.expand_data.clicked.connect(self.expandClicked)
        layout_left_options.addWidget(self.expand_data)

        self.all = QToolButton(self)
        self.all.setText('Select all')
        self.all.clicked.connect(self.allClicked)
        layout_left_options.addWidget(self.all)

        self.none = QToolButton(self)
        self.none.setText('Deselect all')
        self.none.clicked.connect(self.noneClicked)
        layout_left_options.addWidget(self.none)

        # Set default significant figures to 5
        getcontext().prec = 5

        # Set up past selected items
        self.past_selected = []

        # Sort by subsets as a default
        self.sortBySubsets()

        # Set up the combo box for users to choose the number of significant figures in the table

        # Set up bottom options layout
        layout_bottom_options = QHBoxLayout()

        self.siglabel = QLabel(self)
        self.siglabel.setText('Number of significant figures:')
        layout_bottom_options.addWidget(self.siglabel)

        self.sigfig = QSpinBox(self)
        self.sigfig.setRange(1, 10)
        self.sigfig.setValue(5)
        self.sigfig.valueChanged.connect(self.sigchange)
        layout_bottom_options.addWidget(self.sigfig)

        # Export to file button
        self.export = QPushButton(self)
        self.export.setText('Export to file')
        self.export.clicked.connect(self.exportToFile)
        layout_bottom_options.addWidget(self.export)

        # Set up the toggle button to switch tree sorting modes
        self.switch_mode = QToolButton(self)
        self.switch_mode.setText('Sort tree by components')
        self.switch_mode.clicked.connect(self.switchMode)
        layout_left_options.addWidget(self.switch_mode)

        # Add instructions to sort the table
        self.how = QLabel(self)
        self.how.setText('Click each header to sort table')
        layout_left_options.addWidget(self.how)

        #################Set up the QTableView Widget#############################
        self.table = QTableView(self)
        self.table.setSortingEnabled(True)
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.verticalHeader().setVisible(False)

        #Set the table headings
        self.headings = ('Subset', 'Dataset', 'Component', 'Mean', 'Median',
                         'Minimum', 'Maximum', 'Sum')
        self.data_frame = pd.DataFrame(columns=self.headings)
        self.data_accurate = pd.DataFrame(columns=self.headings)
        self.model = pandasModel(self.data_frame, self.dc)

        self.table.setModel(self.model)

        layout_table = QHBoxLayout()
        layout_table.addWidget(self.table)
        layout_table.stretch(10)

        # Finish nesting all the layouts
        main_layout = QVBoxLayout()

        main_layout.addWidget(self.treeview)
        main_layout.addLayout(layout_left_options)
        main_layout.addLayout(layout_table)
        main_layout.addLayout(layout_bottom_options)

        self.setLayout(main_layout)

        # Set up dict for caching
        self.cache_stash = dict()

    def myPressedEvent(self, currentQModelIndex):
        ''' 
        Every time a row (or rows) in the tree view is clicked:
        if it is selected, add it to the table
        if it is deselected, remove it from the table
        '''

        # Get the indexes of all the selected components
        self.selected_indices = self.treeview.selectionModel().selectedRows()

        newly_selected = np.setdiff1d(self.selected_indices,
                                      self.past_selected)

        for index in range(0, len(newly_selected)):

            # Check which view mode the tree is in to get the correct indices
            if self.switch_mode.text() == 'Sort tree by components':
                data_i = newly_selected[index].parent().row()
                comp_i = newly_selected[index].row()
                subset_i = newly_selected[index].parent().parent().row()

            else:
                data_i = newly_selected[index].parent().parent().row()
                comp_i = newly_selected[index].parent().row()
                subset_i = newly_selected[index].row() - 1

            is_subset = newly_selected[index].parent().parent().parent().row(
            ) == 1 or (self.switch_mode.text() == 'Sort tree by subsets'
                       and subset_i != -1)

            # Check if its a subset and if so run subset stats
            if is_subset:
                self.runSubsetStats(subset_i, data_i, comp_i)
            else:
                # Run standard data stats
                self.runDataStats(data_i, comp_i)

        newly_dropped = np.setdiff1d(self.past_selected, self.selected_indices)

        for index in range(0, len(newly_dropped)):

            # Check which view mode the tree is in to get the correct indices
            if self.switch_mode.text() == 'Sort tree by components':
                data_i = newly_dropped[index].parent().row()
                comp_i = newly_dropped[index].row()
                subset_i = newly_dropped[index].parent().parent().row()

            else:
                data_i = newly_dropped[index].parent().parent().row()
                comp_i = newly_dropped[index].parent().row()
                subset_i = newly_dropped[index].row() - 1

            is_subset = newly_dropped[index].parent().parent().parent().row(
            ) == 1 or (self.switch_mode.text() == 'Sort tree by subsets'
                       and subset_i != -1)

            if is_subset:
                try:
                    # Get the indices that match the component, dataset, and subset requirements
                    idx_c = np.where(self.data_frame['Component'] ==
                                     self.dc[data_i].components[comp_i].label)
                    idx_d = np.where(
                        self.data_frame['Dataset'] == self.dc[data_i].label)
                    idx_s = np.where(self.data_frame['Subset'] ==
                                     self.dc[data_i].subsets[subset_i].label)
                    idx1 = np.intersect1d(idx_c, idx_d)
                    idx2 = np.intersect1d(idx1, idx_s)

                    self.data_frame = self.data_frame.drop(idx2)
                except:
                    pass

            else:
                try:
                    # Find the index in the table of the unchecked element, if it's in the table

                    # Find the matching component and dataset indices and intersect them to get the unique index
                    idx_c = np.where(self.data_frame['Component'] ==
                                     self.dc[data_i].components[comp_i].label)
                    idx_d = np.where(
                        self.data_frame['Dataset'] == self.dc[data_i].label)
                    idx_s = np.where(self.data_frame['Subset'] == '--')
                    idx1 = np.intersect1d(idx_c, idx_d)
                    idx2 = np.intersect1d(idx1, idx_s)

                    self.data_frame = self.data_frame.drop(idx2)
                except:
                    pass

        # Update the past selected indices
        self.past_selected = self.selected_indices

        model = pandasModel(self.data_frame, self.dc)

        self.table.setModel(model)

        self.table.setSortingEnabled(True)
        self.table.setShowGrid(False)

    def runDataStats(self, data_i, comp_i):
        '''
        Runs statistics for the component comp_i of data set data_i
        '''

        subset_label = "--"
        data_label = dc[data_i].label
        comp_label = self.dc[data_i].components[
            comp_i].label  # add to the name array to build the table

        # Build the cache key
        cache_key = subset_label + data_label + comp_label

        # See if the values have already been cached
        try:
            column_data = self.cache_stash[cache_key]

        except:
            # Find the stat values
            # Save the data in the cache
            mean_val = self.dc[data_i].compute_statistic(
                'mean', self.dc[data_i].components[comp_i])
            median_val = self.dc[data_i].compute_statistic(
                'median', self.dc[data_i].components[comp_i])
            min_val = self.dc[data_i].compute_statistic(
                'minimum', self.dc[data_i].components[comp_i])
            max_val = self.dc[data_i].compute_statistic(
                'maximum', self.dc[data_i].components[comp_i])
            sum_val = self.dc[data_i].compute_statistic(
                'sum', self.dc[data_i].components[comp_i])

            column_data = np.asarray([[subset_label],
                                      [data_label], [comp_label], [mean_val],
                                      [median_val], [min_val], [max_val],
                                      [sum_val]]).transpose()

            self.cache_stash[cache_key] = column_data

        # Save the accurate data in self.data_accurate
        column_df = pd.DataFrame(column_data, columns=self.headings)
        self.data_accurate = self.data_accurate.append(column_df,
                                                       ignore_index=True)

        # Round the values according to the number of significant figures set by the user
        mean_val = Decimal(float(column_data[0][3])) * Decimal(1)
        median_val = Decimal(float(column_data[0][4])) * Decimal(1)
        min_val = Decimal(float(column_data[0][5])) * Decimal(1)
        max_val = Decimal(float(column_data[0][6])) * Decimal(1)
        sum_val = Decimal(float(column_data[0][7])) * Decimal(1)

        # Create the column data array and append it to the data frame
        column_data = np.asarray([[subset_label], [data_label], [comp_label],
                                  [mean_val], [median_val], [min_val],
                                  [max_val], [sum_val]]).transpose()
        column_df = pd.DataFrame(column_data, columns=self.headings)
        self.data_frame = self.data_frame.append(column_df, ignore_index=True)

    def runSubsetStats(self, subset_i, data_i, comp_i):
        '''
        Runs statistics for the subset subset_i with respect to the component comp_i of data set data_i
        '''

        subset_label = dc[data_i].subsets[subset_i].label
        data_label = dc[data_i].label
        comp_label = self.dc[data_i].components[
            comp_i].label  # add to the name array to build the table

        # Build the cache key
        cache_key = subset_label + data_label + comp_label

        # See if the statistics are already in the cache
        try:
            column_data = self.cache_stash[cache_key]

        # Find the stats if not in the cache
        # Save in the cache

        except:
            mean_val = self.dc[data_i].compute_statistic(
                'mean',
                self.dc[data_i].subsets[subset_i].components[comp_i],
                subset_state=self.dc[data_i].subsets[subset_i].subset_state)
            median_val = self.dc[data_i].compute_statistic(
                'median',
                self.dc[data_i].subsets[subset_i].components[comp_i],
                subset_state=self.dc.subset_groups[subset_i].subset_state)
            min_val = self.dc[data_i].compute_statistic(
                'minimum',
                self.dc[data_i].subsets[subset_i].components[comp_i],
                subset_state=self.dc.subset_groups[subset_i].subset_state)
            max_val = self.dc[data_i].compute_statistic(
                'maximum',
                self.dc[data_i].subsets[subset_i].components[comp_i],
                subset_state=self.dc.subset_groups[subset_i].subset_state)
            sum_val = self.dc[data_i].compute_statistic(
                'sum',
                self.dc[data_i].subsets[subset_i].components[comp_i],
                subset_state=self.dc.subset_groups[subset_i].subset_state)

            column_data = np.asarray([[subset_label],
                                      [data_label], [comp_label], [mean_val],
                                      [median_val], [min_val], [max_val],
                                      [sum_val]]).transpose()

            self.cache_stash[cache_key] = column_data

        # Save the data in self.data_accurate
        column_df = pd.DataFrame(column_data, columns=self.headings)
        self.data_accurate = self.data_accurate.append(column_df,
                                                       ignore_index=True)

        # Round the values according to the number of significant figures set by the user
        mean_val = Decimal(float(column_data[0][3])) * Decimal(1)
        median_val = Decimal(float(column_data[0][4])) * Decimal(1)
        min_val = Decimal(float(column_data[0][5])) * Decimal(1)
        max_val = Decimal(float(column_data[0][6])) * Decimal(1)
        sum_val = Decimal(float(column_data[0][7])) * Decimal(1)

        # Create the column data array and append it to the data frame
        column_data = np.asarray([[subset_label], [data_label], [comp_label],
                                  [mean_val], [median_val], [min_val],
                                  [max_val], [sum_val]]).transpose()
        column_df = pd.DataFrame(column_data, columns=self.headings)
        self.data_frame = self.data_frame.append(column_df, ignore_index=True)

    def sigchange(self, i):
        # Set the number of significant figures according to what the user selects
        getcontext().prec = i

        # Retrospectively change the number of significant figures in the table

        data_labels = self.data_frame['Dataset']
        comp_labels = self.data_frame['Component']
        subset_labels = self.data_frame['Subset']

        mean_vals = []
        median_vals = []
        min_vals = []
        max_vals = []
        sum_vals = []

        # Get the values from the self.data_accurate array and append them
        for i in range(0, len(self.data_frame)):
            mean_vals.append(
                Decimal(self.data_accurate['Mean'][i]) * Decimal(1))
            median_vals.append(
                Decimal(self.data_accurate['Median'][i]) * Decimal(1))
            min_vals.append(
                Decimal(self.data_accurate['Minimum'][i]) * Decimal(1))
            max_vals.append(
                Decimal(self.data_accurate['Maximum'][i]) * Decimal(1))
            sum_vals.append(Decimal(self.data_accurate['Sum'][i]) * Decimal(1))

        column_data = np.asarray([
            subset_labels, data_labels, comp_labels, mean_vals, median_vals,
            min_vals, max_vals, sum_vals
        ]).transpose()
        self.data_frame = pd.DataFrame(column_data, columns=self.headings)
        model = pandasModel(self.data_frame, self.dc)
        self.table.setModel(model)
        self.table.setSortingEnabled(True)
        self.table.setShowGrid(False)

    def expandClicked(self):
        if self.expand_data.text() == "Expand all data and subsets":
            self.treeview.expandAll()
            self.expand_data.setText("Collapse all data and subsets")
        else:
            self.treeview.collapseAll()
            self.expand_data.setText("Expand all data and subsets")

    def allClicked(self):
        # Select all components of the treeview if checked and fill the table with newly checked items
        # Does not deselect if user unclicks it

        original_idx = self.treeview.selectionModel().selectedRows()

        self.treeview.selectAll()
        end_idx = self.treeview.selectionModel().selectedRows()
        for index in end_idx:
            if index not in original_idx:
                # Check to see if the clicked item is a subset component or a data component
                if index.parent().parent().parent().row() != 1:
                    self.runDataStats(index.parent().row(), index.row())
                else:
                    self.runSubsetStats(index.parent().parent().row(),
                                        index.parent().row(), index.row())

        # Set the table to display the correct data frame
        model = pandasModel(self.data_frame, self.dc)
        self.table.setModel(model)
        self.table.setSortingEnabled(True)
        self.table.setShowGrid(False)

    def noneClicked(self):
        self.treeview.clearSelection()
        self.data_frame = pd.DataFrame(columns=self.headings)
        model = pandasModel(self.data_frame, self.dc)
        self.table.setModel(model)
        self.table.setSortingEnabled(True)
        self.table.setShowGrid(False)

    def exportToFile(self):
        file_name, fltr = compat.getsavefilename(
            caption="Choose an output filename")

        try:
            self.data_frame.to_csv(str(file_name), index=False)
        except:
            print("passed")
            pass

    def switchMode(self):
        # if the user clicks to sort by components, change the text to "sort by subsets" and sort tree by components
        if self.switch_mode.text() == 'Sort tree by components':
            self.sortByComponents()
            self.switch_mode.setText('Sort tree by subsets')
        # otherwise the user wants to sort by subsets, change text to "sort by components" and sort tree by subsets
        else:
            self.sortBySubsets()
            self.switch_mode.setText('Sort tree by components')

    def sizeHint(self):
        return QSize(600, 800)

    def sortBySubsets(self):
        '''
        Sorts the treeview by subsets- Dataset then subset then component.
        What we originally had as the default
        '''
        # Save the selected rows from the component view
        try:
            selected = dict()
            for i in range(0, len(self.selected_indices)):
                item = self.model_components.itemFromIndex(
                    self.selected_indices[i])
                if item.row() != 0:
                    key = item.text() + " (" + item.parent().parent().text(
                    ) + ")" + item.parent().text()
                    selected[key] = item.index()
                else:
                    key = item.text() + item.parent().text()
                    selected[key] = item.index()
        except:
            pass

        # Set Expand/collapse button to "expand all"
        self.expand_data.setText("Expand all data and subsets")

        #Allow the user to select multiple rows at a time
        self.selection_model = QAbstractItemView.MultiSelection
        self.treeview.setSelectionMode(self.selection_model)

        # See if the model already exists instead of regenerating
        try:
            self.treeview.setModel(self.model_subsets)

        except:
            self.model_subsets = QStandardItemModel()
            self.model_subsets.setHorizontalHeaderLabels([''])

            self.treeview.setModel(self.model_subsets)
            self.treeview.setUniformRowHeights(True)

            # populate the tree
            # Make all the datasets be parents, and make it so they are not selectable
            parent_data = QStandardItem('{}'.format('Data'))
            parent_data.setEditable(False)
            parent_data.setSelectable(False)

            for i in range(0, len(self.dc)):
                parent = QStandardItem('{}'.format(self.dc.labels[i]))
                parent.setIcon(helpers.layer_icon(self.dc[i]))
                parent.setEditable(False)
                parent.setSelectable(False)

                # Make all the data components be children, nested under their parent
                for j in range(0, len(self.dc[i].components)):
                    child = QStandardItem('{}'.format(
                        str(self.dc[i].components[j])))
                    child.setEditable(False)

                    # Add to the subset_dict
                    key = self.dc[i].label + self.dc[i].components[
                        j].label + "All data-" + self.dc[i].label
                    self.subset_dict[key] = child.index()

                    parent.appendRow(child)

                parent_data.appendRow(parent)

                #Add the parents with their children to the QStandardItemModel
            self.model_subsets.appendRow(parent_data)

            parent_subset = QStandardItem('{}'.format('Subsets'))
            parent_subset.setEditable(False)
            parent_subset.setSelectable(False)

            # Set up the subsets as Subsets > choose subset > choose data set > choose component

            for j in range(0, len(self.dc.subset_groups)):
                grandparent = QStandardItem('{}'.format(
                    self.dc.subset_groups[j].label))
                grandparent.setIcon(
                    helpers.layer_icon(self.dc.subset_groups[j]))

                grandparent.setEditable(False)
                grandparent.setSelectable(False)

                for i in range(0, len(self.dc)):
                    parent = QStandardItem(
                        '{}'.format(self.dc.subset_groups[j].label) + ' (' +
                        '{}'.format(self.dc[i].label) + ')')

                    # Set up the circles
                    parent.setIcon(helpers.layer_icon(
                        self.dc.subset_groups[j]))
                    parent.setEditable(False)
                    parent.setSelectable(False)

                    try:
                        self.dc[i].compute_statistic(
                            'mean',
                            self.dc[i].subsets[j].components[0],
                            subset_state=self.dc[i].subsets[j].subset_state)

                    except:
                        parent.setForeground(QtGui.QBrush(Qt.gray))

                    for k in range(0, len(self.dc[i].components)):

                        child = QStandardItem('{}'.format(
                            str(self.dc[i].components[k])))
                        child.setEditable(False)

                        # Update the dict to keep track of row indices
                        key = self.dc[i].label + self.dc[i].components[
                            k].label + self.dc[i].subsets[j].label
                        self.subset_dict[key] = child.index()

                        parent.appendRow(child)

                        # Make gray and unselectable components that aren't defined for a subset
                        try:
                            self.dc[i].compute_statistic(
                                'mean',
                                self.dc[i].subsets[j].components[k],
                                subset_state=self.dc[i].subsets[j].subset_state
                            )

                        except:
                            #                             print("Glue has raised an Incompatible Attribute error on this component. Let's do this instead.")
                            child.setEditable(False)
                            child.setSelectable(False)
                            child.setForeground(QtGui.QBrush(Qt.gray))

                    grandparent.appendRow(parent)
                parent_subset.appendRow(grandparent)
            self.model_subsets.appendRow(parent_subset)

            # Fill out the dict now that the indices are connected to the QStandardItemModel

            # Full datasets
            for i in range(0, parent_data.rowCount()):
                for j in range(0, parent_data.child(i).rowCount()):
                    key = "All data (" + parent_data.child(
                        i).text() + ")" + parent_data.child(i).child(j).text()
                    self.subset_dict[key] = parent_data.child(i).child(
                        j).index()

            # Subsets
            for i in range(0, parent_subset.rowCount()):
                for j in range(0, parent_subset.child(i).rowCount()):
                    for k in range(0,
                                   parent_subset.child(i).child(j).rowCount()):
                        key = parent_subset.child(i).child(j).text(
                        ) + parent_subset.child(i).child(j).child(k).text()
                        self.subset_dict[key] = parent_subset.child(i).child(
                            j).child(k).index()

        self.treeview.setUniformRowHeights(True)

        selection_model = QItemSelectionModel(self.model_subsets)
        self.treeview.setSelectionModel(selection_model)
        selection_model.selectionChanged.connect(self.myPressedEvent)

        # Select rows that should be selected

        sel_mod = self.treeview.selectionModel()

        for i in range(0, len(selected)):
            #             key = list(self.selected_dict.keys())[list(self.selected_dict.values()).index(self.selected_dict[i])]
            key = list(selected.keys())[i]
            index = self.subset_dict[key]
            print(index.parent().row(), index.row())
            #             print(index, type(index))
            #             print(type(self.treeview.selectionModel().select(index, QItemSelectionModel.Select)))
            #             sel_mod.select(index, QItemSelectionModel.Select|QItemSelectionModel.Rows)
            self.treeview.setCurrentIndex(index)

        self.treeview.setSelectionModel(sel_mod)

    def sortByComponents(self):
        '''
        Sorts the treeview by components- Dataset then component then subsets
        '''
        # Save the selected rows from the subset view if applicable

        try:
            selected = dict()
            for i in range(0, len(self.selected_indices)):
                item = self.model_subsets.itemFromIndex(
                    self.selected_indices[i])
                if item.parent().parent().text() == "Data":
                    key = "All data (" + item.parent().text(
                    ) + ")" + item.text()
                    selected[key] = item.index()
                else:
                    key = item.parent().text() + item.text()
                    selected[key] = item.index()
        except:
            pass

        # Set Expand/collapse button to "expand all"
        self.expand_data.setText("Expand all data and subsets")

        self.selection_model = QAbstractItemView.MultiSelection
        self.treeview.setSelectionMode(self.selection_model)

        # See if the model already exists
        try:
            self.treeview.setModel(self.model_components)

        except:

            self.model_components = QStandardItemModel()
            self.model_components.setHorizontalHeaderLabels([''])

            self.treeview.setModel(self.model_components)
            self.treeview.setUniformRowHeights(True)

            # populate the tree
            # Make all the datasets be parents, and make it so they are not selectable

            for i in range(0, len(dc)):
                grandparent = QStandardItem('{}'.format(self.dc.labels[i]))
                grandparent.setIcon(helpers.layer_icon(self.dc[i]))
                grandparent.setEditable(False)
                grandparent.setSelectable(False)

                # Make all the data components be children, nested under their parent
                for k in range(0, len(self.dc[i].components)):
                    parent = QStandardItem('{}'.format(
                        str(self.dc[i].components[k])))
                    parent.setEditable(False)
                    parent.setSelectable(False)

                    child = QStandardItem('{}'.format('All data (' +
                                                      self.dc.labels[i] + ')'))
                    child.setIcon(helpers.layer_icon(self.dc[i]))
                    child.setEditable(False)

                    parent.appendRow(child)

                    for j in range(0, len(self.dc.subset_groups)):
                        child = QStandardItem('{}'.format(
                            self.dc.subset_groups[j].label))
                        child.setEditable(False)
                        child.setIcon(
                            helpers.layer_icon(self.dc.subset_groups[j]))

                        try:
                            self.dc[i].compute_statistic(
                                'mean',
                                self.dc[i].subsets[j].components[k],
                                subset_state=self.dc[i].subsets[j].subset_state
                            )

                        except:
                            #                             print("Glue has raised an Incompatible Attribute error on this component. Let's do this instead.")
                            child.setEditable(False)
                            child.setSelectable(False)
                            child.setForeground(QtGui.QBrush(Qt.gray))

                        parent.appendRow(child)
                    grandparent.appendRow(parent)
                self.model_components.appendRow(grandparent)

                # Fill out the dict now that the indices are connected to the QStandardItemModel
                for i in range(0, grandparent.rowCount()):
                    for j in range(0, grandparent.child(i).rowCount()):
                        if grandparent.child(i).child(j).row() == 0:
                            key = grandparent.child(i).child(
                                j).text() + grandparent.child(i).text()
                            self.component_dict[key] = grandparent.child(
                                i).child(j).index()
                        else:
                            key = grandparent.child(i).child(
                                j).text() + " (" + grandparent.text(
                                ) + ")" + grandparent.child(i).text()
                            self.component_dict[key] = grandparent.child(
                                i).child(j).index()

        self.treeview.setUniformRowHeights(True)

        selection_model = QItemSelectionModel(self.model_components)
        self.treeview.setSelectionModel(selection_model)
        selection_model.selectionChanged.connect(self.myPressedEvent)

        # Select the rows that should be selected

        sel_mod = self.treeview.selectionModel()

        for i in range(0, len(selected)):
            key = list(selected.keys())[i]
            index = self.component_dict[key]
            #             self.treeview.selectionModel().select(index, QItemSelectionModel.Select)
            print(index.parent().row(), index.row())
            # This causes an error when it runs
            #             sel_mod.select(index, QItemSelectionModel.Select|QItemSelectionModel.Rows)
            self.treeview.setCurrentIndex(index)

        self.treeview.setSelectionModel(sel_mod)
예제 #16
0
    def init_ui(self, window: QMainWindow, system_info):

        v_box = QVBoxLayout()
        button_style = "background-color: #006699; padding-left:20px; padding-right:20px;" \
                       "padding-top:5px; padding-bottom:5px;"

        # proceed to the json - button
        json_button = QPushButton("Proceed to JSON")
        json_button.setStyleSheet(button_style)
        json_button.clicked.connect(
            lambda: self.display_plaintext_data(window, system_info))

        v_box.addSpacing(20)

        # if system_info is empty
        if not system_info:
            nothing_found = QLabel("Nothing was found.")
            v_box.addWidget(nothing_found, alignment=Qt.AlignCenter)

        layout_grid = QGridLayout()
        for i, component in enumerate(system_info):
            if i == 0:
                prev_type = component["type"]
            else:
                prev_type = system_info[i - 1]["type"]

            if component["type"] != prev_type or i == 0:
                if component['type'] == 'I':
                    title = QLabel('ITEMS')
                    layout_grid.addWidget(title, 0, 0)
                else:
                    title = QLabel('PRODUCTS')
                    layout_grid.addWidget(title, 0, 1)
                # noinspection PyArgumentList
                title.setFont(QFont("futura", pointSize=16, italic=False))
                if i != 0:
                    v_box.addSpacing(10)
                tree = QTreeView()
                root_model = QStandardItemModel()
                root_model.setHorizontalHeaderLabels(['Name', 'Value'])
                tree.setModel(root_model)

            parent = root_model.invisibleRootItem()
            if component['type'] == 'I':
                self.list_element(component, parent)
                index = 0
            else:
                index = 1
                name = component['features'].get('type',
                                                 'Unknown component').upper()
                parent.appendRow([QStandardItem(name), QStandardItem('')])
                new_parent = parent.child(parent.rowCount() - 1)
                for feature in component.items():
                    if feature[0] != "type":
                        if feature[0] == 'features':
                            self.list_features(str(feature[1]), new_parent)
                        elif feature[0] == 'contents':
                            self.list_contents(str(feature[1]), new_parent)
                        else:
                            self.list_data(feature[0], feature[1], new_parent)

            tree.expandAll()

            layout_grid.addWidget(tree, 1, index)
            tree.resizeColumnToContents(0)
            v_box.addLayout(layout_grid)

        v_box.addWidget(json_button, alignment=Qt.AlignCenter)
        v_box.addSpacing(20)

        self.setLayout(v_box)
예제 #17
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.currentDict = {}
        self.initUI()

    def updateTree(self, data):
        print(data)
        # self.contents.show()

    def initUI(self):
        hLayout = QHBoxLayout()

        self.verticalGroupBox = QGroupBox()
        vLayout = QVBoxLayout()

        self.dropArea = DropArea("<drop here>", self)
        vLayout.addWidget(self.dropArea)

        self.dataList = QListWidget()
        vLayout.addWidget(self.dataList)

        self.verticalGroupBox.setLayout(vLayout)
        hLayout.addWidget(self.verticalGroupBox)

        self.contents = QTreeView()
        hLayout.addWidget(self.contents)

        self.setLayout(hLayout)
        self.setWindowTitle('Simplify3d to CSV')
        self.setGeometry(300, 300, 300, 150)

        self.dropArea.dropped.connect(self.onFileDropped)

    def onFileDropped(self, filename):
        filename = parse.unquote(filename)
        if filename.startswith('file:/'):
            filename = filename[6:]
        print(filename)
        if os.path.isfile(filename) is not True:
            return

        tree = ET.parse(filename)
        root = tree.getroot()
        self.currentDict = XmlDictConfig(root)
        '''
        QList<QStandardItem *> preparedRow =prepareRow("first", "second", "third");
        QStandardItem *item = standardModel->invisibleRootItem();
        // adding a row to the invisible root item produces a root element
        item->appendRow(preparedRow);

        QList<QStandardItem *> secondRow =prepareRow("111", "222", "333");
        // adding a row to an item starts a subtree
        preparedRow.first()->appendRow(secondRow);

        treeView->setModel(standardModel);
        treeView->expandAll();
        '''
        standardModel = QStandardItemModel()
        preparedRow = (QStandardItem("Title"), QStandardItem("Description"))
        item = standardModel.invisibleRootItem()
        item.appendRow(preparedRow)
        self.addDictTree(self.currentDict, item)
        self.contents.setModel(standardModel)
        self.contents.expandAll()

        print("dict reading finished")

    def addDictTree(self, data, item):
        for k,v in data.items():
            if isinstance(v, dict):
                childItem = QStandardItem(k)
                item.appendRow(childItem)
                self.addDictTree(v, childItem)
            else:
                try:
                    print(k+":"+v)
                    item.appendRow((QStandardItem(k), QStandardItem(v)))
                except:
                    print('Item adding failed')
예제 #18
0
class PyCommonist(QWidget):

    tool = None

    def __init__(self):
        super(PyCommonist, self).__init__()
        self.initUI()
        self.threads = []
        self.workers = []

    def initUI(self):

        self.currentDirectoryPath = ""

        self.generateSplitter()
        self.generateLeftTopFrame()
        self.generateLeftBottomFrame()

        self.showMaximized()
        self.setWindowTitle("PyCommonist - Wikimedia Commons")
        self.show()

    """
        onSelectFolder
    """

    def onSelectFolder(self, selected, deselected):

        try:
            currentIndex = selected.indexes()[0]
            self.currentDirectoryPath = self.modelTree.filePath(currentIndex)
            print(self.currentDirectoryPath)
            self.statusBar.setText("")
            self.exifImageCollection = []

            list_dir = os.listdir(self.currentDirectoryPath)
            files = [
                f for f in sorted(list_dir)
                if isfile(join(self.currentDirectoryPath, f))
            ]
            for file in files:
                fullFilePath = os.path.join(self.currentDirectoryPath, file)
                if fullFilePath.endswith(".jpeg") or fullFilePath.endswith(
                        ".jpg") or fullFilePath.endswith(".png"):

                    currentExifImage = EXIFImage()
                    currentExifImage.fullFilePath = fullFilePath
                    currentExifImage.filename = file
                    tags = None

                    try:
                        """ EXIF """
                        f_exif = open(fullFilePath, "rb")
                        tags = exifread.process_file(f_exif)
                        # print(tags)
                    except:
                        print("A problem with EXIF data reading")
                    """ Location"""
                    # 'GPS GPSLatitude', 'GPS GPSLongitude'] # [45, 49, 339/25] [4, 55, 716/25]
                    # 'GPS GPSImgDirection' 'GPS GPSLatitudeRef'
                    lat = ""
                    long = ""
                    heading = ""
                    try:
                        currentExifImage.lat, currentExifImage.long, currentExifImage.heading = get_exif_location(
                            tags)
                    except:
                        print("A problem with EXIF data reading")

                    dt = None
                    try:
                        """ Date Time """
                        dt = tags[
                            "EXIF DateTimeOriginal"]  # 2021:01:13 14:48:44
                    except:
                        print("A problem with EXIF data reading")

                    print(dt)
                    dt = str(dt)
                    indexSpace = dt.find(" ")
                    currentExifImage.date = dt[0:indexSpace].replace(":", "-")
                    currentExifImage.time = dt[indexSpace + 1:]

                    self.exifImageCollection.append(currentExifImage)
                    print(currentExifImage)

            self.generateRightFrame()

        except:
            print("Something bad happened inside onSelectFolder function")
            traceback.print_exc()

    """
        cbImportNoneStateChanged
    """

    def cbImportNoneStateChanged(self):

        print(self.cbImportNone.isChecked())
        print(len(self._currentUpload))

        if self.cbImportNone.isChecked() and len(self._currentUpload) > 0:

            for element in self._currentUpload:
                element.cbImport.setCheckState(False)

    """
        cbImportAllStateChanged
    """

    def cbImportAllStateChanged(self):

        print(self.cbImportAll.isChecked())
        print(len(self._currentUpload))
        if self.cbImportAll.isChecked() and len(self._currentUpload) > 0:

            for element in self._currentUpload:
                element.cbImport.setCheckState(True)

    """
        onClickImport
    """

    def onClickImport(self):
        if self.tool == None:
            self.tool = UploadTool()
        ret = self.tool.uploadImages(self)

    """
        cleanThreads
    """

    def cleanThreads(self):
        try:
            print("Clean properly threads")

            for thread in self.threads:
                print("Current thread proper deletion")
                thread.quit()
                thread.wait()

        except:
            print("A problem with cleanThreads")

    """
        generateSplitter
    """

    def generateSplitter(self):

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()

        self.leftTopFrame = QFrame()
        self.leftTopFrame.setFrameShape(QFrame.StyledPanel)

        self.rightWidget = QWidget()
        self.rightWidget.resize(300, 300)
        self.layoutRight = QVBoxLayout()
        self.rightWidget.setLayout(self.layoutRight)

        self.scroll = QScrollArea()
        self.layoutRight.addWidget(self.scroll)
        self.scroll.setWidgetResizable(True)
        self.scrollContent = QWidget(self.scroll)

        self.scrollLayout = QVBoxLayout(self.scrollContent)
        self.scrollContent.setLayout(self.scrollLayout)
        self.scroll.setWidget(self.scrollContent)

        self.splitterLeft = QSplitter(Qt.Vertical)
        self.leftBottonFrame = QFrame()
        self.leftBottonFrame.setFrameShape(QFrame.StyledPanel)

        self.splitterLeft.addWidget(self.leftTopFrame)
        self.splitterLeft.addWidget(self.leftBottonFrame)
        self.splitterLeft.setSizes([VERTICAL_TOP_SIZE, VERTICAL_BOTTOM_SIZE])
        """ Horizontal Splitter """
        self.splitterCentral = QSplitter(Qt.Horizontal)
        self.splitterCentral.addWidget(self.splitterLeft)
        self.splitterCentral.addWidget(self.rightWidget)
        self.splitterCentral.setSizes(
            [HORIZONTAL_LEFT_SIZE, HORIZONTAL_RIGHT_SIZE])
        hbox.addWidget(self.splitterCentral)

        vbox.addLayout(hbox)
        """ Status Bar """
        self.statusBar = QLabel()
        self.statusBar.setStyleSheet(STYLE_STATUSBAR)
        vbox.addWidget(self.statusBar)

        self.setLayout(vbox)

    """
        generateLeftTopFrame
    """

    def generateLeftTopFrame(self):

        self.layoutLeftTop = QFormLayout()
        self.layoutLeftTop.setFormAlignment(Qt.AlignTop)

        self.lblUserName = QLabel("Username: "******"Password: "******"Source: ")
        self.lblSource.setAlignment(Qt.AlignLeft)
        self.lineEditSource = QLineEdit()
        self.lineEditSource.setFixedWidth(WIDTH_WIDGET)
        self.lineEditSource.setText(LeftFrameConfig.source)
        self.lineEditSource.setAlignment(Qt.AlignLeft)
        self.layoutLeftTop.addRow(self.lblSource, self.lineEditSource)

        self.lblAuthor = QLabel("Author: ")
        self.lblAuthor.setAlignment(Qt.AlignLeft)
        self.lineEditAuthor = QLineEdit()
        self.lineEditAuthor.setFixedWidth(WIDTH_WIDGET)
        self.lineEditAuthor.setText(LeftFrameConfig.author)
        self.lineEditAuthor.setAlignment(Qt.AlignLeft)
        self.layoutLeftTop.addRow(self.lblAuthor, self.lineEditAuthor)

        self.lblCategories = QLabel("Categories: ")
        self.lblCategories.setAlignment(Qt.AlignLeft)
        self.lineEditCategories = QLineEdit()
        self.lineEditCategories.setText(LeftFrameConfig.categories)
        self.lineEditCategories.setFixedWidth(WIDTH_WIDGET)
        self.lineEditCategories.setAlignment(Qt.AlignLeft)
        self.layoutLeftTop.addRow(self.lblCategories, self.lineEditCategories)

        self.lblLicense = QLabel("License: ")
        self.lblLicense.setAlignment(Qt.AlignLeft)
        self.lineEditLicense = QLineEdit()
        self.lineEditLicense.setFixedWidth(WIDTH_WIDGET)
        self.lineEditLicense.setText(LeftFrameConfig.licence)
        self.lineEditLicense.setAlignment(Qt.AlignLeft)
        self.layoutLeftTop.addRow(self.lblLicense, self.lineEditLicense)

        self.lblDescription = QLabel("Description: ")
        self.lblDescription.setAlignment(Qt.AlignLeft)
        self.lineEditDescription = QPlainTextEdit()
        self.lineEditDescription.setFixedWidth(WIDTH_WIDGET)
        self.layoutLeftTop.addRow(self.lblDescription,
                                  self.lineEditDescription)

        separationLeftTopFrame = QLabel()
        self.layoutLeftTop.addWidget(separationLeftTopFrame)
        """ Button Import & None/All checkboxes"""
        importWidget = QWidget()
        importLayout = QHBoxLayout()
        importWidget.setLayout(importLayout)

        self.cbImportNone = QCheckBox("None")
        self.cbImportNone.stateChanged.connect(self.cbImportNoneStateChanged)

        self.cbImportAll = QCheckBox("All")
        self.cbImportAll.stateChanged.connect(self.cbImportAllStateChanged)

        self.btnImport = QPushButton("Import!")

        self.btnImport.clicked.connect(self.onClickImport)

        importLayout.addWidget(self.cbImportNone)
        importLayout.addWidget(self.cbImportAll)
        importLayout.addWidget(self.btnImport)
        self.layoutLeftTop.addWidget(importWidget)
        importWidget.setStyleSheet("border:1px solid #808080;")
        self.cbImportNone.setStyleSheet("border:0px;")
        self.cbImportAll.setStyleSheet("border:0px;")

        self.btnImport.setStyleSheet(STYLE_IMPORT_BUTTON)
        """ Layout Association of the Left Top Frame"""
        self.leftTopFrame.setLayout(self.layoutLeftTop)

    """
        generateLeftBottomFrame
    """

    def generateLeftBottomFrame(self):

        self.layoutLeftBottom = QVBoxLayout()
        """Model for QTreeView"""
        self.modelTree = QFileSystemModel()
        self.modelTree.setRootPath(QDir.currentPath())
        self.modelTree.setFilter(QDir.Dirs)  # Only directories
        """ QTreeView """
        self.treeLeftBottom = QTreeView()
        self.treeLeftBottom.setModel(self.modelTree)
        self.treeLeftBottom.setAnimated(False)
        self.treeLeftBottom.setIndentation(10)
        self.treeLeftBottom.setColumnWidth(0, 300)
        self.treeLeftBottom.expandAll()
        self.treeLeftBottom.selectionModel().selectionChanged.connect(
            self.onSelectFolder)
        self.layoutLeftBottom.addWidget(self.treeLeftBottom)
        self.leftBottonFrame.setLayout(self.layoutLeftBottom)

    """
        generateRightFrame
    """

    def generateRightFrame(self):

        self._currentUpload = []

        layout = self.scrollLayout
        print(layout)
        print(layout.count())

        while layout.count():
            print("destroy")
            child = layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()

        for currentExifImage in self.exifImageCollection:
            """ Current image """
            localWidget = ImageUpload()
            localLayout = QHBoxLayout()
            localLayout.setAlignment(Qt.AlignRight)
            localWidget.setLayout(localLayout)
            self.scrollLayout.addWidget(localWidget)
            self._currentUpload.append(localWidget)
            """Local Left Widget"""
            localLeftWidget = QWidget()
            localLeftLayout = QFormLayout()
            localLeftLayout.setAlignment(Qt.AlignRight)
            localLeftWidget.setLayout(localLeftLayout)
            localLayout.addWidget(localLeftWidget)
            """ import? + Import Status """
            cbImport = QCheckBox("Import")
            lblUploadResult = QLabel()
            lblUploadResult.setStyleSheet(STYLE_IMPORT_STATUS)
            localLeftLayout.addRow(cbImport, lblUploadResult)
            localWidget.cbImport = cbImport
            localWidget.lblUploadResult = lblUploadResult
            """ File Name of picture """
            lblFileName = QLabel("Name: ")
            lblFileName.setAlignment(Qt.AlignLeft)
            lineEditFileName = QLineEdit()
            lineEditFileName.setFixedWidth(WIDTH_WIDGET_RIGHT)
            lineEditFileName.setText(currentExifImage.filename)
            lineEditFileName.setAlignment(Qt.AlignLeft)
            localLeftLayout.addRow(lblFileName, lineEditFileName)
            localWidget.lineEditFileName = lineEditFileName
            """ Shadow Real FileName """
            lblRealFileName = QLineEdit()
            lblRealFileName.setText(currentExifImage.filename)
            localWidget.lblRealFileName = lblRealFileName
            localWidget.lblRealFileName.isVisible = False
            """ Description """
            lblDescription = QLabel("Description: ")
            lblDescription.setAlignment(Qt.AlignLeft)
            lineEditDescription = QPlainTextEdit()
            lineEditDescription.setFixedWidth(WIDTH_WIDGET_RIGHT)
            localLeftLayout.addRow(lblDescription, lineEditDescription)
            localWidget.lineEditDescription = lineEditDescription
            """ Categories """
            lblCategories = QLabel("Categories: ")
            lblCategories.setAlignment(Qt.AlignLeft)
            lineEditCategories = QLineEdit()
            lineEditCategories.setFixedWidth(WIDTH_WIDGET_RIGHT)
            lineEditCategories.setAlignment(Qt.AlignLeft)
            localLeftLayout.addRow(lblCategories, lineEditCategories)
            localWidget.lineEditCategories = lineEditCategories

            lblLocation = QLabel("Location: ")
            lblLocation.setAlignment(Qt.AlignLeft)
            lineEditLocation = QLineEdit()
            lineEditLocation.setFixedWidth(WIDTH_WIDGET_RIGHT)
            if currentExifImage.lat == None or currentExifImage.long == None:
                lineEditLocation.setText("")
            else:
                lineEditLocation.setText(
                    str(currentExifImage.lat) + "|" +
                    str(currentExifImage.long) + "|heading:" +
                    str(currentExifImage.heading))
            lineEditLocation.setAlignment(Qt.AlignLeft)
            localLeftLayout.addRow(lblLocation, lineEditLocation)
            localWidget.lineEditLocation = lineEditLocation

            lblDateTime = QLabel("Date Time: ")
            lblDateTime.setAlignment(Qt.AlignLeft)
            lineEditDateTime = QLineEdit()
            lineEditDateTime.setFixedWidth(WIDTH_WIDGET_RIGHT)
            lineEditDateTime.setText(currentExifImage.date + " " +
                                     currentExifImage.time)
            lineEditDateTime.setAlignment(Qt.AlignLeft)
            localLeftLayout.addRow(lblDateTime, lineEditDateTime)
            localWidget.lineEditDateTime = lineEditDateTime
            """ Image itself """
            label = QLabel()
            pixmap = QPixmap(currentExifImage.fullFilePath)
            pixmapResize = pixmap.scaledToWidth(IMAGE_DIMENSION,
                                                Qt.FastTransformation)
            label.setPixmap(pixmapResize)
            localLayout.addWidget(label)
            localWidget.fullFilePath = currentExifImage.fullFilePath

            self.update()
    # Defining a couple of items
    americaItem = QStandardItem("America")
    canadaItem = QStandardItem("Canada")
    europeItem = QStandardItem("Europe")
    franceItem = QStandardItem("France")
    brittanyItem = QStandardItem("Brittany")

    # Building up the hierarchy
    rootItem.appendRow(americaItem)
    rootItem.appendRow(europeItem)
    americaItem.appendRow(canadaItem)
    europeItem.appendRow(franceItem)
    franceItem.appendRow(brittanyItem)

    tree_view.setModel(model)

    # Bind selection to the print_selection function (must be after the model setup)
    selection_model = tree_view.selectionModel()
    selection_model.selectionChanged.connect(print_selection)

    tree_view.expandAll()      # expand all (this is not the case by default)
    tree_view.show()

    # The mainloop of the application. The event handling starts from this point.
    # The exec_() method has an underscore. It is because the exec is a Python keyword. And thus, exec_() was used instead.
    exit_code = app.exec_()

    # The sys.exit() method ensures a clean exit.
    # The environment will be informed, how the application ended.
    sys.exit(exit_code)
class AttributeController(QMainWindow):
    _visibility_dict = {
        'Beginner': EVisibility.Beginner,
        'Expert': EVisibility.Expert,
        'Guru': EVisibility.Guru,
        'All': EVisibility.Invisible,
    }

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

        #
        self.setWindowTitle('Attribute Controller')

        #
        self._view = QTreeView()
        self._view.setFont(get_system_font())

        #
        self._node_map = node_map
        self._model = FeatureTreeModel(node_map=self._node_map, )

        #
        self._proxy = FilterProxyModel()
        self._proxy.setSourceModel(self._model)
        self._proxy.setDynamicSortFilter(False)

        #
        self._delegate = FeatureEditDelegate(proxy=self._proxy)
        self._view.setModel(self._proxy)
        self._view.setItemDelegate(self._delegate)
        self._view.setUniformRowHeights(True)

        #
        unit = 260
        for i in range(2):
            self._view.setColumnWidth(i, unit)

        w, h = 700, 600
        self._view.setGeometry(100, 100, w, h)

        self.setCentralWidget(self._view)
        self.setGeometry(100, 100, unit * 2, 640)

        self._combo_box_visibility = None
        self._line_edit_search_box = None

        #
        self._setup_toolbars()

    def _setup_toolbars(self):
        #
        group_filter = self.addToolBar('Node Visibility')
        group_manipulation = self.addToolBar('Node Tree Manipulation')

        #
        label_visibility = QLabel()
        label_visibility.setText('Visibility')
        label_visibility.setFont(get_system_font())

        #
        self._combo_box_visibility = QComboBox()
        self._combo_box_visibility.setSizeAdjustPolicy(
            QComboBox.AdjustToContents)

        #
        items = ('Beginner', 'Expert', 'Guru', 'All')
        for item in items:
            self._combo_box_visibility.addItem(item)

        shortcut_key = 'Ctrl+v'
        shortcut = QShortcut(QKeySequence(shortcut_key), self)

        def show_popup():
            self._combo_box_visibility.showPopup()

        shortcut.activated.connect(show_popup)

        self._combo_box_visibility.setToolTip(
            compose_tooltip('Filter the nodes to show', shortcut_key))
        self._combo_box_visibility.setFont(get_system_font())
        self._combo_box_visibility.currentIndexChanged.connect(
            self._invalidate_feature_tree_by_visibility)

        #
        button_expand_all = ActionExpandAll(icon='expand.png',
                                            title='Expand All',
                                            parent=self,
                                            action=self.action_on_expand_all)
        shortcut_key = 'Ctrl+e'
        button_expand_all.setToolTip(
            compose_tooltip('Expand the node tree', shortcut_key))
        button_expand_all.setShortcut(shortcut_key)
        button_expand_all.toggle()

        #
        button_collapse_all = ActionCollapseAll(
            icon='collapse.png',
            title='Collapse All',
            parent=self,
            action=self.action_on_collapse_all)
        shortcut_key = 'Ctrl+c'
        button_collapse_all.setToolTip(
            compose_tooltip('Collapse the node tree', shortcut_key))
        button_collapse_all.setShortcut(shortcut_key)
        button_collapse_all.toggle()

        #
        label_search = QLabel()
        label_search.setText('RegEx Search')
        label_search.setFont(get_system_font())

        #
        self._line_edit_search_box = QLineEdit()
        self._line_edit_search_box.setFont(get_system_font())
        self._line_edit_search_box.textEdited.connect(
            self._invalidate_feature_tree_by_keyword)

        #
        group_filter.addWidget(label_visibility)
        group_filter.addWidget(self._combo_box_visibility)
        group_filter.addWidget(label_search)
        group_filter.addWidget(self._line_edit_search_box)
        group_filter.setStyleSheet('QToolBar{spacing:6px;}')

        #
        group_manipulation.addAction(button_expand_all)
        group_manipulation.addAction(button_collapse_all)

        #
        group_manipulation.actionTriggered[QAction].connect(
            self.on_button_clicked_action)

        #
        self._combo_box_visibility.setCurrentIndex(
            self._visibility_dict['Expert'])

    def _invalidate_feature_tree_by_visibility(self):
        visibility = self._visibility_dict[
            self._combo_box_visibility.currentText()]
        self._proxy.setVisibility(visibility)
        self._view.expandAll()

    @pyqtSlot('QString')
    def _invalidate_feature_tree_by_keyword(self, keyword):
        self._proxy.setKeyword(keyword)
        self._view.expandAll()

    @staticmethod
    def on_button_clicked_action(action):
        action.execute()

    def expand_all(self):
        self._view.expandAll()

    def collapse_all(self):
        self._view.collapseAll()

    def resize_column_width(self):
        for i in range(self._model.columnCount()):
            self._view.resizeColumnToContents(i)

    def action_on_expand_all(self):
        self.expand_all()

    def action_on_collapse_all(self):
        self.collapse_all()
예제 #21
0
파일: tdm.py 프로젝트: kylegordon/tdm
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self._version = "0.1.20"
        self.setWindowIcon(QIcon("GUI/icons/logo.png"))
        self.setWindowTitle("Tasmota Device Manager {}".format(self._version))

        self.main_splitter = QSplitter()
        self.devices_splitter = QSplitter(Qt.Vertical)

        self.mqtt_queue = []
        self.devices = {}

        self.fulltopic_queue = []
        old_settings = QSettings()

        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()),
                                  QSettings.IniFormat)
        self.setMinimumSize(QSize(1280, 800))

        for k in old_settings.allKeys():
            self.settings.setValue(k, old_settings.value(k))
            old_settings.remove(k)

        self.device_model = TasmotaDevicesModel()
        self.telemetry_model = TasmotaDevicesTree()
        self.console_model = ConsoleModel()

        self.sorted_console_model = QSortFilterProxyModel()
        self.sorted_console_model.setSourceModel(self.console_model)
        self.sorted_console_model.setFilterKeyColumn(CnsMdl.FRIENDLY_NAME)

        self.setup_mqtt()
        self.setup_telemetry_view()
        self.setup_main_layout()
        self.add_devices_tab()
        self.build_toolbars()
        self.setStatusBar(QStatusBar())

        self.queue_timer = QTimer()
        self.queue_timer.timeout.connect(self.mqtt_publish_queue)
        self.queue_timer.start(500)

        self.auto_timer = QTimer()
        self.auto_timer.timeout.connect(self.autoupdate)

        self.load_window_state()

        if self.settings.value("connect_on_startup", False, bool):
            self.actToggleConnect.trigger()

    def setup_main_layout(self):
        self.mdi = QMdiArea()
        self.mdi.setActivationOrder(QMdiArea.ActivationHistoryOrder)
        self.mdi.setViewMode(QMdiArea.TabbedView)
        self.mdi.setDocumentMode(True)

        mdi_widget = QWidget()
        mdi_widget.setLayout(VLayout())
        mdi_widget.layout().addWidget(self.mdi)

        self.devices_splitter.addWidget(mdi_widget)

        vl_console = VLayout()
        hl_filter = HLayout()
        self.cbFilter = QCheckBox("Console filtering")
        self.cbxFilterDevice = QComboBox()
        self.cbxFilterDevice.setEnabled(False)
        self.cbxFilterDevice.setFixedWidth(200)
        self.cbxFilterDevice.setModel(self.device_model)
        self.cbxFilterDevice.setModelColumn(DevMdl.FRIENDLY_NAME)
        hl_filter.addWidgets([self.cbFilter, self.cbxFilterDevice])
        hl_filter.addStretch(0)
        vl_console.addLayout(hl_filter)

        self.console_view = TableView()
        self.console_view.setModel(self.console_model)
        self.console_view.setupColumns(columns_console)
        self.console_view.setAlternatingRowColors(True)
        self.console_view.verticalHeader().setDefaultSectionSize(20)
        self.console_view.setMinimumHeight(200)

        vl_console.addWidget(self.console_view)

        console_widget = QWidget()
        console_widget.setLayout(vl_console)

        self.devices_splitter.addWidget(console_widget)
        self.main_splitter.insertWidget(0, self.devices_splitter)
        self.setCentralWidget(self.main_splitter)
        self.console_view.clicked.connect(self.select_cons_entry)
        self.console_view.doubleClicked.connect(self.view_payload)

        self.cbFilter.toggled.connect(self.toggle_console_filter)
        self.cbxFilterDevice.currentTextChanged.connect(
            self.select_console_filter)

    def setup_telemetry_view(self):
        tele_widget = QWidget()
        vl_tele = VLayout()
        self.tview = QTreeView()
        self.tview.setMinimumWidth(300)
        self.tview.setModel(self.telemetry_model)
        self.tview.setAlternatingRowColors(True)
        self.tview.setUniformRowHeights(True)
        self.tview.setIndentation(15)
        self.tview.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum))
        self.tview.expandAll()
        self.tview.resizeColumnToContents(0)
        vl_tele.addWidget(self.tview)
        tele_widget.setLayout(vl_tele)
        self.main_splitter.addWidget(tele_widget)

    def setup_mqtt(self):
        self.mqtt = MqttClient()
        self.mqtt.connecting.connect(self.mqtt_connecting)
        self.mqtt.connected.connect(self.mqtt_connected)
        self.mqtt.disconnected.connect(self.mqtt_disconnected)
        self.mqtt.connectError.connect(self.mqtt_connectError)
        self.mqtt.messageSignal.connect(self.mqtt_message)

    def add_devices_tab(self):
        tabDevicesList = DevicesListWidget(self)
        self.mdi.addSubWindow(tabDevicesList)
        tabDevicesList.setWindowState(Qt.WindowMaximized)

    def load_window_state(self):
        wndGeometry = self.settings.value('window_geometry')
        if wndGeometry:
            self.restoreGeometry(wndGeometry)
        spltState = self.settings.value('splitter_state')
        if spltState:
            self.main_splitter.restoreState(spltState)

    def build_toolbars(self):
        main_toolbar = Toolbar(orientation=Qt.Horizontal,
                               iconsize=16,
                               label_position=Qt.ToolButtonTextBesideIcon)
        main_toolbar.setObjectName("main_toolbar")
        self.addToolBar(main_toolbar)

        main_toolbar.addAction(QIcon("./GUI/icons/connections.png"), "Broker",
                               self.setup_broker)
        self.actToggleConnect = QAction(QIcon("./GUI/icons/disconnect.png"),
                                        "MQTT")
        self.actToggleConnect.setCheckable(True)
        self.actToggleConnect.toggled.connect(self.toggle_connect)
        main_toolbar.addAction(self.actToggleConnect)

        self.actToggleAutoUpdate = QAction(QIcon("./GUI/icons/automatic.png"),
                                           "Auto telemetry")
        self.actToggleAutoUpdate.setCheckable(True)
        self.actToggleAutoUpdate.toggled.connect(self.toggle_autoupdate)
        main_toolbar.addAction(self.actToggleAutoUpdate)

        main_toolbar.addSeparator()
        main_toolbar.addAction(QIcon("./GUI/icons/bssid.png"), "BSSId",
                               self.bssid)
        main_toolbar.addAction(QIcon("./GUI/icons/export.png"), "Export list",
                               self.export)

    def initial_query(self, idx, queued=False):
        for q in initial_queries:
            topic = "{}status".format(self.device_model.commandTopic(idx))
            if queued:
                self.mqtt_queue.append([topic, q])
            else:
                self.mqtt.publish(topic, q, 1)
            self.console_log(topic, "Asked for STATUS {}".format(q), q)

    def setup_broker(self):
        brokers_dlg = BrokerDialog()
        if brokers_dlg.exec_(
        ) == QDialog.Accepted and self.mqtt.state == self.mqtt.Connected:
            self.mqtt.disconnect()

    def toggle_autoupdate(self, state):
        if state:
            self.auto_timer.setInterval(5000)
            self.auto_timer.start()

    def toggle_connect(self, state):
        if state and self.mqtt.state == self.mqtt.Disconnected:
            self.broker_hostname = self.settings.value('hostname', 'localhost')
            self.broker_port = self.settings.value('port', 1883, int)
            self.broker_username = self.settings.value('username')
            self.broker_password = self.settings.value('password')

            self.mqtt.hostname = self.broker_hostname
            self.mqtt.port = self.broker_port

            if self.broker_username:
                self.mqtt.setAuth(self.broker_username, self.broker_password)
            self.mqtt.connectToHost()
        elif not state and self.mqtt.state == self.mqtt.Connected:
            self.mqtt_disconnect()

    def autoupdate(self):
        if self.mqtt.state == self.mqtt.Connected:
            for d in range(self.device_model.rowCount()):
                idx = self.device_model.index(d, 0)
                cmnd = self.device_model.commandTopic(idx)
                self.mqtt.publish(cmnd + "STATUS", payload=8)

    def mqtt_connect(self):
        self.broker_hostname = self.settings.value('hostname', 'localhost')
        self.broker_port = self.settings.value('port', 1883, int)
        self.broker_username = self.settings.value('username')
        self.broker_password = self.settings.value('password')

        self.mqtt.hostname = self.broker_hostname
        self.mqtt.port = self.broker_port

        if self.broker_username:
            self.mqtt.setAuth(self.broker_username, self.broker_password)

        if self.mqtt.state == self.mqtt.Disconnected:
            self.mqtt.connectToHost()

    def mqtt_disconnect(self):
        self.mqtt.disconnectFromHost()

    def mqtt_connecting(self):
        self.statusBar().showMessage("Connecting to broker")

    def mqtt_connected(self):
        self.actToggleConnect.setIcon(QIcon("./GUI/icons/connect.png"))
        self.statusBar().showMessage("Connected to {}:{} as {}".format(
            self.broker_hostname, self.broker_port,
            self.broker_username if self.broker_username else '[anonymous]'))

        self.mqtt_subscribe()

        for d in range(self.device_model.rowCount()):
            idx = self.device_model.index(d, 0)
            self.initial_query(idx)

    def mqtt_subscribe(self):
        main_topics = ["+/stat/+", "+/tele/+", "stat/#", "tele/#"]

        for d in range(self.device_model.rowCount()):
            idx = self.device_model.index(d, 0)
            if not self.device_model.isDefaultTemplate(idx):
                main_topics.append(self.device_model.commandTopic(idx))
                main_topics.append(self.device_model.statTopic(idx))

        for t in main_topics:
            self.mqtt.subscribe(t)

    def mqtt_publish_queue(self):
        for q in self.mqtt_queue:
            t, p = q
            self.mqtt.publish(t, p)
            self.mqtt_queue.pop(self.mqtt_queue.index(q))

    def mqtt_disconnected(self):
        self.actToggleConnect.setIcon(QIcon("./GUI/icons/disconnect.png"))
        self.statusBar().showMessage("Disconnected")

    def mqtt_connectError(self, rc):
        reason = {
            1: "Incorrect protocol version",
            2: "Invalid client identifier",
            3: "Server unavailable",
            4: "Bad username or password",
            5: "Not authorized",
        }
        self.statusBar().showMessage("Connection error: {}".format(reason[rc]))
        self.actToggleConnect.setChecked(False)

    def mqtt_message(self, topic, msg):
        found = self.device_model.findDevice(topic)
        if found.reply == 'LWT':
            if not msg:
                msg = "offline"

            if found.index.isValid():
                self.console_log(topic, "LWT update: {}".format(msg), msg)
                self.device_model.updateValue(found.index, DevMdl.LWT, msg)
                self.initial_query(found.index, queued=True)

            elif msg == "Online":
                self.console_log(
                    topic,
                    "LWT for unknown device '{}'. Asking for FullTopic.".
                    format(found.topic), msg, False)
                self.mqtt_queue.append(
                    ["cmnd/{}/fulltopic".format(found.topic), ""])
                self.mqtt_queue.append(
                    ["{}/cmnd/fulltopic".format(found.topic), ""])

        elif found.reply == 'RESULT':
            try:
                full_topic = loads(msg).get('FullTopic')
                new_topic = loads(msg).get('Topic')
                template_name = loads(msg).get('NAME')
                ota_url = loads(msg).get('OtaUrl')
                teleperiod = loads(msg).get('TelePeriod')

                if full_topic:
                    # TODO: update FullTopic for existing device AFTER the FullTopic changes externally (the message will arrive from new FullTopic)
                    if not found.index.isValid():
                        self.console_log(
                            topic, "FullTopic for {}".format(found.topic), msg,
                            False)

                        new_idx = self.device_model.addDevice(found.topic,
                                                              full_topic,
                                                              lwt='online')
                        tele_idx = self.telemetry_model.addDevice(
                            TasmotaDevice, found.topic)
                        self.telemetry_model.devices[found.topic] = tele_idx
                        #TODO: add QSortFilterProxyModel to telemetry treeview and sort devices after adding

                        self.initial_query(new_idx)
                        self.console_log(
                            topic,
                            "Added {} with fulltopic {}, querying for STATE".
                            format(found.topic, full_topic), msg)
                        self.tview.expand(tele_idx)
                        self.tview.resizeColumnToContents(0)

                elif new_topic:
                    if found.index.isValid() and found.topic != new_topic:
                        self.console_log(
                            topic, "New topic for {}".format(found.topic), msg)

                        self.device_model.updateValue(found.index,
                                                      DevMdl.TOPIC, new_topic)

                        tele_idx = self.telemetry_model.devices.get(
                            found.topic)

                        if tele_idx:
                            self.telemetry_model.setDeviceName(
                                tele_idx, new_topic)
                            self.telemetry_model.devices[
                                new_topic] = self.telemetry_model.devices.pop(
                                    found.topic)

                elif template_name:
                    self.device_model.updateValue(
                        found.index, DevMdl.MODULE,
                        "{} (0)".format(template_name))

                elif ota_url:
                    self.device_model.updateValue(found.index, DevMdl.OTA_URL,
                                                  ota_url)

                elif teleperiod:
                    self.device_model.updateValue(found.index,
                                                  DevMdl.TELEPERIOD,
                                                  teleperiod)

            except JSONDecodeError as e:
                self.console_log(
                    topic,
                    "JSON payload decode error. Check error.log for additional info."
                )
                with open("{}/TDM/error.log".format(QDir.homePath()),
                          "a+") as l:
                    l.write("{}\t{}\t{}\t{}\n".format(
                        QDateTime.currentDateTime().toString(
                            "yyyy-MM-dd hh:mm:ss"), topic, msg, e.msg))

        elif found.index.isValid():
            ok = False
            try:
                if msg.startswith("{"):
                    payload = loads(msg)
                else:
                    payload = msg
                ok = True
            except JSONDecodeError as e:
                self.console_log(
                    topic,
                    "JSON payload decode error. Check error.log for additional info."
                )
                with open("{}/TDM/error.log".format(QDir.homePath()),
                          "a+") as l:
                    l.write("{}\t{}\t{}\t{}\n".format(
                        QDateTime.currentDateTime().toString(
                            "yyyy-MM-dd hh:mm:ss"), topic, msg, e.msg))

            if ok:
                try:
                    if found.reply == 'STATUS':
                        self.console_log(topic, "Received device status", msg)
                        payload = payload['Status']
                        self.device_model.updateValue(
                            found.index, DevMdl.FRIENDLY_NAME,
                            payload['FriendlyName'][0])
                        self.telemetry_model.setDeviceFriendlyName(
                            self.telemetry_model.devices[found.topic],
                            payload['FriendlyName'][0])
                        module = payload['Module']
                        if module == 0:
                            self.mqtt.publish(
                                self.device_model.commandTopic(found.index) +
                                "template")
                        else:
                            self.device_model.updateValue(
                                found.index, DevMdl.MODULE,
                                modules.get(module, 'Unknown'))
                        self.device_model.updateValue(found.index,
                                                      DevMdl.MODULE_ID, module)

                    elif found.reply == 'STATUS1':
                        self.console_log(topic, "Received program information",
                                         msg)
                        payload = payload['StatusPRM']
                        self.device_model.updateValue(
                            found.index, DevMdl.RESTART_REASON,
                            payload.get('RestartReason'))
                        self.device_model.updateValue(found.index,
                                                      DevMdl.OTA_URL,
                                                      payload.get('OtaUrl'))

                    elif found.reply == 'STATUS2':
                        self.console_log(topic,
                                         "Received firmware information", msg)
                        payload = payload['StatusFWR']
                        self.device_model.updateValue(found.index,
                                                      DevMdl.FIRMWARE,
                                                      payload['Version'])
                        self.device_model.updateValue(found.index, DevMdl.CORE,
                                                      payload['Core'])

                    elif found.reply == 'STATUS3':
                        self.console_log(topic, "Received syslog information",
                                         msg)
                        payload = payload['StatusLOG']
                        self.device_model.updateValue(found.index,
                                                      DevMdl.TELEPERIOD,
                                                      payload['TelePeriod'])

                    elif found.reply == 'STATUS5':
                        self.console_log(topic, "Received network status", msg)
                        payload = payload['StatusNET']
                        self.device_model.updateValue(found.index, DevMdl.MAC,
                                                      payload['Mac'])
                        self.device_model.updateValue(found.index, DevMdl.IP,
                                                      payload['IPAddress'])

                    elif found.reply in ('STATE', 'STATUS11'):
                        self.console_log(topic, "Received device state", msg)
                        if found.reply == 'STATUS11':
                            payload = payload['StatusSTS']
                        self.parse_state(found.index, payload)

                    elif found.reply in ('SENSOR', 'STATUS8'):
                        self.console_log(topic, "Received telemetry", msg)
                        if found.reply == 'STATUS8':
                            payload = payload['StatusSNS']
                        self.parse_telemetry(found.index, payload)

                    elif found.reply.startswith('POWER'):
                        self.console_log(
                            topic, "Received {} state".format(found.reply),
                            msg)
                        payload = {found.reply: msg}
                        self.parse_power(found.index, payload)

                except KeyError as k:
                    self.console_log(
                        topic,
                        "JSON key error. Check error.log for additional info.")
                    with open("{}/TDM/error.log".format(QDir.homePath()),
                              "a+") as l:
                        l.write("{}\t{}\t{}\tKeyError: {}\n".format(
                            QDateTime.currentDateTime().toString(
                                "yyyy-MM-dd hh:mm:ss"), topic, payload,
                            k.args[0]))

    def parse_power(self, index, payload, from_state=False):
        old = self.device_model.power(index)
        power = {
            k: payload[k]
            for k in payload.keys() if k.startswith("POWER")
        }
        # TODO: fix so that number of relays get updated properly after module/no. of relays change
        needs_update = False
        if old:
            # if from_state and len(old) != len(power):
            #     needs_update = True
            #
            # else:
            for k in old.keys():
                needs_update |= old[k] != power.get(k, old[k])
                if needs_update:
                    break
        else:
            needs_update = True

        if needs_update:
            self.device_model.updateValue(index, DevMdl.POWER, power)

    def parse_state(self, index, payload):
        bssid = payload['Wifi'].get('BSSId')
        if not bssid:
            bssid = payload['Wifi'].get('APMac')
        self.device_model.updateValue(index, DevMdl.BSSID, bssid)
        self.device_model.updateValue(index, DevMdl.SSID,
                                      payload['Wifi']['SSId'])
        self.device_model.updateValue(index, DevMdl.CHANNEL,
                                      payload['Wifi'].get('Channel', "n/a"))
        self.device_model.updateValue(index, DevMdl.RSSI,
                                      payload['Wifi']['RSSI'])
        self.device_model.updateValue(index, DevMdl.UPTIME, payload['Uptime'])
        self.device_model.updateValue(index, DevMdl.LOADAVG,
                                      payload.get('LoadAvg'))
        self.device_model.updateValue(index, DevMdl.LINKCOUNT,
                                      payload['Wifi'].get('LinkCount', "n/a"))
        self.device_model.updateValue(index, DevMdl.DOWNTIME,
                                      payload['Wifi'].get('Downtime', "n/a"))

        self.parse_power(index, payload, True)

        tele_idx = self.telemetry_model.devices.get(
            self.device_model.topic(index))

        if tele_idx:
            tele_device = self.telemetry_model.getNode(tele_idx)
            self.telemetry_model.setDeviceFriendlyName(
                tele_idx, self.device_model.friendly_name(index))

            pr = tele_device.provides()
            for k in pr.keys():
                self.telemetry_model.setData(pr[k], payload.get(k))

    def parse_telemetry(self, index, payload):
        device = self.telemetry_model.devices.get(
            self.device_model.topic(index))
        if device:
            node = self.telemetry_model.getNode(device)
            time = node.provides()['Time']
            if 'Time' in payload:
                self.telemetry_model.setData(time, payload.pop('Time'))

            temp_unit = "C"
            pres_unit = "hPa"

            if 'TempUnit' in payload:
                temp_unit = payload.pop('TempUnit')

            if 'PressureUnit' in payload:
                pres_unit = payload.pop('PressureUnit')

            for sensor in sorted(payload.keys()):
                if sensor == 'DS18x20':
                    for sns_name in payload[sensor].keys():
                        d = node.devices().get(sensor)
                        if not d:
                            d = self.telemetry_model.addDevice(
                                DS18x20, payload[sensor][sns_name]['Type'],
                                device)
                        self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                        payload[sensor][sns_name]['Id'] = payload[sensor][
                            sns_name].pop('Address')

                        pr = self.telemetry_model.getNode(d).provides()
                        for pk in pr.keys():
                            self.telemetry_model.setData(
                                pr[pk], payload[sensor][sns_name].get(pk))
                        self.tview.expand(d)

                elif sensor.startswith('DS18B20'):
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            DS18x20, sensor, device)
                    self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                    pr = self.telemetry_model.getNode(d).provides()
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)

                if sensor == 'COUNTER':
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            CounterSns, "Counter", device)
                    pr = self.telemetry_model.getNode(d).provides()
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)

                else:
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            sensor_map.get(sensor, Node), sensor, device)
                    pr = self.telemetry_model.getNode(d).provides()
                    if 'Temperature' in pr:
                        self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                    if 'Pressure' in pr or 'SeaPressure' in pr:
                        self.telemetry_model.getNode(d).setPresUnit(pres_unit)
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)
        # self.tview.resizeColumnToContents(0)

    def console_log(self, topic, description, payload="", known=True):
        longest_tp = 0
        longest_fn = 0
        short_topic = "/".join(topic.split("/")[0:-1])
        fname = self.devices.get(short_topic, "")
        if not fname:
            device = self.device_model.findDevice(topic)
            fname = self.device_model.friendly_name(device.index)
            self.devices.update({short_topic: fname})
        self.console_model.addEntry(topic, fname, description, payload, known)

        if len(topic) > longest_tp:
            longest_tp = len(topic)
            self.console_view.resizeColumnToContents(1)

        if len(fname) > longest_fn:
            longest_fn = len(fname)
            self.console_view.resizeColumnToContents(1)

    def view_payload(self, idx):
        if self.cbFilter.isChecked():
            idx = self.sorted_console_model.mapToSource(idx)
        row = idx.row()
        timestamp = self.console_model.data(
            self.console_model.index(row, CnsMdl.TIMESTAMP))
        topic = self.console_model.data(
            self.console_model.index(row, CnsMdl.TOPIC))
        payload = self.console_model.data(
            self.console_model.index(row, CnsMdl.PAYLOAD))

        dlg = PayloadViewDialog(timestamp, topic, payload)
        dlg.exec_()

    def select_cons_entry(self, idx):
        self.cons_idx = idx

    def export(self):
        fname, _ = QFileDialog.getSaveFileName(self,
                                               "Export device list as...",
                                               directory=QDir.homePath(),
                                               filter="CSV files (*.csv)")
        if fname:
            if not fname.endswith(".csv"):
                fname += ".csv"

            with open(fname, "w", encoding='utf8') as f:
                column_titles = [
                    'mac', 'topic', 'friendly_name', 'full_topic',
                    'cmnd_topic', 'stat_topic', 'tele_topic', 'module',
                    'module_id', 'firmware', 'core'
                ]
                c = csv.writer(f)
                c.writerow(column_titles)

                for r in range(self.device_model.rowCount()):
                    d = self.device_model.index(r, 0)
                    c.writerow([
                        self.device_model.mac(d),
                        self.device_model.topic(d),
                        self.device_model.friendly_name(d),
                        self.device_model.fullTopic(d),
                        self.device_model.commandTopic(d),
                        self.device_model.statTopic(d),
                        self.device_model.teleTopic(d),
                        modules.get(self.device_model.module(d)),
                        self.device_model.module(d),
                        self.device_model.firmware(d),
                        self.device_model.core(d)
                    ])

    def bssid(self):
        BSSIdDialog().exec_()
        # if dlg.exec_() == QDialog.Accepted:

    def toggle_console_filter(self, state):
        self.cbxFilterDevice.setEnabled(state)
        if state:
            self.console_view.setModel(self.sorted_console_model)
        else:
            self.console_view.setModel(self.console_model)

    def select_console_filter(self, fname):
        self.sorted_console_model.setFilterFixedString(fname)

    def closeEvent(self, e):
        self.settings.setValue("window_geometry", self.saveGeometry())
        self.settings.setValue("splitter_state",
                               self.main_splitter.saveState())
        self.settings.sync()
        e.accept()
예제 #22
0
class FileTreeView(QWidget):
    on_menu_select = pyqtSignal(str, str)
    on_dir_change = pyqtSignal()

    def __init__(self, parent: Application):
        super().__init__()
        self.stopped = threading.Event()
        self.tree = QTreeView()
        self.handle = self.Handler(self)
        self.get_data_file()
        self.model = QtGui.QStandardItemModel()
        self.item_construct = {}

        v_box = QVBoxLayout()
        v_box.addWidget(self.finder())
        v_box.addWidget(self.tree_view())
        self.setLayout(v_box)
        self.watch_dog()
        parent.app_close.connect(self.exit_push)

        self.tree.setAlternatingRowColors(True)

    def exit_push(self):
        self.stopped.set()

    def finder(self):
        w_find = QLineEdit()
        w_find.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))
        w_find.textChanged.connect(self.sort_list)
        w_find.setPlaceholderText("Search file..")

        return w_find

    def sort_list(self, text):
        list_sort = []
        if text == "":
            self.show_tree(self.list_file)
        else:
            for data in self.list_file:
                if text.lower() in data.name().lower():
                    list_sort.append(data)
            self.show_tree(list_sort)

    def watch_dog(self):
        watch = ProcessRunnable(target=watch_winform,
                                args=(get_data_folder(), self.handle,
                                      self.stopped))
        watch.start()

    class Handler(watchdog.events.PatternMatchingEventHandler):
        def __init__(self, parent):
            super().__init__()
            self.parent = parent

        def on_created(self, event):
            print("Watchdog received created event", event.src_path, sep=" : ")
            asyncio.run(
                self.parent.file_change('create', event.src_path,
                                        event.is_directory))

        def on_modified(self, event):
            print("Watchdog received modified event",
                  event.src_path,
                  sep=" : ")
            asyncio.run(
                self.parent.file_change('modify', event.src_path,
                                        event.is_directory))

        def on_moved(self, event):
            print("Watchdog received move event",
                  event.src_path,
                  event.dest_path,
                  sep=" : ")
            asyncio.run(
                self.parent.file_change('move', event.src_path,
                                        event.is_directory, event.dest_path))

        def on_deleted(self, event):
            print("Watchdog received delete event", event.src_path, sep=" : ")
            asyncio.run(
                self.parent.file_change('delete', event.src_path,
                                        event.is_directory))

    async def file_change(self, tpe, old, is_directory, new=""):
        if tpe == "move":
            self.import_single(self.model.invisibleRootItem(), new)
            self.remove_single(old)
        elif tpe == "delete":
            self.remove_single(old)
        elif tpe == "create":
            self.import_single(self.model.invisibleRootItem(), old)

        if is_directory:
            self.on_dir_change.emit()

    def get_data_file(self):
        self.list_file = []
        self.create_list(get_data_folder())

    def create_list(self, dir):
        lst = os.listdir(path=dir)
        for f in lst:
            path = os.path.join(dir, f)
            file = MyFile()
            if os.path.isdir(path):
                file.setParentName(os.path.basename(dir))
                file.setParent(dir)
                file.setName(f)
                file.setDir(True)
                self.list_file.append(file)
                self.create_list(path)
            else:
                file.setParentName(os.path.basename(dir))
                file.setParent(dir)
                file.setName(f)
                file.setDir(False)
                self.list_file.append(file)

    def tree_view(self):
        self.tree.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))

        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.open_menu)
        self.tree.doubleClicked.connect(self.open_event)
        # self.model.itemChanged.connect(self.data_change)
        self.tree.setModel(self.model)
        self.show_tree(self.list_file)
        return self.tree

    def show_tree(self, list_file):
        self.model.clear()
        self.model.setHorizontalHeaderLabels(['List API'])
        self.tree.header().setDefaultSectionSize(180)
        parent = self.model.invisibleRootItem()
        self.item_construct = {}
        self.import_data(parent, list_file)
        self.tree.expandAll()

    def import_data_by_path(self, parent, path: list, index):
        if index < len(path):
            full = os.sep.join(path[:index + 1])
            if full in self.item_construct:
                item = self.item_construct[full]
            else:
                item = QStandardItem(path[index])
                if os.path.isfile(os.path.join(get_data_folder(), full)):
                    item.setToolTip(
                        self.read_description(
                            os.path.join(get_data_folder(), full)))
                item.setEditable(False)
                if not os.path.isdir(os.path.join(get_data_folder(), full)):
                    item.setIcon(QIcon(get_icon_link("text_snippet.svg")))
                else:
                    item.setIcon(QIcon(get_icon_link("folder_yellow.svg")))

                item.setData(full)
                parent.appendRow(item)
                self.item_construct[full] = item

            self.import_data_by_path(item, path, index + 1)

    def read_description(self, path):
        try:
            data = json.loads(open(path, encoding='utf-8').read())
            json_data = APIData()
            json_data.construct(data)
            x = json_data.parseSave().description()
            if x.isspace() or x == "":
                return ".."
            else:
                return x
        except Exception as ex:
            print(ex)
            return ".."

    def import_data(self, parent, list_data):
        for i in list_data:
            self.import_single(parent, i)

    def import_single(self, parent, file_path):
        path = self.path_extract(file_path)
        self.import_data_by_path(parent, path, 0)

    def remove_single(self, file_path):
        path = self.path_extract(file_path)
        full = os.sep.join(path[:len(path)])
        if full in self.item_construct:
            item = self.item_construct[full]
            (item.parent()
             or self.model.invisibleRootItem()).removeRow(item.row())
            del self.item_construct[full]

    def path_extract(self, file_path):
        if isinstance(file_path, MyFile):
            path = os.path.join(file_path.parent(), file_path.name())
        else:
            path = file_path

        path = path.replace(get_data_folder(), "")
        if path.startswith(os.sep):
            path = path.replace(os.sep, "", 1)
        path = path.split(os.sep)
        return path

    def open_menu(self, position):
        indexes = self.tree.selectedIndexes()
        level = 0
        data = ""
        item = None
        if len(indexes) > 0:
            index = indexes[0]
            item = self.model.itemFromIndex(index)
            data = item.data()
            data = os.path.join(get_data_folder(), data)
            if os.path.isdir(data):
                level = 1
            else:
                level = 2

        menu = QMenu()
        menu.setStyleSheet(open(get_stylesheet()).read())

        rename_action = QAction(QIcon(get_icon_link('edit.svg')), '&Rename',
                                self)
        rename_action.setStatusTip('Rename')

        new_action = QAction(QIcon(get_icon_link('create_new_folder.svg')),
                             '&New Folder', self)
        new_action.setStatusTip('New Folder')

        refresh_action = QAction(QIcon(get_icon_link('refresh.svg')),
                                 '&Refresh', self)
        refresh_action.setStatusTip('Refresh')

        delete_action = QAction(QIcon(get_icon_link('delete_forever.svg')),
                                '&Delete', self)
        delete_action.setStatusTip('Delete')

        open_action = QAction(QIcon(get_icon_link('open_in_new.svg')), '&Open',
                              self)
        open_action.setStatusTip('Open file')

        expand_action = QAction(QIcon(), '&Expand', self)
        expand_action.setStatusTip('Expand')

        collapse_action = QAction(QIcon(), '&Collapse', self)
        collapse_action.setStatusTip('Collapse')

        duplicate_action = QAction(QIcon(get_icon_link('content_copy.svg')),
                                   '&Duplicate', self)
        duplicate_action.setStatusTip('Duplicate')

        copy_action = QAction(QIcon(get_icon_link('content_copy.svg')),
                              '&Copy', self)
        copy_action.setStatusTip('Copy')

        move_action = QAction(QIcon(get_icon_link('zoom_out_map.svg')),
                              '&Move', self)
        move_action.setStatusTip('Move')

        if level == 1:
            menu.addAction(rename_action)
            menu.addAction(new_action)
            menu.addSeparator()
            menu.addAction(refresh_action)
            menu.addAction(expand_action)
            menu.addAction(collapse_action)
            menu.addSeparator()
            menu.addAction(delete_action)
        elif level == 2:
            menu.addAction(open_action)
            menu.addAction(new_action)
            menu.addAction(refresh_action)
            menu.addSeparator()
            menu.addAction(rename_action)
            menu.addAction(duplicate_action)
            menu.addAction(copy_action)
            menu.addAction(move_action)
            menu.addSeparator()
            menu.addAction(delete_action)
        else:
            menu.addAction(new_action)
            menu.addAction(refresh_action)

        action = menu.exec_(self.tree.viewport().mapToGlobal(position))

        if action == open_action:
            if data != "":
                self.on_menu_select.emit("open", data)
        elif action == refresh_action:
            self.get_data_file()
            self.show_tree(self.list_file)
        elif action == expand_action:
            if item is not None:
                self.tree.expand(item.index())
        elif action == collapse_action:
            if item is not None:
                self.tree.collapse(item.index())
        elif action == delete_action:
            if data != "":
                msg = QMessageBox()
                msg.setStyleSheet(open(get_stylesheet()).read())
                msg.setIcon(QMessageBox.Warning)
                msg.setBaseSize(QSize(500, 300))
                msg.setText("Delete file.")
                msg.setInformativeText("Are you sure to detele " +
                                       os.path.basename(data) + "?")
                msg.setWindowTitle("Delete Warning!!!")
                msg.addButton('Delete', QMessageBox.YesRole)
                msg.addButton('Move to Trash', QMessageBox.YesRole)
                msg.addButton('Cancel', QMessageBox.NoRole)

                rs = msg.exec_()
                if rs == 0:
                    if os.path.isdir(data):
                        shutil.rmtree(data)
                    else:
                        os.remove(data)
                elif rs == 1:
                    send2trash(data)
        elif action == new_action:
            if data == "":
                data = get_data_folder()
            # input_name = QInputDialog()
            # input_name.setStyleSheet(open(get_stylesheet()).read())
            # text, ok = input_name.getText(self, 'New Folder', 'Folder name:')
            inp = QComboDialog('New Folder', 'Folder name:', QComboDialog.Text)
            ok = inp.exec_()
            if ok and inp.select:
                if os.path.isdir(data):
                    try:
                        os.mkdir(os.path.join(data, inp.select))
                    except Exception as ex:
                        alert = Alert("Error", "Create folder error", str(ex))
                        alert.exec_()
                        print(ex)
                else:
                    new = os.path.join(os.path.dirname(data), inp.select)
                    try:
                        os.mkdir(new)
                    except Exception as ex:
                        alert = Alert("Error", "Create folder error", str(ex))
                        alert.exec_()
                        print(ex)
        elif action == rename_action:
            if data != "":
                # input_name = QInputDialog()
                # input_name.setStyleSheet(open(get_stylesheet()).read())
                # text, ok = input_name.getText(self, 'Rename file', 'New name:')
                inp = QComboDialog('Rename file', 'New name:',
                                   QComboDialog.Text)
                ok = inp.exec_()
                if ok and inp.select:
                    if os.path.isdir(data):
                        new = os.path.join(os.path.dirname(data), inp.select)
                        try:
                            os.rename(data, new)
                        except Exception as ex:
                            alert = Alert("Error", "Rename folder error",
                                          str(ex))
                            alert.exec_()
                            print(ex)
                    else:
                        filename, file_extension = os.path.splitext(data)
                        new = os.path.join(os.path.dirname(data),
                                           inp.select + file_extension)
                        try:
                            os.rename(data, new)
                        except Exception as ex:
                            alert = Alert("Error", "Rename file error",
                                          str(ex))
                            alert.exec_()
                            print(ex)
        elif action == move_action:
            if data != "":
                items = get_list_folder(get_data_folder(), get_data_folder())
                #
                # item, ok = QInputDialog.getItem(self, "Select folder dialog",
                #                                 "Select the destination folder", items, 0, False)

                inp = QComboDialog("Move", "Select the destination folder",
                                   QComboDialog.ComboBox, items)
                ok = inp.exec_()

                if ok and inp.select:
                    folder = inp.select
                    if inp.select.startswith(os.sep):
                        folder = inp.select.replace(os.sep, "", 1)
                    new = os.path.join(get_data_folder(), folder,
                                       os.path.basename(data))
                    try:
                        os.rename(data, new)
                    except Exception as ex:
                        alert = Alert("Error", "Move file error", str(ex))
                        alert.exec_()
                        print(ex)
        elif action == duplicate_action:
            if data != "":
                # input_name = QInputDialog()
                # input_name.setStyleSheet(open(get_stylesheet()).read())
                # text, ok = input_name.getText(self, 'Duplicate file', 'New name:')
                inp = QComboDialog('Duplicate file', 'New name:',
                                   QComboDialog.Text)
                filename, file_extension = os.path.splitext(data)
                inp.set_init_text(filename)
                ok = inp.exec_()
                if ok and inp.select:
                    new = os.path.join(os.path.dirname(data),
                                       inp.select + file_extension)
                    try:
                        copyfile(data, new)
                    except Exception as ex:
                        alert = Alert("Error", "Duplicate file error", str(ex))
                        alert.exec_()
                        print(ex)
        elif action == copy_action:
            if data != "":
                items = get_list_folder(get_data_folder(), get_data_folder())
                inp = QComboDialog("Copy", "Select the destination folder",
                                   QComboDialog.ComboBox, items)
                ok = inp.exec_()
                # item, ok = QInputDialog.getItem(self, "Select folder dialog",
                #                                 "Select the destination folder", items, 0, False)

                if ok and inp.select:
                    folder = inp.select
                    if inp.select.startswith(os.sep):
                        folder = inp.select.replace(os.sep, "", 1)
                    new = os.path.join(get_data_folder(), folder,
                                       os.path.basename(data))
                    try:
                        copyfile(data, new)
                    except Exception as ex:
                        alert = Alert("Error", "Copy file error", str(ex))
                        alert.exec_()
                        print(ex)

    def open_event(self, index):
        item = self.model.itemFromIndex(index)
        if item is not None:
            data = item.data()
            data = os.path.join(get_data_folder(), data)
            if os.path.isdir(data):
                level = 1
            else:
                level = 2
            if data != "":
                if level == 2:
                    self.on_menu_select.emit("open", data)
                elif level == 1:
                    if not self.tree.isExpanded(item.index()):
                        self.tree.collapse(item.index())
                    else:
                        self.tree.expand(item.index())
예제 #23
0
class TestDialog(QDialog):
    def __init__(self, data):

        super(TestDialog, self).__init__()

        self.data = copy.deepcopy(data)

        # Layout
        btOk = QPushButton("OK")
        btCancel = QPushButton("Cancel")
        self.tree = QTreeView()
        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(btOk)
        hbox.addWidget(btCancel)
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.tree)
        self.setLayout(vbox)
        self.setGeometry(300, 300, 600, 400)

        # Button signals
        btCancel.clicked.connect(self.reject)
        btOk.clicked.connect(self.accept)

        # Tree view
        self.tree.setModel(QStandardItemModel())
        self.tree.setAlternatingRowColors(True)
        self.tree.setSortingEnabled(True)
        self.tree.setHeaderHidden(False)
        self.tree.setSelectionBehavior(QAbstractItemView.SelectItems)

        self.tree.model().setHorizontalHeaderLabels(['Parameter', 'Value'])

        for x in self.data:
            if not self.data[x]:
                continue
            parent = QStandardItem(x)
            parent.setFlags(QtCore.Qt.NoItemFlags)
            for y in self.data[x]:
                value = self.data[x][y]
                child0 = QStandardItem(y)
                child0.setFlags(QtCore.Qt.NoItemFlags
                                | QtCore.Qt.ItemIsEnabled)
                child1 = QStandardItem(repr(value))
                child1.setFlags(QtCore.Qt.ItemIsEnabled
                                | QtCore.Qt.ItemIsEditable
                                | ~QtCore.Qt.ItemIsSelectable)
                parent.appendRow([child0, child1])
            self.tree.model().appendRow(parent)

        self.tree.expandAll()
        self.tree.model().itemChanged.connect(self.handleItemChanged)

    def get_data(self):
        return self.data

    def handleItemChanged(self, item):
        parent = self.data[item.parent().text()]
        key = item.parent().child(item.row(), 0).text()
        parent[key] = eval(item.text())
예제 #24
0
class AddBookmarkDialog(QDialog, Ui_AddBookmarkDialog):
    """
    Class implementing a dialog to add a bookmark or a bookmark folder.
    """
    def __init__(self, parent=None, bookmarksManager=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        @param bookmarksManager reference to the bookmarks manager
            object (BookmarksManager)
        """
        super(AddBookmarkDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.__bookmarksManager = bookmarksManager
        self.__addedNode = None
        self.__addFolder = False
        
        if self.__bookmarksManager is None:
            import Helpviewer.HelpWindow
            self.__bookmarksManager = \
                Helpviewer.HelpWindow.HelpWindow.bookmarksManager()
        
        self.__proxyModel = AddBookmarkProxyModel(self)
        model = self.__bookmarksManager.bookmarksModel()
        self.__proxyModel.setSourceModel(model)
        
        self.__treeView = QTreeView(self)
        self.__treeView.setModel(self.__proxyModel)
        self.__treeView.expandAll()
        self.__treeView.header().setStretchLastSection(True)
        self.__treeView.header().hide()
        self.__treeView.setItemsExpandable(False)
        self.__treeView.setRootIsDecorated(False)
        self.__treeView.setIndentation(10)
        self.__treeView.show()
        
        self.locationCombo.setModel(self.__proxyModel)
        self.locationCombo.setView(self.__treeView)
        
        self.addressEdit.setInactiveText(self.tr("Url"))
        self.nameEdit.setInactiveText(self.tr("Title"))
        
        self.resize(self.sizeHint())
    
    def setUrl(self, url):
        """
        Public slot to set the URL of the new bookmark.
        
        @param url URL of the bookmark (string)
        """
        self.addressEdit.setText(url)
        self.resize(self.sizeHint())
    
    def url(self):
        """
        Public method to get the URL of the bookmark.
        
        @return URL of the bookmark (string)
        """
        return self.addressEdit.text()
    
    def setTitle(self, title):
        """
        Public method to set the title of the new bookmark.
        
        @param title title of the bookmark (string)
        """
        self.nameEdit.setText(title)
    
    def title(self):
        """
        Public method to get the title of the bookmark.
        
        @return title of the bookmark (string)
        """
        return self.nameEdit.text()
    
    def setDescription(self, description):
        """
        Public method to set the description of the new bookmark.
        
        @param description description of the bookamrk (string)
        """
        self.descriptionEdit.setPlainText(description)
    
    def description(self):
        """
        Public method to get the description of the bookmark.
        
        @return description of the bookamrk (string)
        """
        return self.descriptionEdit.toPlainText()
    
    def setCurrentIndex(self, idx):
        """
        Public method to set the current index.
        
        @param idx current index to be set (QModelIndex)
        """
        proxyIndex = self.__proxyModel.mapFromSource(idx)
        self.__treeView.setCurrentIndex(proxyIndex)
        self.locationCombo.setCurrentIndex(proxyIndex.row())
    
    def currentIndex(self):
        """
        Public method to get the current index.
        
        @return current index (QModelIndex)
        """
        idx = self.locationCombo.view().currentIndex()
        idx = self.__proxyModel.mapToSource(idx)
        return idx
    
    def setFolder(self, folder):
        """
        Public method to set the dialog to "Add Folder" mode.
        
        @param folder flag indicating "Add Folder" mode (boolean)
        """
        self.__addFolder = folder
        
        if folder:
            self.setWindowTitle(self.tr("Add Folder"))
            self.addressEdit.setVisible(False)
        else:
            self.setWindowTitle(self.tr("Add Bookmark"))
            self.addressEdit.setVisible(True)
        
        self.resize(self.sizeHint())
    
    def isFolder(self):
        """
        Public method to test, if the dialog is in "Add Folder" mode.
        
        @return flag indicating "Add Folder" mode (boolean)
        """
        return self.__addFolder
    
    def addedNode(self):
        """
        Public method to get a reference to the added bookmark node.
        
        @return reference to the added bookmark node (BookmarkNode)
        """
        return self.__addedNode
    
    def accept(self):
        """
        Public slot handling the acceptance of the dialog.
        """
        if (not self.__addFolder and not self.addressEdit.text()) or \
           not self.nameEdit.text():
            super(AddBookmarkDialog, self).accept()
            return
        
        from .BookmarkNode import BookmarkNode
        
        idx = self.currentIndex()
        if not idx.isValid():
            idx = self.__bookmarksManager.bookmarksModel().index(0, 0)
        parent = self.__bookmarksManager.bookmarksModel().node(idx)
        
        if self.__addFolder:
            type_ = BookmarkNode.Folder
        else:
            type_ = BookmarkNode.Bookmark
        bookmark = BookmarkNode(type_)
        bookmark.title = self.nameEdit.text()
        if not self.__addFolder:
            bookmark.url = self.addressEdit.text()
        bookmark.desc = self.descriptionEdit.toPlainText()
        
        self.__bookmarksManager.addBookmark(parent, bookmark)
        self.__addedNode = bookmark
        
        super(AddBookmarkDialog, self).accept()
예제 #25
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle('World Country Diagram')
        self.resize(500, 700)

        treeView = QTreeView()
        treeView.setHeaderHidden(False)
        treeModel = QStandardItemModel()
        self.most_used_cat_header = [
            'Nom', "Prénom", "Sexe", "Date Inscription", "Courriel Client",
            "Mot de passe", "Numéro de carte", "Expiration", "Code"
        ]
        treeModel.setHorizontalHeaderLabels(self.most_used_cat_header)
        rootNode = treeModel.invisibleRootItem()

        # America
        america = QStandardItem('America')

        california = QStandardItem('California')
        america.appendRow(california)

        oakland = QStandardItem('Oakland')
        sanfrancisco = QStandardItem('San Francisco')
        sanjose = QStandardItem('San Jose')

        california.appendRow(oakland)
        california.appendRow(sanfrancisco)
        california.appendRow(sanjose)

        texas = QStandardItem('Texas')
        america.appendRow(texas)

        austin = QStandardItem('Austin')
        houston = QStandardItem('Houston')
        dallas = QStandardItem('dallas')
        testo = QStandardItem("testo")
        testo2 = QStandardItem("testo2")
        testo3 = QStandardItem("testo3")
        vide1 = QStandardItem("")
        vide2 = QStandardItem("")
        vide3 = QStandardItem("")
        item = (austin, houston, dallas)
        america.appendRow(item)
        item2 = (vide1, vide2, vide3, testo, testo2, testo3)
        #texas.appendRow(austin)
        #texas.appendRow(houston)
        #texas.appendRow(dallas)

        austin.appendRow(item2)

        # Canada
        canada = QStandardItem('Canada')

        alberta = QStandardItem('Alberta')
        bc = QStandardItem('British Columbia')
        ontario = QStandardItem('Ontario')
        canada.appendRows([alberta, bc, ontario])

        rootNode.appendRow(america)
        rootNode.appendRow(canada)

        treeView.setModel(treeModel)
        treeView.expandAll()
        treeView.doubleClicked.connect(self.getValue)

        self.setCentralWidget(treeView)
예제 #26
0
class KerningWindow(QWidget):

    def __init__(self, font, parent=None):
        super().__init__(parent, Qt.Window)
        self._font = font
        self._font.kerning.addObserver(
            self, "_kerningChanged", "Kerning.Changed")
        self._font.info.addObserver(self, "_fontInfoChanged", "Info.Changed")
        self.kerningView = QTreeView(self)
        self.kerningView.setModel(
            KerningDictModel(font.kerning, self.kerningView))
        self.kerningView.expandAll()
        metrics = self.kerningView.fontMetrics()
        self.kerningView.setColumnWidth(1, 8 * metrics.width("0"))
        hdr = self.kerningView.header()
        hdr.setStretchLastSection(False)
        hdr.setSectionResizeMode(0, hdr.Stretch)
        hdr.hide()

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

        self.updateWindowTitle(font=font)
        self.readSettings()

    def readSettings(self):
        geometry = settings.kerningWindowGeometry()
        if geometry:
            self.restoreGeometry(geometry)

    def writeSettings(self):
        settings.setKerningWindowGeometry(self.saveGeometry())

    def updateWindowTitle(self, title=None, font=None):
        if title is None:
            title = self.tr("Kerning")
        if font is not None:
            title = "%s – %s %s" % (
                title, font.info.familyName, font.info.styleName)
        self.setWindowTitle(title)

    # -------------
    # Notifications
    # -------------

    def _kerningChanged(self, notification):
        model = self.kerningView.model()
        model.setupModelData(self._font.kerning)

    def _fontInfoChanged(self, notification):
        self.updateWindowTitle(font=self._font)

    # ----------
    # Qt methods
    # ----------

    def sizeHint(self):
        return QSize(280, 460)

    def moveEvent(self, event):
        self.writeSettings()

    resizeEvent = moveEvent

    def closeEvent(self, event):
        super().closeEvent(event)
        if event.isAccepted():
            self._font.kerning.removeObserver(self, "Kerning.Changed")
            self._font.info.removeObserver(self, "Info.Changed")
    ###

    model = QStandardItemModel(None)

    row1 = [QStandardItem("a"), QStandardItem("b")]
    row2 = [QStandardItem("c"), QStandardItem("d")]
    row3 = [QStandardItem("e"), QStandardItem("f")]
    row4 = [QStandardItem("g"), QStandardItem("h")]
    row5 = [QStandardItem("i"), QStandardItem("j")]

    root_item = model.invisibleRootItem()
    root_item.appendRow(row1)
    row1[0].appendRow(row2)
    row1[0].appendRow(row3)
    #row1[1].appendRow(row4)   # ignored
    root_item.appendRow(row5)

    ###

    tree_view.setModel(model)
    tree_view.expandAll()  # expand all (this is not the case by default)
    tree_view.show()

    # The mainloop of the application. The event handling starts from this point.
    # The exec_() method has an underscore. It is because the exec is a Python keyword. And thus, exec_() was used instead.
    exit_code = app.exec_()

    # The sys.exit() method ensures a clean exit.
    # The environment will be informed, how the application ended.
    sys.exit(exit_code)
예제 #28
0
class EditScreen(QWidget):
    def __init__(self, rester: Rester):
        super(EditScreen, self).__init__()
        self.last_item_type = ''

        self.rester = rester
        self.tree = QTreeView()
        layout = QVBoxLayout()
        layout.addWidget(self.tree)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Name'])
        self.tree.header().setDefaultSectionSize(200)
        self.tree.setModel(self.model)
        self.data = self.rester.list_request(list(APIEnum))
        self.import_data(self.data)
        self.tree.setSortingEnabled(False)
        self.tree.expandAll()
        self.tree.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tree.selectionModel().selectionChanged.connect(self.item_selected)

        self.init_ui()

    def init_ui(self):
        hbox = QHBoxLayout()

        vbox = QVBoxLayout()
        left_layout = QFormLayout()
        tree_group_box = QGroupBox()
        self.search_field = QLineEdit()
        # self.search_field.editingFinished.connect(self.search_field_changed)
        self.search_field.textEdited.connect(self.search_field_changed)
        left_layout.addRow(QLabel('Search:'), self.search_field)
        tree_group_box.setLayout(left_layout)

        vbox.addWidget(tree_group_box)
        vbox.addWidget(self.tree)

        gb = QGroupBox()
        gb.setLayout(vbox)

        self.splitter = QSplitter()
        self.splitter.addWidget(gb)

        self.ew = EquipmentEdit()
        self.splitter.addWidget(self.ew)

        hbox.addWidget(self.splitter)

        self.setLayout(hbox)

    def import_data(self, data, root=None):

        self.model.setRowCount(0)
        if root is None:
            root = self.model.invisibleRootItem()
        for key, value_list in data.items():
            parent = TreeItem({'name': key}, '', parent=True)
            parent.setEditable(False)
            root.appendRow([parent])
            for value in value_list:
                parent.appendRow([TreeItem(value, key)])

    def search_field_changed(self):
        term = self.search_field.text()
        data = {}
        for key, value_list in self.data.items():
            li = []
            for value in value_list:
                for k in value.keys():
                    if term in k:
                        li.append(value)
            data[key] = li

        self.import_data(data)

    def item_selected(self):
        indexes = self.tree.selectedIndexes()
        selected = indexes[0]

        item = self.model.itemFromIndex(selected)

        if item.is_parent:
            return

        #if item.typ != self.last_item_type:
        self.ew.hide()
        self.ew.destroy()
        self.ew = get_edit_widget(item.typ, self.data)
        self.splitter.addWidget(self.ew)

        self.last_item_type = item.typ

        data_dict = item.get_data_dict()
        self.ew.load_data(data_dict)
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
예제 #30
0
class ShellTableEditor(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.model = None
        self.shell_model = ShellTableTreeModel()
        self.tree_view = QTreeView(self)
        self.tree_view.setModel(self.shell_model)
        layout = QVBoxLayout()
        self.setLayout(layout)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.init_navigation(), 0)
        layout.addWidget(self.tree_view, 1)
        layout.addWidget(self.init_docs(), 0)

    def get_icon(self, name):
        return self.style().standardIcon(name)

    def init_navigation(self):
        self.prev_button = QPushButton(self.get_icon(QStyle.SP_ArrowLeft), "")
        self.prev_button.setFlat(True)
        self.next_button = QPushButton(self.get_icon(QStyle.SP_ArrowRight), "")
        self.next_button.setFlat(True)
        self.prev_button.clicked.connect(self.handle_prev_button_clicked)
        self.next_button.clicked.connect(self.handle_next_button_clicked)
        self.current_index = QSpinBox()
        self.current_index.setMinimumWidth(60)
        self.current_index.valueChanged.connect(self.handle_current_index_changed)
        box = QWidget(self)
        box_layout = QHBoxLayout(box)
        box_layout.setContentsMargins(0, 0, 0, 0)
        box.setLayout(box_layout)
        box_layout.addWidget(self.prev_button, 0)
        box_layout.addWidget(self.next_button, 0)
        box_layout.addWidget(QLabel("Index:"), 0)
        box_layout.addWidget(self.current_index, 0)
        box_layout.addStretch(1)
        return box

    def init_docs(self):
        box = QWidget(self)
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        box.setLayout(layout)
        layout.addWidget(QLabel(DOC_CAPACITY), 0, Qt.AlignTop)
        layout.addWidget(QLabel(DOC_RECOIL), 0, Qt.AlignTop)
        layout.addWidget(QLabel(DOC_RELOAD), 1, Qt.AlignTop)
        return box

    def handle_current_index_changed(self, value):
        parent_index = QModelIndex()
        qindex = self.shell_model.index(self.current_index.value(), 0, parent_index)
        self.tree_view.setRootIndex(qindex)
        self.tree_view.expandAll()

    def handle_prev_button_clicked(self):
        self.current_index.setValue(self.current_index.value() - 1)

    def handle_next_button_clicked(self):
        self.current_index.setValue(self.current_index.value() + 1)

    def set_model(self, model):
        self.model = model
        if model is None:
            self.shell_model.update([])
            self.current_index.setMaximum(0)
        else:
            self.shell_model.update(self.model.data.entries)
            self.current_index.setMaximum(len(self.model.data.entries) - 1)
            self.handle_current_index_changed(0)
            self.tree_view.header().resizeSection(0, 120)
예제 #31
0
class Example(QWidget):
    def __init__(self):
        super().__init__()

        # make a text window for terminal output
        self.txt = QTextEdit()
        self.txt.setReadOnly(True)

        # do something with a push button
        self.btn = QPushButton('scan')
        self.btn.clicked.connect(self.run_scan)

        # A sort of Gadget widget - here using pyqt's model/view concept
        self.model = GadgetModel()
        self.tree = QTreeView()
        self.tree.setModel(self.model)
        self.tree.expandAll()
        self.monitor = GadgetMonitor()
        self.monitor.update.connect(self.model.motor_update)
        self.monitor.start()

        # A progress bar for scans
        self.progress = QProgressBar()
        self.progress.setMinimum(0)
        self._last_dt = 0

        self.plot = pg.PlotWidget(parent=self, background='white')

        # layout containing these things
        hbox = QHBoxLayout()
        col1 = QVBoxLayout()
        col2 = QVBoxLayout()
        col1.addWidget(self.tree)
        col1.addWidget(self.txt)
        col1.addWidget(self.btn)
        col1.addWidget(self.progress)
        col2.addWidget(self.plot)
        hbox.addLayout(col1)
        hbox.addLayout(col2)
        self.setLayout(hbox)
        self.resize(1200, 700)

        # redirect stdout
        queue = Queue()
        sys.stdout = StreamWriter(queue)
        self.reader = StreamReader(queue)
        self.reader.signal.connect(self.new_stdout)
        self.reader.start()

        # a special recorder which generates qt signals
        queue = MP_Queue()
        self.qtrec = PyQtRecorder(queue, name='qtrec')
        self.qtrec.start()
        self.emitter = RecorderEmitter(queue)
        self.emitter.new.connect(self.new_data)
        self.emitter.start()

        # a scan runner object we can refer to,
        self.runner = None

        # quote
        contrast.wisdom()

    @pyqtSlot(dict)
    def new_data(self, dct):
        self.txt.setTextColor(QColor('black'))  # for example
        if 'status' in dct.keys():
            # header/footer
            if dct['status'] == 'started':
                self.progress.setValue(0)
        else:
            # update progress bar
            m = self.progress.maximum()
            n = self.progress.value() + 1
            eta = str(
                datetime.timedelta(
                    seconds=((m - n) *
                             (dct['dt'] - self._last_dt)))).split('.')[0]
            self.progress.setValue(n)
            self.progress.setFormat('%u/%u (done in %s)' % (n, m, eta))
            self._last_dt = dct['dt']
            # plot something
            self.plot.plot([dct['sx']], [dct['det1']], symbol='o', color='k')

    @pyqtSlot(str)
    def new_stdout(self, msg):
        """
        Intercepts the stdout signal and adds it to a text box or so.
        """
        if len(msg) < 2:
            # exclude empty strings
            return
        if '\r' in msg:
            # exclude overwritten text
            return
        self.print(msg, 'gray')

    def print(self, msg, color='black'):
        self.txt.setTextColor(QColor(color))
        self.txt.append(str(msg))

    def run_scan(self):
        """
        Helper method which puts together the scan to run, and launches
        a ScanRunner object.
        """
        if self.runner and self.runner.isRunning():
            return
        N = np.random.randint(5, 40)
        self.progress.setMaximum(N + 1)
        self.runner = ScanRunner(AScan, *[bl.sx, 0, 1, N, .1])
        self.runner.start()
예제 #32
0
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.setMinimumSize(QSize(480, 80))
        self.setWindowTitle("PyQtSample")
        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        hbox_layout = QHBoxLayout(self)
        central_widget.setLayout(hbox_layout)

        buttons_background = QWidget(self)
        buttons_layout = QHBoxLayout()
        buttons_background.setLayout(buttons_layout)

        self.add_button = QPushButton("Add")
        buttons_layout.addWidget(self.add_button)

        self.remove_button = QPushButton("Remove")
        buttons_layout.addWidget(self.remove_button)

        tree_layout = QVBoxLayout(self)
        self.tree_view = QTreeView()
        self.tree_view.header().hide()
        self.tree_view.setMaximumWidth(300)
        self.tree_model = ObjectsModel.TreeModel()
        self.tree_view.setModel(self.tree_model)
        tree_layout.addWidget(buttons_background)
        tree_layout.addWidget(self.tree_view)

        hbox_layout.addLayout(tree_layout)

        self.graphics_view = QGraphicsView()
        self.scene = QGraphicsScene()
        self.graphics_view.setScene(self.scene)
        hbox_layout.addWidget(self.graphics_view)

        self.properties_view = QTableView()
        self.properties_view.setMaximumWidth(300)
        self.properties_model = PropertiesModel.TableModel()
        self.properties_view.setModel(self.properties_model)
        hbox_layout.addWidget(self.properties_view)

        self.init_menu()
        self.test()
        self.connectSignals()

    def connectSignals(self):
        self.add_button.clicked.connect(self.onAddClicked)
        self.remove_button.clicked.connect(self.onRemoveClicked)
        self.tree_view.clicked.connect(self.onClicked)
        self.properties_model.dataChanged.connect(self.onPropertyChanged)

    def onPropertyChanged(self):
        self.rebuildModel()

    def rebuildModel(self):
        #save index hierarhy
        indexes = []
        tmp_index = self.tree_view.currentIndex()
        indexes.append(tmp_index)
        while tmp_index.parent().isValid():
            indexes.append(tmp_index.parent())
            tmp_index = tmp_index.parent()

        self.tree_model.initRoot(self.items)
        self.tree_view.expandAll()

        if len(indexes) == 0:
            self.onClicked(self.tree_model.index(0, 0))
        else:
            last_index = indexes.pop(-1)
            index = self.tree_model.index(last_index.row(),
                                          last_index.column())
            #restore index hierarchy
            while len(indexes) > 0:
                last_index = indexes.pop(-1)
                index = self.tree_model.index(last_index.row(),
                                              last_index.column(), index)

            if index.isValid():
                self.onClicked(index)
            else:
                self.onClicked(self.tree_model.index(0, 0))

    def init_menu(self):
        exit_action = QAction("&Exit", self)
        exit_action.setShortcut('Ctrl+Q')
        exit_action.triggered.connect(qApp.quit)
        file_menu = self.menuBar().addMenu("&File")
        file_menu.addAction(QAction("Open", self))
        file_menu.addAction(QAction("Save", self))
        file_menu.addAction(QAction("SaveAs", self))
        file_menu.addSeparator()
        file_menu.addAction(exit_action)

    def appendObjectOnScene(self, object=DataStructures.Object):
        if object.rect.isValid():
            self.scene.addRect(object.rect, object.color)
        for child in object.childrens:
            self.appendObjectOnScene(child)

    def onClicked(self, index):
        object = index.data(Qt.UserRole + 1)

        self.properties_model.initProperties(object)

        self.scene.clear()
        self.appendObjectOnScene(object)
        self.tree_view.setCurrentIndex(index)

    def onAddClicked(self):
        index = self.tree_view.currentIndex()
        print(index)
        object = index.data(Qt.UserRole + 1)
        print(object.description())
        object.add_children(DataStructures.Object("New item"))
        self.rebuildModel()

    def onRemoveClicked(self):
        index = self.tree_view.currentIndex()
        object = index.data(Qt.UserRole + 1)
        if not object.parent:
            self.items.remove(object)
        else:
            object.parent.childrens.remove(object)

        self.rebuildModel()

    def test(self):
        self.items = []
        static = DataStructures.Object(
            "Static", DataStructures.createRect(0, 0, 800, 200))
        static.add_children(DataStructures.Object("child_1"))
        static.add_children(DataStructures.Object("child_2"))
        static.add_children(DataStructures.Object("child_3"))
        static.color = QColor(200, 0, 0).name()
        static.childrens[0].add_children(
            DataStructures.Object("child_1.1",
                                  DataStructures.createRect(40, 40, 80, 40)))

        self.items.append(static)

        dynamic = DataStructures.Object(
            "Dynamic", DataStructures.createRect(0, 0, 200, 800))
        dynamic.add_children(DataStructures.Object("child_1"))
        dynamic.add_children(DataStructures.Object("child_2"))
        dynamic.add_children(DataStructures.Object("child_3"))
        dynamic.childrens[2].add_children(DataStructures.Object("child_2.1"))
        dynamic.color = QColor(0, 0, 200).name()
        self.items.append(dynamic)

        self.rebuildModel()
예제 #33
0
class ImageViewer(QWidget):
    def __init__(self):

        super(ImageViewer, self).__init__()

        pal = QPalette()
        pal.setColor(QPalette.Background, Qt.lightGray)

        self.factor = 3.0

        self.config = Config()
        self.currentRep = ""

        self.createActions()
        self.createToolbarMenus()
        #self.createMenus()

        self.browserFile()
        self.imgqLabel()
        self.boxSliders()

        self.verticalLayout = QVBoxLayout(self)
        self.horizontalLayout = QHBoxLayout(self)

        self.textInfo = QTextEdit()

        self.textInfoTop = QTextEdit()
        self.textInfoTop.setEnabled(True)
        self.textInfoTop.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Ignored)
        self.textInfoTop.setFontPointSize(11)
        self.textInfoTop.setStyleSheet("background-color: lightgray")
        #self.textInfoTop.adjustSize()
        self.textInfoTop.setText('Welcome to IRMaGe')

        self.tableJson = QTableWidget()
        self.tableJson.setColumnCount(2)
        self.tableJson.setColumnWidth(0, 150)
        self.tableJson.setColumnWidth(1, 400)
        self.tableJson.setSizeAdjustPolicy(
            QAbstractScrollArea.AdjustToContents)

        self.tableJson.setHorizontalHeaderLabels(['Keys', 'Values'])
        #self.tableJson.setBackgroundRole(QPalette.Light)

        self.scrollText = QScrollArea()
        self.scrollText.setBackgroundRole(QPalette.Dark)
        self.scrollText.setWidget(self.textInfoTop)
        self.scrollText.setWidgetResizable(True)
        #=======================================================================
        # self.adjustScrollBar(self.scrollText.horizontalScrollBar(), 1.0)
        # self.adjustScrollBar(self.scrollText.verticalScrollBar(), 2.0)
        #=======================================================================
        self.scrollTable = QScrollArea()
        self.scrollTable.setBackgroundRole(QPalette.Dark)
        self.scrollTable.setWidget(self.tableJson)
        self.scrollTable.setWidgetResizable(True)
        #=======================================================================
        # self.adjustScrollBar(self.scrollTable.horizontalScrollBar(), 2.0)
        # self.adjustScrollBar(self.scrollTable.verticalScrollBar(), 2.0)
        #=======================================================================

        self.headerTabData = [
            'Data', 'PatientName', 'StudyName', 'DateCreation', 'PatientSex',
            'PatientWeight', 'ProtocolName', 'SequenceName'
        ]

        self.tableData = TableDataBrower(self)
        self.tableData.setColumnCount(8)
        self.tableData.setRowCount(10)
        self.tableData.setColumnWidth(0, 200)
        self.tableData.setHorizontalHeaderLabels(self.headerTabData)
        self.tableData.setBackgroundRole(QPalette.Light)
        self.tableData.setSizeAdjustPolicy(
            QAbstractScrollArea.AdjustToContents)
        self.tableData.verticalHeader().hide()

        self.scrollBrowser = QScrollArea()
        self.scrollBrowser.setBackgroundRole(QPalette.Dark)
        self.scrollBrowser.setWidget(self.tableData)
        self.scrollBrowser.setWidgetResizable(True)

        self.splitter0 = QSplitter(Qt.Vertical)
        self.splitter0.addWidget(self.scrollText)
        self.splitter0.addWidget(self.scrollTable)

        self.scrollArea = QScrollArea()
        self.scrollArea.setBackgroundRole(QPalette.Dark)
        self.scrollArea.setWidget(self.imageLabel)
        self.scrollArea.setWidgetResizable(False)
        self.scrollArea.setAlignment(Qt.AlignCenter)

        self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), 0.8)
        self.adjustScrollBar(self.scrollArea.verticalScrollBar(), 1.0)

        self.splitter1 = QSplitter(Qt.Horizontal)
        self.splitter1.addWidget(self.splitter0)
        self.splitter1.addWidget(self.scrollArea)
        self.splitter1.addWidget(self.layoutSlide)

        self.splitter3 = QSplitter(Qt.Horizontal)
        self.splitter3.addWidget(self.browser)
        self.splitter3.addWidget(self.scrollBrowser)

        self.splitter2 = QSplitter(Qt.Vertical)
        self.splitter2.addWidget(self.splitter1)
        self.splitter2.addWidget(self.splitter3)
        self.splitter2.setHandleWidth(15)
        #=======================================================================
        # self.splitter2.
        #=======================================================================

        self.verticalLayout.addWidget(self.menuToolBar)
        self.verticalLayout.addWidget(self.splitter2)

        self.setWindowTitle("MRImage Viewer (IRMaGe)")
        self.resize(800, 600)

        self.setAutoFillBackground(True)
        self.setPalette(pal)

    def changeSel(self):
        print('Tab changed')

    def adjustScrollBar(self, scrollBar, factor):
        scrollBar.setValue(
            int(factor * scrollBar.value() +
                ((factor - 1) * scrollBar.pageStep() / 2)))

    def imgqLabel(self):
        QLabel.__init__(self)
        image = QImage('sources_images/LogoIRMaGe.png')
        self.scaleFactor = 1.0
        self.imageLabel = QLabel()
        self.imageLabel.setBackgroundRole(QPalette.Base)
        self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.imageLabel.setScaledContents(True)
        self.imageLabel.setPixmap(QPixmap.fromImage(image))
        self.scaleFactor *= self.factor
        self.imageLabel.adjustSize()
        self.imageLabel.resize(self.scaleFactor *
                               self.imageLabel.pixmap().size())

    def open(self, filePath):
        self.img = nib.load(filePath)
        self.textInfoTop.setText('File : ' + filePath + '\n')
        self.textInfoTop.append('Dim : ' + str(self.img.shape) + '\n')
        self.enableSliders()
        self.a1.setValue(0)
        self.a2.setValue(0)
        self.a3.setValue(0)
        self.c2.setMaximum(self.img.shape[0])
        self.c2.setMinimum(-self.img.shape[0])
        self.c3.setMaximum(self.img.shape[1])
        self.c3.setMinimum(-self.img.shape[1])
        self.navigImage()
        self.fitToWindowAct.setEnabled(True)
        self.fitToWindow()

    def openJson(self, pathJson, fileName):
        with open(pathJson, 'r') as stream:
            try:
                json_object = json.load(stream)
                data = json.dumps(json_object, indent=0, sort_keys=True)
                data = json.loads(data)
                rowPosition = 0
                self.tableJson.setRowCount(0)

                i = 0
                for keyd in self.headerTabData:
                    try:
                        val = str(data[keyd])
                        val = val.replace('[', '')
                        val = val.replace(']', '')
                    except:
                        val = ''
                    #===========================================================
                    # self.tableData.insertRow(i)
                    # self.tableData.setItem(0,i,QTableWidgetItem(val))
                    # i+=1
                    #===========================================================
                #===============================================================
                # self.tableData.setItem(0,0,QTableWidgetItem(fileName))
                # self.tableData.selectRow(0)
                #===============================================================
                for keys in data:
                    stringValue = str(data[keys])
                    stringValue = stringValue.replace('[', '')
                    stringValue = stringValue.replace(']', '')
                    self.tableJson.insertRow(rowPosition)
                    self.tableJson.setItem(rowPosition, 0,
                                           QTableWidgetItem(keys))
                    self.tableJson.setItem(rowPosition, 1,
                                           QTableWidgetItem(stringValue))
                    rowPosition += 1
                self.tableJson.resizeColumnsToContents()
            except json.JSONDecodeError as exc:
                itemError = 'Error Json format'
                self.tableJson.setRowCount(0)
                self.tableJson.insertRow(0)
                self.tableJson.setItem(0, 0, QTableWidgetItem(itemError))
                print(exc)

    def jsonParser(self, pathJson):
        with open(pathJson, 'r') as stream:
            try:
                json_object = json.load(stream)
                listTag = json.dumps(json_object, indent=0, sort_keys=True)
                listTag = json.loads(listTag)
            except json.JSONDecodeError as exc:
                itemError = 'Error Json format'
        return listTag

    def tableDataFill(self, pathRepertory):
        files = [f for f in fnmatch.filter(os.listdir(pathRepertory), '*.nii')]
        self.tableData.setRowCount(0)
        j = 0
        for f in files:
            base = os.path.splitext(f)[0]
            g = os.path.join(pathRepertory, base + ".json")
            self.tableData.insertRow(j)
            if os.path.isfile(g):
                data = self.jsonParser(g)
                i = 0
                for keyw in self.headerTabData:
                    try:
                        val = str(data[keyw])
                        val = val.replace('[', '')
                        val = val.replace(']', '')
                    except:
                        val = ''
                    self.tableData.setItem(j, i, QTableWidgetItem(val))
                    i += 1
            else:
                self.tableData.setItem(j, 1,
                                       QTableWidgetItem('No json file found'))
            self.tableData.setItem(j, 0, QTableWidgetItem(f))
            self.tableData.resizeColumnsToContents()
            j += 1

    def indexImage(self):
        sl1 = self.a1.value()
        sl2 = self.a2.value()
        sl3 = self.a3.value()
        if len(self.img.shape) == 3:
            x = self.img.get_data()[:, :, sl1].copy()
            self.a1.setMaximum(self.img.shape[2] - 1)
            self.a2.setMaximum(0)
            self.a3.setMaximum(0)
        if len(self.img.shape) == 4:
            x = self.img.get_data()[:, :, sl1, sl2].copy()
            self.a1.setMaximum(self.img.shape[2] - 1)
            self.a2.setMaximum(self.img.shape[3] - 1)
            self.a3.setMaximum(0)
        if len(self.img.shape) == 5:
            x = self.img.get_data()[:, :, sl1, sl2, sl3].copy()
            self.a1.setMaximum(self.img.shape[2] - 1)
            self.a2.setMaximum(self.img.shape[3] - 1)
            self.a3.setMaximum(self.img.shape[4] - 1)
        x = rotate(x, -90, reshape=False)
        x = np.uint8((x - x.min()) / x.ptp() * 255.0)
        self.x = x

############################ Slice controls  #########################################

    def boxSliders(self):
        self.k1 = QLabel('Slider 1    ')
        self.k2 = QLabel('Slider 2')
        self.k3 = QLabel('Slider 3')

        self.a1 = self.createSlider(0, 0, 0)
        self.a2 = self.createSlider(0, 0, 0)
        self.a3 = self.createSlider(0, 0, 0)

        self.a1.valueChanged.connect(self.changePosValue)
        self.a2.valueChanged.connect(self.changePosValue)
        self.a3.valueChanged.connect(self.changePosValue)

        self.txta1 = self.createFieldValue()
        self.txta2 = self.createFieldValue()
        self.txta3 = self.createFieldValue()

        self.controlsGroup = QGroupBox('Slice Controls')
        gridCtrl = QGridLayout()
        gridCtrl.addWidget(self.k1, 0, 0)
        gridCtrl.addWidget(self.a1, 0, 1)
        gridCtrl.addWidget(self.txta1, 0, 2)
        gridCtrl.addWidget(self.k2, 1, 0)
        gridCtrl.addWidget(self.a2, 1, 1)
        gridCtrl.addWidget(self.txta2, 1, 2)
        gridCtrl.addWidget(self.k3, 2, 0)
        gridCtrl.addWidget(self.a3, 2, 1)
        gridCtrl.addWidget(self.txta3, 2, 2)
        self.controlsGroup.setLayout(gridCtrl)

        ############################ brightness and contrast  ################################
        self.txtb1 = self.createFieldValue()
        self.txtb2 = self.createFieldValue()
        self.txtb3 = self.createFieldValue()
        self.txtb4 = self.createFieldValue()

        self.l1 = QLabel('Brightness    ')
        self.b1 = self.createSlider(101, 0, 50)
        self.l2 = QLabel('Contrast')
        self.b2 = self.createSlider(101, 0, 50)
        self.l3 = QLabel('Sharpness')
        self.b3 = self.createSlider(101, 0, 50)
        self.l4 = QLabel('Color')
        self.b4 = self.createSlider(101, 0, 50)

        self.b1.valueChanged.connect(self.changeContValue)
        self.b2.valueChanged.connect(self.changeContValue)
        self.b3.valueChanged.connect(self.changeContValue)
        self.b4.valueChanged.connect(self.changeContValue)

        self.txtb1.setText(str(0))
        self.txtb2.setText(str(0))
        self.txtb3.setText(str(0))
        self.txtb4.setText(str(0))

        self.buttonResetContrast = QPushButton('reset', self)
        self.buttonResetContrast.setToolTip('Reset all values')
        self.buttonResetContrast.setEnabled(False)
        self.buttonResetContrast.clicked.connect(self.resetValuesContrast)

        self.contrastGroup = QGroupBox('Brightness and Contrast')
        gridCont = QGridLayout()
        gridCont.addWidget(self.l1, 0, 0)
        gridCont.addWidget(self.b1, 0, 1)
        gridCont.addWidget(self.txtb1, 0, 2)
        gridCont.addWidget(self.l2, 1, 0)
        gridCont.addWidget(self.b2, 1, 1)
        gridCont.addWidget(self.txtb2, 1, 2)
        gridCont.addWidget(self.l3, 2, 0)
        gridCont.addWidget(self.b3, 2, 1)
        gridCont.addWidget(self.txtb3, 2, 2)
        gridCont.addWidget(self.l4, 3, 0)
        gridCont.addWidget(self.b4, 3, 1)
        gridCont.addWidget(self.txtb4, 3, 2)
        gridCont.addWidget(self.buttonResetContrast, 4, 2)
        self.contrastGroup.setLayout(gridCont)

        ############################ Transformation  #########################################
        self.txtc1 = self.createFieldValue()
        self.txtc2 = self.createFieldValue()
        self.txtc3 = self.createFieldValue()
        self.txtc4 = self.createFieldValue()

        self.m1 = QLabel('Rotation')
        self.c1 = self.createSlider(180, -180, 0)
        self.m2 = QLabel('Translate X    ')
        self.c2 = self.createSlider(1, -1, 0)
        self.m3 = QLabel('Translate Y    ')
        self.c3 = self.createSlider(1, -1, 0)
        self.m4 = QLabel('Resize')
        self.c4 = self.createSlider(10, 0, 0)

        self.c1.valueChanged.connect(self.changeTransValue)
        self.c2.valueChanged.connect(self.changeTransValue)
        self.c3.valueChanged.connect(self.changeTransValue)
        self.c4.valueChanged.connect(self.changeTransValue)

        self.txtc1.setText(str(0))
        self.txtc2.setText(str(0))
        self.txtc3.setText(str(0))
        self.txtc4.setText(str(0))

        self.buttonResetTransform = QPushButton('reset', self)
        self.buttonResetTransform.setToolTip('Reset all values')
        self.buttonResetTransform.setEnabled(False)
        self.buttonResetTransform.clicked.connect(self.resetValuesTransform)

        self.transformationGroup = QGroupBox('Transformations')
        gridTransf = QGridLayout()
        gridTransf.addWidget(self.m1, 0, 0)
        gridTransf.addWidget(self.c1, 0, 1)
        gridTransf.addWidget(self.txtc1, 0, 2)
        gridTransf.addWidget(self.m2, 1, 0)
        gridTransf.addWidget(self.c2, 1, 1)
        gridTransf.addWidget(self.txtc2, 1, 2)
        gridTransf.addWidget(self.m3, 2, 0)
        gridTransf.addWidget(self.c3, 2, 1)
        gridTransf.addWidget(self.txtc3, 2, 2)
        gridTransf.addWidget(self.m4, 3, 0)
        gridTransf.addWidget(self.c4, 3, 1)
        gridTransf.addWidget(self.txtc4, 3, 2)
        gridTransf.addWidget(self.buttonResetTransform, 4, 2)
        self.transformationGroup.setLayout(gridTransf)

        ####################################################################################
        self.layoutSliders = QVBoxLayout()
        self.layoutSliders.addWidget(self.controlsGroup)
        self.layoutSliders.addWidget(self.contrastGroup)
        self.layoutSliders.addWidget(self.transformationGroup)

        self.layoutSlide = QWidget()
        self.layoutSlide.setLayout(self.layoutSliders)

    def createSlider(self, maxm=0, minm=0, pos=0):
        slider = QSlider(Qt.Horizontal)
        slider.setFocusPolicy(Qt.StrongFocus)
        #slider.setTickPosition(QSlider.TicksBothSides)
        slider.setTickInterval(1)
        #slider.setSingleStep(1)
        slider.setMaximum(maxm)
        slider.setMinimum(minm)
        slider.setValue(pos)
        slider.setEnabled(False)
        return slider

    def createFieldValue(self):
        fieldValue = QLineEdit()
        fieldValue.setEnabled(False)
        fieldValue.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        return fieldValue

    def displayPosValue(self):
        self.txta1.setText(
            str(self.a1.value() + 1) + ' / ' + str(self.a1.maximum() + 1))
        self.txta2.setText(
            str(self.a2.value() + 1) + ' / ' + str(self.a2.maximum() + 1))
        self.txta3.setText(
            str(self.a3.value() + 1) + ' / ' + str(self.a3.maximum() + 1))

    def changePosValue(self):
        self.navigImage()

    def navigImage(self):
        self.indexImage()
        self.displayPosValue()
        w, h = self.x.shape
        image = QImage(self.x.data, w, h, QImage.Format_Indexed8)
        self.pixm = QPixmap.fromImage(image)
        self.imageLabel.setPixmap(self.pixm)
        self.imageLabel.adjustSize()
        self.imageLabel.resize(self.scaleFactor *
                               self.imageLabel.pixmap().size())
        self.filter()

    def changeContValue(self):
        self.txtb1.setText(str(self.b1.value() - 50))
        self.txtb2.setText(str(self.b2.value() - 50))
        self.txtb3.setText(str(self.b3.value() - 50))
        self.txtb4.setText(str(self.b4.value() - 50))
        self.filter()

    def changeTransValue(self):
        self.txtc1.setText(str(self.c1.value()))
        self.txtc2.setText(str(self.c2.value()))
        self.txtc3.setText(str(self.c3.value()))
        self.txtc4.setText(str(self.c4.value()))
        self.filter()

    def filter(self):
        img = Image.fromarray(self.x, 'L')

        brightness = ImageEnhance.Brightness(img)
        newImg = brightness.enhance(1.2 * (self.b1.value() + 1) / 50.0)

        contrast = ImageEnhance.Contrast(newImg)
        newImg = contrast.enhance((self.b2.value() + 1) / 50.0)

        sharpness = ImageEnhance.Sharpness(newImg)
        newImg = sharpness.enhance(2.0 * (self.b3.value() + 1) / 50.0)

        color = ImageEnhance.Color(newImg)
        newImg = color.enhance((self.b4.value() + 1) / 50.0)

        newImg = newImg.rotate(self.c1.value())

        newImg = newImg.transform(
            img.size, Image.AFFINE,
            (1, 0, self.c2.value(), 0, 1, self.c3.value()))

        size1 = int(img.size[0] * (self.c4.value() + 1))
        size2 = int(img.size[1] * (self.c4.value() + 1))

        newImg = newImg.resize((size1, size2), Image.ANTIALIAS)

        self.pixm = QPixmap.fromImage(newImg.toqimage())
        self.imageLabel.setPixmap(self.pixm)
        self.imageLabel.adjustSize()
        self.imageLabel.resize(self.scaleFactor *
                               self.imageLabel.pixmap().size())

    def resetValuesContrast(self):
        self.b1.setSliderPosition(50)
        self.b2.setSliderPosition(50)
        self.b3.setSliderPosition(50)
        self.b4.setSliderPosition(50)
        self.changeContValue()

    def resetValuesTransform(self):
        self.c1.setSliderPosition(0)
        self.c2.setSliderPosition(0)
        self.c3.setSliderPosition(0)
        self.c4.setSliderPosition(0)
        self.changeTransValue()

    def enableSliders(self):
        self.a1.setEnabled(True)
        self.a2.setEnabled(True)
        self.a3.setEnabled(True)
        self.b1.setEnabled(True)
        self.b2.setEnabled(True)
        self.b3.setEnabled(True)
        self.b4.setEnabled(True)
        self.c1.setEnabled(True)
        self.c2.setEnabled(True)
        self.c3.setEnabled(True)
        self.c4.setEnabled(True)
        self.buttonResetContrast.setEnabled(True)
        self.buttonResetTransform.setEnabled(True)

####################################################################################

    def browserFile(self):

        global Browser, Model

        self.browser = QTreeView()

        model = QFileSystemModel()
        model.setNameFilters(['*.nii'])
        model.setNameFilterDisables(False)
        model.setReadOnly(True)

        self.browser.setModel(model)
        self.browser.expandAll()
        self.browser.setColumnWidth(0, 400)

        self.browser.selectionModel().selectionChanged.connect(self.select)

        Browser = self.browser
        Model = model

        #=======================================================================
        # self.browser.doubleClicked.connect(self.selection)
        #self.browser.clicked.connect(self.selection)
        #=======================================================================

    def select(self, signal):
        file_path = self.browser.model().filePath(signal.indexes()[0])
        shortName, fileExt = os.path.splitext(file_path)
        filePath, fileName = os.path.split(file_path)
        self.textInfo.setText(filePath)
        blackColor = QColor(0, 0, 0)

        if os.path.isfile(file_path):
            if fileExt == ".nii":
                if self.currentRep != filePath:
                    self.tableDataFill(filePath)
                    self.currentRep = filePath
                self.open(file_path)
                self.tableData.selectRow(
                    self.tableData.findItems(fileName,
                                             Qt.MatchExactly)[0].row())
                if os.path.isfile(shortName + '.json'):
                    greenColor = QColor(50, 150, 100)
                    self.textInfoTop.setTextColor(greenColor)
                    self.textInfoTop.append('Json file exists ' + '\n')
                    self.openJson(shortName + '.json', fileName)
                else:
                    redColor = QColor(255, 0, 0)
                    self.textInfoTop.setTextColor(redColor)
                    self.textInfoTop.append('Json file doesn\'t exist' + '\n')
                    self.tableJson.setRowCount(0)
        else:
            self.tableData.setRowCount(0)
            self.currentRep = filePath

        self.textInfoTop.setTextColor(blackColor)
        self.scrollText.setWidgetResizable(True)


####################################################################################

    def createMenus(self):
        self.fileMenu = QMenu("&File", self)
        self.fileMenu.addAction(self.exitAct)

        self.viewMenu = QMenu("&View", self)
        self.viewMenu.addAction(self.zoomInAct)
        self.viewMenu.addAction(self.zoomOutAct)
        self.viewMenu.addAction(self.normalSizeAct)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.fitToWindowAct)
        self.viewMenu.addSeparator()

        self.helpMenu = QMenu("&Help", self)
        self.helpMenu.addAction(self.aboutAct)

        self.menuBar = QMenuBar()

        self.menuBar.addMenu(self.fileMenu)
        self.menuBar.addMenu(self.viewMenu)
        self.menuBar.addMenu(self.helpMenu)

    def createToolbarMenus(self):
        self.menuToolBar = QToolBar()

        viewMenu = QToolButton()
        viewMenu.setText('View')
        viewMenu.setPopupMode(QToolButton.MenuButtonPopup)
        aMenu = QMenu()
        aMenu.addAction(self.zoomInAct)
        aMenu.addAction(self.zoomOutAct)
        aMenu.addAction(self.normalSizeAct)
        aMenu.addSeparator()
        aMenu.addAction(self.fitToWindowAct)
        viewMenu.setMenu(aMenu)

        helpMenu = QToolButton()
        helpMenu.setText('Help')
        helpMenu.setPopupMode(QToolButton.MenuButtonPopup)
        bMenu = QMenu()
        helpMenu.setMenu(bMenu)

        self.menuToolBar.addWidget(viewMenu)
        self.menuToolBar.addWidget(helpMenu)

    def createActions(self):
        self.exitAct = QAction("Exit",
                               self,
                               shortcut="Ctrl+Q",
                               triggered=self.close)

        self.zoomInAct = QAction("Zoom In (25%)",
                                 self,
                                 shortcut="Ctrl++",
                                 enabled=False,
                                 triggered=self.zoomIn)

        self.zoomOutAct = QAction("Zoom Out (25%)",
                                  self,
                                  shortcut="Ctrl+-",
                                  enabled=False,
                                  triggered=self.zoomOut)

        self.normalSizeAct = QAction("Normal Size",
                                     self,
                                     shortcut="Ctrl+S",
                                     enabled=False,
                                     triggered=self.normalSize)

        self.fitToWindowAct = QAction("Fit to Window",
                                      self,
                                      enabled=False,
                                      checkable=True,
                                      shortcut="Ctrl+F",
                                      triggered=self.fitToWindow)

    def zoomIn(self):
        self.factor = 1.25
        self.scaleImage(self.factor)

    def zoomOut(self):
        self.factor = 0.8
        self.scaleImage(self.factor)

    def normalSize(self):
        self.imageLabel.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scrollArea.setWidgetResizable(fitToWindow)
        self.scrollText.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()

        self.updateActions()

    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())

    def scaleImage(self, factor):
        self.scaleFactor *= factor
        self.imageLabel.resize(self.scaleFactor *
                               self.imageLabel.pixmap().size())

        self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
        self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)

        self.zoomInAct.setEnabled(self.scaleFactor < 5.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)

    def close(self):
        self.close()
class Broswer_Img(QMainWindow):
    """
    选择图片文件并且预览,自动匹配多图的情况和背景图片
    """
    Close_Signal = pyqtSignal(list)

    def __init__(self, *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)
        self.Current_Dir = QDir.home().absolutePath()
        #self.Current_Dir = Wk_Dir
        self.setWindowTitle("Select Imags")
        self.setWindowModality(Qt.ApplicationModal)
        self.Left_Dock_Code()
        self.Central_Frame_Code()
        self.Right_Dock_Code()
        self.connect_Signals()

        self.wb_nav_left.setEnabled(False)
        self.wb_nav_right.setEnabled(False)
        self.bkgd_nav_left.setEnabled(False)
        self.bkgd_nav_right.setEnabled(False)

        #self.setGeometry(200, 200, 1000, 600)
        #self.setMaximumSize(QSize(1000, 600))

    def Left_Dock_Code(self):
        self.Left_Frame = QFrame(self)
        self.Model = QFileSystemModel()
        self.Model.setNameFilterDisables(False)
        self.Model.setRootPath(self.Current_Dir)
        #self.Model.setSorting(QDir.DirsFirst | QDir.IgnoreCase | QDir.Name)
        self.Model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs
                             | QDir.AllEntries)
        self.Model.setNameFilters(['*.tif'])
        self.Tree = QTreeView(self.Left_Frame)
        self.Tree.setModel(self.Model)
        self.Tree.setRootIndex(self.Model.index(self.Current_Dir))
        self.Tree.expandAll()
        self.Dir_Select = QPushButton("Select a Folder", self.Left_Frame)
        layout = QVBoxLayout()
        layout.addWidget(self.Tree)
        layout.addWidget(self.Dir_Select)
        self.Left_Frame.setLayout(layout)
        self.Left_Dock = QDockWidget('Broswer Images', self)
        self.Left_Dock.setWidget(self.Left_Frame)
        self.Left_Dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.Dir_Select.clicked.connect(self.dir_selection)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.Left_Dock)

    def Central_Frame_Code(self):
        self.Central_Frame = QFrame(self)
        layout = QGridLayout()
        self.wb_label = QLabel(self.Central_Frame)
        self.bkgd_label = QLabel(self.Central_Frame)
        #self.wb_label.setMaximumHeight(30)
        self.wb_label.setWordWrap(True)

        self.wb = QLabel(self.Central_Frame)
        self.wb.setScaledContents(True)
        self.bkgd = QLabel(self.Central_Frame)
        self.bkgd.setScaledContents(True)
        self.wb.setMaximumSize(QSize(300, 300))
        self.bkgd.setMaximumSize(QSize(300, 300))

        self.wb_navigator = QFrame(self.Central_Frame)
        self.wb_nav_left = QPushButton('<--', self.wb_navigator)
        self.wb_nav_right = QPushButton('-->', self.wb_navigator)
        nav_layout = QHBoxLayout()
        nav_layout.addWidget(self.wb_nav_left)
        nav_layout.addWidget(self.wb_nav_right)
        self.wb_navigator.setLayout(nav_layout)
        self.wb_navigator.setMaximumHeight(60)

        self.bkgd_navigator = QFrame(self.Central_Frame)
        self.bkgd_nav_left = QPushButton('<--', self.bkgd_navigator)
        self.bkgd_nav_right = QPushButton('-->', self.bkgd_navigator)
        nav_layout2 = QHBoxLayout()
        nav_layout2.addWidget(self.bkgd_nav_left)
        nav_layout2.addWidget(self.bkgd_nav_right)
        self.bkgd_navigator.setLayout(nav_layout2)
        self.bkgd_navigator.setMaximumHeight(60)

        self.btns = QFrame(self.Central_Frame)
        self.btns.setMaximumHeight(60)
        self.Btn_Add = QPushButton('Add', self.btns)
        self.Btn_Close = QPushButton('Close', self.btns)
        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.Btn_Add)
        btn_layout.addWidget(self.Btn_Close)
        self.btns.setLayout(btn_layout)

        # 根据具体的传入参数构建不同的视图
        layout.addWidget(self.wb_label, 0, 0)
        layout.addWidget(self.bkgd_label, 0, 1)

        layout.addWidget(self.wb, 1, 0)
        layout.addWidget(self.bkgd, 1, 1)

        layout.addWidget(self.wb_navigator, 2, 0)
        layout.addWidget(self.bkgd_navigator, 2, 1)

        layout.addWidget(self.btns, 3, 0, 2, 0)
        layouts = QVBoxLayout()
        layouts.addLayout(layout)
        self.Central_Frame.setLayout(layouts)
        self.setCentralWidget(self.Central_Frame)
        #self.setStyleSheet('border:1px solid red')

    def Right_Dock_Code(self):
        self.Added_Img_tree = Img_Tree([], self)
        self.Right_Dock = QDockWidget('Selected Images', self)
        self.Right_Dock.setWidget(self.Added_Img_tree)
        self.Right_Dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.addDockWidget(Qt.RightDockWidgetArea, self.Right_Dock)

    def connect_Signals(self):
        self.Tree.clicked.connect(self.Load_Img_to_Central_Frame)
        self.wb_nav_left.clicked.connect(self.change_img_index)
        self.wb_nav_right.clicked.connect(self.change_img_index)
        self.bkgd_nav_left.clicked.connect(self.change_img_index)
        self.bkgd_nav_right.clicked.connect(self.change_img_index)
        self.Btn_Add.clicked.connect(self.Add_Btn_Action)
        self.Btn_Close.clicked.connect(self.Close_Btn_Action)

    def Load_Img_to_Central_Frame(self, Index):
        select_file = self.Tree.model().filePath(Index)
        _, ext = os.path.splitext(select_file)
        if ext in ['.tif', '.jpeg', '.png', '.jpg']:
            self.Related_Imgs = BioRad_Imgs(select_file)
        self.set_Central_Frame()

    def set_Central_Frame(self):
        self.wb_nav_left.setEnabled(False)
        self.wb_nav_right.setEnabled(False)
        self.bkgd_nav_left.setEnabled(False)
        self.bkgd_nav_right.setEnabled(False)

        self.current_wb = self.Related_Imgs.WB_list[self.Related_Imgs.wb_index]
        self.current_bkgd = self.Related_Imgs.BKGD_list[
            self.Related_Imgs.bkgd_index]
        self.wb_label.setText(
            self.current_wb.replace(self.Related_Imgs.Dir, '.'))
        self.bkgd_label.setText(
            self.current_bkgd.replace(self.Related_Imgs.Dir, '.'))
        wb, _ = CV_Img_to_QImage(cv2.imread(self.current_wb))
        bkgd, _ = CV_Img_to_QImage(cv2.imread(self.current_bkgd))
        self.wb.setPixmap(wb)
        self.wb.setScaledContents(True)
        self.bkgd.setPixmap(bkgd)
        wb_len = len(self.Related_Imgs.WB_list)
        bkgd_len = len(self.Related_Imgs.BKGD_list)
        if self.Related_Imgs.wb_index > 0:
            self.wb_nav_left.setEnabled(True)
        if wb_len - self.Related_Imgs.wb_index > 1:
            self.wb_nav_right.setEnabled(True)

        if self.Related_Imgs.bkgd_index > 0:
            self.bkgd_nav_left.setEnabled(True)
        if bkgd_len - self.Related_Imgs.bkgd_index > 1:
            self.bkgd_nav_right.setEnabled(True)

    def change_img_index(self):
        sender = self.sender()
        if sender == self.wb_nav_left:
            self.Related_Imgs.wb_index = self.Related_Imgs.wb_index - 1
        if sender == self.wb_nav_right:
            self.Related_Imgs.wb_index = self.Related_Imgs.wb_index + 1
        if sender == self.bkgd_nav_left:
            self.Related_Imgs.bkgd_index = self.Related_Imgs.bkgd_index - 1
        if sender == self.bkgd_nav_right:
            self.Related_Imgs.bkgd_index = self.Related_Imgs.bkgd_index + 1
        self.set_Central_Frame()

    def Add_Btn_Action(self):
        list = [{'wb': self.current_wb, 'bkgd': self.current_bkgd}]
        self.Added_Img_tree.Add_top_Level_Item(list)
        print(self.Added_Img_tree.imgs)

    def Close_Btn_Action(self):
        self.close()

    def closeEvent(self, event):
        self.Close_Signal.emit(self.Added_Img_tree.imgs)

    def dir_selection(self):
        global Wk_Dir
        dir = QFileDialog.getExistingDirectory(self, "Choose a Directory",
                                               Wk_Dir)
        self.Current_Dir = dir
        Wk_Dir = dir
        self.Tree.setRootIndex(self.Model.index(self.Current_Dir))
        self.Left_Dock.setWindowTitle(dir)
예제 #35
0
class AddBookmarkDialog(QDialog, Ui_AddBookmarkDialog):
    """
    Class implementing a dialog to add a bookmark or a bookmark folder.
    """
    def __init__(self, parent=None, bookmarksManager=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        @param bookmarksManager reference to the bookmarks manager
            object (BookmarksManager)
        """
        super(AddBookmarkDialog, self).__init__(parent)
        self.setupUi(self)

        self.__bookmarksManager = bookmarksManager
        self.__addedNode = None
        self.__addFolder = False

        if self.__bookmarksManager is None:
            import Helpviewer.HelpWindow
            self.__bookmarksManager = \
                Helpviewer.HelpWindow.HelpWindow.bookmarksManager()

        self.__proxyModel = AddBookmarkProxyModel(self)
        model = self.__bookmarksManager.bookmarksModel()
        self.__proxyModel.setSourceModel(model)

        self.__treeView = QTreeView(self)
        self.__treeView.setModel(self.__proxyModel)
        self.__treeView.expandAll()
        self.__treeView.header().setStretchLastSection(True)
        self.__treeView.header().hide()
        self.__treeView.setItemsExpandable(False)
        self.__treeView.setRootIsDecorated(False)
        self.__treeView.setIndentation(10)
        self.__treeView.show()

        self.locationCombo.setModel(self.__proxyModel)
        self.locationCombo.setView(self.__treeView)

        self.addressEdit.setInactiveText(self.tr("Url"))
        self.nameEdit.setInactiveText(self.tr("Title"))

        self.resize(self.sizeHint())

    def setUrl(self, url):
        """
        Public slot to set the URL of the new bookmark.
        
        @param url URL of the bookmark (string)
        """
        self.addressEdit.setText(url)
        self.resize(self.sizeHint())

    def url(self):
        """
        Public method to get the URL of the bookmark.
        
        @return URL of the bookmark (string)
        """
        return self.addressEdit.text()

    def setTitle(self, title):
        """
        Public method to set the title of the new bookmark.
        
        @param title title of the bookmark (string)
        """
        self.nameEdit.setText(title)

    def title(self):
        """
        Public method to get the title of the bookmark.
        
        @return title of the bookmark (string)
        """
        return self.nameEdit.text()

    def setDescription(self, description):
        """
        Public method to set the description of the new bookmark.
        
        @param description description of the bookamrk (string)
        """
        self.descriptionEdit.setPlainText(description)

    def description(self):
        """
        Public method to get the description of the bookmark.
        
        @return description of the bookamrk (string)
        """
        return self.descriptionEdit.toPlainText()

    def setCurrentIndex(self, idx):
        """
        Public method to set the current index.
        
        @param idx current index to be set (QModelIndex)
        """
        proxyIndex = self.__proxyModel.mapFromSource(idx)
        self.__treeView.setCurrentIndex(proxyIndex)
        self.locationCombo.setCurrentIndex(proxyIndex.row())

    def currentIndex(self):
        """
        Public method to get the current index.
        
        @return current index (QModelIndex)
        """
        idx = self.locationCombo.view().currentIndex()
        idx = self.__proxyModel.mapToSource(idx)
        return idx

    def setFolder(self, folder):
        """
        Public method to set the dialog to "Add Folder" mode.
        
        @param folder flag indicating "Add Folder" mode (boolean)
        """
        self.__addFolder = folder

        if folder:
            self.setWindowTitle(self.tr("Add Folder"))
            self.addressEdit.setVisible(False)
        else:
            self.setWindowTitle(self.tr("Add Bookmark"))
            self.addressEdit.setVisible(True)

        self.resize(self.sizeHint())

    def isFolder(self):
        """
        Public method to test, if the dialog is in "Add Folder" mode.
        
        @return flag indicating "Add Folder" mode (boolean)
        """
        return self.__addFolder

    def addedNode(self):
        """
        Public method to get a reference to the added bookmark node.
        
        @return reference to the added bookmark node (BookmarkNode)
        """
        return self.__addedNode

    def accept(self):
        """
        Public slot handling the acceptance of the dialog.
        """
        if (not self.__addFolder and not self.addressEdit.text()) or \
           not self.nameEdit.text():
            super(AddBookmarkDialog, self).accept()
            return

        from .BookmarkNode import BookmarkNode

        idx = self.currentIndex()
        if not idx.isValid():
            idx = self.__bookmarksManager.bookmarksModel().index(0, 0)
        parent = self.__bookmarksManager.bookmarksModel().node(idx)

        if self.__addFolder:
            type_ = BookmarkNode.Folder
        else:
            type_ = BookmarkNode.Bookmark
        bookmark = BookmarkNode(type_)
        bookmark.title = self.nameEdit.text()
        if not self.__addFolder:
            bookmark.url = self.addressEdit.text()
        bookmark.desc = self.descriptionEdit.toPlainText()

        self.__bookmarksManager.addBookmark(parent, bookmark)
        self.__addedNode = bookmark

        super(AddBookmarkDialog, self).accept()
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()