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.encodings import to_unicode
28 from timelinelib.general.observer import Listener
29 from timelinelib.wxgui.components.maincanvas.createperiodeventbydrag import CreatePeriodEventByDragInputHandler
30 from timelinelib.wxgui.components.maincanvas.maincanvas import MainCanvas
31 from timelinelib.wxgui.components.maincanvas.movebydrag import MoveByDragInputHandler
32 from timelinelib.wxgui.components.maincanvas.noop import NoOpInputHandler
33 from timelinelib.wxgui.components.maincanvas.resizebydrag import ResizeByDragInputHandler
34 from timelinelib.wxgui.components.maincanvas.scrollbydrag import ScrollByDragInputHandler
35 from timelinelib.wxgui.components.maincanvas.zoombydrag import ZoomByDragInputHandler
36 from timelinelib.wxgui.components.maincanvas.selectevents import SelectEventsInputHandler
37 from timelinelib.wxgui.components.messagebar import MessageBar
38 from timelinelib.wxgui.components.sidebar import Sidebar
39 from timelinelib.wxgui.dialogs.duplicateevent.view import open_duplicate_event_dialog_for_event
40 from timelinelib.wxgui.dialogs.editevent.view import open_create_event_editor
41 from timelinelib.wxgui.dialogs.editevent.view import open_event_editor_for
42 from timelinelib.wxgui.dialogs.milestone.view import open_milestone_editor_for
43 from timelinelib.wxgui.frames.mainframe.toolbar import ToolbarCreator
44 from timelinelib.wxgui.utils import _ask_question
45 from timelinelib.config.paths import ICONS_DIR
46 from timelinelib.wxgui.cursor import Cursor
47
48
49 LEFT_RIGHT_SCROLL_FACTOR = 1 / 200.0
50
51
53
58
61
64
66 self._create_toolbar()
67 self._create_warning_bar()
68 self._create_divider_line_slider()
69 self._create_splitter()
70 self._layout_components()
71
74
77
79
80 def on_slider(evt):
81 self.config.divider_line_slider_pos = evt.GetPosition()
82
83 style = wx.SL_LEFT | wx.SL_VERTICAL
84 self.divider_line_slider = wx.Slider(self, size=(20, -1), style=style)
85 self.Bind(wx.EVT_SCROLL, on_slider, self.divider_line_slider)
86
87 self.divider_line_slider.Bind(wx.EVT_SLIDER, self._slider_on_slider)
88 self.divider_line_slider.Bind(wx.EVT_CONTEXT_MENU, self._slider_on_context_menu)
89
92
94 menu = wx.Menu()
95 menu_item = wx.MenuItem(menu, wx.NewId(), _("Center"))
96 self.Bind(wx.EVT_MENU, self._context_menu_on_menu_center, id=menu_item.GetId())
97 menu.AppendItem(menu_item)
98 self.PopupMenu(menu)
99 menu.Destroy()
100
102 self.timeline_canvas.SetDividerPosition(50)
103
105 self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
106 self.splitter.SetMinimumPaneSize(50)
107 self.Bind(
108 wx.EVT_SPLITTER_SASH_POS_CHANGED,
109 self._splitter_on_splitter_sash_pos_changed, self.splitter)
110 self._create_sidebar()
111 self._create_timeline_canvas()
112 self.splitter.Initialize(self.timeline_canvas)
113
115 if self.IsShown():
116 self.sidebar_width = self.splitter.GetSashPosition()
117
120
122 self.timeline_canvas = MainCanvas(
123 self.splitter, self._edit_controller, self.status_bar_adapter)
124 self.timeline_canvas.Bind(
125 wx.EVT_LEFT_DCLICK,
126 self._timeline_canvas_on_double_clicked
127 )
128 self.timeline_canvas.Bind(
129 wx.EVT_RIGHT_DOWN,
130 self._timeline_canvas_on_right_down
131 )
132 self.timeline_canvas.Bind(
133 wx.EVT_KEY_DOWN,
134 self._timeline_canvas_on_key_down
135 )
136 self.timeline_canvas.Bind(
137 EVT_DIVIDER_POSITION_CHANGED,
138 self._timeline_canvas_on_divider_position_changed
139 )
140 self.timeline_canvas.Bind(
141 EVT_TIMELINE_REDRAWN,
142 self._timeline_canvas_on_timeline_redrawn
143 )
144 self.timeline_canvas.SetDividerPosition(self.config.divider_line_slider_pos)
145 self.timeline_canvas.SetEventBoxDrawer(self._get_saved_event_box_drawer())
146 self.timeline_canvas.SetInputHandler(NoOpInputHandler(
147 InputHandlerState(
148 self.timeline_canvas, self.status_bar_adapter,
149 self._edit_controller, self.config),
150 self.timeline_canvas))
151
152 def update_appearance():
153 appearance = self.timeline_canvas.GetAppearance()
154 appearance.set_legend_visible(self.config.show_legend)
155 appearance.set_balloons_visible(self.config.balloon_on_hover)
156 appearance.set_hide_events_done(self.config.hide_events_done)
157 appearance.set_minor_strip_divider_line_colour(self.config.minor_strip_divider_line_colour)
158 appearance.set_major_strip_divider_line_colour(self.config.major_strip_divider_line_colour)
159 appearance.set_now_line_colour(self.config.now_line_colour)
160 appearance.set_weekend_colour(self.config.weekend_colour)
161 appearance.set_bg_colour(self.config.bg_colour)
162 appearance.set_colorize_weekends(self.config.colorize_weekends)
163 appearance.set_draw_period_events_to_right(self.config.draw_point_events_to_right)
164 appearance.set_text_below_icon(self.config.text_below_icon)
165 appearance.set_minor_strip_font(self.config.minor_strip_font)
166 appearance.set_major_strip_font(self.config.major_strip_font)
167 appearance.set_balloon_font(self.config.balloon_font)
168 appearance.set_legend_font(self.config.legend_font)
169 appearance.set_center_event_texts(self.config.center_event_texts)
170 appearance.set_never_show_period_events_as_point_events(self.config.never_show_period_events_as_point_events)
171 appearance.set_week_start(self.config.get_week_start())
172 appearance.set_use_inertial_scrolling(self.config.use_inertial_scrolling)
173 appearance.set_fuzzy_icon(self.config.fuzzy_icon)
174 appearance.set_locked_icon(self.config.locked_icon)
175 appearance.set_hyperlink_icon(self.config.hyperlink_icon)
176 appearance.set_vertical_space_between_events(self.config.vertical_space_between_events)
177 appearance.set_skip_s_in_decade_text(self.config.skip_s_in_decade_text)
178 appearance.set_display_checkmark_on_events_done(self.config.display_checkmark_on_events_done)
179 appearance.set_never_use_time(self.config.never_use_time)
180 appearance.set_legend_pos(self.config.legend_pos)
181 self.config.listen_for_any(update_appearance)
182 update_appearance()
183
190
211
223
237
239 self._try_move_event_vertically(True)
240
242 self._try_move_event_vertically(False)
243
248
271 safe_locking(self._edit_controller, edit_function)
272
274 menu_definitions = [
275 (_("Delete"), self._context_menu_on_delete_event, None),
276 ]
277 nbr_of_selected_events = len(self.timeline_canvas.GetSelectedEvents())
278 if nbr_of_selected_events == 1:
279 menu_definitions.insert(0, (_("Edit"), self._context_menu_on_edit_event, None))
280 menu_definitions.insert(1, (_("Duplicate..."), self._context_menu_on_duplicate_event, None))
281 menu_definitions.append((_("Mark Event as Done"), self._context_menu_on_done_event, None))
282 menu_definitions.append((_("Select Category..."), self._context_menu_on_select_category, None))
283 if nbr_of_selected_events == 1 and self.timeline_canvas.GetSelectedEvent().has_data():
284 menu_definitions.append((_("Sticky Balloon"), self._context_menu_on_sticky_balloon_event, None))
285 if nbr_of_selected_events == 1:
286 hyperlinks = self.timeline_canvas.GetSelectedEvent().get_data("hyperlink")
287 if hyperlinks is not None:
288 imp = wx.Menu()
289 menuid = 0
290 for hyperlink in hyperlinks.split(";"):
291 imp.Append(menuid, hyperlink)
292 menuid += 1
293 menu_definitions.append((_("Goto URL"), self._context_menu_on_goto_hyperlink_event, imp))
294 menu = wx.Menu()
295 mid = 0
296 for menu_definition in menu_definitions:
297 text, method, imp = menu_definition
298 menu_item = wx.MenuItem(menu, mid, text)
299 if imp is not None:
300 for menu_item in imp.GetMenuItems():
301 self.Bind(wx.EVT_MENU, method, id=menu_item.GetId())
302 menu.AppendMenu(wx.ID_ANY, text, imp)
303 else:
304 self.Bind(wx.EVT_MENU, method, id=menu_item.GetId())
305 menu.AppendItem(menu_item)
306 mid += 1
307 self.PopupMenu(menu)
308 menu.Destroy()
309
311 self._delete_selected_events()
312
323
324 def user_ack():
325 if number_of_selected_events > 1:
326 text = _("Are you sure you want to delete %d events?" %
327 number_of_selected_events)
328 else:
329 text = _("Are you sure you want to delete this event?")
330 return _ask_question(text) == wx.YES
331 safe_locking(self._edit_controller, edit_function)
332
334 self.open_event_editor(self.timeline_canvas.GetSelectedEvent())
335
337 open_duplicate_event_dialog_for_event(
338 self._edit_controller,
339 self,
340 self.timeline_canvas.GetDb(),
341 self.timeline_canvas.GetSelectedEvent())
342
343
345 def edit_function():
346 with self.timeline_canvas.GetDb().transaction("Mark events done"):
347 for event in self.timeline_canvas.GetSelectedEvents():
348 if not event.is_container():
349 event.set_progress(100)
350 event.save()
351 self.timeline_canvas.ClearSelectedEvents()
352 safe_locking(self._edit_controller, edit_function)
353
355
356
357 set_category_on_selected = getattr(self.main_frame, 'set_category_on_selected', None)
358 if callable(set_category_on_selected):
359 set_category_on_selected()
360
362 self.timeline_canvas.SetEventStickyBalloon(self.timeline_canvas.GetSelectedEvent(), True)
363
365 hyperlinks = self.timeline_canvas.GetSelectedEvent().get_data("hyperlink")
366 hyperlink = hyperlinks.split(";")[evt.Id]
367 webbrowser.open(to_unicode(hyperlink))
368
372
379
381 hsizer = wx.BoxSizer(wx.HORIZONTAL)
382 hsizer.Add(self.splitter, proportion=1, flag=wx.EXPAND)
383 hsizer.Add(self.divider_line_slider, proportion=0, flag=wx.EXPAND)
384 vsizer = wx.BoxSizer(wx.VERTICAL)
385 vsizer.Add(self.tool_bar, proportion=0, flag=wx.EXPAND)
386 vsizer.Add(self.message_bar, proportion=0, flag=wx.EXPAND)
387 vsizer.Add(hsizer, proportion=1, flag=wx.EXPAND)
388 self.SetSizer(vsizer)
389
390
392
393 - def __init__(self, parent, config, status_bar_adapter, main_frame):
400
404
406 return self.timeline_canvas
407
410
418
426
428 self.timeline_canvas.Redraw()
429
431 return self.timeline_canvas.Navigate(navigation_fn)
432
435
438
443
446
450
462
463
512