1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import os
20 import webbrowser
21
22 import wx
23
24 from timelinelib.canvas import EVT_DIVIDER_POSITION_CHANGED
25 from timelinelib.canvas import EVT_TIMELINE_REDRAWN
26 from timelinelib.db.utils import safe_locking
27 from timelinelib.general.observer import Listener
28 from timelinelib.wxgui.components.maincanvas.createperiodeventbydrag import CreatePeriodEventByDragInputHandler
29 from timelinelib.wxgui.components.maincanvas.maincanvas import MainCanvas
30 from timelinelib.wxgui.components.maincanvas.movebydrag import MoveByDragInputHandler
31 from timelinelib.wxgui.components.maincanvas.noop import NoOpInputHandler
32 from timelinelib.wxgui.components.maincanvas.resizebydrag import ResizeByDragInputHandler
33 from timelinelib.wxgui.components.maincanvas.scrollbydrag import ScrollByDragInputHandler
34 from timelinelib.wxgui.components.maincanvas.zoombydrag import ZoomByDragInputHandler
35 from timelinelib.wxgui.components.maincanvas.selectevents import SelectEventsInputHandler
36 from timelinelib.wxgui.components.messagebar import MessageBar
37 from timelinelib.wxgui.components.sidebar import Sidebar
38 from timelinelib.wxgui.dialogs.duplicateevent.view import open_duplicate_event_dialog_for_event
39 from timelinelib.wxgui.dialogs.editevent.view import open_create_event_editor
40 from timelinelib.wxgui.dialogs.editevent.view import open_event_editor_for
41 from timelinelib.wxgui.dialogs.milestone.view import open_milestone_editor_for
42 from timelinelib.wxgui.frames.mainframe.toolbar import ToolbarCreator
43 from timelinelib.wxgui.utils import _ask_question
44 from timelinelib.config.paths import ICONS_DIR
45 from timelinelib.wxgui.cursor import Cursor
46
47
48 LEFT_RIGHT_SCROLL_FACTOR = 1 / 200.0
49
50
52
57
60
63
65 self._create_toolbar()
66 self._create_warning_bar()
67 self._create_divider_line_slider()
68 self._create_splitter()
69 self._layout_components()
70
73
76
78
79 def on_slider(evt):
80 self.config.divider_line_slider_pos = evt.GetPosition()
81
82 style = wx.SL_LEFT | wx.SL_VERTICAL
83 self.divider_line_slider = wx.Slider(self, size=(20, -1), style=style)
84 self.Bind(wx.EVT_SCROLL, on_slider, self.divider_line_slider)
85
86 self.divider_line_slider.Bind(wx.EVT_SLIDER, self._slider_on_slider)
87 self.divider_line_slider.Bind(wx.EVT_CONTEXT_MENU, self._slider_on_context_menu)
88
91
93 menu = wx.Menu()
94 menu_item = wx.MenuItem(menu, wx.NewId(), _("Center"))
95 self.Bind(wx.EVT_MENU, self._context_menu_on_menu_center, id=menu_item.GetId())
96 menu.Append(menu_item)
97 self.PopupMenu(menu)
98 menu.Destroy()
99
101 self.timeline_canvas.SetDividerPosition(50)
102
104 self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
105 self.splitter.SetMinimumPaneSize(50)
106 self.Bind(
107 wx.EVT_SPLITTER_SASH_POS_CHANGED,
108 self._splitter_on_splitter_sash_pos_changed, self.splitter)
109 self._create_sidebar()
110 self._create_timeline_canvas()
111 self.splitter.Initialize(self.timeline_canvas)
112
114 if self.IsShown():
115 self.sidebar_width = self.splitter.GetSashPosition()
116
119
121 self.timeline_canvas = MainCanvas(
122 self.splitter, self._edit_controller, self.status_bar_adapter)
123 self.timeline_canvas.Bind(
124 wx.EVT_LEFT_DCLICK,
125 self._timeline_canvas_on_double_clicked
126 )
127 self.timeline_canvas.Bind(
128 wx.EVT_RIGHT_DOWN,
129 self._timeline_canvas_on_right_down
130 )
131 self.timeline_canvas.Bind(
132 wx.EVT_KEY_DOWN,
133 self._timeline_canvas_on_key_down
134 )
135 self.timeline_canvas.Bind(
136 EVT_DIVIDER_POSITION_CHANGED,
137 self._timeline_canvas_on_divider_position_changed
138 )
139 self.timeline_canvas.Bind(
140 EVT_TIMELINE_REDRAWN,
141 self._timeline_canvas_on_timeline_redrawn
142 )
143 self.timeline_canvas.SetDividerPosition(self.config.divider_line_slider_pos)
144 self.timeline_canvas.SetEventBoxDrawer(self._get_saved_event_box_drawer())
145 self.timeline_canvas.SetInputHandler(NoOpInputHandler(
146 InputHandlerState(
147 self.timeline_canvas, self.status_bar_adapter,
148 self._edit_controller, self.config),
149 self.timeline_canvas))
150
151 def update_appearance():
152 appearance = self.timeline_canvas.GetAppearance()
153 appearance.set_legend_visible(self.config.show_legend)
154 appearance.set_balloons_visible(self.config.balloon_on_hover)
155 appearance.set_hide_events_done(self.config.hide_events_done)
156 appearance.set_minor_strip_divider_line_colour(self.config.minor_strip_divider_line_colour)
157 appearance.set_major_strip_divider_line_colour(self.config.major_strip_divider_line_colour)
158 appearance.set_now_line_colour(self.config.now_line_colour)
159 appearance.set_weekend_colour(self.config.weekend_colour)
160 appearance.set_bg_colour(self.config.bg_colour)
161 appearance.set_colorize_weekends(self.config.colorize_weekends)
162 appearance.set_draw_period_events_to_right(self.config.draw_point_events_to_right)
163 appearance.set_text_below_icon(self.config.text_below_icon)
164 appearance.set_minor_strip_font(self.config.minor_strip_font)
165 appearance.set_major_strip_font(self.config.major_strip_font)
166 appearance.set_balloon_font(self.config.balloon_font)
167 appearance.set_legend_font(self.config.legend_font)
168 appearance.set_center_event_texts(self.config.center_event_texts)
169 appearance.set_never_show_period_events_as_point_events(self.config.never_show_period_events_as_point_events)
170 appearance.set_week_start(self.config.get_week_start())
171 appearance.set_use_inertial_scrolling(self.config.use_inertial_scrolling)
172 appearance.set_fuzzy_icon(self.config.fuzzy_icon)
173 appearance.set_locked_icon(self.config.locked_icon)
174 appearance.set_hyperlink_icon(self.config.hyperlink_icon)
175 appearance.set_vertical_space_between_events(self.config.vertical_space_between_events)
176 appearance.set_skip_s_in_decade_text(self.config.skip_s_in_decade_text)
177 appearance.set_display_checkmark_on_events_done(self.config.display_checkmark_on_events_done)
178 appearance.set_never_use_time(self.config.never_use_time)
179 appearance.set_legend_pos(self.config.legend_pos)
180 appearance.set_time_scale_pos(self.config.time_scale_pos)
181 appearance.set_use_bold_nowline(self.config.use_bold_nowline)
182 self.config.listen_for_any(update_appearance)
183 update_appearance()
184
191
212
224
238
240 self._try_move_event_vertically(True)
241
243 self._try_move_event_vertically(False)
244
249
272 safe_locking(self._edit_controller, edit_function)
273
275 menu_definitions = [
276 (_("Delete"), self._context_menu_on_delete_event, None),
277 ]
278 nbr_of_selected_events = len(self.timeline_canvas.GetSelectedEvents())
279 if nbr_of_selected_events == 1:
280 menu_definitions.insert(0, (_("Edit"), self._context_menu_on_edit_event, None))
281 menu_definitions.insert(1, (_("Duplicate..."), self._context_menu_on_duplicate_event, None))
282 menu_definitions.append((_("Mark Event as Done"), self._context_menu_on_done_event, None))
283 menu_definitions.append((_("Select Category..."), self._context_menu_on_select_category, None))
284 if nbr_of_selected_events == 1 and self.timeline_canvas.GetSelectedEvent().has_data():
285 menu_definitions.append((_("Sticky Balloon"), self._context_menu_on_sticky_balloon_event, None))
286 if nbr_of_selected_events == 1:
287 hyperlinks = self.timeline_canvas.GetSelectedEvent().get_data("hyperlink")
288 if hyperlinks is not None:
289 imp = wx.Menu()
290 menuid = 0
291 for hyperlink in hyperlinks.split(";"):
292 imp.Append(menuid, hyperlink)
293 menuid += 1
294 menu_definitions.append((_("Goto URL"), self._context_menu_on_goto_hyperlink_event, imp))
295 menu = wx.Menu()
296 mid = 0
297 for menu_definition in menu_definitions:
298 text, method, imp = menu_definition
299 menu_item = wx.MenuItem(menu, mid, text)
300 if imp is not None:
301 for menu_item in imp.GetMenuItems():
302 self.Bind(wx.EVT_MENU, method, id=menu_item.GetId())
303 menu.AppendMenu(wx.ID_ANY, text, imp)
304 else:
305 self.Bind(wx.EVT_MENU, method, id=menu_item.GetId())
306 menu.Append(menu_item)
307 mid += 1
308 self.PopupMenu(menu)
309 menu.Destroy()
310
312 self._delete_selected_events()
313
324
325 def user_ack():
326 if number_of_selected_events > 1:
327 text = _("Are you sure you want to delete %d events?" %
328 number_of_selected_events)
329 else:
330 text = _("Are you sure you want to delete this event?")
331 return _ask_question(text) == wx.YES
332 safe_locking(self._edit_controller, edit_function)
333
335 self.open_event_editor(self.timeline_canvas.GetSelectedEvent())
336
338 open_duplicate_event_dialog_for_event(
339 self._edit_controller,
340 self,
341 self.timeline_canvas.GetDb(),
342 self.timeline_canvas.GetSelectedEvent())
343
344
346 def edit_function():
347 with self.timeline_canvas.GetDb().transaction("Mark events done"):
348 for event in self.timeline_canvas.GetSelectedEvents():
349 if not event.is_container():
350 event.set_progress(100)
351 event.save()
352 self.timeline_canvas.ClearSelectedEvents()
353 safe_locking(self._edit_controller, edit_function)
354
356
357
358 set_category_on_selected = getattr(self.main_frame, 'set_category_on_selected', None)
359 if callable(set_category_on_selected):
360 set_category_on_selected()
361
363 self.timeline_canvas.SetEventStickyBalloon(self.timeline_canvas.GetSelectedEvent(), True)
364
366 hyperlinks = self.timeline_canvas.GetSelectedEvent().get_data("hyperlink")
367 hyperlink = hyperlinks.split(";")[evt.Id]
368 webbrowser.open(hyperlink)
369
373
380
382 hsizer = wx.BoxSizer(wx.HORIZONTAL)
383 hsizer.Add(self.splitter, proportion=1, flag=wx.EXPAND)
384 hsizer.Add(self.divider_line_slider, proportion=0, flag=wx.EXPAND)
385 vsizer = wx.BoxSizer(wx.VERTICAL)
386 vsizer.Add(self.tool_bar, proportion=0, flag=wx.EXPAND)
387 vsizer.Add(self.message_bar, proportion=0, flag=wx.EXPAND)
388 vsizer.Add(hsizer, proportion=1, flag=wx.EXPAND)
389 self.SetSizer(vsizer)
390
391
393
394 - def __init__(self, parent, config, status_bar_adapter, main_frame):
401
405
407 return self.timeline_canvas
408
411
422
430
432 self.timeline_canvas.Redraw()
433
435 return self.timeline_canvas.Navigate(navigation_fn)
436
439
442
447
450
454
466
467
516