Skip to content

Commit ab2435a

Browse files
committed
Title Editor: Model & program flow tweaks
- New model design uses only a single column, all data for each template is stored on the same QStandardItem under different roles - TitleRoles.PathRole references the file path (former column 2) - Dialog now preserves user-supplied filename across launches of the external Advanced Editor process - TitlesModel is now a QObject, parented to MainWindow
1 parent 837cc15 commit ab2435a

File tree

4 files changed

+161
-212
lines changed

4 files changed

+161
-212
lines changed

src/windows/main_window.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -416,14 +416,9 @@ def actionTitle_trigger(self):
416416
from windows.title_editor import TitleEditor
417417
win = TitleEditor()
418418
# Run the dialog event loop - blocking interaction on this window during that time
419-
result = win.exec_()
420-
if result == QDialog.Accepted:
421-
log.info('title editor add confirmed')
422-
else:
423-
log.info('title editor add cancelled')
419+
win.exec_()
424420

425421
def actionEditTitle_trigger(self):
426-
427422
# Loop through selected files (set 1 selected file if more than 1)
428423
for f in self.selected_files():
429424
if f.data.get("path").endswith(".svg"):
@@ -436,7 +431,7 @@ def actionEditTitle_trigger(self):
436431

437432
# show dialog for editing title
438433
from windows.title_editor import TitleEditor
439-
win = TitleEditor(file_path)
434+
win = TitleEditor(edit_file_path=file_path)
440435
# Run the dialog event loop - blocking interaction on this window during that time
441436
win.exec_()
442437

@@ -470,7 +465,7 @@ def actionDuplicateTitle_trigger(self):
470465

471466
# show dialog for editing title
472467
from windows.title_editor import TitleEditor
473-
win = TitleEditor(file_path, duplicate=True)
468+
win = TitleEditor(edit_file_path=file_path, duplicate=True)
474469
# Run the dialog event loop - blocking interaction on this window during that time
475470
return win.exec_()
476471

src/windows/models/titles_model.py

+57-69
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import os
2929
import fnmatch
3030

31-
from PyQt5.QtCore import QMimeData, Qt, QSize
32-
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QIcon, QPixmap
31+
from PyQt5.QtCore import Qt, QObject, QMimeData
32+
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QIcon
3333
from PyQt5.QtWidgets import QMessageBox
3434
import openshot # Python module for libopenshot (required video editing module installed separately)
3535

@@ -41,52 +41,56 @@
4141

4242

4343
class TitleStandardItemModel(QStandardItemModel):
44-
def __init__(self, parent=None):
45-
QStandardItemModel.__init__(self)
44+
def __init__(self, *args, **kwargs):
45+
super().__init__(*args, **kwargs)
46+
self.setObjectName("titles.model")
4647

4748
def mimeData(self, indexes):
4849
# Create MimeData for drag operation
4950
data = QMimeData()
5051

5152
# Get list of all selected file ids
52-
files = []
53-
for item in indexes:
54-
selected_row = self.itemFromIndex(item).row()
55-
files.append(self.item(selected_row, 2).text())
53+
files = [
54+
self.itemFromIndex(i).data(TitleRoles.PathRole)
55+
for i in indexes
56+
]
5657
data.setText(json.dumps(files))
5758
data.setHtml("title")
5859

5960
# Return Mimedata
6061
return data
6162

6263

63-
class TitlesModel():
64-
def update_model(self, clear=True):
65-
log.info("updating title model.")
66-
app = get_app()
64+
class TitleRoles:
65+
PathRole = Qt.UserRole + 11
66+
6767

68-
_ = app._tr
68+
class TitlesModel(QObject):
69+
def update_model(self, clear=True):
70+
log.debug("Updating title model")
71+
# Get window to check filters
72+
_ = self.app._tr
6973

7074
# Clear all items
7175
if clear:
7276
self.model_paths = {}
7377
self.model.clear()
7478

7579
# Add Headers
76-
self.model.setHorizontalHeaderLabels([_("Thumb"), _("Name")])
80+
self.model.setHorizontalHeaderLabels([_("Name")])
7781

