Adding more filtering options
[multilist] / src / multilist_gtk.py
index 4933a11..4cf649c 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
+from __future__ import with_statement
+
 """
 This file is part of Multilist.
 
@@ -22,6 +24,7 @@ Copyright (C) 2008 Christoph Würstle
 
 import os
 import logging
+import ConfigParser
 
 import gtk
 
@@ -78,10 +81,13 @@ class Multilist(hildonize.get_app_class()):
                                raise
 
                self.db = libspeichern.Speichern()
-               self.window_in_fullscreen = False #The window isn't in full screen mode initially.
+               self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
+               self.__isPortrait = False
 
                #Haupt vbox für alle Elemente
                self.window = gtk.Window()
+               self.__settingsWindow = None
+               self.__settingsManager = None
                self.vbox = gtk.VBox(homogeneous = False, spacing = 0)
 
                self.selection = libselection.Selection(self.db, isHildon)
@@ -95,15 +101,15 @@ class Multilist(hildonize.get_app_class()):
                        fileMenu = gtk.Menu()
 
                        menu_items = gtk.MenuItem(_("Choose database file"))
-                       menu_items.connect("activate", self.select_db_dialog, None)
+                       menu_items.connect("activate", self._on_select_db, None)
                        fileMenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("SQL history"))
-                       menu_items.connect("activate", self.view_sql_history, None)
+                       menu_items.connect("activate", self._on_view_sql_history, None)
                        fileMenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("SQL optimize"))
-                       menu_items.connect("activate", self.optimizeSQL, None)
+                       menu_items.connect("activate", self._on_optimize_sql, None)
                        fileMenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("Sync items"))
@@ -111,30 +117,34 @@ class Multilist(hildonize.get_app_class()):
                        fileMenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("Quit"))
-                       menu_items.connect("activate", self.destroy, None)
+                       menu_items.connect("activate", self._on_destroy, None)
                        fileMenu.append(menu_items)
 
                        fileMenuItem = gtk.MenuItem(_("File"))
                        fileMenuItem.show()
                        fileMenuItem.set_submenu(fileMenu)
 
-                       categorymenu = gtk.Menu()
+                       listmenu = gtk.Menu()
 
                        menu_items = gtk.MenuItem(_("Search"))
                        menu_items.connect("activate", self._on_toggle_search)
-                       categorymenu.append(menu_items)
+                       listmenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("Checkout All"))
                        menu_items.connect("activate", self._on_checkout_all)
-                       categorymenu.append(menu_items)
+                       listmenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("Rename List"))
+                       menu_items.connect("activate", self.bottombar.rename_list, None)
+                       listmenu.append(menu_items)
 
                        menu_items = gtk.MenuItem(_("Rename Category"))
                        menu_items.connect("activate", self.bottombar.rename_category, None)
-                       categorymenu.append(menu_items)
+                       listmenu.append(menu_items)
 
-                       category_menu = gtk.MenuItem(_("Category"))
-                       category_menu.show()
-                       category_menu.set_submenu(categorymenu)
+                       listMenuItem = gtk.MenuItem(_("List"))
+                       listMenuItem.show()
+                       listMenuItem.set_submenu(listmenu)
 
                        viewMenu = gtk.Menu()
 
@@ -150,36 +160,25 @@ class Multilist(hildonize.get_app_class()):
                        viewMenuItem.show()
                        viewMenuItem.set_submenu(viewMenu)
 
-                       toolsMenu = gtk.Menu()
-
-                       menu_items = gtk.MenuItem(_("Rename List"))
-                       menu_items.connect("activate", self.bottombar.rename_list, None)
-                       toolsMenu.append(menu_items)
-
-                       toolsMenuItem = gtk.MenuItem(_("Tools"))
-                       toolsMenuItem.show()
-                       toolsMenuItem.set_submenu(toolsMenu)
-
                        helpMenu = gtk.Menu()
                        menu_items = gtk.MenuItem(_("About"))
                        helpMenu.append(menu_items)
-                       menu_items.connect("activate", self.show_about, None)
+                       menu_items.connect("activate", self._on_about, None)
 
                        helpMenuItem = gtk.MenuItem(_("Help"))
                        helpMenuItem.show()
                        helpMenuItem.set_submenu(helpMenu)
 
-                       menu_bar = gtk.MenuBar()
-                       menu_bar.show()
-                       menu_bar.append (fileMenuItem)
-                       menu_bar.append (toolsMenuItem)
-                       menu_bar.append (category_menu)
-                       menu_bar.append (viewMenuItem)
-                       # unten -> damit als letztes menu_bar.append (helpMenuItem)
+                       menuBar = gtk.MenuBar()
+                       menuBar.show()
+                       menuBar.append (fileMenuItem)
+                       menuBar.append (listMenuItem)
+                       menuBar.append (viewMenuItem)
+                       # unten -> damit als letztes menuBar.append (helpMenuItem)
                        #Als letztes menü
-                       menu_bar.append (helpMenuItem)
+                       menuBar.append (helpMenuItem)
 
-                       self.vbox.pack_start(menu_bar, False, False, 0)
+                       self.vbox.pack_start(menuBar, False, False, 0)
                else:
                        menuBar = gtk.MenuBar()
                        menuBar.show()
@@ -196,9 +195,9 @@ class Multilist(hildonize.get_app_class()):
 
                self.window = hildonize.hildonize_window(self, self.window)
                hildonize.set_application_title(self.window, "%s" % constants.__pretty_app_name__)
-               menu_bar = hildonize.hildonize_menu(
+               menuBar = hildonize.hildonize_menu(
                        self.window,
-                       menu_bar,
+                       menuBar,
                )
                if hildonize.IS_FREMANTLE_SUPPORTED:
                        button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, None)
@@ -209,19 +208,31 @@ class Multilist(hildonize.get_app_class()):
                        filterGroup = button
 
                        button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup)
+                       button.set_label("New")
+                       menuBar.add_filter(button)
+                       button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_NEW)
+                       button.set_mode(False)
+
+                       button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup)
                        button.set_label("Active")
                        menuBar.add_filter(button)
                        button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ACTIVE)
                        button.set_mode(False)
 
-                       renameCategoryButton = gtk.Button(_("Rename Category"))
-                       renameCategoryButton.connect("clicked", self.bottombar.rename_category)
-                       menuBar.append(renameCategoryButton)
+                       button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup)
+                       button.set_label("Done")
+                       menuBar.add_filter(button)
+                       button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_COMPLETE)
+                       button.set_mode(False)
 
                        renameListButton= gtk.Button(_("Rename List"))
                        renameListButton.connect("clicked", self.bottombar.rename_list)
                        menuBar.append(renameListButton)
 
+                       renameCategoryButton = gtk.Button(_("Rename Category"))
+                       renameCategoryButton.connect("clicked", self.bottombar.rename_category)
+                       menuBar.append(renameCategoryButton)
+
                        searchButton= gtk.Button(_("Search Category"))
                        searchButton.connect("clicked", self._on_toggle_search)
                        menuBar.append(searchButton)
@@ -245,16 +256,88 @@ class Multilist(hildonize.get_app_class()):
                        _moduleLogger.info("No osso support")
                        self._osso_c = None
 
-               self.window.connect("delete_event", self.delete_event)
-               self.window.connect("destroy", self.destroy)
+               self.window.connect("delete_event", self._on_delete_event)
+               self.window.connect("destroy", self._on_destroy)
                self.window.connect("key-press-event", self.on_key_press)
-               self.window.connect("window-state-event", self.on_window_state_change)
+               self.window.connect("window-state-event", self._on_window_state_change)
                self._search.connect("search_changed", self._on_search)
 
                self.window.show_all()
                self._search.hide()
-               self.prepare_sync_dialog()
-               self.ladeAlles()
+               self._load_settings()
+               self._prepare_sync_dialog()
+
+       def _save_settings(self):
+               config = ConfigParser.SafeConfigParser()
+               self.save_settings(config)
+               with open(self._user_settings, "wb") as configFile:
+                       config.write(configFile)
+
+       def save_settings(self, config):
+               config.add_section(constants.__pretty_app_name__)
+               config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
+               config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
+
+       def _load_settings(self):
+               config = ConfigParser.SafeConfigParser()
+               config.read(self._user_settings)
+               self.load_settings(config)
+
+       def load_settings(self, config):
+               isPortrait = False
+               window_in_fullscreen = False
+               try:
+                       isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
+                       window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
+               except ConfigParser.NoSectionError, e:
+                       _moduleLogger.info(
+                               "Settings file %s is missing section %s" % (
+                                       self._user_settings,
+                                       e.section,
+                               )
+                       )
+
+               if isPortrait ^ self.__isPortrait:
+                       if isPortrait:
+                               orientation = gtk.ORIENTATION_VERTICAL
+                       else:
+                               orientation = gtk.ORIENTATION_HORIZONTAL
+                       self.set_orientation(orientation)
+
+               self.__window_in_fullscreen = window_in_fullscreen
+               if self.__window_in_fullscreen:
+                       self.window.fullscreen()
+               else:
+                       self.window.unfullscreen()
+
+       def _toggle_search(self):
+               if self._search.get_property("visible"):
+                       self._search.hide()
+               else:
+                       self._search.show()
+
+       def set_orientation(self, orientation):
+               if orientation == gtk.ORIENTATION_VERTICAL:
+                       hildonize.window_to_portrait(self.window)
+                       self.bottombar.set_orientation(gtk.ORIENTATION_VERTICAL)
+                       self.selection.set_orientation(gtk.ORIENTATION_VERTICAL)
+                       self.__isPortrait = True
+               elif orientation == gtk.ORIENTATION_HORIZONTAL:
+                       hildonize.window_to_landscape(self.window)
+                       self.bottombar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+                       self.selection.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+                       self.__isPortrait = False
+               else:
+                       raise NotImplementedError(orientation)
+
+       def get_orientation(self):
+               return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
+
+       def _toggle_rotate(self):
+               if self.__isPortrait:
+                       self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+               else:
+                       self.set_orientation(gtk.ORIENTATION_VERTICAL)
 
        @gtk_toolbox.log_exception(_moduleLogger)
        def _on_checkout_all(self, widget):
@@ -268,12 +351,6 @@ class Multilist(hildonize.get_app_class()):
        def _on_click_menu_filter(self, button, val):
                self.liststorehandler.set_filter(val)
 
-       def _toggle_search(self):
-               if self._search.get_property("visible"):
-                       self._search.hide()
-               else:
-                       self._search.show()
-
        @gtk_toolbox.log_exception(_moduleLogger)
        def _on_toggle_search(self, *args):
                self._toggle_search()
@@ -296,11 +373,14 @@ class Multilist(hildonize.get_app_class()):
                        event.keyval in RETURN_TYPES and isCtrl
                ):
                        # The "Full screen" hardware key has been pressed 
-                       if self.window_in_fullscreen:
+                       if self.__window_in_fullscreen:
                                self.window.unfullscreen ()
                        else:
                                self.window.fullscreen ()
                        return True
+               elif event.keyval == gtk.keysyms.r and isCtrl:
+                       self._toggle_rotate()
+                       return True
                elif event.keyval == gtk.keysyms.f and isCtrl:
                        self._toggle_search()
                        return True
@@ -317,71 +397,79 @@ class Multilist(hildonize.get_app_class()):
                        return True
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def on_window_state_change(self, widget, event, *args):
+       def _on_window_state_change(self, widget, event, *args):
                if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
-                       self.window_in_fullscreen = True
+                       self.__window_in_fullscreen = True
                else:
-                       self.window_in_fullscreen = False
-
-       def speichereAlles(self, data = None, data2 = None):
-               logging.info("Speichere alles")
-
-       def ladeAlles(self, data = None, data2 = None):
-               logging.info("Lade alles")
-
-       def beforeSync(self, data = None, data2 = None):
-               logging.info("Lade alles")
+                       self.__window_in_fullscreen = False
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def sync_finished(self, data = None, data2 = None):
+       def _on_sync_finished(self, data = None, data2 = None):
                self.selection.comboList_changed()
                self.selection.comboCategory_changed()
                self.liststorehandler.update_list()
 
-       def prepare_sync_dialog(self):
+       def _prepare_sync_dialog(self):
                self.sync_dialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
                self.sync_dialog.set_position(gtk.WIN_POS_CENTER)
                sync = libsync.Sync(self.db, self.window, 50503)
-               sync.connect("syncFinished", self.sync_finished)
+               sync.connect("syncFinished", self._on_sync_finished)
                self.sync_dialog.vbox.pack_start(sync, True, True, 0)
                self.sync_dialog.set_size_request(500, 350)
                self.sync_dialog.vbox.show_all()
 
        @gtk_toolbox.log_exception(_moduleLogger)
        def sync_notes(self, widget = None, data = None):
-               if self.sync_dialog == None:
-                       self.prepare_sync_dialog()
+               if self.sync_dialog is None:
+                       self._prepare_sync_dialog()
                self.sync_dialog.run()
                self.sync_dialog.hide()
 
        @gtk_toolbox.log_exception(_moduleLogger)
        def _on_settings(self, *args):
-               col_dialog = gtk.Dialog(
-                       _("Settings"),
-                       self.window,
-                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
-                       (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
-               )
+               if self.__settingsWindow is None:
+                       vbox = gtk.VBox()
+                       self.__settingsManager = settings.SettingsDialog(vbox, self.db, self.liststorehandler)
+
+                       self.__settingsWindow = gtk.Window()
+                       self.__settingsWindow.add(vbox)
+                       self.__settingsWindow = hildonize.hildonize_window(self, self.__settingsWindow)
+
+                       self.__settingsWindow.set_title(_("Settings"))
+                       self.__settingsWindow.set_transient_for(self.window)
+                       self.__settingsWindow.set_default_size(*self.window.get_size())
+                       self.__settingsWindow.connect("delete-event", self._on_settings_delete)
+               self.__settingsManager.set_portrait_state(self.__isPortrait)
+               self.__settingsWindow.set_modal(True)
+               self.__settingsWindow.show_all()
 
-               cols = settings.SettingsDialog(col_dialog.vbox, self.db, self.liststorehandler)
-               col_dialog.show_all()
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_settings_delete(self, *args):
+               self.__settingsWindow.emit_stop_by_name("delete-event")
+               self.__settingsWindow.hide()
+               self.__settingsWindow.set_modal(False)
+
+               logging.info("changing columns")
+               self.__settingsManager.save(self.db)
+               self.view.reload_view()
+
+               isPortrait = self.__settingsManager.is_portrait()
+               if isPortrait ^ self.__isPortrait:
+                       if isPortrait:
+                               orientation = gtk.ORIENTATION_VERTICAL
+                       else:
+                               orientation = gtk.ORIENTATION_HORIZONTAL
+                       self.set_orientation(orientation)
 
-               resp = col_dialog.run()
-               try:
-                       col_dialog.hide()
-                       if resp == gtk.RESPONSE_ACCEPT:
-                               logging.info("changing columns")
-                               cols.save(self.db)
-                               self.view.reload_view()
-               finally:
-                       col_dialog.destroy()
+               return True
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def destroy(self, widget = None, data = None):
+       def _on_destroy(self, widget = None, data = None):
                try:
-                       self.speichereAlles()
                        self.db.close()
+                       self._save_settings()
+
                        try:
                                self._osso_c.close()
                        except AttributeError:
@@ -390,32 +478,11 @@ class Multilist(hildonize.get_app_class()):
                        gtk.main_quit()
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def delete_event(self, widget, event, data = None):
-               #print "delete event occurred"
-               return False
-
-       def dlg_delete(self, widget, event, data = None):
+       def _on_delete_event(self, widget, event, data = None):
                return False
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def show_about(self, widget = None, data = None):
-               dialog = gtk.AboutDialog()
-               dialog.set_position(gtk.WIN_POS_CENTER)
-               dialog.set_name(constants.__pretty_app_name__)
-               dialog.set_version(constants.__version__)
-               dialog.set_copyright("")
-               dialog.set_website("http://axique.de/f = Multilist")
-               comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
-               dialog.set_comments(comments)
-               dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
-               dialog.run()
-               dialog.destroy()
-
-       def on_info1_activate(self, menuitem):
-               self.show_about(menuitem)
-
-       @gtk_toolbox.log_exception(_moduleLogger)
-       def view_sql_history(self, widget = None, data = None, data2 = None):
+       def _on_view_sql_history(self, widget = None, data = None, data2 = None):
                sqldiag = sqldialog.SqlDialog(self.db)
                res = sqldiag.run()
                sqldiag.hide()
@@ -447,30 +514,39 @@ class Multilist(hildonize.get_app_class()):
                        sqldiag.destroy()
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def optimizeSQL(self, widget = None, data = None, data2 = None):
+       def _on_optimize_sql(self, widget = None, data = None, data2 = None):
                #optimiere sql
                self.db.speichereSQL("VACUUM", log = False)
 
        @gtk_toolbox.log_exception(_moduleLogger)
-       def select_db_dialog(self, widget = None, data = None, data2 = None):
-               if (isHildon == False):
-                       dlg = gtk.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
-                       dlg.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
-                       dlg.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK)
-               else:
-                       #dlg = hildon.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
-                       dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
+       def _on_select_db(self, widget = None, data = None, data2 = None):
+               dlg = hildon.FileChooserDialog(parent=self._window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
 
                if self.db.ladeDirekt('datenbank'):
                        dlg.set_filename(self.db.ladeDirekt('datenbank'))
                dlg.set_title(_("Choose your database file"))
-               if dlg.run() == gtk.RESPONSE_OK:
-                       fileName = dlg.get_filename()
-                       self.db.speichereDirekt('datenbank', fileName)
-                       self.speichereAlles()
-                       self.db.openDB()
-                       self.ladeAlles()
-               dlg.destroy()
+               resp = dlg.run()
+               try:
+                       if resp == gtk.RESPONSE_OK:
+                               fileName = dlg.get_filename()
+                               self.db.speichereDirekt('datenbank', fileName)
+                               self.db.openDB()
+               finally:
+                       dlg.destroy()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_about(self, widget = None, data = None):
+               dialog = gtk.AboutDialog()
+               dialog.set_position(gtk.WIN_POS_CENTER)
+               dialog.set_name(constants.__pretty_app_name__)
+               dialog.set_version(constants.__version__)
+               dialog.set_copyright("")
+               dialog.set_website("http://axique.de/f = Multilist")
+               comments = "%s is a program to handle multiple lists." % constants.__pretty_app_name__
+               dialog.set_comments(comments)
+               dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <eopage@byu.net> (Blame him for the most recent bugs)"])
+               dialog.run()
+               dialog.destroy()
 
 
 def run_multilist():