13 @contextlib.contextmanager
15 gtk.gdk.threads_enter()
19 gtk.gdk.threads_leave()
24 Decorator that makes a generator-function into a function that will continue execution on next call
28 @functools.wraps(func)
29 def decorated_func(*args, **kwds):
31 a.append(func(*args, **kwds))
42 def asynchronous_gtk_message(original_func):
44 @note Idea came from http://www.aclevername.com/articles/python-webgui/
48 args, kwargs = allArgs
49 original_func(*args, **kwargs)
51 @functools.wraps(original_func)
52 def delayed_func(*args, **kwargs):
53 gobject.idle_add(execute, (args, kwargs))
58 def synchronous_gtk_message(original_func):
60 @note Idea came from http://www.aclevername.com/articles/python-webgui/
63 @functools.wraps(original_func)
64 def immediate_func(*args, **kwargs):
66 return original_func(*args, **kwargs)
71 class ErrorDisplay(object):
73 def __init__(self, widgetTree):
74 super(ErrorDisplay, self).__init__()
75 self.__errorBox = widgetTree.get_widget("errorEventBox")
76 self.__errorDescription = widgetTree.get_widget("errorDescription")
77 self.__errorClose = widgetTree.get_widget("errorClose")
78 self.__parentBox = self.__errorBox.get_parent()
80 self.__errorBox.connect("button_release_event", self._on_close)
83 self.__parentBox.remove(self.__errorBox)
85 def push_message_with_lock(self, message):
86 gtk.gdk.threads_enter()
88 self.push_message(message)
90 gtk.gdk.threads_leave()
92 def push_message(self, message):
93 if 0 < len(self.__messages):
94 self.__messages.append(message)
96 self.__show_message(message)
98 def push_exception(self, exception = None):
100 userMessage = str(sys.exc_value)
101 warningMessage = str(traceback.format_exc())
103 userMessage = str(exception)
104 warningMessage = str(exception)
105 self.push_message(userMessage)
106 warnings.warn(warningMessage, stacklevel=3)
108 def pop_message(self):
109 if 0 < len(self.__messages):
110 self.__show_message(self.__messages[0])
111 del self.__messages[0]
113 self.__hide_message()
115 def _on_close(self, *args):
118 def __show_message(self, message):
119 self.__errorDescription.set_text(message)
120 self.__parentBox.pack_start(self.__errorBox, False, False)
121 self.__parentBox.reorder_child(self.__errorBox, 1)
123 def __hide_message(self):
124 self.__errorDescription.set_text("")
125 self.__parentBox.remove(self.__errorBox)
128 class DummyErrorDisplay(object):
131 super(DummyErrorDisplay, self).__init__()
135 def push_message_with_lock(self, message):
136 self.push_message(message)
138 def push_message(self, message):
139 if 0 < len(self.__messages):
140 self.__messages.append(message)
142 self.__show_message(message)
144 def push_exception(self, exception = None):
145 if exception is None:
146 warningMessage = traceback.format_exc()
148 warningMessage = exception
149 warnings.warn(warningMessage, stacklevel=3)
151 def pop_message(self):
152 if 0 < len(self.__messages):
153 self.__show_message(self.__messages[0])
154 del self.__messages[0]
156 def __show_message(self, message):
157 warnings.warn(message, stacklevel=2)
160 class MessageBox(gtk.MessageDialog):
162 def __init__(self, message):
164 gtk.MessageDialog.__init__(
167 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
172 self.set_default_response(gtk.RESPONSE_OK)
173 self.connect('response', self._handle_clicked)
175 def _handle_clicked(self, *args):
179 class MessageBox2(gtk.MessageDialog):
181 def __init__(self, message):
183 gtk.MessageDialog.__init__(
186 gtk.DIALOG_DESTROY_WITH_PARENT,
191 self.set_default_response(gtk.RESPONSE_OK)
192 self.connect('response', self._handle_clicked)
194 def _handle_clicked(self, *args):
198 class PopupCalendar(object):
200 def __init__(self, parent, displayDate, title = ""):
201 self._displayDate = displayDate
203 self._calendar = gtk.Calendar()
204 self._calendar.select_month(self._displayDate.month, self._displayDate.year)
205 self._calendar.select_day(self._displayDate.day)
206 self._calendar.set_display_options(
207 gtk.CALENDAR_SHOW_HEADING |
208 gtk.CALENDAR_SHOW_DAY_NAMES |
209 gtk.CALENDAR_NO_MONTH_CHANGE |
212 self._calendar.connect("day-selected", self._on_day_selected)
214 self._popupWindow = gtk.Window()
215 self._popupWindow.set_title(title)
216 self._popupWindow.add(self._calendar)
217 self._popupWindow.set_transient_for(parent)
218 self._popupWindow.set_modal(True)
219 self._popupWindow.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
220 self._popupWindow.set_skip_pager_hint(True)
221 self._popupWindow.set_skip_taskbar_hint(True)
224 self._popupWindow.show_all()
226 def _on_day_selected(self, *args):
228 self._calendar.select_month(self._displayDate.month, self._displayDate.year)
229 self._calendar.select_day(self._displayDate.day)
230 except StandardError, e:
231 warnings.warn(e.message)
234 class QuickAddView(object):
236 def __init__(self, widgetTree, errorDisplay, signalSink, prefix):
237 self._errorDisplay = errorDisplay
239 self._signalSink = signalSink
241 self._clipboard = gtk.clipboard_get()
243 self._taskNameEntry = widgetTree.get_widget(prefix+"-nameEntry")
244 self._addTaskButton = widgetTree.get_widget(prefix+"-addButton")
245 self._pasteTaskNameButton = widgetTree.get_widget(prefix+"-pasteNameButton")
246 self._clearTaskNameButton = widgetTree.get_widget(prefix+"-clearNameButton")
248 self._onAddClickedId = None
249 self._onAddReleasedId = None
250 self._addToEditTimerId = None
251 self._onClearId = None
252 self._onPasteId = None
254 def enable(self, manager):
255 self._manager = manager
257 self._onAddId = self._addTaskButton.connect("clicked", self._on_add)
258 self._onAddClickedId = self._addTaskButton.connect("pressed", self._on_add_pressed)
259 self._onAddReleasedId = self._addTaskButton.connect("released", self._on_add_released)
260 self._onPasteId = self._pasteTaskNameButton.connect("clicked", self._on_paste)
261 self._onClearId = self._clearTaskNameButton.connect("clicked", self._on_clear)
266 self._addTaskButton.disconnect(self._onAddId)
267 self._addTaskButton.disconnect(self._onAddClickedId)
268 self._addTaskButton.disconnect(self._onAddReleasedId)
269 self._pasteTaskNameButton.disconnect(self._onPasteId)
270 self._clearTaskNameButton.disconnect(self._onClearId)
272 def set_addability(self, addability):
273 self._addTaskButton.set_sensitive(addability)
275 def _on_add(self, *args):
277 name = self._taskNameEntry.get_text()
278 self._taskNameEntry.set_text("")
280 self._signalSink.stage.send(("add", name))
281 except StandardError, e:
282 self._errorDisplay.push_exception()
284 def _on_add_edit(self, *args):
286 name = self._taskNameEntry.get_text()
287 self._taskNameEntry.set_text("")
289 self._signalSink.stage.send(("add-edit", name))
290 except StandardError, e:
291 self._errorDisplay.push_exception()
293 def _on_add_pressed(self, widget):
295 self._addToEditTimerId = gobject.timeout_add(1000, self._on_add_edit)
296 except StandardError, e:
297 self._errorDisplay.push_exception()
299 def _on_add_released(self, widget):
301 if self._addToEditTimerId is not None:
302 gobject.source_remove(self._addToEditTimerId)
303 self._addToEditTimerId = None
304 except StandardError, e:
305 self._errorDisplay.push_exception()
307 def _on_paste(self, *args):
309 entry = self._taskNameEntry.get_text()
310 addedText = self._clipboard.wait_for_text()
313 self._taskNameEntry.set_text(entry)
314 except StandardError, e:
315 self._errorDisplay.push_exception()
317 def _on_clear(self, *args):
319 self._taskNameEntry.set_text("")
320 except StandardError, e:
321 self._errorDisplay.push_exception()
324 if __name__ == "__main__":
327 win.set_title("Tap'N'Hold")
328 eventBox = gtk.EventBox()
331 context = ContextHandler(eventBox, coroutines.printer_sink())
333 win.connect("destroy", lambda w: gtk.main_quit())
339 cal = PopupCalendar(None, datetime.datetime.now())
340 cal._popupWindow.connect("destroy", lambda w: gtk.main_quit())