예제 #1
0
파일: layer_tree.py 프로젝트: ssec/sift
 def select(self,
            uuids,
            lbox: QTreeView = None,
            scroll_to_show_single=True):
     lbox = self.current_set_listbox if lbox is None else lbox
     lbox.clearSelection()
     if not uuids:
         return
     # FUTURE: this is quick and dirty
     rowdict = dict(
         (u, i) for i, u in enumerate(self.doc.current_layer_uuid_order))
     items = QItemSelection()
     q = None
     for uuid in uuids:
         row = rowdict.get(uuid, None)
         if row is None:
             LOG.error(
                 'UUID {} cannot be selected in list view'.format(uuid))
             continue
         q = self.createIndex(row, 0)
         items.select(q, q)
         lbox.selectionModel().select(items, QItemSelectionModel.Select)
         # lbox.setCurrentIndex(q)
     if scroll_to_show_single and len(uuids) == 1 and q is not None:
         lbox.scrollTo(q)
예제 #2
0
class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(600, 300)
        self.model = QDirModel(self)  # 1
        self.model.setReadOnly(False)
        self.model.setSorting(QDir.Name | QDir.IgnoreCase)

        self.tree = QTreeView(self)  # 2
        self.tree.setModel(self.model)
        self.tree.clicked.connect(self.show_info)
        self.index = self.model.index(QDir.currentPath())
        self.tree.expand(self.index)
        self.tree.scrollTo(self.index)

        self.info_label = QLabel(self)  # 3

        self.v_layout = QVBoxLayout()
        self.v_layout.addWidget(self.tree)
        self.v_layout.addWidget(self.info_label)
        self.setLayout(self.v_layout)

    def show_info(self):  # 4
        index = self.tree.currentIndex()
        file_name = self.model.fileName(index)
        file_path = self.model.filePath(index)
        file_info = 'File Name: {}\nFile Path: {}'.format(file_name, file_path)
        self.info_label.setText(file_info)
