From 1d5ebde5b8fcc8ebaecba44bc261f9b17dd2e6c1 Mon Sep 17 00:00:00 2001 From: Robert Griesel Date: Thu, 24 Sep 2020 11:10:05 +0200 Subject: [PATCH] some refactoring in code folding module --- setzer/document/code_folding/code_folding.py | 79 +++---------------- .../code_folding/code_folding_controller.py | 23 +++++- .../code_folding/code_folding_presenter.py | 70 ++++++++++++++++ 3 files changed, 102 insertions(+), 70 deletions(-) diff --git a/setzer/document/code_folding/code_folding.py b/setzer/document/code_folding/code_folding.py index 6c847533..7e4717ef 100644 --- a/setzer/document/code_folding/code_folding.py +++ b/setzer/document/code_folding/code_folding.py @@ -17,20 +17,20 @@ import gi gi.require_version('Gtk', '3.0') -gi.require_version('GtkSource', '4') from gi.repository import Gtk -from gi.repository import Gdk from gi.repository import GObject -from gi.repository import GtkSource import setzer.document.code_folding.code_folding_viewgtk as code_folding_view import setzer.document.code_folding.code_folding_controller as code_folding_controller import setzer.document.code_folding.code_folding_presenter as code_folding_presenter +from setzer.helpers.observable import Observable -class CodeFolding(object): +class CodeFolding(Observable): def __init__(self, document): + Observable.__init__(self) + self.is_enabled = False self.folding_regions = dict() @@ -41,17 +41,11 @@ def __init__(self, document): self.initial_folding_regions_checked_count = 0 self.document = document - self.source_view = document.view.source_view - self.source_gutter = self.source_view.get_gutter(Gtk.TextWindowType.LEFT) - self.tag_table = self.document.source_buffer.get_tag_table() self.view = code_folding_view.CodeFoldingView() self.presenter = code_folding_presenter.CodeFoldingPresenter(self, self.view) - self.controller = code_folding_controller.CodeFoldingController(self, self.view) - - self.source_view.get_gutter(Gtk.TextWindowType.LEFT).insert(self.view, 3) - self.source_view.connect('button-press-event', self.on_click) + self.controller = code_folding_controller.CodeFoldingController(self) - self.on_buffer_changed(self.source_view.get_buffer()) + self.on_buffer_changed(self.document.get_buffer()) def enable_code_folding(self): self.is_enabled = True @@ -64,22 +58,6 @@ def disable_code_folding(self): self.toggle_folding_region(region, show_region_regardless_of_state=True) self.presenter.hide_folding_bar() - def on_buffer_changed(self, buffer): - for i in range(len(self.presenter.line_invisible), buffer.get_end_iter().get_line() + 1): - self.presenter.line_invisible[i] = False - - def on_click(self, widget, event): - if self.is_enabled: - x, y = self.source_view.window_to_buffer_coords(Gtk.TextWindowType.LEFT, event.x, event.y) - if event.window == self.source_view.get_window(Gtk.TextWindowType.LEFT): - line_iter, line_top = self.source_view.get_line_at_y(y) - line_number = line_iter.get_line() - if x >= -18 and line_number in self.folding_regions: - if event.type == Gdk.EventType.BUTTON_PRESS: - self.toggle_folding_region(self.folding_regions[line_number]) - return True - return False - def toggle_folding_region(self, region, show_region_regardless_of_state=False, hide_region_regardless_of_state=False): if show_region_regardless_of_state: is_folded = False @@ -87,50 +65,16 @@ def toggle_folding_region(self, region, show_region_regardless_of_state=False, h is_folded = True else: is_folded = not region['is_folded'] - source_buffer = self.document.source_buffer - region_id = region['id'] - tag = self.get_invisible_region_tag(region_id) - - if is_folded: - mark_start = region['mark_start'] - start_iter = source_buffer.get_iter_at_mark(mark_start) - mark_end = region['mark_end'] - end_iter = source_buffer.get_iter_at_mark(mark_end) - end_iter.forward_char() - source_buffer.apply_tag(tag, start_iter, end_iter) - else: - start_iter = source_buffer.get_start_iter() - end_iter = source_buffer.get_end_iter() - source_buffer.remove_tag(tag, start_iter, end_iter) - self.delete_invisible_region_tag(region_id) - region['is_folded'] = is_folded - self.update_line_invisibility() - self.source_gutter.queue_draw() + self.add_change_code('folding_state_changed', region) - def get_invisible_region_tag(self, region_id): - tag = self.tag_table.lookup('invisible_region_' + str(region_id)) - if tag == None: - tag = self.document.source_buffer.create_tag('invisible_region_' + str(region_id), invisible=1) - return tag - - def delete_invisible_region_tag(self, region_id): - tag = self.tag_table.lookup('invisible_region_' + str(region_id)) - if tag != None: - self.tag_table.remove(tag) + def on_buffer_changed(self, buffer): + for i in range(len(self.presenter.line_invisible), buffer.get_end_iter().get_line() + 1): + self.presenter.line_invisible[i] = False def get_folding_region_by_region_id(self, region_id): return self.folding_regions_by_region_id[region_id] - def update_line_invisibility(self): - source_buffer = self.document.source_buffer - for i in range(len(self.presenter.line_invisible)): - self.presenter.line_invisible[i] = False - for region in self.folding_regions.values(): - if region['is_folded']: - for line in range(region['starting_line'] + 1, region['ending_line'] + 1): - self.presenter.line_invisible[line] = True - def update_folding_regions(self): folding_regions = dict() folding_regions_by_region_id = dict() @@ -179,8 +123,7 @@ def update_folding_regions(self): if not self.initial_folding_done: self.initial_folding() else: - self.update_line_invisibility() - self.source_gutter.queue_draw() + self.presenter.update_line_visibility() return self.is_enabled diff --git a/setzer/document/code_folding/code_folding_controller.py b/setzer/document/code_folding/code_folding_controller.py index 2847e240..d2e4f26c 100644 --- a/setzer/document/code_folding/code_folding_controller.py +++ b/setzer/document/code_folding/code_folding_controller.py @@ -15,14 +15,19 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import Gdk + from setzer.app.service_locator import ServiceLocator class CodeFoldingController(object): - def __init__(self, model, view): + def __init__(self, model): self.model = model - self.view = view + self.source_view = self.model.document.view.source_view self.settings = ServiceLocator.get_settings() if self.settings.get_value('preferences', 'enable_code_folding'): @@ -31,6 +36,20 @@ def __init__(self, model, view): self.model.disable_code_folding() self.settings.register_observer(self) + self.source_view.connect('button-press-event', self.on_click) + + def on_click(self, widget, event): + if self.model.is_enabled: + x, y = self.source_view.window_to_buffer_coords(Gtk.TextWindowType.LEFT, event.x, event.y) + if event.window == self.source_view.get_window(Gtk.TextWindowType.LEFT): + line_iter, line_top = self.source_view.get_line_at_y(y) + line_number = line_iter.get_line() + if x >= -18 and line_number in self.model.folding_regions: + if event.type == Gdk.EventType.BUTTON_PRESS: + self.model.toggle_folding_region(self.model.folding_regions[line_number]) + return True + return False + def change_notification(self, change_code, notifying_object, parameter): if change_code == 'settings_changed': diff --git a/setzer/document/code_folding/code_folding_presenter.py b/setzer/document/code_folding/code_folding_presenter.py index ef478a74..372f3d5b 100644 --- a/setzer/document/code_folding/code_folding_presenter.py +++ b/setzer/document/code_folding/code_folding_presenter.py @@ -15,16 +15,86 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + class CodeFoldingPresenter(object): def __init__(self, model, view): self.model = model self.view = view + self.source_gutter = self.model.document.view.source_view.get_gutter(Gtk.TextWindowType.LEFT) + self.tag_table = self.model.document.source_buffer.get_tag_table() self.line_invisible = dict() + self.source_gutter.insert(self.view, 3) self.view.connect('query-data', self.query_data) + self.model.register_observer(self) + + def change_notification(self, change_code, notifying_object, parameter): + + if change_code == 'is_enabled_changed': + if self.model.is_enabled: + self.show_folding_bar() + else: + self.hide_folding_bar() + + if change_code == 'buffer_changed': + buffer = parameter + for i in range(len(self.line_invisible), buffer.get_end_iter().get_line() + 1): + self.line_invisible[i] = False + + if change_code == 'folding_regions_updated': + self.update_line_visibility() + + if change_code == 'folding_state_changed': + if parameter['is_folded']: + self.hide_region(parameter) + else: + self.show_region(parameter) + + def show_region(self, region): + tag = self.get_invisible_region_tag(region['id']) + source_buffer = self.model.document.source_buffer + start_iter = source_buffer.get_start_iter() + end_iter = source_buffer.get_end_iter() + source_buffer.remove_tag(tag, start_iter, end_iter) + self.delete_invisible_region_tag(region['id']) + self.update_line_visibility() + + def hide_region(self, region): + tag = self.get_invisible_region_tag(region['id']) + source_buffer = self.model.document.source_buffer + mark_start = region['mark_start'] + start_iter = source_buffer.get_iter_at_mark(mark_start) + mark_end = region['mark_end'] + end_iter = source_buffer.get_iter_at_mark(mark_end) + end_iter.forward_char() + source_buffer.apply_tag(tag, start_iter, end_iter) + self.update_line_visibility() + + def get_invisible_region_tag(self, region_id): + tag = self.tag_table.lookup('invisible_region_' + str(region_id)) + if tag == None: + tag = self.model.document.source_buffer.create_tag('invisible_region_' + str(region_id), invisible=1) + return tag + + def delete_invisible_region_tag(self, region_id): + tag = self.tag_table.lookup('invisible_region_' + str(region_id)) + if tag != None: + self.tag_table.remove(tag) + + def update_line_visibility(self): + for i in range(len(self.line_invisible)): + self.line_invisible[i] = False + for region in self.model.folding_regions.values(): + if region['is_folded']: + for line in range(region['starting_line'] + 1, region['ending_line'] + 1): + self.line_invisible[line] = True + self.source_gutter.queue_draw() def query_data(self, renderer, start_iter, end_iter, state): if self.line_invisible[start_iter.get_line()]: return