Skip to content

Commit 5690011

Browse files
committed
Convert transitions model to use proxy filter and sort class, with custom sort and filter function (which takes into account the group: common, extra, user) and the filter text. Also, moved the models outside of the widgets for Effects, Transitions, and Emojis.
1 parent 2ab54f1 commit 5690011

7 files changed

+107
-66
lines changed

src/windows/main_window.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@
5555
from images import openshot_rc
5656
from windows.views.files_treeview import FilesTreeView
5757
from windows.views.files_listview import FilesListView
58+
from windows.models.transition_model import TransitionsModel
5859
from windows.views.transitions_treeview import TransitionsTreeView
5960
from windows.views.transitions_listview import TransitionsListView
61+
from windows.models.emoji_model import EmojisModel
6062
from windows.views.emojis_listview import EmojisListView
63+
from windows.models.effects_model import EffectsModel
6164
from windows.views.effects_treeview import EffectsTreeView
6265
from windows.views.effects_listview import EffectsListView
6366
from windows.views.properties_tableview import PropertiesTableView, SelectionLabel
@@ -1839,7 +1842,7 @@ def actionDetailsView_trigger(self, event):
18391842
self.tabTransitions.layout().removeWidget(self.transitionsTreeView)
18401843
self.transitionsTreeView.deleteLater()
18411844
self.transitionsTreeView = None
1842-
self.transitionsTreeView = TransitionsTreeView(self)
1845+
self.transitionsTreeView = TransitionsTreeView(self.transition_model)
18431846
self.tabTransitions.layout().addWidget(self.transitionsTreeView)
18441847

18451848
# Effects
@@ -1848,7 +1851,7 @@ def actionDetailsView_trigger(self, event):
18481851
self.tabEffects.layout().removeWidget(self.effectsTreeView)
18491852
self.effectsTreeView.deleteLater()
18501853
self.effectsTreeView = None
1851-
self.effectsTreeView = EffectsTreeView(self)
1854+
self.effectsTreeView = EffectsTreeView(self.effects_model)
18521855
self.tabEffects.layout().addWidget(self.effectsTreeView)
18531856

18541857
def actionThumbnailView_trigger(self, event):
@@ -1877,7 +1880,7 @@ def actionThumbnailView_trigger(self, event):
18771880
self.tabTransitions.layout().removeWidget(self.transitionsTreeView)
18781881
self.transitionsTreeView.deleteLater()
18791882
self.transitionsTreeView = None
1880-
self.transitionsTreeView = TransitionsListView(self)
1883+
self.transitionsTreeView = TransitionsListView(self.transition_model)
18811884
self.tabTransitions.layout().addWidget(self.transitionsTreeView)
18821885

18831886
# Effects
@@ -1886,7 +1889,7 @@ def actionThumbnailView_trigger(self, event):
18861889
self.tabEffects.layout().removeWidget(self.effectsTreeView)
18871890
self.effectsTreeView.deleteLater()
18881891
self.effectsTreeView = None
1889-
self.effectsTreeView = EffectsListView(self)
1892+
self.effectsTreeView = EffectsListView(self.effects_model)
18901893
self.tabEffects.layout().addWidget(self.effectsTreeView)
18911894

18921895
def resize_contents(self):
@@ -2550,21 +2553,24 @@ def __init__(self, mode=None):
25502553
self.filesTreeView.setFocus()
25512554

25522555
# Setup transitions tree
2556+
self.transition_model = TransitionsModel()
25532557
if s.get("transitions_view") == "details":
2554-
self.transitionsTreeView = TransitionsTreeView(self)
2558+
self.transitionsTreeView = TransitionsTreeView(self.transition_model)
25552559
else:
2556-
self.transitionsTreeView = TransitionsListView(self)
2560+
self.transitionsTreeView = TransitionsListView(self.transition_model)
25572561
self.tabTransitions.layout().addWidget(self.transitionsTreeView)
25582562

25592563
# Setup effects tree
2564+
self.effects_model = EffectsModel()
25602565
if s.get("effects_view") == "details":
2561-
self.effectsTreeView = EffectsTreeView(self)
2566+
self.effectsTreeView = EffectsTreeView(self.effects_model)
25622567
else:
2563-
self.effectsTreeView = EffectsListView(self)
2568+
self.effectsTreeView = EffectsListView(self.effects_model)
25642569
self.tabEffects.layout().addWidget(self.effectsTreeView)
25652570

