OpenShot Video Editor  2.0.0
transition_model.py
Go to the documentation of this file.
1 ##
2 #
3 # @file
4 # @brief This file contains the transitions model, used by the main window
5 # @author Jonathan Thomas <jonathan@openshot.org>
6 #
7 # @section LICENSE
8 #
9 # Copyright (c) 2008-2016 OpenShot Studios, LLC
10 # (http://www.openshotstudios.com). This file is part of
11 # OpenShot Video Editor (http://www.openshot.org), an open-source project
12 # dedicated to delivering high quality video editing and animation solutions
13 # to the world.
14 #
15 # OpenShot Video Editor is free software: you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation, either version 3 of the License, or
18 # (at your option) any later version.
19 #
20 # OpenShot Video Editor is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
27 #
28 
29 import os
30 
31 from PyQt5.QtCore import QMimeData, Qt
32 from PyQt5.QtGui import *
33 from PyQt5.QtWidgets import QMessageBox
34 import openshot # Python module for libopenshot (required video editing module installed separately)
35 
36 from classes import info
37 from classes.logger import log
38 from classes.app import get_app
39 
40 try:
41  import json
42 except ImportError:
43  import simplejson as json
44 
45 
46 class TransitionStandardItemModel(QStandardItemModel):
47  def __init__(self, parent=None):
48  QStandardItemModel.__init__(self)
49 
50  def mimeData(self, indexes):
51  # Create MimeData for drag operation
52  data = QMimeData()
53 
54  # Get list of all selected file ids
55  files = []
56  for item in indexes:
57  selected_row = self.itemFromIndex(item).row()
58  files.append(self.item(selected_row, 3).text())
59  data.setText(json.dumps(files))
60  data.setHtml("transition")
61 
62  # Return Mimedata
63  return data
64 
65 
67  def update_model(self, clear=True):
68  log.info("updating transitions model.")
69  app = get_app()
70 
71  # Get window to check filters
72  win = app.window
73  _ = app._tr
74 
75  # Clear all items
76  if clear:
77  self.model_paths = {}
78  self.model.clear()
79 
80  # Add Headers
81  self.model.setHorizontalHeaderLabels([_("Thumb"), _("Name")])
82 
83  # get a list of files in the OpenShot /transitions directory
84  transitions_dir = os.path.join(info.PATH, "transitions")
85  common_dir = os.path.join(transitions_dir, "common")
86  extra_dir = os.path.join(transitions_dir, "extra")
87  transition_groups = [{"type": "common", "dir": common_dir, "files": os.listdir(common_dir)},
88  {"type": "extra", "dir": extra_dir, "files": os.listdir(extra_dir)}]
89 
90  # Add optional user-defined transitions folder
91  if (os.path.exists(info.TRANSITIONS_PATH) and os.listdir(info.TRANSITIONS_PATH)):
92  transition_groups.append({"type": "user", "dir": info.TRANSITIONS_PATH, "files": os.listdir(info.TRANSITIONS_PATH)})
93 
94  for group in transition_groups:
95  type = group["type"]
96  dir = group["dir"]
97  files = group["files"]
98 
99  for filename in sorted(files):
100  path = os.path.join(dir, filename)
101  (fileBaseName, fileExtension) = os.path.splitext(filename)
102 
103  # Skip hidden files (such as .DS_Store, etc...)
104  if filename[0] == "." or "thumbs.db" in filename.lower():
105  continue
106 
107  # split the name into parts (looking for a number)
108  suffix_number = None
109  name_parts = fileBaseName.split("_")
110  if name_parts[-1].isdigit():
111  suffix_number = name_parts[-1]
112 
113  # get name of transition
114  trans_name = fileBaseName.replace("_", " ").capitalize()
115 
116  # replace suffix number with placeholder (if any)
117  if suffix_number:
118  trans_name = trans_name.replace(suffix_number, "%s")
119  trans_name = self.app._tr(trans_name) % suffix_number
120  else:
121  trans_name = self.app._tr(trans_name)
122 
123  if not win.actionTransitionsShowAll.isChecked():
124  if win.actionTransitionsShowCommon.isChecked():
125  if not type == "common":
126  continue # to next file, didn't match filter
127 
128  if win.transitionsFilter.text() != "":
129  if not win.transitionsFilter.text().lower() in trans_name.lower():
130  continue
131 
132  # Check for thumbnail path (in build-in cache)
133  thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName))
134 
135  # Check built-in cache (if not found)
136  if not os.path.exists(thumb_path):
137  # Check user folder cache
138  thumb_path = os.path.join(info.CACHE_PATH, "{}.png".format(fileBaseName))
139 
140  # Generate thumbnail (if needed)
141  if not os.path.exists(thumb_path):
142 
143  try:
144  # Reload this reader
145  clip = openshot.Clip(path)
146  reader = clip.Reader()
147 
148  # Open reader
149  reader.Open()
150 
151  # Save thumbnail
152  reader.GetFrame(0).Thumbnail(thumb_path, 98, 64, os.path.join(info.IMAGES_PATH, "mask.png"), "", "#000", True)
153  reader.Close()
154  clip.Close()
155 
156  except:
157  # Handle exception
158  msg = QMessageBox()
159  msg.setText(_("{} is not a valid image file.".format(filename)))
160  msg.exec_()
161  continue
162 
163  row = []
164 
165  # Append thumbnail
166  col = QStandardItem()
167  col.setIcon(QIcon(thumb_path))
168  col.setText(trans_name)
169  col.setToolTip(trans_name)
170  col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
171  row.append(col)
172 
173  # Append Filename
174  col = QStandardItem("Name")
175  col.setData(trans_name, Qt.DisplayRole)
176  col.setText(trans_name)
177  col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
178  row.append(col)
179 
180  # Append Media Type
181  col = QStandardItem("Type")
182  col.setData(type, Qt.DisplayRole)
183  col.setText(type)
184  col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
185  row.append(col)
186 
187  # Append Path
188  col = QStandardItem("Path")
189  col.setData(path, Qt.DisplayRole)
190  col.setText(path)
191  col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled)
192  row.append(col)
193 
194  # Append ROW to MODEL (if does not already exist in model)
195  if not path in self.model_paths:
196  self.model.appendRow(row)
197  self.model_paths[path] = path
198 
199  # Process events in QT (to keep the interface responsive)
200  app.processEvents()
201 
202  def __init__(self, *args):
203 
204  # Create standard model
205  self.app = get_app()
207  self.model.setColumnCount(4)
208  self.model_paths = {}
def get_app()
Returns the current QApplication instance of OpenShot.
Definition: app.py:54
def update_model(self, clear=True)