[hamster-applet] moved time input widget also to widgets
- From: Toms Baugis <tbaugis src gnome org>
- To: svn-commits-list gnome org
- Subject: [hamster-applet] moved time input widget also to widgets
- Date: Sat, 25 Apr 2009 15:36:02 -0400 (EDT)
commit a17270c8a320836453312794a9fd6e1328b081e7
Author: Toms Bauģis <toms baugis gmail com>
Date: Sat Apr 25 20:17:31 2009 +0100
moved time input widget also to widgets
---
data/edit_activity.ui | 57 ++---------
hamster/edit_activity.py | 242 ++++++-------------------------------------
hamster/widgets.py | 260 +++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 287 insertions(+), 272 deletions(-)
diff --git a/data/edit_activity.ui b/data/edit_activity.ui
index 1363638..bdb5fea 100644
--- a/data/edit_activity.ui
+++ b/data/edit_activity.ui
@@ -91,14 +91,11 @@
</packing>
</child>
<child>
- <object class="GtkEntry" id="start_time">
+ <object class="GtkAlignment" id="start_time_placeholder">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="width_chars">7</property>
- <signal name="button_press_event" handler="on_time_button_press_event"/>
- <signal name="key_press_event" handler="on_time_key_press_event"/>
- <signal name="focus_out_event" handler="on_start_time_focus_out_event"/>
- <signal name="focus_in_event" handler="on_start_time_focus_in_event"/>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="position">1</property>
@@ -124,14 +121,11 @@
<property name="visible">True</property>
<property name="spacing">4</property>
<child>
- <object class="GtkEntry" id="end_time">
+ <object class="GtkAlignment" id="end_time_placeholder">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="width_chars">7</property>
- <signal name="button_press_event" handler="on_time_button_press_event"/>
- <signal name="key_press_event" handler="on_time_key_press_event"/>
- <signal name="focus_out_event" handler="on_end_time_focus_out_event"/>
- <signal name="focus_in_event" handler="on_end_time_focus_in_event"/>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="position">0</property>
@@ -300,39 +294,4 @@
</object>
</child>
</object>
- <object class="GtkWindow" id="calendar_window">
- <property name="type">popup</property>
- <property name="resizable">False</property>
- <property name="window_position">center-on-parent</property>
- <child>
- <object class="GtkAlignment" id="calendar_box">
- <property name="visible">True</property>
- <child>
- <placeholder/>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkWindow" id="time_window">
- <property name="type">popup</property>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="time_tree">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="headers_visible">False</property>
- <property name="enable_search">False</property>
- <property name="hover_selection">True</property>
- <property name="show_expanders">False</property>
- <signal name="button_press_event" handler="on_time_tree_button_press_event"/>
- </object>
- </child>
- </object>
- </child>
- </object>
</interface>
diff --git a/hamster/edit_activity.py b/hamster/edit_activity.py
index 60084ab..4fa660e 100644
--- a/hamster/edit_activity.py
+++ b/hamster/edit_activity.py
@@ -24,7 +24,6 @@ pygtk.require('2.0')
import os
import gtk
import gobject
-import re
from hamster import dispatcher, storage, SHARED_DATA_DIR, stuff
from hamster import graphics, widgets
@@ -355,13 +354,23 @@ class CustomFactController:
end_date = end_date or start_date + dt.timedelta(minutes = 30)
- self.start_date = widgets.DateInput()
- self.start_date.connect("date-entered", self.validate_fields)
+ self.start_date = widgets.DateInput(start_date)
self.get_widget("start_date_placeholder").add(self.start_date)
- self.end_date = widgets.DateInput()
+ self.start_date.connect("date-entered", self.validate_fields)
+
+ self.end_date = widgets.DateInput(end_date)
self.get_widget("end_date_placeholder").add(self.end_date)
self.end_date.connect("date-entered", self.validate_fields)
+ self.start_time = widgets.TimeInput(start_date)
+ self.get_widget("start_time_placeholder").add(self.start_time)
+ self.start_time.connect("time-entered", self.on_start_time_entered)
+
+ self.end_time = widgets.TimeInput(end_date, start_date)
+ self.get_widget("end_time_placeholder").add(self.end_time)
+ self.end_time.connect("time-entered", self.on_end_time_entered)
+
+
self.set_dropdown()
self.refresh_menu()
@@ -370,19 +379,13 @@ class CustomFactController:
self.dayline.on_more_data = storage.get_facts
self._gui.get_object("day_preview").add(self.dayline)
- self.update_time(start_date, end_date)
-
self.on_in_progress_toggled(self.get_widget("in_progress"))
-
- self.init_time_window()
-
self._gui.connect_signals(self)
def update_time(self, start_time, end_time):
- self.get_widget("start_time").set_text(self.format_time(start_time))
+ self.start_time.set_time(start_time)
self.start_date.set_date(start_time)
-
- self.get_widget("end_time").set_text(self.format_time(end_time))
+ self.end_time.set_time(end_time)
self.end_date.set_date(end_time)
@@ -391,42 +394,6 @@ class CustomFactController:
self.dayline.draw(day_facts, highlight)
- def init_time_window(self):
- self.time_window = self._gui.get_object('time_window')
- self.time_tree = self.get_widget('time_tree')
- self.time_tree.append_column(gtk.TreeViewColumn("Time", gtk.CellRendererText(), text=0))
-
- def on_time_button_press_event(self, button, event):
- if self.time_window.get_property("visible"):
- self.time_window.hide()
-
-
- def figure_time(self, str_time):
- # strip everything non-numeric and consider hours to be first number
- # and minutes - second number
- numbers = re.split("\D", str_time)
- numbers = filter(lambda x: x!="", numbers)
- hours, minutes = None, None
-
- if len(numbers) >= 1:
- hours = int(numbers[0])
-
- if len(numbers) >= 2:
- minutes = int(numbers[1])
-
- if (hours == None and minutes == None) or hours > 24 or minutes > 60:
- return None #no can do
-
- """ this breaks 24 hour mode, when hours are given
- #if hours specified in 12 hour mode, default to PM
- #TODO - laame, show me how to do this better, pleease
- am = dt.time(1, 00).strftime("%p")
- if hours <= 11 and str_time.find(am) < 0:
- hours += 12
- """
-
- return dt.datetime(1900, 1, 1, hours, minutes)
-
def set_dropdown(self):
# set up drop down menu
@@ -524,7 +491,7 @@ class CustomFactController:
def _get_datetime(self, prefix):
# adds symbolic time to date in seconds
date = getattr(self, prefix + '_date').get_date()
- time = self.figure_time(self.get_widget(prefix + '_time').get_text())
+ time = getattr(self, prefix + '_time').get_time()
if time and date:
return dt.datetime.combine(date, time.time())
@@ -589,178 +556,31 @@ class CustomFactController:
if event.keyval == gtk.keysyms.Tab:
event.keyval = gtk.keysyms.Down
return False
-
- def on_start_time_focus_in_event(self, entry, event):
- self.show_time_window(entry)
-
- def on_start_time_focus_out_event(self, event, something):
- self.time_window.hide()
- self.validate_fields()
- def on_end_time_focus_in_event(self, entry, event):
- start_time = self.figure_time(self.get_widget("start_time").get_text())
- self.show_time_window(entry, start_time)
-
- def on_end_time_focus_out_event(self, event, something):
- self.time_window.hide()
- self.validate_fields()
-
def on_in_progress_toggled(self, check):
- self.get_widget("end_time").set_sensitive(not check.get_active())
+ self.end_time.set_sensitive(not check.get_active())
self.end_date.set_sensitive(not check.get_active())
self.validate_fields()
- def show_time_window(self, widget, start_time = None):
-
- focus_time = self.figure_time(widget.get_text())
-
- hours = gtk.ListStore(gobject.TYPE_STRING)
-
- # populate times
- i_time = start_time or dt.datetime(1900, 1, 1, 0, 0)
-
- if focus_time and focus_time < i_time:
- focus_time += dt.timedelta(days = 1)
-
- if start_time:
- end_time = i_time + dt.timedelta(hours = 12)
- else:
- end_time = i_time + dt.timedelta(hours = 24)
-
- i, focus_row = 0, None
- while i_time < end_time:
- if start_time:
- i_time += dt.timedelta(minutes = 15)
- else:
- i_time += dt.timedelta(minutes = 30)
-
- row_text = self.format_time(i_time)
- if start_time:
- delta = (i_time - start_time).seconds / 60
- delta_text = stuff.format_duration(delta)
-
- row_text += " (%s)" % delta_text
-
- hours.append([row_text])
-
-
- if focus_time and i_time <= focus_time <= i_time + dt.timedelta(minutes = 30):
- focus_row = i
-
- i += 1
-
-
-
-
- self.time_tree.set_model(hours)
-
-
- #focus on row
- if focus_row != None:
- self.time_tree.set_cursor(focus_row)
- self.time_tree.scroll_to_cell(focus_row, use_align = True, row_align = 0.4)
-
-
-
- #move popup under the widget
- alloc = widget.get_allocation()
- w = alloc.width
- if start_time:
- w = w * 2
- self.time_tree.set_size_request(w, alloc.height * 5)
-
- window = widget.get_parent_window()
- x, y= window.get_origin()
-
- self.time_window.move(x + alloc.x,y + alloc.y + alloc.height)
- self.time_window.show_all()
-
-
- def format_time(self, time):
- if time == None:
- return None
-
- #return time.strftime("%I:%M%p").lstrip("0").lower()
- return time.strftime("%H:%M").lower()
-
- def set_time(self, time_text):
- #convert forth and back so we have text formated as we want
- time = self.figure_time(time_text)
- time_text = self.format_time(time)
-
- widget = None
- if self.get_widget("start_time").is_focus():
- widget = self.get_widget("start_time")
- self.get_widget("end_time") \
- .set_text(self.format_time(time + dt.timedelta(minutes=30))) #set also end time on start time change
-
-
- elif self.get_widget("end_time").is_focus():
- start_datetime = self._get_datetime("start")
- start_time = self.figure_time(self.get_widget("start_time").get_text())
- delta = abs(time - start_time)
-
- end_date = start_datetime + delta
- self.end_date.set_date(end_date)
-
- widget = self.get_widget("end_time")
-
- if widget:
- widget.set_text(time_text)
-
- widget.set_position(len(time_text))
- self.time_window.hide()
- self.validate_fields()
-
-
-
- def on_time_tree_button_press_event(self, tree, event):
- model, iter = tree.get_selection().get_selected()
- time = model.get_value(iter, 0)
- self.set_time(time)
-
-
- def on_time_key_press_event(self, entry, event):
- if not self.time_tree.get_cursor():
- return
-
- i = self.time_tree.get_cursor()[0][0]
-
- if event.keyval == gtk.keysyms.Up:
- i-=1
- elif event.keyval == gtk.keysyms.Down:
- i+=1
- elif (event.keyval == gtk.keysyms.Return or
- event.keyval == gtk.keysyms.KP_Enter):
-
- if self.time_window.get_property("visible"):
- self.set_time(self.time_tree.get_model()[i][0])
- else:
- self.set_time(entry.get_text())
- elif (event.keyval == gtk.keysyms.Escape):
- self.time_window.hide()
- else:
- #any kind of other input
- self.time_window.hide()
- return False
-
- # keep it in the sane borders
- i = min(max(i, 0), len(self.time_tree.get_model()) - 1)
-
- self.time_tree.set_cursor(i)
- self.time_tree.scroll_to_cell(i, use_align = True, row_align = 0.4)
- return True
-
-
def on_cancel_clicked(self, button):
self.close_window()
def on_activity_combo_changed(self, combo):
self.validate_fields()
- def validate_fields(self, event = None):
- # do not allow empty tasks
-
+ def on_start_time_entered(self, widget):
+ self.end_time.set_time(self.start_time.get_time() +
+ dt.timedelta(minutes = 30))
+ self.end_time.set_start_time(self.start_time.get_time())
+ self.validate_fields()
+
+ def on_end_time_entered(self, widget):
+ if self.end_time.get_time() < self.start_time.get_time():
+ self.end_date.set_date(self.start_date.get_date() +
+ dt.timedelta(days=1))
+ self.validate_fields()
+
+ def validate_fields(self, widget = None):
activity_text = self.get_widget("activity_combo").child.get_text()
start_time = self._get_datetime("start")
@@ -776,7 +596,7 @@ class CustomFactController:
self.update_time(start_time, end_time)
self.validate_fields()
return
-
+
looks_good = False
if activity_text != "" and start_time and end_time and \
(end_time - start_time).days == 0:
diff --git a/hamster/widgets.py b/hamster/widgets.py
index 0f4df3c..7a2c7ab 100644
--- a/hamster/widgets.py
+++ b/hamster/widgets.py
@@ -17,11 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
-
+from hamster.stuff import format_duration
import gtk
import datetime as dt
import calendar
import gobject
+import re
+
class DateInput(gtk.Entry):
""" a text entry widget with calendar popup"""
@@ -30,19 +32,24 @@ class DateInput(gtk.Entry):
}
- def __init__(self):
+ def __init__(self, date = None):
gtk.Entry.__init__(self)
-
+
+ self.set_width_chars(12) #12 is enough for 12-oct-2009, which is verbose
+ if date:
+ self.set_date(date)
+
+ self.news = False
self.prev_cal_day = None #workaround
self.calendar_window = gtk.Window(type = gtk.WINDOW_POPUP)
calendar_box = gtk.HBox()
-
-
+
self.date_calendar = gtk.Calendar()
-
self.date_calendar.connect("day-selected", self._on_day_selected)
- self.date_calendar.connect("day-selected-double-click", self.__on_day_selected_double_click)
- self.date_calendar.connect("button-press-event", self._on_cal_button_press_event)
+ self.date_calendar.connect("day-selected-double-click",
+ self.__on_day_selected_double_click)
+ self.date_calendar.connect("button-press-event",
+ self._on_cal_button_press_event)
calendar_box.add(self.date_calendar)
self.calendar_window.add(calendar_box)
@@ -50,6 +57,7 @@ class DateInput(gtk.Entry):
self.connect("key-press-event", self._on_key_press_event)
self.connect("focus-in-event", self._on_focus_in_event)
self.connect("focus-out-event", self._on_focus_out_event)
+ self.connect("changed", self._on_text_changed)
self.show()
def set_date(self, date):
@@ -72,6 +80,9 @@ class DateInput(gtk.Entry):
else:
return date.strftime("%x")
+ def _on_text_changed(self, widget):
+ self.news = True
+
def _on_button_press_event(self, button, event):
if self.calendar_window.get_property("visible"):
self.calendar_window.hide()
@@ -96,8 +107,10 @@ class DateInput(gtk.Entry):
self.set_text(self._format_date(date))
- self.calendar_window.hide()
- self.emit("date-entered")
+ self.calendar_window.hide()
+ if self.news:
+ self.emit("date-entered")
+ self.news = False
def _on_focus_in_event(self, entry, event):
@@ -117,7 +130,9 @@ class DateInput(gtk.Entry):
def _on_focus_out_event(self, event, something):
self.calendar_window.hide()
- self.emit("date-entered")
+ if self.news:
+ self.emit("date-entered")
+ self.news = False
def _on_key_press_event(self, entry, event):
if self.calendar_window.get_property("visible"):
@@ -148,8 +163,229 @@ class DateInput(gtk.Entry):
if enter_pressed:
self.prev_cal_day = "borken"
else:
- self.prev_cal_day = date.day #prev_cal_day is our only way of checking that date is right
+ #prev_cal_day is our only way of checking that date is right
+ self.prev_cal_day = date.day
self.date_calendar.select_month(date.month, date.year)
self.date_calendar.select_day(date.day)
return True
+
+
+class TimeInput(gtk.Entry):
+ __gsignals__ = {
+ 'time-entered': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+ }
+
+
+ def __init__(self, time = None, start_time = None):
+ gtk.Entry.__init__(self)
+
+ self.start_time = start_time
+ self.news = False
+
+ self.set_width_chars(7) #7 is like 11:24pm
+ if time:
+ self.set_time(time)
+
+
+ self.time_window = gtk.Window(type = gtk.WINDOW_POPUP)
+ time_box = gtk.ScrolledWindow()
+ time_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+
+ self.time_tree = gtk.TreeView()
+ self.time_tree.set_headers_visible(False)
+ self.time_tree.set_hover_selection(True)
+
+ self.time_tree.append_column(gtk.TreeViewColumn("Time",
+ gtk.CellRendererText(),
+ text=0))
+ self.time_tree.connect("button-press-event",
+ self._on_time_tree_button_press_event)
+
+ time_box.add(self.time_tree)
+ self.time_window.add(time_box)
+
+ self.connect("button-press-event", self._on_button_press_event)
+ self.connect("key-press-event", self._on_key_press_event)
+ self.connect("focus-in-event", self._on_focus_in_event)
+ self.connect("focus-out-event", self._on_focus_out_event)
+ self.connect("changed", self._on_text_changed)
+ self.show()
+
+
+ def set_start_time(self, start_time):
+ """ set the start time. when start time is set, drop down list
+ will start from start time and duration will be displayed in
+ brackets
+ """
+ self.start_time = start_time
+
+ def set_time(self, time):
+ self.set_text(self._format_time(time))
+
+ def _on_text_changed(self, widget):
+ self.news = True
+
+ def _select_time(self, time_text):
+ #convert forth and back so we have text formated as we want
+ time = self.figure_time(time_text)
+ time_text = self._format_time(time)
+
+ self.set_text(time_text)
+ self.set_position(len(time_text))
+ self.time_window.hide()
+ if self.news:
+ self.emit("time-entered")
+ self.news = False
+
+ def get_time(self):
+ return self.figure_time(self.get_text())
+
+ def _format_time(self, time):
+ if time == None:
+ return None
+
+ #return time.strftime("%I:%M%p").lstrip("0").lower()
+ return time.strftime("%H:%M").lower()
+
+
+ def _on_focus_in_event(self, entry, event):
+ self.show_time_window()
+
+ def _on_focus_out_event(self, event, something):
+ self.time_window.hide()
+ if self.news:
+ self.emit("time-entered")
+ self.news = False
+
+
+ def show_time_window(self):
+ focus_time = self.figure_time(self.get_text())
+
+ hours = gtk.ListStore(gobject.TYPE_STRING)
+
+ # populate times
+ i_time = self.start_time or dt.datetime(1900, 1, 1, 0, 0)
+
+ if focus_time and focus_time < i_time:
+ focus_time += dt.timedelta(days = 1)
+
+ if self.start_time:
+ end_time = i_time + dt.timedelta(hours = 12)
+ else:
+ end_time = i_time + dt.timedelta(hours = 24)
+
+ i, focus_row = 0, None
+ while i_time < end_time:
+ if self.start_time:
+ i_time += dt.timedelta(minutes = 15)
+ else:
+ i_time += dt.timedelta(minutes = 30)
+
+ row_text = self._format_time(i_time)
+ if self.start_time:
+ delta = (i_time - self.start_time).seconds / 60
+ delta_text = format_duration(delta)
+
+ row_text += " (%s)" % delta_text
+
+ hours.append([row_text])
+
+
+ if focus_time and i_time <= focus_time <= i_time + dt.timedelta(minutes = 30):
+ focus_row = i
+
+ i += 1
+
+ self.time_tree.set_model(hours)
+
+ #focus on row
+ if focus_row != None:
+ self.time_tree.set_cursor(focus_row)
+ self.time_tree.scroll_to_cell(focus_row, use_align = True, row_align = 0.4)
+
+ #move popup under the widget
+ alloc = self.get_allocation()
+ w = alloc.width
+ if self.start_time:
+ w = w * 2
+ self.time_tree.set_size_request(w, alloc.height * 5)
+
+ window = self.get_parent_window()
+ x, y= window.get_origin()
+
+ self.time_window.move(x + alloc.x,y + alloc.y + alloc.height)
+ self.time_window.show_all()
+
+
+ def _on_time_tree_button_press_event(self, tree, event):
+ model, iter = tree.get_selection().get_selected()
+ time = model.get_value(iter, 0)
+ self._select_time(time)
+
+
+ def _on_key_press_event(self, entry, event):
+ if not self.time_tree.get_cursor():
+ return
+
+ i = self.time_tree.get_cursor()[0][0]
+
+ if event.keyval == gtk.keysyms.Up:
+ i-=1
+ elif event.keyval == gtk.keysyms.Down:
+ i+=1
+ elif (event.keyval == gtk.keysyms.Return or
+ event.keyval == gtk.keysyms.KP_Enter):
+
+ if self.time_window.get_property("visible"):
+ self._select_time(self.time_tree.get_model()[i][0])
+ else:
+ self._select_time(entry.get_text())
+ elif (event.keyval == gtk.keysyms.Escape):
+ self.time_window.hide()
+ else:
+ #any kind of other input
+ self.time_window.hide()
+ return False
+
+ # keep it in the sane borders
+ i = min(max(i, 0), len(self.time_tree.get_model()) - 1)
+
+ self.time_tree.set_cursor(i)
+ self.time_tree.scroll_to_cell(i, use_align = True, row_align = 0.4)
+ return True
+
+
+ def _on_button_press_event(self, button, event):
+ if self.time_window.get_property("visible"):
+ self.time_window.hide()
+
+
+ def figure_time(self, str_time):
+ # strip everything non-numeric and consider hours to be first number
+ # and minutes - second number
+ numbers = re.split("\D", str_time)
+ numbers = filter(lambda x: x!="", numbers)
+ hours, minutes = None, None
+
+ if len(numbers) >= 1:
+ hours = int(numbers[0])
+
+ if len(numbers) >= 2:
+ minutes = int(numbers[1])
+
+ if (hours == None and minutes == None) or hours > 24 or minutes > 60:
+ return None #no can do
+
+ """ this breaks 24 hour mode, when hours are given
+ #if hours specified in 12 hour mode, default to PM
+ #TODO - laame, show me how to do this better, pleease
+ am = dt.time(1, 00).strftime("%p")
+ if hours <= 11 and str_time.find(am) < 0:
+ hours += 12
+ """
+
+ return dt.datetime(1900, 1, 1, hours, minutes)
+
+
+
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]