2 # -*- coding: utf-8 -*-
5 This file is part of Multilist.
7 Multilist is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Multilist is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Multilist. If not, see <http://www.gnu.org/licenses/>.
20 Copyright (C) 2008 Christoph Würstle
49 import libliststorehandler
59 _moduleLogger = logging.getLogger(__name__)
60 PROFILE_STARTUP = False
63 class Multilist(hildonize.get_app_class()):
65 _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
66 _user_settings = "%s/settings.ini" % _user_data
69 super(Multilist, self).__init__()
70 self._clipboard = gtk.clipboard_get()
72 logging.info('Starting Multilist')
75 os.makedirs(self._user_data)
80 self.db = libspeichern.Speichern()
81 self.window_in_fullscreen = False #The window isn't in full screen mode initially.
83 #Haupt vbox für alle Elemente
84 self.window = gtk.Window()
85 self.vbox = gtk.VBox(homogeneous = False, spacing = 0)
87 self.selection = libselection.Selection(self.db, isHildon)
88 self._search = search.Search()
89 self.liststorehandler = libliststorehandler.Liststorehandler(self.db, self.selection)
90 self.view = libview.View(self.db, self.liststorehandler, self.window)
91 self.bottombar = libbottombar.Bottombar(self.db, self.view, isHildon)
94 if hildonize.GTK_MENU_USED:
97 menu_items = gtk.MenuItem(_("Choose database file"))
98 menu_items.connect("activate", self.select_db_dialog, None)
99 fileMenu.append(menu_items)
101 menu_items = gtk.MenuItem(_("SQL history"))
102 menu_items.connect("activate", self.view_sql_history, None)
103 fileMenu.append(menu_items)
105 menu_items = gtk.MenuItem(_("SQL optimize"))
106 menu_items.connect("activate", self.optimizeSQL, None)
107 fileMenu.append(menu_items)
109 menu_items = gtk.MenuItem(_("Sync items"))
110 menu_items.connect("activate", self.sync_notes, None)
111 fileMenu.append(menu_items)
113 menu_items = gtk.MenuItem(_("Quit"))
114 menu_items.connect("activate", self._on_destroy, None)
115 fileMenu.append(menu_items)
117 fileMenuItem = gtk.MenuItem(_("File"))
119 fileMenuItem.set_submenu(fileMenu)
121 listmenu = gtk.Menu()
123 menu_items = gtk.MenuItem(_("Search"))
124 menu_items.connect("activate", self._on_toggle_search)
125 listmenu.append(menu_items)
127 menu_items = gtk.MenuItem(_("Checkout All"))
128 menu_items.connect("activate", self._on_checkout_all)
129 listmenu.append(menu_items)
131 menu_items = gtk.MenuItem(_("Rename List"))
132 menu_items.connect("activate", self.bottombar.rename_list, None)
133 listmenu.append(menu_items)
135 menu_items = gtk.MenuItem(_("Rename Category"))
136 menu_items.connect("activate", self.bottombar.rename_category, None)
137 listmenu.append(menu_items)
139 listMenuItem = gtk.MenuItem(_("List"))
141 listMenuItem.set_submenu(listmenu)
143 viewMenu = gtk.Menu()
145 menu_items = gtk.MenuItem(_("Show Active"))
146 menu_items.connect("activate", self._on_toggle_filter, None)
147 viewMenu.append(menu_items)
149 menu_items = gtk.MenuItem(_("Settings"))
150 menu_items.connect("activate", self._on_settings, None)
151 viewMenu.append(menu_items)
153 viewMenuItem = gtk.MenuItem(_("View"))
155 viewMenuItem.set_submenu(viewMenu)
157 helpMenu = gtk.Menu()
158 menu_items = gtk.MenuItem(_("About"))
159 helpMenu.append(menu_items)
160 menu_items.connect("activate", self._on_about, None)
162 helpMenuItem = gtk.MenuItem(_("Help"))
164 helpMenuItem.set_submenu(helpMenu)
166 menu_bar = gtk.MenuBar()
168 menu_bar.append (fileMenuItem)
169 menu_bar.append (listMenuItem)
170 menu_bar.append (viewMenuItem)
171 # unten -> damit als letztes menu_bar.append (helpMenuItem)
173 menu_bar.append (helpMenuItem)
175 self.vbox.pack_start(menu_bar, False, False, 0)
177 menuBar = gtk.MenuBar()
179 self.vbox.pack_start(menuBar, False, False, 0)
181 #add to vbox below (to get it on top)
182 self.vbox.pack_end(self._search, expand = False, fill = True)
183 self.vbox.pack_end(self.bottombar, expand = False, fill = True, padding = 0)
184 self.vbox.pack_end(self.view, expand = True, fill = True, padding = 0)
185 self.vbox.pack_end(self.selection, expand = False, fill = True, padding = 0)
187 #Get the Main Window, and connect the "destroy" event
188 self.window.add(self.vbox)
190 self.window = hildonize.hildonize_window(self, self.window)
191 hildonize.set_application_title(self.window, "%s" % constants.__pretty_app_name__)
192 menu_bar = hildonize.hildonize_menu(
196 if hildonize.IS_FREMANTLE_SUPPORTED:
197 button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, None)
198 button.set_label("All")
199 menuBar.add_filter(button)
200 button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ALL)
201 button.set_mode(False)
204 button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup)
205 button.set_label("Active")
206 menuBar.add_filter(button)
207 button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ACTIVE)
208 button.set_mode(False)
210 renameListButton= gtk.Button(_("Rename List"))
211 renameListButton.connect("clicked", self.bottombar.rename_list)
212 menuBar.append(renameListButton)
214 renameCategoryButton = gtk.Button(_("Rename Category"))
215 renameCategoryButton.connect("clicked", self.bottombar.rename_category)
216 menuBar.append(renameCategoryButton)
218 searchButton= gtk.Button(_("Search Category"))
219 searchButton.connect("clicked", self._on_toggle_search)
220 menuBar.append(searchButton)
222 searchButton= gtk.Button(_("Settings"))
223 searchButton.connect("clicked", self._on_settings)
224 menuBar.append(searchButton)
228 if not hildonize.IS_HILDON_SUPPORTED:
229 _moduleLogger.info("No hildonization support")
232 self.osso_c = osso.Context(
233 constants.__app_name__,
234 constants.__version__,
238 _moduleLogger.info("No osso support")
241 self.window.connect("delete_event", self._on_delete_event)
242 self.window.connect("destroy", self._on_destroy)
243 self.window.connect("key-press-event", self.on_key_press)
244 self.window.connect("window-state-event", self._on_window_state_change)
245 self._search.connect("search_changed", self._on_search)
247 self.window.show_all()
249 self.prepare_sync_dialog()
252 @gtk_toolbox.log_exception(_moduleLogger)
253 def _on_checkout_all(self, widget):
254 self.liststorehandler.checkout_rows()
256 @gtk_toolbox.log_exception(_moduleLogger)
257 def _on_search(self, widget):
258 self.liststorehandler.get_liststore(self._search.get_search_pattern())
260 @gtk_toolbox.log_exception(_moduleLogger)
261 def _on_click_menu_filter(self, button, val):
262 self.liststorehandler.set_filter(val)
264 def _toggle_search(self):
265 if self._search.get_property("visible"):
270 @gtk_toolbox.log_exception(_moduleLogger)
271 def _on_toggle_search(self, *args):
272 self._toggle_search()
274 @gtk_toolbox.log_exception(_moduleLogger)
275 def _on_toggle_filter(self, *args):
276 if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ALL:
277 self.liststorehandler.set_filter(self.liststorehandler.SHOW_ACTIVE)
278 elif self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
279 self.liststorehandler.set_filter(self.liststorehandler.SHOW_ALL)
281 assert False, "Unknown"
283 @gtk_toolbox.log_exception(_moduleLogger)
284 def on_key_press(self, widget, event, *args):
285 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
286 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
288 event.keyval == gtk.keysyms.F6 or
289 event.keyval in RETURN_TYPES and isCtrl
291 # The "Full screen" hardware key has been pressed
292 if self.window_in_fullscreen:
293 self.window.unfullscreen ()
295 self.window.fullscreen ()
297 elif event.keyval == gtk.keysyms.f and isCtrl:
298 self._toggle_search()
301 event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
302 event.get_state() & gtk.gdk.CONTROL_MASK
304 self.window.destroy()
305 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
306 with open(constants._user_logpath_, "r") as f:
307 logLines = f.xreadlines()
308 log = "".join(logLines)
309 self._clipboard.set_text(str(log))
312 @gtk_toolbox.log_exception(_moduleLogger)
313 def _on_window_state_change(self, widget, event, *args):
314 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
315 self.window_in_fullscreen = True
317 self.window_in_fullscreen = False
319 def speichereAlles(self, data = None, data2 = None):
320 logging.info("Speichere alles")
322 def ladeAlles(self, data = None, data2 = None):
323 logging.info("Lade alles")
325 def beforeSync(self, data = None, data2 = None):
326 logging.info("Lade alles")
328 @gtk_toolbox.log_exception(_moduleLogger)
329 def sync_finished(self, data = None, data2 = None):
330 self.selection.comboList_changed()
331 self.selection.comboCategory_changed()
332 self.liststorehandler.update_list()
334 def prepare_sync_dialog(self):
335 self.sync_dialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
337 self.sync_dialog.set_position(gtk.WIN_POS_CENTER)
338 sync = libsync.Sync(self.db, self.window, 50503)
339 sync.connect("syncFinished", self.sync_finished)
340 self.sync_dialog.vbox.pack_start(sync, True, True, 0)
341 self.sync_dialog.set_size_request(500, 350)
342 self.sync_dialog.vbox.show_all()
344 @gtk_toolbox.log_exception(_moduleLogger)
345 def sync_notes(self, widget = None, data = None):
346 if self.sync_dialog == None:
347 self.prepare_sync_dialog()
348 self.sync_dialog.run()
349 self.sync_dialog.hide()
351 @gtk_toolbox.log_exception(_moduleLogger)
352 def _on_settings(self, *args):
353 col_dialog = gtk.Dialog(
356 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
357 (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
360 cols = settings.SettingsDialog(col_dialog.vbox, self.db, self.liststorehandler)
361 col_dialog.show_all()
363 resp = col_dialog.run()
366 if resp == gtk.RESPONSE_ACCEPT:
367 logging.info("changing columns")
369 self.view.reload_view()
373 @gtk_toolbox.log_exception(_moduleLogger)
374 def _on_destroy(self, widget = None, data = None):
376 self.speichereAlles()
380 except AttributeError:
381 pass # Either None or close was removed (in Fremantle)
385 @gtk_toolbox.log_exception(_moduleLogger)
386 def _on_delete_event(self, widget, event, data = None):
387 #print "delete event occurred"
390 def dlg_delete(self, widget, event, data = None):
393 @gtk_toolbox.log_exception(_moduleLogger)
394 def _on_about(self, widget = None, data = None):
395 dialog = gtk.AboutDialog()
396 dialog.set_position(gtk.WIN_POS_CENTER)
397 dialog.set_name(constants.__pretty_app_name__)
398 dialog.set_version(constants.__version__)
399 dialog.set_copyright("")
400 dialog.set_website("http://axique.de/f = Multilist")
401 comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
402 dialog.set_comments(comments)
403 dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
407 def on_info1_activate(self, menuitem):
408 self._on_about(menuitem)
410 @gtk_toolbox.log_exception(_moduleLogger)
411 def view_sql_history(self, widget = None, data = None, data2 = None):
412 sqldiag = sqldialog.SqlDialog(self.db)
417 if res != gtk.RESPONSE_OK:
419 logging.info("exporting sql")
422 dlg = gtk.FileChooserDialog(
423 parent = self.window,
424 action = gtk.FILE_CHOOSER_ACTION_SAVE
426 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
427 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
429 dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
431 dlg.set_title(_("Select SQL export file"))
432 exportFileResponse = dlg.run()
434 if exportFileResponse == gtk.RESPONSE_OK:
435 fileName = dlg.get_filename()
436 sqldiag.exportSQL(fileName)
442 @gtk_toolbox.log_exception(_moduleLogger)
443 def optimizeSQL(self, widget = None, data = None, data2 = None):
445 self.db.speichereSQL("VACUUM", log = False)
447 @gtk_toolbox.log_exception(_moduleLogger)
448 def select_db_dialog(self, widget = None, data = None, data2 = None):
449 if (isHildon == False):
450 dlg = gtk.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
451 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
452 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
454 dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
456 if self.db.ladeDirekt('datenbank'):
457 dlg.set_filename(self.db.ladeDirekt('datenbank'))
458 dlg.set_title(_("Choose your database file"))
461 if resp == gtk.RESPONSE_OK:
462 fileName = dlg.get_filename()
463 self.db.speichereDirekt('datenbank', fileName)
464 self.speichereAlles()
472 if hildonize.IS_HILDON_SUPPORTED:
473 gtk.set_application_name(constants.__pretty_app_name__)
475 if not PROFILE_STARTUP:
479 if __name__ == "__main__":
480 logging.basicConfig(level = logging.DEBUG)