9 class LoginWindow(object):
11 def __init__(self, widgetTree):
15 self._dialog = widgetTree.get_widget("loginDialog")
16 self._parentWindow = widgetTree.get_widget("mainWindow")
17 self._serviceCombo = widgetTree.get_widget("serviceCombo")
18 self._usernameEntry = widgetTree.get_widget("usernameentry")
19 self._passwordEntry = widgetTree.get_widget("passwordentry")
21 self._serviceList = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
22 self._serviceCombo.set_model(self._serviceList)
23 cell = gtk.CellRendererText()
24 self._serviceCombo.pack_start(cell, True)
25 self._serviceCombo.add_attribute(cell, 'text', 1)
26 self._serviceCombo.set_active(0)
29 "on_loginbutton_clicked": self._on_loginbutton_clicked,
30 "on_loginclose_clicked": self._on_loginclose_clicked,
32 widgetTree.signal_autoconnect(callbackMapping)
34 def request_credentials(self, parentWindow = None):
38 if parentWindow is None:
39 parentWindow = self._parentWindow
41 self._serviceCombo.hide()
42 self._serviceList.clear()
45 self._dialog.set_transient_for(parentWindow)
46 self._dialog.set_default_response(gtk.RESPONSE_OK)
47 response = self._dialog.run()
48 if response != gtk.RESPONSE_OK:
49 raise RuntimeError("Login Cancelled")
51 username = self._usernameEntry.get_text()
52 password = self._passwordEntry.get_text()
53 self._passwordEntry.set_text("")
57 return username, password
59 def request_credentials_from(self, services, parentWindow = None):
63 if parentWindow is None:
64 parentWindow = self._parentWindow
66 self._serviceList.clear()
67 for serviceIdserviceName in services.iteritems():
68 self._serviceList.append(serviceIdserviceName)
69 self._serviceCombo.set_active(0)
70 self._serviceCombo.show()
73 self._dialog.set_transient_for(parentWindow)
74 self._dialog.set_default_response(gtk.RESPONSE_OK)
75 response = self._dialog.run()
76 if response != gtk.RESPONSE_OK:
77 raise RuntimeError("Login Cancelled")
79 username = self._usernameEntry.get_text()
80 password = self._passwordEntry.get_text()
81 self._passwordEntry.set_text("")
85 itr = self._serviceCombo.get_active_iter()
86 serviceId = int(self._serviceList.get_value(itr, 0))
87 self._serviceList.clear()
88 return serviceId, username, password
90 def _on_loginbutton_clicked(self, *args):
91 self._dialog.response(gtk.RESPONSE_OK)
93 def _on_loginclose_clicked(self, *args):
94 self._dialog.response(gtk.RESPONSE_CANCEL)
97 class ErrorDisplay(object):
99 def __init__(self, widgetTree):
100 super(ErrorDisplay, self).__init__()
101 self.__errorBox = widgetTree.get_widget("errorEventBox")
102 self.__errorDescription = widgetTree.get_widget("errorDescription")
103 self.__errorClose = widgetTree.get_widget("errorClose")
104 self.__parentBox = self.__errorBox.get_parent()
106 self.__errorBox.connect("button_release_event", self._on_close)
109 self.__parentBox.remove(self.__errorBox)
111 def push_message_with_lock(self, message):
112 gtk.gdk.threads_enter()
114 self.push_message(message)
116 gtk.gdk.threads_leave()
118 def push_message(self, message):
119 if 0 < len(self.__messages):
120 self.__messages.append(message)
122 self.__show_message(message)
124 def push_exception(self, exception):
125 self.push_message(exception.message)
126 warnings.warn(exception, stacklevel=3)
128 def pop_message(self):
129 if 0 < len(self.__messages):
130 self.__show_message(self.__messages[0])
131 del self.__messages[0]
133 self.__hide_message()
135 def _on_close(self, *args):
138 def __show_message(self, message):
139 self.__errorDescription.set_text(message)
140 self.__parentBox.pack_start(self.__errorBox, False, False)
141 self.__parentBox.reorder_child(self.__errorBox, 1)
143 def __hide_message(self):
144 self.__errorDescription.set_text("")
145 self.__parentBox.remove(self.__errorBox)
148 class MessageBox(gtk.MessageDialog):
150 def __init__(self, message):
152 gtk.MessageDialog.__init__(
155 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
160 self.set_default_response(gtk.RESPONSE_OK)
161 self.connect('response', self._handle_clicked)
163 def _handle_clicked(self, *args):
167 class MessageBox2(gtk.MessageDialog):
169 def __init__(self, message):
171 gtk.MessageDialog.__init__(
174 gtk.DIALOG_DESTROY_WITH_PARENT,
179 self.set_default_response(gtk.RESPONSE_OK)
180 self.connect('response', self._handle_clicked)
182 def _handle_clicked(self, *args):
186 class PopupCalendar(object):
188 def __init__(self, parent):
189 self.__calendar = gtk.Calendar()
190 self.__calendar.connect("day-selected-double-click", self._on_date_select)
192 self.__popupWindow = gtk.Window(type = gtk.WINDOW_POPUP)
193 self.__popupWindow.set_title("")
194 self.__popupWindow.add(self.__calendar)
195 self.__popupWindow.set_transient_for(parent)
196 self.__popupWindow.set_modal(True)
199 year, month, day = self.__calendar.get_date()
200 month += 1 # Seems to be 0 indexed
201 return year, month, day
204 self.__popupWindow.show_all()
206 def _on_date_select(self, *args):
207 self.__popupWindow.hide()
214 class EditTaskDialog(object):
216 def __init__(self, widgetTree):
217 self._projectsList = gtk.ListStore(gobject.TYPE_STRING)
219 self._dialog = widgetTree.get_widget("editTaskDialog")
220 self._projectCombo = widgetTree.get_widget("edit-targetProjectCombo")
221 self._taskName = widgetTree.get_widget("edit-taskNameEntry")
222 self._pasteTaskNameButton = widgetTree.get_widget("edit-pasteTaskNameButton")
223 self._priorityChoiceCombo = widgetTree.get_widget("edit-priorityChoiceCombo")
224 self._dueDateDisplay = widgetTree.get_widget("edit-dueDateDisplay")
225 self._dueDateProperties = widgetTree.get_widget("edit-dueDateProperties")
226 self._clearDueDate = widgetTree.get_widget("edit-clearDueDate")
228 self._addButton = widgetTree.get_widget("edit-commitEditTaskButton")
229 self._cancelButton = widgetTree.get_widget("edit-cancelEditTaskButton")
231 self._popupCalendar = PopupCalendar(self._dialog)
233 def enable(self, todoManager):
234 self._populate_projects(todoManager)
235 self._pasteTaskNameButton.connect("clicked", self._on_name_paste)
236 self._dueDateProperties.connect("clicked", self._on_choose_duedate)
237 self._clearDueDate.connect("clicked", self._on_clear_duedate)
239 self._addButton.connect("clicked", self._on_add_clicked)
240 self._cancelButton.connect("clicked", self._on_cancel_clicked)
242 self._popupCalendar.callback = self._update_duedate
245 self._popupCalendar.callback = lambda: None
247 self._pasteTaskNameButton.disconnect("clicked", self._on_name_paste)
248 self._dueDateProperties.disconnect("clicked", self._on_choose_duedate)
249 self._clearDueDate.disconnect("clicked", self._on_clear_duedate)
250 self._projectsList.clear()
251 self._projectCombo.set_model(None)
253 def request_task(self, todoManager, taskId, parentWindow = None):
254 if parentWindow is not None:
255 self._dialog.set_transient_for(parentWindow)
257 taskDetails = todoManager.get_task_details(taskId)
258 originalProjectId = taskDetails["projId"]
259 originalProjectName = todoManager.get_project(originalProjectId)["name"]
260 originalName = taskDetails["name"]
262 originalPriority = int(taskDetails["priority"])
265 originalDue = taskDetails["due"]
267 self._dialog.set_default_response(gtk.RESPONSE_OK)
268 self._taskName.set_text(originalName)
269 self._set_active_proj(originalProjectName)
270 self._priorityChoiceCombo.set_active(originalPriority)
271 self._dueDateDisplay.set_text(originalDue)
274 response = self._dialog.run()
275 if response != gtk.RESPONSE_OK:
276 raise RuntimeError("Edit Cancelled")
280 newProjectName = self._get_project(todoManager)
281 newName = self._taskName.get_text()
282 newPriority = self._get_priority()
283 newDueDate = self._dueDateDisplay.get_text()
285 isProjDifferent = newProjectName != originalProjectName
286 isNameDifferent = newName != originalName
287 isPriorityDifferent = newPriority != originalPriority
288 isDueDifferent = newDueDate != originalDue
291 newProjectId = todoManager.lookup_project(newProjectName)
292 todoManager.set_project(taskId, newProjectId)
295 todoManager.set_name(taskId, newName)
297 if isPriorityDifferent:
298 todoManager.set_priority(taskId, newPriority)
301 todoManager.set_duedate(taskId, newDueDate)
305 "projId": isProjDifferent,
306 "name": isNameDifferent,
307 "priority": isPriorityDifferent,
308 "due": isDueDifferent,
311 def _populate_projects(self, todoManager):
312 for projectName in todoManager.get_projects():
313 row = (projectName["name"], )
314 self._projectsList.append(row)
315 self._projectCombo.set_model(self._projectsList)
316 cell = gtk.CellRendererText()
317 self._projectCombo.pack_start(cell, True)
318 self._projectCombo.add_attribute(cell, 'text', 0)
319 self._projectCombo.set_active(0)
321 def _set_active_proj(self, projName):
322 for i, row in enumerate(self._projectsList):
323 if row[0] == projName:
324 self._projectCombo.set_active(i)
327 raise ValueError("%s not in list" % projName)
329 def _get_project(self, todoManager):
330 name = self._projectCombo.get_active_text()
333 def _get_priority(self):
334 index = self._priorityChoiceCombo.get_active()
342 # @bug The date is not used in a consistent manner causing ... issues
343 dateParts = self._popupCalendar.get_date()
344 dateParts = (str(part) for part in dateParts)
345 return "-".join(dateParts)
347 def _update_duedate(self):
348 self._dueDateDisplay.set_text(self._get_date())
350 def _on_name_paste(self, *args):
351 clipboard = gtk.clipboard_get()
352 contents = clipboard.wait_for_text()
353 if contents is not None:
354 self._taskName.set_text(contents)
356 def _on_choose_duedate(self, *args):
357 self._popupCalendar.run()
359 def _on_clear_duedate(self, *args):
360 self._dueDateDisplay.set_text("")
362 def _on_add_clicked(self, *args):
363 self._dialog.response(gtk.RESPONSE_OK)
365 def _on_cancel_clicked(self, *args):
366 self._dialog.response(gtk.RESPONSE_CANCEL)