예제 #1
0
	def __init__(self, context):
		super(TriageFilePicker, self).__init__()
		self.context = context
		self.actionHandler = UIActionHandler()
		self.actionHandler.setupActionHandler(self)
		self.contextMenu = Menu()
		self.contextMenuManager = ContextMenuManager(self)

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

		self.model = QFileSystemModel()
		self.model.setRootPath("")
		self.model.setFilter(QDir.AllEntries | QDir.Hidden | QDir.System)
		self.tree = QTreeView(self)
		self.tree.setModel(self.model)
		self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
		self.tree.setColumnWidth(0, 500)
		layout.addWidget(self.tree, 1)

		self.setLayout(layout)

		self.tree.doubleClicked.connect(self.onDoubleClick)

		recentFile = QSettings().value("triage/recentFile", os.path.expanduser("~"))
		while len(recentFile) > 0:
			f = self.model.index(recentFile)
			if f.isValid():
				self.tree.scrollTo(f)
				self.tree.setExpanded(f, True)
				break
			parentDir = os.path.dirname(recentFile)
			if parentDir == recentFile:
				break
			recentFile = parentDir

		self.actionHandler.bindAction("Open Selected Files", UIAction(
			lambda context: self.openSelectedFiles(),
			lambda context: self.areFilesSelected()))
		self.contextMenu.addAction("Open Selected Files", "Open")
예제 #2
0
파일: utility.py 프로젝트: tmahlburg/tfm
def indexes_to_paths(files_as_indexes: List[QModelIndex]) -> List[str]:
    """
    Converts the given indexes to a list of paths.

    :param files_as_indexes: List of indexes of files.
    :type files_as_indexes: List[QModelIndex]
    :return: List of paths to the given files.
    :rtype: List[str]
    """
    files_as_path = []
    for index in files_as_indexes:
        if (index.column() == 0):
            files_as_path.append(QFileSystemModel().filePath(index))
    return files_as_path
예제 #3
0
class TriageFilePicker(QWidget):
	def __init__(self, context):
		super(TriageFilePicker, self).__init__()
		self.context = context
		self.actionHandler = UIActionHandler()
		self.actionHandler.setupActionHandler(self)
		self.contextMenu = Menu()
		self.contextMenuManager = ContextMenuManager(self)

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

		self.model = QFileSystemModel()
		self.model.setRootPath("")
		self.model.setFilter(QDir.AllEntries | QDir.Hidden | QDir.System)
		self.tree = QTreeView(self)
		self.tree.setModel(self.model)
		self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
		self.tree.setColumnWidth(0, 500)
		layout.addWidget(self.tree, 1)

		self.setLayout(layout)

		self.tree.doubleClicked.connect(self.onDoubleClick)

		recentFile = QSettings().value("triage/recentFile", os.path.expanduser("~"))
		while len(recentFile) > 0:
			f = self.model.index(recentFile)
			if f.isValid():
				self.tree.scrollTo(f)
				self.tree.setExpanded(f, True)
				break
			parentDir = os.path.dirname(recentFile)
			if parentDir == recentFile:
				break
			recentFile = parentDir

		self.actionHandler.bindAction("Open Selected Files", UIAction(
			lambda context: self.openSelectedFiles(),
			lambda context: self.areFilesSelected()))
		self.contextMenu.addAction("Open Selected Files", "Open")

	def contextMenuEvent(self, event):
		self.contextMenuManager.show(self.contextMenu, self.actionHandler)

	def onDoubleClick(self, index):
		self.openSelectedFiles()

	def openSelectedFiles(self):
		failedToOpen = []
		files = set()

		for index in self.tree.selectionModel().selectedIndexes():
			if self.model.fileInfo(index).isFile():
				files.add(self.model.fileInfo(index).absoluteFilePath())

		for filename in files:
				QSettings().setValue("triage/recentFile", filename)

				f = FileContext.openFilename(filename)
				if not f:
					failedToOpen.append(filename)
					continue

				for data in f.getAllDataViews():
					Settings().set_string("analysis.mode", Settings().get_string("triage.analysisMode"), data)
					Settings().set_bool("triage.preferSummaryView", True, data)
					if data.view_type != "Raw":
						linearSweepMode = Settings().get_string("triage.linearSweep")
						if linearSweepMode == "none":
							Settings().set_bool("analysis.linearSweep.autorun", False, data)
						elif linearSweepMode == "partial":
							Settings().set_bool("analysis.linearSweep.autorun", True, data)
							Settings().set_bool("analysis.linearSweep.controlFlowGraph", False, data)
						elif linearSweepMode == "full":
							Settings().set_bool("analysis.linearSweep.autorun", True, data)
							Settings().set_bool("analysis.linearSweep.controlFlowGraph", True, data)

				self.context.openFileContext(f)

		if len(failedToOpen) > 0:
			QMessageBox.critical(self, "Error", "Unable to open:\n" + "\n".join(failedToOpen))

	def areFilesSelected(self):
		return self.tree.selectionModel().hasSelection()
