1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import wx
20
21 from timelinelib.calendar.bosparanian.bosparanian import BosparanianDateTime, is_valid_time
22 from timelinelib.calendar.bosparanian.dateformatter import BosparanianDateFormatter
23 from timelinelib.calendar.bosparanian.time import BosparanianDelta
24 from timelinelib.calendar.bosparanian.timetype import BosparanianTimeType
25
26
28
29 - def __init__(self, parent, show_time=True, config=None, on_change=None):
37
43
49
51 self.time_picker.Show(show)
52 self.GetSizer().Layout()
53
59
62
64 self.date_picker = BosparanianDatePicker(self, on_change)
65 self.time_picker = BosparanianTimePicker(self, on_change)
66
67 sizer = wx.BoxSizer(wx.HORIZONTAL)
68 sizer.Add(self.date_picker, proportion=1,
69 flag=wx.ALIGN_CENTER_VERTICAL)
70 sizer.Add(self.time_picker, proportion=0,
71 flag=wx.ALIGN_CENTER_VERTICAL)
72 self.SetSizerAndFit(sizer)
73
74
76
77 - def __init__(self, date_picker, time_picker, now_fn):
78 self.date_picker = date_picker
79 self.time_picker = time_picker
80 self.now_fn = now_fn
81
83 if self.time_picker.IsShown():
84 hour, minute, second = self.time_picker.get_value()
85 else:
86 hour, minute, second = (0, 0, 0)
87 year, month, day = self.date_picker.get_value()
88 return BosparanianDateTime(year, month, day, hour, minute, second).to_time()
89
95
96
130 self.Bind(wx.EVT_KILL_FOCUS, on_kill_focus)
131 def on_char(evt):
132 if evt.GetKeyCode() == wx.WXK_TAB:
133 if evt.ShiftDown():
134 skip = self.controller.on_shift_tab()
135 else:
136 skip = self.controller.on_tab()
137 else:
138 skip = True
139 evt.Skip(skip)
140 self.Bind(wx.EVT_CHAR, on_char)
141 def on_text(evt):
142 self.controller.on_text_changed()
143 self.Bind(wx.EVT_TEXT, on_text)
144 def on_key_down(evt):
145 if evt.GetKeyCode() == wx.WXK_UP:
146 self.controller.on_up()
147 elif evt.GetKeyCode() == wx.WXK_DOWN:
148 self.controller.on_down()
149 elif (evt.GetKeyCode() == wx.WXK_NUMPAD_ENTER or
150 evt.GetKeyCode() == wx.WXK_RETURN):
151 self.parent.on_return()
152 elif (evt.GetKeyCode() == wx.WXK_ESCAPE):
153 self.parent.on_escape()
154 else:
155 evt.Skip()
156 self.Bind(wx.EVT_KEY_DOWN, on_key_down)
157
159 w, _ = self.GetTextExtent("0000BF-MMM-00")
160 width = w + 20
161 self.SetMinSize((width, -1))
162
163
165
166 - def __init__(self, date_picker, error_bg="pink", on_change=None):
167 self.date_picker = date_picker
168 self.error_bg = error_bg
169 self.original_bg = self.date_picker.GetBackgroundColour()
170 self.date_formatter = BosparanianDateFormatter()
171 self.separator = self.date_formatter.separator()
172 self.region_year, self.region_month, self.region_day = self.date_formatter.get_regions()
173 self.region_siblings = ((self.region_year, self.region_month),
174 (self.region_month, self.region_day))
175 self.preferred_day = None
176 self.save_preferred_day = True
177 self.last_selection = None
178 self.on_change = on_change
179
181 try:
182 (year, month, day) = self._parse_year_month_day()
183 self._ensure_within_allowed_period((year, month, day))
184 return (year, month, day)
185 except ValueError:
186 raise ValueError("Invalid date.")
187
189 year, month, day = value
190 date_string = self.date_formatter.format(year, month, day)
191 self.date_picker.set_date_string(date_string)
192 self._on_change()
193
195 if self._current_date_is_valid() and not self.on_change is None:
196 self.on_change()
197
199 if self.last_selection:
200 start, end = self.last_selection
201 self.date_picker.SetSelection(start, end)
202 else:
203 self._select_region_if_possible(self.region_year)
204 self.last_selection = self.date_picker.GetSelection()
205
207 if self.last_selection:
208 self.last_selection = self.date_picker.GetSelection()
209
211 for (left_region, right_region) in self.region_siblings:
212 if self._insertion_point_in_region(left_region):
213 self._select_region_if_possible(right_region)
214 return False
215 return True
216
218 for (left_region, right_region) in self.region_siblings:
219 if self._insertion_point_in_region(right_region):
220 self._select_region_if_possible(left_region)
221 return False
222 return True
223
224 - def on_text_changed(self):
225 self._change_background_depending_on_date_validity()
226 if self._current_date_is_valid():
227 current_date = self.get_value()
228
229
230
231
232
233
234 if self.save_preferred_day:
235 self._save_preferred_day(current_date)
236 self._on_change()
237
245 def increment_month(date):
246 year, month, day = date
247 if month < 13:
248 return self._set_valid_day(year, month + 1, day)
249 elif year < max_year - 1:
250 return self._set_valid_day(year + 1, 1, day)
251 return date
252 def increment_day(date):
253 year, month, day = date
254 time = BosparanianDateTime.from_ymd(year, month, day).to_time()
255 if time < BosparanianTimeType().get_max_time() - BosparanianDelta.from_days(1):
256 return BosparanianDateTime.from_time(time + BosparanianDelta.from_days(1)).to_date_tuple()
257 return date
258 if not self._current_date_is_valid():
259 return
260 selection = self.date_picker.GetSelection()
261 current_date = self.get_value()
262 if self._insertion_point_in_region(self.region_year):
263 new_date = increment_year(current_date)
264 elif self._insertion_point_in_region(self.region_month):
265 new_date = increment_month(current_date)
266 else:
267 new_date = increment_day(current_date)
268 self._save_preferred_day(new_date)
269 if current_date != new_date:
270 self._set_new_date_and_restore_selection(new_date, selection)
271 self._on_change()
272
279 def decrement_month(date):
280 year, month, day = date
281 if month > 1:
282 return self._set_valid_day(year, month - 1, day)
283 elif year > BosparanianDateTime.from_time(BosparanianTimeType().get_min_time()).year:
284 return self._set_valid_day(year - 1, 13, day)
285 return date
286 def decrement_day(date):
287 year, month, day = date
288 if day > 1:
289 return self._set_valid_day(year, month, day - 1)
290 elif month > 1:
291 return self._set_valid_day(year, month - 1, 30)
292 elif year > BosparanianDateTime.from_time(BosparanianTimeType().get_min_time()).year:
293 return self._set_valid_day(year - 1, 13, 5)
294 return date
295 if not self._current_date_is_valid():
296 return
297 selection = self.date_picker.GetSelection()
298 current_date = self.get_value()
299 if self._insertion_point_in_region(self.region_year):
300 new_date = decrement_year(current_date)
301 elif self._insertion_point_in_region(self.region_month):
302 new_date = decrement_month(current_date)
303 else:
304 year, month, day = current_date
305 BosparanianDateTime.from_ymd(year, month, day)
306 if BosparanianDateTime.from_ymd(year, month, day).to_time() == BosparanianTimeType().get_min_time():
307 return
308 new_date = decrement_day(current_date)
309 self._save_preferred_day(new_date)
310 if current_date != new_date:
311 self._set_new_date_and_restore_selection(new_date, selection)
312 self._on_change()
313
321
324
331
333 def restore_selection(selection):
334 self.date_picker.SetSelection(selection[0], selection[1])
335 self.save_preferred_day = False
336 if self.preferred_day is not None:
337 year, month, _ = new_date
338 new_date = self._set_valid_day(year, month, self.preferred_day)
339 self.set_value(new_date)
340 restore_selection(selection)
341 self.save_preferred_day = True
342
352
354 _, _, day = date
355 if day > 28:
356 self.preferred_day = day
357 else:
358 self.preferred_day = None
359
361 try:
362 self.get_value()
363 except ValueError:
364 return False
365 return True
366
368 region_range = self._get_region_range(region)
369 if region_range:
370 self.date_picker.SetSelection(region_range[0], region_range[-1])
371
373 region_range = self._get_region_range(n)
374 if region_range:
375 return self.date_picker.GetInsertionPoint() in region_range
376
378
379
380 def region_is_not_valid(region):
381 return region not in (self.region_year, self.region_month,
382 self.region_day)
383 def date_has_exactly_two_seperators(datestring):
384 return len(datestring.split(self.separator)) == 3
385 def calculate_pos_range(region, datestring):
386 pos_of_separator1 = datestring.find(self.separator)
387 pos_of_separator2 = datestring.find(self.separator,
388 pos_of_separator1 + 1)
389 if region == self.region_year:
390 return range(0, pos_of_separator1 + 1)
391 elif region == self.region_month:
392 return range(pos_of_separator1 + 1, pos_of_separator2 + 1)
393 else:
394 return range(pos_of_separator2 + 1, len(datestring) + 1)
395 if region_is_not_valid(n):
396 return None
397 date = self.date_picker.get_date_string()
398 if not date_has_exactly_two_seperators(date):
399 return None
400 pos_range = calculate_pos_range(n, date)
401 return pos_range
402
403
436 self.Bind(wx.EVT_KILL_FOCUS, on_kill_focus)
437 def on_char(evt):
438 if evt.GetKeyCode() == wx.WXK_TAB:
439 if evt.ShiftDown():
440 skip = self.controller.on_shift_tab()
441 else:
442 skip = self.controller.on_tab()
443 else:
444 skip = True
445 evt.Skip(skip)
446 self.Bind(wx.EVT_CHAR, on_char)
447 def on_text(evt):
448 self.controller.on_text_changed()
449 self.Bind(wx.EVT_TEXT, on_text)
450 def on_key_down(evt):
451 if evt.GetKeyCode() == wx.WXK_UP:
452 self.controller.on_up()
453 elif evt.GetKeyCode() == wx.WXK_DOWN:
454 self.controller.on_down()
455 elif (evt.GetKeyCode() == wx.WXK_NUMPAD_ENTER or
456 evt.GetKeyCode() == wx.WXK_RETURN):
457 self.parent.on_return()
458 elif (evt.GetKeyCode() == wx.WXK_ESCAPE):
459 self.parent.on_escape()
460 else:
461 evt.Skip()
462 self.Bind(wx.EVT_KEY_DOWN, on_key_down)
463
465 w, _ = self.GetTextExtent("00:00")
466 width = w + 20
467 self.SetMinSize((width, -1))
468
469
471
472 - def __init__(self, time_picker, on_change):
473 self.time_picker = time_picker
474 self.original_bg = self.time_picker.GetBackgroundColour()
475 self.separator = ":"
476 self.hour_part = 0
477 self.minute_part = 1
478 self.last_selection = None
479 self.on_change = on_change
480
482 try:
483 split = self.time_picker._get_time_string().split(self.separator)
484 if len(split) != 2:
485 raise ValueError()
486 hour_string, minute_string = split
487 hour = int(hour_string)
488 minute = int(minute_string)
489 if not is_valid_time(hour, minute, 0):
490 raise ValueError()
491 return (hour, minute, 0)
492 except ValueError:
493 raise ValueError("Invalid time.")
494
500
502 if self._time_is_valid() and not self.on_change is None:
503 self.on_change()
504
506 if self.last_selection:
507 start, end = self.last_selection
508 self.time_picker.SetSelection(start, end)
509 else:
510 self._select_part(self.hour_part)
511
514
516 if self._in_minute_part():
517 return True
518 self._select_part(self.minute_part)
519 return False
520
522 if self._in_hour_part():
523 return True
524 self._select_part(self.hour_part)
525 return False
526
527 - def on_text_changed(self):
528 try:
529 self.get_value()
530 self.time_picker.SetBackgroundColour(self.original_bg)
531 except ValueError:
532 self.time_picker.SetBackgroundColour("pink")
533 self.time_picker.Refresh()
534
536 def increment_hour(time):
537 hour, minute, second = time
538 new_hour = hour + 1
539 if new_hour > 23:
540 new_hour = 0
541 return (new_hour, minute, second)
542 def increment_minutes(time):
543 hour, minute, second = time
544 new_hour = hour
545 new_minute = minute + 1
546 if new_minute > 59:
547 new_minute = 0
548 new_hour = hour + 1
549 if new_hour > 23:
550 new_hour = 0
551 return (new_hour, new_minute, second)
552 if not self._time_is_valid():
553 return
554 selection = self.time_picker.GetSelection()
555 current_time = self.get_value()
556 if self._in_hour_part():
557 new_time = increment_hour(current_time)
558 else:
559 new_time = increment_minutes(current_time)
560 if current_time != new_time:
561 self._set_new_time_and_restore_selection(new_time, selection)
562 self._on_change()
563
565 def decrement_hour(time):
566 hour, minute, second = time
567 new_hour = hour - 1
568 if new_hour < 0:
569 new_hour = 23
570 return (new_hour, minute, second)
571 def decrement_minutes(time):
572 hour, minute, second = time
573 new_hour = hour
574 new_minute = minute - 1
575 if new_minute < 0:
576 new_minute = 59
577 new_hour = hour - 1
578 if new_hour < 0:
579 new_hour = 23
580 return (new_hour, new_minute, second)
581 if not self._time_is_valid():
582 return
583 selection = self.time_picker.GetSelection()
584 current_time = self.get_value()
585 if self._in_hour_part():
586 new_time = decrement_hour(current_time)
587 else:
588 new_time = decrement_minutes(current_time)
589 if current_time != new_time:
590 self._set_new_time_and_restore_selection(new_time, selection)
591 self._on_change()
592
594 def restore_selection(selection):
595 self.time_picker.SetSelection(selection[0], selection[1])
596 self.set_value(new_time)
597 restore_selection(selection)
598
600 try:
601 self.get_value()
602 except ValueError:
603 return False
604 return True
605
607 if self._separator_pos() == -1:
608 return
609 if part == self.hour_part:
610 self.time_picker.SetSelection(0, self._separator_pos())
611 else:
612 time_string_len = len(self.time_picker._get_time_string())
613 self.time_picker.SetSelection(self._separator_pos() + 1, time_string_len)
614 self.preferred_part = part
615
617 if self._separator_pos() == -1:
618 return
619 return self.time_picker.GetInsertionPoint() <= self._separator_pos()
620
622 if self._separator_pos() == -1:
623 return
624 return self.time_picker.GetInsertionPoint() > self._separator_pos()
625
627 return self.time_picker._get_time_string().find(self.separator)
628