Package Gnumed :: Package timelinelib :: Package wxgui :: Package frames :: Package mainframe :: Module mainframe
[frames] | no frames]

Source Code for Module Gnumed.timelinelib.wxgui.frames.mainframe.mainframe

  1  # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg 
  2  # 
  3  # This file is part of Timeline. 
  4  # 
  5  # Timeline 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  # Timeline 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 Timeline.  If not, see <http://www.gnu.org/licenses/>. 
 17   
 18   
 19  import os.path 
 20   
 21  import wx.lib.newevent 
 22   
 23  from timelinelib.canvas.data import TimePeriod 
 24  from timelinelib.config.dotfile import read_config 
 25  from timelinelib.config.paths import ICONS_DIR 
 26  from timelinelib.config.paths import LOCALE_DIR 
 27  from timelinelib.dataexport.timelinexml import export_db_to_timeline_xml 
 28  from timelinelib.db import db_open 
 29  from timelinelib.features.experimental.experimentalfeatures import ExperimentalFeatures 
 30  from timelinelib.meta.about import APPLICATION_NAME 
 31  from timelinelib.calendar.bosparanian.timetype import BosparanianTimeType 
 32  from timelinelib.calendar.num.timetype import NumTimeType 
 33  from timelinelib.utils import ex_msg 
 34  from timelinelib.wxgui.dialogs.changenowdate.view import ChangeNowDateDialog 
 35  from timelinelib.wxgui.dialogs.eraseditor.view import ErasEditorDialog 
 36  from timelinelib.wxgui.dialogs.setcategory.view import SetCategoryDialog 
 37  from timelinelib.wxgui.dialogs.timeeditor.view import TimeEditorDialog 
 38  from timelinelib.wxgui.frames.helpbrowserframe.helpbrowserframe import HelpBrowserFrame 
 39  from timelinelib.wxgui.frames.mainframe.mainframecontroller import LockedException 
 40  from timelinelib.wxgui.frames.mainframe.mainframecontroller import MainFrameController 
 41  from timelinelib.wxgui.timer import TimelineTimer 
 42  from timelinelib.wxgui.utils import display_categories_editor_moved_message 
 43  from timelinelib.wxgui.utils import display_error_message 
 44  from timelinelib.wxgui.utils import display_information_message 
 45  from timelinelib.wxgui.utils import WildcardHelper 
 46  import timelinelib.wxgui.frames.mainframe.guicreator as guic 
 47  from timelinelib.wxgui.frames.mainframe.controllerapi import MainFrameApiUsedByController 
 48  from timelinelib.wxgui.frames.mainframe.alertcontroller import AlertController 
 49  from timelinelib.wxgui.frames.mainframe.menucontroller import MenuController 
 50  from timelinelib.calendar.coptic.timetype import CopticTimeType 
 51  from timelinelib.calendar.pharaonic.timetype import PharaonicTimeType 
 52   
 53  CatsViewChangedEvent, EVT_CATS_VIEW_CHANGED = wx.lib.newevent.NewCommandEvent() 
 54   
 55   