예제 #4
0
파일: tfm.py 프로젝트: tmahlburg/tfm
    def __init__(self, args: List[str]):
        """
        At the moment the very, very long initialization of the main window,
        setting up everything.

        :param default_path: Use a user defined path as entrypoint. If it's
                             empty, the home directory of the current user will
                             be used.
        :type default_path: str
        """
        super(tfm, self).__init__()
        self.setupUi(self)
        self.setWindowIcon(QIcon.fromTheme('system-file-manager'))

        self.clipboard = QApplication.clipboard()
        self.marked_to_cut = []

        self.back_stack = stack()
        self.forward_stack = stack()

        self.config_dir = os.path.join(
            QStandardPaths.writableLocation(
                QStandardPaths().ConfigLocation),
            type(self).__name__)

        self.current_path = utility.handle_args(args)
        self.default_path = self.current_path

        self.threadpool = QThreadPool()

        # MAIN VIEW #
        # set up QFileSystemModel
        self.filesystem = QFileSystemModel()
        self.filesystem.setRootPath(self.current_path)
        self.filesystem.setReadOnly(False)

        # connect QFileSystemModel to View
        self.table_view.setModel(self.filesystem)
        self.table_view.setRootIndex(
            self.filesystem.index(self.current_path))

        # set up header
        self.horizontal_header = self.table_view.horizontalHeader()
        self.horizontal_header.setSectionsMovable(True)
        # name
        self.horizontal_header.resizeSection(0, 200)
        # size
        self.horizontal_header.resizeSection(1, 100)
        # type
        self.horizontal_header.resizeSection(2, 100)

        # FS TREE #
        # create seperate FileSystemModel for the fs tree
        self.fs_tree_model = QFileSystemModel()
        self.fs_tree_model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.fs_tree_model.setRootPath(QDir.rootPath())

        # connect model to view
        self.fs_tree.setModel(self.fs_tree_model)
        # hide unneeded columns
        for column in range(1, self.fs_tree.header().count()):
            self.fs_tree.hideColumn(column)
        # expand root item
        self.fs_tree.expand(self.fs_tree_model.index(0, 0))

        # BOOKMARKS #
        self.bookmarks = bm(path_to_bookmark_file=os.path.join(self.config_dir,
                                                               'bookmarks'))
        self.bookmark_view.setModel(self.bookmarks)

        # MOUNTS #
        self.udev_context = Context()
        self.mounts = mounts_model(context=self.udev_context)
        self.mounts_view.setModel(self.mounts)
        udev_monitor = Monitor.from_netlink(self.udev_context)
        udev_monitor.filter_by(subsystem='block', device_type='partition')
        udev_observer = MonitorObserver(udev_monitor,
                                        self.devices_changed)
        udev_observer.start()

        # STATUSBAR #
        # TODO: dir info
        self.item_info = QLabel()
        # self.dir_info = QLabel()
        self.part_info = QLabel()
        self.statusbar.addPermanentWidget(self.item_info)
        # self.statusbar.addPermanentWidget(self.dir_info)
        self.statusbar.addPermanentWidget(self.part_info)

        self.part_info.setText(utility.part_info(self.current_path))

        # TOOLBAR #
        # initially disable back/forward navigation
        self.action_back.setEnabled(False)
        self.action_forward.setEnabled(False)

        # main menu
        self.main_menu = QMenu()
        self.main_menu.addAction(self.action_show_hidden)

        self.menu_button = QToolButton()
        self.menu_button.setMenu(self.main_menu)
        self.menu_button.setPopupMode(QToolButton().InstantPopup)
        self.menu_button.setDefaultAction(self.action_menu)

        self.toolbar.insertWidget(self.action_back, self.menu_button)

        # adress bar
        self.adressbar = QLineEdit()
        self.adressbar.setText(self.current_path)
        self.toolbar.insertWidget(self.action_go, self.adressbar)

        # menu for new file or directory
        self.new_menu = QMenu()
        self.new_menu.addAction(self.action_new_dir)
        self.new_menu.addAction(self.action_new_file)

        self.new_button = QToolButton()
        self.new_button.setMenu(self.new_menu)
        self.new_button.setPopupMode(QToolButton().MenuButtonPopup)
        self.new_button.setDefaultAction(self.action_new_dir)

        self.toolbar.insertWidget(self.action_back, self.new_button)

        self.connect_actions_to_events()
        self.set_shortcuts()
        self.set_icons()
        self.set_context_menus()
