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

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

  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 collections 
 20   
 21  import wx.lib.newevent 
 22   
 23  from timelinelib.db.utils import safe_locking 
 24  from timelinelib.meta.about import display_about_dialog 
 25  from timelinelib.plugin.factory import EVENTBOX_DRAWER 
 26  from timelinelib.plugin.factory import EXPORTER 
 27  from timelinelib.plugin import factory 
 28  from timelinelib.proxies.drawingarea import DrawingAreaProxy 
 29  from timelinelib.wxgui.components.mainpanel import MainPanel 
 30  from timelinelib.wxgui.components.statusbaradapter import StatusBarAdapter 
 31  from timelinelib.wxgui.dialogs.duplicateevent.view import open_duplicate_event_dialog_for_event 
 32  from timelinelib.wxgui.dialogs.editevent.view import open_create_event_editor 
 33  from timelinelib.wxgui.dialogs.feedback.view import show_feedback_dialog 
 34  from timelinelib.wxgui.dialogs.filenew.view import FileNewDialog 
 35  from timelinelib.wxgui.dialogs.importevents.view import ImportEventsDialog 
 36  from timelinelib.wxgui.dialogs.milestone.view import open_milestone_editor_for 
 37  from timelinelib.wxgui.dialogs.preferences.view import PreferencesDialog 
 38  from timelinelib.wxgui.dialogs.shortcutseditor.view import ShortcutsEditorDialog 
 39  from timelinelib.wxgui.dialogs.systeminfo.view import show_system_info_dialog 
 40   
 41   
 42  NONE = 0 
 43  CHECKBOX = 1 
 44  CHECKED_RB = 2 
 45  UNCHECKED_RB = 3 
 46  ID_SIDEBAR = wx.NewId() 
 47  ID_LEGEND = wx.NewId() 
 48  ID_BALLOONS = wx.NewId() 
 49  ID_ZOOMIN = wx.NewId() 
 50  ID_ZOOMOUT = wx.NewId() 
 51  ID_VERT_ZOOMIN = wx.NewId() 
 52  ID_VERT_ZOOMOUT = wx.NewId() 
 53  ID_CREATE_EVENT = wx.NewId() 
 54  ID_CREATE_MILESTONE = wx.NewId() 
 55  ID_PT_EVENT_TO_RIGHT = wx.NewId() 
 56  ID_EDIT_EVENT = wx.NewId() 
 57  ID_DUPLICATE_EVENT = wx.NewId() 
 58  ID_SET_CATEGORY_ON_SELECTED = wx.NewId() 
 59  ID_MEASURE_DISTANCE = wx.NewId() 
 60  ID_COMPRESS = wx.NewId() 
 61  ID_SET_CATEGORY_ON_WITHOUT = wx.NewId() 
 62  ID_EDIT_CATEGORIES = wx.NewId() 
 63  ID_EDIT_ERAS = wx.NewId() 
 64  ID_SET_READONLY = wx.NewId() 
 65  ID_FIND_FIRST = wx.NewId() 
 66  ID_FIND_LAST = wx.NewId() 
 67  ID_FIT_ALL = wx.NewId() 
 68  ID_EDIT_SHORTCUTS = wx.NewId() 
 69  ID_TUTORIAL = wx.NewId() 
 70  ID_FEEDBACK = wx.NewId() 
 71  ID_CONTACT = wx.NewId() 
 72  ID_SYSTEM_INFO = wx.NewId() 
 73  ID_IMPORT = wx.NewId() 
 74  ID_EXPORT = wx.NewId() 
 75  ID_EXPORT_ALL = wx.NewId() 
 76  ID_EXPORT_SVG = wx.NewId() 
 77  ID_FIND_CATEGORIES = wx.NewId() 
 78  ID_SELECT_ALL = wx.NewId() 
 79  ID_RESTORE_TIME_PERIOD = wx.NewId() 
 80  ID_NEW = wx.ID_NEW 
 81  ID_FIND = wx.ID_FIND 
 82  ID_UNDO = wx.NewId() 
 83  ID_REDO = wx.NewId() 
 84  ID_PREFERENCES = wx.ID_PREFERENCES 
 85  ID_HELP = wx.ID_HELP 
 86  ID_ABOUT = wx.ID_ABOUT 
 87  ID_SAVEAS = wx.ID_SAVEAS 
 88  ID_EXIT = wx.ID_EXIT 
 89  ID_MOVE_EVENT_UP = wx.NewId() 
 90  ID_MOVE_EVENT_DOWN = wx.NewId() 
 91  ID_PRESENTATION = wx.NewId() 
 92  ID_HIDE_DONE = wx.NewId() 
 93  ID_NAVIGATE = wx.NewId() + 100 
 94   
 95   
