def __init__(self, parent, font=None): super(MultiFileEditor, self).__init__(parent) if not font: font = text_font() completion_enabled = True if CONF.has(ENABLE_COMPLETION_KEY): completion_enabled = CONF.get(ENABLE_COMPLETION_KEY) # layout self.editors = MultiPythonFileInterpreter( font=font, default_content=DEFAULT_SCRIPT_CONTENT, parent=self, completion_enabled=completion_enabled) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAcceptDrops(True) # attributes self.tabs_open_on_closing = None self.editors_zoom_level = None
class MultiFileEditor(PluginWidget): """Provides a tab widget for editing multiple files""" def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter( default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # attributes self.run_action = create_action( self, "Run", on_triggered=self.editors.execute_current, shortcut="Ctrl+Return", shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action( self, "Abort", on_triggered=self.editors.abort_current) self.editor_actions = [self.run_action, self.abort_action] def execute_current(self): '''This is used by MainWindow to execute a file after opening it''' return self.editors.execute_current() # ----------- Plugin API -------------------- def app_closing(self): """ Tries to close all editors :return: True if editors can be closed, false if cancelled """ return self.editors.close_all() def get_plugin_title(self): return "Editor" def readSettings(self, _): pass def writeSettings(self, _): pass def register_plugin(self): self.main.add_dockwidget(self) # menus add_actions(self.main.editor_menu, self.editor_actions) # ----------- Plugin Behaviour -------------------- def open_file_in_new_tab(self, filepath): return self.editors.open_file_in_new_tab(filepath) def save_current_file(self): self.editors.save_current_file()
class MultiFileEditor(PluginWidget): """Provides a tab widget for editing multiple files""" def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter(default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # attributes self.run_action = create_action(self, "Run", on_triggered=self.editors.execute_current, shortcut="Ctrl+Return", shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action(self, "Abort", on_triggered=self.editors.abort_current) self.editor_actions = [self.run_action, self.abort_action] def execute_current(self): '''This is used by MainWindow to execute a file after opening it''' return self.editors.execute_current() # ----------- Plugin API -------------------- def app_closing(self): """ Tries to close all editors :return: True if editors can be closed, false if cancelled """ return self.editors.close_all() def get_plugin_title(self): return "Editor" def readSettings(self, _): pass def writeSettings(self, _): pass def register_plugin(self): self.main.add_dockwidget(self) # menus add_actions(self.main.editor_menu, self.editor_actions) # ----------- Plugin Behaviour -------------------- def open_file_in_new_tab(self, filepath): return self.editors.open_file_in_new_tab(filepath) def save_current_file(self): self.editors.save_current_file()
def test_open_file_in_new_tab_no_import_added(self): test_string = "Test file\n" widget = MultiPythonFileInterpreter() mock_open_func = mock.mock_open(read_data=test_string) with mock.patch(widget.__module__ + '.open', mock_open_func, create=True): with mock.patch(PERMISSION_BOX_FUNC, lambda: True): widget.open_file_in_new_tab(test_string) self.assertNotIn(MANTID_API_IMPORT, widget.current_editor().editor.text())
def test_open_file_in_new_tab_no_import_added(self): test_string = "Test file\n" widget = MultiPythonFileInterpreter() mock_open_func = mock.mock_open(read_data=test_string) with mock.patch(widget.__module__ + '.open', mock_open_func, create=True): with mock.patch(PERMISSION_BOX_FUNC, lambda: True): widget.open_file_in_new_tab(test_string) self.assertNotIn(MANTID_API_IMPORT, widget.current_editor().editor.text())
def test_open_file_in_new_tab_import_added(self): test_string = "Test file\nLoad()" widget = MultiPythonFileInterpreter() mock_open_func = mock.mock_open(read_data=test_string) with mock.patch(widget.__module__ + '.open', mock_open_func, create=True): with mock.patch(PERMISSION_BOX_FUNC, lambda: True): widget.open_file_in_new_tab(test_string) self.assertEqual(widget.current_editor().editor.isModified(), True, msg="Script not marked as modified.") self.assertIn(MANTID_API_IMPORT, widget.current_editor().editor.text(), msg="'simpleapi' import not added to script.")
def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter(font=text_font(), default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAcceptDrops(True) # attributes self.tabs_open_on_closing = None
def test_editor_widget_deletes_find_replace_dialog(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 2) widget.current_editor().show_find_replace_dialog() self.assert_number_of_widgets_matching("Embedded", 1) widget.close_tab(1) QApplication.processEvents() # there will always be 1, because we never allow an empty editor widget self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 1) self.assert_number_of_widgets_matching("Embedded", 0) # close the whole widget, this should delete everything from the QApplication widget.close() QApplication.processEvents() self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 0) self.assert_no_toplevel_widgets()
def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter( default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # attributes self.run_action = create_action( self, "Run", on_triggered=self.editors.execute_current, shortcut="Ctrl+Return", shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action( self, "Abort", on_triggered=self.editors.abort_current) self.editor_actions = [self.run_action, self.abort_action]
def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter(default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # attributes self.run_action = create_action(self, "Run", on_triggered=self.editors.execute_current, shortcut="Ctrl+Return", shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action(self, "Abort", on_triggered=self.editors.abort_current) self.editor_actions = [self.run_action, self.abort_action]
def test_editor_widget_doesnt_create_find_replace_unless_requested(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assert_number_of_widgets_matching( ".interpreter.PythonFileInterpreter", 2) self.assert_number_of_widgets_matching("Embedded", 0) widget.close_tab(1) QApplication.processEvents() # there will always be 1, because we never allow an empty editor widget self.assert_number_of_widgets_matching( ".interpreter.PythonFileInterpreter", 1) self.assert_number_of_widgets_matching("Embedded", 0)
def test_open_file_in_new_tab_import_added(self): test_string = "Test file\nLoad()" widget = MultiPythonFileInterpreter() mock_open_func = mock.mock_open(read_data=test_string) with mock.patch(widget.__module__ + '.open', mock_open_func, create=True): with mock.patch(PERMISSION_BOX_FUNC, lambda: True): widget.open_file_in_new_tab(test_string) self.assertEqual(widget.current_editor().editor.isModified(), True, msg="Script not marked as modified.") self.assertIn(MANTID_API_IMPORT, widget.current_editor().editor.text(), msg="'simpleapi' import not added to script.")
class MultiFileEditor(PluginWidget): """Provides a tab widget for editing multiple files""" def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter( default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAcceptDrops(True) # attributes self.tabs_open_on_closing = None self.run_action = create_action( self, "Run", on_triggered=self.editors.execute_current, shortcut=("Ctrl+Return", "Ctrl+Enter"), shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action( self, "Abort", on_triggered=self.editors.abort_current) # menu action to toggle the find/replace dialog self.toggle_find_replace = create_action( self, 'Find/Replace...', on_triggered=self.editors.toggle_find_replace_dialog, shortcut='Ctrl+F') self.toggle_comment_action = create_action( self.editors.current_editor(), "Comment/Uncomment", on_triggered=self.editors.toggle_comment_current, shortcut="Ctrl+/", shortcut_context=Qt.ApplicationShortcut) self.tabs_to_spaces_action = create_action( self, 'Tabs to Spaces', on_triggered=self.editors.tabs_to_spaces_current) self.spaces_to_tabs_action = create_action( self, 'Spaces to Tabs', on_triggered=self.editors.spaces_to_tabs_current) self.toggle_whitespace_action = create_action( self, 'Toggle Whitespace Visible', on_triggered=self.editors.toggle_whitespace_visible_all) # Store actions for adding to menu bar; None will add a separator self.editor_actions = [ self.run_action, self.abort_action, None, self.toggle_find_replace, None, self.toggle_comment_action, self.toggle_whitespace_action, None, self.tabs_to_spaces_action, self.spaces_to_tabs_action, None ] def execute_current(self): '''This is used by MainWindow to execute a file after opening it''' return self.editors.execute_current() def restore_session_tabs(self, session_tabs): self.open_files_in_new_tabs(session_tabs, startup=True) self.editors.close_tab(0) # close default empty tab # ----------- Plugin API -------------------- def app_closing(self): """ Tries to close all editors :return: True if editors can be closed, false if cancelled """ self.tabs_open_on_closing = self.editors.tab_filepaths return self.editors.close_all() def dragEnterEvent(self, event): data = event.mimeData() if data.hasText() and data.hasUrls(): filepaths = [url.toLocalFile() for url in data.urls()] for filepath in filepaths: if osp.splitext(filepath)[1] in ACCEPTED_FILE_EXTENSIONS: event.acceptProposedAction() def dropEvent(self, event): data = event.mimeData() for url in data.urls(): filepath = url.toLocalFile() if osp.splitext(filepath)[1] in ACCEPTED_FILE_EXTENSIONS: try: self.open_file_in_new_tab(filepath) except IOError as io_error: logger.warning("Could not load file:\n '{}'" "".format(io_error)) def get_plugin_title(self): return "Editor" def readSettings(self, settings): try: prev_session_tabs = settings.get(TAB_SETTINGS_KEY) except KeyError: return self.restore_session_tabs(prev_session_tabs) def writeSettings(self, settings): settings.set(TAB_SETTINGS_KEY, self.tabs_open_on_closing) def register_plugin(self): self.main.add_dockwidget(self) # menus add_actions(self.main.editor_menu, self.editor_actions) # ----------- Plugin Behaviour -------------------- def open_file_in_new_tab(self, filepath, startup=False): return self.editors.open_file_in_new_tab(filepath, startup) def open_files_in_new_tabs(self, filepaths, startup=False): for filepath in filepaths: try: self.open_file_in_new_tab(filepath, startup) except IOError as io_error: logger.warning("Could not load file:\n {}" "".format(io_error)) def save_current_file(self): self.editors.save_current_file()
def test_add_editor(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assertEqual(2, widget.editor_count)
def test_editor_widget_not_leaked(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assertEqual(2, widget.editor_count) widget.append_new_editor() self.assertEqual(3, widget.editor_count) widget.close_tab(0) QApplication.processEvents() self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 2) widget.close_tab(0) QApplication.processEvents() self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 1) widget.close_all() QApplication.processEvents() # there should be zero interpreters self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 0) # close the whole widget, this should delete everything from the QApplication widget.close() QApplication.processEvents() self.assert_number_of_widgets_matching(".interpreter.PythonFileInterpreter", 0) self.assert_no_toplevel_widgets()
def test_editor_widget_not_leaked(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assertEqual(2, widget.editor_count) widget.append_new_editor() self.assertEqual(3, widget.editor_count) widget.close_tab(0) QApplication.processEvents() self.assert_number_of_widgets_matching( ".interpreter.PythonFileInterpreter", 2) widget.close_tab(0) QApplication.processEvents() self.assert_number_of_widgets_matching( ".interpreter.PythonFileInterpreter", 1) widget.close_all() QApplication.processEvents() # there will always be 1, because we never allow an empty editor widget self.assert_number_of_widgets_matching( ".interpreter.PythonFileInterpreter", 1)
class MultiFileEditor(PluginWidget): """ Provides the container for the widget containing the CodeEditors in the Workbench """ def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter(font=text_font(), default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAcceptDrops(True) # attributes self.tabs_open_on_closing = None def load_settings_from_config(self, config): self.editors.load_settings_from_config(config) def execute_current_async(self): """ Executes the selection in the currently active code editor. This is used by MainWindow to execute a file after opening it. """ return self.editors.execute_current_async() def execute_async(self): """ Executes _everything_ in currently active code editor. :return: """ return self.editors.execute_async() def restore_session_tabs(self, session_tabs): self.open_files_in_new_tabs(session_tabs, startup=True) self.editors.close_tab(0) # close default empty tab # ----------- Plugin API -------------------- def app_closing(self): """ Tries to close all editors :return: True if editors can be closed, false if cancelled """ self.tabs_open_on_closing = self.editors.tab_filepaths return self.editors.close_all() def dragEnterEvent(self, event): data = event.mimeData() if data.hasText() and data.hasUrls(): filepaths = [url.toLocalFile() for url in data.urls()] for filepath in filepaths: if osp.splitext(filepath)[1] in ACCEPTED_FILE_EXTENSIONS: event.acceptProposedAction() def dropEvent(self, event): data = event.mimeData() for url in data.urls(): filepath = url.toLocalFile() if osp.splitext(filepath)[1] in ACCEPTED_FILE_EXTENSIONS: try: self.open_file_in_new_tab(filepath) except IOError as io_error: logger.warning("Could not load file:\n '{}'" "".format(io_error)) def get_plugin_title(self): return "Editor" def readSettings(self, settings): try: prev_session_tabs = settings.get(TAB_SETTINGS_KEY) except KeyError: return self.restore_session_tabs(prev_session_tabs) def writeSettings(self, settings): settings.set(TAB_SETTINGS_KEY, set(self.tabs_open_on_closing)) def register_plugin(self): self.main.add_dockwidget(self) # ----------- Plugin Behaviour -------------------- def open_file_in_new_tab(self, filepath, startup=False): return self.editors.open_file_in_new_tab(filepath, startup) def open_files_in_new_tabs(self, filepaths, startup=False): for filepath in filepaths: try: self.open_file_in_new_tab(filepath, startup) except IOError as io_error: logger.warning("Could not load file:\n {}" "".format(io_error)) def save_current_file(self): self.editors.save_current_file() def save_current_file_as(self): self.editors.save_current_file_as()
def test_add_editor(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count) widget.append_new_editor() self.assertEqual(2, widget.editor_count)
def test_default_contains_single_editor(self): widget = MultiPythonFileInterpreter() self.assertEqual(1, widget.editor_count)
def __init__(self, parent): super(MultiFileEditor, self).__init__(parent) # layout self.editors = MultiPythonFileInterpreter( default_content=DEFAULT_CONTENT, parent=self) layout = QVBoxLayout() layout.addWidget(self.editors) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAcceptDrops(True) # attributes self.tabs_open_on_closing = None self.run_action = create_action( self, "Run", on_triggered=self.editors.execute_current, shortcut=("Ctrl+Return", "Ctrl+Enter"), shortcut_context=Qt.ApplicationShortcut) self.abort_action = create_action( self, "Abort", on_triggered=self.editors.abort_current) # menu action to toggle the find/replace dialog self.toggle_find_replace = create_action( self, 'Find/Replace...', on_triggered=self.editors.toggle_find_replace_dialog, shortcut='Ctrl+F') self.toggle_comment_action = create_action( self.editors.current_editor(), "Comment/Uncomment", on_triggered=self.editors.toggle_comment_current, shortcut="Ctrl+/", shortcut_context=Qt.ApplicationShortcut) self.tabs_to_spaces_action = create_action( self, 'Tabs to Spaces', on_triggered=self.editors.tabs_to_spaces_current) self.spaces_to_tabs_action = create_action( self, 'Spaces to Tabs', on_triggered=self.editors.spaces_to_tabs_current) self.toggle_whitespace_action = create_action( self, 'Toggle Whitespace Visible', on_triggered=self.editors.toggle_whitespace_visible_all) # Store actions for adding to menu bar; None will add a separator self.editor_actions = [ self.run_action, self.abort_action, None, self.toggle_find_replace, None, self.toggle_comment_action, self.toggle_whitespace_action, None, self.tabs_to_spaces_action, self.spaces_to_tabs_action, None ]