예제 #5
0
파일: tfm.py 프로젝트: tmahlburg/tfm
class tfm(QMainWindow, Ui_tfm):
    """
    The main window class, setting up the application and implementing the
    needed events.
    """

    def __init__(self, args: List[str]):
        """
        At the moment the very, very long initialization of the main window,
        setting up everything.

        :param default_path: Use a user defined path as entrypoint. If it's
                             empty, the home directory of the current user will
                             be used.
        :type default_path: str
        """
        super(tfm, self).__init__()
        self.setupUi(self)
        self.setWindowIcon(QIcon.fromTheme('system-file-manager'))

        self.clipboard = QApplication.clipboard()
        self.marked_to_cut = []

        self.back_stack = stack()
        self.forward_stack = stack()

        self.config_dir = os.path.join(
            QStandardPaths.writableLocation(
                QStandardPaths().ConfigLocation),
            type(self).__name__)

        self.current_path = utility.handle_args(args)
        self.default_path = self.current_path

        self.threadpool = QThreadPool()

        # MAIN VIEW #
        # set up QFileSystemModel
        self.filesystem = QFileSystemModel()
        self.filesystem.setRootPath(self.current_path)
        self.filesystem.setReadOnly(False)

        # connect QFileSystemModel to View
        self.table_view.setModel(self.filesystem)
        self.table_view.setRootIndex(
            self.filesystem.index(self.current_path))

        # set up header
        self.horizontal_header = self.table_view.horizontalHeader()
        self.horizontal_header.setSectionsMovable(True)
        # name
        self.horizontal_header.resizeSection(0, 200)
        # size
        self.horizontal_header.resizeSection(1, 100)
        # type
        self.horizontal_header.resizeSection(2, 100)

        # FS TREE #
        # create seperate FileSystemModel for the fs tree
        self.fs_tree_model = QFileSystemModel()
        self.fs_tree_model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.fs_tree_model.setRootPath(QDir.rootPath())

        # connect model to view
        self.fs_tree.setModel(self.fs_tree_model)
        # hide unneeded columns
        for column in range(1, self.fs_tree.header().count()):
            self.fs_tree.hideColumn(column)
        # expand root item
        self.fs_tree.expand(self.fs_tree_model.index(0, 0))

        # BOOKMARKS #
        self.bookmarks = bm(path_to_bookmark_file=os.path.join(self.config_dir,
                                                               'bookmarks'))
        self.bookmark_view.setModel(self.bookmarks)

        # MOUNTS #
        self.udev_context = Context()
        self.mounts = mounts_model(context=self.udev_context)
        self.mounts_view.setModel(self.mounts)
        udev_monitor = Monitor.from_netlink(self.udev_context)
        udev_monitor.filter_by(subsystem='block', device_type='partition')
        udev_observer = MonitorObserver(udev_monitor,
                                        self.devices_changed)
        udev_observer.start()

        # STATUSBAR #
        # TODO: dir info
        self.item_info = QLabel()
        # self.dir_info = QLabel()
        self.part_info = QLabel()
        self.statusbar.addPermanentWidget(self.item_info)
        # self.statusbar.addPermanentWidget(self.dir_info)
        self.statusbar.addPermanentWidget(self.part_info)

        self.part_info.setText(utility.part_info(self.current_path))

        # TOOLBAR #
        # initially disable back/forward navigation
        self.action_back.setEnabled(False)
        self.action_forward.setEnabled(False)

        # main menu
        self.main_menu = QMenu()
        self.main_menu.addAction(self.action_show_hidden)

        self.menu_button = QToolButton()
        self.menu_button.setMenu(self.main_menu)
        self.menu_button.setPopupMode(QToolButton().InstantPopup)
        self.menu_button.setDefaultAction(self.action_menu)

        self.toolbar.insertWidget(self.action_back, self.menu_button)

        # adress bar
        self.adressbar = QLineEdit()
        self.adressbar.setText(self.current_path)
        self.toolbar.insertWidget(self.action_go, self.adressbar)

        # menu for new file or directory
        self.new_menu = QMenu()
        self.new_menu.addAction(self.action_new_dir)
        self.new_menu.addAction(self.action_new_file)

        self.new_button = QToolButton()
        self.new_button.setMenu(self.new_menu)
        self.new_button.setPopupMode(QToolButton().MenuButtonPopup)
        self.new_button.setDefaultAction(self.action_new_dir)

        self.toolbar.insertWidget(self.action_back, self.new_button)

        self.connect_actions_to_events()
        self.set_shortcuts()
        self.set_icons()
        self.set_context_menus()

    # ---------------- setup ----------------------------------------------- #
    def set_icons(self):
        """
        Adds icons to all applicable actions.
        """
        self.action_back.setIcon(QIcon.fromTheme('go-previous'))
        self.action_forward.setIcon(QIcon.fromTheme('go-next'))
        self.action_home.setIcon(QIcon.fromTheme('go-home'))
        self.action_up.setIcon(QIcon.fromTheme('go-up'))
        self.action_go.setIcon(QIcon.fromTheme('go-jump'))
        self.action_new_dir.setIcon(QIcon.fromTheme('folder-new'))
        self.action_new_file.setIcon(QIcon.fromTheme('document-new'))
        self.action_menu.setIcon(QIcon.fromTheme('start-here'))
        self.action_copy.setIcon(QIcon.fromTheme('edit-copy'))
        self.action_cut.setIcon(QIcon.fromTheme('edit-cut'))
        self.action_paste.setIcon(QIcon.fromTheme('edit-paste'))
        self.action_delete.setIcon(QIcon.fromTheme('edit-delete'))
        self.action_add_to_bookmarks.setIcon(QIcon.fromTheme('list-add'))
        self.action_remove_bookmark.setIcon(QIcon.fromTheme('list-remove'))

    def connect_actions_to_events(self):
        """
        Connects actions to their event functions.
        """
        self.adressbar.returnPressed.connect(self.action_go_event)

        self.action_go.triggered.connect(self.action_go_event)
        self.action_home.triggered.connect(self.action_home_event)
        self.action_up.triggered.connect(self.action_up_event)
        self.action_back.triggered.connect(self.action_back_event)
        self.action_forward.triggered.connect(self.action_forward_event)
        self.action_copy.triggered.connect(self.action_copy_event)
        self.action_copy_path.triggered.connect(self.action_copy_path_event)
        self.action_paste.triggered.connect(self.action_paste_event)
        self.action_cut.triggered.connect(self.action_cut_event)
        self.action_delete.triggered.connect(self.action_delete_event)
        self.action_rename.triggered.connect(self.action_rename_event)
        self.action_show_hidden.toggled.connect(self.action_show_hidden_event)
        self.action_new_dir.triggered.connect(self.action_new_dir_event)
        self.action_new_file.triggered.connect(self.action_new_file_event)
        self.action_add_to_bookmarks.triggered.connect(
            self.action_add_to_bookmarks_event)
        self.action_remove_bookmark.triggered.connect(
            self.action_remove_bookmark_event)
        self.action_extract_here.triggered.connect(
            self.action_extract_here_event)
        self.action_mount_iso.triggered.connect(self.action_mount_iso_event)

        self.bookmark_view.pressed.connect(self.bookmark_selected_event)
        self.fs_tree.pressed.connect(self.fs_tree_event)
        self.mounts_view.pressed.connect(self.mount_selected_event)
        self.mounts_view.activated.connect(self.mount_toggle_event)
        self.table_view.pressed.connect(self.item_selected_event)
        self.table_view.activated.connect(self.item_open_event)

    def set_shortcuts(self):
        """
        Set shortcuts for actions.
        """
        self.action_copy.setShortcuts(
            QKeySequence.keyBindings(QKeySequence.Copy))
        self.action_paste.setShortcuts(
            QKeySequence.keyBindings(QKeySequence.Paste))
        self.action_cut.setShortcuts(
            QKeySequence.keyBindings(QKeySequence.Cut))
        self.action_delete.setShortcuts(
            QKeySequence.keyBindings(QKeySequence.Delete))

    def set_context_menus(self):
        """
        Setup context menus.
        """
        self.table_view.addAction(self.action_copy)
        self.table_view.addAction(self.action_copy_path)
        self.table_view.addAction(self.action_paste)
        self.table_view.addAction(self.action_cut)
        self.table_view.addAction(self.action_rename)
        self.table_view.addAction(self.action_delete)
        self.table_view.addAction(self.action_show_hidden)

        self.bookmark_view.addAction(self.action_remove_bookmark)

    # ---------------- events ---------------------------------------------- #
    def action_new_dir_event(self):
        """
        Prompts the user for a dir name and creates one with that name in the
        current directory.
        """
        dir_name, ok = QInputDialog().getText(self,
                                              'Create new directory',
                                              'Directory name:')
        if (ok):
            if (dir_name):
                if not QDir().mkpath(os.path.join(self.current_path,
                                                  dir_name)):
                    dialog = utility.message_dialog('Directory could not be'
                                                    + ' created.',
                                                    QMessageBox.Critical)
                    dialog.exec()
            else:
                dialog = utility.message_dialog('Please enter a name for the '
                                                + 'new directory.',
                                                QMessageBox.Warning)
                dialog.exec()

    def action_new_file_event(self):
        """
        Prompts the user for a file name and creates one with that name in the
        current directory.
        """
        file_name, ok = QInputDialog().getText(self,
                                               'Create new file',
                                               'File name:')
        if (ok):
            if (file_name):
                try:
                    with open(os.path.join(self.current_path, file_name), 'a'):
                        pass
                except OSError:
                    dialog = utility.message_dialog('File cannot be created.',
                                                    QMessageBox.Warning)
                    dialog.exec()
            else:
                dialog = utility.message_dialog('Please enter a name for the'
                                                + ' new file.',
                                                QMessageBox.Warning)
                dialog.exec()

    def action_go_event(self):
        """
        Changes the current dir to the one, that is given in the adress bar.
        """
        next_dir = QDir(self.adressbar.text())
        if (next_dir.isAbsolute() and next_dir.exists()):
            next_path = next_dir.path()
            self.update_current_path(next_path)
        else:
            dialog = utility.message_dialog('The path entered does not exist.',
                                            QMessageBox.Warning)
            dialog.exec()

    def action_home_event(self):
        """
        Changes the current dir to the users $HOME.
        """
        next_path = QDir().homePath()
        self.update_current_path(next_path)

    def action_up_event(self):
        """
        Changes the current dir to one dir up in the hierarchy
        """
        dir_up = QDir(self.current_path)
        if (dir_up.cdUp()):
            next_path = dir_up.path()
            self.update_current_path(next_path)
        else:
            logging.warning('There is no directory above the one you are in.'
                            + ' This message should not occur, because the'
                            + ' button triggering this should be deactivated'
                            + ' Please report this issue.')

    def action_back_event(self):
        """
        Goes back one step in the navigation history. If after this, there are
        no more steps, it disables it's button.
        """
        next_path = self.back_stack.pop()
        self.forward_stack.push(self.current_path)
        self.action_forward.setEnabled(True)
        if (self.back_stack.empty()):
            self.action_back.setEnabled(False)
        self.update_current_path(next_path,
                                 skip_stack=True,
                                 reset_forward_stack=False)

    def action_forward_event(self):
        """
        Goes forward one step in the navigation history. If after this, there
        are no more steps, it disables it's button.
        """
        if (not self.forward_stack.empty()):
            next_path = self.forward_stack.pop()
            self.update_current_path(next_path, reset_forward_stack=False)
            # disable forward action if there are no more forward actions
            if (self.forward_stack.empty()):
                self.action_forward.setEnabled(False)
        else:
            logging.warning('Forward stack unexpectedly empty. This should not'
                            + ' happen, because the button triggering this'
                            + ' message should be deactivated. Please report'
                            + ' this issue.')

    def item_open_event(self):
        """
        Opens the selected files using xdg-open, runs it, if it is executable
        or changes the current dir if it's dir.
        """
        selected_items = []
        for index in self.table_view.selectedIndexes():
            if index.column() == 0:
                selected_items.append(QFileInfo(os.path.join(self.current_path,
                                      index.siblingAtColumn(0).data())))

        # warn before accidentally open a bunch of files
        open = True
        if len(selected_items) > 3:
            dialog = utility.question_dialog('Do you really want to open '
                                             + str(len(selected_items))
                                             + ' files?')
            button = dialog.exec()
            if button == QMessageBox.Cancel:
                open = False

        if open:
            for item in selected_items:
                if (item.isDir()):
                    next_path = item.absoluteFilePath()
                    self.update_current_path(next_path)
                elif (item.isFile()):
                    if (item.isExecutable()):
                        QProcess().startDetached(item.absoluteFilePath(),
                                                 [],
                                                 self.current_path)
                    else:
                        QProcess().startDetached('xdg-open',
                                                 [item.absoluteFilePath()],
                                                 self.current_path)
                else:
                    dialog = utility.message_dialog('The type of the selected'
                                                    + ' file can not be'
                                                    + ' detected.',
                                                    QMessageBox.Warning)
                    dialog.exec()

    def item_selected_event(self):
        """
        Updates statusbar info, depending on the selected file.
        """
        selected_items = self.table_view.selectedIndexes()
        files = []
        for item in selected_items:
            files.append(os.path.join(self.current_path,
                                      item.siblingAtColumn(0).data()))
        files = list(set(files))
        if len(files) == 1:
            # update context menu according to file type
            if (os.path.isdir(files[0])):
                self.table_view.addAction(self.action_add_to_bookmarks)
                self.table_view.removeAction(self.action_extract_here)
                self.table_view.removeAction(self.action_mount_iso)
            else:
                self.table_view.removeAction(self.action_add_to_bookmarks)
                if (is_tarfile(files[0]) or is_zipfile(files[0])):
                    self.table_view.addAction(self.action_extract_here)
                    if (os.path.splitext(files[0])[1] == '.iso'):
                        self.table_view.addAction(self.action_mount_iso)
                else:
                    self.table_view.removeAction(self.action_extract_here)
                    self.table_view.removeAction(self.action_mount_iso)

        files = list(set(files))
        self.item_info.setText(utility.file_info(files))

    def fs_tree_event(self):
        """
        Changes the current dir to the dir selected in the fs_tree view.
        """
        next_path = self.fs_tree_model.filePath(self.fs_tree.currentIndex())
        self.update_current_path(next_path)

    def action_extract_here_event(self):
        """
        Extracts the given file if possible.
        """
        selected_item = os.path.join(self.current_path,
                                     self.table_view.currentIndex().
                                     siblingAtColumn(0).data())
        # setup QProgressDialog
        progress_dialog = QProgressDialog(parent=self)
        progress_dialog.reset()
        progress_dialog.setMinimumDuration(1000)
        progress_dialog.setLabelText('Extracting archive ' + selected_item
                                     + '...')
        progress_dialog.setValue(0)
        # setup extract_worker
        extract_worker = ew(archive_path=selected_item)

        # canceled
        progress_dialog.canceled.connect(extract_worker.cancel,
                                         type=Qt.DirectConnection)
        # ready
        extract_worker.signals.ready.connect(progress_dialog.setMaximum)
        # progress
        extract_worker.signals.progress.connect(progress_dialog.setValue)
        # progress message
        extract_worker.signals.progress_message.connect(
            progress_dialog.setLabelText)
        # finished
        extract_worker.signals.finished.connect(progress_dialog.reset)

        self.threadpool.start(extract_worker)

    def action_copy_event(self):
        """
        Copies the currently selected files to the clipboard.
        """
        # get current selection
        _, mime_data = utility.get_MIME(
            self.table_view.selectionModel().selectedIndexes())
        self.clipboard.setMimeData(mime_data)

    def action_paste_event(self):
        """
        Pastes the files currently in the clipboard to the current dir.
        """
        # setup QProgressDialog
        progress_dialog = QProgressDialog(parent=self)
        progress_dialog.reset()
        progress_dialog.setMinimumDuration(1000)
        progress_dialog.setLabelText('Pasting...')
        progress_dialog.setValue(0)
        # setup paste_worker
        paste_worker = pw(clipboard=self.clipboard,
                          target_path=self.current_path,
                          marked_to_cut=self.marked_to_cut)
        # canceled
        progress_dialog.canceled.connect(paste_worker.cancel,
                                         type=Qt.DirectConnection)

        # ready
        paste_worker.signals.ready.connect(progress_dialog.setMaximum)
        # progress
        paste_worker.signals.progress.connect(progress_dialog.setValue)
        # progress message
        paste_worker.signals.progress_message.connect(
            progress_dialog.setLabelText)
        # finished
        paste_worker.signals.finished.connect(progress_dialog.reset)

        self.threadpool.start(paste_worker)

    # TODO: visual feedback for cut files
    def action_cut_event(self):
        """
        Copies the current selection to the clipboard and marks them as cut.
        """
        self.marked_to_cut, mime_data = utility.get_MIME(
            self.table_view.selectionModel().selectedIndexes())
        self.clipboard.setMimeData(mime_data)

    def action_delete_event(self):
        """
        Throws the current selection in the trash after asking for
        confirmation.
        """
        path_list = utility.indexes_to_paths(
            self.table_view.selectionModel().selectedIndexes())
        if len(path_list) < 0:
            return

        if (len(path_list) == 1):
            confirmation_msg = ('Do you want to throw "'
                                + os.path.basename(path_list[0])
                                + '" in the trash?')
        else:
            confirmation_msg = ('Do you want to throw the '
                                + str(len(path_list))
                                + ' selected items and all the items contained'
                                + ' in them in the trash?')

        dialog = utility.question_dialog(confirmation_msg)
        button_clicked = dialog.exec()

        if (button_clicked == QMessageBox.Yes):
            for item in path_list:
                send2trash(item)

    def action_rename_event(self):
        """
        Prompts the user to enter a new name and changes the selected file's
        name.
        """
        file_name = self.table_view.currentIndex().data()
        new_file_name, ok = QInputDialog().getText(self,
                                                   'Rename ' + file_name,
                                                   'New name:')
        if (ok):
            if (new_file_name):
                QFile().rename(os.path.join(self.current_path, file_name),
                               os.path.join(self.current_path, new_file_name))
            else:
                dialog = utility.message_dialog('Please enter the new name '
                                                + 'for the file.',
                                                QMessageBox.Warning)
                dialog.exec()

    def action_show_hidden_event(self):
        """
        Shows hidden files and dirs in the main view.
        """
        if self.action_show_hidden.isChecked():
            self.filesystem.setFilter(QDir.AllEntries
                                      | QDir.NoDotAndDotDot
                                      | QDir.AllDirs
                                      | QDir.Hidden)
        else:
            self.filesystem.setFilter(QDir.AllEntries
                                      | QDir.NoDotAndDotDot
                                      | QDir.AllDirs)

    def action_copy_path_event(self):
        """
        Copy path of currently selected item to clipboard.
        """
        path = os.path.join(self.current_path,
                            self.table_view.currentIndex().siblingAtColumn(0)
                            .data())
        self.clipboard.setText(path)

    def action_add_to_bookmarks_event(self):
        """
        Adds the selected dir to the bookmark by the name the user gave it via
        a dialog.
        """
        path = os.path.join(self.current_path,
                            self.table_view.currentIndex().data())
        if (os.path.isdir(path)):
            name, ok = QInputDialog().getText(self,
                                              'Create new bookmark',
                                              'Bookmark name:',
                                              text=self.table_view.
                                              currentIndex().data())
            if (ok):
                if (name):
                    self.bookmarks.add_bookmark(name, path)
                    self.bookmark_view.reset()
                else:
                    dialog = utility.message_dialog('Please enter name for'
                                                    + ' the bookmark.',
                                                    QMessageBox.Warning)
                    dialog.exec()
        else:
            dialog = utility.message_dialog('Please select a directory, not'
                                            + ' a file, to create a bookmark.',
                                            QMessageBox.Warning)
            dialog.exec()

    def action_remove_bookmark_event(self):
        """
        Removes the selected bookmark after asking the user for confirmation.
        """
        name = self.bookmark_view.currentIndex().data()
        dialog = utility.question_dialog('Do you really want to delete this '
                                         + 'bookmark ('
                                         + name
                                         + ')?')
        button_clicked = dialog.exec()

        if (button_clicked == QMessageBox.Yes):
            self.bookmarks.remove_bookmark(name)
            self.bookmark_view.reset()

    def bookmark_selected_event(self):
        """
        Changes the current dir to the one associated with the selected
        bookmark.
        """
        next_path = self.bookmarks.get_path_from_name(
            self.bookmark_view.currentIndex().data())
        self.update_current_path(next_path)

    def mount_selected_event(self):
        """
        Checks the mount point of the selected drive and makes it the current
        path.
        """
        try:
            device = self.mounts.get_device_at(
                self.mounts_view.currentIndex().row())
        except IndexError:
            logging.critical('Device index out of range. This should never '
                             + 'happen, please report this error.')
            exit(1)
        mount_point = self.mounts.get_mount_point(device)
        if mount_point != '':
            self.update_current_path(mount_point)

    def action_mount_iso_event(self):
        """
        """
        iso_path = os.path.join(self.current_path,
                                self.table_view.currentIndex()
                                .siblingAtColumn(0).data())
        self.mounts.mount_and_add_iso(iso_path)

    # TODO: handle performance better
    def mount_toggle_event(self):
        """
        Tries to mount or unmount the selected drive.
        """
        try:
            device = self.mounts.get_device_at(
                self.mounts_view.currentIndex().row())
        except IndexError:
            logging.critical('Device index out of range. This should never '
                             + 'happen, please report this error.')
            exit(1)
        former_mount_point = self.mounts.get_mount_point(device)
        try:
            self.mounts.toggle_mount(device)
        except CalledProcessError:
            dialog = utility.message_dialog('udisks2 was unable to mount or'
                                            + ' unmount this devices. Please'
                                            + ' check, if it is installed'
                                            + ' correctly and report this'
                                            + ' error, if the problem'
                                            + ' presists.',
                                            QMessageBox.Critical)
            dialog.exec()
            return
        mount_point = self.mounts.get_mount_point(device)
        if mount_point != '':
            self.mount_selected_event()
        elif former_mount_point == self.current_path:
            self.update_current_path(self.default_path)

    # ---------------- functions ------------------------------------------- #
    def update_current_path(self,
                            next_path: str,
                            skip_stack=False,
                            reset_forward_stack=True):
        """
        Updates the current path to the value given in next_path. It also
        updates the UI accordingly and changes the forward an backward
        stacks, if needed.

        :param next_path: The path to the directory that should become the next
                          dir.
        :type next_path: str
        :param skip_stack: This determines wether the stack handling should be
                           skipped. Default value is False.
        :type skip_stack: bool
        :param reset_forward_stack: This determines wether the forward stack
                                    should be reset or not. Default is True
        :type reset_forward_stack: bool
        """
        self.filesystem.setRootPath(next_path)
        self.table_view.setRootIndex(
            self.filesystem.index(next_path))
        self.table_view.setCurrentIndex(
            self.filesystem.index(self.current_path))
        self.adressbar.setText(next_path)
        self.part_info.setText(utility.part_info(next_path))
        # disable up navigation if in fs root
        if (next_path == QDir().rootPath()):
            self.action_up.setEnabled(False)
        else:
            self.action_up.setEnabled(True)
        # handle back stack
        if (not skip_stack):
            if (self.back_stack.empty()
                    or self.back_stack.top() != self.current_path):
                self.back_stack.push(self.current_path)
                # reenable back navigation
                self.action_back.setEnabled(True)
        if (reset_forward_stack):
            self.forward_stack.drop()
            self.action_forward.setEnabled(False)
        self.current_path = next_path

    def devices_changed(self, action: str, device: Device):
        """
        Updates the mountable devices. Is run, when udev detects a change in
        the block device subsystem.

        :param action: Action that happened to the block device.
        :type action: str
        :param device: Device that changed it's status.
        :type device: Device
        """
        if action == 'add':
            self.mounts.add(device)
        elif action == 'remove':
            self.mounts.remove(device)
        self.mounts.layoutChanged.emit()
