diff --git a/python/find_and_replace_dialog_wrapper.py b/python/find_and_replace_dialog_wrapper.py index 377f319327e68e876b5f078b46b66a151b0e7680..cf9084a56cc778e1c0ee921a748745d0eda27561 100644 --- a/python/find_and_replace_dialog_wrapper.py +++ b/python/find_and_replace_dialog_wrapper.py @@ -12,7 +12,6 @@ from find_and_replace_dialog import Ui_FindAndReplaceDialog from color_selector_widget import ColorSelectorWidget from paths_gryphon import SNAPSHOTS_PATH from settings_manager import settings -from message_popup import message_popup from mp_code_dynamic_tokens import dynamic_token_names class FindAndReplaceDialogWrapper(QDialog): diff --git a/python/gui_manager.py b/python/gui_manager.py index e9749a1a963360b2f99c9a198cc573e8394237a8..bce7f20a01791b82722ec2a09cc53011d69ecdbe 100644 --- a/python/gui_manager.py +++ b/python/gui_manager.py @@ -161,11 +161,9 @@ class GUIManager(QObject): self.graphs_manager.signal_graphs_loaded, self.preferences_manager) - # persistent wrapper + # persistent dialog self.search_mp_files_dialog_wrapper = SearchMPFilesDialogWrapper( self.w, self.preferences_manager, self.settings_manager) - # zzzz - self.search_mp_files_dialog_wrapper.show() # setup self.define_actions() diff --git a/python/mp_code_view.py b/python/mp_code_view.py index aad013e70fc6469f6940ffb5f84807538014f7fe..62a87423140ca97eb7bf20f1c17f8677f0f82032 100644 --- a/python/mp_code_view.py +++ b/python/mp_code_view.py @@ -2,9 +2,12 @@ # https://stackoverflow.com/questions/33243852/codeeditor-example-in-pyqt # http://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html +from os.path import join, split from PyQt5.QtWidgets import QWidget from PyQt5.QtWidgets import QPlainTextEdit from PyQt5.QtWidgets import QCompleter +from PyQt5.QtWidgets import QAction +from PyQt5.QtWidgets import QFileDialog from PyQt5.QtGui import QFont from PyQt5.QtGui import QFontMetrics from PyQt5.QtGui import QColor @@ -12,6 +15,7 @@ from PyQt5.QtGui import QTextCursor from PyQt5.QtGui import QPainter from PyQt5.QtGui import QKeyEvent from PyQt5.QtGui import QTextOption +from PyQt5.QtGui import QIcon from PyQt5.QtCore import QSize from PyQt5.QtCore import Qt from PyQt5.QtCore import QRect @@ -23,6 +27,9 @@ from mp_code_expressions import KEYWORD_SET, WORD_EXPRESSION, \ LEADING_WHITESPACE_EXPRESSION from find_and_replace import FindAndReplace from find_and_replace_dialog_wrapper import FindAndReplaceDialogWrapper +from mp_json_io_manager import save_mp_code_file +from preferences_manager import cached_preferences +from message_popup import message_popup # the set of words and the number of words def words(text): @@ -70,6 +77,12 @@ class MPCodeView(QPlainTextEdit): self.set_use_auto_indent) preferences_manager.signal_use_dark_mode_changed.connect( self.set_use_dark_mode) + self.copyAvailable.connect(self._copy_available) + + # action + self.action_save_selection = QAction(QIcon(":/icons/save"), + "&Save selection...", self) + self.action_save_selection.triggered.connect(self._save_selection) # the cursor highlighter manages cursor highlighting on mouse click self.mp_code_cursor_highlighter = MPCodeCursorHighlighter(self) @@ -112,6 +125,47 @@ class MPCodeView(QPlainTextEdit): self.completer.setCompletionMode(QCompleter.PopupCompletion) self.completer.activated.connect(self.insert_completion_text) + # state + self.copy_is_available = False + + # copy available + @pyqtSlot(bool) + def _copy_available(self, copy_is_available): + self.copy_is_available = copy_is_available + + # save selection + @pyqtSlot() + def _save_selection(self): + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog + + # suggested filename + suggested_filename = "selection.mp" + + mp_code_filename, _ = QFileDialog.getSaveFileName(None, + "Save MP Code selection", + join(cached_preferences[ + "preferred_save_selection_dir"], + suggested_filename), + "MP Code files (*.mp);;All Files (*)", + options=options) + + if mp_code_filename: + # remember the preferred path + head, _tail = split(mp_code_filename) + cached_preferences["preferred_save_selection_dir"] = head + + # get the selection + selected_text = self.textCursor().selectedText() + status = save_mp_code_file(selected_text, mp_code_filename) + print("Saved selection to", mp_code_filename) + if status: + # log failure + message_popup(None, status) + else: + # great, exported. + pass + # standard menu plus custom items def contextMenuEvent(self, context_menu_event): menu = self.createStandardContextMenu() @@ -119,6 +173,8 @@ class MPCodeView(QPlainTextEdit): menu.addAction(self.find_and_replace.action_find_and_replace) self.find_and_replace.action_find_and_replace.setDisabled( FindAndReplaceDialogWrapper.a_wrapper_instance_is_visible) + menu.addAction(self.action_save_selection) + self.action_save_selection.setDisabled(not self.copy_is_available) menu.exec_(context_menu_event.globalPos()) del menu diff --git a/python/search_mp_files_dialog_wrapper.py b/python/search_mp_files_dialog_wrapper.py index 194707dde4f722646507ab25aa49b6ea67a3699c..5d5f32f422df187a4995e21c0c66d4481768e508 100644 --- a/python/search_mp_files_dialog_wrapper.py +++ b/python/search_mp_files_dialog_wrapper.py @@ -12,10 +12,9 @@ from PyQt5.QtWidgets import QAction from search_mp_files_dialog import Ui_SearchMPFilesDialog from paths_examples import examples_paths from preferences_manager import cached_preferences -from message_popup import message_popup from mp_code_dynamic_tokens import dynamic_token_names from search_mp_code_dialog_wrapper import SearchMPCodeDialogWrapper -from message_popup import message_popup +from startup_options import verbose class FileMetadata(): """Properties: @@ -144,7 +143,8 @@ class FileMetadataTableView(QTableView): def _append_library(library_path, file_metadata_list): p = Path(library_path) posix_paths = sorted(p.rglob("*.mp")) - print("Reading library %s count %d"%(library_path, len(posix_paths))) + if verbose(): + print("Reading library %s count %d"%(library_path, len(posix_paths))) for posix_path in posix_paths: if posix_path.is_file(): file_metadata_list.append(FileMetadata(posix_path)) @@ -258,7 +258,7 @@ class SearchMPFilesDialogWrapper(QDialog): row = self.proxy_model.mapToSource(model_index).row() posix_path = self.file_metadata_table_model.file_metadata_list[row]\ .posix_path - print("_select_index", posix_path) + print("Open search", posix_path) wrapper = SearchMPCodeDialogWrapper(self.parent, self.preferences_manager, self.settings_manager,