1#!/usr/bin/env python3
2# coding: utf-8
3
4# Copyright (C) 2017, 2018 Robert Griesel
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>
17
18import os.path
19import time
20
21import setzer.document.document_controller as document_controller
22import setzer.document.document_presenter as document_presenter
23import setzer.document.context_menu.context_menu as context_menu
24import setzer.document.document_switcher_item.document_switcher_item as document_switcher_item
25import setzer.document.document_viewgtk as document_view
26import setzer.document.search.search as search
27import setzer.document.shortcutsbar.shortcutsbar_presenter as shortcutsbar_presenter
28import setzer.document.source_buffer.source_buffer as source_buffer
29import setzer.document.spellchecker.spellchecker as spellchecker
30import setzer.document.gutter.gutter as gutter
31import setzer.document.line_numbers.line_numbers as line_numbers
32from setzer.helpers.observable import Observable
33from setzer.app.service_locator import ServiceLocator
34from setzer.helpers.timer import timer
35
36
37class Document(Observable):
38
39    def __init__(self):
40        Observable.__init__(self)
41
42        self.settings = ServiceLocator.get_settings()
43
44        self.displayname = ''
45        self.filename = None
46        self.save_date = None
47        self.deleted_on_disk_dialog_shown_after_last_save = False
48        self.last_activated = 0
49        self.dark_mode = False
50        self.is_root = False
51        self.root_is_set = False
52
53        self.source_buffer = source_buffer.SourceBuffer(self)
54
55        self.view = document_view.DocumentView(self, self.source_buffer.view)
56        self.gutter = gutter.Gutter(self, self.view)
57        self.search = search.Search(self, self.view, self.view.search_bar)
58        self.spellchecker = spellchecker.Spellchecker(self.view.source_view)
59        self.document_switcher_item = document_switcher_item.DocumentSwitcherItem(self)
60        self.context_menu = context_menu.ContextMenu(self, self.view)
61        self.shortcutsbar = shortcutsbar_presenter.ShortcutsbarPresenter(self, self.view)
62
63        self.presenter = document_presenter.DocumentPresenter(self, self.view)
64        self.controller = document_controller.DocumentController(self, self.view)
65
66        self.line_numbers = line_numbers.LineNumbers(self, self.view)
67
68    def set_search_text(self, search_text):
69        self.source_buffer.search_settings.set_search_text(search_text)
70
71    def set_dark_mode(self, dark_mode):
72        self.dark_mode = dark_mode
73        self.get_buffer().set_use_dark_scheme(dark_mode)
74
75    def get_buffer(self):
76        return self.source_buffer
77
78    def get_search_context(self):
79        return self.source_buffer.search_context
80
81    def set_filename(self, filename):
82        if filename == None:
83            self.filename = filename
84        else:
85            self.filename = os.path.realpath(filename)
86        self.add_change_code('filename_change', filename)
87
88    def get_filename(self):
89        return self.filename
90
91    def get_dirname(self):
92        if self.filename != None:
93            return os.path.dirname(self.filename)
94        else:
95            return ''
96
97    def get_displayname(self):
98        if self.filename != None:
99            return self.get_filename()
100        else:
101            return self.displayname
102
103    def set_displayname(self, displayname):
104        self.displayname = displayname
105        self.add_change_code('displayname_change')
106
107    def get_basename(self):
108        if self.filename != None:
109            return os.path.basename(self.filename)
110        else:
111            return self.displayname
112
113    def get_last_activated(self):
114        return self.last_activated
115
116    def set_last_activated(self, date):
117        self.last_activated = date
118
119    def get_modified(self):
120        return self.get_buffer().get_modified()
121
122    def populate_from_filename(self):
123        if self.filename == None: return False
124        if not os.path.isfile(self.filename):
125            self.set_filename(None)
126            return False
127        if self.get_buffer() == None: return False
128
129        with open(self.filename) as f:
130            text = f.read()
131        self.initially_set_text(text)
132        self.place_cursor(0, 0)
133        self.update_save_date()
134        return True
135
136    def save_to_disk(self):
137        if self.filename == None: return False
138        if self.get_buffer() == None: return False
139
140        text = self.get_text()
141        if text != None:
142            with open(self.filename, 'w') as f:
143                f.write(text)
144            self.update_save_date()
145            self.deleted_on_disk_dialog_shown_after_last_save = False
146            self.get_buffer().set_modified(False)
147
148    def update_save_date(self):
149        self.save_date = os.path.getmtime(self.filename)
150
151    def get_changed_on_disk(self):
152        return self.save_date <= os.path.getmtime(self.filename) - 0.001
153
154    def get_deleted_on_disk(self):
155        return not os.path.isfile(self.filename)
156
157    def initially_set_text(self, text):
158        self.get_buffer().initially_set_text(text)
159
160    #@timer
161    def get_text(self):
162        return self.get_buffer().get_all_text()
163
164    def get_text_after_offset(self, offset):
165        return self.get_buffer().get_text_after_offset(offset)
166
167    def get_selected_text(self):
168        return self.get_buffer().get_selected_text()
169
170    def get_line_at_cursor(self):
171        return self.get_buffer().get_line_at_cursor()
172
173    def get_char_at_cursor(self):
174        return self.get_buffer().get_char_at_cursor()
175
176    def get_line(self, line_number):
177        return self.get_buffer().get_line(line_number)
178
179    def get_current_line_number(self):
180        return self.get_buffer().get_current_line_number()
181
182    def is_empty(self):
183        return self.source_buffer.is_empty()
184
185    def place_cursor(self, line_number, offset=0):
186        self.get_buffer().place_cursor_and_scroll(line_number, offset)
187
188    def get_cursor_offset(self):
189        return self.get_buffer().get_cursor_offset()
190
191    def get_cursor_line_offset(self):
192        return self.get_buffer().get_cursor_line_offset()
193
194    def cursor_inside_latex_command_or_at_end(self):
195        current_word = self.get_latex_command_at_cursor()
196        if ServiceLocator.get_regex_object(r'\\(\w*(?:\*){0,1})').fullmatch(current_word):
197            return True
198        return False
199
200    def cursor_at_latex_command_end(self):
201        current_word = self.get_latex_command_at_cursor()
202        if ServiceLocator.get_regex_object(r'\\(\w*(?:\*){0,1})').fullmatch(current_word):
203            return self.get_buffer().cursor_ends_word()
204        return False
205
206    def insert_before_document_end(self, text):
207        self.get_buffer().insert_before_document_end(text)
208
209    def insert_text(self, line_number, offset, text, indent_lines=True):
210        self.get_buffer().insert_text(line_number, offset, text, indent_lines)
211
212    def insert_text_at_cursor(self, text, indent_lines=True, scroll=True, select_dot=True):
213        self.get_buffer().insert_text_at_cursor(text, indent_lines, scroll, select_dot)
214
215    def replace_range(self, offset, length, text, indent_lines=True, select_dot=True):
216        self.get_buffer().replace_range_by_offset_and_length(offset, length, text, indent_lines, select_dot)
217
218    def insert_before_after(self, before, after):
219        self.get_buffer().insert_before_after(before, after)
220
221    def add_backslash_with_space(self):
222        self.get_buffer().add_backslash_with_space()
223
224    def autoadd_latex_brackets(self, char):
225        self.get_buffer().autoadd_latex_brackets(char)
226
227    def undo(self):
228        self.get_buffer().undo()
229
230    def redo(self):
231        self.get_buffer().redo()
232
233    def cut(self):
234        self.get_buffer().cut()
235
236    def copy(self):
237        self.get_buffer().copy()
238
239    def paste(self):
240        self.get_buffer().paste()
241
242    def delete_selection(self):
243        self.get_buffer().delete_selection(True, True)
244
245    def select_all(self):
246        self.get_buffer().select_all()
247
248
249