96 -class GuiCreator(object):
97
98 - def _create_gui(self):
99 self.shortcut_items = {} 100 self._create_status_bar() 101 self._create_main_panel() 102 self._create_main_menu_bar() 103 self._bind_frame_events()
104
105 - def _create_status_bar(self):
106 self.CreateStatusBar() 107 self.status_bar_adapter = StatusBarAdapter(self.GetStatusBar())
108
109 - def _create_main_panel(self):
110 self.main_panel = MainPanel(self, self.config, self)
111
112 - def _create_main_menu_bar(self):
113 main_menu_bar = wx.MenuBar() 114 main_menu_bar.Append(self._create_file_menu(), _("&File")) 115 main_menu_bar.Append(self._create_edit_menu(), _("&Edit")) 116 main_menu_bar.Append(self._create_view_menu(), _("&View")) 117 main_menu_bar.Append(self._create_timeline_menu(), _("&Timeline")) 118 main_menu_bar.Append(self._create_navigate_menu(), _("&Navigate")) 119 main_menu_bar.Append(self._create_help_menu(), _("&Help")) 120 self._set_shortcuts() 121 self.SetMenuBar(main_menu_bar) 122 self.update_navigation_menu_items() 123 self.enable_disable_menus()
124
125 - def _set_shortcuts(self):
126 from timelinelib.config.shortcut import ShortcutController 127 self.shortcut_controller = ShortcutController(self.config, self.shortcut_items) 128 self.shortcut_controller.load_config_settings()
129
130 - def _bind_frame_events(self):
131 self.Bind(wx.EVT_CLOSE, self._window_on_close)
132
133 - def _create_file_menu(self):
134 file_menu = wx.Menu() 135 self._create_file_new_menu_item(file_menu) 136 self._create_file_open_menu_item(file_menu) 137 self._create_file_open_recent_menu(file_menu) 138 file_menu.AppendSeparator() 139 self._create_file_save_as_menu(file_menu) 140 file_menu.AppendSeparator() 141 self._create_import_menu_item(file_menu) 142 file_menu.AppendSeparator() 143 self._create_export_menues(file_menu) 144 file_menu.AppendSeparator() 145 self._create_file_exit_menu_item(file_menu) 146 self._file_menu = file_menu 147 return file_menu
148
149 - def _create_export_menues(self, file_menu):
150 151 def create_click_handler(plugin, main_frame): 152 def event_handler(evt): 153 plugin.run(main_frame)
154 return event_handler
155 156 submenu = wx.Menu() 157 file_menu.AppendMenu(wx.ID_ANY, _("Export"), submenu) 158 for plugin in factory.get_plugins(EXPORTER): 159 mnu = submenu.Append(wx.ID_ANY, plugin.display_name(), plugin.display_name()) 160 self.menu_controller.add_menu_requiring_timeline(mnu) 161 handler = create_click_handler(plugin, self) 162 self.Bind(wx.EVT_MENU, handler, mnu) 163 method = getattr(plugin, "wxid", None) 164 if callable(method): 165 self.shortcut_items[method()] = mnu 166
167 - def _create_file_new_menu_item(self, file_menu):
168 accel = wx.GetStockLabel(wx.ID_NEW, wx.STOCK_WITH_ACCELERATOR | wx.STOCK_WITH_MNEMONIC) 169 accel = accel.split("\t", 1)[1] 170 file_menu.Append( 171 wx.ID_NEW, _("New...") + "\t" + accel, _("Create a new timeline")) 172 self.shortcut_items[wx.ID_NEW] = file_menu.FindItemById(wx.ID_NEW) 173 self.Bind(wx.EVT_MENU, self._mnu_file_new_on_click, id=wx.ID_NEW)
174
175 - def _create_file_open_menu_item(self, file_menu):
176 file_menu.Append( 177 wx.ID_OPEN, self._add_ellipses_to_menuitem(wx.ID_OPEN), 178 _("Open an existing timeline")) 179 self.Bind(wx.EVT_MENU, self._mnu_file_open_on_click, id=wx.ID_OPEN)
180
181 - def _create_file_open_recent_menu(self, file_menu):
182 self.mnu_file_open_recent_submenu = wx.Menu() 183 file_menu.AppendMenu(wx.ID_ANY, _("Open &Recent"), self.mnu_file_open_recent_submenu) 184 self.update_open_recent_submenu()
185
186 - def _create_file_save_as_menu(self, file_menu):
187 menu = file_menu.Append(wx.ID_SAVEAS, "", _("Save As...")) 188 self.shortcut_items[wx.ID_SAVEAS] = menu 189 self.Bind(wx.EVT_MENU, self.mnu_file_save_as_on_click, id=wx.ID_SAVEAS)
190
191 - def _create_import_menu_item(self, file_menu):
192 mnu_file_import = file_menu.Append( 193 ID_IMPORT, _("Import events..."), _("Import events...")) 194 self.shortcut_items[ID_IMPORT] = mnu_file_import 195 self.Bind(wx.EVT_MENU, self._mnu_file_import_on_click, mnu_file_import) 196 self.menu_controller.add_menu_requiring_writable_timeline(mnu_file_import)
197
198 - def _create_file_exit_menu_item(self, file_menu):
199 file_menu.Append(wx.ID_EXIT, "", _("Exit the program")) 200 self.shortcut_items[wx.ID_EXIT] = file_menu.FindItemById(wx.ID_EXIT) 201 self.Bind(wx.EVT_MENU, self._mnu_file_exit_on_click, id=wx.ID_EXIT)
202
203 - def _create_edit_menu(self):
204 from timelinelib.wxgui.dialogs.categoryfinder.view import CategoryFinderDialog 205 206 def create_category_find_dialog(): 207 return CategoryFinderDialog(self, self.timeline)
208 209 def find(evt): 210 self.main_panel.show_searchbar(True) 211 212 def find_categories(evt): 213 dialog = create_category_find_dialog() 214 dialog.ShowModal() 215 dialog.Destroy() 216 217 def select_all(evt): 218 self.controller.select_all() 219 220 def preferences(evt): 221 def edit_function(): 222 dialog = PreferencesDialog(self, self.config) 223 dialog.ShowModal() 224 dialog.Destroy() 225 safe_locking(self, edit_function) 226 227 def edit_shortcuts(evt): 228 229 def edit_function(): 230 dialog = ShortcutsEditorDialog(self, self.shortcut_controller) 231 dialog.ShowModal() 232 dialog.Destroy() 233 safe_locking(self, edit_function) 234 cbx = NONE 235 items_spec = ((wx.ID_FIND, find, None, cbx), 236 (ID_FIND_CATEGORIES, find_categories, _("Find Categories..."), cbx), 237 None, 238 (ID_SELECT_ALL, select_all, _("Select All Events"), cbx), 239 None, 240 (wx.ID_PREFERENCES, preferences, None, cbx), 241 (ID_EDIT_SHORTCUTS, edit_shortcuts, _("Shortcuts..."), cbx)) 242 self._edit_menu = self._create_menu(items_spec) 243 self._add_edit_menu_items_to_controller(self._edit_menu) 244 return self._edit_menu 245
246 - def _add_edit_menu_items_to_controller(self, edit_menu):
247 find_item = edit_menu.FindItemById(ID_FIND) 248 find_categories_item = edit_menu.FindItemById(ID_FIND_CATEGORIES) 249 self.menu_controller.add_menu_requiring_timeline(find_item) 250 self.menu_controller.add_menu_requiring_timeline(find_categories_item)
251
252 - def _create_view_menu(self):
253 254 def sidebar(evt): 255 self.config.show_sidebar = evt.IsChecked() 256 if evt.IsChecked(): 257 self.main_panel.show_sidebar() 258 else: 259 self.main_panel.hide_sidebar()
260 261 def legend(evt): 262 self.config.show_legend = evt.IsChecked() 263 264 def balloons(evt): 265 self.config.balloon_on_hover = evt.IsChecked() 266 267 def zoomin(evt): 268 DrawingAreaProxy(self).zoom_in() 269 270 def zoomout(evt): 271 DrawingAreaProxy(self).zoom_out() 272 273 def vert_zoomin(evt): 274 DrawingAreaProxy(self).VertZoomIn() 275 276 def vert_zoomout(evt): 277 DrawingAreaProxy(self).VertZoomOut() 278 279 def start_slide_show(evt): 280 canvas = self.main_panel.get_timeline_canvas() 281 self.controller.start_slide_show(canvas) 282 283 def hide_events_done(evt): 284 self.config.hide_events_done = evt.IsChecked() 285 286 items_spec = [self._create_view_toolbar_menu_item, 287 (ID_SIDEBAR, sidebar, _("&Sidebar") + "\tCtrl+I", CHECKBOX), 288 (ID_LEGEND, legend, _("&Legend"), CHECKBOX), 289 None, 290 (ID_BALLOONS, balloons, _("&Balloons on hover"), CHECKBOX), 291 None, 292 (ID_ZOOMIN, zoomin, _("Zoom &In") + "\tCtrl++", NONE), 293 (ID_ZOOMOUT, zoomout, _("Zoom &Out") + "\tCtrl+-", NONE), 294 (ID_VERT_ZOOMIN, vert_zoomin, _("Vertical Zoom &In") + "\tAlt++", NONE), 295 (ID_VERT_ZOOMOUT, vert_zoomout, _("Vertical Zoom &Out") + "\tAlt+-", NONE), 296 None, 297 self._create_view_point_event_alignment_menu, 298 None, 299 self._create_event_box_drawers_menu, 300 None, 301 (ID_PRESENTATION, start_slide_show, _("Start slide show") + "...", NONE), 302 None, 303 (ID_HIDE_DONE, hide_events_done, _("&Hide Events done"), CHECKBOX), 304 ] 305 self._view_menu = self._create_menu(items_spec) 306 self._check_view_menu_items(self._view_menu) 307 self._add_view_menu_items_to_controller(self._view_menu) 308 return self._view_menu 309
310 - def _create_view_toolbar_menu_item(self, view_menu):
311 item = view_menu.Append(wx.ID_ANY, _("Toolbar"), kind=wx.ITEM_CHECK) 312 313 def on_click(event): 314 self.config.show_toolbar = event.IsChecked()
315 316 def check_item_corresponding_to_config(): 317 item.Check(self.config.show_toolbar) 318 319 self.Bind(wx.EVT_MENU, on_click, item) 320 self.config.listen_for_any(check_item_corresponding_to_config) 321 check_item_corresponding_to_config() 322
323 - def _create_event_box_drawers_menu(self, view_menu):
324 325 def create_click_handler(plugin): 326 def event_handler(evt): 327 self.main_panel.get_timeline_canvas().SetEventBoxDrawer(plugin.run()) 328 self.config.set_selected_event_box_drawer(plugin.display_name())
329 return event_handler 330 331 items = [] 332 for plugin in factory.get_plugins(EVENTBOX_DRAWER): 333 if (plugin.display_name() == self.config.get_selected_event_box_drawer()): 334 items.append((wx.ID_ANY, create_click_handler(plugin), plugin.display_name(), CHECKED_RB)) 335 else: 336 items.append((wx.ID_ANY, create_click_handler(plugin), plugin.display_name(), UNCHECKED_RB)) 337 sub_menu = self._create_menu(items) 338 view_menu.AppendMenu(wx.ID_ANY, _("Event appearance"), sub_menu) 339
340 - def _create_view_point_event_alignment_menu(self, view_menu):
341 sub_menu = wx.Menu() 342 left_item = sub_menu.Append(wx.ID_ANY, _("Left"), kind=wx.ITEM_RADIO) 343 center_item = sub_menu.Append(wx.ID_ANY, _("Center"), kind=wx.ITEM_RADIO) 344 view_menu.AppendMenu(wx.ID_ANY, _("Point event alignment"), sub_menu) 345 346 def on_first_tool_click(event): 347 self.config.draw_point_events_to_right = True
348 349 def on_second_tool_click(event): 350 self.config.draw_point_events_to_right = False 351 352 def check_item_corresponding_to_config(): 353 if self.config.draw_point_events_to_right: 354 left_item.Check() 355 else: 356 center_item.Check() 357 358 self.Bind(wx.EVT_MENU, on_first_tool_click, left_item) 359 self.Bind(wx.EVT_MENU, on_second_tool_click, center_item) 360 self.config.listen_for_any(check_item_corresponding_to_config) 361 check_item_corresponding_to_config() 362
363 - def _check_view_menu_items(self, view_menu):
364 365 def item(item_id): 366 return view_menu.FindItemById(item_id)
367 368 item(ID_SIDEBAR).Check(self.config.show_sidebar) 369 item(ID_LEGEND).Check(self.config.show_legend) 370 item(ID_BALLOONS).Check(self.config.balloon_on_hover) 371 item(ID_HIDE_DONE).Check(self.config.hide_events_done) 372
373 - def _add_view_menu_items_to_controller(self, view_menu):
374 sidebar_item = view_menu.FindItemById(ID_SIDEBAR) 375 legend_item = view_menu.FindItemById(ID_LEGEND) 376 balloons_item = view_menu.FindItemById(ID_BALLOONS) 377 self.menu_controller.add_menu_requiring_visible_timeline_view(sidebar_item) 378 self.menu_controller.add_menu_requiring_timeline(legend_item) 379 self.menu_controller.add_menu_requiring_timeline(balloons_item) 380 self.menu_controller.add_menu_requiring_timeline(view_menu.FindItemById(ID_ZOOMIN)) 381 self.menu_controller.add_menu_requiring_timeline(view_menu.FindItemById(ID_ZOOMOUT)) 382 self.menu_controller.add_menu_requiring_timeline(view_menu.FindItemById(ID_VERT_ZOOMIN)) 383 self.menu_controller.add_menu_requiring_timeline(view_menu.FindItemById(ID_VERT_ZOOMOUT))
384
385 - def set_category_on_selected(self):
386 387 def edit_function(): 388 self._set_category_to_selected_events()
389 390 safe_locking(self, edit_function) 391
392 - def _create_timeline_menu(self):
393 394 def create_event(evt): 395 open_create_event_editor(self, self, self.config, self.timeline)
396 397 def edit_event(evt): 398 try: 399 event_id = self.main_panel.get_id_of_first_selected_event() 400 event = self.timeline.find_event_with_id(event_id) 401 except IndexError: 402 # No event selected so do nothing! 403 return 404 self.main_panel.open_event_editor(event) 405 406 def duplicate_event(evt): 407 try: 408 event_id = self.main_panel.get_id_of_first_selected_event() 409 event = self.timeline.find_event_with_id(event_id) 410 except IndexError: 411 # No event selected so do nothing! 412 return 413 open_duplicate_event_dialog_for_event(self, self.timeline, event) 414 415 def create_milestone(evt): 416 open_milestone_editor_for(self, self, self.config, self.timeline) 417 418 def set_categoryon_selected(evt): 419 420 def edit_function(): 421 self._set_category_to_selected_events() 422 safe_locking(self, edit_function) 423 424 def measure_distance(evt): 425 self._measure_distance_between_events() 426 427 def set_category_on_without(evt): 428 def edit_function(): 429 self._set_category() 430 safe_locking(self, edit_function) 431 432 def edit_categories(evt): 433 def edit_function(): 434 self._edit_categories() 435 safe_locking(self, edit_function) 436 437 def edit_eras(evt): 438 def edit_function(): 439 self._edit_eras() 440 safe_locking(self, edit_function) 441 442 def set_readonly(evt): 443 self.controller.set_timeline_in_readonly_mode() 444 445 def undo(evt): 446 safe_locking(self, self.timeline.undo) 447 448 def redo(evt): 449 safe_locking(self, self.timeline.redo) 450 451 def compress(evt): 452 safe_locking(self, self.timeline.compress) 453 454 def move_up_handler(event): 455 self.main_panel.timeline_panel.move_selected_event_up() 456 457 def move_down_handler(event): 458 self.main_panel.timeline_panel.move_selected_event_down() 459 460 cbx = NONE 461 items_spec = ((ID_CREATE_EVENT, create_event, _("Create &Event..."), cbx), 462 (ID_EDIT_EVENT, edit_event, _("&Edit Selected Event..."), cbx), 463 (ID_DUPLICATE_EVENT, duplicate_event, _("&Duplicate Selected Event..."), cbx), 464 (ID_SET_CATEGORY_ON_SELECTED, set_categoryon_selected, _("Set Category on Selected Events..."), cbx), 465 (ID_MOVE_EVENT_UP, move_up_handler, _("Move event up") + "\tAlt+Up", cbx), 466 (ID_MOVE_EVENT_DOWN, move_down_handler, _("Move event down") + "\tAlt+Down", cbx), 467 None, 468 (ID_CREATE_MILESTONE, create_milestone, _("Create &Milestone..."), cbx), 469 None, 470 (ID_COMPRESS, compress, _("&Compress timeline Events"), cbx), 471 None, 472 (ID_MEASURE_DISTANCE, measure_distance, _("&Measure Distance between two Events..."), cbx), 473 None, 474 (ID_SET_CATEGORY_ON_WITHOUT, set_category_on_without, 475 _("Set Category on events &without category..."), cbx), 476 (ID_EDIT_CATEGORIES, edit_categories, _("Edit &Categories"), cbx), 477 None, 478 (ID_EDIT_ERAS, edit_eras, _("Edit Era's..."), cbx), 479 None, 480 (ID_SET_READONLY, set_readonly, _("&Read Only"), cbx), 481 None, 482 (ID_UNDO, undo, _("&Undo") + "\tCtrl+Z", cbx), 483 (ID_REDO, redo, _("&Redo") + "\tAlt+Z", cbx)) 484 self._timeline_menu = self._create_menu(items_spec) 485 self._add_timeline_menu_items_to_controller(self._timeline_menu) 486 return self._timeline_menu 487
488 - def _add_timeline_menu_items_to_controller(self, menu):
489 self._add_to_controller_requiring_writeable_timeline(menu, ID_CREATE_EVENT) 490 self._add_to_controller_requiring_writeable_timeline(menu, ID_EDIT_EVENT) 491 self._add_to_controller_requiring_writeable_timeline(menu, ID_CREATE_MILESTONE) 492 self._add_to_controller_requiring_writeable_timeline(menu, ID_DUPLICATE_EVENT) 493 self._add_to_controller_requiring_writeable_timeline(menu, ID_SET_CATEGORY_ON_SELECTED) 494 self._add_to_controller_requiring_writeable_timeline(menu, ID_MEASURE_DISTANCE) 495 self._add_to_controller_requiring_writeable_timeline(menu, ID_SET_CATEGORY_ON_WITHOUT) 496 self._add_to_controller_requiring_writeable_timeline(menu, ID_EDIT_CATEGORIES) 497 self._add_to_controller_requiring_writeable_timeline(menu, ID_SET_READONLY) 498 self._add_to_controller_requiring_writeable_timeline(menu, ID_EDIT_ERAS) 499 self._add_to_controller_requiring_writeable_timeline(menu, ID_COMPRESS)
500
501 - def _add_to_controller_requiring_writeable_timeline(self, menu, item_id):
502 mnu_item = menu.FindItemById(item_id) 503 self.menu_controller.add_menu_requiring_writable_timeline(mnu_item)
504
505 - def _create_navigate_menu(self):
506 507 def find_first(evt): 508 event = self.timeline.get_first_event() 509 if event: 510 start = event.get_start_time() 511 delta = self.main_panel.get_displayed_period_delta() 512 end = start + delta 513 margin_delta = delta / 24 514 self.main_panel.Navigate(lambda tp: tp.update(start, end, -margin_delta))
515 516 def find_last(evt): 517 event = self.timeline.get_last_event() 518 if event: 519 end = event.get_end_time() 520 delta = self.main_panel.get_displayed_period_delta() 521 try: 522 start = end - delta 523 except ValueError: 524 start = self.timeline.get_time_type().get_min_time() 525 margin_delta = delta / 24 526 self.main_panel.Navigate(lambda tp: tp.update(start, end, end_delta=margin_delta)) 527 528 def restore_time_period(evt): 529 if self.prev_time_period: 530 self.main_panel.Navigate(lambda tp: self.prev_time_period) 531 532 def fit_all(evt): 533 self._fit_all_events() 534 535 cbx = NONE 536 items_spec = (None, 537 (ID_FIND_FIRST, find_first, _("Find &First Event"), cbx), 538 (ID_FIND_LAST, find_last, _("Find &Last Event"), cbx), 539 (ID_FIT_ALL, fit_all, _("Fit &All Events"), cbx), 540 None, 541 (ID_RESTORE_TIME_PERIOD, restore_time_period, _("Go to previous time period"), cbx),) 542 self._navigation_menu_items = [] 543 self._navigation_functions_by_menu_item_id = {} 544 self.update_navigation_menu_items() 545 self._navigate_menu = self._create_menu(items_spec) 546 self._add_navigate_menu_items_to_controller(self._navigate_menu) 547 return self._navigate_menu 548
549 - def _add_navigate_menu_items_to_controller(self, menu):
550 self._add_to_controller_requiring_timeline(menu, ID_FIND_FIRST) 551 self._add_to_controller_requiring_timeline(menu, ID_FIND_LAST) 552 self._add_to_controller_requiring_timeline(menu, ID_FIT_ALL)
553
554 - def _add_to_controller_requiring_timeline(self, menu, item_id):
555 mnu_item = menu.FindItemById(item_id) 556 self.menu_controller.add_menu_requiring_timeline(mnu_item)
557
558 - def _create_help_menu(self):
559 560 def feedback(e): 561 show_feedback_dialog(parent=None, info="", subject=_("Feedback"), body="")
562 563 cbx = NONE 564 items_spec = [(wx.ID_HELP, self.help_browser.show_contents_page, _("&Contents") + "\tF1", cbx), 565 None, 566 (ID_TUTORIAL, self.controller.open_gregorian_tutorial_timeline, _("Getting started &tutorial"), cbx), 567 None, 568 (ID_FEEDBACK, feedback, _("Give &Feedback..."), cbx), 569 (ID_CONTACT, self.help_browser.show_contact_page, _("Co&ntact"), cbx), 570 None, 571 (ID_SYSTEM_INFO, show_system_info_dialog, _("System information"), cbx), 572 None, 573 (wx.ID_ABOUT, display_about_dialog, None, cbx)] 574 self._help_menu = self._create_menu(items_spec) 575 return self._help_menu 576
577 - def display_timeline_context_menu(self):
578 try: 579 menu = self.context_menu 580 except: 581 self.context_menu = self._create_timeline_context_menu() 582 menu = self.context_menu 583 self.PopupMenu(menu) 584 self._create_main_menu_bar()
585
586 - def create_timeline_context_menu(self):
587 self.context_menu = self._create_timeline_context_menu()
588
589 - def _create_timeline_context_menu(self):
590 menu = wx.Menu() 591 menu_bar = self._file_menu.GetMenuBar() 592 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(0), self._file_menu) 593 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(1), self._edit_menu) 594 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(2), self._view_menu) 595 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(3), self._timeline_menu) 596 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(4), self._navigate_menu) 597 menu.AppendMenu(wx.ID_ANY, menu_bar.GetMenuLabel(5), self._help_menu) 598 return menu
599
600 - def _create_menu(self, items_spec):
601 menu = wx.Menu() 602 for item in items_spec: 603 if item is not None: 604 self._create_menu_item(menu, item) 605 else: 606 menu.AppendSeparator() 607 return menu
608
609 - def _create_menu_item(self, menu, item_spec):
610 if isinstance(item_spec, collections.Callable): 611 item_spec(menu) 612 else: 613 item_id, handler, label, checkbox = item_spec 614 if label is not None: 615 if checkbox == CHECKBOX: 616 item = menu.Append(item_id, label, kind=wx.ITEM_CHECK) 617 elif checkbox == CHECKED_RB: 618 item = menu.Append(item_id, label, kind=wx.ITEM_RADIO) 619 item.Check(True) 620 elif checkbox == UNCHECKED_RB: 621 item = menu.Append(item_id, label, kind=wx.ITEM_RADIO) 622 else: 623 if label is not None: 624 item = menu.Append(item_id, label) 625 else: 626 item = menu.Append(item_id) 627 else: 628 item = menu.Append(item_id) 629 self.shortcut_items[item_id] = menu.FindItemById(item_id) 630 self.Bind(wx.EVT_MENU, handler, item)
631
632 - def _mnu_file_new_on_click(self, event):
633 items = [ 634 { 635 "text": _("Gregorian"), 636 "description": _("This creates a timeline using the standard calendar."), 637 "create_fn": self._create_new_timeline, 638 }, 639 { 640 "text": _("Numeric"), 641 "description": _("This creates a timeline that has numbers on the x-axis instead of dates."), 642 "create_fn": self._create_new_numeric_timeline, 643 }, 644 { 645 "text": _("Directory"), 646 "description": _("This creates a timeline where the modification date of files in a directory are shown as events."), 647 "create_fn": self._create_new_dir_timeline, 648 }, 649 { 650 "text": _("Bosparanian"), 651 "description": _("This creates a timeline using the fictuous Bosparanian calendar from the German pen-and-paper RPG \"The Dark Eye\" (\"Das schwarze Auge\", DSA)."), 652 "create_fn": self._create_new_bosparanian_timeline, 653 }, 654 ] 655 dialog = FileNewDialog(self, items) 656 if dialog.ShowModal() == wx.ID_OK: 657 dialog.GetSelection()["create_fn"]() 658 dialog.Destroy()
659
660 - def _mnu_file_open_on_click(self, event):
661 self._open_existing_timeline()
662
663 - def mnu_file_save_as_on_click(self, event):
664 if self.timeline is not None: 665 self._save_as()
666
667 - def _mnu_file_import_on_click(self, menu):
668 def open_import_dialog(): 669 dialog = ImportEventsDialog(self.timeline, self) 670 dialog.ShowModal() 671 dialog.Destroy()
672 safe_locking(self, open_import_dialog) 673
674 - def _mnu_file_exit_on_click(self, evt):
675 self.Close()
676
677 - def _add_ellipses_to_menuitem(self, wx_id):
678 plain = wx.GetStockLabel(wx_id, wx.STOCK_WITH_ACCELERATOR | wx.STOCK_WITH_MNEMONIC) 679 # format of plain 'xxx[\tyyy]', example '&New\tCtrl+N' 680 tab_index = plain.find("\t") 681 if tab_index != -1: 682 return plain[:tab_index] + "..." + plain[tab_index:] 683 return plain + "..."
684