25662571
# Setup emojis view
2567-
self.emojiListView = EmojisListView(self)
2572+
self.emoji_model = EmojisModel()
2573+
self.emojiListView = EmojisListView(self.emoji_model)
25682574
self.tabEmojis.layout().addWidget(self.emojiListView)
25692575

25702576
# Set up status bar

src/windows/models/transition_model.py

+33-10
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
import os
2929

30-
from PyQt5.QtCore import QMimeData, Qt
30+
from PyQt5.QtCore import QMimeData, Qt, QSortFilterProxyModel
3131
from PyQt5.QtGui import *
3232
from PyQt5.QtWidgets import QMessageBox
3333
import openshot # Python module for libopenshot (required video editing module installed separately)
@@ -58,6 +58,37 @@ def mimeData(self, indexes):
5858
return data
5959

6060

61+
class TransitionFilterProxyModel(QSortFilterProxyModel):
62+
"""Proxy class used for sorting and filtering model data"""
63+
64+
def filterAcceptsRow(self, sourceRow, sourceParent):
65+
"""Filter for common transitions and text filter"""
66+
67+
if get_app().window.actionTransitionsShowCommon.isChecked():
68+
# Fetch the group name
69+
index = self.sourceModel().index(sourceRow, 2, sourceParent) # group name column
70+
group_name = self.sourceModel().data(index) # group name (i.e. common)
71+
72+
# Fetch the transitions name
73+
index = self.sourceModel().index(sourceRow, 0, sourceParent) # transition name column
74+
trans_name = self.sourceModel().data(index) # transition name (i.e. Fade In)
75+
76+
# Return, if regExp match in displayed format.
77+
return "common" == group_name and self.filterRegExp().indexIn(trans_name) >= 0
78+
79+
# Continue running built-in parent filter logic
80+
return super(TransitionFilterProxyModel, self).filterAcceptsRow(sourceRow, sourceParent)
81+
82+
def lessThan(self, left, right):
83+
"""Sort with both group name and transition name"""
84+
leftData = self.sourceModel().data(left)
85+
leftGroup = self.sourceModel().data(left, 257) # Strange way to access 'type' column in model
86+
rightData = self.sourceModel().data(right)
87+
rightGroup = self.sourceModel().data(right, 257)
88+
89+
return leftGroup < rightGroup and leftData < rightData
90+
91+
6192
class TransitionsModel():
6293
def update_model(self, clear=True):
6394
log.info("updating transitions model.")
@@ -115,15 +146,6 @@ def update_model(self, clear=True):
115146
else:
116147
trans_name = self.app._tr(trans_name)
117148

118-
if not win.actionTransitionsShowAll.isChecked():
119-
if win.actionTransitionsShowCommon.isChecked():
120-
if not type == "common":
121-
continue # to next file, didn't match filter
122-
123-
if win.transitionsFilter.text() != "":
124-
if not win.transitionsFilter.text().lower() in trans_name.lower():
125-
continue
126-
127149
# Check for thumbnail path (in build-in cache)
128150
thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName))
129151

@@ -164,6 +186,7 @@ def update_model(self, clear=True):
164186
col.setIcon(QIcon(thumb_path))
165187
col.setText(trans_name)
166188
col.setToolTip(trans_name)
189+
col.setData(type)
167190
col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
168191
row.append(col)
169192

