diff --git a/src/GUI_UIs/ui_dialog_code_av.ui b/src/GUI_UIs/ui_dialog_code_av.ui index c59ae89a5..12be1385d 100644 --- a/src/GUI_UIs/ui_dialog_code_av.ui +++ b/src/GUI_UIs/ui_dialog_code_av.ui @@ -495,7 +495,7 @@ - 120 + 150 0 28 28 @@ -508,6 +508,23 @@ + + + + 120 + 1 + 28 + 28 + + + + Go to bookmark (Shift B) +To set a bookmark press B + + + + + diff --git a/src/GUI_UIs/ui_dialog_view_av.ui b/src/GUI_UIs/ui_dialog_view_av.ui index 32bccff37..73e047ccf 100644 --- a/src/GUI_UIs/ui_dialog_view_av.ui +++ b/src/GUI_UIs/ui_dialog_view_av.ui @@ -307,7 +307,7 @@ Forward 5 seconds. Press 5 - 890 + 940 10 28 28 @@ -382,7 +382,7 @@ red underline = Assigned to code or annotation - <html><head/><body><p>Search for text.</p></body></html> + Search for text @@ -467,14 +467,17 @@ red underline = Assigned to code or annotation - 480 + 470 3 - 161 + 30 30 + + New speaker (Ctrl N) + - New speaker + @@ -487,7 +490,7 @@ red underline = Assigned to code or annotation - Insert timestamp + Insert timestamp (Ctrl T) @@ -496,14 +499,17 @@ red underline = Assigned to code or annotation - 650 + 500 3 - 161 + 30 30 + + Remove speaker (Ctrl D) + - Remove Speaker + @@ -550,6 +556,38 @@ red underline = Assigned to code or annotation + + + + 650 + 3 + 30 + 30 + + + + Set bookmark (Ctrl B) + + + + + + + + + 620 + 3 + 30 + 30 + + + + Go to bookmark (Ctrl Shift B) + + + + + diff --git a/src/qualcoder/GUI/ui_dialog_code_av.py b/src/qualcoder/GUI/ui_dialog_code_av.py index e015a1c7c..d3b3b7918 100644 --- a/src/qualcoder/GUI/ui_dialog_code_av.py +++ b/src/qualcoder/GUI/ui_dialog_code_av.py @@ -146,9 +146,13 @@ def setupUi(self, Dialog_code_av): self.pushButton_file_attributes.setText("") self.pushButton_file_attributes.setObjectName("pushButton_file_attributes") self.pushButton_clear_filter_file = QtWidgets.QPushButton(parent=self.groupBox_file_buttons) - self.pushButton_clear_filter_file.setGeometry(QtCore.QRect(120, 0, 28, 28)) + self.pushButton_clear_filter_file.setGeometry(QtCore.QRect(150, 0, 28, 28)) self.pushButton_clear_filter_file.setText("") self.pushButton_clear_filter_file.setObjectName("pushButton_clear_filter_file") + self.pushButton_goto_bookmark = QtWidgets.QPushButton(parent=self.groupBox_file_buttons) + self.pushButton_goto_bookmark.setGeometry(QtCore.QRect(120, 1, 28, 28)) + self.pushButton_goto_bookmark.setText("") + self.pushButton_goto_bookmark.setObjectName("pushButton_goto_bookmark") self.treeWidget = QtWidgets.QTreeWidget(parent=self.splitter) self.treeWidget.setObjectName("treeWidget") self.treeWidget.headerItem().setText(0, "Codes") @@ -235,6 +239,8 @@ def retranslateUi(self, Dialog_code_av): self.pushButton_document_memo.setToolTip(_translate("Dialog_code_av", "

File memo

")) self.pushButton_file_attributes.setToolTip(_translate("Dialog_code_av", "Show files with selected file attributes")) self.pushButton_clear_filter_file.setToolTip(_translate("Dialog_code_av", "Clear file filter")) + self.pushButton_goto_bookmark.setToolTip(_translate("Dialog_code_av", "Go to bookmark (Shift B)\n" +"To set a bookmark press B")) self.pushButton_clear_filter_code.setToolTip(_translate("Dialog_code_av", "Clear code filter")) self.lineEdit_code_filter.setToolTip(_translate("Dialog_code_av", "Code name filter")) self.plainTextEdit.setToolTip(_translate("Dialog_code_av", "

Transcript

")) diff --git a/src/qualcoder/GUI/ui_dialog_view_av.py b/src/qualcoder/GUI/ui_dialog_view_av.py index 952e362e3..805e981d8 100644 --- a/src/qualcoder/GUI/ui_dialog_view_av.py +++ b/src/qualcoder/GUI/ui_dialog_view_av.py @@ -94,7 +94,7 @@ def setupUi(self, Dialog_view_av): self.pushButton_forward_30.setText("") self.pushButton_forward_30.setObjectName("pushButton_forward_30") self.pushButton_help = QtWidgets.QPushButton(parent=self.groupBox_2) - self.pushButton_help.setGeometry(QtCore.QRect(890, 10, 28, 28)) + self.pushButton_help.setGeometry(QtCore.QRect(940, 10, 28, 28)) self.pushButton_help.setText("") self.pushButton_help.setObjectName("pushButton_help") self.gridLayout.addWidget(self.groupBox_2, 3, 0, 1, 1) @@ -136,14 +136,16 @@ def setupUi(self, Dialog_view_av): self.label_search_totals.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_search_totals.setObjectName("label_search_totals") self.pushButton_new_speaker = QtWidgets.QPushButton(parent=self.groupBox_search_text) - self.pushButton_new_speaker.setGeometry(QtCore.QRect(480, 3, 161, 30)) + self.pushButton_new_speaker.setGeometry(QtCore.QRect(470, 3, 30, 30)) + self.pushButton_new_speaker.setText("") self.pushButton_new_speaker.setObjectName("pushButton_new_speaker") self.pushButton_insert_timestamp = QtWidgets.QPushButton(parent=self.groupBox_search_text) self.pushButton_insert_timestamp.setGeometry(QtCore.QRect(440, 3, 30, 30)) self.pushButton_insert_timestamp.setText("") self.pushButton_insert_timestamp.setObjectName("pushButton_insert_timestamp") self.pushButton_remove_speaker = QtWidgets.QPushButton(parent=self.groupBox_search_text) - self.pushButton_remove_speaker.setGeometry(QtCore.QRect(650, 3, 161, 30)) + self.pushButton_remove_speaker.setGeometry(QtCore.QRect(500, 3, 30, 30)) + self.pushButton_remove_speaker.setText("") self.pushButton_remove_speaker.setObjectName("pushButton_remove_speaker") self.checkBox_case_sensitive = QtWidgets.QCheckBox(parent=self.groupBox_search_text) self.checkBox_case_sensitive.setGeometry(QtCore.QRect(38, 7, 21, 24)) @@ -155,6 +157,14 @@ def setupUi(self, Dialog_view_av): self.label_case_sensitive.setMaximumSize(QtCore.QSize(28, 28)) self.label_case_sensitive.setText("") self.label_case_sensitive.setObjectName("label_case_sensitive") + self.pushButton_set_bookmark = QtWidgets.QPushButton(parent=self.groupBox_search_text) + self.pushButton_set_bookmark.setGeometry(QtCore.QRect(650, 3, 30, 30)) + self.pushButton_set_bookmark.setText("") + self.pushButton_set_bookmark.setObjectName("pushButton_set_bookmark") + self.pushButton_goto_bookmark = QtWidgets.QPushButton(parent=self.groupBox_search_text) + self.pushButton_goto_bookmark.setGeometry(QtCore.QRect(620, 3, 30, 30)) + self.pushButton_goto_bookmark.setText("") + self.pushButton_goto_bookmark.setObjectName("pushButton_goto_bookmark") self.gridLayout.addWidget(self.groupBox_search_text, 6, 0, 1, 1) self.label_note = QtWidgets.QLabel(parent=Dialog_view_av) self.label_note.setText("") @@ -208,16 +218,18 @@ def retranslateUi(self, Dialog_view_av): self.label_transcription.setText(_translate("Dialog_view_av", "Transcription:")) self.label_speakers.setToolTip(_translate("Dialog_view_av", "

Add a speaker name to shortcuts. In the text entry box press ctrl + n

Insert a speaker into transcription. In the text entry box press ctrl + 1 up to ctrl + 8 for the speakers name.

")) self.label_speakers.setText(_translate("Dialog_view_av", "Speakers:")) - self.lineEdit_search.setToolTip(_translate("Dialog_view_av", "

Search for text.

")) + self.lineEdit_search.setToolTip(_translate("Dialog_view_av", "Search for text")) self.pushButton_next.setToolTip(_translate("Dialog_view_av", "Next")) self.label_search_regex.setToolTip(_translate("Dialog_view_av", "

Search uses Regex functions.

A dot ‘.’ is used as a wild card, e.g. ‘.ears’ will match ‘bears’ and ‘years’.

A ‘?’ after a character will match one or none times that character, e.g. ‘bears?’ will match ‘bear’ and ‘bears’

A ‘*’ after a character will match zero or more times.

\\. will match the dot symbol, ‘\\?’ will match the question mark. ‘\\n’ will match the line ending symbol.

Regex cheatsheet: www.rexegg.com/regex-quickstart.html

")) self.pushButton_previous.setToolTip(_translate("Dialog_view_av", "Previous")) self.label_search_totals.setText(_translate("Dialog_view_av", "0 / 0")) - self.pushButton_new_speaker.setText(_translate("Dialog_view_av", "New speaker")) - self.pushButton_insert_timestamp.setToolTip(_translate("Dialog_view_av", "Insert timestamp")) - self.pushButton_remove_speaker.setText(_translate("Dialog_view_av", "Remove Speaker")) + self.pushButton_new_speaker.setToolTip(_translate("Dialog_view_av", "New speaker (Ctrl N)")) + self.pushButton_insert_timestamp.setToolTip(_translate("Dialog_view_av", "Insert timestamp (Ctrl T)")) + self.pushButton_remove_speaker.setToolTip(_translate("Dialog_view_av", "Remove speaker (Ctrl D)")) self.checkBox_case_sensitive.setToolTip(_translate("Dialog_view_av", "Case sensitive")) self.label_case_sensitive.setToolTip(_translate("Dialog_view_av", "Case sensitive")) + self.pushButton_set_bookmark.setToolTip(_translate("Dialog_view_av", "Set bookmark (Ctrl B)")) + self.pushButton_goto_bookmark.setToolTip(_translate("Dialog_view_av", "Go to bookmark (Ctrl Shift B)")) if __name__ == "__main__": diff --git a/src/qualcoder/view_av.py b/src/qualcoder/view_av.py index ff1da12bd..df2a58cd4 100644 --- a/src/qualcoder/view_av.py +++ b/src/qualcoder/view_av.py @@ -133,6 +133,7 @@ def __init__(self, app, parent_text_edit, tab_reports): self.ui.splitter_2.setSizes([h0, h1]) except KeyError: pass + # Header section self.ui.splitter.splitterMoved.connect(self.update_sizes) self.ui.splitter_2.splitterMoved.connect(self.update_sizes) self.ui.label_volume.setPixmap(qta.icon('mdi6.volume-high').pixmap(22, 22)) @@ -149,37 +150,43 @@ def __init__(self, app, parent_text_edit, tab_reports): self.ui.pushButton_rate_up.pressed.connect(self.increase_play_rate) self.ui.pushButton_help.setIcon(qta.icon('mdi6.help')) self.ui.pushButton_help.pressed.connect(self.help) + self.ui.pushButton_important.setIcon(qta.icon('mdi6.star-outline', options=[{'scale_factor': 1.3}])) + self.ui.pushButton_important.pressed.connect(self.show_important_coded) + self.ui.pushButton_add_image_to_project.setIcon( + qta.icon('mdi6.image-plus-outline', options=[{'scale_factor': 1.3}])) + self.ui.pushButton_add_image_to_project.pressed.connect(self.import_screenshot_into_project) + self.ui.pushButton_add_image_to_project.setEnabled(False) + self.ui.pushButton_screensshot.setIcon(qta.icon('mdi6.image-outline', options=[{'scale_factor': 1.3}])) + self.ui.pushButton_screensshot.pressed.connect(self.save_screenshot) + self.ui.pushButton_screensshot.setEnabled(False) self.ui.pushButton_find_code.setIcon(qta.icon('mdi6.card-search-outline', options=[{'scale-factor': 1.2}])) self.ui.pushButton_find_code.pressed.connect(self.find_code_in_tree) - # Widgets under codes tree - self.ui.pushButton_clear_filter_code.setIcon(qta.icon('mdi6.filter-off-outline', options=[{'scale_factor': 1.3}])) # for clear filter code <- L - self.ui.pushButton_clear_filter_code.pressed.connect(self.clear_code_filter) - self.ui.pushButton_clear_filter_code.setToolTip(_("Clear code filter")) - self.ui.pushButton_clear_filter_code.setVisible(False) - self.ui.lineEdit_code_filter.textChanged.connect(lambda textchanged: self.show_codes_like(self.ui.lineEdit_code_filter.text())) - # The buttons in the splitter are smaller 24x24 pixels + # The buttons under the files list self.ui.pushButton_latest.setIcon(qta.icon('mdi6.arrow-collapse-right', options=[{'scale_factor': 1.3}])) self.ui.pushButton_latest.pressed.connect(self.go_to_latest_coded_file) self.ui.pushButton_next_file.setIcon(qta.icon('mdi6.arrow-right', options=[{'scale_factor': 1.3}])) self.ui.pushButton_next_file.pressed.connect(self.go_to_next_file) self.ui.pushButton_document_memo.setIcon(qta.icon('mdi6.text-box-outline', options=[{'scale_factor': 1.3}])) self.ui.pushButton_document_memo.pressed.connect(self.active_file_memo) - self.ui.pushButton_important.setIcon(qta.icon('mdi6.star-outline', options=[{'scale_factor': 1.3}])) - self.ui.pushButton_important.pressed.connect(self.show_important_coded) self.ui.pushButton_file_attributes.setIcon(qta.icon('mdi6.variable', options=[{'scale_factor': 1.3}])) self.ui.pushButton_file_attributes.pressed.connect(self.get_files_from_attributes) self.ui.pushButton_clear_filter_file.setIcon(qta.icon('mdi6.filter-off-outline', options=[{'scale_factor': 1.3}])) # for clear filter file <- L self.ui.pushButton_clear_filter_file.pressed.connect(self.clear_file_filter) self.ui.pushButton_clear_filter_file.setToolTip(_("Clear file filter")) self.ui.pushButton_clear_filter_file.setVisible(False) - self.ui.pushButton_add_image_to_project.setIcon(qta.icon('mdi6.image-plus-outline', options=[{'scale_factor': 1.3}])) - self.ui.pushButton_add_image_to_project.pressed.connect(self.import_screenshot_into_project) - self.ui.pushButton_add_image_to_project.setEnabled(False) - self.ui.pushButton_screensshot.setIcon(qta.icon('mdi6.image-outline', options=[{'scale_factor': 1.3}])) - self.ui.pushButton_screensshot.pressed.connect(self.save_screenshot) - self.ui.pushButton_screensshot.setEnabled(False) + self.ui.pushButton_goto_bookmark.setIcon(qta.icon('mdi6.bookmark', options=[{'scale_factor': 1.3}])) + self.ui.pushButton_goto_bookmark.pressed.connect(self.go_to_bookmark) + + # Widgets under codes tree + self.ui.pushButton_clear_filter_code.setIcon( + qta.icon('mdi6.filter-off-outline', options=[{'scale_factor': 1.3}])) # for clear filter code <- L + self.ui.pushButton_clear_filter_code.pressed.connect(self.clear_code_filter) + self.ui.pushButton_clear_filter_code.setToolTip(_("Clear code filter")) + self.ui.pushButton_clear_filter_code.setVisible(False) + self.ui.lineEdit_code_filter.textChanged.connect( + lambda textchanged: self.show_codes_like(self.ui.lineEdit_code_filter.text())) # Until any media is selected disable some widgets self.ui.pushButton_play.setEnabled(False) @@ -854,7 +861,7 @@ def show_case_files(self): return if selection['id'] == -1: self.get_files() - self.ui.pushButton_clear_filter_file.setVisible(False) # rreset filter button when showing all <- L + self.ui.pushButton_clear_filter_file.setVisible(False) # reset filter button when showing all self.ui.pushButton_clear_filter_file.setStyleSheet("") return cur = self.app.conn.cursor() @@ -869,7 +876,7 @@ def show_files_like(self): """ Show files that contain specified filename text. If blank, show all files. """ - dialog = QtWidgets.QInputDialog(None) #correct: dialog embedded in workspace instead of floating + dialog = QtWidgets.QInputDialog(None) # correct: dialog embedded in workspace instead of floating dialog.setStyleSheet(f"* {{font-size:{self.app.settings['fontsize']}pt}}") dialog.setWindowTitle(_("Show files like")) dialog.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint) @@ -1303,15 +1310,6 @@ def set_position(self): pos = self.ui.horizontalSlider.value() msecs = self.mediaplayer.get_time() self.mediaplayer.set_position(pos / 1000.0) - - ''' # This code may not be needed - blockSignals seems to fix a problem where msecs returns -1 - counter = 0 - while pos > 0 and msecs == -1 and counter < 10000: - self.mediaplayer.set_position(pos / 1000.0) - msecs = self.mediaplayer.get_time() - counter += 1 - #print("slider pos", pos, pos/1000.0 , "msecs", msecs, "counter", counter)''' - self.ui.label_time.setText(msecs_to_hours_mins_secs(msecs) + self.media_duration_text) self.ui.horizontalSlider.blockSignals(False) @@ -1702,7 +1700,6 @@ def move_multiple_codes(self): self.parent_textEdit.append(_("Code moved.") + s['name'].replace(" ← ", "/") + " → " + category['name']) self.update_dialog_codes_and_categories(["code_name"]) - def move_code(self, selected): """ Move code to another category or to no category. Uses a list selection. @@ -1968,45 +1965,9 @@ def keyPressEvent(self, event): if hasattr(self, 'active_handles') and self.active_handles: self.hide_resize_handles() return - '''# Get screenshot and load in project for coding - D - if key == QtCore.Qt.Key.Key_D and not self.ddialog.isHidden(): - self.import_screenshot_into_project() - return - if key == QtCore.Qt.Key.Key_ABC and not (self.ddialog.isHidden() or self.mediaplayer.get_media() is None): - self.save_screenshot() - return''' # Go to bookmark if key == QtCore.Qt.Key.Key_B and mods & QtCore.Qt.KeyboardModifier.ShiftModifier: - cur = self.app.conn.cursor() - cur.execute("select avbookmarkfile, avbookmarkmsec, avbookmarktextpos from project") - result = cur.fetchone() - self.file_ = None - for i, f in enumerate(self.files): - if f['id'] == result[0]: - self.file_ = f - self.ui.listWidget.setCurrentItem(self.ui.listWidget.findItems(self.file_['name'], QtCore.Qt.MatchFlag.MatchExactly)[0]) - self.load_media() - self.load_segments() - self.fill_code_counts_in_tree() - break - if self.file_ is None: - print("returning") - return - duration_msecs = self.media.get_duration() - self.mediaplayer.set_time(result[1]) - self.mediaplayer.play() - # Playback must be active to set_time(). Also add a small sleep to give vlc time to load the media. - time.sleep(0.2) - self.mediaplayer.set_time(result[1]) - self.ui.horizontalSlider.setValue(int(result[1] / self.media.get_duration() * 1000)) - self.mediaplayer.pause() - cursor = self.ui.plainTextEdit.textCursor() - cursor.setPosition(result[2]) - endpos = result[2] - 1 - if endpos < 0: - endpos = 0 - cursor.setPosition(endpos, QtGui.QTextCursor.MoveMode.KeepAnchor) - self.ui.plainTextEdit.setTextCursor(cursor) + self.go_to_bookmark() return # Set bookmark if key == QtCore.Qt.Key.Key_B: @@ -2153,6 +2114,39 @@ def keyPressEvent(self, event): self.textedit_recent_codes_menu(self.ui.plainTextEdit.cursorRect().topLeft()) return + def go_to_bookmark(self): + """ B or button. """ + + cur = self.app.conn.cursor() + cur.execute("select avbookmarkfile, avbookmarkmsec, avbookmarktextpos from project") + result = cur.fetchone() + self.file_ = None + for i, f in enumerate(self.files): + if f['id'] == result[0]: + self.file_ = f + self.ui.listWidget.setCurrentItem( + self.ui.listWidget.findItems(self.file_['name'], QtCore.Qt.MatchFlag.MatchExactly)[0]) + self.load_media() + self.load_segments() + self.fill_code_counts_in_tree() + break + if self.file_ is None: + return + self.mediaplayer.set_time(result[1]) + self.mediaplayer.play() + # Playback must be active to set_time(). Also add a small sleep to give vlc time to load the media. + time.sleep(0.2) + self.mediaplayer.set_time(result[1]) + self.ui.horizontalSlider.setValue(int(result[1] / self.media.get_duration() * 1000)) + self.mediaplayer.pause() + cursor = self.ui.plainTextEdit.textCursor() + cursor.setPosition(result[2]) + endpos = result[2] - 1 + if endpos < 0: + endpos = 0 + cursor.setPosition(endpos, QtGui.QTextCursor.MoveMode.KeepAnchor) + self.ui.plainTextEdit.setTextCursor(cursor) + def save_screenshot(self): hms = msecs_to_hours_mins_secs(self.mediaplayer.get_time()) image_name = f"{self.file_['name']}_{hms}.png" @@ -4496,7 +4490,7 @@ def __init__(self, app, file_, parent=None): "Positions of the underlying codes / annotations / case-assigned may not correctly adjust if text is typed over or deleted.") self.ui.label_note.setToolTip(tt) self.ui.textEdit.installEventFilter(self) - self.installEventFilter(self) # for rewind, play/stop + self.installEventFilter(self) # for rewind, play/stop, etc if platform.system() in ("Windows", "Darwin"): self.get_waveform() # Crashes on Fedora 40, segmentation fault with ffmpeg # Get the transcription text and fill textedit @@ -4574,14 +4568,23 @@ def __init__(self, app, file_, parent=None): self.ui.checkBox_case_sensitive.stateChanged.connect(self.search_for_text) # Transcription buttons self.ui.pushButton_new_speaker.setIcon(qta.icon('mdi6.account-plus-outline')) - self.ui.pushButton_new_speaker.setToolTip("Ctrl+N") self.ui.pushButton_new_speaker.pressed.connect(self.add_speakername) self.ui.pushButton_remove_speaker.setIcon(qta.icon('mdi6.account-minus-outline')) - self.ui.pushButton_remove_speaker.setToolTip("Ctrl+D") self.ui.pushButton_remove_speaker.pressed.connect(self.delete_speakernames) self.ui.pushButton_insert_timestamp.setIcon(qta.icon('mdi6.clock-outline')) - self.ui.pushButton_insert_timestamp.setToolTip("Ctrl+T") self.ui.pushButton_insert_timestamp.pressed.connect(self.insert_timestamp) + # Bookmark buttons + self.ui.pushButton_goto_bookmark.setIcon(qta.icon('mdi6.bookmark-off')) + self.ui.pushButton_goto_bookmark.setEnabled(False) + cur = self.app.conn.cursor() + cur.execute("select avbookmarkfile from project") + result = cur.fetchone() + if self.file_['id'] == result[0]: + self.ui.pushButton_goto_bookmark.setIcon(qta.icon('mdi6.bookmark-check')) + self.ui.pushButton_goto_bookmark.setEnabled(True) + self.ui.pushButton_goto_bookmark.pressed.connect(self.go_to_bookmark) + self.ui.pushButton_set_bookmark.setIcon(qta.icon('mdi6.bookmark')) + self.ui.pushButton_set_bookmark.pressed.connect(self.set_bookmark) # My solution to getting gui mouse events by putting vlc video in another dialog self.ddialog = QtWidgets.QDialog() @@ -4770,17 +4773,6 @@ def get_cases_codings_annotations(self): if len(self.codetext) > 0 or len(self.annotations) > 0 or len(self.casetext) > 0: self.no_codes_annotes_cases = False - ''' Problem with pydub pyaudioop module - def speech_to_text(self): - """ Convert speech to text using online service. """ - - ui = SpeechToText(self.app, self.abs_path) - ok = ui.exec() - if not ok: - return - txt = ui.text - self.ui.textEdit.setText(txt)''' - def help(self): """ Open help for transcribe section in browser. """ @@ -4790,7 +4782,7 @@ def ddialog_menu(self, position): """ Context menu to export a screenshot, to resize dialog """ menu = QtWidgets.QMenu() - menu.setStyleSheet("QMenu {font-size:" + str(self.app.settings['fontsize']) + "pt} ") + menu.setStyleSheet(f"QMenu {{font-size:{self.app.settings['fontsize']}pt}} ") action_screenshot = menu.addAction(_("Screenshot")) action_resize = menu.addAction(_("Resize")) @@ -4829,16 +4821,18 @@ def set_position(self): def eventFilter(self, object_, event): """ Add key options to improve manual transcribing. Options are: - Alt + minus to rewind 30 seconds. - Ctrl + R rewind 5 seconds - Alt + plus forward 30 seconds - Ctrl + S OR ctrl + P to start/pause On start rewind 1 second - Ctrl + T to insert timestamp in format [hh.mm.ss] - Ctrl + N to enter a new speakers name into shortcuts - Ctrl + D to delete speaker names from shortcuts - Ctrl + 1 .. 8 to insert speaker in format [speaker name] - Ctrl + Shift + > to increase play rate - Ctrl + Shift + < to decrease play rate + Crtl B Set Bookmark + Ctrl Shift B Go to Bookmart + Ctrl D Delete speaker names from shortcuts + Ctrl N Enter a new speakers name into shortcuts + Ctrl R Rewind 5 seconds + Ctrl S OR ctrl + P Start/pause On start rewind slightly + Ctrl T Insert timestamp in format [hh.mm.ss] + Ctrl +1 .. 8 Insert speaker in format [speaker name] + Ctrl Shift > Increase play rate + Ctrl Shift < Decrease play rate + Alt plus Forward 30 seconds + Alt minus Rewind 30 seconds. """ if event.type() != 7: # QtGui.QKeyEvent @@ -4876,16 +4870,56 @@ def eventFilter(self, object_, event): if key == QtCore.Qt.Key.Key_D and mods == QtCore.Qt.KeyboardModifier.ControlModifier: self.pause() self.delete_speakernames() - # Increase play rate Ctrl + Shift + > + # Increase play rate Ctrl Shift > if key == QtCore.Qt.Key.Key_Greater and (mods and QtCore.Qt.KeyboardModifier.ShiftModifier) and \ (mods and QtCore.Qt.KeyboardModifier.ControlModifier): self.increase_play_rate() - # Decrease play rate Ctrl + Shift + < + # Decrease play rate Ctrl Shift < if key == QtCore.Qt.Key.Key_Less and (mods and QtCore.Qt.KeyboardModifier.ShiftModifier) and \ (mods and QtCore.Qt.KeyboardModifier.ControlModifier): self.decrease_play_rate() + # Go to bookmark, if this is the correct a/v file + if key == QtCore.Qt.Key.Key_B and mods & QtCore.Qt.KeyboardModifier.ShiftModifier and \ + mods & QtCore.Qt.KeyboardModifier.ControlModifier: + self.go_to_bookmark() + # Set bookmark + if key == QtCore.Qt.Key.Key_B and mods & QtCore.Qt.KeyboardModifier.ControlModifier: + self.set_bookmark() return True + def go_to_bookmark(self): + """ Only if this file is bookmarked. Ctrl Shift B or button. """ + + cur = self.app.conn.cursor() + cur.execute("select avbookmarkfile, avbookmarkmsec, avbookmarktextpos from project") + result = cur.fetchone() + if self.file_['id'] != result[0]: + return True + self.mediaplayer.play() + # Playback must be active to set_time(). + time.sleep(0.1) + self.mediaplayer.set_time(result[1]) + self.ui.horizontalSlider.setValue(int(result[1] / self.media.get_duration() * 1000)) + self.mediaplayer.pause() + cursor = self.ui.textEdit.textCursor() + cursor.setPosition(result[2]) + endpos = result[2] - 1 + if endpos < 0: + endpos = 0 + cursor.setPosition(endpos, QtGui.QTextCursor.MoveMode.KeepAnchor) + self.ui.textEdit.setTextCursor(cursor) + + def set_bookmark(self): + """ Ctrl B or button. """ + + cur = self.app.conn.cursor() + cursor_pos = self.ui.textEdit.textCursor().position() + cur.execute("update project set avbookmarkfile=?, avbookmarkmsec=?, avbookmarktextpos=?", + [self.file_['id'], self.mediaplayer.get_time(), cursor_pos]) + self.app.conn.commit() + self.ui.pushButton_goto_bookmark.setIcon(qta.icon('mdi6.bookmark-check')) + self.ui.pushButton_goto_bookmark.setEnabled(True) + def rewind_30_seconds(self): """ Rewind 30 seconds. Alt + R """