78-
# get a list of files in the OpenShot /transitions directory
82+
# get a list of files in the OpenShot package directory
7983
titles_dir = os.path.join(info.PATH, "titles")
80-
81-
# Add build-in templates
82-
titles_list = []
83-
for filename in sorted(os.listdir(titles_dir)):
84-
titles_list.append(os.path.join(titles_dir, filename))
85-
84+
titles_list = [
85+
os.path.join(titles_dir, filename)
86+
for filename in sorted(os.listdir(titles_dir))
87+
]
8688
# Add user-defined titles (if any)
87-
for filename in sorted(os.listdir(info.USER_TITLES_PATH)):
88-
if fnmatch.fnmatch(filename, '*.svg'):
89-
titles_list.append(os.path.join(info.USER_TITLES_PATH, filename))
89+
titles_list.extend([
90+
os.path.join(info.USER_TITLES_PATH, filename)
91+
for filename in sorted(os.listdir(info.USER_TITLES_PATH))
92+
if fnmatch.fnmatch(filename, '*.svg')
93+
])
9094

9195
for path in sorted(titles_list):
9296
filename = os.path.basename(path)
@@ -116,78 +120,62 @@ def update_model(self, clear=True):
116120

117121
# Check for thumbnail path (in build-in cache)
118122
thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName))
119-
120-
# Check built-in cache (if not found)
121123
if not os.path.exists(thumb_path):
122-
# Check user folder cache
124+
# Check user folder cache (if not found)
123125
thumb_path = os.path.join(info.CACHE_PATH, "{}.png".format(fileBaseName))
124-
125-
# Generate thumbnail (if needed)
126126
if not os.path.exists(thumb_path):
127-
127+
# Generate thumbnail (if needed)
128128
try:
129129
# Reload this reader
130130
clip = openshot.Clip(path)
131131
reader = clip.Reader()
132-
133-
# Open reader
134132
reader.Open()
135133

136-
# Save thumbnail
134+
# Save thumbnail to disk
137135
reader.GetFrame(0).Thumbnail(
138136
thumb_path, 98, 64,
139137
os.path.join(info.IMAGES_PATH, "mask.png"),
140138
"", "#000", True, "png", 85
141139
)
142140
reader.Close()
143141
clip.Close()
144-
145142
except Exception as ex:
146-
# Handle exception
147143
log.info('Failed to open {} as title: {}'.format(filename, ex))
148144
msg = QMessageBox()
149145
msg.setText(_("%s is not a valid image file." % filename))
150146
msg.exec_()
151147
continue
152-
153-
row = []
154-
155-
# Append thumbnail
156-
col = QStandardItem()
157-
icon_pixmap = QPixmap(thumb_path)
158-
scaled_pixmap = icon_pixmap.scaled(QSize(93, 62), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
159-
col.setIcon(QIcon(scaled_pixmap))
160-
col.setText(title_name)
161-
col.setToolTip(title_name)
162-
col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
163-
row.append(col)
164-
165-
# Append Filename
166-
col = QStandardItem("Name")
167-
col.setData(title_name, Qt.DisplayRole)
168-
col.setText(title_name)
169-
col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
170-
row.append(col)
171-
172-
# Append Path
173-
col = QStandardItem("Path")
174-
col.setData(path, Qt.DisplayRole)
175-
col.setText(path)
176-
col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
177-
row.append(col)
178-
179-
# Append ROW to MODEL (if does not already exist in model)
148+
# Create item entry for model
149+
flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled
150+
item = QStandardItem(QIcon(thumb_path), title_name)
151+
item.setData(path, TitleRoles.PathRole)
152+
item.setToolTip(title_name)
153+
item.setFlags(flags)
154+
# Append to MODEL (if does not already exist)
180155
if path not in self.model_paths:
181-
self.model.appendRow(row)
156+
self.model.appendRow([item])
182157
self.model_paths[path] = path
183158

184159
# Process events in QT (to keep the interface responsive)
185-
app.processEvents()
186-
187-
def __init__(self, *args):
160+
self.app.processEvents()
188161

162+
def __init__(self, *args, **kwargs):
163+
super().__init__(*args, **kwargs)
164+
self.setObjectName("TitlesModel")
189165
# Create standard model
190166
self.app = get_app()
191-
self.model = TitleStandardItemModel()
192-
self.model.setColumnCount(3)
167+
self.model = TitleStandardItemModel(self.parent())
168+
self.model.setColumnCount(1)
193169
self.model_paths = {}
170+
171+
# Attempt to load model testing interface, if requested
172+
# (will only succeed with Qt 5.11+)
173+
if info.MODEL_TEST:
174+
try:
175+
# Create model tester objects
176+
from PyQt5.QtTest import QAbstractItemModelTester
177+
QAbstractItemModelTester(
178+
self.model, QAbstractItemModelTester.FailureReportingMode.Warning)
179+
log.info("Enabled model tests for title editor data")
180+
except ImportError:
181+
pass

0 commit comments

Comments
 (0)