1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
106 self.prev_time_period = self.main_panel.get_time_period()
107
108
109 - def ok_to_edit(self):
110 try:
111 return self.controller.ok_to_edit()
112 except LockedException:
113 return False
114
116 return self.controller._get_lockpath()
117
118 - def edit_ends(self):
120
122 return self.main_panel.get_view_properties()
123
126
127
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
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
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
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
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
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
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
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
266 event1, event2 = self._get_selected_events()
267 self._display_distance(event1.distance_to(event2))
268
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
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
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):
333
334 - def _last_time(self, events):
337
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
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
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