Esempio n. 1
1
class FilenamePrompt(_BasePrompt):

    """A prompt for a filename."""

    def __init__(self, question, parent=None):
        super().__init__(question, parent)
        self._init_texts(question)
        self._init_fileview()
        self._set_fileview_root(question.default)

        self._lineedit = LineEdit(self)
        if question.default:
            self._lineedit.setText(question.default)
        self._lineedit.textEdited.connect(self._set_fileview_root)
        self._vbox.addWidget(self._lineedit)

        self.setFocusProxy(self._lineedit)
        self._init_key_label()

        if config.get('ui', 'prompt-filebrowser'):
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

    @pyqtSlot(str)
    def _set_fileview_root(self, path, *, tabbed=False):
        """Set the root path for the file display."""
        separators = os.sep
        if os.altsep is not None:
            separators += os.altsep

        dirname = os.path.dirname(path)

        try:
            if not path:
                pass
            elif path in separators and os.path.isdir(path):
                # Input "/" -> don't strip anything
                pass
            elif path[-1] in separators and os.path.isdir(path):
                # Input like /foo/bar/ -> show /foo/bar/ contents
                path = path.rstrip(separators)
            elif os.path.isdir(dirname) and not tabbed:
                # Input like /foo/ba -> show /foo contents
                path = dirname
            else:
                return
        except OSError:
            log.prompt.exception("Failed to get directory information")
            return

        root = self._file_model.setRootPath(path)
        self._file_view.setRootIndex(root)

    @pyqtSlot(QModelIndex)
    def _insert_path(self, index, *, clicked=True):
        """Handle an element selection.

        Args:
            index: The QModelIndex of the selected element.
            clicked: Whether the element was clicked.
        """
        path = os.path.normpath(self._file_model.filePath(index))
        if clicked:
            path += os.sep
        else:
            # On Windows, when we have C:\foo and tab over .., we get C:\
            path = path.rstrip(os.sep)

        log.prompt.debug('Inserting path {}'.format(path))
        self._lineedit.setText(path)
        self._lineedit.setFocus()
        self._set_fileview_root(path, tabbed=True)
        if clicked:
            # Avoid having a ..-subtree highlighted
            self._file_view.setCurrentIndex(QModelIndex())

    def _init_fileview(self):
        self._file_view = QTreeView(self)
        self._file_model = QFileSystemModel(self)
        self._file_view.setModel(self._file_model)
        self._file_view.clicked.connect(self._insert_path)

        if config.get('ui', 'prompt-filebrowser'):
            self._vbox.addWidget(self._file_view)
        else:
            self._file_view.hide()

        # Only show name
        self._file_view.setHeaderHidden(True)
        for col in range(1, 4):
            self._file_view.setColumnHidden(col, True)
        # Nothing selected initially
        self._file_view.setCurrentIndex(QModelIndex())
        # The model needs to be sorted so we get the correct first/last index
        self._file_model.directoryLoaded.connect(
            lambda: self._file_model.sort(0))

    def accept(self, value=None):
        text = value if value is not None else self._lineedit.text()
        text = downloads.transform_path(text)
        if text is None:
            message.error("Invalid filename")
            return False
        self.question.answer = text
        return True

    def item_focus(self, which):
        # This duplicates some completion code, but I don't see a nicer way...
        assert which in ['prev', 'next'], which
        selmodel = self._file_view.selectionModel()

        parent = self._file_view.rootIndex()
        first_index = self._file_model.index(0, 0, parent)
        row = self._file_model.rowCount(parent) - 1
        last_index = self._file_model.index(row, 0, parent)

        if not first_index.isValid():
            # No entries
            return

        assert last_index.isValid()

        idx = selmodel.currentIndex()
        if not idx.isValid():
            # No item selected yet
            idx = last_index if which == 'prev' else first_index
        elif which == 'prev':
            idx = self._file_view.indexAbove(idx)
        else:
            assert which == 'next', which
            idx = self._file_view.indexBelow(idx)

        # wrap around if we arrived at beginning/end
        if not idx.isValid():
            idx = last_index if which == 'prev' else first_index

        selmodel.setCurrentIndex(
            idx, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
        self._insert_path(idx, clicked=False)

    def _allowed_commands(self):
        return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
Esempio n. 2
0
class FilenamePrompt(_BasePrompt):

    """A prompt for a filename."""

    def __init__(self, question, parent=None):
        super().__init__(question, parent)
        self._init_texts(question)
        self._init_key_label()

        self._lineedit = LineEdit(self)
        if question.default:
            self._lineedit.setText(question.default)
        self._lineedit.textEdited.connect(self._set_fileview_root)
        self._vbox.addWidget(self._lineedit)

        self.setFocusProxy(self._lineedit)

        self._init_fileview()
        self._set_fileview_root(question.default)

        if config.val.prompt.filebrowser:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        self._to_complete = ''

    @pyqtSlot(str)
    def _set_fileview_root(self, path, *, tabbed=False):
        """Set the root path for the file display."""
        separators = os.sep
        if os.altsep is not None:
            separators += os.altsep

        dirname = os.path.dirname(path)
        basename = os.path.basename(path)
        if not tabbed:
            self._to_complete = ''

        try:
            if not path:
                pass
            elif path in separators and os.path.isdir(path):
                # Input "/" -> don't strip anything
                pass
            elif path[-1] in separators and os.path.isdir(path):
                # Input like /foo/bar/ -> show /foo/bar/ contents
                path = path.rstrip(separators)
            elif os.path.isdir(dirname) and not tabbed:
                # Input like /foo/ba -> show /foo contents
                path = dirname
                self._to_complete = basename
            else:
                return
        except OSError:
            log.prompt.exception("Failed to get directory information")
            return

        root = self._file_model.setRootPath(path)
        self._file_view.setRootIndex(root)

    @pyqtSlot(QModelIndex)
    def _insert_path(self, index, *, clicked=True):
        """Handle an element selection.

        Args:
            index: The QModelIndex of the selected element.
            clicked: Whether the element was clicked.
        """
        if index == QModelIndex():
            path = os.path.join(self._file_model.rootPath(), self._to_complete)
        else:
            path = os.path.normpath(self._file_model.filePath(index))

        if clicked:
            path += os.sep
        else:
            # On Windows, when we have C:\foo and tab over .., we get C:\
            path = path.rstrip(os.sep)

        log.prompt.debug('Inserting path {}'.format(path))
        self._lineedit.setText(path)
        self._lineedit.setFocus()
        self._set_fileview_root(path, tabbed=True)
        if clicked:
            # Avoid having a ..-subtree highlighted
            self._file_view.setCurrentIndex(QModelIndex())

    def _init_fileview(self):
        self._file_view = QTreeView(self)
        self._file_model = QFileSystemModel(self)
        self._file_view.setModel(self._file_model)
        self._file_view.clicked.connect(self._insert_path)

        if config.val.prompt.filebrowser:
            self._vbox.addWidget(self._file_view)
        else:
            self._file_view.hide()

        # Only show name
        self._file_view.setHeaderHidden(True)
        for col in range(1, 4):
            self._file_view.setColumnHidden(col, True)
        # Nothing selected initially
        self._file_view.setCurrentIndex(QModelIndex())
        # The model needs to be sorted so we get the correct first/last index
        self._file_model.directoryLoaded.connect(
            lambda: self._file_model.sort(0))

    def accept(self, value=None, save=False):
        self._check_save_support(save)
        text = value if value is not None else self._lineedit.text()
        text = downloads.transform_path(text)
        if text is None:
            message.error("Invalid filename")
            return False
        self.question.answer = text
        return True

    def item_focus(self, which):
        # This duplicates some completion code, but I don't see a nicer way...
        assert which in ['prev', 'next'], which
        selmodel = self._file_view.selectionModel()

        parent = self._file_view.rootIndex()
        first_index = self._file_model.index(0, 0, parent)
        row = self._file_model.rowCount(parent) - 1
        last_index = self._file_model.index(row, 0, parent)

        if not first_index.isValid():
            # No entries
            return

        assert last_index.isValid()

        idx = selmodel.currentIndex()

        if not idx.isValid():
            # No item selected yet
            idx = last_index if which == 'prev' else first_index
        elif which == 'prev':
            idx = self._file_view.indexAbove(idx)
        else:
            assert which == 'next', which
            idx = self._file_view.indexBelow(idx)

        # wrap around if we arrived at beginning/end
        if not idx.isValid():
            idx = last_index if which == 'prev' else first_index

        idx = self._do_completion(idx, which)

        selmodel.setCurrentIndex(
            idx,
            QItemSelectionModel.ClearAndSelect |  # type: ignore[arg-type]
            QItemSelectionModel.Rows)
        self._insert_path(idx, clicked=False)

    def _do_completion(self, idx, which):
        filename = self._file_model.fileName(idx)
        while not filename.startswith(self._to_complete) and idx.isValid():
            if which == 'prev':
                idx = self._file_view.indexAbove(idx)
            else:
                assert which == 'next', which
                idx = self._file_view.indexBelow(idx)
            filename = self._file_model.fileName(idx)

        return idx

    def _allowed_commands(self):
        return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
Esempio n. 3
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'PyQt5 file system view - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.default_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files/examples'))
        self.user_path = (os.path.join('/media'))
        self.currentPath = None
        self.EXT = INFO.PROGRAM_FILTERS_EXTENSIONS
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.setNameFilters(self.EXT)

        self.list = QListView()
        self.list.setModel(self.model)
        self.updateDirectoryView(self.default_path)
        self.list.setWindowTitle("Dir View")
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.clicked)
        self.list.activated.connect(self._getPathActivated)
        #self.list.currentChanged = self.currentChanged
        self.list.setAlternatingRowColors(True)

        self.cb = QComboBox()
        self.cb.currentTextChanged.connect(self.filterChanged)
        self.cb.addItems(self.EXT)
        #self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.button = QPushButton()
        self.button.setText('Media')
        self.button.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button.setToolTip('Jump to Media directory')
        self.button.clicked.connect(self.onMediaClicked)

        self.button2 = QPushButton()
        self.button2.setText('User')
        self.button2.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setToolTip('Jump to linuxcnc directory')
        self.button2.clicked.connect(self.onUserClicked)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button)
        hbox.addWidget(self.button2)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addWidget(self.list)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    # this could return the current/previous selected as it's selected.
    # need to uncomment monkey patch of self.list.currentChanged above
    # so far this is not needed
    def currentChanged(self,c,p):
        dir_path = self.model.filePath(c)
        print('-> ',dir_path)

    def updateDirectoryView(self, path):
        self.list.setRootIndex(self.model.setRootPath(path))

    def filterChanged(self, text):
        self.model.setNameFilters([text])

    def clicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)

    def onMediaClicked(self):
        self.updateDirectoryView(self.user_path)

    def onUserClicked(self):
        self.updateDirectoryView(self.default_path)

    def select_row(self, style):
        style = style.lower()
        selectionModel = self.list.selectionModel()
        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(self.list.rootIndex())

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows:
                row += 1
            else:
                row = self.rows
        else:
            return
        top = self.model.index(row, 0, self.list.rootIndex())
        selectionModel.setCurrentIndex(top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    # returns the current highlighted (selected) path as well as
    # whether it's a file or not.
    def getCurrentSelected(self):
        selectionModel = self.list.selectionModel()
        index = selectionModel.currentIndex()
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            return (dir_path, True)
        else:
            return (dir_path, False)

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_loaded_directory', self.default_path, str, 'BOOK_KEEPING')
            self.updateDirectoryView(last_path)
            LOG.debug("lAST FILE PATH: {}".format(last_path))
        else:
            LOG.debug("lAST FILE PATH: {}".format(self.default_path))
            self.updateDirectoryView(self.default_path)

    # get current selection and update the path
    # then if the path is good load it into linuxcnc
    # record it in the preference file if available
    def _getPathActivated(self):
        row = self.list.selectionModel().currentIndex()
        self.clicked(row)

        fname = self.currentPath
        if fname is None: 
            return
        if fname:
            self.load(fname)

    # this can be class patched to do something else
    def load(self, fname=None):
        if fname is None:
            self._getPathActivated()
            return
        self.recordBookKeeping()
        ACTION.OPEN_PROGRAM(fname)
        STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')

    # this can be class patched to do something else
    def recordBookKeeping(self):
        fname = self.currentPath
        if fname is None: 
            return
        if self.PREFS_:
            self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING')
            self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')

    # moves the selection up
    # used with MPG scrolling
    def up(self):
        self.select_row('up')

    # moves the selection down
    # used with MPG scrolling
    def down(self):
        self.select_row('down')
Esempio n. 4
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'PyQt5 file system view - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.default_path = (os.path.join(os.path.expanduser('~'),
                                          'labvcnc/nc_files/examples'))
        self.user_path = (os.path.join('/media'))
        self.currentPath = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.setNameFilters(["*.ngc", '*.py'])

        self.list = QListView()
        self.list.setModel(self.model)
        self.updateDirectoryView(self.default_path)
        self.list.setWindowTitle("Dir View")
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.clicked)
        self.list.activated.connect(self.load)
        self.list.setAlternatingRowColors(True)

        self.cb = QComboBox()
        self.cb.currentTextChanged.connect(self.filterChanged)
        self.cb.addItems(sorted({'*.ngc', '*.py', '*'}))
        #self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.button = QPushButton()
        self.button.setText('Media')
        self.button.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button.setToolTip('Jump to Media directory')
        self.button.clicked.connect(self.onMediaClicked)

        self.button2 = QPushButton()
        self.button2.setText('User')
        self.button2.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setToolTip('Jump to labvcnc directory')
        self.button2.clicked.connect(self.onUserClicked)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button)
        hbox.addWidget(self.button2)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addWidget(self.list)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    def updateDirectoryView(self, path):
        self.list.setRootIndex(self.model.setRootPath(path))

    def filterChanged(self, text):
        self.model.setNameFilters([text])

    def clicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)

    def onMediaClicked(self):
        self.updateDirectoryView(self.user_path)

    def onUserClicked(self):
        self.updateDirectoryView(self.default_path)

    def select_row(self, style):
        style = style.lower()
        selectionModel = self.list.selectionModel()
        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(self.list.rootIndex())

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows:
                row += 1
            else:
                row = self.rows
        else:
            return
        top = self.model.index(row, 0, self.list.rootIndex())
        selectionModel.setCurrentIndex(
            top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_file_path',
                                            self.default_path, str,
                                            'BOOK_KEEPING')
            self.updateDirectoryView(last_path)
            LOG.debug("lAST FILE PATH: {}".format(last_path))
        else:
            LOG.debug("lAST FILE PATH: {}".format(self.default_path))
            self.updateDirectoryView(self.default_path)

    # get current selection and update the path
    # then if the path is good load it into labvcnc
    # record it in the preference file if available
    def load(self):
        row = self.list.selectionModel().currentIndex()
        self.clicked(row)

        fname = self.currentPath
        if fname is None:
            return
        if fname:
            if self.PREFS_:
                self.PREFS_.putpref('last_file_path', fname, str,
                                    'BOOK_KEEPING')
            ACTION.OPEN_PROGRAM(fname)
            STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')

    def up(self):
        self.select_row('up')

    def down(self):
        self.select_row('down')
