# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline. If not, see <http://www.gnu.org/licenses/>.
import wx
from timelinelib.canvas.data import Event
from timelinelib.canvas.data import Subevent
from timelinelib.canvas.data import TimePeriod
from timelinelib.features.experimental.experimentalfeatures import EXTENDED_CONTAINER_STRATEGY
from timelinelib.utils import ex_msg
from timelinelib.wxgui.framework import Controller
[docs]class EditEventDialogController(Controller):
[docs] def on_init(self, config, time_type, event_repository, timeline, start, end, event):
self.config = config
self.timeline = timeline
self.time_type = time_type
self.event_repository = event_repository
self._set_values(start, end, event)
self.view.SetFocusOnFirstControl()
[docs] def on_locked_checkbox_changed(self, event):
self._enable_disable_ends_today()
[docs] def on_container_changed(self, event):
self._enable_disable_ends_today()
self._enable_disable_locked(EXTENDED_CONTAINER_STRATEGY.enabled())
[docs] def on_enlarge_click(self, event):
self.reduced_size = self.view.GetSize()
self.reduced_pos = self.view.GetPosition()
screen_width, screen_height = wx.DisplaySize()
dialog_size = (screen_width * 0.9, screen_height * 0.8)
dialog_pos = (screen_width * 0.05, screen_height * 0.05)
self._set_position_and_size(dialog_pos, dialog_size)
[docs] def on_reduce_click(self, event):
self._set_position_and_size(self.reduced_pos, self.reduced_size)
[docs] def on_ok_clicked(self, event):
self._create_or_update_event()
[docs] def on_duplicate(self, evt):
self._create_or_update_event()
if self._done:
self._duplicate_event()
def _duplicate_event(self):
dlg = self.view.GetDuplicateEventDialog(self.timeline, self.event)
dlg.ShowModal()
dlg.Destroy()
def _create_or_update_event(self):
try:
with self.timeline.transaction("Save event"):
self._save_event()
if self.view.IsAddMoreChecked():
self.event = None
self.view.SetName("")
self.view.ClearEventData()
self.view.SetFocusOnFirstControl()
self._done = False
else:
if self.opened_from_menu:
self.config.event_editor_show_period = self.view.GetShowPeriod()
self.config.event_editor_show_time = self.view.GetShowTime()
self.view.EndModalOk()
self._done = True
except ValueError:
self._done = True
def _set_values(self, start, end, event):
self.event = event
self.opened_from_menu = self.event is None and start is None
if self.event is None:
self._set_period_in_view(start, end)
self.view.SetName("")
self.view.SetCategory(None)
self.view.SetFuzzyStart(False)
self.view.SetFuzzyEnd(False)
self.view.SetLocked(False)
self.view.SetEndsToday(False)
self.view.SetContainer(None)
self.view.SetShowAddMoreCheckbox(True)
else:
self._set_period_in_view(
self.event.get_time_period().start_time,
self.event.get_time_period().end_time
)
self.view.SetName(self.event.get_text())
self.view.SetCategory(self.event.get_category())
self.view.SetFuzzyStart(self.event.fuzzy_start)
self.view.SetFuzzyEnd(self.event.fuzzy_end)
self.view.SetLocked(self.event.get_locked())
self.view.SetEndsToday(self.event.get_ends_today())
self.view.SetEventData(self.event.data)
if self.event.is_subevent():
self.view.SetContainer(self.event.container)
else:
self.view.SetContainer(None)
self.view.SetShowAddMoreCheckbox(False)
def _set_period_in_view(self, start, end):
self.view.SetPeriod(self._get_period(start, end))
if self.event:
pass
else:
if self.opened_from_menu:
self.view.SetShowPeriod(self.config.event_editor_show_period)
self.view.SetShowTime(self.config.event_editor_show_time)
else:
pass
if self.config.never_use_time:
self.view.DisableTime()
elif self.event is None and self.config.uncheck_time_for_new_events:
self.view.SetShowTime(False)
def _get_period(self, start, end):
if start is None and end is None:
time = self.time_type.now()
return TimePeriod(time, time)
elif end is None:
return TimePeriod(start, start)
else:
return TimePeriod(start, end)
def _get_period_from_view(self):
try:
period = self.view.GetPeriod()
except ValueError as ex:
self.view.DisplayInvalidPeriod("%s" % ex_msg(ex))
raise ValueError()
(start, end) = (period.get_start_time(), period.get_end_time())
if self.event is not None and self.view.GetLocked():
self._verify_that_time_has_not_been_changed(start, end)
end = self._adjust_end_if_ends_today(start, end)
TimePeriod(start, end)
return (start, end)
def _verify_that_time_has_not_been_changed(self, start, end):
original_start = self.event.get_start_time()
original_end = self.event.get_end_time()
if (original_start != start or
(not self.view.GetEndsToday() and original_end != end)):
self.view.SetPeriod(self.event.get_time_period())
error_message = _("You can't change time when the Event is locked")
self.view.DisplayInvalidPeriod(error_message)
raise ValueError()
def _save_event(self):
if self.event is None:
self._create_new_event()
else:
self._update_event()
self.event.data = self.view.GetEventData()
self._save_event_to_db()
def _update_event(self):
container_selected = (self.view.GetContainer() is not None)
if container_selected:
self._update_event_when_container_selected()
else:
self._update_event_when_container_not_selected()
def _update_event_when_container_selected(self):
if self.event.is_subevent():
self._update_event_when_container_selected_and_event_is_subevent()
else:
self._add_event_to_container()
def _update_event_when_container_selected_and_event_is_subevent(self):
if self.event.container == self.view.GetContainer():
(start, end) = self._get_period_from_view()
self.event.update(
start,
end,
self.view.GetName(),
self.view.GetCategory(),
self.view.GetFuzzy(),
self.view.GetLocked(),
self.view.GetEndsToday(),
self.view.GetFuzzyStart(),
self.view.GetFuzzyEnd(),
)
else:
self._change_container()
def _update_event_when_container_not_selected(self):
if self.event.is_subevent():
self._remove_event_from_container()
else:
(start, end) = self._get_period_from_view()
self.event.update(
start,
end,
self.view.GetName(),
self.view.GetCategory(),
self.view.GetFuzzy(),
self.view.GetLocked(),
self.view.GetEndsToday(),
self.view.GetFuzzyStart(),
self.view.GetFuzzyEnd(),
)
def _remove_event_from_container(self):
self.event.container = None
if self.event.id is not None:
self.timeline.delete_event(self.event)
self._create_new_event()
def _add_event_to_container(self):
self.timeline.delete_event(self.event)
self._create_subevent()
def _change_container(self):
if self._is_new_container(self.view.GetContainer()):
self._add_new_container()
self._remove_event_from_container()
self.event.container = self.view.GetContainer()
def _create_new_event(self):
if self.view.GetContainer() is not None:
self._create_subevent()
else:
(start, end) = self._get_period_from_view()
self.event = Event().update(
start,
end,
self.view.GetName(),
self.view.GetCategory(),
self.view.GetFuzzy(),
self.view.GetLocked(),
self.view.GetEndsToday(),
self.view.GetFuzzyStart(),
self.view.GetFuzzyEnd(),
)
def _create_subevent(self):
if self._is_new_container(self.view.GetContainer()):
self._add_new_container()
(start, end) = self._get_period_from_view()
self.event = Subevent().update(
start,
end,
self.view.GetName(),
self.view.GetCategory(),
ends_today=self.view.GetEndsToday()
)
self.event.container = self.view.GetContainer()
def _is_new_container(self, container):
return container not in self.timeline.get_containers()
def _add_new_container(self):
self._save_container_to_db()
def _adjust_end_if_ends_today(self, start, end):
if self.view.GetEndsToday():
end_time = self.time_type.now()
else:
end_time = end
if end_time < start:
self.view.DisplayInvalidPeriod(_("End must be > Start"))
raise ValueError()
return end_time
def _save_event_to_db(self):
self.event_repository.save(self.event)
def _save_container_to_db(self):
self.event_repository.save(self.view.GetContainer())
def _enable_disable_ends_today(self):
enable = ((self._container_not_selected() or self._container_allows_ends_today()) and
not self.view.GetLocked() and
self._start_is_in_history())
self.view.EnableEndsToday(enable)
def _enable_disable_locked(self, extended_container_strategy_enabled):
if self.event is not None and extended_container_strategy_enabled:
enable = not self.event.is_container()
else:
enable = self._container_not_selected()
self.view.EnableLocked(enable)
def _container_not_selected(self):
return self.view.GetContainer() is None
def _container_allows_ends_today(self):
container = self.view.GetContainer()
if container is None:
return True
else:
return container.allow_ends_today_on_subevents()
def _start_is_in_history(self):
if self.event is None:
return True
if self.event.get_start_time() is None:
return False
return self.event.get_start_time() < self.time_type.now()
def _set_position_and_size(self, pos, size):
self.view.SetPosition(pos)
self.view.SetSize(size)