~cmiller/+junk/notify-friends-contacts

« back to all changes in this revision

Viewing changes to ui/widgets/date_entry.py

  • Committer: Chad MILLER
  • Date: 2010-07-03 23:18:35 UTC
  • mfrom: (2.1.2 contacts_sync)
  • Revision ID: cmiller@hypatia-20100703231835-jqd5pmqcrlfb3avg
Merge Mandel's ui code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import gobject
 
2
import gtk
 
3
from gtk import gdk
 
4
import time
 
5
import datetime
 
6
import logging
 
7
 
 
8
 
 
9
(DATE_EDIT_SHOW_TIME,
 
10
 DATE_EDIT_24_HR,
 
11
 DATE_EDIT_WEEK_STARTS_ON_MONDAY) = [1 << 0, 1 << 1, 1 << 2]
 
12
 
 
13
(DATE_CHANGED,
 
14
 TIME_CHANGED) = [1 << 0, 1 << 1]
 
15
 
 
16
logger = logging.getLogger("macaco.ui.widgets.date_entry")
 
17
 
 
18
class DateEntry(gtk.HBox):
 
19
 
 
20
    ###########################################################################
 
21
    ################################ class vars ###############################
 
22
    ###########################################################################
 
23
 
 
24
    __gtype_name__ = 'DateEntry'
 
25
    __gsignals__ = {'time_changed' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
 
26
        (gobject.TYPE_PYOBJECT,)),
 
27
        'date_changed' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
 
28
        (gobject.TYPE_PYOBJECT,))
 
29
    }
 
30
 
 
31
    ###########################################################################
 
32
    ############################### end class vars ############################
 
33
    ###########################################################################
 
34
 
 
35
    def __init__(self, the_time = None, show_time = True, use_24_format = True):
 
36
        """
 
37
        @the_time: date and time to be displayed on the widget
 
38
        @show_time: whether time should be displayed
 
39
        @use_24_format: whether 24-hour format is desired for the time display.
 
40
 
 
41
        Description: Creates a new #GnomeDateEntry widget which can be used
 
42
        to provide an easy to use way for entering dates and times.
 
43
        If @the_time is 0 then current time is used.
 
44
        Returns: a new #GnomeDateEntry widget.
 
45
        """
 
46
 
 
47
        gtk.HBox.__init__(self)
 
48
 
 
49
        # preset values
 
50
        self.__lower_hour = 7;
 
51
        self.__upper_hour = 19;
 
52
        self.__flags = DATE_EDIT_SHOW_TIME
 
53
 
 
54
        # the date entry
 
55
        self.__date_entry = gtk.Entry()
 
56
        self.__date_entry.set_size_request(90, -1)
 
57
        self.pack_start(self.__date_entry, True, True, 0)
 
58
        self.__date_entry.show()
 
59
 
 
60
        # the date button
 
61
        self.__date_button = gtk.Button()
 
62
        self.__date_button.connect('clicked', self.select_clicked)
 
63
        self.pack_start(self.__date_button, False, False, 0)
 
64
        hbox = gtk.HBox(False, 3)
 
65
        self.__date_button.add(hbox)
 
66
        hbox.show()
 
67
        # calendar label, only show if the date editor has a time field
 
68
        self.__cal_label = gtk.Label('Calendar')
 
69
        self.__cal_label.set_alignment(0.0, 0.5)
 
70
        hbox.pack_start(self.__cal_label, True, True, 0)
 
71
        self.__cal_label.show()
 
72
        # the down arrow
 
73
        arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
 
74
        hbox.pack_start(arrow, True, False, 0)
 
75
        arrow.show()
 
76
        # finally show the button
 
77
        self.__date_button.show()
 
78
 
 
79
        # the time entry
 
80
        self.__time_entry = gtk.Entry()
 
81
        self.__time_entry.set_max_length(12)
 
82
        self.__time_entry.set_size_request(88, -1)
 
83
        self.pack_start(self.__time_entry, True, True, 0)
 
84
 
 
85
        # the time popup menu
 
86
        self.__time_popup = gtk.OptionMenu()
 
87
        self.pack_start(self.__time_popup, False, False, 0)
 
88
        self.connect('realize', self.fill_time_popup)
 
89
 
 
90
        if show_time == True:
 
91
            self.__time_entry.show()
 
92
            self.__time_popup.show()
 
93
 
 
94
        # the calendar popup
 
95
        self.__cal_popup = gtk.Window(gtk.WINDOW_POPUP)
 
96
        self.__cal_popup.set_events(self.__cal_popup.get_events() | gdk.KEY_PRESS_MASK)
 
97
        self.__cal_popup.connect('delete_event', self.delete_popup)
 
98
        self.__cal_popup.connect('key_press_event', self.key_press_popup)
 
99
        self.__cal_popup.connect('button_press_event', self.button_press_popup)
 
100
        self.__cal_popup.set_resizable(False) # Todo: Needed?
 
101
        frame = gtk.Frame()
 
102
        frame.set_shadow_type(gtk.SHADOW_OUT)
 
