Start development series 2.1-post
[memo.git] / Window.py
blob433092e50da8f12a783df652d11fca2a9aa8ac5c
1 import rox
2 from rox import g, TRUE, FALSE, app_options
3 from rox.Menu import Menu
4 from rox.options import Option
5 import gobject
7 from MenuWindow import MenuWindow
8 import dbus_notify
9 import pretty_time, time
10 import timer
11 from Alarm import Alarm
13 time_format = Option('time_format', 'text')
14 main_sticky = Option('main_sticky', 1)
15 alert_early = Option('alert_early', 0)
17 class Window(rox.Window, MenuWindow):
18 drag_start = None
20 def __init__(self, memo_list):
21 rox.Window.__init__(self)
22 MenuWindow.__init__(self)
23 self.set_wmclass('Memo', 'Memo')
24 self.set_title('Memo')
25 self.set_resizable(False)
26 if hasattr(self, 'set_deletable'):
27 self.set_deletable(False)
28 #self.set_type_hint(g.gdk.WINDOW_TYPE_HINT_DIALOG)
30 self.tips = g.Tooltips()
32 if main_sticky.int_value:
33 self.stick()
35 self.memo_list = memo_list
36 self.last_day = None
37 self.prime_in_progress = False
39 vbox = g.VBox(FALSE, 0)
40 self.add(vbox)
42 hbox = g.HBox(False, 0)
43 vbox.pack_start(hbox, expand = False)
45 self.time_label = g.Label('')
46 self.time_button = g.Button()
47 self.time_button.add(self.time_label)
48 self.time_button.unset_flags(g.CAN_FOCUS)
49 hbox.pack_start(self.time_button, expand = True)
51 hbox.pack_start(timer.TimerButton(), expand = False)
53 self.list = g.TreeView(memo_list.visible)
54 vbox.pack_start(self.list, expand = TRUE)
55 self.list.unset_flags(g.CAN_FOCUS)
57 cell = g.CellRendererText()
58 column = g.TreeViewColumn('Time', cell, text = 0)
59 cell.set_property('xalign', 1)
60 self.list.append_column(column)
62 cell = g.CellRendererText()
63 column = g.TreeViewColumn('Message', cell, text = 1)
64 self.list.append_column(column)
66 self.list.set_headers_visible(FALSE)
68 sel = self.list.get_selection()
69 sel.set_mode(g.SELECTION_NONE)
71 def activate(view, path, column):
72 memo = memo_list.visible.get_memo_by_path(path)
73 from EditBox import EditBox
74 EditBox(memo).show()
76 self.add_events(g.gdk.BUTTON_PRESS_MASK)
77 self.list.connect('button-press-event', self.button_press)
78 self.list.connect('row-activated', activate)
79 self.time_button.add_events(g.gdk.BUTTON1_MOTION_MASK)
80 self.time_button.connect('button-press-event', self.button_press)
81 self.time_button.connect('motion-notify-event', self.button_motion)
82 self.time_button.connect('clicked', self.time_button_clicked)
84 self.update()
85 gobject.timeout_add(10000, self.update) # Update clock
87 self.timeout = None # For next alarm
88 self.alert_box = None
89 self.show_all_box = None
90 self.save_box = None
91 self.prime()
93 # If we had more than one window, we'd need a remove too...
94 memo_list.connect("MemoListChanged", self.prime)
95 app_options.add_notify(self.options_changed)
97 vbox.show_all()
99 def time_button_clicked(self, widget):
100 ev = g.get_current_event()
101 if ev.type == g.gdk.MOTION_NOTIFY and self.drag_start:
102 # Fake release from motion handler
103 self.begin_move_drag(1, self.drag_start[0], self.drag_start[1], ev.time)
104 self.drag_start = None
105 else:
106 self.new_memo()
108 def options_changed(self):
109 if time_format.has_changed:
110 self.update()
112 if main_sticky.int_value:
113 self.stick()
114 else:
115 self.unstick()
117 def update(self):
118 if time_format.value == 'text':
119 text = pretty_time.rough_time(time.time())
120 self.tips.set_tip(self.time_button,
121 time.strftime('%H:%M %a %Y-%m-%d'))
122 else:
123 # Note: importing gtk breaks strftime for am/pm
124 text = time.strftime('%a %d-%b-%Y ') + \
125 pretty_time.str_time()
126 self.tips.set_tip(self.time_button, None)
127 self.time_label.set_text(text)
129 t = time.localtime()
130 year, month, day, hour, minute, second, weekday, julian, dst = t
131 if self.last_day != day:
132 if self.last_day is not None:
133 self.memo_list.new_day()
134 self.last_day = day
136 return TRUE
138 def button_press(self, widget, event):
139 if event.type != g.gdk.BUTTON_PRESS:
140 return
141 elif event.button == 2 or event.button == 3:
142 self.popup_menu(event)
143 return 1
144 self.drag_start = map(int, (event.x_root, event.y_root))
145 return 0
147 def button_motion(self, widget, mev):
148 if self.drag_start is None: return
149 pos = map(int, (mev.x_root, mev.y_root))
150 if self.time_button.drag_check_threshold(*(self.drag_start + pos)):
151 self.time_button.released()
152 if self.drag_start:
153 # Release event was ignored (outside the button)
154 self.time_button_clicked(widget)
156 # Deal with any missed alarms
157 # Set a timeout for the next alarm
158 def prime(self, memo_list = None):
159 if self.alert_box:
160 return # Don't do anything until closed
162 if self.prime_in_progress:
163 return # Make this method atomic
164 else:
165 self.prime_in_progress = True
167 missed, delay = self.memo_list.catch_up( alert_early.int_value )
168 if missed:
169 if dbus_notify.is_available():
170 for m in missed:
171 dbus_notify.notify(m)
172 else:
173 # Show the first one.
174 self.alert_box = Alarm(missed[0])
175 def destroyed(widget):
176 self.alert_box = None
177 self.prime()
178 self.alert_box.connect('destroy', destroyed)
179 g.gdk.beep()
180 g.gdk.flush()
181 time.sleep(0.3)
182 g.gdk.beep()
183 g.gdk.flush()
184 time.sleep(1)
185 self.alert_box.show()
186 if delay:
187 self.schedule(delay)
188 self.prime_in_progress = False
190 def timeout_cb(self):
191 gobject.source_remove(self.timeout)
192 self.timeout = 0
193 self.prime()
194 return 0
196 def schedule(self, delay):
197 if self.timeout:
198 gobject.source_remove(self.timeout)
200 # Avoid overflows - don't resched more than a day ahead
201 if delay > 60 * 60 * 24:
202 delay = 60 * 60 * 24
204 self.timeout = gobject.timeout_add(int(1000 * delay), self.timeout_cb)