def __init__(self, parent, **kwargs): super(BrowserTab, self).__init__(parent) self._parent = parent self.loading = False self.title = False # Search query self.search_query = { "id_view": kwargs.get("id_view", min(config["views"])), "fulltext": kwargs.get("fulltext", ""), "order": kwargs.get("order", "ctime desc"), "conds": kwargs.get("conds", []), } # Layout self.search_box = SearchWidget(self) if self.search_query.get("fulltext"): self.search_box.setText(self.search_query["fulltext"]) self.first_load = True self.view = FireflyBrowserView(self) self.view.horizontalHeader().sectionResized.connect(self.on_section_resize) self.view.horizontalHeader().sortIndicatorChanged.connect( self.on_section_resize ) action_clear = QAction(QIcon(pixlib["cancel"]), "&Clear search query", parent) action_clear.triggered.connect(self.on_clear) self.action_search = QMenu("Views") self.action_search.setStyleSheet(app_skin) self.action_search.menuAction().setIcon(QIcon(pixlib["search"])) self.action_search.menuAction().triggered.connect(self.load) self.load_view_menu() action_copy = QAction("Copy result", self) action_copy.setShortcut("CTRL+SHIFT+C") action_copy.triggered.connect(self.on_copy_result) self.addAction(action_copy) toolbar = QToolBar(self) toolbar.addAction(action_clear) toolbar.addAction(self.action_search.menuAction()) search_layout = QHBoxLayout() search_layout.setContentsMargins(0, 0, 0, 0) search_layout.addWidget(self.search_box) search_layout.addWidget(toolbar) self.pager = Pager(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(search_layout, 0) layout.addWidget(self.view, 1) layout.addWidget(self.pager, 0) self.setLayout(layout)
def key_menu(self, key, position): menu = QMenu() section = QAction("Search in...") section.setEnabled(False) menu.addAction(section) for id_view in sorted(config["views"].keys(), key=lambda k: config["views"][k]["position"]): view = config["views"][id_view] if view.get("separator", False): menu.addSeparator() action = QAction(view["title"], self) action.triggered.connect( functools.partial(self._parent.search_by_key, key, id_view)) menu.addAction(action) menu.exec_(self.labels[key].mapToGlobal(position))
def contextMenuEvent(self, event): menu = QMenu(self.parent()) menu.setStyleSheet(app_skin) action_open_rundown = QAction("Open rundown", self) action_open_rundown.triggered.connect(self.on_open_rundown) menu.addAction(action_open_rundown) action_import_template = QAction("Import template", self) action_import_template.triggered.connect( functools.partial(self.parent().parent().import_template, self.dow)) menu.addAction(action_import_template) menu.exec_(event.globalPos())
def contextMenuEvent(self, event): if not self.cursor_event: return menu = QMenu(self.parent()) menu.setStyleSheet(app_skin) self.calendar.selected_event = self.cursor_event action_open_rundown = QAction("Open rundown", self) action_open_rundown.triggered.connect(self.on_open_rundown) menu.addAction(action_open_rundown) action_edit_event = QAction("Event details", self) action_edit_event.triggered.connect(self.on_edit_event) menu.addAction(action_edit_event) if has_right("scheduler_edit", self.calendar.id_channel): menu.addSeparator() action_delete_event = QAction("Delete event", self) action_delete_event.triggered.connect(self.on_delete_event) menu.addAction(action_delete_event) menu.exec_(event.globalPos())
def contextMenuEvent(self, event): obj_set = list(set([itm.object_type for itm in self.selected_objects])) menu = QMenu(self) if len(obj_set) == 1: if len(self.selected_objects) == 1: if self.selected_objects[0]["item_role"] == "placeholder": solvers = self.playout_config.get("solvers", []) if solvers: solver_menu = menu.addMenu("Solve using...") for solver in solvers: action_solve = QAction(solver.capitalize(), self) action_solve.setStatusTip( "Solve this placeholder using {}".format( solver)) action_solve.triggered.connect( functools.partial(self.on_solve, solver)) solver_menu.addAction(action_solve) if obj_set[0] == "item" and self.selected_objects[0][ "id_asset"]: action_trim = QAction("Trim", self) action_trim.setStatusTip("Trim selected item") action_trim.triggered.connect(self.on_trim) menu.addAction(action_trim) if obj_set[0] == "item" and ( self.selected_objects[0]["id_asset"] or self.selected_objects[0]["item_role"] == "live"): mode_menu = menu.addMenu("Run mode") action_mode_auto = QAction("&Auto", self) action_mode_auto.setStatusTip("Set run mode to auto") action_mode_auto.setCheckable(True) action_mode_auto.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_AUTO) action_mode_auto.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_AUTO)) mode_menu.addAction(action_mode_auto) action_mode_manual = QAction("&Manual", self) action_mode_manual.setStatusTip("Set run mode to manual") action_mode_manual.setCheckable(True) action_mode_manual.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_MANUAL) action_mode_manual.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_MANUAL)) mode_menu.addAction(action_mode_manual) action_mode_skip = QAction("&Skip", self) action_mode_skip.setStatusTip("Set run mode to skip") action_mode_skip.setCheckable(True) action_mode_skip.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_SKIP) action_mode_skip.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_SKIP)) mode_menu.addAction(action_mode_skip) if self.selected_objects[0]["id_asset"]: mode_menu.addSeparator() action_mode_loop = QAction("&Loop", self) action_mode_loop.setStatusTip("Loop item") action_mode_loop.setCheckable(True) action_mode_loop.setChecked( bool(self.selected_objects[0]["loop"])) action_mode_loop.triggered.connect(self.on_set_loop) mode_menu.addAction(action_mode_loop) elif obj_set[0] == "event" and len(self.selected_objects) == 1: mode_menu = menu.addMenu("Run mode") action_mode_auto = QAction("&Auto", self) action_mode_auto.setStatusTip("Set run mode to auto") action_mode_auto.setCheckable(True) action_mode_auto.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_AUTO) action_mode_auto.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_AUTO)) mode_menu.addAction(action_mode_auto) action_mode_manual = QAction("&Manual", self) action_mode_manual.setStatusTip("Set run mode to manual") action_mode_manual.setCheckable(True) action_mode_manual.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_MANUAL) action_mode_manual.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_MANUAL)) mode_menu.addAction(action_mode_manual) action_mode_soft = QAction("&Soft", self) action_mode_soft.setStatusTip("Set run mode to soft") action_mode_soft.setCheckable(True) action_mode_soft.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_SOFT) action_mode_soft.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_SOFT)) mode_menu.addAction(action_mode_soft) action_mode_hard = QAction("&Hard", self) action_mode_hard.setStatusTip("Set run mode to hard") action_mode_hard.setCheckable(True) action_mode_hard.setChecked( self.selected_objects[0]["run_mode"] == RunMode.RUN_HARD) action_mode_hard.triggered.connect( functools.partial(self.on_set_mode, RunMode.RUN_HARD)) mode_menu.addAction(action_mode_hard) if "item" in obj_set: if len(self.selected_objects ) == 1 and self.selected_objects[0]["item_role"] in [ "placeholder", "lead_in", "lead_out", "live" ]: pass else: action_send_to = QAction("&Send to...", self) action_send_to.setStatusTip( "Create action for selected asset(s)") action_send_to.triggered.connect(self.on_send_to) menu.addAction(action_send_to) if "event" in obj_set: pass if len(obj_set) > 0: menu.addSeparator() action_delete = QAction("&Delete", self) action_delete.setStatusTip("Delete selected object") action_delete.triggered.connect(self.on_delete) menu.addAction(action_delete) if len(self.selected_objects) == 1: if "event" in obj_set: action_edit = QAction("Edit", self) action_edit.triggered.connect(self.on_edit_event) menu.addAction(action_edit) elif self.selected_objects[0]["item_role"] in [ "placeholder", "live" ]: action_edit = QAction("Edit", self) action_edit.triggered.connect(self.on_edit_item) menu.addAction(action_edit) menu.exec_(event.globalPos())
def preview_toolbar(wnd): toolbar = QToolBar(wnd) action_poster = QMenu("Set poster", wnd) action_poster.menuAction().setIcon(QIcon(pixlib["set-poster"])) action_poster.menuAction().triggered.connect(wnd.set_poster) action_poster.menuAction().setStatusTip("Set poster frame") action_poster_set = QAction("Set poster", wnd) action_poster_set.triggered.connect(wnd.set_poster) action_poster.addAction(action_poster_set) action_poster_goto = QAction("Go to poster", wnd) action_poster_goto.triggered.connect(wnd.go_to_poster) action_poster.addAction(action_poster_goto) toolbar.addAction(action_poster.menuAction()) action_save_marks = QAction(QIcon(pixlib["save-marks"]), "Save marks", wnd) action_save_marks.setStatusTip("Save marks") action_save_marks.triggered.connect(wnd.save_marks) toolbar.addAction(action_save_marks) # TODO # action_restore_marks = QAction(QIcon(pix_lib["restore-marks"]), 'Restore', wnd) # action_restore_marks.setStatusTip('Restore marks') # action_restore_marks.triggered.connect(wnd.restore_marks) # toolbar.addAction(action_restore_marks) action_create_subclip = QAction( QIcon(pixlib["create-subclip"]), "Create subclip", wnd ) action_create_subclip.setStatusTip("Create subclip") action_create_subclip.triggered.connect(wnd.create_subclip) toolbar.addAction(action_create_subclip) action_manage_subclips = QAction( QIcon(pixlib["manage-subclips"]), "Manage subclips", wnd ) action_manage_subclips.setStatusTip("Manage subclips") action_manage_subclips.triggered.connect(wnd.manage_subclips) toolbar.addAction(action_manage_subclips) return toolbar
def contextMenuEvent(self, event): if not self.view.selected_objects: return menu = QMenu(self) objs = self.view.selected_objects states = set([obj["status"] for obj in objs]) if states == set([ObjectStatus.TRASHED]): action_untrash = QAction("Untrash", self) action_untrash.setStatusTip("Take selected asset(s) from trash") action_untrash.triggered.connect(self.on_untrash) menu.addAction(action_untrash) if states == set([ObjectStatus.ARCHIVED]): action_unarchive = QAction("Unarchive", self) action_unarchive.setStatusTip("Take selected asset(s) from archive") action_unarchive.triggered.connect(self.on_unarchive) menu.addAction(action_unarchive) elif states.issubset( [ObjectStatus.ONLINE, ObjectStatus.CREATING, ObjectStatus.OFFLINE] ): action_move_to_trash = QAction("Move to trash", self) action_move_to_trash.setStatusTip("Move selected asset(s) to trash") action_move_to_trash.triggered.connect(self.on_trash) menu.addAction(action_move_to_trash) action_move_to_archive = QAction("Move to archive", self) action_move_to_archive.setStatusTip("Move selected asset(s) to archive") action_move_to_archive.triggered.connect(self.on_archive) menu.addAction(action_move_to_archive) action_reset = QAction("Reset", self) action_reset.setStatusTip("Reload asset metadata") action_reset.triggered.connect(self.on_reset) menu.addAction(action_reset) action_batch_ops = QAction("&Batch ops...", self) action_batch_ops.setStatusTip("Batch operations") action_batch_ops.triggered.connect(self.on_batch_ops) menu.addAction(action_batch_ops) if len(objs) == 1: menu.addSeparator() for link in config["folders"][objs[0]["id_folder"]].get("links", []): action_link = QAction(link["title"]) action_link.triggered.connect( functools.partial(self.link_exec, objs[0], **link) ) menu.addAction(action_link) menu.addSeparator() action_send_to = QAction("&Send to...", self) action_send_to.setStatusTip("Create action for selected asset(s)") action_send_to.triggered.connect(self.on_send_to) menu.addAction(action_send_to) menu.exec_(event.globalPos())
class BrowserTab(QWidget): def __init__(self, parent, **kwargs): super(BrowserTab, self).__init__(parent) self._parent = parent self.loading = False self.title = False # Search query self.search_query = { "id_view": kwargs.get("id_view", min(config["views"])), "fulltext": kwargs.get("fulltext", ""), "order": kwargs.get("order", "ctime desc"), "conds": kwargs.get("conds", []), } # Layout self.search_box = SearchWidget(self) if self.search_query.get("fulltext"): self.search_box.setText(self.search_query["fulltext"]) self.first_load = True self.view = FireflyBrowserView(self) self.view.horizontalHeader().sectionResized.connect(self.on_section_resize) self.view.horizontalHeader().sortIndicatorChanged.connect( self.on_section_resize ) action_clear = QAction(QIcon(pixlib["cancel"]), "&Clear search query", parent) action_clear.triggered.connect(self.on_clear) self.action_search = QMenu("Views") self.action_search.setStyleSheet(app_skin) self.action_search.menuAction().setIcon(QIcon(pixlib["search"])) self.action_search.menuAction().triggered.connect(self.load) self.load_view_menu() action_copy = QAction("Copy result", self) action_copy.setShortcut("CTRL+SHIFT+C") action_copy.triggered.connect(self.on_copy_result) self.addAction(action_copy) toolbar = QToolBar(self) toolbar.addAction(action_clear) toolbar.addAction(self.action_search.menuAction()) search_layout = QHBoxLayout() search_layout.setContentsMargins(0, 0, 0, 0) search_layout.addWidget(self.search_box) search_layout.addWidget(toolbar) self.pager = Pager(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(search_layout, 0) layout.addWidget(self.view, 1) layout.addWidget(self.pager, 0) self.setLayout(layout) def model(self): return self.view.model() @property def id_view(self): return self.search_query["id_view"] @property def main_window(self): return self._parent.main_window @property def app_state(self): return self._parent.app_state def load_view_menu(self): i = 1 for id_view in sorted( config["views"].keys(), key=lambda k: config["views"][k]["position"] ): view = config["views"][id_view] if view.get("separator", False): self.action_search.addSeparator() action = QAction(view["title"], self) action.setCheckable(True) if i < 10: action.setShortcut(f"ALT+{i}") action.id_view = id_view action.triggered.connect(functools.partial(self.set_view, id_view)) self.action_search.addAction(action) i += 1 def on_section_resize(self, *args, **kwargs): if self.loading: return if "browser_view_sizes" not in self.app_state: self.app_state["browser_view_sizes"] = {} if "browser_default_sizes" not in self.app_state: self.app_state["browser_default_sizes"] = {} data = {} for i, h in enumerate(self.model().header_data): w = self.view.horizontalHeader().sectionSize(i) self.app_state["browser_default_sizes"][h] = w data[h] = w self.app_state["browser_view_sizes"][self.id_view] = data # # Do browse # def load(self, **kwargs): self.loading = True self.old_view = self.search_query.get("id_view", -1) search_string = self.search_box.text() self.search_query["fulltext"] = search_string self.search_query.update(kwargs) if self.search_query.get("id_view") != self.old_view: self.view.current_page = 1 self.model().load(self.load_callback, **self.search_query) def load_callback(self): if self.first_load or self.id_view != self.old_view: view_state = self.app_state.get("browser_view_sizes", {}).get( self.id_view, {} ) default_sizes = self.app_state.get("browser_defaut_sizes", {}) for i, h in enumerate(self.model().header_data): if h in view_state: w = view_state[h] elif h in default_sizes: w = default_sizes[h] elif h in ["title", "subtitle"]: w = 300 elif h in ["qc/state"]: w = 20 else: w = 120 self.view.horizontalHeader().resizeSection(i, w) for action in self.action_search.actions(): if not hasattr(action, "id_view"): continue if action.id_view == self.id_view: action.setChecked(True) else: action.setChecked(False) self.first_load = False self.loading = False self._parent.redraw_tabs() def on_clear(self): self.search_box.setText("") self.load(fulltext="") def set_view(self, id_view): self.search_query["conds"] = [] self.title = False self.load(id_view=id_view) def contextMenuEvent(self, event): if not self.view.selected_objects: return menu = QMenu(self) objs = self.view.selected_objects states = set([obj["status"] for obj in objs]) if states == set([ObjectStatus.TRASHED]): action_untrash = QAction("Untrash", self) action_untrash.setStatusTip("Take selected asset(s) from trash") action_untrash.triggered.connect(self.on_untrash) menu.addAction(action_untrash) if states == set([ObjectStatus.ARCHIVED]): action_unarchive = QAction("Unarchive", self) action_unarchive.setStatusTip("Take selected asset(s) from archive") action_unarchive.triggered.connect(self.on_unarchive) menu.addAction(action_unarchive) elif states.issubset( [ObjectStatus.ONLINE, ObjectStatus.CREATING, ObjectStatus.OFFLINE] ): action_move_to_trash = QAction("Move to trash", self) action_move_to_trash.setStatusTip("Move selected asset(s) to trash") action_move_to_trash.triggered.connect(self.on_trash) menu.addAction(action_move_to_trash) action_move_to_archive = QAction("Move to archive", self) action_move_to_archive.setStatusTip("Move selected asset(s) to archive") action_move_to_archive.triggered.connect(self.on_archive) menu.addAction(action_move_to_archive) action_reset = QAction("Reset", self) action_reset.setStatusTip("Reload asset metadata") action_reset.triggered.connect(self.on_reset) menu.addAction(action_reset) action_batch_ops = QAction("&Batch ops...", self) action_batch_ops.setStatusTip("Batch operations") action_batch_ops.triggered.connect(self.on_batch_ops) menu.addAction(action_batch_ops) if len(objs) == 1: menu.addSeparator() for link in config["folders"][objs[0]["id_folder"]].get("links", []): action_link = QAction(link["title"]) action_link.triggered.connect( functools.partial(self.link_exec, objs[0], **link) ) menu.addAction(action_link) menu.addSeparator() action_send_to = QAction("&Send to...", self) action_send_to.setStatusTip("Create action for selected asset(s)") action_send_to.triggered.connect(self.on_send_to) menu.addAction(action_send_to) menu.exec_(event.globalPos()) def link_exec(self, obj, **kwargs): param = kwargs["target_key"] value = obj[kwargs["source_key"]] self._parent.new_tab( obj["title"], id_view=kwargs["id_view"], conds=[f"'{param}' = '{value}'"] ) self._parent.redraw_tabs() def on_send_to(self): objs = self.view.selected_objects if objs: show_send_to_dialog(objs) def on_batch_ops(self): objs = self.view.selected_objects if objs: if show_batch_ops_dialog(objs): self.load() def on_reset(self): objects = [ obj.id for obj in self.view.selected_objects if obj["status"] not in [ObjectStatus.ARCHIVED, ObjectStatus.TRASHED, ObjectStatus.RESET] ] if not objects: return response = api.set(objects=objects, data={"status": ObjectStatus.RESET}) if not response: return self.refresh_assets(*objects, request_data=True) def on_trash(self): objects = [ obj.id for obj in self.view.selected_objects if obj["status"] not in [ObjectStatus.ARCHIVED, ObjectStatus.TRASHED] ] if not objects: return ret = QMessageBox.question( self, "Trash", f"Do you really want to trash {len(objects)} selected asset(s)?", QMessageBox.Yes | QMessageBox.No, ) if ret == QMessageBox.Yes: response = api.set(objects=objects, data={"status": ObjectStatus.TRASHED}) else: return if not response: logging.error("Unable to trash:\n\n" + response.message) return self.refresh_assets(*objects, request_data=True) def on_untrash(self): objects = [ obj.id for obj in self.view.selected_objects if obj["status"] in [ObjectStatus.TRASHED] ] if not objects: return response = api.set(objects=objects, data={"status": ObjectStatus.CREATING}) if not response: logging.error("Unable to untrash:\n\n" + response.message) return self.refresh_assets(*objects, request_data=True) def on_archive(self): objects = [ obj.id for obj in self.view.selected_objects if obj["status"] not in [ObjectStatus.ARCHIVED, ObjectStatus.TRASHED] ] if not objects: return ret = QMessageBox.question( self, "Archive", f"Do you really want to move {len(objects)} selected asset(s) to archive?", QMessageBox.Yes | QMessageBox.No, ) if ret == QMessageBox.Yes: response = api.set(objects=objects, data={"status": ObjectStatus.ARCHIVED}) else: return if not response: logging.error("Unable to archive:\n\n" + response.message) return self.refresh_assets(*objects, request_data=True) def on_unarchive(self): objects = [ obj.id for obj in self.view.selected_objects if obj["status"] in [ObjectStatus.ARCHIVED] ] if not objects: return response = api.set(objects=objects, data={"status": ObjectStatus.RETRIEVING}) if not response: logging.error("Unable to unarchive:\n\n" + response.message) return self.refresh_assets(*objects, request_data=True) def on_choose_columns(self): # TODO logging.error("Not implemented") def on_copy_result(self): result = "" for obj in self.view.selected_objects: result += "{}\n".format( "\t".join( [obj.format_display(key) or "" for key in self.model().header_data] ) ) clipboard = QApplication.clipboard() clipboard.setText(result) def refresh_assets(self, *objects, request_data=False): if request_data: asset_cache.request([[aid, 0] for aid in objects]) for row, obj in enumerate(self.model().object_data): if obj.id in objects: self.model().object_data[row] = asset_cache[obj.id] self.model().dataChanged.emit( self.model().index(row, 0), self.model().index(row, len(self.model().header_data) - 1), ) def seismic_handler(self, message): pass # No seismic message needed - refresh_assets method does the job