103
        self.__cal_popup.add(frame)
 
104
        frame.show()
 
105
        # the calendar
 
106
        self.__calendar = gtk.Calendar()
 
107
        self.__calendar.display_options(gtk.CALENDAR_SHOW_DAY_NAMES
 
108
                                        | gtk.CALENDAR_SHOW_HEADING)
 
109
        self.__calendar.connect('day-selected', self.day_selected)
 
110
        self.__calendar.connect('day-selected-double-click', self.day_selected_double_click)
 
111
        frame.add(self.__calendar)
 
112
        self.__calendar.show()
 
113
 
 
114
        # set user provided flags, will toggle visibility of some widgets
 
115
        new_flags = 0
 
116
        if show_time is True:
 
117
            new_flags |= DATE_EDIT_SHOW_TIME
 
118
        if use_24_format is True:
 
119
            new_flags |= DATE_EDIT_24_HR
 
120
        self.set_flags(new_flags)
 
121
 
 
122
        # set provided date and time
 
123
        self.set_date_time(the_time)
 
124
 
 
125
 
 
126
    # Changes the display flags on an existing date editor widget
 
127
    def set_flags(self, flags):
 
128
        old_flags = self.__flags
 
129
        self.__flags = flags
 
130
 
 
131
        if (flags & DATE_EDIT_SHOW_TIME) != (old_flags & DATE_EDIT_SHOW_TIME):
 
132
            if flags & DATE_EDIT_SHOW_TIME is True:
 
133
                print 'show'
 
134
                self.__cal_label.show()
 
135
                self.__time_entry.show()
 
136
                self.__time_popup.show()
 
137
            else:
 
138
                print 'hide'
 
139
                self.__cal_label.hide()
 
140
                self.__time_entry.hide()
 
141
                self.__time_popup.hide()
 
142
 
 
143
        if (flags & DATE_EDIT_24_HR) != (old_flags & DATE_EDIT_24_HR):
 
144
            self.fill_time_popup(self)
 
145
 
 
146
        if (flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY) is (old_flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY):
 
147
            if flags & DATE_EDIT_WEEK_STARTS_ON_MONDAY is True:
 
148
                self.__calendar.set_display_options(self.__calendar.get_display_options() | gtk.CALENDAR_WEEK_START_MONDAY)
 
149
            else:
 
150
                self.__calendar.set_display_options(self.__calendar.get_display_options() & ~gtk.CALENDAR_WEEK_START_MONDAY)
 
151
 
 
152
    def set_date_time(self, the_time):
 
153
        if the_time is None:
 
154
            the_time = datetime.datetime.today()
 
155
        assert isinstance(the_time, (datetime.datetime, datetime.date))
 
156
        # set the date
 
157
        self.__initial_time = the_time
 
158
        self.__date_entry.set_text(the_time.strftime('%x'))
 
159
        # set the time
 
160
        if self.__flags & DATE_EDIT_24_HR is True:
 
161
            self.__time_entry.set_text(the_time.strftime('%H:%M'))
 
162
        else:
 
163
            self.__time_entry.set_text(the_time.strftime('%I:%M %p'))
 
164
 
 
165
    def popup_grab_on_window(self, window, activate_time):
 
166
        if gdk.pointer_grab(window, True, gdk.BUTTON_PRESS_MASK
 
167
                                          | gdk.BUTTON_RELEASE_MASK
 
168
                                          | gdk.POINTER_MOTION_MASK,
 
169
                            None, None, activate_time) == 0:
 
170
                if gdk.keyboard_grab (window, True, activate_time) == 0:
 
171
                    return True
 
172
                else:
 
173
                    gdk.pointer_ungrab(activate_time)
 
174
                    return False
 
175
        return False
 
176
 
 
177
    def select_clicked(self, widget, data=None):
 
178
        # Temporarily grab pointer and keyboard on a window we know exists
 
179
        if not self.popup_grab_on_window(widget.window, gtk.get_current_event_time()):
 
180
            print 'error during grab'
 
181
            return
 
182
 
 
183
        # set calendar date
 
184
        str = self.__date_entry.get_text()
 
185
        mtime = time.strptime(str, '%x')
 
186
        self.__calendar.select_month(mtime.tm_mon - 1, mtime.tm_year)
 
187
        self.__calendar.select_day(mtime.tm_mday)
 
188
 
 
189
        # position and show popup window
 
190
        self.position_popup()
 
191
        self.__cal_popup.grab_add()
 
192
        self.__cal_popup.show()
 
193
        self.__calendar.grab_focus()
 
194
 
 
195
        # Now transfer our grabs to the popup window, this should always succed
 
196
        self.popup_grab_on_window(self.__cal_popup.window, gtk.get_current_event_time())
 
197
 
 
198
    def position_popup(self):
 
199
        req = self.__cal_popup.size_request()
 
200
        (x,y) = gdk.Window.get_origin(self.__date_button.window)
 
201
 
 
202
        x += self.__date_button.allocation.x
 
203
        y += self.__date_button.allocation.y
 
