diff --git a/src/settings/_default.settings b/src/settings/_default.settings index 459370da9d..4371eef88f 100644 --- a/src/settings/_default.settings +++ b/src/settings/_default.settings @@ -687,10 +687,6 @@ "value": "-", "type": "text" }, - - - - { "category": "Keyboard", "title": "Previous Frame", @@ -906,5 +902,21 @@ "setting": "nudgeRight", "value": "Shift+Right", "type": "text" + }, + { + "category": "Keyboard", + "title": "Edit Title", + "restart": true, + "setting": "actionEditTitle", + "value": "", + "type": "text" + }, + { + "category": "Keyboard", + "title": "Duplicate Title", + "restart": true, + "setting": "actionDuplicateTitle", + "value": "Ctrl+Shift+C", + "type": "text" } ] diff --git a/src/windows/main_window.py b/src/windows/main_window.py index ea6ae1497d..5f39900734 100644 --- a/src/windows/main_window.py +++ b/src/windows/main_window.py @@ -395,20 +395,13 @@ def actionEditTitle_trigger(self, event): file = File.get(id=selected_file_id) file_path = file.data.get("path") - # Delete thumbnail for this file (it will be recreated soon) - thumb_path = os.path.join(info.THUMBNAIL_PATH, "{}.png".format(file.id)) - - # Check if thumb exists (and delete it) - if os.path.exists(thumb_path): - os.remove(thumb_path) - # show dialog for editing title from windows.title_editor import TitleEditor win = TitleEditor(file_path) # Run the dialog event loop - blocking interaction on this window during that time result = win.exec_() - # Force update of files model (which will rebuild missing thumbnails) + # Force update of files model (which will rebuild thumbnails) get_app().window.filesTreeView.refresh_view() # Force update of clips @@ -423,10 +416,18 @@ def actionEditTitle_trigger(self, event): def actionDuplicateTitle_trigger(self, event): - # Get selected svg title file - selected_file_id = self.selected_files[0] - file = File.get(id=selected_file_id) - file_path = file.data.get("path") + file_path = None + + # Loop through selected files (set 1 selected file if more than 1) + for file_id in self.selected_files: + # Find matching file + f = File.get(id=file_id) + if f.data.get("path").endswith(".svg"): + file_path = f.data.get("path") + break + + if not file_path: + return # show dialog for editing title from windows.title_editor import TitleEditor @@ -911,7 +912,7 @@ def actionPreview_File_trigger(self, event): # Bail out if no file selected if not f: - log.info(self.selected_files) + log.info("Preview action failed, selected files: {}".format(self.selected_files)) return # show dialog @@ -1260,7 +1261,6 @@ def actionArrowTool_trigger(self, event): def actionSnappingTool_trigger(self, event): log.info("actionSnappingTool_trigger") - log.info(self.actionSnappingTool.isChecked()) # Enable / Disable snapping mode self.timeline.SetSnappingMode(self.actionSnappingTool.isChecked()) @@ -1344,7 +1344,6 @@ def actionPreviousMarker_trigger(self, event): def actionNextMarker_trigger(self, event): log.info("actionNextMarker_trigger") - log.info(self.preview_thread.current_frame) # Calculate current position (in seconds) fps = get_app().project.get("fps") @@ -1487,7 +1486,7 @@ def keyPressEvent(self, event): self.actionRemoveClip.trigger() self.actionRemoveTransition.trigger() - # Boiler plate key mappings (mostly for menu support on Ubuntu/Unity) + # Menu shortcuts elif key.matches(self.getShortcutByName("actionNew")) == QKeySequence.ExactMatch: self.actionNew.trigger() elif key.matches(self.getShortcutByName("actionOpen")) == QKeySequence.ExactMatch: @@ -1526,6 +1525,11 @@ def keyPressEvent(self, event): self.actionTitle.trigger() elif key.matches(self.getShortcutByName("actionAnimatedTitle")) == QKeySequence.ExactMatch: self.actionAnimatedTitle.trigger() + elif key.matches(self.getShortcutByName("actionDuplicateTitle")) == QKeySequence.ExactMatch: + log.info("Duplicating title, {}".format(event)) + self.actionDuplicateTitle.trigger() + elif key.matches(self.getShortcutByName("actionEditTitle")) == QKeySequence.ExactMatch: + self.actionEditTitle.trigger() elif key.matches(self.getShortcutByName("actionFullscreen")) == QKeySequence.ExactMatch: self.actionFullscreen.trigger() elif key.matches(self.getShortcutByName("actionAbout")) == QKeySequence.ExactMatch: @@ -1602,8 +1606,9 @@ def keyPressEvent(self, event): elif key.matches(self.getShortcutByName("selectNone")) == QKeySequence.ExactMatch: self.timeline.ClearAllSelections() - # Bubble event on - event.ignore() + # If we didn't act on the event, forward it to the base class + else: + super(MainWindow, self).keyPressEvent(event) def actionProfile_trigger(self, event): @@ -1627,7 +1632,7 @@ def actionSplitClip_trigger(self, event): # Bail out if no file selected if not f: - log.info(self.selected_files) + log.warn("Split clip action failed, selected files: {}".format(self.selected_files)) return # show dialog diff --git a/src/windows/ui/main-window.ui b/src/windows/ui/main-window.ui index 3d1d26a20c..52a94d1aaf 100644 --- a/src/windows/ui/main-window.ui +++ b/src/windows/ui/main-window.ui @@ -888,7 +888,7 @@ - :/icons/Humanity/actions/custom/center-on-playhead.svg:/icons/Humanity/actions/custom/center-on-playhead.svg + :/icons/Humanity/actions/custom/center-on-playhead.svg:/icons/Humanity/actions/custom/center-on-playhead.svg Center on Playhead @@ -1552,9 +1552,6 @@ Edit Title - - Ctrl+Shift+T - @@ -1568,7 +1565,7 @@ Duplicate Title - Ctrl+Shift+T + Ctrl+Shift+C diff --git a/src/windows/views/files_listview.py b/src/windows/views/files_listview.py index 65df788872..64e3d7efb5 100644 --- a/src/windows/views/files_listview.py +++ b/src/windows/views/files_listview.py @@ -48,39 +48,44 @@ class FilesListView(QListView): drag_item_size = 48 def updateSelection(self): - log.info('updateSelection') - # Track selected items - self.selected = self.selectionModel().selectedIndexes() + m = self.files_model.model + selected_items = [m.itemFromIndex(x) for x in self.selectionModel().selectedIndexes()] # Track selected file ids on main window - rows = [] - self.win.selected_files = [] - for selection in self.selected: - selected_row = self.files_model.model.itemFromIndex(selection).row() - if selected_row not in rows: - self.win.selected_files.append(self.files_model.model.item(selected_row, 5).text()) - rows.append(selected_row) + self.win.selected_files = [x.text() for x in self.selected_items if x.column() == 5] def contextMenuEvent(self, event): - # Update selection - self.updateSelection() # Set context menu mode app = get_app() app.context_menu_object = "files" + index = self.indexAt(event.pos()) + + # Build menu menu = QMenu(self) menu.addAction(self.win.actionImportFiles) menu.addAction(self.win.actionDetailsView) - if self.selected: - # If file selected, show file related options + + if index.isValid(): + # Look up the model item and our unique ID + item = self.files_model.model.itemFromIndex(index) + file_id = self.files_model.model.item(item.row(), 5).text() + + try: + # Check whether we know the item is selected + i = self.win.selected_files.index(file_id) + except ValueError: + # Add to our list, if it's not already there + self.win.selected_files.append(file_id) + + # If a valid file is selected, show file related options menu.addSeparator() # Add edit title option (if svg file) - selected_file_id = self.win.selected_files[0] - file = File.get(id=selected_file_id) + file = File.get(id=file_id) if file and file.data.get("path").endswith(".svg"): menu.addAction(self.win.actionEditTitle) menu.addAction(self.win.actionDuplicateTitle) @@ -95,7 +100,7 @@ def contextMenuEvent(self, event): menu.addSeparator() # Show menu - menu.exec_(QCursor.pos()) + menu.exec_(event.globalPos()) def dragEnterEvent(self, event): # If dragging urls onto widget, accept @@ -103,7 +108,7 @@ def dragEnterEvent(self, event): event.setDropAction(Qt.CopyAction) event.accept() - def startDrag(self, event): + def startDrag(self, supportedActions): """ Override startDrag method to display custom icon """ # Get image of selected item @@ -325,7 +330,6 @@ def __init__(self, *args): self.setAcceptDrops(True) self.setDragEnabled(True) self.setDropIndicatorShown(True) - self.selected = [] self.ignore_image_sequence_paths = [] # Setup header columns @@ -335,6 +339,7 @@ def __init__(self, *args): self.setViewMode(QListView.IconMode) self.setResizeMode(QListView.Adjust) self.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setUniformItemSizes(True) self.setWordWrap(False) self.setTextElideMode(Qt.ElideRight) @@ -346,3 +351,5 @@ def __init__(self, *args): # setup filter events app = get_app() app.window.filesFilter.textChanged.connect(self.filter_changed) + self.selectionModel().selectionChanged.connect(self.updateSelection) + diff --git a/src/windows/views/files_treeview.py b/src/windows/views/files_treeview.py index a6137c768d..eb3bafa81f 100644 --- a/src/windows/views/files_treeview.py +++ b/src/windows/views/files_treeview.py @@ -44,43 +44,50 @@ import json + class FilesTreeView(QTreeView): """ A TreeView QWidget used on the main window """ drag_item_size = 48 def updateSelection(self): - # Track selected items - self.selected = self.selectionModel().selectedIndexes() + m = self.files_model.model + self.selected_items = [m.itemFromIndex(x) for x in self.selectionModel().selectedIndexes()] # Track selected file ids on main window - rows = [] - self.win.selected_files = [] - for selection in self.selected: - selected_row = self.files_model.model.itemFromIndex(selection).row() - if selected_row not in rows: - self.win.selected_files.append(self.files_model.model.item(selected_row, 5).text()) - rows.append(selected_row) + self.win.selected_files = [x.text() for x in self.selected_items if x.column() == 5] def contextMenuEvent(self, event): - # Update selection - self.updateSelection() # Set context menu mode app = get_app() app.context_menu_object = "files" + index = self.indexAt(event.pos()) + + # Build menu menu = QMenu(self) menu.addAction(self.win.actionImportFiles) - menu.addAction(self.win.actionThumbnailView) - if self.selected: - # If file selected, show file related options + menu.addAction(self.win.actionDetailsView) + + if index.isValid(): + # Look up the model item and our unique ID + item = self.files_model.model.itemFromIndex(index) + file_id = self.files_model.model.item(item.row(), 5).text() + + try: + # Check whether we know the item is selected + i = self.win.selected_files.index(file_id) + except ValueError: + # Add to our list, if it's not already there + self.win.selected_files.append(file_id) + + # If a valid file is selected, show file related options menu.addSeparator() # Add edit title option (if svg file) - selected_file_id = self.win.selected_files[0] - file = File.get(id=selected_file_id) + file = File.get(id=file_id) if file and file.data.get("path").endswith(".svg"): menu.addAction(self.win.actionEditTitle) menu.addAction(self.win.actionDuplicateTitle) @@ -95,7 +102,7 @@ def contextMenuEvent(self, event): menu.addSeparator() # Show menu - menu.exec_(QCursor.pos()) + menu.exec_(event.globalPos()) def dragEnterEvent(self, event): # If dragging urls onto widget, accept @@ -103,7 +110,7 @@ def dragEnterEvent(self, event): event.setDropAction(Qt.CopyAction) event.accept() - def startDrag(self, event): + def startDrag(self, supportedActions): """ Override startDrag method to display custom icon """ # Get image of selected item @@ -377,7 +384,6 @@ def __init__(self, *args): self.setAcceptDrops(True) self.setDragEnabled(True) self.setDropIndicatorShown(True) - self.selected = [] self.ignore_image_sequence_paths = [] # Setup header columns @@ -400,3 +406,5 @@ def __init__(self, *args): app = get_app() app.window.filesFilter.textChanged.connect(self.filter_changed) self.files_model.model.itemChanged.connect(self.value_updated) + self.selectionModel().selectionChanged.connect(self.updateSelection) +