3
# Copyright (C) 2008-2009 Toms Bauģis <toms.baugis at gmail.com>
5
# This file is part of Project Hamster.
7
# Project Hamster is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
12
# Project Hamster is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
20
from .hamster.stuff import format_duration
27
class TimeInput(gtk.Entry):
29
'time-entered': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
33
def __init__(self, time = None, start_time = None):
34
gtk.Entry.__init__(self)
36
self.start_time = start_time
39
self.set_width_chars(7) #7 is like 11:24pm
45
self.popup = gtk.Window(type = gtk.WINDOW_POPUP)
46
time_box = gtk.ScrolledWindow()
47
time_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
48
time_box.set_shadow_type(gtk.SHADOW_IN)
50
self.time_tree = gtk.TreeView()
51
self.time_tree.set_headers_visible(False)
52
self.time_tree.set_hover_selection(True)
54
self.time_tree.append_column(gtk.TreeViewColumn("Time",
55
gtk.CellRendererText(),
57
self.time_tree.connect("button-press-event",
58
self._on_time_tree_button_press_event)
60
time_box.add(self.time_tree)
61
self.popup.add(time_box)
63
self.connect("button-press-event", self._on_button_press_event)
64
self.connect("key-press-event", self._on_key_press_event)
65
self.connect("focus-in-event", self._on_focus_in_event)
66
self.connect("focus-out-event", self._on_focus_out_event)
67
self.connect("changed", self._on_text_changed)
71
def set_start_time(self, start_time):
72
""" set the start time. when start time is set, drop down list
73
will start from start time and duration will be displayed in
76
self.start_time = start_time
78
def set_time(self, time):
80
self.set_text(self._format_time(time))
82
def _on_text_changed(self, widget):
85
def figure_time(self, str_time):
89
# strip everything non-numeric and consider hours to be first number
90
# and minutes - second number
91
numbers = re.split("\D", str_time)
92
numbers = filter(lambda x: x!="", numbers)
94
hours, minutes = None, None
96
if len(numbers) == 1 and len(numbers[0]) == 4:
97
hours, minutes = int(numbers[0][:2]), int(numbers[0][2:])
100
hours = int(numbers[0])
101
if len(numbers) >= 2:
102
minutes = int(numbers[1])
104
if (hours is None or minutes is None) or hours > 24 or minutes > 60:
105
return self.time #no can do
107
return dt.datetime.now().replace(hour = hours, minute = minutes,
108
second = 0, microsecond = 0)
111
def _select_time(self, time_text):
112
#convert forth and back so we have text formated as we want
113
time = self.figure_time(time_text)
114
time_text = self._format_time(time)
116
self.set_text(time_text)
117
self.set_position(len(time_text))
120
self.emit("time-entered")
124
self.time = self.figure_time(self.get_text())
125
self.set_text(self._format_time(self.time))
128
def _format_time(self, time):
132
#return time.strftime("%I:%M%p").lstrip("0").lower()
133
return time.strftime("%H:%M").lower()
136
def _on_focus_in_event(self, entry, event):
139
def _on_button_press_event(self, button, event):
142
def _on_focus_out_event(self, event, something):
145
self.emit("time-entered")
149
def show_popup(self):
150
focus_time = self.figure_time(self.get_text())
152
hours = gtk.ListStore(gobject.TYPE_STRING)
155
i_time = self.start_time or dt.datetime(1900, 1, 1, 0, 0)
157
if focus_time and focus_time < i_time:
158
focus_time += dt.timedelta(days = 1)
161
end_time = i_time + dt.timedelta(hours = 12)
162
i_time += dt.timedelta(minutes = 15)
164
end_time = i_time + dt.timedelta(hours = 24)
166
i, focus_row = 0, None
168
while i_time < end_time:
169
row_text = self._format_time(i_time)
171
delta = (i_time - self.start_time).seconds / 60
172
delta_text = format_duration(delta)
174
row_text += " (%s)" % delta_text
176
hours.append([row_text])
178
if focus_time and i_time <= focus_time <= i_time + \
179
dt.timedelta(minutes = 30):
183
i_time += dt.timedelta(minutes = 15)
185
i_time += dt.timedelta(minutes = 30)
189
self.time_tree.set_model(hours)
192
if focus_row != None:
193
self.time_tree.set_cursor(focus_row)
194
self.time_tree.scroll_to_cell(focus_row, use_align = True, row_align = 0.4)
196
#move popup under the widget
197
alloc = self.get_allocation()
201
self.time_tree.set_size_request(w, alloc.height * 5)
203
window = self.get_parent_window()
204
x, y= window.get_origin()
206
self.popup.move(x + alloc.x,y + alloc.y + alloc.height)
207
self.popup.show_all()
210
def _on_time_tree_button_press_event(self, tree, event):
211
model, iter = tree.get_selection().get_selected()
212
time = model.get_value(iter, 0)
213
self._select_time(time)
216
def _on_key_press_event(self, entry, event):
217
cursor = self.time_tree.get_cursor()
219
if not cursor or not cursor[0]:
224
if event.keyval == gtk.keysyms.Up:
226
elif event.keyval == gtk.keysyms.Down:
228
elif (event.keyval == gtk.keysyms.Return or
229
event.keyval == gtk.keysyms.KP_Enter):
231
if self.popup.get_property("visible"):
232
self._select_time(self.time_tree.get_model()[i][0])
234
self._select_time(entry.get_text())
235
elif (event.keyval == gtk.keysyms.Escape):
238
#any kind of other input
242
# keep it in the sane borders
243
i = min(max(i, 0), len(self.time_tree.get_model()) - 1)
245
self.time_tree.set_cursor(i)
246
self.time_tree.scroll_to_cell(i, use_align = True, row_align = 0.4)