예제 #6
0
    def __init__(self, context, parent=None):
        super(Snippets, self).__init__(parent)
        # Create widgets
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.title = QLabel(self.tr("Snippet Editor"))
        self.saveButton = QPushButton(self.tr("&Save"))
        self.saveButton.setShortcut(QKeySequence(self.tr("Ctrl+S")))
        self.runButton = QPushButton(self.tr("&Run"))
        self.runButton.setShortcut(QKeySequence(self.tr("Ctrl+R")))
        self.closeButton = QPushButton(self.tr("Close"))
        self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey"))
        self.setWindowTitle(self.title.text())
        #self.newFolderButton = QPushButton("New Folder")
        self.browseButton = QPushButton("Browse Snippets")
        self.browseButton.setIcon(QIcon.fromTheme("edit-undo"))
        self.deleteSnippetButton = QPushButton("Delete")
        self.newSnippetButton = QPushButton("New Snippet")
        indentation = Settings().get_string("snippets.indentation")
        if Settings().get_bool("snippets.syntaxHighlight"):
            self.edit = QCodeEditor(SyntaxHighlighter=Pylighter,
                                    delimeter=indentation)
        else:
            self.edit = QCodeEditor(SyntaxHighlighter=None,
                                    delimeter=indentation)
        self.edit.setPlaceholderText("python code")
        self.resetting = False
        self.columns = 3
        self.context = context

        self.keySequenceEdit = QKeySequenceEdit(self)
        self.currentHotkey = QKeySequence()
        self.currentHotkeyLabel = QLabel("")
        self.currentFileLabel = QLabel()
        self.currentFile = ""
        self.snippetDescription = QLineEdit()
        self.snippetDescription.setPlaceholderText("optional description")

        #Set Editbox Size
        font = getMonospaceFont(self)
        self.edit.setFont(font)
        font = QFontMetrics(font)
        self.edit.setTabStopDistance(
            4 * font.horizontalAdvance(' '))  #TODO, replace with settings API

        #Files
        self.files = QFileSystemModel()
        self.files.setRootPath(snippetPath)
        self.files.setNameFilters(["*.py"])

        #Tree
        self.tree = QTreeView()
        self.tree.setModel(self.files)
        self.tree.setSortingEnabled(True)
        self.tree.hideColumn(2)
        self.tree.sortByColumn(0, Qt.AscendingOrder)
        self.tree.setRootIndex(self.files.index(snippetPath))
        for x in range(self.columns):
            #self.tree.resizeColumnToContents(x)
            self.tree.header().setSectionResizeMode(
                x, QHeaderView.ResizeToContents)
        treeLayout = QVBoxLayout()
        treeLayout.addWidget(self.tree)
        treeButtons = QHBoxLayout()
        #treeButtons.addWidget(self.newFolderButton)
        treeButtons.addWidget(self.browseButton)
        treeButtons.addWidget(self.newSnippetButton)
        treeButtons.addWidget(self.deleteSnippetButton)
        treeLayout.addLayout(treeButtons)
        treeWidget = QWidget()
        treeWidget.setLayout(treeLayout)

        # Create layout and add widgets
        buttons = QHBoxLayout()
        buttons.addWidget(self.clearHotkeyButton)
        buttons.addWidget(self.keySequenceEdit)
        buttons.addWidget(self.currentHotkeyLabel)
        buttons.addWidget(self.closeButton)
        buttons.addWidget(self.runButton)
        buttons.addWidget(self.saveButton)

        description = QHBoxLayout()
        description.addWidget(QLabel(self.tr("Description: ")))
        description.addWidget(self.snippetDescription)

        vlayoutWidget = QWidget()
        vlayout = QVBoxLayout()
        vlayout.addLayout(description)
        vlayout.addWidget(self.edit)
        vlayout.addLayout(buttons)
        vlayoutWidget.setLayout(vlayout)

        hsplitter = QSplitter()
        hsplitter.addWidget(treeWidget)
        hsplitter.addWidget(vlayoutWidget)

        hlayout = QHBoxLayout()
        hlayout.addWidget(hsplitter)

        self.showNormal()  #Fixes bug that maximized windows are "stuck"
        #Because you can't trust QT to do the right thing here
        if (sys.platform == "darwin"):
            self.settings = QSettings("Vector35", "Snippet Editor")
        else:
            self.settings = QSettings("Vector 35", "Snippet Editor")
        if self.settings.contains("ui/snippeteditor/geometry"):
            self.restoreGeometry(
                self.settings.value("ui/snippeteditor/geometry"))
        else:
            self.edit.setMinimumWidth(80 * font.averageCharWidth())
            self.edit.setMinimumHeight(30 * font.lineSpacing())

        # Set dialog layout
        self.setLayout(hlayout)

        # Add signals
        self.saveButton.clicked.connect(self.save)
        self.closeButton.clicked.connect(self.close)
        self.runButton.clicked.connect(self.run)
        self.clearHotkeyButton.clicked.connect(self.clearHotkey)
        self.tree.selectionModel().selectionChanged.connect(self.selectFile)
        self.newSnippetButton.clicked.connect(self.newFileDialog)
        self.deleteSnippetButton.clicked.connect(self.deleteSnippet)
        #self.newFolderButton.clicked.connect(self.newFolder)
        self.browseButton.clicked.connect(self.browseSnippets)

        if self.settings.contains("ui/snippeteditor/selected"):
            selectedName = self.settings.value("ui/snippeteditor/selected")
            self.tree.selectionModel().select(
                self.files.index(selectedName),
                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
            if self.tree.selectionModel().hasSelection():
                self.selectFile(self.tree.selectionModel().selection(), None)
                self.edit.setFocus()
                cursor = self.edit.textCursor()
                cursor.setPosition(self.edit.document().characterCount() - 1)
                self.edit.setTextCursor(cursor)
            else:
                self.readOnly(True)
        else:
            self.readOnly(True)
예제 #7
0
class Snippets(QDialog):
    def __init__(self, context, parent=None):
        super(Snippets, self).__init__(parent)
        # Create widgets
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.title = QLabel(self.tr("Snippet Editor"))
        self.saveButton = QPushButton(self.tr("&Save"))
        self.saveButton.setShortcut(QKeySequence(self.tr("Ctrl+S")))
        self.runButton = QPushButton(self.tr("&Run"))
        self.runButton.setShortcut(QKeySequence(self.tr("Ctrl+R")))
        self.closeButton = QPushButton(self.tr("Close"))
        self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey"))
        self.setWindowTitle(self.title.text())
        #self.newFolderButton = QPushButton("New Folder")
        self.browseButton = QPushButton("Browse Snippets")
        self.browseButton.setIcon(QIcon.fromTheme("edit-undo"))
        self.deleteSnippetButton = QPushButton("Delete")
        self.newSnippetButton = QPushButton("New Snippet")
        indentation = Settings().get_string("snippets.indentation")
        if Settings().get_bool("snippets.syntaxHighlight"):
            self.edit = QCodeEditor(SyntaxHighlighter=Pylighter,
                                    delimeter=indentation)
        else:
            self.edit = QCodeEditor(SyntaxHighlighter=None,
                                    delimeter=indentation)
        self.edit.setPlaceholderText("python code")
        self.resetting = False
        self.columns = 3
        self.context = context

        self.keySequenceEdit = QKeySequenceEdit(self)
        self.currentHotkey = QKeySequence()
        self.currentHotkeyLabel = QLabel("")
        self.currentFileLabel = QLabel()
        self.currentFile = ""
        self.snippetDescription = QLineEdit()
        self.snippetDescription.setPlaceholderText("optional description")

        #Set Editbox Size
        font = getMonospaceFont(self)
        self.edit.setFont(font)
        font = QFontMetrics(font)
        self.edit.setTabStopDistance(
            4 * font.horizontalAdvance(' '))  #TODO, replace with settings API

        #Files
        self.files = QFileSystemModel()
        self.files.setRootPath(snippetPath)
        self.files.setNameFilters(["*.py"])

        #Tree
        self.tree = QTreeView()
        self.tree.setModel(self.files)
        self.tree.setSortingEnabled(True)
        self.tree.hideColumn(2)
        self.tree.sortByColumn(0, Qt.AscendingOrder)
        self.tree.setRootIndex(self.files.index(snippetPath))
        for x in range(self.columns):
            #self.tree.resizeColumnToContents(x)
            self.tree.header().setSectionResizeMode(
                x, QHeaderView.ResizeToContents)
        treeLayout = QVBoxLayout()
        treeLayout.addWidget(self.tree)
        treeButtons = QHBoxLayout()
        #treeButtons.addWidget(self.newFolderButton)
        treeButtons.addWidget(self.browseButton)
        treeButtons.addWidget(self.newSnippetButton)
        treeButtons.addWidget(self.deleteSnippetButton)
        treeLayout.addLayout(treeButtons)
        treeWidget = QWidget()
        treeWidget.setLayout(treeLayout)

        # Create layout and add widgets
        buttons = QHBoxLayout()
        buttons.addWidget(self.clearHotkeyButton)
        buttons.addWidget(self.keySequenceEdit)
        buttons.addWidget(self.currentHotkeyLabel)
        buttons.addWidget(self.closeButton)
        buttons.addWidget(self.runButton)
        buttons.addWidget(self.saveButton)

        description = QHBoxLayout()
        description.addWidget(QLabel(self.tr("Description: ")))
        description.addWidget(self.snippetDescription)

        vlayoutWidget = QWidget()
        vlayout = QVBoxLayout()
        vlayout.addLayout(description)
        vlayout.addWidget(self.edit)
        vlayout.addLayout(buttons)
        vlayoutWidget.setLayout(vlayout)

        hsplitter = QSplitter()
        hsplitter.addWidget(treeWidget)
        hsplitter.addWidget(vlayoutWidget)

        hlayout = QHBoxLayout()
        hlayout.addWidget(hsplitter)

        self.showNormal()  #Fixes bug that maximized windows are "stuck"
        #Because you can't trust QT to do the right thing here
        if (sys.platform == "darwin"):
            self.settings = QSettings("Vector35", "Snippet Editor")
        else:
            self.settings = QSettings("Vector 35", "Snippet Editor")
        if self.settings.contains("ui/snippeteditor/geometry"):
            self.restoreGeometry(
                self.settings.value("ui/snippeteditor/geometry"))
        else:
            self.edit.setMinimumWidth(80 * font.averageCharWidth())
            self.edit.setMinimumHeight(30 * font.lineSpacing())

        # Set dialog layout
        self.setLayout(hlayout)

        # Add signals
        self.saveButton.clicked.connect(self.save)
        self.closeButton.clicked.connect(self.close)
        self.runButton.clicked.connect(self.run)
        self.clearHotkeyButton.clicked.connect(self.clearHotkey)
        self.tree.selectionModel().selectionChanged.connect(self.selectFile)
        self.newSnippetButton.clicked.connect(self.newFileDialog)
        self.deleteSnippetButton.clicked.connect(self.deleteSnippet)
        #self.newFolderButton.clicked.connect(self.newFolder)
        self.browseButton.clicked.connect(self.browseSnippets)

        if self.settings.contains("ui/snippeteditor/selected"):
            selectedName = self.settings.value("ui/snippeteditor/selected")
            self.tree.selectionModel().select(
                self.files.index(selectedName),
                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
            if self.tree.selectionModel().hasSelection():
                self.selectFile(self.tree.selectionModel().selection(), None)
                self.edit.setFocus()
                cursor = self.edit.textCursor()
                cursor.setPosition(self.edit.document().characterCount() - 1)
                self.edit.setTextCursor(cursor)
            else:
                self.readOnly(True)
        else:
            self.readOnly(True)

    @staticmethod
    def registerAllSnippets():
        for action in list(
                filter(lambda x: x.startswith("Snippets\\"),
                       UIAction.getAllRegisteredActions())):
            if action == "Snippets\\Snippet Editor...":
                continue
            UIActionHandler.globalActions().unbindAction(action)
            Menu.mainMenu("Tools").removeAction(action)
            UIAction.unregisterAction(action)

        for snippet in includeWalk(snippetPath, ".py"):
            snippetKeys = None
            (snippetDescription, snippetKeys,
             snippetCode) = loadSnippetFromFile(snippet)
            actionText = actionFromSnippet(snippet, snippetDescription)
            if snippetCode:
                if snippetKeys == None:
                    UIAction.registerAction(actionText)
                else:
                    UIAction.registerAction(actionText, snippetKeys)
                UIActionHandler.globalActions().bindAction(
                    actionText,
                    UIAction(makeSnippetFunction(snippetCode, actionText)))
                Menu.mainMenu("Tools").addAction(actionText, "Snippets")

    def clearSelection(self):
        self.keySequenceEdit.clear()
        self.currentHotkey = QKeySequence()
        self.currentHotkeyLabel.setText("")
        self.currentFileLabel.setText("")
        self.snippetDescription.setText("")
        self.edit.clear()
        self.tree.clearSelection()
        self.currentFile = ""

    def askSave(self):
        return QMessageBox.question(
            self, self.tr("Save?"),
            self.tr("Do you want to save changes to {}?").format(
                self.currentFileLabel.text()),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)

    def reject(self):
        self.settings.setValue("ui/snippeteditor/geometry",
                               self.saveGeometry())

        if self.snippetChanged():
            save = self.askSave()
            if save == QMessageBox.Yes:
                self.save()
            elif save == QMessageBox.No:
                self.loadSnippet()
            elif save == QMessageBox.Cancel:
                return
        self.accept()

    def browseSnippets(self):
        url = QUrl.fromLocalFile(snippetPath)
        QDesktopServices.openUrl(url)

    def newFolder(self):
        (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"),
                                                self.tr("Folder Name: "))
        if ok and folderName:
            index = self.tree.selectionModel().currentIndex()
            selection = self.files.filePath(index)
            if QFileInfo(selection).isDir():
                QDir(selection).mkdir(folderName)
            else:
                QDir(snippetPath).mkdir(folderName)

    def selectFile(self, new, old):
        if (self.resetting):
            self.resetting = False
            return
        if len(new.indexes()) == 0:
            self.clearSelection()
            self.currentFile = ""
            self.readOnly(True)
            return
        newSelection = self.files.filePath(new.indexes()[0])
        self.settings.setValue("ui/snippeteditor/selected", newSelection)
        if QFileInfo(newSelection).isDir():
            self.readOnly(True)
            self.clearSelection()
            self.currentFile = ""
            return

        if old and old.length() > 0:
            oldSelection = self.files.filePath(old.indexes()[0])
            if not QFileInfo(oldSelection).isDir() and self.snippetChanged():
                save = self.askSave()
                if save == QMessageBox.Yes:
                    self.save()
                elif save == QMessageBox.No:
                    pass
                elif save == QMessageBox.Cancel:
                    self.resetting = True
                    self.tree.selectionModel().select(
                        old, QItemSelectionModel.ClearAndSelect
                        | QItemSelectionModel.Rows)
                    return False

        self.currentFile = newSelection
        self.loadSnippet()

    def loadSnippet(self):
        self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName())
        (snippetDescription, snippetKeys,
         snippetCode) = loadSnippetFromFile(self.currentFile)
        self.snippetDescription.setText(
            snippetDescription
        ) if snippetDescription else self.snippetDescription.setText("")
        self.keySequenceEdit.setKeySequence(
            snippetKeys
        ) if snippetKeys else self.keySequenceEdit.setKeySequence(
            QKeySequence(""))
        self.edit.setPlainText(
            snippetCode) if snippetCode else self.edit.setPlainText("")
        self.readOnly(False)

    def newFileDialog(self):
        (snippetName, ok) = QInputDialog.getText(self,
                                                 self.tr("Snippet Name"),
                                                 self.tr("Snippet Name: "),
                                                 flags=self.windowFlags())
        if ok and snippetName:
            if not snippetName.endswith(".py"):
                snippetName += ".py"
            index = self.tree.selectionModel().currentIndex()
            selection = self.files.filePath(index)
            if QFileInfo(selection).isDir():
                path = os.path.join(selection, snippetName)
            else:
                path = os.path.join(snippetPath, snippetName)
                self.readOnly(False)
            open(path, "w").close()
            self.tree.setCurrentIndex(self.files.index(path))
            log_debug("Snippet %s created." % snippetName)

    def readOnly(self, flag):
        self.keySequenceEdit.setEnabled(not flag)
        self.snippetDescription.setReadOnly(flag)
        self.edit.setReadOnly(flag)
        if flag:
            self.snippetDescription.setDisabled(True)
            self.edit.setDisabled(True)
        else:
            self.snippetDescription.setEnabled(True)
            self.edit.setEnabled(True)

    def deleteSnippet(self):
        selection = self.tree.selectedIndexes()[::self.columns][
            0]  #treeview returns each selected element in the row
        snippetName = self.files.fileName(selection)
        question = QMessageBox.question(
            self, self.tr("Confirm"),
            self.tr("Confirm deletion: ") + snippetName)
        if (question == QMessageBox.StandardButton.Yes):
            log_debug("Deleting snippet %s." % snippetName)
            self.clearSelection()
            self.files.remove(selection)
            self.registerAllSnippets()

    def snippetChanged(self):
        if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()):
            return False
        (snippetDescription, snippetKeys,
         snippetCode) = loadSnippetFromFile(self.currentFile)
        if snippetKeys == None and not self.keySequenceEdit.keySequence(
        ).isEmpty():
            return True
        if snippetKeys != None and snippetKeys != self.keySequenceEdit.keySequence(
        ).toString():
            return True
        return self.edit.toPlainText() != snippetCode or \
               self.snippetDescription.text() != snippetDescription

    def save(self):
        log_debug("Saving snippet %s" % self.currentFile)
        outputSnippet = codecs.open(self.currentFile, "w", "utf-8")
        outputSnippet.write("#" + self.snippetDescription.text() + "\n")
        outputSnippet.write("#" +
                            self.keySequenceEdit.keySequence().toString() +
                            "\n")
        outputSnippet.write(self.edit.toPlainText())
        outputSnippet.close()
        self.registerAllSnippets()

    def run(self):
        if self.context == None:
            log_warn("Cannot run snippets outside of the UI at this time.")
            return
        if self.snippetChanged():
            self.save()
        actionText = actionFromSnippet(self.currentFile,
                                       self.snippetDescription.text())
        UIActionHandler.globalActions().executeAction(actionText, self.context)

        log_debug("Saving snippet %s" % self.currentFile)
        outputSnippet = codecs.open(self.currentFile, "w", "utf-8")
        outputSnippet.write("#" + self.snippetDescription.text() + "\n")
        outputSnippet.write("#" +
                            self.keySequenceEdit.keySequence().toString() +
                            "\n")
        outputSnippet.write(self.edit.toPlainText())
        outputSnippet.close()
        self.registerAllSnippets()

    def clearHotkey(self):
        self.keySequenceEdit.clear()
예제 #8
0
#!/usr/bin/env python3
"""
    【简介】
	PySide6中 QTreeView 例子


"""

import sys
from PySide6.QtWidgets import QApplication, QTreeView, QFileSystemModel
from PySide6.QtCore import QDir
from PySide6.QtGui import *

if __name__ == '__main__':
    app = QApplication(sys.argv)
    # Window系统提供的模式
    model = QFileSystemModel()

    # QFileSystemModel 只有设置了setRootPath后才会起作用。
    model.setRootPath('')
    # 创建一个QtreeView部件
    tree = QTreeView()
    # 为部件添加模式
    tree.setModel(model)
    tree.setWindowTitle("QTreeView 例子")
    tree.resize(500, 310)
    tree.show()
    sys.exit(app.exec())