56 -class MainFrame(wx.Frame, guic.GuiCreator, MainFrameApiUsedByController):
57
58 - def __init__(self, application_arguments):
59 self.config = read_config(application_arguments.get_config_file_path()) 60 wx.Frame.__init__(self, None, size=self.config.get_window_size(), 61 pos=self.config.get_window_pos(), 62 style=wx.DEFAULT_FRAME_STYLE, name="main_frame") 63 self.Bind(EVT_CATS_VIEW_CHANGED, self._on_cats_view_changed) 64 # To enable translations of wx stock items. 65 self.locale = wx.Locale(wx.LANGUAGE_DEFAULT) 66 self.locale.AddCatalogLookupPathPrefix(LOCALE_DIR) 67 self.locale.AddCatalog("wxstd") 68 self.help_browser = HelpBrowserFrame(self) 69 self.controller = MainFrameController(self, db_open, self.config) 70 self.menu_controller = MenuController() 71 self._set_initial_values_to_member_variables() 72 self._create_print_data() 73 self._set_experimental_features() 74 self._create_gui() 75 self.Maximize(self.config.window_maximized) 76 self.SetTitle(APPLICATION_NAME) 77 self.SetIcons(self._load_icon_bundle()) 78 self.main_panel.show_welcome_panel() 79 self.enable_disable_menus() 80 self.controller.on_started(application_arguments) 81 self._create_and_start_timer() 82 self.prev_time_period = None
83
84 - def DisplayErrorMessage(self, message):
86
87 - def DisplayStatus(self, message):
88 self.status_bar_adapter.set_text(message)
89 90 # API:s used by time types
91 - def week_starts_on_monday(self):
93
94 - def display_time_editor_dialog(self, time_type, initial_time, 95 handle_new_time_fn, title):
96 dialog = TimeEditorDialog(self, self.config, time_type, initial_time, title) 97 dialog.ShowModal() 98 result = dialog.GetReturnCode() 99 if result == wx.ID_OK: 100 handle_new_time_fn(dialog.GetTime()) 101 dialog.Destroy()
102
103 - def display_now_date_editor_dialog(self, handle_new_time_fn, title):
104 dialog = ChangeNowDateDialog(self, self.config, self.timeline, handle_new_time_fn, title) 105 dialog.Show()
106
107 - def save_time_period(self):
108 self.prev_time_period = self.main_panel.get_time_period()
109 110 # Concurrent editing
111 - def ok_to_edit(self):
112 try: 113 return self.controller.ok_to_edit() 114 except LockedException: 115 return False
116
117 - def get_lockfile_path(self):
118 return self.controller._get_lockpath()
119
120 - def edit_ends(self):
121 self.controller.edit_ends()
122
123 - def get_view_properties(self, ):
124 return self.main_panel.get_view_properties()
125
126 - def _on_cats_view_changed(self, evt):
128 129 # Creation process methods
131 self.timeline = None 132 self.timeline_wildcard_helper = WildcardHelper( 133 _("Timeline files"), ["timeline", "ics"]) 134 self.images_svg_wildcard_helper = WildcardHelper( 135 _("SVG files"), ["svg"])
136
137 - def _create_print_data(self):
138 self.printData = wx.PrintData() 139 self.printData.SetPaperId(wx.PAPER_A4) 140 self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER) 141 self.printData.SetOrientation(wx.LANDSCAPE)
142
143 - def _create_and_start_timer(self):
144 self.alert_dialog_open = False 145 self.timer = TimelineTimer(self) 146 self.timer.register(self._timer_tick) 147 self.timer.start(10000)
148
149 - def _timer_tick(self, evt):
150 self._handle_event_alerts()
151 154
155 - def _load_icon_bundle(self):
156 bundle = wx.IconBundle() 157 for size in ["16", "32", "48"]: 158 iconpath = os.path.join(ICONS_DIR, "%s.png" % size) 159 icon = wx.Icon(wx.Bitmap(wx.Image(iconpath))) 160 bundle.AddIcon(icon) 161 return bundle
162 163 # File Menu action handlers
164 - def _create_new_timeline(self, timetype=None):
165 path = self._get_file_path() 166 if path is not None: 167 self.controller.open_timeline(path, timetype)
168
170 self._create_new_timeline(BosparanianTimeType())
171
173 self._create_new_timeline(CopticTimeType())
174
176 self._create_new_timeline(PharaonicTimeType())
177
179 self._create_new_timeline(NumTimeType())
180
181 - def _get_file_path(self):
182 path = None 183 wildcard = self.timeline_wildcard_helper.wildcard_string() 184 dialog = wx.FileDialog(self, message=_("Create Timeline"), 185 wildcard=wildcard, style=wx.FD_SAVE) 186 if dialog.ShowModal() == wx.ID_OK: 187 path = self.timeline_wildcard_helper.get_path(dialog) 188 if os.path.exists(path): 189 msg_first_part = _("The specified timeline already exists.") 190 msg_second_part = _("Opening timeline instead of creating new.") 191 wx.MessageBox("%s\n\n%s" % (msg_first_part, msg_second_part), 192 _("Information"), 193 wx.OK | wx.ICON_INFORMATION, self) 194 dialog.Destroy() 195 return path
196
197 - def _create_new_dir_timeline(self):
198 dialog = wx.DirDialog(self, message=_("Create Timeline")) 199 if dialog.ShowModal() == wx.ID_OK: 200 self.controller.open_timeline(dialog.GetPath()) 201 dialog.Destroy()
202
203 - def _open_existing_timeline(self):
204 directory = "" 205 if self.timeline is not None: 206 directory = os.path.dirname(self.timeline.path) 207 wildcard = self.timeline_wildcard_helper.wildcard_string() 208 dialog = wx.FileDialog(self, message=_("Open Timeline"), 209 defaultDir=directory, 210 wildcard=wildcard, style=wx.FD_OPEN) 211 if dialog.ShowModal() == wx.ID_OK: 212 self.controller.open_timeline(dialog.GetPath()) 213 dialog.Destroy()
214
215 - def _save_as(self):
216 new_timeline_path = self._get_new_timeline_path_from_user() 217 self._save_timeline_to_new_path(new_timeline_path)
218
220 defaultDir = os.path.dirname(self.timeline.path) 221 wildcard_helper = WildcardHelper(_("Timeline files"), ["timeline"]) 222 wildcard = wildcard_helper.wildcard_string() 223 style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT 224 message = _("Save Timeline As") 225 dialog = wx.FileDialog(self, message=message, defaultDir=defaultDir, 226 wildcard=wildcard, style=style) 227 if dialog.ShowModal() == wx.ID_OK: 228 new_timeline_path = wildcard_helper.get_path(dialog) 229 else: 230 new_timeline_path = None 231 dialog.Destroy() 232 return new_timeline_path
233
234 - def _save_timeline_to_new_path(self, new_timeline_path):
235 if new_timeline_path is not None: 236 assert new_timeline_path.endswith(".timeline") 237 export_db_to_timeline_xml(self.timeline, new_timeline_path) 238 self.controller.open_timeline(new_timeline_path)
239
240 - def _window_on_close(self, event):
241 self.timer.stop() 242 self._save_application_config() 243 try: 244 if self.ok_to_edit(): 245 self.save_current_timeline_data() 246 finally: 247 self.edit_ends() 248 self.Destroy()
249
250 - def _save_application_config(self):
251 self.config.set_window_size(self.GetSize()) 252 self.config.set_window_pos(self.GetPosition()) 253 self.config.window_maximized = self.IsMaximized() 254 self.config.sidebar_width = self.main_panel.get_sidebar_width() 255 try: 256 self.config.write() 257 except IOError as ex: 258 friendly = _("Unable to write configuration file.") 259 msg = "%s\n\n%s" % (friendly, ex_msg(ex)) 260 display_error_message(msg, self)
261
263 if self.timeline: 264 self.main_panel.save_view_properties(self.timeline)
265 266 # Timeline Menu action handlers
268 event1, event2 = self._get_selected_events() 269 self._display_distance(event1.distance_to(event2))
270
271 - def _get_selected_events(self):
272 event_id_1, event_id_2 = self.main_panel.get_ids_of_two_first_selected_events() 273 event1 = self.timeline.find_event_with_id(event_id_1) 274 event2 = self.timeline.find_event_with_id(event_id_2) 275 return event1, event2
276
277 - def _display_distance(self, distance):
278 caption = _("Distance between selected events") 279 if distance is None: 280 distance_text = _("Events are overlapping or distance is 0") 281 else: 282 distance_text = self.timeline.get_time_type().format_delta(distance) 283 display_information_message(caption, distance_text)
284
285 - def _set_category(self):
286 dialog = SetCategoryDialog(self, self.timeline) 287 dialog.ShowModal() 288 dialog.Destroy() 289 self.main_panel.redraw_timeline()
290
292 selected_event_ids = self.main_panel.get_selected_event_ids() 293 dialog = SetCategoryDialog(self, self.timeline, selected_event_ids) 294 dialog.ShowModal() 295 dialog.Destroy()
296
297 - def _edit_categories(self):
299
300 - def _edit_eras(self):
301 dialog = ErasEditorDialog(self, self.timeline, self.config) 302 dialog.ShowModal() 303 dialog.Destroy() 304 self.main_panel.redraw_timeline()
305
306 - def _fit_all_events(self):
307 all_period = self._period_for_all_visible_events() 308 if all_period is None: 309 return 310 if all_period.is_period(): 311 self.main_panel.Navigate(lambda tp: tp.update(all_period.start_time, all_period.end_time)) 312 else: 313 self.main_panel.Navigate(lambda tp: tp.center(all_period.mean_time()))
314
316 try: 317 visible_events = self._all_visible_events() 318 if len(visible_events) > 0: 319 start = self._first_time(visible_events) 320 end = self._last_time(visible_events) 321 return TimePeriod(start, end).zoom(-1) 322 else: 323 return None 324 except ValueError as ex: 325 display_error_message(str(ex)) 326 return None
327
328 - def _all_visible_events(self):
329 all_events = self.timeline.get_all_events() 330 return self.main_panel.get_visible_events(all_events)
331
332 - def _first_time(self, events):
333 start_time = lambda event: event.get_start_time() 334 return start_time(min(events, key=start_time))
335
336 - def _last_time(self, events):
337 end_time = lambda event: event.get_end_time() 338 return end_time(max(events, key=end_time))
339
340 - def get_export_periods(self):
341 events = self._all_visible_events() 342 first_time = self._first_time(events) 343 last_time = self._last_time(events) 344 return self.main_panel.get_export_periods(first_time, last_time)
345 346 # Timer event handlers
347 - def _handle_event_alerts(self):
348 if self.timeline is None: 349 return 350 if self.alert_dialog_open: 351 return 352 self._display_events_alerts() 353 self.alert_dialog_open = False
354
355 - def _display_events_alerts(self):
356 self.alert_dialog_open = True 357 all_events = self.timeline.get_all_events() 358 AlertController(self).display_events_alerts(all_events, self.timeline.get_time_type())
359