Esempio n. 5
0
class Ui(QtWidgets.QMainWindow):
    """Main Class of the simple DMS user interface.

    Arguments:
        nothing

    Returns:
        nothing

    """
    def __init__(self):
        """Initialize variables and connect actions with functions."""
        super(Ui, self).__init__()
        uic.loadUi(os.path.join(CURRDIR, "ui", "main_simpledms.ui"), self)
        self.loadpref()
        self.rules = rules.Rules(self.pref["dmsroot"])
        self.currentselectedrulesfolder = None
        self.currentselectedsearchfolder = None
        self.current_monitorfolder_index = None
        self.parent_index = None
        self.filemodelmonitor = QFileSystemModel()
        self.rulesfoldermodel = QFileSystemModel()
        self.resultfoldermodel = QFileSystemModel()
        self.searchfoldermodel = QFileSystemModel()
        self.textEdit_tags = MyTextEdit(self.textEdit_tags)
        self.updateui_settings()
        self.updateui_pdfrename()
        self.show()

        # Connect Widget Toolbar Actions
        self.actionScan.triggered.connect(self.select_widget)
        self.actionPdf.triggered.connect(self.select_widget)
        self.actionSettings.triggered.connect(self.select_widget)
        self.actionAbout.triggered.connect(self.show_ui_about)
        self.actionExit.triggered.connect(self.select_widget)

        # Connect Preferences
        self.pushButton_setmonitorfolder.clicked.connect(
            self.browse_monitor_folder)
        self.pushButton_setdmsroot.clicked.connect(self.browse_dms_root)
        self.treeView_rulesfolders.clicked.connect(self.rulesfolderselected)
        self.treeView_rules.doubleClicked.connect(self.ruledoubleclicked)
        self.pushButton_addrule.clicked.connect(self.addruleclicked)
        self.pushButton_deleterule.clicked.connect(self.deleteruleclicked)

        # Connect page pdf renaming
        self.listView_monitorfiles.clicked.connect(
            self.listView_monitorfiles_clicked)

        self.treeView_output.clicked.connect(self.treeView_output_clicked)
        self.pushButton_ok.clicked.connect(self.pushButton_ok_clicked)
        self.listView_monitorfiles.doubleClicked.connect(
            self.listView_monitorfiles_doubleclicked)
        self.lineEdit_outputfilename.textChanged.connect(self.readyforstorage)
        self.pushButton_addDate.clicked.connect(
            self.pushButton_addDate_clicked)

    # -------- Settings page -----------
    def rulesfolderselected(self, signal):
        """Update ui if a folder in settings -> rules is selected."""
        self.currentselectedrulesfolder = self.rulesfoldermodel.filePath(
            signal)
        self.updateui_settings()
        self.pushButton_addrule.setEnabled(True)

    def ruledoubleclicked(self):
        """Open ui for rule adaption of double clicked rule."""
        selectedrule = self.treeView_rules_model.itemData(
            self.treeView_rules.selectedIndexes()[0])
        rule = self.rules.returnruleofkeywords([selectedrule[0]],
                                               self.currentselectedrulesfolder)
        rulesdialog = MyRulesWidget(
            keywords=rule[0][1],
            booleanoperator=rule[0][2],
            tags=rule[0][3],
            doctitle=rule[0][4],
            indexertags=set(self.rules.returnalltags()),
        )
        rulesdialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        if rulesdialog.exec_():
            self.rules.replacerule(
                rule[0][0],
                rulesdialog.keywords,
                rulesdialog.booleanoperator,
                rulesdialog.tags,
                rulesdialog.doctitle,
                self.currentselectedrulesfolder,
            )
            self.updateui_settings()

    def deleteruleclicked(self):
        """Delete selected rule and update ui."""
        if self.treeView_rules.selectedIndexes():
            selectedrule = self.treeView_rules_model.itemData(
                self.treeView_rules.selectedIndexes()[0])
            self.rules.delrule([selectedrule[0]],
                               self.currentselectedrulesfolder)
            self.updateui_settings()

    def addruleclicked(self):
        """Add rule to database if it does not exist yet."""
        rulesdialog = MyRulesWidget(
            indexertags=set(self.rules.returnalltags()))
        rulesdialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        if rulesdialog.exec_():
            if self.rules.returnruleofkeywords(
                    rulesdialog.keywords, self.currentselectedrulesfolder):
                QtWidgets.QMessageBox.information(
                    self, "Error",
                    "A rule with these keywords already exists.")
            else:
                self.rules.addrule(
                    rulesdialog.keywords,
                    rulesdialog.booleanoperator,
                    rulesdialog.tags,
                    rulesdialog.doctitle,
                    self.currentselectedrulesfolder,
                )
                self.updateui_settings()

    def loadpref(self):
        """Load preferences: root of dms and monitorfolder."""
        if os.path.isfile("pref.json"):
            with open("pref.json") as f:
                self.pref = json.load(f)
                if not os.path.isdir(self.pref["dmsroot"]):
                    os.makedirs(self.pref["dmsroot"])
                    QtWidgets.QMessageBox.information(
                        self, "Attention!",
                        "Stored path of dmsroot does not exist")
                if not os.path.isdir(self.pref["monitorfolder"]):
                    os.makedirs(self.pref["monitorfolder"])
                    QtWidgets.QMessageBox.information(
                        self,
                        "Attention!",
                        "Stored path of monitorfolder does not exist.",
                    )
        else:
            # If pref.json file does not exist
            if not os.path.isdir(
                    os.path.join(os.path.expanduser("~"), "paperwork")):
                os.makedirs(os.path.join(os.path.expanduser("~"), "paperwork"))
                QtWidgets.QMessageBox.information(
                    self,
                    "Attention!",
                    "Standard path for file cabinet"
                    "was created. If "
                    "needed, please change.",
                )

            if not os.path.isdir(
                    os.path.join(os.path.expanduser("~"), "paperwork_open")):
                os.makedirs(
                    os.path.join(os.path.expanduser("~"), "paperwork_open"))
                QtWidgets.QMessageBox.information(
                    self,
                    "Attention!",
                    "Standard path for monitor folder"
                    "was created. If "
                    "needed, please change.",
                )

            self.pref = {
                "dmsroot":
                os.path.join(os.path.expanduser("~"), "paperwork"),
                "monitorfolder":
                os.path.join(os.path.expanduser("~"), "paperwork_open"),
            }
            self.savepref()

    def savepref(self):
        """Save preferences to pref.json."""
        with open("pref.json", "w") as f:
            json.dump(self.pref, f)

    def browse_monitor_folder(self):
        """Select monitor folder."""
        # execute getExistingDirectory dialog and set the directory variable to be equal
        # to the user selected directory
        directory = QFileDialog.getExistingDirectory(
            self, "Select a monitor folder with files to be "
            "processed/imported")
        # if user didn't pick a directory don't continue
        if directory:
            self.pref["monitorfolder"] = directory
            self.savepref()
            self.updateui_settings()
            self.updateui_pdfrename()

    def browse_dms_root(self):
        """Select dms root folder."""
        # execute getExistingDirectory dialog and set the directory variable to be equal
        # to the user selected directory
        directory = QFileDialog.getExistingDirectory(
            self, "Select a root directory of the filing cabinet")
        # if user didn't pick a directory don't continue
        if directory:
            if not len(self.rules.returnallrules()) == 0:
                result = QtWidgets.QMessageBox.question(
                    self,
                    "Attention",
                    "If the root directory is changed, the current rules are "
                    "deleted! Are you sure and want to proceed?",
                )
                if result == QtWidgets.QMessageBox.No:
                    return
            self.rules.resetdb(directory)
            self.pref["dmsroot"] = directory
            self.savepref()
            # self.indexer.__init__(directory)
            self.updateui_settings()

    def updateui_settings(self):
        """Update ui elements of settings page."""
        self.label_monitorfolder.setText(self.pref["monitorfolder"])
        self.label_monitordir.setText(
            ".." + os.sep +
            os.path.basename(os.path.normpath(self.pref["monitorfolder"])))
        self.label_dmsroot.setText(self.pref["dmsroot"])
        self.rulesfoldermodel.setRootPath(self.pref["dmsroot"])
        self.rulesfoldermodel.setFilter(QtCore.QDir.NoDotAndDotDot
                                        | QtCore.QDir.Dirs)
        self.treeView_rulesfolders.setModel(self.rulesfoldermodel)
        self.treeView_rulesfolders.setRootIndex(
            self.rulesfoldermodel.index(self.pref["dmsroot"]))
        self.treeView_rulesfolders.hideColumn(1)
        self.treeView_rulesfolders.hideColumn(2)
        self.treeView_rulesfolders.hideColumn(3)
        self.treeView_rules_model = QtGui.QStandardItemModel()
        self.treeView_rules.setModel(self.treeView_rules_model)
        self.treeView_rules_model.setHorizontalHeaderLabels(
            ["Rules (keywords)"])
        rulesoffolder = self.rules.returnrulesoffolder(
            self.currentselectedrulesfolder)
        if rulesoffolder is not None:
            for i in rulesoffolder:
                rule = QtGui.QStandardItem(i[1])
                self.treeView_rules_model.appendRow(rule)

    # -------- Action Bar -----------
    def select_widget(self):
        """Select index of stacked widget based on toolbox actions."""
        sender = self.sender()
        if sender.text() == "Scan":
            pass
        elif sender.text() == "Import":
            self.stackedWidget.setCurrentIndex(0)
        elif sender.text() == "Settings":
            self.stackedWidget.setCurrentIndex(1)
        elif sender.text() == "Exit":
            QtWidgets.QApplication.instance().quit()

    def show_ui_about(self):
        """Show about page."""
        dialog = QDialog()
        dialog.ui = ui.about.Ui_Dialog()
        dialog.ui.setupUi(dialog)
        dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        dialog.exec_()

    # -------- pdf renaming page -----------
    def listView_monitorfiles_clicked(self, index):
        """Show preview of pdf, extract date and words and propose tags and directory in dms root."""
        self.current_monitorfolder_index = index
        pdffile = os.path.join(self.pref["monitorfolder"],
                               self.filemodelmonitor.itemData(index)[0])

        # Check if file is really a pdf.
        if "PDF" not in magic.from_file(pdffile):
            QtWidgets.QMessageBox.information(self, "Attention!",
                                              "Document is not a pdf.")
            return

        self.listView_monitorfiles.setEnabled(False)
        self.setCursor(QtCore.Qt.BusyCursor)
        self.statusbar.showMessage("Reading pdf...")

        self.pdfhandler = PdfHandler(pdffile)
        self.pdfhandler.thumbheight = (
            self.listView_monitorfiles.frameGeometry().height())
        self.pdfhandler.createthumbnail()

        pixmap = QtGui.QPixmap(self.pdfhandler.thumbfpath)
        self.thumbnail.setPixmap(pixmap)
        self.thumbnail.resize(pixmap.width(), pixmap.height())
        self.analyze_text()
        if self.readyforstorage():
            self.statusbar.showMessage("Automatic renaming and moving file...")
            # self.pushButton_ok_clicked()
        self.listView_monitorfiles.setEnabled(True)
        self.setCursor(QtCore.Qt.ArrowCursor)
        self.statusbar.showMessage("Ready")

    def listView_monitorfiles_doubleclicked(self, index):
        """Open doubleclicked file.

        Arguments:
            index: index from pyqt5 listview which element was clicked.

        Returns:
            nothing

        """
        file2open = os.path.join(self.pref["monitorfolder"],
                                 self.filemodelmonitor.itemData(index)[0])
        webbrowser.open(file2open)

    def listWidget_pdfthumbnails_doubleclicked(self):
        """Open file in browser."""
        file2open = self.pdfhandler.filepath
        if os.path.isfile(file2open):
            webbrowser.open(file2open)
        else:
            QtWidgets.QMessageBox.information(self, "Attention!",
                                              "File does not exist!")

    def analyze_text(self):
        """Analyze the found text."""
        text = self.pdfhandler.gettext()
        dateext = DateExtractor(text)
        date = dateext.getdate()
        # If Date not found in text, search for date in filename
        if not date:
            dateext = DateExtractor(self.pdfhandler.filepath)
            date = dateext.getdate()
        result = self.rules.applyrule(text)

        if result["doctitle"] is not None:
            if date is not None:
                self.lineEdit_outputfilename.setText(
                    date.strftime("%Y-%m-%d") + " " + result["doctitle"])
            else:
                self.lineEdit_outputfilename.setText(result["doctitle"])
        else:
            if date is not None:
                self.lineEdit_outputfilename.setText(
                    date.strftime("%Y-%m-%d") + " ")
            else:
                self.lineEdit_outputfilename.clear()

        if result["tags"] is not None:
            self.textEdit_tags.setText(result["tags"])
        else:
            self.textEdit_tags.clear()

        self.destination = result["destination"]

        self.treeView_output.setCurrentIndex(
            self.resultfoldermodel.index(self.destination))

        if not self.readyforstorage():
            self.lineEdit_outputfilename.setFocus()
        else:
            self.pushButton_ok.setFocus()

        self.statusbar.showMessage("Ready")
        self.setCursor(QtCore.Qt.ArrowCursor)

    def readyforstorage(self) -> bool:
        """Check if file infos like date, text, tags and folder are set."""
        if (self.lineEdit_outputfilename.text() and re.match(
                r"(\d{4}-\d{2}-\d{2}\s\S+)",
                self.lineEdit_outputfilename.text(),
                re.I | re.UNICODE,
        ) and self.resultfoldermodel.filePath(
                self.treeView_output.currentIndex())):
            self.pushButton_ok.setEnabled(True)
            return True
        else:
            self.pushButton_ok.setEnabled(False)
            return False

    def pushButton_ok_clicked(self):
        """Store document with new metadata in target directory."""
        self.setCursor(QtCore.Qt.BusyCursor)
        self.statusbar.showMessage("Storing...")
        doctitle = self.lineEdit_outputfilename.text()[11:]
        date = self.lineEdit_outputfilename.text()[0:10]
        tags = self.textEdit_tags.toPlainText()
        tags = tags.strip(", ")
        path = self.resultfoldermodel.filePath(
            self.treeView_output.currentIndex())
        self.pdfhandler.update_and_move(path, doctitle, tags, date)
        self.updateui_pdfrename()
        self.setCursor(QtCore.Qt.ArrowCursor)
        row = self.current_monitorfolder_index.row()
        n_elements = self.filemodelmonitor.rowCount(self.parent_index)
        if row + 1 < n_elements and n_elements > 0:
            self.listView_monitorfiles_clicked(
                self.current_monitorfolder_index.sibling(row + 1, 0))
        if row + 1 >= n_elements and n_elements > 1:
            self.listView_monitorfiles_clicked(
                self.current_monitorfolder_index.sibling(row - 1, 0))
        self.updateui_pdfrename()
        self.statusbar.showMessage("ready")

    def pushButton_addDate_clicked(self):
        """Add current date to document name field."""
        if self.lineEdit_outputfilename.text():
            if re.match(r"(\d{4}-\d{2}-\d{2})",
                        self.lineEdit_outputfilename.text()):
                text = (str(datetime.date.today()) +
                        self.lineEdit_outputfilename.text()[10:])
                self.lineEdit_outputfilename.setText(text)
            else:
                self.lineEdit_outputfilename.setText(
                    str(datetime.date.today()) + " ")
        else:
            self.lineEdit_outputfilename.setText(
                str(datetime.date.today()) + " ")
        self.lineEdit_outputfilename.setFocus()

    def treeView_output_clicked(self):
        """Check if all input is available after the target directory was selected."""
        self.readyforstorage()

    def updateui_pdfrename(self):
        """Update ui of page pdfrename."""
        self.filemodelmonitor.setFilter(QtCore.QDir.NoDotAndDotDot
                                        | QtCore.QDir.Files)
        self.filemodelmonitor.setNameFilters(["*.pdf"])
        self.filemodelmonitor.setNameFilterDisables(False)
        self.parent_index = self.filemodelmonitor.setRootPath(
            self.pref["monitorfolder"])
        self.listView_monitorfiles.setModel(self.filemodelmonitor)
        self.listView_monitorfiles.setRootIndex(
            self.filemodelmonitor.index(self.pref["monitorfolder"]))
        self.resultfoldermodel.setRootPath(self.pref["dmsroot"])
        self.resultfoldermodel.setFilter(QtCore.QDir.NoDotAndDotDot
                                         | QtCore.QDir.Dirs)
        self.treeView_output.setModel(self.resultfoldermodel)
        self.treeView_output.setRootIndex(
            self.resultfoldermodel.index(self.pref["dmsroot"]))
        self.treeView_output.hideColumn(1)
        self.treeView_output.hideColumn(2)
        self.treeView_output.hideColumn(3)
        indexertags = set(self.rules.returnalltags())
        completer = MyDictionaryCompleter(myKeywords=indexertags)
        self.textEdit_tags.setCompleter(completer)