204
        bwidth = self.__date_button.allocation.width
 
205
        bheight = self.__date_button.allocation.height
 
206
 
 
207
        x += bwidth - req[0]
 
208
        y += bheight
 
209
 
 
210
        if x < 0: x = 0
 
211
        if y < 0: y = 0
 
212
 
 
213
        self.__cal_popup.move(x,y)
 
214
 
 
215
    def day_selected(self, widget, data=None):
 
216
        (year, month, day) = self.__calendar.get_date()
 
217
        month += 1
 
218
        the_time = datetime.date(year, month, day)
 
219
        self.__date_entry.set_text(the_time.strftime('%x'))
 
220
        self.emit('date_changed', None)
 
221
 
 
222
    def day_selected_double_click(self, widget, data=None):
 
223
        self.hide_popup()
 
224
 
 
225
    def hide_popup(self):
 
226
        self.__cal_popup.hide()
 
227
        self.__cal_popup.grab_remove()
 
228
 
 
229
    def key_press_popup(self, widget, data=None):
 
230
        # Todo, Fixme: what is the name of gdk.Escape? missing?
 
231
        if data == None or data.keyval != 65307:
 
232
            return False
 
233
 
 
234
        # Todo: does not work and what does it do anyway?
 
235
        # widget.stop_emission_by_name('key_press_event')
 
236
        self.hide_popup()
 
237
        return True
 
238
 
 
239
    def button_press_popup(self, widget, data=None):
 
240
        # We don't ask for button press events on the grab widget, so
 
241
        # if an event is reported directly to the grab widget, it must
 
242
        # be on a window outside the application (and thus we remove
 
243
        # the popup window). Otherwise, we check if the widget is a child
 
244
        # of the grab widget, and only remove the popup window if it
 
245
        # is not.
 
246
        if data == None or data.window == None:
 
247
            return False
 
248
 
 
249
        child = data.window.get_user_data()
 
250
        if child != widget:
 
251
            while child:
 
252
                if child == widget:
 
253
                    return False
 
254
                child = child.parent
 
255
 
 
256
        self.hide_popup()
 
257
        return True
 
258
 
 
259
    def delete_popup(self, widget, data=None):
 
260
        # Todo: when is this ever called??
 
261
        print 'delete_popup'
 
262
        hide_popup (gde);
 
263
        return TRUE;
 
264
 
 
265
    def fill_time_popup(self, widget, data=None):
 
266
        if self.__lower_hour > self.__upper_hour:
 
267
            return
 
268
 
 
269
        # create menu
 
270
        menu = gtk.Menu()
 
271
        for i in range(self.__lower_hour, self.__upper_hour + 1):
 
272
            the_time = datetime.time(i, 0)
 
273
 
 
274
            if self.__flags & DATE_EDIT_24_HR is True:
 
275
                label = the_time.strftime('%H:%M')
 
276
            else:
 
277
                label = the_time.strftime('%I:%M %p')
 
278
 
 
279
            item = gtk.MenuItem(label)
 
280
            menu.append(item)
 
281
            item.show()
 
282
 
 
283
            # create submenu
 
284
            submenu = gtk.Menu()
 
285
            item.set_submenu(submenu)
 
286
            for j in range(0,60,15):
 
287
                the_time = datetime.time(i,j)
 
288
 
 
289
                if self.__flags & DATE_EDIT_24_HR is True:
 
290
                    label = the_time.strftime('%H:%M')
 
291
                else:
 
292
                    label = the_time.strftime('%I:%M %p')
 
293
                # create submenu item
 
294
                submenu_item = gtk.MenuItem(label)
 
295
                submenu.append(submenu_item)
 
296
                # add event handler
 
297
                submenu_item.connect('activate', self.time_selected, label)
 
298
                submenu_item.show()
 
299
 
 
300
        # finally replace current menu with this new one
 
301
        self.__time_popup.set_menu(menu)
 
302
 
 
303
    def time_selected(self, widget, data = None):
 
304
        self.__time_entry.set_text(data)
 
305
        self.emit('time_changed', None);
 
306
 
 
307
    def get_date(self):
 
308
        """
 
309
        @rtype: string
 
310
        @return: The currently selected date in the entry.
 
311
 
 
312
        Gets the selected date in the entry.
 
313
        """
 
314
        return self.__date_entry.get_text()
 
315
 
 
316
    def set_date(self, value):
 
317
        """
 
318
        @type value: string
 
319
        @param value: The new date to display in the entry.
 
320
        """
 
321
        self.__date_entry.set_text(value)
 
322
 
 
323
    # Todo: get_properties
 
324
        # PROP_TIME
 
325
        # PROP_DATE_EDIT_FLAGS
 
326
        # PROP_LOWER_HOUR
 
327
        # PROP_UPPER_HOUR
 
328
        # PROP_INITIAL_TIME
 
329
    # Todo: set_properties
 
330
        # PROP_TIME
 
331
        # PROP_DATE_EDIT_FLAGS
 
332
        # PROP_LOWER_HOUR
 
333
        # PROP_UPPER_HOUR