예제 #3
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """

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

        self._workspace = workspace

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        menu.exec_(self.tvFiles.mapToGlobal(pos))
예제 #4
0
class Dialog_ImageFolder():
    def __init__(self, parent, title, init_path):
        self.w = QDialog(parent)

        self.parent = parent
        self.left = 300
        self.top = 300
        self.width = 600
        self.height = 400
        self.title = title

        self.dirModel = QFileSystemModel()
        self.dirModel.setRootPath(init_path)
        self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
        self.treeview = QTreeView()
        self.treeview.setModel(self.dirModel)
        self.treeview.setRootIndex(self.dirModel.index(""))
        self.treeview.clicked.connect(self.on_clicked)
        #--- Hide All Header Sections Except First ----
        header = self.treeview.header()
        for sec in range(1, header.count()):
            header.setSectionHidden(sec, True)
        #--- ---- ---- ---- ---- ---- ---- ---- ---- --

        focus_index = self.dirModel.index(init_path)
        self.treeview.setCurrentIndex(focus_index)
        self.current_row_changed()

        self.listview = QListView()
        self.listview.setViewMode(QListView.IconMode)
        self.listview.setIconSize(QSize(192, 192))

        targetfiles1 = glob.glob(os.path.join(init_path, '*.png'))
        targetfiles2 = glob.glob(os.path.join(init_path, '*.tif'))
        targetfiles3 = glob.glob(os.path.join(init_path, '*.tiff'))
        targetfiles = targetfiles1 + targetfiles2 + targetfiles3
        lm = _MyListModel(targetfiles, self.parent)
        self.listview.setModel(lm)

        self.sub_layout = QHBoxLayout()
        self.sub_layout.addWidget(self.treeview)
        self.sub_layout.addWidget(self.listview)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Open
                                          | QDialogButtonBox.Cancel)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.main_layout = QVBoxLayout()
        self.main_layout.addLayout(self.sub_layout)
        self.main_layout.addWidget(self.buttonBox)

        self.w.setGeometry(self.left, self.top, self.width, self.height)
        self.w.setWindowTitle(self.title)
        self.w.setWindowIcon(QIcon(os.path.join(icon_dir, 'Mojo2_16.png')))
        self.w.setLayout(self.main_layout)

    def current_row_changed(self):
        index = self.treeview.currentIndex()
        self.treeview.scrollTo(index, QAbstractItemView.EnsureVisible)
        self.treeview.resizeColumnToContents(0)

    def on_clicked(self, index):
        path = self.dirModel.fileInfo(index).absoluteFilePath()

        targetfiles1 = glob.glob(os.path.join(path, '*.png'))
        targetfiles2 = glob.glob(os.path.join(path, '*.tif'))
        targetfiles3 = glob.glob(os.path.join(path, '*.tiff'))
        targetfiles = targetfiles1 + targetfiles2 + targetfiles3

        lm = _MyListModel(targetfiles, self.parent)
        self.listview.setModel(lm)

    def accept(self):
        index = self.treeview.currentIndex()
        self.newdir = self.dirModel.filePath(index)
        self.w.done(1)

    def reject(self):
        self.w.done(0)

    def GetValue(self):
        index = self.treeview.currentIndex()
        self.newdir = self.dirModel.filePath(index)
        return self.newdir
예제 #5
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """
    def __init__(self, workspace):
        DockWidget.__init__(self, workspace, "&Opened Files",
                            QIcon(":/enkiicons/filtered.png"), "Alt+O")

        self._workspace = workspace

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        menu.exec_(self.tvFiles.mapToGlobal(pos))
예제 #6
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)
예제 #7
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """

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

        self._workspace = workspace

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def eventFilter(self, obj, event):
        """An event filter that looks for ctrl key releases and focus out
           events."""
        # Wait for the user to release the Ctrl key.
        if ( self._waitForCtrlRelease and event.type() == QEvent.KeyRelease and
          event.key() == Qt.Key_Control and
          event.modifiers() == Qt.NoModifier):
            self.model.sortDocuments()
            self._waitForCtrlRelease = False
            if not self.isPinned():
                self.hide()
        # Look for a focus out event sent by the containing widget's focus
        # proxy.
        if event.type() == QEvent.FocusOut and obj == self.focusProxy():
            self.model.sortDocuments()
        return QObject.eventFilter(self, obj, event)
예제 #8
0
class OpenedFileExplorer(DockWidget):
    """Opened File Explorer is list widget with list of opened files.
    It implements switching current file, files sorting. Uses _OpenedFileModel internally.
    Class instance created by Workspace.
    """
    def __init__(self, workspace):
        DockWidget.__init__(self, workspace, "&Opened Files",
                            QIcon(":/enkiicons/filtered.png"), "Alt+O")

        self._workspace = workspace

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def eventFilter(self, obj, event):
        """An event filter that looks for ctrl key releases and focus out
           events."""
        # Wait for the user to release the Ctrl key.
        if (self._waitForCtrlRelease and event.type() == QEvent.KeyRelease
                and event.key() == Qt.Key_Control
                and event.modifiers() == Qt.NoModifier):
            self.model.sortDocuments()
            self._waitForCtrlRelease = False
            if not self.isPinned():
                self.hide()
        # Look for a focus out event sent by the containing widget's focus
        # proxy.
        if event.type() == QEvent.FocusOut and obj == self.focusProxy():
            self.model.sortDocuments()
        return QObject.eventFilter(self, obj, event)
예제 #9
0
class FileBrowserWidget(QWidget):
    on_open = pyqtSignal(str)

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

    def initUI(self):
        self.model = QFileSystemModel()
        self.rootFolder = ''
        self.model.setRootPath(self.rootFolder)
        self.tree = QTreeView()
        self.tree.setModel(self.model)

        self.tree.setAnimated(False)
        self.tree.setIndentation(20)
        self.tree.setSortingEnabled(True)
        self.tree.sortByColumn(0, 0)
        self.tree.setColumnWidth(0, 200)
        self.tree.setDragEnabled(True)

        self.tree.setWindowTitle("Dir View")
        self.tree.resize(640, 480)
        self.tree.doubleClicked.connect(self.onDblClick)
        self.tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(
            self.onCustomContextMenuRequested)

        windowLayout = QVBoxLayout()
        windowLayout.addWidget(self.tree)
        windowLayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(windowLayout)

    def onCustomContextMenuRequested(self, point):
        index = self.tree.indexAt(point)
        selectedFile = None
        selectedFolder = None
        ctx = QMenu("Context menu", self)
        if index.isValid():
            file = self.model.fileInfo(index)
            selectedFile = file.absoluteFilePath()
            selectedFolder = selectedFile if file.isDir(
            ) else file.absolutePath()
            if file.isDir():
                ctx.addAction(
                    "Open in file manager", lambda: QDesktopServices.openUrl(
                        QUrl.fromLocalFile(selectedFile)))
            if not file.isDir():
                for wndTyp, meta in WindowTypes.types:
                    text = 'Open with ' + meta.get('displayName', meta['name'])
                    print(wndTyp, meta)
                    ctx.addAction(
                        QAction(text,
                                self,
                                statusTip=text,
                                triggered=lambda dummy, meta=meta: navigate(
                                    "WINDOW", "Type=" + meta['name'],
                                    "FileName=" + selectedFile)))
                ctx.addSeparator()

        ctx.addAction("Set root folder ...",
                      lambda: self.selectRootFolder(preselect=selectedFolder))
        ctx.exec(self.tree.viewport().mapToGlobal(point))

    def selectRootFolder(self, preselect=None):
        if preselect == None: preselect = self.rootFolder
        dir = QFileDialog.getExistingDirectory(self, "Set root folder",
                                               preselect)
        if dir != None:
            self.setRoot(dir)

    def setRoot(self, dir):
        self.rootFolder = dir
        self.model.setRootPath(dir)
        self.tree.setRootIndex(self.model.index(dir))

    def onDblClick(self, index):
        if index.isValid():
            file = self.model.fileInfo(index)
            if not file.isDir():
                navigate("OPEN", "FileName=" + file.absoluteFilePath())

    def saveState(self):
        if self.tree.currentIndex().isValid():
            info = self.model.fileInfo(self.tree.currentIndex())
            return {"sel": info.absoluteFilePath(), "root": self.rootFolder}

    def restoreState(self, state):
        try:
            self.setRoot(state["root"])
        except:
            pass
        try:
            idx = self.model.index(state["sel"])
            if idx.isValid():
                self.tree.expand(idx)
                self.tree.setCurrentIndex(idx)
                self.tree.scrollTo(idx, QAbstractItemView.PositionAtCenter)
        except:
            pass
예제 #10
0
class TapeWidget(QWidget):
    def __init__(self, parent = None):
        super().__init__(parent)

        self._main_layout    = QVBoxLayout(self)
        self._search_box     = QLineEdit(self)
        self._button_layout  = QHBoxLayout()

        self._view = QTreeView()
        self._view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        self._view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self._view.setHeaderHidden(True)

        self._add_note_button = QPushButton(self)
        self._add_note_button.setText("New note")

        self._add_child_button = QPushButton(self)
        self._add_child_button.setText("New child")

        self._add_sibling_button = QPushButton(self)
        self._add_sibling_button.setText("New sibling")

        self._delete_note_button = QPushButton(self)
        self._delete_note_button.setText("Delete note")

        self._button_layout.addWidget(self._add_note_button)
        self._button_layout.addWidget(self._add_sibling_button)
        self._button_layout.addWidget(self._add_child_button)
        self._button_layout.addWidget(self._delete_note_button)
        self._button_layout.addStretch()

        self._main_layout.addWidget(self._search_box)
        self._main_layout.addLayout(self._button_layout)
        self._main_layout.addWidget(self._view)

        self._tape_filter_proxy_model = TapeFilterProxyModel()
        self._note_delegate           = NoteDelegate()

        self._tape_model = QStandardItemModel()
        self.set_model(self._tape_model)
        self._view.setItemDelegate(self._note_delegate)
        self._view.setModel(self._tape_filter_proxy_model)

        self._add_note_button.clicked.connect(lambda checked: self.add_and_focus_note())
        self._add_sibling_button.clicked.connect(self._new_sibling_handler)
        self._add_child_button.clicked.connect(self._new_child_handler)
        self._delete_note_button.clicked.connect(self.delete_selected_notes)
        self._search_box.textChanged.connect(self._tape_filter_proxy_model.setFilterFixedString)

    def model(self):
        """ Returns the model that contains all notes managed by the tape.

            The model should be treated as read-only. You can only modify it indirectly through
            the methods provided by TapeWidget. """

        return self._tape_model

    def proxy_model(self):
        """ Returns the model that contains notes matching current filter.

            The model should be treated as read-only. You can only modify it indirectly through
            the methods provided by TapeWidget. """

        return self._tape_filter_proxy_model

    def set_model(self, model):
        assert (
            len(set([item_to_id(item) for item in all_items(model) if item_to_id(item) != None])) ==
            len(    [item_to_id(item) for item in all_items(model) if item_to_id(item) != None])
        )

        # NOTE: If there's an exception in setSourceModel(), we can hope that the source model
        # remains unchanged. That's why we assing to _tape_model only if that instruction succeeds.
        self._tape_filter_proxy_model.setSourceModel(model)
        self._tape_model = model

    def notes(self):
        return all_notes(self._tape_model)

    def assign_ids(self):
        assign_note_ids(self._tape_model)

    def create_empty_note(self):
        return Note(
            body       = "",
            tags       = [],
            created_at = datetime.utcnow()
        )

    def add_note(self, note = None, parent_index = None):
        # NOTE: Remember to use indexes from _tape_model, not _tape_filter_proxy_model here
        assert parent_index == None or self._tape_model.itemFromIndex(parent_index) != None and parent_index.isValid()

        root_item = self._tape_model.invisibleRootItem()
        if parent_index == None:
            parent_item = root_item
        else:
            parent_item = self._tape_model.itemFromIndex(parent_index)

        if note != None:
            assert note not in self.notes()
        else:
            note = self.create_empty_note()

        item = QStandardItem()
        set_item_note(item, note)
        parent_item.appendRow(item)

    def add_and_focus_note(self, parent_proxy_index = None):
        if parent_proxy_index != None:
            parent_index = self._tape_filter_proxy_model.mapToSource(parent_proxy_index)
        else:
            parent_index = None

        self.add_note(parent_index = parent_index)

        if parent_proxy_index != None:
            self._view.expand(parent_proxy_index)

            parent_item = self._tape_model.itemFromIndex(parent_index)
        else:
            parent_item = self._tape_model.invisibleRootItem()

        # NOTE: It's likely that the new note does not match the filter and won't not be present
        # in the proxy model. We want to select it and focus on it so the filter must be cleared.
        # And it must be cleared before taking the index in the proxy because changing the filter
        # may change the set of notes present in the proxy and invalidate the index.
        self.set_filter('')

        new_note_index       = parent_item.child(parent_item.rowCount() - 1).index()
        new_note_proxy_index = self._tape_filter_proxy_model.mapFromSource(new_note_index)

        self.clear_selection()
        self.set_note_selection(new_note_proxy_index, True)
        self._view.scrollTo(new_note_proxy_index)

    def remove_notes(self, indexes):
        remove_items(self._tape_model, indexes)

    def clear(self):
        self._tape_model.clear()

    def set_filter(self, text):
        # NOTE: This triggers textChanged() signal which applies the filter
        self._search_box.setText(text)

    def get_filter(self):
        return self._search_box.text()

    def selected_proxy_indexes(self):
        return self._view.selectedIndexes()

    def selected_indexes(self):
        return [self._tape_filter_proxy_model.mapToSource(proxy_index) for proxy_index in self.selected_proxy_indexes()]

    def set_note_selection(self, proxy_index, select):
        assert proxy_index != None and proxy_index.isValid()
        assert self._tape_model.itemFromIndex(self._tape_filter_proxy_model.mapToSource(proxy_index)) != None

        self._view.selectionModel().select(
            QItemSelection(proxy_index, proxy_index),
            QItemSelectionModel.Select if select else QItemSelectionModel.Deselect
        )

    def clear_selection(self):
        self._view.selectionModel().clear()

    def delete_selected_notes(self):
        self.remove_notes(self.selected_indexes())

    def _new_sibling_handler(self):
        selected_proxy_indexes = self._view.selectedIndexes()
        if len(selected_proxy_indexes) > 1:
            self.clear_selection()
            selected_proxy_indexes = []

        if len(selected_proxy_indexes) == 0 or selected_proxy_indexes[0].parent() == QModelIndex():
            self.add_and_focus_note()
        else:
            self.add_and_focus_note(selected_proxy_indexes[0].parent())

    def add_child_to_selected_element(self):
        selected_proxy_indexes = self._view.selectedIndexes()
        if len(selected_proxy_indexes) != 1:
            return False
        else:
            self.add_and_focus_note(selected_proxy_indexes[0])
            return True

    def _new_child_handler(self):
        added = self.add_child_to_selected_element()
        if not added:
            QMessageBox.warning(self, "Can't add note", "To be able to add a new child note select exactly one parent")