Removing dead code and cleaning things up
[multilist] / src / multilist_gtk.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 This file is part of Multilist.
6
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.
11
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.
16
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/>.
19
20 Copyright (C) 2008 Christoph Würstle
21 """
22
23 import os
24 import logging
25
26 import gtk
27
28 try:
29         import hildon
30         isHildon = True
31 except:
32         isHildon = False
33
34 try:
35         import osso
36 except ImportError:
37         osso = None
38
39 import constants
40 import hildonize
41 import gtk_toolbox
42
43 import libspeichern
44 import search
45 import sqldialog
46 import settings
47 import libselection
48 import libview
49 import libliststorehandler
50 import libsync
51 import libbottombar
52
53 try:
54         _
55 except NameError:
56         _ = lambda x: x
57
58
59 _moduleLogger = logging.getLogger(__name__)
60 PROFILE_STARTUP = False
61
62
63 class Multilist(hildonize.get_app_class()):
64
65         _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
66         _user_settings = "%s/settings.ini" % _user_data
67
68         def __init__(self):
69                 super(Multilist, self).__init__()
70                 self._clipboard = gtk.clipboard_get()
71
72                 logging.info('Starting Multilist')
73
74                 try:
75                         os.makedirs(self._user_data)
76                 except OSError, e:
77                         if e.errno != 17:
78                                 raise
79
80                 self.db = libspeichern.Speichern()
81                 self.window_in_fullscreen = False #The window isn't in full screen mode initially.
82
83                 #Haupt vbox für alle Elemente
84                 self.window = gtk.Window()
85                 self.vbox = gtk.VBox(homogeneous = False, spacing = 0)
86
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)
92
93                 #Menue
94                 if hildonize.GTK_MENU_USED:
95                         fileMenu = gtk.Menu()
96
97                         menu_items = gtk.MenuItem(_("Choose database file"))
98                         menu_items.connect("activate", self._on_select_db, None)
99                         fileMenu.append(menu_items)
100
101                         menu_items = gtk.MenuItem(_("SQL history"))
102                         menu_items.connect("activate", self._on_view_sql_history, None)
103                         fileMenu.append(menu_items)
104
105                         menu_items = gtk.MenuItem(_("SQL optimize"))
106                         menu_items.connect("activate", self._on_optimize_sql, None)
107                         fileMenu.append(menu_items)
108
109                         menu_items = gtk.MenuItem(_("Sync items"))
110                         menu_items.connect("activate", self.sync_notes, None)
111                         fileMenu.append(menu_items)
112
113                         menu_items = gtk.MenuItem(_("Quit"))
114                         menu_items.connect("activate", self._on_destroy, None)
115                         fileMenu.append(menu_items)
116
117                         fileMenuItem = gtk.MenuItem(_("File"))
118                         fileMenuItem.show()
119                         fileMenuItem.set_submenu(fileMenu)
120
121                         listmenu = gtk.Menu()
122
123                         menu_items = gtk.MenuItem(_("Search"))
124                         menu_items.connect("activate", self._on_toggle_search)
125                         listmenu.append(menu_items)
126
127                         menu_items = gtk.MenuItem(_("Checkout All"))
128                         menu_items.connect("activate", self._on_checkout_all)
129                         listmenu.append(menu_items)
130
131                         menu_items = gtk.MenuItem(_("Rename List"))
132                         menu_items.connect("activate", self.bottombar.rename_list, None)
133                         listmenu.append(menu_items)
134
135                         menu_items = gtk.MenuItem(_("Rename Category"))
136                         menu_items.connect("activate", self.bottombar.rename_category, None)
137                         listmenu.append(menu_items)
138
139                         listMenuItem = gtk.MenuItem(_("List"))
140                         listMenuItem.show()
141                         listMenuItem.set_submenu(listmenu)
142
143                         viewMenu = gtk.Menu()
144
145                         menu_items = gtk.MenuItem(_("Show Active"))
146                         menu_items.connect("activate", self._on_toggle_filter, None)
147                         viewMenu.append(menu_items)
148
149                         menu_items = gtk.MenuItem(_("Settings"))
150                         menu_items.connect("activate", self._on_settings, None)
151                         viewMenu.append(menu_items)
152
153                         viewMenuItem = gtk.MenuItem(_("View"))
154                         viewMenuItem.show()
155                         viewMenuItem.set_submenu(viewMenu)
156
157                         helpMenu = gtk.Menu()
158                         menu_items = gtk.MenuItem(_("About"))
159                         helpMenu.append(menu_items)
160                         menu_items.connect("activate", self._on_about, None)
161
162                         helpMenuItem = gtk.MenuItem(_("Help"))
163                         helpMenuItem.show()
164                         helpMenuItem.set_submenu(helpMenu)
165
166                         menu_bar = gtk.MenuBar()
167                         menu_bar.show()
168                         menu_bar.append (fileMenuItem)
169                         menu_bar.append (listMenuItem)
170                         menu_bar.append (viewMenuItem)
171                         # unten -> damit als letztes menu_bar.append (helpMenuItem)
172                         #Als letztes menü
173                         menu_bar.append (helpMenuItem)
174
175                         self.vbox.pack_start(menu_bar, False, False, 0)
176                 else:
177                         menuBar = gtk.MenuBar()
178                         menuBar.show()
179                         self.vbox.pack_start(menuBar, False, False, 0)
180
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)
186
187                 #Get the Main Window, and connect the "destroy" event
188                 self.window.add(self.vbox)
189
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(
193                         self.window,
194                         menu_bar,
195                 )
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)
202                         filterGroup = button
203
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)
209
210                         renameListButton= gtk.Button(_("Rename List"))
211                         renameListButton.connect("clicked", self.bottombar.rename_list)
212                         menuBar.append(renameListButton)
213
214                         renameCategoryButton = gtk.Button(_("Rename Category"))
215                         renameCategoryButton.connect("clicked", self.bottombar.rename_category)
216                         menuBar.append(renameCategoryButton)
217
218                         searchButton= gtk.Button(_("Search Category"))
219                         searchButton.connect("clicked", self._on_toggle_search)
220                         menuBar.append(searchButton)
221
222                         searchButton= gtk.Button(_("Settings"))
223                         searchButton.connect("clicked", self._on_settings)
224                         menuBar.append(searchButton)
225
226                         menuBar.show_all()
227
228                 if not hildonize.IS_HILDON_SUPPORTED:
229                         _moduleLogger.info("No hildonization support")
230
231                 if osso is not None:
232                         self.osso_c = osso.Context(
233                                 constants.__app_name__,
234                                 constants.__version__,
235                                 False
236                         )
237                 else:
238                         _moduleLogger.info("No osso support")
239                         self._osso_c = None
240
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)
246
247                 self.window.show_all()
248                 self._search.hide()
249                 self._prepare_sync_dialog()
250
251         def _toggle_search(self):
252                 if self._search.get_property("visible"):
253                         self._search.hide()
254                 else:
255                         self._search.show()
256
257         @gtk_toolbox.log_exception(_moduleLogger)
258         def _on_checkout_all(self, widget):
259                 self.liststorehandler.checkout_rows()
260
261         @gtk_toolbox.log_exception(_moduleLogger)
262         def _on_search(self, widget):
263                 self.liststorehandler.get_liststore(self._search.get_search_pattern())
264
265         @gtk_toolbox.log_exception(_moduleLogger)
266         def _on_click_menu_filter(self, button, val):
267                 self.liststorehandler.set_filter(val)
268
269         @gtk_toolbox.log_exception(_moduleLogger)
270         def _on_toggle_search(self, *args):
271                 self._toggle_search()
272
273         @gtk_toolbox.log_exception(_moduleLogger)
274         def _on_toggle_filter(self, *args):
275                 if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ALL:
276                         self.liststorehandler.set_filter(self.liststorehandler.SHOW_ACTIVE)
277                 elif self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
278                         self.liststorehandler.set_filter(self.liststorehandler.SHOW_ALL)
279                 else:
280                         assert False, "Unknown"
281
282         @gtk_toolbox.log_exception(_moduleLogger)
283         def on_key_press(self, widget, event, *args):
284                 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
285                 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
286                 if (
287                         event.keyval == gtk.keysyms.F6 or
288                         event.keyval in RETURN_TYPES and isCtrl
289                 ):
290                         # The "Full screen" hardware key has been pressed 
291                         if self.window_in_fullscreen:
292                                 self.window.unfullscreen ()
293                         else:
294                                 self.window.fullscreen ()
295                         return True
296                 elif event.keyval == gtk.keysyms.f and isCtrl:
297                         self._toggle_search()
298                         return True
299                 elif (
300                         event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
301                         event.get_state() & gtk.gdk.CONTROL_MASK
302                 ):
303                         self.window.destroy()
304                 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
305                         with open(constants._user_logpath_, "r") as f:
306                                 logLines = f.xreadlines()
307                                 log = "".join(logLines)
308                                 self._clipboard.set_text(str(log))
309                         return True
310
311         @gtk_toolbox.log_exception(_moduleLogger)
312         def _on_window_state_change(self, widget, event, *args):
313                 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
314                         self.window_in_fullscreen = True
315                 else:
316                         self.window_in_fullscreen = False
317
318         @gtk_toolbox.log_exception(_moduleLogger)
319         def _on_sync_finished(self, data = None, data2 = None):
320                 self.selection.comboList_changed()
321                 self.selection.comboCategory_changed()
322                 self.liststorehandler.update_list()
323
324         def _prepare_sync_dialog(self):
325                 self.sync_dialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
326
327                 self.sync_dialog.set_position(gtk.WIN_POS_CENTER)
328                 sync = libsync.Sync(self.db, self.window, 50503)
329                 sync.connect("syncFinished", self._on_sync_finished)
330                 self.sync_dialog.vbox.pack_start(sync, True, True, 0)
331                 self.sync_dialog.set_size_request(500, 350)
332                 self.sync_dialog.vbox.show_all()
333
334         @gtk_toolbox.log_exception(_moduleLogger)
335         def sync_notes(self, widget = None, data = None):
336                 if self.sync_dialog is None:
337                         self._prepare_sync_dialog()
338                 self.sync_dialog.run()
339                 self.sync_dialog.hide()
340
341         @gtk_toolbox.log_exception(_moduleLogger)
342         def _on_settings(self, *args):
343                 col_dialog = gtk.Dialog(
344                         _("Settings"),
345                         self.window,
346                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
347                         (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
348                 )
349
350                 cols = settings.SettingsDialog(col_dialog.vbox, self.db, self.liststorehandler)
351                 col_dialog.show_all()
352
353                 resp = col_dialog.run()
354                 try:
355                         col_dialog.hide()
356                         if resp == gtk.RESPONSE_ACCEPT:
357                                 logging.info("changing columns")
358                                 cols.save(self.db)
359                                 self.view.reload_view()
360                 finally:
361                         col_dialog.destroy()
362
363         @gtk_toolbox.log_exception(_moduleLogger)
364         def _on_destroy(self, widget = None, data = None):
365                 try:
366                         self.db.close()
367                         try:
368                                 self._osso_c.close()
369                         except AttributeError:
370                                 pass # Either None or close was removed (in Fremantle)
371                 finally:
372                         gtk.main_quit()
373
374         @gtk_toolbox.log_exception(_moduleLogger)
375         def _on_delete_event(self, widget, event, data = None):
376                 return False
377
378         @gtk_toolbox.log_exception(_moduleLogger)
379         def _on_view_sql_history(self, widget = None, data = None, data2 = None):
380                 sqldiag = sqldialog.SqlDialog(self.db)
381                 res = sqldiag.run()
382                 sqldiag.hide()
383
384                 try:
385                         if res != gtk.RESPONSE_OK:
386                                 return
387                         logging.info("exporting sql")
388
389                         if not isHildon:
390                                 dlg = gtk.FileChooserDialog(
391                                         parent = self.window,
392                                         action = gtk.FILE_CHOOSER_ACTION_SAVE
393                                 )
394                                 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
395                                 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
396                         else:
397                                 dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
398
399                         dlg.set_title(_("Select SQL export file"))
400                         exportFileResponse = dlg.run()
401                         try:
402                                 if exportFileResponse == gtk.RESPONSE_OK:
403                                         fileName = dlg.get_filename()
404                                         sqldiag.exportSQL(fileName)
405                         finally:
406                                 dlg.destroy()
407                 finally:
408                         sqldiag.destroy()
409
410         @gtk_toolbox.log_exception(_moduleLogger)
411         def _on_optimize_sql(self, widget = None, data = None, data2 = None):
412                 #optimiere sql
413                 self.db.speichereSQL("VACUUM", log = False)
414
415         @gtk_toolbox.log_exception(_moduleLogger)
416         def _on_select_db(self, widget = None, data = None, data2 = None):
417                 dlg = hildon.FileChooserDialog(parent=self._window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
418
419                 if self.db.ladeDirekt('datenbank'):
420                         dlg.set_filename(self.db.ladeDirekt('datenbank'))
421                 dlg.set_title(_("Choose your database file"))
422                 resp = dlg.run()
423                 try:
424                         if resp == gtk.RESPONSE_OK:
425                                 fileName = dlg.get_filename()
426                                 self.db.speichereDirekt('datenbank', fileName)
427                                 self.db.openDB()
428                 finally:
429                         dlg.destroy()
430
431         @gtk_toolbox.log_exception(_moduleLogger)
432         def _on_about(self, widget = None, data = None):
433                 dialog = gtk.AboutDialog()
434                 dialog.set_position(gtk.WIN_POS_CENTER)
435                 dialog.set_name(constants.__pretty_app_name__)
436                 dialog.set_version(constants.__version__)
437                 dialog.set_copyright("")
438                 dialog.set_website("http://axique.de/f = Multilist")
439                 comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
440                 dialog.set_comments(comments)
441                 dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
442                 dialog.run()
443                 dialog.destroy()
444
445
446 def run_multilist():
447         if hildonize.IS_HILDON_SUPPORTED:
448                 gtk.set_application_name(constants.__pretty_app_name__)
449         app = Multilist()
450         if not PROFILE_STARTUP:
451                 gtk.main()
452
453
454 if __name__ == "__main__":
455         logging.basicConfig(level = logging.DEBUG)
456         run_multilist()