Esempio n. 6
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'Qtvcp File System View'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self._last = 0

        if INFO.PROGRAM_PREFIX is not None:
            self.user_path = os.path.expanduser(INFO.PROGRAM_PREFIX)
        else:
            self.user_path = (os.path.join(os.path.expanduser('~'),
                                           'linuxcnc/nc_files'))
        user = os.path.split(os.path.expanduser('~'))[-1]
        self.media_path = (os.path.join('/media', user))
        temp = [('User', self.user_path), ('Media', self.media_path)]
        self._jumpList = OrderedDict(temp)
        self.currentPath = None
        self.currentFolder = None
        self.PREFS_ = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        pasteBox = QHBoxLayout()
        self.textLine = QLineEdit()
        self.textLine.setToolTip('Current Director/selected File')
        self.pasteButton = QToolButton()
        self.pasteButton.setEnabled(False)
        self.pasteButton.setText('Paste')
        self.pasteButton.setToolTip(
            'Copy file from copy path to current directory/file')
        self.pasteButton.clicked.connect(self.paste)
        self.pasteButton.hide()
        pasteBox.addWidget(self.textLine)
        pasteBox.addWidget(self.pasteButton)

        self.copyBox = QFrame()
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        self.copyLine = QLineEdit()
        self.copyLine.setToolTip('File path to copy from, when pasting')
        self.copyButton = QToolButton()
        self.copyButton.setText('Copy')
        self.copyButton.setToolTip('Record current file as copy path')
        self.copyButton.clicked.connect(self.recordCopyPath)
        hbox.addWidget(self.copyButton)
        hbox.addWidget(self.copyLine)
        self.copyBox.setLayout(hbox)
        self.copyBox.hide()

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.rootPathChanged.connect(self.folderChanged)

        self.list = QListView()
        self.list.setModel(self.model)
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.listClicked)
        self.list.activated.connect(self._getPathActivated)
        self.list.setAlternatingRowColors(True)
        self.list.hide()

        self.table = QTableView()
        self.table.setModel(self.model)
        self.table.resize(640, 480)
        self.table.clicked[QModelIndex].connect(self.listClicked)
        self.table.activated.connect(self._getPathActivated)
        self.table.setAlternatingRowColors(True)

        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
        header.swapSections(1, 3)
        header.setSortIndicator(1, Qt.AscendingOrder)

        self.table.setSortingEnabled(True)
        self.table.setColumnHidden(2, True)  # type
        self.table.verticalHeader().setVisible(False)  # row count header

        self.cb = QComboBox()
        self.cb.currentIndexChanged.connect(self.filterChanged)
        self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS)
        self.cb.setMinimumHeight(30)
        self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,
                                          QSizePolicy.Fixed))

        self.button2 = QToolButton()
        self.button2.setText('User')
        self.button2.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setMinimumSize(60, 30)
        self.button2.setToolTip(
            'Jump to User directory.\nLong press for Options.')
        self.button2.clicked.connect(self.onJumpClicked)

        self.button3 = QToolButton()
        self.button3.setText('Add Jump')
        self.button3.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button3.setMinimumSize(60, 30)
        self.button3.setToolTip('Add current directory to jump button list')
        self.button3.clicked.connect(self.onActionClicked)

        self.settingMenu = QMenu(self)
        self.button2.setMenu(self.settingMenu)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button2)
        hbox.addWidget(self.button3)
        hbox.insertStretch(2, stretch=0)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addLayout(pasteBox)
        windowLayout.addWidget(self.copyBox)
        windowLayout.addWidget(self.list)
        windowLayout.addWidget(self.table)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_loaded_directory',
                                            self.user_path, str,
                                            'BOOK_KEEPING')
            LOG.debug("lAST FILE PATH: {}".format(last_path))
            if not last_path == '':
                self.updateDirectoryView(last_path)
            else:
                self.updateDirectoryView(self.user_path)

            # get all the saved jumplist paths
            temp = self.PREFS_.getall('FILEMANAGER_JUMPLIST')
            self._jumpList.update(temp)

        else:
            LOG.debug("lAST FILE PATH: {}".format(self.user_path))
            self.updateDirectoryView(self.user_path)

        # install jump paths into toolbutton menu
        for i in self._jumpList:
            self.addAction(i)

        # set recorded columns sort settings
        self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName()))
        sect = self.SETTINGS_.value('sortIndicatorSection', type=int)
        order = self.SETTINGS_.value('sortIndicatorOrder', type=int)
        self.SETTINGS_.endGroup()
        if not None in (sect, order):
            self.table.horizontalHeader().setSortIndicator(sect, order)

    # when qtvcp closes this gets called
    # record jump list paths
    def _hal_cleanup(self):
        if self.PREFS_:
            for i, key in enumerate(self._jumpList):
                if i in (0, 1):
                    continue
                self.PREFS_.putpref(key, self._jumpList.get(key), str,
                                    'FILEMANAGER_JUMPLIST')

        # record sorted columns
        h = self.table.horizontalHeader()
        self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName()))
        self.SETTINGS_.setValue('sortIndicatorSection',
                                h.sortIndicatorSection())
        self.SETTINGS_.setValue('sortIndicatorOrder', h.sortIndicatorOrder())
        self.SETTINGS_.endGroup()

    #########################
    # callbacks
    #########################

    # add shown text and hidden filter data from the INI
    def fillCombobox(self, data):
        for i in data:
            self.cb.addItem(i[0], i[1])

    def folderChanged(self, data):
        data = os.path.normpath(data)
        self.currentFolder = data
        self.textLine.setText(data)

    def updateDirectoryView(self, path, quiet=False):
        if os.path.exists(path):
            self.list.setRootIndex(self.model.setRootPath(path))
            self.table.setRootIndex(self.model.setRootPath(path))
        else:
            LOG.debug(
                "Set directory view error - no such path {}".format(path))
            if not quiet:
                STATUS.emit(
                    'error', LOW_ERROR,
                    "File Manager error - No such path: {}".format(path))

    # retrieve selected filter (it's held as QT.userData)
    def filterChanged(self, index):
        userdata = self.cb.itemData(index)
        self.model.setNameFilters(userdata)

    def listClicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = os.path.normpath(self.model.filePath(index))
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            self.textLine.setText(self.currentPath)
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)
        self.table.setRootIndex(root_index)

    def onUserClicked(self):
        self.showUserDir()

    def onMediaClicked(self):
        self.showMediaDir()

    # jump directly to a saved path shown on the button
    def onJumpClicked(self):
        data = self.button2.text()
        if data.upper() == 'MEDIA':
            self.showMediaDir()
        elif data.upper() == 'USER':
            self.showUserDir()
        else:
            temp = self._jumpList.get(data)
            if temp is not None:
                self.updateDirectoryView(temp)
            else:
                STATUS.emit('error', linuxcnc.OPERATOR_ERROR,
                            'file jumopath: {} not valid'.format(data))
                log.debug('file jumopath: {} not valid'.format(data))

    # jump directly to a saved path from the menu
    def jumpTriggered(self, data):
        if data.upper() == 'MEDIA':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip(
                'Jump to Media directory.\nLong press for Options.')
            self.showMediaDir()
        elif data.upper() == 'USER':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip(
                'Jump to User directory.\nLong press for Options.')
            self.showUserDir()
        else:
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to directory:\n{}'.format(
                self._jumpList.get(data)))
            self.updateDirectoryView(self._jumpList.get(data))

    # add a jump list path
    def onActionClicked(self):
        i = self.currentFolder
        try:
            self._jumpList[i] = i
        except Exception as e:
            print(e)
        button = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        button.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(button)

    # get current selection and update the path
    # then if the path is good load it into linuxcnc
    # record it in the preference file if available
    def _getPathActivated(self):
        if self.list.isVisible():
            row = self.list.selectionModel().currentIndex()
        else:
            row = self.table.selectionModel().currentIndex()
            self.listClicked(row)

        fname = self.currentPath
        if fname is None:
            return
        if fname:
            self.load(fname)

    def recordCopyPath(self):
        data, isFile = self.getCurrentSelected()
        if isFile:
            self.copyLine.setText(os.path.normpath(data))
            self.pasteButton.setEnabled(True)
        else:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)
            STATUS.emit('error', OPERATOR_ERROR,
                        'Can only copy a file, not a folder')

    def paste(self):
        res = self.copyFile(self.copyLine.text(), self.textLine.text())
        if res:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)

    ########################
    # helper functions
    ########################

    def addAction(self, i):
        axisButton = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        axisButton.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(axisButton)

    def showList(self, state=True):
        if state:
            self.table.hide()
            self.list.show()
        else:
            self.table.show()
            self.list.hide()

    def showTable(self, state=True):
        self.showList(not state)

    def showCopyControls(self, state):
        if state:
            self.copyBox.show()
            self.pasteButton.show()
        else:
            self.copyBox.hide()
            self.pasteButton.hide()

    def showMediaDir(self, quiet=False):
        self.updateDirectoryView(self.media_path, quiet)

    def showUserDir(self, quiet=False):
        self.updateDirectoryView(self.user_path, quiet)

    def copyFile(self, s, d):
        try:
            shutil.copy(s, d)
            return True
        except Exception as e:
            LOG.error("Copy file error: {}".format(e))
            STATUS.emit('error', OPERATOR_ERROR,
                        "Copy file error: {}".format(e))
            return False

    @pyqtSlot(float)
    @pyqtSlot(int)
    def scroll(self, data):
        if data > self._last:
            self.up()
        elif data < self._last:
            self.down()
        self._last = data

    # moves the selection up
    # used with MPG scrolling
    def up(self):
        self.select_row('up')

    # moves the selection down
    # used with MPG scrolling
    def down(self):
        self.select_row('down')

    def select_row(self, style='down'):
        style = style.lower()
        if self.list.isVisible():
            i = self.list.rootIndex()
            selectionModel = self.list.selectionModel()
        else:
            i = self.table.rootIndex()
            selectionModel = self.table.selectionModel()

        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(i)

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows - 1:
                row += 1
            else:
                row = self.rows - 1
        else:
            return
        top = self.model.index(row, 0, i)
        selectionModel.setCurrentIndex(
            top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    # returns the current highlighted (selected) path as well as
    # whether it's a file or not.
    def getCurrentSelected(self):
        if self.list.isVisible():
            selectionModel = self.list.selectionModel()
        else:
            selectionModel = self.table.selectionModel()
        index = selectionModel.currentIndex()
        dir_path = os.path.normpath(self.model.filePath(index))
        if self.model.fileInfo(index).isFile():
            return (dir_path, True)
        else:
            return (dir_path, False)

    # This can be class patched to do something else
    def load(self, fname=None):
        try:
            if fname is None:
                self._getPathActivated()
                return
            self.recordBookKeeping()
            ACTION.OPEN_PROGRAM(fname)
            STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')
        except Exception as e:
            LOG.error("Load file error: {}".format(e))
            STATUS.emit('error', NML_ERROR, "Load file error: {}".format(e))

    # This can be class patched to do something else
    def recordBookKeeping(self):
        fname = self.currentPath
        if fname is None:
            return
        if self.PREFS_:
            self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(),
                                str, 'BOOK_KEEPING')
            self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