src/windows/views/effects_listview.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
"""
1+
"""
22
@file
33
@brief This file contains the effects file listview, used by the main window
44
@author Jonathan Thomas <[email protected]>
5-
5+
66
@section LICENSE
7-
7+
88
Copyright (c) 2008-2018 OpenShot Studios, LLC
99
(http://www.openshotstudios.com). This file is part of
1010
OpenShot Video Editor (http://www.openshot.org), an open-source project
1111
dedicated to delivering high quality video editing and animation solutions
1212
to the world.
13-
13+
1414
OpenShot Video Editor is free software: you can redistribute it and/or modify
1515
it under the terms of the GNU General Public License as published by
1616
the Free Software Foundation, either version 3 of the License, or
1717
(at your option) any later version.
18-
18+
1919
OpenShot Video Editor is distributed in the hope that it will be useful,
2020
but WITHOUT ANY WARRANTY; without even the implied warranty of
2121
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2222
GNU General Public License for more details.
23-
23+
2424
You should have received a copy of the GNU General Public License
2525
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2626
"""
@@ -67,15 +67,15 @@ def filter_changed(self):
6767
def refresh_view(self):
6868
self.effects_model.update_model()
6969

70-
def __init__(self, *args):
70+
def __init__(self, model):
7171
# Invoke parent init
72-
QListView.__init__(self, *args)
72+
QListView.__init__(self)
7373

7474
# Get a reference to the window object
7575
self.win = get_app().window
7676

7777
# Get Model data
78-
self.effects_model = EffectsModel()
78+
self.effects_model = model
7979

8080
# Keep track of mouse press start position to determine when to start drag
8181
self.setAcceptDrops(True)

src/windows/views/effects_treeview.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
"""
1+
"""
22
@file
33
@brief This file contains the effects file treeview, used by the main window
44
@author Jonathan Thomas <[email protected]>
5-
5+
66
@section LICENSE
7-
7+
88
Copyright (c) 2008-2018 OpenShot Studios, LLC
99
(http://www.openshotstudios.com). This file is part of
1010
OpenShot Video Editor (http://www.openshot.org), an open-source project
1111
dedicated to delivering high quality video editing and animation solutions
1212
to the world.
13-
13+
1414
OpenShot Video Editor is free software: you can redistribute it and/or modify
1515
it under the terms of the GNU General Public License as published by
1616
the Free Software Foundation, either version 3 of the License, or
1717
(at your option) any later version.
18-
18+
1919
OpenShot Video Editor is distributed in the hope that it will be useful,
2020
but WITHOUT ANY WARRANTY; without even the implied warranty of
2121
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2222
GNU General Public License for more details.
23-
23+
2424
You should have received a copy of the GNU General Public License
2525
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2626
"""
@@ -70,15 +70,15 @@ def refresh_view(self):
7070
self.hideColumn(3)
7171
self.hideColumn(4)
7272

73-
def __init__(self, *args):
73+
def __init__(self, model):
7474
# Invoke parent init
75-
QTreeView.__init__(self, *args)
75+
QTreeView.__init__(self)
7676

7777
# Get a reference to the window object
7878
self.win = get_app().window
7979

8080
# Get Model data
81-
self.effects_model = EffectsModel()
81+
self.effects_model = model
8282

8383
# Keep track of mouse press start position to determine when to start drag
8484
self.setAcceptDrops(True)

src/windows/views/emojis_listview.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,21 @@ def filter_changed(self):
114114
self.refresh_view()
115115

116116
def refresh_view(self):
117+
"""Filter transitions with proxy class"""
117118
filter_text = self.win.emojisFilter.text()
118119
self.proxy_model.setFilterRegExp(QRegExp(filter_text.replace(' ', '.*')))
119120
self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
120121
self.proxy_model.sort(Qt.AscendingOrder)
121122

122-
def __init__(self, *args):
123+
def __init__(self, model):
123124
# Invoke parent init
124-
QListView.__init__(self, *args)
125+
QListView.__init__(self)
125126

126127
# Get a reference to the window object
127128
self.win = get_app().window
128129

129130
# Get Model data
130-
self.emojis_model = EmojisModel()
131+
self.emojis_model = model
131132

132133
# Create proxy model (for sorting and filtering)
133134
self.proxy_model = QSortFilterProxyModel(self)

src/windows/views/transitions_listview.py

+28-17
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
"""
1+
"""
22
@file
33
@brief This file contains the transitions file treeview, used by the main window
44
@author Jonathan Thomas <[email protected]>
5-
5+
66
@section LICENSE
7-
7+
88
Copyright (c) 2008-2018 OpenShot Studios, LLC
99
(http://www.openshotstudios.com). This file is part of
1010
OpenShot Video Editor (http://www.openshot.org), an open-source project
1111
dedicated to delivering high quality video editing and animation solutions
1212
to the world.
13-
13+
1414
OpenShot Video Editor is free software: you can redistribute it and/or modify
1515
it under the terms of the GNU General Public License as published by
1616
the Free Software Foundation, either version 3 of the License, or
1717
(at your option) any later version.
18-
18+
1919
OpenShot Video Editor is distributed in the hope that it will be useful,
2020
but WITHOUT ANY WARRANTY; without even the implied warranty of
2121
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2222
GNU General Public License for more details.
23-
23+
2424
You should have received a copy of the GNU General Public License
2525
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2626
"""
2727

28-
from PyQt5.QtCore import QSize, QPoint, Qt
28+
from PyQt5.QtCore import QSize, QPoint, Qt, QRegExp
2929
from PyQt5.QtGui import *
3030
from PyQt5.QtWidgets import QListView, QMenu
3131

3232
from classes.app import get_app
33-
from windows.models.transition_model import TransitionsModel
33+
from windows.models.transition_model import TransitionsModel, TransitionFilterProxyModel
3434

3535
import json
3636

@@ -54,12 +54,12 @@ def startDrag(self, event):
5454
""" Override startDrag method to display custom icon """
5555

5656
# Get image of selected item
57-
selected_row = self.transition_model.model.itemFromIndex(self.selectionModel().selectedIndexes()[0]).row()
57+
selected_row = self.transition_model.model.itemFromIndex(self.proxy_model.mapToSource(self.selectionModel().selectedIndexes()[0])).row()
5858
icon = self.transition_model.model.item(selected_row, 0).icon()
5959

6060
# Start drag operation
6161
drag = QDrag(self)
62-
drag.setMimeData(self.transition_model.model.mimeData(self.selectionModel().selectedIndexes()))
62+
drag.setMimeData(self.proxy_model.mimeData(self.selectionModel().selectedIndexes()))
6363
# drag.setPixmap(QIcon.fromTheme('document-new').pixmap(QSize(self.drag_item_size,self.drag_item_size)))
6464
drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
6565
drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
@@ -69,25 +69,36 @@ def filter_changed(self):
6969
self.refresh_view()
7070

7171
def refresh_view(self):
72-
self.transition_model.update_model()
72+
"""Filter transitions with proxy class"""
73+
filter_text = self.win.transitionsFilter.text()
74+
self.proxy_model.setFilterRegExp(QRegExp(filter_text.replace(' ', '.*')))
75+
self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
76+
self.proxy_model.sort(Qt.AscendingOrder)
7377

74-
def __init__(self, *args):
78+
def __init__(self, model):
7579
# Invoke parent init
76-
QListView.__init__(self, *args)
80+
QListView.__init__(self)
7781

7882
# Get a reference to the window object
7983
self.win = get_app().window
8084

8185
# Get Model data
82-
self.transition_model = TransitionsModel()
86+
self.transition_model = model
87+
88+
# Create proxy model (for sorting and filtering)
89+
self.proxy_model = TransitionFilterProxyModel(self)
90+
self.proxy_model.setDynamicSortFilter(True)
91+
self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
92+
self.proxy_model.setSortCaseSensitivity(Qt.CaseSensitive)
93+
self.proxy_model.setSourceModel(self.transition_model.model)
8394

8495
# Keep track of mouse press start position to determine when to start drag
8596
self.setAcceptDrops(True)
8697
self.setDragEnabled(True)
8798
self.setDropIndicatorShown(True)
8899

89100
# Setup header columns
90-
self.setModel(self.transition_model.model)
101+
self.setModel(self.proxy_model)
91102
self.setIconSize(QSize(131, 108))
92103
self.setGridSize(QSize(102, 92))
93104
self.setViewMode(QListView.IconMode)
@@ -97,8 +108,8 @@ def __init__(self, *args):
97108
self.setTextElideMode(Qt.ElideRight)
98109
self.setStyleSheet('QListView::item { padding-top: 2px; }')
99110

100-
# Refresh view
101-
self.refresh_view()
111+
# Load initial transition model data
112+
self.transition_model.update_model()
102113

103114
# setup filter events
104115
app = get_app()

0 commit comments

Comments
 (0)