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
48 import libliststorehandler
58 _moduleLogger = logging.getLogger(__name__)
59 PROFILE_STARTUP = False
62 class Multilist(hildonize.get_app_class()):
64 _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
65 _user_settings = "%s/settings.ini" % _user_data
68 super(Multilist, self).__init__()
69 self._clipboard = gtk.clipboard_get()
71 logging.info('Starting Multilist')
74 os.makedirs(self._user_data)
79 self.db = libspeichern.Speichern()
80 self.window_in_fullscreen = False #The window isn't in full screen mode initially.
82 #Haupt vbox für alle Elemente
83 self.window = gtk.Window()
84 self.vbox = gtk.VBox(homogeneous = False, spacing = 0)
86 self.selection = libselection.Selection(self.db, isHildon)
87 self._search = search.Search()
88 self.liststorehandler = libliststorehandler.Liststorehandler(self.db, self.selection)
89 self.view = libview.View(self.db, self.liststorehandler, self.window)
90 self.bottombar = libbottombar.Bottombar(self.db, self.view, isHildon)
93 if hildonize.GTK_MENU_USED:
96 menu_items = gtk.MenuItem(_("Choose database file"))
97 menu_items.connect("activate", self.select_db_dialog, None)
98 fileMenu.append(menu_items)
100 menu_items = gtk.MenuItem(_("SQL history"))
101 menu_items.connect("activate", self.view_sql_history, None)
102 fileMenu.append(menu_items)
104 menu_items = gtk.MenuItem(_("SQL optimize"))
105 menu_items.connect("activate", self.optimizeSQL, None)
106 fileMenu.append(menu_items)
108 menu_items = gtk.MenuItem(_("Sync items"))
109 menu_items.connect("activate", self.sync_notes, None)
110 fileMenu.append(menu_items)
112 menu_items = gtk.MenuItem(_("Quit"))
113 menu_items.connect("activate", self.destroy, None)
114 fileMenu.append(menu_items)
116 fileMenuItem = gtk.MenuItem(_("File"))
118 fileMenuItem.set_submenu(fileMenu)
120 categorymenu = gtk.Menu()
122 menu_items = gtk.MenuItem(_("Search"))
123 categorymenu.append(menu_items)
124 menu_items.connect("activate", self._on_toggle_search)
126 category_menu = gtk.MenuItem(_("Category"))
128 category_menu.set_submenu(categorymenu)
130 viewMenu = gtk.Menu()
132 menu_items = gtk.MenuItem(_("Show Active"))
133 menu_items.connect("activate", self._on_toggle_filter, None)
134 viewMenu.append(menu_items)
136 viewMenuItem = gtk.MenuItem(_("View"))
138 viewMenuItem.set_submenu(viewMenu)
140 toolsMenu = gtk.Menu()
142 menu_items = gtk.MenuItem(_("Choose columns"))
143 menu_items.connect("activate", self.show_columns_dialog, None)
144 toolsMenu.append(menu_items)
146 menu_items = gtk.MenuItem(_("Rename Category"))
147 menu_items.connect("activate", self.bottombar.rename_category, None)
148 toolsMenu.append(menu_items)
150 menu_items = gtk.MenuItem(_("Rename List"))
151 menu_items.connect("activate", self.bottombar.rename_list, None)
152 toolsMenu.append(menu_items)
154 toolsMenuItem = gtk.MenuItem(_("Tools"))
156 toolsMenuItem.set_submenu(toolsMenu)
158 helpMenu = gtk.Menu()
159 menu_items = gtk.MenuItem(_("About"))
160 helpMenu.append(menu_items)
161 menu_items.connect("activate", self.show_about, None)
163 helpMenuItem = gtk.MenuItem(_("Help"))
165 helpMenuItem.set_submenu(helpMenu)
167 menu_bar = gtk.MenuBar()
169 menu_bar.append (fileMenuItem)
170 menu_bar.append (toolsMenuItem)
171 menu_bar.append (category_menu)
172 menu_bar.append (viewMenuItem)
173 # unten -> damit als letztes menu_bar.append (helpMenuItem)
175 menu_bar.append (helpMenuItem)
177 self.vbox.pack_start(menu_bar, False, False, 0)
179 menuBar = gtk.MenuBar()
181 self.vbox.pack_start(menuBar, False, False, 0)
183 #add to vbox below (to get it on top)
184 self.vbox.pack_end(self._search, expand = False, fill = True)
185 self.vbox.pack_end(self.bottombar, expand = False, fill = True, padding = 0)
186 self.vbox.pack_end(self.view, expand = True, fill = True, padding = 0)
187 self.vbox.pack_end(self.selection, expand = False, fill = True, padding = 0)
189 #Get the Main Window, and connect the "destroy" event
190 self.window.add(self.vbox)
192 self.window = hildonize.hildonize_window(self, self.window)
193 hildonize.set_application_title(self.window, "%s" % constants.__pretty_app_name__)
194 menu_bar = hildonize.hildonize_menu(
198 if hildonize.IS_FREMANTLE_SUPPORTED:
199 button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, None)
200 button.set_label("All")
201 menuBar.add_filter(button)
202 button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ALL)
203 button.set_mode(False)
206 button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup)
207 button.set_label("Active")
208 menuBar.add_filter(button)
209 button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ACTIVE)
210 button.set_mode(False)
212 renameCategoryButton = gtk.Button(_("Rename Category"))
213 renameCategoryButton.connect("clicked", self.bottombar.rename_category)
214 menuBar.append(renameCategoryButton)
216 renameListButton= gtk.Button(_("Rename List"))
217 renameListButton.connect("clicked", self.bottombar.rename_list)
218 menuBar.append(renameListButton)
220 searchButton= gtk.Button(_("Search Category"))
221 searchButton.connect("clicked", self._on_toggle_search)
222 menuBar.append(searchButton)
226 if not hildonize.IS_HILDON_SUPPORTED:
227 _moduleLogger.info("No hildonization support")
230 self.osso_c = osso.Context(
231 constants.__app_name__,
232 constants.__version__,
236 _moduleLogger.info("No osso support")
239 self.window.connect("delete_event", self.delete_event)
240 self.window.connect("destroy", self.destroy)
241 self.window.connect("key-press-event", self.on_key_press)
242 self.window.connect("window-state-event", self.on_window_state_change)
243 self._search.connect("search_changed", self._on_search)
245 self.window.show_all()
247 self.prepare_sync_dialog()
250 @gtk_toolbox.log_exception(_moduleLogger)
251 def _on_search(self, widget):
252 self.liststorehandler.get_liststore(self._search.get_search_pattern())
254 @gtk_toolbox.log_exception(_moduleLogger)
255 def _on_click_menu_filter(self, button, val):
256 self.liststorehandler.set_filter(val)
258 def _toggle_search(self):
259 if self._search.get_property("visible"):
264 @gtk_toolbox.log_exception(_moduleLogger)
265 def _on_toggle_search(self, *args):
266 self._toggle_search()
268 @gtk_toolbox.log_exception(_moduleLogger)
269 def _on_toggle_filter(self, *args):
270 if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ALL:
271 self.liststorehandler.set_filter(self.liststorehandler.SHOW_ACTIVE)
272 elif self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
273 self.liststorehandler.set_filter(self.liststorehandler.SHOW_ALL)
275 assert False, "Unknown"
277 @gtk_toolbox.log_exception(_moduleLogger)
278 def on_key_press(self, widget, event, *args):
279 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
280 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
282 event.keyval == gtk.keysyms.F6 or
283 event.keyval in RETURN_TYPES and isCtrl
285 # The "Full screen" hardware key has been pressed
286 if self.window_in_fullscreen:
287 self.window.unfullscreen ()
289 self.window.fullscreen ()
291 elif event.keyval == gtk.keysyms.f and isCtrl:
292 self._toggle_search()
295 event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
296 event.get_state() & gtk.gdk.CONTROL_MASK
298 self.window.destroy()
299 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
300 with open(constants._user_logpath_, "r") as f:
301 logLines = f.xreadlines()
302 log = "".join(logLines)
303 self._clipboard.set_text(str(log))
306 @gtk_toolbox.log_exception(_moduleLogger)
307 def on_window_state_change(self, widget, event, *args):
308 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
309 self.window_in_fullscreen = True
311 self.window_in_fullscreen = False
313 def speichereAlles(self, data = None, data2 = None):
314 logging.info("Speichere alles")
316 def ladeAlles(self, data = None, data2 = None):
317 logging.info("Lade alles")
319 def beforeSync(self, data = None, data2 = None):
320 logging.info("Lade alles")
322 @gtk_toolbox.log_exception(_moduleLogger)
323 def sync_finished(self, data = None, data2 = None):
324 self.selection.comboList_changed()
325 self.selection.comboCategory_changed()
326 self.liststorehandler.update_list()
328 def prepare_sync_dialog(self):
329 self.sync_dialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
331 self.sync_dialog.set_position(gtk.WIN_POS_CENTER)
332 sync = libsync.Sync(self.db, self.window, 50503)
333 sync.connect("syncFinished", self.sync_finished)
334 self.sync_dialog.vbox.pack_start(sync, True, True, 0)
335 self.sync_dialog.set_size_request(500, 350)
336 self.sync_dialog.vbox.show_all()
338 @gtk_toolbox.log_exception(_moduleLogger)
339 def sync_notes(self, widget = None, data = None):
340 if self.sync_dialog == None:
341 self.prepare_sync_dialog()
342 self.sync_dialog.run()
343 self.sync_dialog.hide()
345 @gtk_toolbox.log_exception(_moduleLogger)
346 def show_columns_dialog(self, widget = None, data = None):
347 col_dialog = gtk.Dialog(_("Choose columns"), self.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
349 col_dialog.set_position(gtk.WIN_POS_CENTER)
350 cols = libview.Columns_dialog(self.db, self.liststorehandler)
352 col_dialog.vbox.pack_start(cols, True, True, 0)
353 col_dialog.set_size_request(500, 350)
354 col_dialog.vbox.show_all()
356 resp = col_dialog.run()
358 if resp == gtk.RESPONSE_ACCEPT:
359 logging.info("changing columns")
360 cols.save_column_setting()
361 self.view.reload_view()
362 #children = self.vbox.get_children()
363 #while len(children)>1:
364 # self.vbox.remove(children[1])
366 #self.vbox.pack_end(self.bottombar, expand = True, fill = True, padding = 0)
367 #self.vbox.pack_end(view, expand = True, fill = True, padding = 0)
368 #self.vbox.pack_end(self.selection, expand = False, fill = True, padding = 0)
372 @gtk_toolbox.log_exception(_moduleLogger)
373 def destroy(self, widget = None, data = None):
375 self.speichereAlles()
379 except AttributeError:
380 pass # Either None or close was removed (in Fremantle)
384 @gtk_toolbox.log_exception(_moduleLogger)
385 def delete_event(self, widget, event, data = None):
386 #print "delete event occurred"
389 def dlg_delete(self, widget, event, data = None):
392 @gtk_toolbox.log_exception(_moduleLogger)
393 def show_about(self, widget = None, data = None):
394 dialog = gtk.AboutDialog()
395 dialog.set_position(gtk.WIN_POS_CENTER)
396 dialog.set_name(constants.__pretty_app_name__)
397 dialog.set_version(constants.__version__)
398 dialog.set_copyright("")
399 dialog.set_website("http://axique.de/f = Multilist")
400 comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
401 dialog.set_comments(comments)
402 dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
406 def on_info1_activate(self, menuitem):
407 self.show_about(menuitem)
409 @gtk_toolbox.log_exception(_moduleLogger)
410 def view_sql_history(self, widget = None, data = None, data2 = None):
411 sqldiag = sqldialog.SqlDialog(self.db)
416 if res != gtk.RESPONSE_OK:
418 logging.info("exporting sql")
421 dlg = gtk.FileChooserDialog(
422 parent = self.window,
423 action = gtk.FILE_CHOOSER_ACTION_SAVE
425 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
426 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
428 dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
430 dlg.set_title(_("Select SQL export file"))
431 exportFileResponse = dlg.run()
433 if exportFileResponse == gtk.RESPONSE_OK:
434 fileName = dlg.get_filename()
435 sqldiag.exportSQL(fileName)
441 @gtk_toolbox.log_exception(_moduleLogger)
442 def optimizeSQL(self, widget = None, data = None, data2 = None):
444 self.db.speichereSQL("VACUUM", log = False)
446 @gtk_toolbox.log_exception(_moduleLogger)
447 def select_db_dialog(self, widget = None, data = None, data2 = None):
448 if (isHildon == False):
449 dlg = gtk.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
450 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
451 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
453 #dlg = hildon.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
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"))
459 if dlg.run() == gtk.RESPONSE_OK:
460 fileName = dlg.get_filename()
461 self.db.speichereDirekt('datenbank', fileName)
462 self.speichereAlles()
469 if hildonize.IS_HILDON_SUPPORTED:
470 gtk.set_application_name(constants.__pretty_app_name__)
472 if not PROFILE_STARTUP:
476 if __name__ == "__main__":
477 logging.basicConfig(level = logging.DEBUG)