Esempio n. 7
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'Qtvcp File System View'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.media_path = (os.path.join(os.path.expanduser('~'),
                                        'linuxcnc/nc_files'))
        user = os.path.split(os.path.expanduser('~'))[-1]
        self.user_path = (os.path.join('/media', user))
        self.currentPath = None
        self.currentFolder = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        pasteBox = QHBoxLayout()
        self.textLine = QLineEdit()
        self.textLine.setToolTip('Current Director/selected File')
        self.pasteButton = QToolButton()
        self.pasteButton.setEnabled(False)
        self.pasteButton.setText('Paste')
        self.pasteButton.setToolTip(
            'Copy file from copy path to current directory/file')
        self.pasteButton.clicked.connect(self.paste)
        self.pasteButton.hide()
        pasteBox.addWidget(self.textLine)
        pasteBox.addWidget(self.pasteButton)

        self.copyBox = QFrame()
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        self.copyLine = QLineEdit()
        self.copyLine.setToolTip('File path to copy from, when pasting')
        self.copyButton = QToolButton()
        self.copyButton.setText('Copy')
        self.copyButton.setToolTip('Record current file as copy path')
        self.copyButton.clicked.connect(self.recordCopyPath)
        hbox.addWidget(self.copyButton)
        hbox.addWidget(self.copyLine)
        self.copyBox.setLayout(hbox)
        self.copyBox.hide()

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.rootPathChanged.connect(self.folderChanged)

        self.list = QListView()
        self.list.setModel(self.model)
        self.updateDirectoryView(self.media_path)
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.listClicked)
        self.list.activated.connect(self._getPathActivated)
        self.list.setAlternatingRowColors(True)

        self.cb = QComboBox()
        self.cb.currentIndexChanged.connect(self.filterChanged)
        self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS)
        self.cb.setMinimumHeight(30)
        self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,
                                          QSizePolicy.Fixed))

        self.button2 = QToolButton()
        self.button2.setText('Media')
        self.button2.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setMinimumSize(60, 30)
        self.button2.setToolTip('Jump to Media directory')
        self.button2.clicked.connect(self.onJumpClicked)

        SettingMenu = QMenu(self)
        self.settingMenu = SettingMenu
        for i in ('Media', 'User'):
            axisButton = QAction(QIcon.fromTheme('user-home'), i, self)
            # weird lambda i=i to work around 'function closure'
            axisButton.triggered.connect(
                lambda state, i=i: self.jumpTriggered(i))
            SettingMenu.addAction(axisButton)
        self.button2.setMenu(SettingMenu)

        self.button3 = QToolButton()
        self.button3.setText('Add Jump')
        self.button3.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button3.setMinimumSize(60, 30)
        self.button3.setToolTip('Add current directory to jump button list')
        self.button3.clicked.connect(self.onActionClicked)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button2)
        hbox.addWidget(self.button3)
        hbox.insertStretch(2, stretch=0)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addLayout(pasteBox)
        windowLayout.addWidget(self.copyBox)
        windowLayout.addWidget(self.list)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_loaded_directory',
                                            self.media_path, str,
                                            'BOOK_KEEPING')
            self.updateDirectoryView(last_path)
            LOG.debug("lAST FILE PATH: {}".format(last_path))
        else:
            LOG.debug("lAST FILE PATH: {}".format(self.media_path))
            self.updateDirectoryView(self.media_path)

    #########################
    # callbacks
    #########################

    # add shown text and hidden filter data from the INI
    def fillCombobox(self, data):
        for i in data:
            self.cb.addItem(i[0], i[1])

    def folderChanged(self, data):
        self.currentFolder = data
        self.textLine.setText(data)

    def updateDirectoryView(self, path):
        self.list.setRootIndex(self.model.setRootPath(path))

    # retrieve selected filter (it's held as QT.userData)
    def filterChanged(self, index):
        userdata = self.cb.itemData(index)
        self.model.setNameFilters(userdata)

    def listClicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            self.textLine.setText(self.currentPath)
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)

    def onUserClicked(self):
        self.showUserDir()

    def onMediaClicked(self):
        self.showMediaDir()

    def onJumpClicked(self):
        data = self.button2.text()
        if data == 'Media':
            self.showMediaDir()
        elif data == 'User':
            self.showUserDir()
        else:
            self.updateDirectoryView(self.button2.text())

    def jumpTriggered(self, data):
        if data == 'Media':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to Media directory')
            self.showMediaDir()
        elif data == 'User':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to User directory')
            self.showUserDir()
        else:
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to directory: {}'.format(data))
            self.updateDirectoryView(self.button2.text())

    def onActionClicked(self):
        i = self.currentFolder
        button = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        button.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(button)

    # get current selection and update the path
    # then if the path is good load it into linuxcnc
    # record it in the preference file if available
    def _getPathActivated(self):
        row = self.list.selectionModel().currentIndex()
        self.listClicked(row)

        fname = self.currentPath
        if fname is None:
            return
        if fname:
            self.load(fname)

    def recordCopyPath(self):
        data, isFile = self.getCurrentSelected()
        if isFile:
            self.copyLine.setText(os.path.normpath(data))
            self.pasteButton.setEnabled(True)
        else:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)
            STATUS.emit('error', OPERATOR_ERROR,
                        'Can only copy a file, not a folder')

    def paste(self):
        res = self.copyFile(self.copyLine.text(), self.textLine.text())
        if res:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)

    ########################
    # helper functions
    ########################

    def showCopyControls(self, state):
        if state:
            self.copyBox.show()
            self.pasteButton.show()
        else:
            self.copyBox.hide()
            self.pasteButton.hide()

    def showMediaDir(self):
        self.updateDirectoryView(self.user_path)

    def showUserDir(self):
        self.updateDirectoryView(self.media_path)

    def copyFile(self, s, d):
        try:
            shutil.copy(s, d)
            return True
        except Exception as e:
            LOG.error("Copy file error: {}".format(e))
            STATUS.emit('error', OPERATOR_ERROR,
                        "Copy file error: {}".format(e))
            return False

    # moves the selection up
    # used with MPG scrolling
    def up(self):
        self.select_row('up')

    # moves the selection down
    # used with MPG scrolling
    def down(self):
        self.select_row('down')

    def select_row(self, style='down'):
        style = style.lower()
        selectionModel = self.list.selectionModel()
        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(self.list.rootIndex())

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows:
                row += 1
            else:
                row = self.rows
        else:
            return
        top = self.model.index(row, 0, self.list.rootIndex())
        selectionModel.setCurrentIndex(
            top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    # returns the current highlighted (selected) path as well as
    # whether it's a file or not.
    def getCurrentSelected(self):
        selectionModel = self.list.selectionModel()
        index = selectionModel.currentIndex()
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            return (dir_path, True)
        else:
            return (dir_path, False)

    # This can be class patched to do something else
    def load(self, fname=None):
        if fname is None:
            self._getPathActivated()
            return
        self.recordBookKeeping()
        ACTION.OPEN_PROGRAM(fname)
        STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')

    # This can be class patched to do something else
    def recordBookKeeping(self):
        fname = self.currentPath
        if fname is None:
            return
        if self.PREFS_:
            self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(),
                                str, 'BOOK_KEEPING')
            self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
