34 from urllib.parse
import urlparse
39 from PyQt5.QtWidgets import QListView, QMessageBox, QAbstractItemView, QMenu
41 from classes.app
import get_app
42 from classes.logger
import log
43 from classes.query
import File
44 from windows.models.files_model
import FilesModel
49 import simplejson
as json
58 log.info(
'updateSelection')
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.actionDetailsView)
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()))
134 path = file[
"path"].lower()
136 if path.endswith((
".jpg",
".jpeg",
".png",
".bmp",
".svg",
".thm",
".gif",
".bmp",
".pgm",
".tif",
".tiff")):
142 path, filename = os.path.split(filepath)
149 file = File.get(path=filepath)
156 clip = openshot.Clip(filepath)
160 reader = clip.Reader()
161 file_data = json.loads(reader.Json())
164 if file_data[
"has_video"]
and not self.
is_image(file_data):
165 file_data[
"media_type"] =
"video"
166 elif file_data[
"has_video"]
and self.
is_image(file_data):
167 file_data[
"media_type"] =
"image"
168 elif file_data[
"has_audio"]
and not file_data[
"has_video"]:
169 file_data[
"media_type"] =
"audio"
173 file.data = file_data
177 if image_seq_details:
179 folder_path = image_seq_details[
"folder_path"]
180 file_name = image_seq_details[
"file_path"]
181 base_name = image_seq_details[
"base_name"]
182 fixlen = image_seq_details[
"fixlen"]
183 digits = image_seq_details[
"digits"]
184 extension = image_seq_details[
"extension"]
189 zero_pattern =
"%%0%sd" % digits
192 pattern =
"%s%s.%s" % (base_name, zero_pattern, extension)
195 (parentPath, folderName) = os.path.split(folder_path)
198 file.data[
"name"] =
"%s (%s)" % (folderName, pattern)
201 image_seq = openshot.Clip(os.path.join(folder_path, pattern))
204 file.data[
"path"] = os.path.join(folder_path, pattern)
205 file.data[
"media_type"] =
"video"
206 file.data[
"duration"] = image_seq.Reader().info.duration
207 file.data[
"video_length"] = image_seq.Reader().info.video_length
216 msg.setText(_(
"{} is not a valid video, audio, or image file.".format(filename)))
225 (dirName, fileName) = os.path.split(file_path)
226 extensions = [
"png",
"jpg",
"jpeg",
"gif",
"tif"]
227 match = re.findall(
r"(.*[^\d])?(0*)(\d+)\.(%s)" %
"|".join(extensions), fileName, re.I)
234 base_name = match[0][0]
235 fixlen = match[0][1] >
""
236 number = int(match[0][2])
237 digits = len(match[0][1] + match[0][2])
238 extension = match[0][3]
240 full_base_name = os.path.join(dirName, base_name)
243 fixlen = fixlen
or not (glob.glob(
"%s%s.%s" % (full_base_name,
"[0-9]" * (digits + 1), extension))
245 "%s%s.%s" % (full_base_name,
"[0-9]" * ((digits - 1)
if digits > 1
else 3), extension)))
248 for x
in range(max(0, number - 100), min(number + 101, 50000)):
249 if x != number
and os.path.exists(
"%s%s.%s" % (
250 full_base_name, str(x).rjust(digits,
"0")
if fixlen
else str(x), extension)):
257 log.info(
'Prompt user to import image sequence')
259 self.ignore_image_sequence_paths.append(dirName)
265 ret = QMessageBox.question(self, _(
"Import Image Sequence"), _(
"Would you like to import %s as an image sequence?") % fileName, QMessageBox.No | QMessageBox.Yes)
266 if ret == QMessageBox.Yes:
268 parameters = {
"file_path":file_path,
"folder_path":dirName,
"base_name":base_name,
"fixlen":fixlen,
"digits":digits,
"extension":extension}
280 for uri
in event.mimeData().urls():
281 log.info(
'Processing drop event for {}'.format(uri))
282 filepath = uri.toLocalFile()
283 if os.path.exists(filepath)
and os.path.isfile(filepath):
284 log.info(
'Adding file: {}'.format(filepath))
285 if ".osp" in filepath:
287 self.win.OpenProjectSignal.emit(filepath)
296 self.win.filesFilter.setText(
"")
300 if self.win.filesFilter.text() ==
"":
301 self.win.actionFilesClear.setEnabled(
False)
303 self.win.actionFilesClear.setEnabled(
True)
307 self.files_model.update_model()
310 log.info(
'currentChanged')
320 self.files_model.model.ModelRefreshed.disconnect()
326 QListView.__init__(self, *args)
333 self.setAcceptDrops(
True)
334 self.setDragEnabled(
True)
335 self.setDropIndicatorShown(
True)
340 self.setModel(self.files_model.model)
341 self.setIconSize(QSize(131, 108))
342 self.setGridSize(QSize(102, 92))
343 self.setViewMode(QListView.IconMode)
344 self.setResizeMode(QListView.Adjust)
345 self.setSelectionMode(QAbstractItemView.ExtendedSelection)
346 self.setUniformItemSizes(
True)
347 self.setWordWrap(
False)
348 self.setTextElideMode(Qt.ElideRight)
349 self.setStyleSheet(
'QListView::item { padding-top: 2px; }')
357 app.window.actionFilesClear.triggered.connect(self.
clear_filter)
def get_app
Returns the current QApplication instance of OpenShot.
def prepare_for_delete
Remove signal handlers and prepare for deletion.
A ListView QWidget used on the main window.
def get_image_sequence_details
Inspect a file path and determine if this is an image sequence.
ignore_image_sequence_paths
def startDrag
Override startDrag method to display custom icon.