Editing entries of QTreeView with QFileSystemModel

Question:

I have written a program to en/decyrpt files and folders (including the names of them). The encrypted folder looks like that:

- rootFolder:        folder
    - 19479:         folder
          91039      file
          49761      file
    - 06937:         folder

Next, I wanted to make a TreeView to represent the folder structure with the decrypted names (so you know which is which). The problem here is that I can’t access the items of the TreeView/TreeModel. My goal is to

  1. read out every single entry (e.g with a for loop)
  2. (optional: get absolute path of entry if possible)
  3. update the entries with the decrypted ones

My current code:

from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QDialog, QTreeView
from PyQt5.Qt import QFileSystemModel
from PyQt5.QtCore import QDir


class TreeView_Window(QDialog):
    def __init__(self):
        super(TreeView_Window, self).__init__()
        loadUi("GUI/tree_view_window.ui", self)
        self.btn_create_tree.clicked.connect(self.create_tree)
        self.treeModel = QFileSystemModel()
        self.treeView.doubleClicked.connect(self.getValue)

    def create_tree(self):
        path = r"C:SomeFolderAnotherFolder"
        password = "password"
        self.treeView.setModel(self.treeModel)
        self.treeModel.setRootPath(QDir.rootPath())
        self.treeView.setRootIndex(self.treeModel.index(path))
        self.treeView.setAnimated(False)
        self.treeView.setIndentation(20)
        [self.treeView.setColumnWidth(x, 200) for x in range(0, 4)]
        self.treeView.frameGeometry().width()
        self.treeView.setSortingEnabled(False)

        # Like so for example:
        for item, index in treeViewItems:  # Loop through the items
           decrypted_name = decryptFileName(item, password)  # Decrypt the name
           self.treeView.setItem(decrypted_name, index)  # update the item to the decrypted one

I tried: self.treeModel.data(self.treeModel.index(0,0)) which only gives me the root ‘C:’
Copying the folder and decrypting the copy is not an option due to the reduction in speed, etc.

Asked By: Pascal Vallaster

||

Answers:

You can use a QIdentityProxyModel and override its data() function in order to return the decrypted name. For obvious reasons, you should always check if the given path actually corresponds to an encrypted file and return a proper value accordingly.

Note that, since the view will use a different model, you cannot use setRootIndex() with an index from the QFileSystemModel, as it would be invalid for the view, so you need to map the index to the proxy.

Also, if you need to implement this also for the other columns, you obviously need to check for them.

class DecryptedModel(QIdentityProxyModel):
    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole:
            if index.column() == 1: # file name
                path = self.sourceModel().filePath(
                    self.mapToSource(index))
                return decryptFileName(path, password)
            elif index.column() == 2: # size
                # etc.
        return super().data(index, role)

class TreeView_Window(QDialog):
    #...
    def create_tree(self):
        self.decryptModel = DecryptedModel()
        self.decryptModel.setSourceModel(self.treeModel)
        self.treeView.setModel(self.decryptModel)

        sourceRootIndex = self.treeModel.index(path)
        self.treeView.setRootIndex(
            self.decryptModel.mapFromSource(sourceRootIndex))

If you need to also provide renaming features, then you shall also check if the role is EditRole in data(), and also override setData() for the same role, by calling the setData() of the source model with the encrypted name.

Answered By: musicamante
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.