Esempio n. 8
0
class TextRenamer(QtWidgets.QMainWindow):
    ui = None

    currentFullNames = None
    currentExtensions = None
    path = None
    currentIndex = None

    showExtension = False

    def __init__(self):

        # init user interface:
        super(TextRenamer, self).__init__()
        self.show()
        self.ui = uic.loadUi('textRenamer.ui', self)

        # TODO: remember last used path
        self.path = QDir.rootPath()

        # Set up files and folder views
        self.foldersModel = QFileSystemModel()
        self.foldersModel.setRootPath(self.path)
        self.foldersModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)

        self.filesModel = QFileSystemModel()
        self.filesModel.setFilter(QDir.NoDotAndDotDot | QDir.Files)

        self.ui.folderView.setModel(self.foldersModel)
        self.ui.filesView.setModel(self.filesModel)

        # Remove all columns but the folder name
        self.ui.folderView.setRootIndex(self.foldersModel.index(self.path))
        self.ui.folderView.hideColumn(1)
        self.ui.folderView.hideColumn(2)
        self.ui.folderView.hideColumn(3)

        # Set path for start
        self.ui.filesView.setRootIndex(self.filesModel.index(self.path))

        # Event handlers:
        self.ui.renameButton.clicked.connect(self.renameFiles)
        self.ui.folderView.clicked.connect(self.openFolder)
        self.filesModel.directoryLoaded.connect(self.loadedFolder)
        self.ui.extensionCheckbox.stateChanged.connect(
            self.extensionCheckboxChanged)

    def extensionCheckboxChanged(self, state):
        if state == 0:
            self.showExtension = False
        else:
            self.showExtension = True
        self.readCurrentNames()

    def loadedFolder(self, path):
        # Delay reading to get correct file order
        QTimer.singleShot(1, self.readCurrentNames)

    def readCurrentNames(self):
        # Reset
        self.currentFullNames = []

        for i in range(self.filesModel.rowCount(self.currentIndex)):
            self.currentFullNames.append(self.currentIndex.child(i, 0).data())

        self.currentNames = [
            os.path.splitext(x)[0] for x in self.currentFullNames
        ]
        self.currentExtensions = [
            os.path.splitext(x)[1] for x in self.currentFullNames
        ]

        if self.showExtension:
            fileListText = '\n'.join(self.currentFullNames)
        else:
            fileListText = '\n'.join(self.currentNames)

        self.ui.newText.setPlainText(fileListText)

        # Only enable the rename button once everything is loaded
        self.ui.renameButton.setEnabled(True)

    def openFolder(self, index):
        self.path = self.foldersModel.fileInfo(index).absoluteFilePath()
        self.currentIndex = self.filesModel.setRootPath(self.path)
        self.ui.filesView.setRootIndex(self.currentIndex)
        # Clear info text
        self.ui.errorLabel.setText("")

    def renameFiles(self):
        # Read new names (only use as many rows as we have currentFullNames):
        newNames = self.ui.newText.toPlainText().split(
            '\n')[:len(self.currentFullNames)]

        if self.showExtension:
            self.newFullNames = newNames
        else:
            # Add extension
            self.newFullNames = [
                i + j for i, j in zip(newNames, self.currentExtensions)
            ]

        # TODO: Add temporary filenames for cases where a new name conflicts with a name that has not yet been renamed

        # Sanity checkes:
        enoughNames = False
        allNamesHaveCharacters = False
        allNamesUnique = False

        # Sanity check: All new names have characters
        if len(self.newFullNames) >= len(self.currentFullNames):
            enoughNames = True
        else:
            self.ui.errorLabel.setText("Error: Not enough names given")

        # Sanity chcek: All names have characters
        allNamesHaveCharacters = True
        for newName in self.newFullNames:
            if newName == "":
                allNamesHaveCharacters = False
                self.ui.errorLabel.setText("Error: Blank new name")
                break

        # Sanity chcek: All names unique
        if self.allUnique(self.newFullNames):
            allNamesUnique = True
        else:
            self.ui.errorLabel.setText("Error: All names have to be unique")

        renamedCount = 0
        notChangedCount = 0
        errorCount = 0
        # Rename
        if enoughNames and allNamesHaveCharacters and allNamesUnique:
            for currentName, newName in zip(self.currentFullNames,
                                            self.newFullNames):
                print(self.path + "/" + currentName + " > " + newName)

                # Dont rename needlessly
                if not currentName == newName:
                    currentFile = os.path.join(self.path, currentName).replace(
                        os.sep, '/')
                    newFileName = os.path.join(self.path,
                                               newName).replace(os.sep, '/')
                    # Only rename if the current file exists
                    if os.path.exists(currentFile):
                        renamedOk = QtCore.QFile.rename(
                            currentFile, newFileName)
                        if not renamedOk:
                            errorCount += 1
                        renamedCount += 1
                    else:
                        notChangedCoint += 1
                else:
                    notChangedCount += 1
            labelText = "Renamed: " + str(renamedCount) + " files"
            if notChangedCount > 0:
                labelText += ", No change: " + str(notChangedCount)
            if errorCount > 0:
                labelText += ", Error: " + str(errorCount)

            # Set info text
            self.ui.errorLabel.setText(labelText)

    # Early exit uniqueness checker, returns true if all items in x are unique
    def allUnique(self, x):
        seen = set()
        return not any(i in seen or seen.add(i) for i in x)