Further cleanup
[multilist] / src / libmultilist.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 sys
25 import logging
26
27 import gtk
28
29 try:
30         import hildon
31         isHildon=True
32 except:
33         isHildon=False
34         class hildon():
35                 def __init__(self):
36                         print "PseudoClass hildon"
37                 class Program():
38                         def __init__(self):
39                                 print "PseudoClass hildon.Program"
40
41 try:
42         import osso
43 except ImportError:
44         osso = None
45
46 import constants
47 import hildonize
48
49 import libspeichern
50 import libsqldialog
51 import libselection
52 import libview
53 import libliststorehandler
54 import libsync
55 import libbottombar
56
57 try:
58         _
59 except NameError:
60         _ = lambda x: x
61
62
63 _moduleLogger = logging.getLogger(__name__)
64 PROFILE_STARTUP = False
65
66
67 class multilistclass(hildonize.get_app_class()):
68
69         _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
70         _user_settings = "%s/settings.ini" % _user_data
71
72         def __init__(self):
73                 super(multilistclass, self).__init__()
74                 self._clipboard = gtk.clipboard_get()
75
76                 logging.info('Starting Multilist')
77
78                 try:
79                         os.makedirs(self._user_data)
80                 except OSError, e:
81                         if e.errno != 17:
82                                 raise
83
84                 self.db = libspeichern.Speichern()
85                 self.window_in_fullscreen = False #The window isn't in full screen mode initially.
86
87                 #Haupt vbox für alle Elemente
88                 self.window = gtk.Window()
89                 self.vbox = gtk.VBox(homogeneous=False, spacing=0)
90
91                 self.selection = libselection.Selection(self.db, isHildon)
92                 self.liststorehandler = libliststorehandler.Liststorehandler(self.db, self.selection)
93                 self.view = libview.View(self.db, self.liststorehandler, self.window)
94                 self.bottombar = libbottombar.Bottombar(self.db, self.view, isHildon)
95
96                 #Menue
97                 if hildonize.GTK_MENU_USED:
98                         dateimenu = gtk.Menu()
99
100                         menu_items = gtk.MenuItem(_("Choose database file"))
101                         dateimenu.append(menu_items)
102                         menu_items.connect("activate", self.select_db_dialog, None)
103
104                         menu_items = gtk.MenuItem(_("SQL history"))
105                         dateimenu.append(menu_items)
106                         menu_items.connect("activate", self.view_sql_history, None)
107
108                         menu_items = gtk.MenuItem(_("SQL optimize"))
109                         dateimenu.append(menu_items)
110                         menu_items.connect("activate", self.optimizeSQL, None)
111
112                         menu_items = gtk.MenuItem(_("Sync items"))
113                         dateimenu.append(menu_items)
114                         menu_items.connect("activate", self.sync_notes, None)
115
116                         menu_items = gtk.MenuItem(_("Quit"))
117                         dateimenu.append(menu_items)
118                         menu_items.connect("activate", self.destroy, None)
119                         #menu_items.show()
120
121                         datei_menu = gtk.MenuItem(_("File"))
122                         datei_menu.show()
123                         datei_menu.set_submenu(dateimenu)
124
125                         toolsmenu = gtk.Menu()
126
127                         menu_items = gtk.MenuItem(_("Choose columns"))
128                         toolsmenu.append(menu_items)
129                         menu_items.connect("activate", self.show_columns_dialog, None)
130
131                         menu_items = gtk.MenuItem(_("Rename Category"))
132                         toolsmenu.append(menu_items)
133                         menu_items.connect("activate", self.bottombar.rename_category, None)
134
135                         menu_items = gtk.MenuItem(_("Rename List"))
136                         toolsmenu.append(menu_items)
137                         menu_items.connect("activate", self.bottombar.rename_list, None)
138
139                         tools_menu = gtk.MenuItem(_("Tools"))
140                         tools_menu.show()
141                         tools_menu.set_submenu(toolsmenu)
142
143                         hilfemenu = gtk.Menu()
144                         menu_items = gtk.MenuItem(_("About"))
145                         hilfemenu.append(menu_items)
146                         menu_items.connect("activate", self.show_about, None)
147
148                         hilfe_menu = gtk.MenuItem(_("Help"))
149                         hilfe_menu.show()
150                         hilfe_menu.set_submenu(hilfemenu)
151
152                         menu_bar = gtk.MenuBar()
153                         menu_bar.show()
154                         menu_bar.append (datei_menu)
155                         menu_bar.append (tools_menu)
156                         # unten -> damit als letztes menu_bar.append (hilfe_menu)
157                         #Als letztes menü
158                         menu_bar.append (hilfe_menu)
159
160                         self.vbox.pack_start(menu_bar, False, False, 0)
161                 else:
162                         menuBar = gtk.MenuBar()
163                         menuBar.show()
164                         self.vbox.pack_start(menuBar, False, False, 0)
165
166                 #add to vbox below (to get it on top)
167                 self.vbox.pack_end(self.bottombar, expand=False, fill=True, padding=0)
168                 self.vbox.pack_end(self.view, expand=True, fill=True, padding=0)
169                 self.vbox.pack_end(self.selection, expand=False, fill=True, padding=0)
170
171                 #Get the Main Window, and connect the "destroy" event
172                 self.window.add(self.vbox)
173
174                 self.window = hildonize.hildonize_window(self, self.window)
175                 hildonize.set_application_title(self.window, "%s" % constants.__pretty_app_name__)
176                 menu_bar = hildonize.hildonize_menu(
177                         self.window,
178                         menu_bar,
179                 )
180                 if hildonize.IS_FREMANTLE_SUPPORTED:
181                         pass
182
183                 if not hildonize.IS_HILDON_SUPPORTED:
184                         _moduleLogger.info("No hildonization support")
185
186                 if osso is not None:
187                         self.osso_c = osso.Context(
188                                 constants.__app_name__,
189                                 constants.__version__,
190                                 False
191                         )
192                 else:
193                         _moduleLogger.info("No osso support")
194                         self._osso_c = None
195
196                 self.window.connect("delete_event", self.delete_event)
197                 self.window.connect("destroy", self.destroy)
198                 self.window.connect("key-press-event", self.on_key_press)
199                 self.window.connect("window-state-event", self.on_window_state_change)
200
201                 self.window.show_all()
202                 self.prepare_sync_dialog()
203                 self.ladeAlles()
204
205         def on_key_press(self, widget, event, *args):
206                 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
207                 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
208                 if (
209                         event.keyval == gtk.keysyms.F6 or
210                         event.keyval in RETURN_TYPES and isCtrl
211                 ):
212                         # The "Full screen" hardware key has been pressed 
213                         if self.window_in_fullscreen:
214                                 self.window.unfullscreen ()
215                         else:
216                                 self.window.fullscreen ()
217                         return True
218                 #elif event.keyval == gtk.keysyms.f and isCtrl:
219                 #       self._toggle_search()
220                 #       return True
221                 elif (
222                         event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
223                         event.get_state() & gtk.gdk.CONTROL_MASK
224                 ):
225                         self._window.destroy()
226                 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
227                         with open(constants._user_logpath_, "r") as f:
228                                 logLines = f.xreadlines()
229                                 log = "".join(logLines)
230                                 self._clipboard.set_text(str(log))
231                         return True
232
233         def on_window_state_change(self, widget, event, *args):
234                 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
235                         self.window_in_fullscreen = True
236                 else:
237                         self.window_in_fullscreen = False
238
239         def speichereAlles(self,data=None,data2=None):
240                 logging.info("Speichere alles")
241
242         def ladeAlles(self,data=None,data2=None):
243                 logging.info("Lade alles")
244
245         def beforeSync(self,data=None,data2=None):
246                 logging.info("Lade alles")
247
248         def sync_finished(self,data=None,data2=None):
249                 self.selection.comboList_changed()
250                 self.selection.comboCategory_changed()
251                 self.liststorehandler.update_list()
252
253         def prepare_sync_dialog(self):
254                 self.sync_dialog = gtk.Dialog(_("Sync"),None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
255
256                 self.sync_dialog.set_position(gtk.WIN_POS_CENTER)
257                 sync=libsync.Sync(self.db,self.window,50503)
258                 sync.connect("syncFinished",self.sync_finished)
259                 self.sync_dialog.vbox.pack_start(sync, True, True, 0)
260                 self.sync_dialog.set_size_request(500,350)
261                 self.sync_dialog.vbox.show_all()
262                 sync.connect("syncFinished",self.sync_finished)
263
264         def sync_notes(self,widget=None,data=None):
265                 if self.sync_dialog==None:
266                         self.prepare_sync_dialog()
267                 self.sync_dialog.run()
268                 self.sync_dialog.hide()
269
270         def show_columns_dialog(self,widget=None,data=None):
271                 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))
272
273                 col_dialog.set_position(gtk.WIN_POS_CENTER)
274                 cols=libview.Columns_dialog(self.db,self.liststorehandler)
275
276                 col_dialog.vbox.pack_start(cols, True, True, 0)
277                 col_dialog.set_size_request(500,350)
278                 col_dialog.vbox.show_all()
279
280                 resp=col_dialog.run()
281                 col_dialog.hide()
282                 if resp==gtk.RESPONSE_ACCEPT:
283                         logging.info("changing columns")
284                         cols.save_column_setting()
285                         self.view.reload_view()
286                         #children=self.vbox.get_children()
287                         #while len(children)>1:
288                         #       self.vbox.remove(children[1])
289
290                         #self.vbox.pack_end(self.bottombar, expand=True, fill=True, padding=0)
291                         #self.vbox.pack_end(view, expand=True, fill=True, padding=0)
292                         #self.vbox.pack_end(self.selection, expand=False, fill=True, padding=0)
293
294                 col_dialog.destroy()
295
296         def destroy(self, widget=None, data=None):
297                 try:
298                         self.speichereAlles()
299                         self.db.close()
300                         try:
301                                 self._osso_c.close()
302                         except AttributeError:
303                                 pass # Either None or close was removed (in Fremantle)
304                 finally:
305                         gtk.main_quit()
306
307         def delete_event(self, widget, event, data=None):
308                 #print "delete event occurred"
309                 return False
310
311         def dlg_delete(self,widget,event,data=None):
312                 return False
313
314         def show_about(self, widget=None,data=None):
315                 dialog = gtk.AboutDialog()
316                 dialog.set_position(gtk.WIN_POS_CENTER)
317                 dialog.set_name(constants.__pretty_app_name__)
318                 dialog.set_version(constants.__version__)
319                 dialog.set_copyright("")
320                 dialog.set_website("http://axique.de/f=Multilist")
321                 comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
322                 dialog.set_comments(comments)
323                 dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
324                 dialog.run()
325                 dialog.destroy()
326
327         def on_info1_activate(self,menuitem):
328                 self.show_about(menuitem)
329
330         def view_sql_history(self,widget=None,data=None,data2=None):
331                 sqldiag=libsqldialog.sqlDialog(self.db)
332                 res=sqldiag.run()
333                 sqldiag.hide()
334                 if res==444:
335                         logging.info("exporting sql")
336
337                         if not isHildon:
338                                 dlg = gtk.FileChooserDialog(
339                                         parent = self.window,
340                                         action = gtk.FILE_CHOOSER_ACTION_SAVE
341                                 )
342                                 dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
343                                 dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
344                         else:
345                                 #dlg = hildon.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
346                                 dlg=hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
347
348                         dlg.set_title(_("Select SQL export file"))
349                         if dlg.run() == gtk.RESPONSE_OK:
350                                 fileName = dlg.get_filename()
351                                 dlg.destroy()
352                                 sqldiag.exportSQL(fileName)
353                         else:
354                                 dlg.destroy()
355
356                 sqldiag.destroy()
357
358         def optimizeSQL(self,widget=None,data=None,data2=None):
359                 #optimiere sql
360                 self.db.speichereSQL("VACUUM",log=False)
361
362         def select_db_dialog(self,widget=None,data=None,data2=None):
363                 if (isHildon==False):
364                         dlg = gtk.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
365                         dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
366                         dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
367                 else:
368                         #dlg = hildon.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
369                         dlg=hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
370
371                 if self.db.ladeDirekt('datenbank'):
372                         dlg.set_filename(self.db.ladeDirekt('datenbank'))
373                 dlg.set_title(_("Choose your database file"))
374                 if dlg.run() == gtk.RESPONSE_OK:
375                         fileName = dlg.get_filename()
376                         self.db.speichereDirekt('datenbank',fileName)
377                         self.speichereAlles()
378                         self.db.openDB()
379                         self.ladeAlles()
380                 dlg.destroy()
381
382
383 def run_multilist():
384         if hildonize.IS_HILDON_SUPPORTED:
385                 gtk.set_application_name(constants.__pretty_app_name__)
386         app = multilistclass()
387         if not PROFILE_STARTUP:
388                 gtk.main()
389
390
391 if __name__ == "__main__":
392         logging.basicConfig(level=logging.DEBUG)
393         run_multilist()