1#!/usr/local/bin/python3.8 2# coding: utf-8 3 4# Copyright (C) 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 gi 19gi.require_version('Gtk', '3.0') 20from gi.repository import Gtk 21from gi.repository import Gio 22 23import sys 24import gettext 25import argparse 26import os.path 27 28from setzer.workspace.workspace import Workspace 29import setzer.workspace.workspace_viewgtk as view 30from setzer.app.service_locator import ServiceLocator 31from setzer.dialogs.dialog_locator import DialogLocator 32 33 34class MainApplicationController(Gtk.Application): 35 36 def __init__(self): 37 Gtk.Application.__init__(self, application_id='org.cvfosammmm.Setzer', flags=Gio.ApplicationFlags.HANDLES_OPEN) 38 39 def do_startup(self): 40 Gtk.Application.do_startup(self) 41 self.is_active = False 42 43 # setup gettext 44 gettext.install('setzer', names=('ngettext',), localedir='@localedir_path@') 45 46 # get settings 47 self.settings = ServiceLocator.get_settings() 48 49 # init static variables 50 ServiceLocator.init_setzer_version('@setzer_version@') 51 ServiceLocator.init_resources_path('@resources_path@') 52 ServiceLocator.init_app_icons_path('@app_icons_path@') 53 resources_path = ServiceLocator.get_resources_path() 54 app_icons_path = ServiceLocator.get_app_icons_path() 55 Gtk.IconTheme.append_search_path(Gtk.IconTheme.get_default(), os.path.join(resources_path, 'icons')) 56 for folder in ['arrows', 'greek_letters', 'misc_math', 'misc_text', 'operators', 'relations']: 57 path = os.path.join(resources_path, 'symbols', folder) 58 Gtk.IconTheme.append_search_path(Gtk.IconTheme.get_default(), path) 59 Gtk.IconTheme.append_search_path(Gtk.IconTheme.get_default(), app_icons_path) 60 61 # init main window, model, dialogs 62 self.main_window = view.MainWindow(self) 63 ServiceLocator.init_main_window(self.main_window) 64 65 def do_open(self, files, number_of_files, hint=""): 66 if not self.is_active: 67 self.activate() 68 self.is_active = True 69 70 # open first session file if any 71 for file in files: 72 if file.get_path().endswith('.stzs'): 73 filename = file.get_path() 74 75 active_document = self.workspace.get_active_document() 76 documents = self.workspace.get_all_documents() 77 unsaved_documents = self.workspace.get_unsaved_documents() 78 dialog = DialogLocator.get_dialog('close_confirmation') 79 not_save_to_close_documents = dialog.run(unsaved_documents)['not_save_to_close_documents'] 80 81 if len(not_save_to_close_documents) == 0: 82 if documents != None: 83 for document in documents: 84 self.workspace.remove_document(document) 85 self.workspace.load_documents_from_session_file(filename) 86 87 # open latex and bibtex files 88 for file in files: 89 if file.get_path().endswith('.tex') or file.get_path().endswith('.bib'): 90 document_candidate = self.workspace.get_document_by_filename(file.get_path()) 91 if document_candidate != None: 92 self.workspace.set_active_document(document_candidate) 93 else: 94 self.workspace.create_document_from_filename(file.get_path(), activate=True) 95 96 def do_activate(self): 97 if not self.is_active: 98 self.activate() 99 self.is_active = True 100 101 def activate(self): 102 self.workspace = Workspace() 103 ServiceLocator.init_workspace(self.workspace) 104 ServiceLocator.init_autocomplete_provider(self.workspace) 105 DialogLocator.init_dialogs(self.main_window, self.workspace) 106 107 # init view 108 if self.settings.get_value('window_state', 'is_maximized'): 109 self.main_window.maximize() 110 else: 111 self.main_window.unmaximize() 112 self.main_window.set_default_size(self.settings.get_value('window_state', 'width'), 113 self.settings.get_value('window_state', 'height')) 114 self.main_window.current_width = self.settings.get_value('window_state', 'width') 115 self.main_window.current_height = self.settings.get_value('window_state', 'height') 116 self.first_window_state_event = True 117 self.main_window.show_all() 118 119 self.color_manager = ServiceLocator.get_color_manager() 120 self.fg_color = self.color_manager.get_theme_color('theme_fg_color') 121 self.bg_color = self.color_manager.get_theme_color('theme_bg_color') 122 123 self.main_window.connect('size-allocate', self.on_window_size_allocate) 124 self.main_window.connect('notify::is-maximized', self.on_window_maximize_event) 125 self.main_window.connect('delete-event', self.on_window_close) 126 self.main_window.connect('draw', self.on_window_draw) 127 128 # init controller 129 self.workspace.init_workspace_controller() 130 self.workspace.actions.quit_action.connect('activate', self.on_quit_action) 131 132 def on_window_size_allocate(self, main_window, window_size): 133 ''' signal handler, update window size variables ''' 134 135 if not main_window.ismaximized: 136 main_window.current_width, main_window.current_height = main_window.get_size() 137 138 def on_window_maximize_event(self, main_window, state_event): 139 ''' signal handler, update window state variables ''' 140 141 main_window.ismaximized = main_window.is_maximized() 142 return False 143 144 def on_window_draw(self, main_window, context): 145 ''' check for theme changes, update sidebar, textviews ''' 146 147 fg_color = self.color_manager.get_theme_color('theme_fg_color') 148 bg_color = self.color_manager.get_theme_color('theme_bg_color') 149 if self.fg_color.red != fg_color.red or self.bg_color.red != bg_color.red: 150 self.fg_color = fg_color 151 self.bg_color = bg_color 152 153 try: documents = self.workspace.open_documents 154 except AttributeError: pass 155 else: 156 is_dark_mode = ServiceLocator.get_is_dark_mode() 157 for document in documents: 158 document.set_dark_mode(is_dark_mode) 159 return False 160 161 def save_window_state(self): 162 main_window = self.main_window 163 self.settings.set_value('window_state', 'width', main_window.current_width) 164 self.settings.set_value('window_state', 'height', main_window.current_height) 165 self.settings.set_value('window_state', 'is_maximized', main_window.ismaximized) 166 self.settings.set_value('window_state', 'show_sidebar', self.workspace.show_sidebar) 167 self.settings.set_value('window_state', 'sidebar_paned_position', self.workspace.sidebar_position) 168 self.settings.set_value('window_state', 'show_help', self.workspace.show_help) 169 self.settings.set_value('window_state', 'show_preview', self.workspace.show_preview) 170 self.settings.set_value('window_state', 'preview_paned_position', self.workspace.preview_position) 171 self.settings.set_value('window_state', 'show_build_log', self.workspace.show_build_log) 172 self.settings.set_value('window_state', 'build_log_paned_position', self.workspace.build_log_position) 173 self.settings.pickle() 174 175 def on_window_close(self, window=None, parameter=None): 176 self.save_quit() 177 return True 178 179 def on_quit_action(self, action=None, parameter=None): 180 self.save_quit() 181 182 def save_quit(self): 183 for document in self.workspace.open_documents: document.state_manager.save_document_state() 184 185 documents = self.workspace.get_unsaved_documents() 186 active_document = self.workspace.get_active_document() 187 188 if documents == None or active_document == None or DialogLocator.get_dialog('close_confirmation').run(documents)['all_save_to_close']: 189 self.save_window_state() 190 self.workspace.save_to_disk() 191 self.quit() 192 193 194argparser = argparse.ArgumentParser(usage='%(prog)s [OPTION...] [FILE...]') 195argparser.add_argument('-V', '--version', action='version', version='@setzer_version@') 196argparser.add_argument('file', nargs='*', help=argparse.SUPPRESS) 197argparser.parse_args() 198 199main_controller = MainApplicationController() 200exit_status = main_controller.run(sys.argv) 201sys.exit(exit_status) 202