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