Fairly substantial rewrite.
This commit is contained in:
180
models.py
180
models.py
@@ -1,15 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
# This file is a part of Lector, a Qt based ebook reader
|
||||
# Copyright (C) 2017 BasioMeusPuga
|
||||
|
||||
from PyQt5 import QtCore, QtGui
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pathlib
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
from resources import pie_chart
|
||||
|
||||
|
||||
class LibraryItemModel(QtGui.QStandardItemModel, QtCore.QAbstractItemModel):
|
||||
class ItemProxyModel(QtCore.QSortFilterProxyModel):
|
||||
# TODO
|
||||
# Implement filterAcceptsRow
|
||||
|
||||
def __init__(self, parent=None):
|
||||
# We're using this to be able to access the match() method
|
||||
super(LibraryItemModel, self).__init__(parent)
|
||||
super(ItemProxyModel, self).__init__(parent)
|
||||
|
||||
|
||||
class MostExcellentTableModel(QtCore.QAbstractTableModel):
|
||||
@@ -39,7 +57,7 @@ class MostExcellentTableModel(QtCore.QAbstractTableModel):
|
||||
if not index.isValid():
|
||||
return None
|
||||
|
||||
# This block specializaes this function for the library
|
||||
# This block specializes this function for the library
|
||||
# Not having a self.temp_dir allows for its reuse elsewhere
|
||||
if self.temp_dir:
|
||||
if role == QtCore.Qt.DecorationRole and index.column() == 2:
|
||||
@@ -71,7 +89,8 @@ class MostExcellentTableModel(QtCore.QAbstractTableModel):
|
||||
return value
|
||||
|
||||
#_________________________________
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
# The EditRole is so that editing a cell doesn't clear its contents
|
||||
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
|
||||
value = self.display_data[index.row()][index.column()]
|
||||
return value
|
||||
|
||||
@@ -84,8 +103,8 @@ class MostExcellentTableModel(QtCore.QAbstractTableModel):
|
||||
return None
|
||||
|
||||
def flags(self, index):
|
||||
# In case of the settings model, model column index 1+ are editable
|
||||
if not self.temp_dir and index.column() != 0:
|
||||
# This means only the Tags column is editable
|
||||
if self.temp_dir and index.column() == 4:
|
||||
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
|
||||
else:
|
||||
# These are standard select but don't edit values
|
||||
@@ -124,10 +143,151 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
|
||||
model = self.sourceModel()
|
||||
|
||||
valid_indices = [model.index(row_num, i) for i in self.filter_columns]
|
||||
valid_data = [model.data(i, QtCore.Qt.DisplayRole).lower() for i in valid_indices if model.data(i, QtCore.Qt.DisplayRole) is not None]
|
||||
valid_data = [
|
||||
model.data(i, QtCore.Qt.DisplayRole).lower() for i in valid_indices if model.data(
|
||||
i, QtCore.Qt.DisplayRole) is not None]
|
||||
|
||||
for i in valid_data:
|
||||
if self.filter_string in i:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class MostExcellentFileSystemModel(QtWidgets.QFileSystemModel):
|
||||
# Directories are tracked on the basis of their paths
|
||||
# Poll the tag_data dictionary to get User selection
|
||||
def __init__(self, tag_data, parent=None):
|
||||
super(MostExcellentFileSystemModel, self).__init__(parent)
|
||||
self.tag_data = tag_data
|
||||
self.field_dict = {
|
||||
0: 'check_state',
|
||||
4: 'name',
|
||||
5: 'tags'}
|
||||
|
||||
def columnCount(self, parent):
|
||||
# The QFileSystemModel returns 4 columns by default
|
||||
# Columns 1, 2, 3 will be present but hidden
|
||||
return 6
|
||||
|
||||
def headerData(self, col, orientation, role):
|
||||
# Columns not mentioned here will be hidden
|
||||
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
|
||||
column_dict = {
|
||||
0: 'Path',
|
||||
4: 'Name',
|
||||
5: 'Tags'}
|
||||
return column_dict[col]
|
||||
|
||||
def data(self, index, role):
|
||||
if (index.column() in (4, 5)
|
||||
and (role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole)):
|
||||
|
||||
read_field = self.field_dict[index.column()]
|
||||
try:
|
||||
return self.tag_data[self.filePath(index)][read_field]
|
||||
except KeyError:
|
||||
return QtCore.QVariant()
|
||||
|
||||
if role == QtCore.Qt.CheckStateRole and index.column() == 0:
|
||||
return self.checkState(index)
|
||||
|
||||
return QtWidgets.QFileSystemModel.data(self, index, role)
|
||||
|
||||
def flags(self, index):
|
||||
if index.column() in (4, 5):
|
||||
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
|
||||
else:
|
||||
return QtWidgets.QFileSystemModel.flags(self, index) | QtCore.Qt.ItemIsUserCheckable
|
||||
|
||||
def checkState(self, index):
|
||||
while index.isValid():
|
||||
index_path = self.filePath(index)
|
||||
if index_path in self.tag_data:
|
||||
return self.tag_data[index_path]['check_state']
|
||||
index = index.parent()
|
||||
return QtCore.Qt.Unchecked
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if (role == QtCore.Qt.EditRole or role == QtCore.Qt.CheckStateRole) and index.isValid():
|
||||
write_field = self.field_dict[index.column()]
|
||||
self.layoutAboutToBeChanged.emit()
|
||||
|
||||
this_path = self.filePath(index)
|
||||
if this_path not in self.tag_data:
|
||||
self.populate_dictionary(this_path)
|
||||
self.tag_data[this_path][write_field] = value
|
||||
|
||||
self.depopulate_dictionary()
|
||||
|
||||
self.layoutChanged.emit()
|
||||
return True
|
||||
|
||||
def populate_dictionary(self, path):
|
||||
self.tag_data[path] = {}
|
||||
self.tag_data[path]['name'] = None
|
||||
self.tag_data[path]['tags'] = None
|
||||
self.tag_data[path]['check_state'] = QtCore.Qt.Checked
|
||||
|
||||
def depopulate_dictionary(self):
|
||||
# This keeps the tag_data dictionary manageable as well as preventing
|
||||
# weird ass behaviour when something is deselected and its tags are cleared
|
||||
deletable = set()
|
||||
for i in self.tag_data.items():
|
||||
all_data = [j[1] for j in i[1].items()]
|
||||
filtered_down = list(filter(lambda x: x is not None and x != 0, all_data))
|
||||
if not filtered_down:
|
||||
deletable.add(i[0])
|
||||
|
||||
# Get untagged subdirectories too
|
||||
all_dirs = [i for i in self.tag_data]
|
||||
all_dirs.sort()
|
||||
|
||||
def is_child(this_dir):
|
||||
this_path = pathlib.Path(this_dir)
|
||||
for i in all_dirs:
|
||||
if pathlib.Path(i) in this_path.parents:
|
||||
# If a parent folder has tags, we only want the deletion
|
||||
# to kick in in case the parent is also checked
|
||||
if self.tag_data[i]['check_state'] == QtCore.Qt.Checked:
|
||||
return True
|
||||
return False
|
||||
|
||||
for i in all_dirs:
|
||||
if is_child(i):
|
||||
dir_tags = (self.tag_data[i]['name'], self.tag_data[i]['tags'])
|
||||
filtered_down = list(filter(lambda x: x is not None and x != '', dir_tags))
|
||||
if not filtered_down:
|
||||
deletable.add(i)
|
||||
|
||||
for i in deletable:
|
||||
del self.tag_data[i]
|
||||
|
||||
|
||||
# TODO
|
||||
# Unbork this
|
||||
class FileSystemProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def __init__(self, parent=None):
|
||||
super(FileSystemProxyModel, self).__init__(parent)
|
||||
|
||||
def filterAcceptsRow(self, row_num, parent):
|
||||
model = self.sourceModel()
|
||||
filter_out = [
|
||||
'boot', 'dev', 'etc', 'lost+found', 'opt', 'pdb',
|
||||
'proc', 'root', 'run', 'srv', 'sys', 'tmp', 'twonky',
|
||||
'usr', 'var', 'bin', 'kdeinit5__0', 'lib', 'lib64', 'sbin']
|
||||
|
||||
name_index = model.index(row_num, 0)
|
||||
valid_data = model.data(name_index)
|
||||
|
||||
print(valid_data)
|
||||
|
||||
return True
|
||||
|
||||
try:
|
||||
if valid_data in filter_out:
|
||||
return False
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
Reference in New Issue
Block a user