35 from urllib.parse
import urlparse
39 from PyQt5.QtWidgets import QTreeView, QMessageBox, QAbstractItemView, QMenu, QSizePolicy, QHeaderView
42 from classes.query
import File
43 from classes.logger
import log
44 from classes.app
import get_app
45 from windows.models.files_model
import FilesModel
50 import simplejson
as json
61 self.
selected = self.selectionModel().selectedIndexes()
65 self.win.selected_files = []
67 selected_row = self.files_model.model.itemFromIndex(selection).row()
68 if selected_row
not in rows:
69 self.win.selected_files.append(self.files_model.model.item(selected_row, 5).text())
70 rows.append(selected_row)
78 app.context_menu_object =
"files"
82 menu.addAction(self.win.actionImportFiles)
83 menu.addAction(self.win.actionThumbnailView)
89 selected_file_id = self.win.selected_files[0]
90 file = File.get(id=selected_file_id)
91 if file
and file.data.get(
"path").endswith(
".svg"):
92 menu.addAction(self.win.actionEditTitle)
93 menu.addAction(self.win.actionDuplicateTitle)
96 menu.addAction(self.win.actionPreview_File)
97 menu.addAction(self.win.actionSplitClip)
98 menu.addAction(self.win.actionAdd_to_Timeline)
99 menu.addAction(self.win.actionFile_Properties)
101 menu.addAction(self.win.actionRemove_from_Project)
105 menu.exec_(QCursor.pos())
109 if event.mimeData().hasUrls():
110 event.setDropAction(Qt.CopyAction)
118 selected_row = self.files_model.model.itemFromIndex(self.selectionModel().selectedIndexes()[0]).row()
119 icon = self.files_model.model.item(selected_row, 0).icon()
123 drag.setMimeData(self.files_model.model.mimeData(self.selectionModel().selectedIndexes()))
133 path = file[
"path"].lower()
135 if path.endswith((
".jpg",
".jpeg",
".png",
".bmp",
".svg",
".thm",
".gif",
".bmp",
".pgm",
".tif",
".tiff")):
141 path, filename = os.path.split(filepath)
148 file = File.get(path=filepath)
155 clip = openshot.Clip(filepath)
159 reader = clip.Reader()
160 file_data = json.loads(reader.Json())
163 if file_data[
"has_video"]
and not self.
is_image(file_data):
164 file_data[
"media_type"] =
"video"
165 elif file_data[
"has_video"]
and self.
is_image(file_data):
166 file_data[
"media_type"] =
"image"
167 elif file_data[
"has_audio"]
and not file_data[
"has_video"]:
168 file_data[
"media_type"] =
"audio"
172 file.data = file_data
176 if image_seq_details:
178 folder_path = image_seq_details[
"folder_path"]
179 file_name = image_seq_details[
"file_path"]
180 base_name = image_seq_details[
"base_name"]
181 fixlen = image_seq_details[
"fixlen"]
182 digits = image_seq_details[
"digits"]
183 extension = image_seq_details[
"extension"]
188 zero_pattern =
"%%0%sd" % digits
191 pattern =
"%s%s.%s" % (base_name, zero_pattern, extension)
194 (parentPath, folderName) = os.path.split(folder_path)
197 file.data[
"name"] =
"%s (%s)" % (folderName, pattern)
200 image_seq = openshot.Clip(os.path.join(folder_path, pattern))
203 file.data[
"path"] = os.path.join(folder_path, pattern)
204 file.data[
"media_type"] =
"video"
205 file.data[
"duration"] = image_seq.Reader().info.duration
206 file.data[
"video_length"] = image_seq.Reader().info.video_length
215 msg.setText(_(
"{} is not a valid video, audio, or image file.".format(filename)))
224 (dirName, fileName) = os.path.split(file_path)
225 extensions = [
"png",
"jpg",
"jpeg",
"gif",
"tif"]
226 match = re.findall(
r"(.*[^\d])?(0*)(\d+)\.(%s)" %
"|".join(extensions), fileName, re.I)
233 base_name = match[0][0]
234 fixlen = match[0][1] >
""
235 number = int(match[0][2])
236 digits = len(match[0][1] + match[0][2])
237 extension = match[0][3]
239 full_base_name = os.path.join(dirName, base_name)
242 fixlen = fixlen
or not (glob.glob(
"%s%s.%s" % (full_base_name,
"[0-9]" * (digits + 1), extension))
244 "%s%s.%s" % (full_base_name,
"[0-9]" * ((digits - 1)
if digits > 1
else 3), extension)))
247 for x
in range(max(0, number - 100), min(number + 101, 50000)):
248 if x != number
and os.path.exists(
"%s%s.%s" % (
249 full_base_name, str(x).rjust(digits,
"0")
if fixlen
else str(x), extension)):
256 log.info(
'Prompt user to import image sequence')
258 self.ignore_image_sequence_paths.append(dirName)
264 ret = QMessageBox.question(self, _(
"Import Image Sequence"), _(
"Would you like to import %s as an image sequence?") % fileName, QMessageBox.No | QMessageBox.Yes)
265 if ret == QMessageBox.Yes:
267 parameters = {
"file_path":file_path,
"folder_path":dirName,
"base_name":base_name,
"fixlen":fixlen,
"digits":digits,
"extension":extension}
279 for uri
in event.mimeData().urls():
280 log.info(
'Processing drop event for {}'.format(uri))
281 filepath = uri.toLocalFile()
282 if os.path.exists(filepath)
and os.path.isfile(filepath):
283 log.info(
'Adding file: {}'.format(filepath))
284 if ".osp" in filepath:
286 self.win.OpenProjectSignal.emit(filepath)
295 self.win.filesFilter.setText(
"")
299 if self.win.filesFilter.text() ==
"":
300 self.win.actionFilesClear.setEnabled(
False)
302 self.win.actionFilesClear.setEnabled(
True)
306 self.files_model.update_model()
311 if type(self) == FilesTreeView:
324 self.header().resizeSection(0, thumbnail_width)
325 self.header().resizeSection(2, tags_width)
328 self.header().setStretchLastSection(
False)
329 self.header().setSectionResizeMode(1, QHeaderView.Stretch)
330 self.header().setSectionResizeMode(2, QHeaderView.Interactive)
333 log.info(
'currentChanged')
343 file_id = self.files_model.model.item(item.row(), 5).text()
344 name = self.files_model.model.item(item.row(), 1).text()
345 tags = self.files_model.model.item(item.row(), 2).text()
348 f = File.get(id=file_id)
349 if name != f.data[
"path"]:
350 f.data[
"name"] = name
353 if "tags" in f.data.keys():
354 if tags != f.data[
"tags"]:
355 f.data[
"tags"] = tags
357 f.data[
"tags"] = tags
360 self.files_model.ignore_update_signal =
True
366 self.files_model.ignore_update_signal =
False
372 self.files_model.model.ModelRefreshed.disconnect()
378 QTreeView.__init__(self, *args)
387 self.setAcceptDrops(
True)
388 self.setDragEnabled(
True)
389 self.setDropIndicatorShown(
True)
394 self.setModel(self.files_model.model)
395 self.setIconSize(QSize(75, 62))
396 self.setIndentation(0)
397 self.setSelectionBehavior(QTreeView.SelectRows)
398 self.setSelectionMode(QAbstractItemView.ExtendedSelection)
399 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
400 self.setWordWrap(
False)
401 self.setTextElideMode(Qt.ElideRight)
402 self.setStyleSheet(
'QTreeView::item { padding-top: 2px; }')
412 app.window.actionFilesClear.triggered.connect(self.
clear_filter)
413 self.files_model.model.itemChanged.connect(self.
value_updated)
def get_app
Returns the current QApplication instance of OpenShot.
A TreeView QWidget used on the main window.
def startDrag
Override startDrag method to display custom icon.
def get_image_sequence_details
Inspect a file path and determine if this is an image sequence.
def value_updated
Name or tags updated.
def refresh_columns
Resize and hide certain columns.
ignore_image_sequence_paths
def prepare_for_delete
Remove signal handlers and prepare for deletion.