Updating source to latest version
authorEd Page <eopage@byu.net>
Thu, 25 Mar 2010 23:48:44 +0000 (18:48 -0500)
committerEd Page <eopage@byu.net>
Thu, 25 Mar 2010 23:48:44 +0000 (18:48 -0500)
15 files changed:
src/__init__.py
src/constants.py [new file with mode: 0644]
src/gtk_toolbox.py [new file with mode: 0644]
src/hildonize.py [new file with mode: 0755]
src/libbottombar.py
src/libliststorehandler.py
src/libselection.py
src/libspeichern.py
src/libsync.py
src/libview.py
src/multilist.py
src/multilist_gtk.py
src/search.py [new file with mode: 0644]
src/settings.py [new file with mode: 0644]
src/sqldialog.py

index 105eaaf..d34b733 100755 (executable)
@@ -1,21 +1,21 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
 
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
 
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
-""" 
+Copyright (C) 2008 Christoph Würstle
+"""
diff --git a/src/constants.py b/src/constants.py
new file mode 100644 (file)
index 0000000..d2e3e84
--- /dev/null
@@ -0,0 +1,9 @@
+import os
+
+__pretty_app_name__ = "Multilist"
+__app_name__ = "multilist"
+__version__ = "0.3.6"
+__build__ = 0
+_data_path_ = os.path.join(os.path.expanduser("~"), ".multilist")
+__app_magic__ = 0xdeadbeef
+_user_logpath_ = "%s/multilist.log" % _data_path_
diff --git a/src/gtk_toolbox.py b/src/gtk_toolbox.py
new file mode 100644 (file)
index 0000000..b81d444
--- /dev/null
@@ -0,0 +1,577 @@
+#!/usr/bin/python
+
+from __future__ import with_statement
+
+import os
+import errno
+import sys
+import time
+import itertools
+import functools
+import contextlib
+import logging
+import threading
+import Queue
+
+import gobject
+import gtk
+
+
+_moduleLogger = logging.getLogger("gtk_toolbox")
+
+
+def get_screen_orientation():
+       width, height = gtk.gdk.get_default_root_window().get_size()
+       if width < height:
+               return gtk.ORIENTATION_VERTICAL
+       else:
+               return gtk.ORIENTATION_HORIZONTAL
+
+
+def orientation_change_connect(handler, *args):
+       """
+       @param handler(orientation, *args) -> None(?)
+       """
+       initialScreenOrientation = get_screen_orientation()
+       orientationAndArgs = list(itertools.chain((initialScreenOrientation, ), args))
+
+       def _on_screen_size_changed(screen):
+               newScreenOrientation = get_screen_orientation()
+               if newScreenOrientation != orientationAndArgs[0]:
+                       orientationAndArgs[0] = newScreenOrientation
+                       handler(*orientationAndArgs)
+
+       rootScreen = gtk.gdk.get_default_root_window()
+       return gtk.connect(rootScreen, "size-changed", _on_screen_size_changed)
+
+
+@contextlib.contextmanager
+def flock(path, timeout=-1):
+       WAIT_FOREVER = -1
+       DELAY = 0.1
+       timeSpent = 0
+
+       acquired = False
+
+       while timeSpent <= timeout or timeout == WAIT_FOREVER:
+               try:
+                       fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
+                       acquired = True
+                       break
+               except OSError, e:
+                       if e.errno != errno.EEXIST:
+                               raise
+               time.sleep(DELAY)
+               timeSpent += DELAY
+
+       assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
+
+       try:
+               yield fd
+       finally:
+               os.unlink(path)
+
+
+@contextlib.contextmanager
+def gtk_lock():
+       gtk.gdk.threads_enter()
+       try:
+               yield
+       finally:
+               gtk.gdk.threads_leave()
+
+
+def find_parent_window(widget):
+       while True:
+               parent = widget.get_parent()
+               if isinstance(parent, gtk.Window):
+                       return parent
+               widget = parent
+
+
+def make_idler(func):
+       """
+       Decorator that makes a generator-function into a function that will continue execution on next call
+       """
+       a = []
+
+       @functools.wraps(func)
+       def decorated_func(*args, **kwds):
+               if not a:
+                       a.append(func(*args, **kwds))
+               try:
+                       a[0].next()
+                       return True
+               except StopIteration:
+                       del a[:]
+                       return False
+
+       return decorated_func
+
+
+def asynchronous_gtk_message(original_func):
+       """
+       @note Idea came from http://www.aclevername.com/articles/python-webgui/
+       """
+
+       def execute(allArgs):
+               args, kwargs = allArgs
+               with gtk_lock():
+                       original_func(*args, **kwargs)
+               return False
+
+       @functools.wraps(original_func)
+       def delayed_func(*args, **kwargs):
+               gobject.idle_add(execute, (args, kwargs))
+
+       return delayed_func
+
+
+def synchronous_gtk_message(original_func):
+       """
+       @note Idea came from http://www.aclevername.com/articles/python-webgui/
+       """
+
+       @functools.wraps(original_func)
+       def immediate_func(*args, **kwargs):
+               with gtk_lock():
+                       return original_func(*args, **kwargs)
+
+       return immediate_func
+
+
+def autostart(func):
+       """
+       >>> @autostart
+       ... def grep_sink(pattern):
+       ...     print "Looking for %s" % pattern
+       ...     while True:
+       ...             line = yield
+       ...             if pattern in line:
+       ...                     print line,
+       >>> g = grep_sink("python")
+       Looking for python
+       >>> g.send("Yeah but no but yeah but no")
+       >>> g.send("A series of tubes")
+       >>> g.send("python generators rock!")
+       python generators rock!
+       >>> g.close()
+       """
+
+       @functools.wraps(func)
+       def start(*args, **kwargs):
+               cr = func(*args, **kwargs)
+               cr.next()
+               return cr
+
+       return start
+
+
+@autostart
+def printer_sink(format = "%s"):
+       """
+       >>> pr = printer_sink("%r")
+       >>> pr.send("Hello")
+       'Hello'
+       >>> pr.send("5")
+       '5'
+       >>> pr.send(5)
+       5
+       >>> p = printer_sink()
+       >>> p.send("Hello")
+       Hello
+       >>> p.send("World")
+       World
+       >>> # p.throw(RuntimeError, "Goodbye")
+       >>> # p.send("Meh")
+       >>> # p.close()
+       """
+       while True:
+               item = yield
+               print format % (item, )
+
+
+@autostart
+def null_sink():
+       """
+       Good for uses like with cochain to pick up any slack
+       """
+       while True:
+               item = yield
+
+
+@autostart
+def comap(function, target):
+       """
+       >>> p = printer_sink()
+       >>> cm = comap(lambda x: x+1, p)
+       >>> cm.send((0, ))
+       1
+       >>> cm.send((1.0, ))
+       2.0
+       >>> cm.send((-2, ))
+       -1
+       """
+       while True:
+               try:
+                       item = yield
+                       mappedItem = function(*item)
+                       target.send(mappedItem)
+               except Exception, e:
+                       _moduleLogger.exception("Forwarding exception!")
+                       target.throw(e.__class__, str(e))
+
+
+def _flush_queue(queue):
+       while not queue.empty():
+               yield queue.get()
+
+
+@autostart
+def queue_sink(queue):
+       """
+       >>> q = Queue.Queue()
+       >>> qs = queue_sink(q)
+       >>> qs.send("Hello")
+       >>> qs.send("World")
+       >>> qs.throw(RuntimeError, "Goodbye")
+       >>> qs.send("Meh")
+       >>> qs.close()
+       >>> print [i for i in _flush_queue(q)]
+       [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
+       """
+       while True:
+               try:
+                       item = yield
+                       queue.put((None, item))
+               except Exception, e:
+                       queue.put((e.__class__, str(e)))
+               except GeneratorExit:
+                       queue.put((GeneratorExit, None))
+                       raise
+
+
+def decode_item(item, target):
+       if item[0] is None:
+               target.send(item[1])
+               return False
+       elif item[0] is GeneratorExit:
+               target.close()
+               return True
+       else:
+               target.throw(item[0], item[1])
+               return False
+
+
+def nonqueue_source(queue, target):
+       isDone = False
+       while not isDone:
+               item = queue.get()
+               isDone = decode_item(item, target)
+               while not queue.empty():
+                       queue.get_nowait()
+
+
+def threaded_stage(target, thread_factory = threading.Thread):
+       messages = Queue.Queue()
+
+       run_source = functools.partial(nonqueue_source, messages, target)
+       thread = thread_factory(target=run_source)
+       thread.setDaemon(True)
+       thread.start()
+
+       # Sink running in current thread
+       return queue_sink(messages)
+
+
+def log_exception(logger):
+
+       def log_exception_decorator(func):
+
+               @functools.wraps(func)
+               def wrapper(*args, **kwds):
+                       try:
+                               return func(*args, **kwds)
+                       except Exception:
+                               logger.exception(func.__name__)
+
+               return wrapper
+
+       return log_exception_decorator
+
+
+class LoginWindow(object):
+
+       def __init__(self, widgetTree):
+               """
+               @note Thread agnostic
+               """
+               self._dialog = widgetTree.get_widget("loginDialog")
+               self._parentWindow = widgetTree.get_widget("mainWindow")
+               self._serviceCombo = widgetTree.get_widget("serviceCombo")
+               self._usernameEntry = widgetTree.get_widget("usernameentry")
+               self._passwordEntry = widgetTree.get_widget("passwordentry")
+
+               self._serviceList = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
+               self._serviceCombo.set_model(self._serviceList)
+               cell = gtk.CellRendererText()
+               self._serviceCombo.pack_start(cell, True)
+               self._serviceCombo.add_attribute(cell, 'text', 1)
+               self._serviceCombo.set_active(0)
+
+               widgetTree.get_widget("loginbutton").connect("clicked", self._on_loginbutton_clicked)
+               widgetTree.get_widget("logins_close_button").connect("clicked", self._on_loginclose_clicked)
+
+       def request_credentials(self,
+               parentWindow = None,
+               defaultCredentials = ("", "")
+       ):
+               """
+               @note UI Thread
+               """
+               if parentWindow is None:
+                       parentWindow = self._parentWindow
+
+               self._serviceCombo.hide()
+               self._serviceList.clear()
+
+               self._usernameEntry.set_text(defaultCredentials[0])
+               self._passwordEntry.set_text(defaultCredentials[1])
+
+               try:
+                       self._dialog.set_transient_for(parentWindow)
+                       self._dialog.set_default_response(gtk.RESPONSE_OK)
+                       response = self._dialog.run()
+                       if response != gtk.RESPONSE_OK:
+                               raise RuntimeError("Login Cancelled")
+
+                       username = self._usernameEntry.get_text()
+                       password = self._passwordEntry.get_text()
+                       self._passwordEntry.set_text("")
+               finally:
+                       self._dialog.hide()
+
+               return username, password
+
+       def request_credentials_from(self,
+               services,
+               parentWindow = None,
+               defaultCredentials = ("", "")
+       ):
+               """
+               @note UI Thread
+               """
+               if parentWindow is None:
+                       parentWindow = self._parentWindow
+
+               self._serviceList.clear()
+               for serviceIdserviceName in services:
+                       self._serviceList.append(serviceIdserviceName)
+               self._serviceCombo.set_active(0)
+               self._serviceCombo.show()
+
+               self._usernameEntry.set_text(defaultCredentials[0])
+               self._passwordEntry.set_text(defaultCredentials[1])
+
+               try:
+                       self._dialog.set_transient_for(parentWindow)
+                       self._dialog.set_default_response(gtk.RESPONSE_OK)
+                       response = self._dialog.run()
+                       if response != gtk.RESPONSE_OK:
+                               raise RuntimeError("Login Cancelled")
+
+                       username = self._usernameEntry.get_text()
+                       password = self._passwordEntry.get_text()
+               finally:
+                       self._dialog.hide()
+
+               itr = self._serviceCombo.get_active_iter()
+               serviceId = int(self._serviceList.get_value(itr, 0))
+               self._serviceList.clear()
+               return serviceId, username, password
+
+       def _on_loginbutton_clicked(self, *args):
+               self._dialog.response(gtk.RESPONSE_OK)
+
+       def _on_loginclose_clicked(self, *args):
+               self._dialog.response(gtk.RESPONSE_CANCEL)
+
+
+def safecall(f, errorDisplay=None, default=None, exception=Exception):
+       '''
+       Returns modified f. When the modified f is called and throws an
+       exception, the default value is returned
+       '''
+       def _safecall(*args, **argv):
+               try:
+                       return f(*args,**argv)
+               except exception, e:
+                       if errorDisplay is not None:
+                               errorDisplay.push_exception(e)
+                       return default
+       return _safecall
+
+
+class ErrorDisplay(object):
+
+       def __init__(self, widgetTree):
+               super(ErrorDisplay, self).__init__()
+               self.__errorBox = widgetTree.get_widget("errorEventBox")
+               self.__errorDescription = widgetTree.get_widget("errorDescription")
+               self.__errorClose = widgetTree.get_widget("errorClose")
+               self.__parentBox = self.__errorBox.get_parent()
+
+               self.__errorBox.connect("button_release_event", self._on_close)
+
+               self.__messages = []
+               self.__parentBox.remove(self.__errorBox)
+
+       def push_message_with_lock(self, message):
+               with gtk_lock():
+                       self.push_message(message)
+
+       def push_message(self, message):
+               self.__messages.append(message)
+               if 1 == len(self.__messages):
+                       self.__show_message(message)
+
+       def push_exception_with_lock(self):
+               with gtk_lock():
+                       self.push_exception()
+
+       def push_exception(self):
+               userMessage = str(sys.exc_info()[1])
+               self.push_message(userMessage)
+               _moduleLogger.exception(userMessage)
+
+       def pop_message(self):
+               del self.__messages[0]
+               if 0 == len(self.__messages):
+                       self.__hide_message()
+               else:
+                       self.__errorDescription.set_text(self.__messages[0])
+
+       def _on_close(self, *args):
+               self.pop_message()
+
+       def __show_message(self, message):
+               self.__errorDescription.set_text(message)
+               self.__parentBox.pack_start(self.__errorBox, False, False)
+               self.__parentBox.reorder_child(self.__errorBox, 1)
+
+       def __hide_message(self):
+               self.__errorDescription.set_text("")
+               self.__parentBox.remove(self.__errorBox)
+
+
+class DummyErrorDisplay(object):
+
+       def __init__(self):
+               super(DummyErrorDisplay, self).__init__()
+
+               self.__messages = []
+
+       def push_message_with_lock(self, message):
+               self.push_message(message)
+
+       def push_message(self, message):
+               if 0 < len(self.__messages):
+                       self.__messages.append(message)
+               else:
+                       self.__show_message(message)
+
+       def push_exception(self, exception = None):
+               userMessage = str(sys.exc_value)
+               _moduleLogger.exception(userMessage)
+
+       def pop_message(self):
+               if 0 < len(self.__messages):
+                       self.__show_message(self.__messages[0])
+                       del self.__messages[0]
+
+       def __show_message(self, message):
+               _moduleLogger.debug(message)
+
+
+class MessageBox(gtk.MessageDialog):
+
+       def __init__(self, message):
+               parent = None
+               gtk.MessageDialog.__init__(
+                       self,
+                       parent,
+                       gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+                       gtk.MESSAGE_ERROR,
+                       gtk.BUTTONS_OK,
+                       message,
+               )
+               self.set_default_response(gtk.RESPONSE_OK)
+               self.connect('response', self._handle_clicked)
+
+       def _handle_clicked(self, *args):
+               self.destroy()
+
+
+class MessageBox2(gtk.MessageDialog):
+
+       def __init__(self, message):
+               parent = None
+               gtk.MessageDialog.__init__(
+                       self,
+                       parent,
+                       gtk.DIALOG_DESTROY_WITH_PARENT,
+                       gtk.MESSAGE_ERROR,
+                       gtk.BUTTONS_OK,
+                       message,
+               )
+               self.set_default_response(gtk.RESPONSE_OK)
+               self.connect('response', self._handle_clicked)
+
+       def _handle_clicked(self, *args):
+               self.destroy()
+
+
+class PopupCalendar(object):
+
+       def __init__(self, parent, displayDate, title = ""):
+               self._displayDate = displayDate
+
+               self._calendar = gtk.Calendar()
+               self._calendar.select_month(self._displayDate.month, self._displayDate.year)
+               self._calendar.select_day(self._displayDate.day)
+               self._calendar.set_display_options(
+                       gtk.CALENDAR_SHOW_HEADING |
+                       gtk.CALENDAR_SHOW_DAY_NAMES |
+                       gtk.CALENDAR_NO_MONTH_CHANGE |
+                       0
+               )
+               self._calendar.connect("day-selected", self._on_day_selected)
+
+               self._popupWindow = gtk.Window()
+               self._popupWindow.set_title(title)
+               self._popupWindow.add(self._calendar)
+               self._popupWindow.set_transient_for(parent)
+               self._popupWindow.set_modal(True)
+               self._popupWindow.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+               self._popupWindow.set_skip_pager_hint(True)
+               self._popupWindow.set_skip_taskbar_hint(True)
+
+       def run(self):
+               self._popupWindow.show_all()
+
+       def _on_day_selected(self, *args):
+               try:
+                       self._calendar.select_month(self._displayDate.month, self._displayDate.year)
+                       self._calendar.select_day(self._displayDate.day)
+               except Exception, e:
+                       _moduleLogger.exception(e)
+
+
+if __name__ == "__main__":
+       if False:
+               import datetime
+               cal = PopupCalendar(None, datetime.datetime.now())
+               cal._popupWindow.connect("destroy", lambda w: gtk.main_quit())
+               cal.run()
+
+       gtk.main()
diff --git a/src/hildonize.py b/src/hildonize.py
new file mode 100755 (executable)
index 0000000..77d585a
--- /dev/null
@@ -0,0 +1,741 @@
+#!/usr/bin/env python
+
+"""
+Open Issues
+       @bug not all of a message is shown
+       @bug Buttons are too small
+"""
+
+
+import gobject
+import gtk
+import dbus
+
+
+class _NullHildonModule(object):
+       pass
+
+
+try:
+       import hildon as _hildon
+       hildon  = _hildon # Dumb but gets around pyflakiness
+except (ImportError, OSError):
+       hildon = _NullHildonModule
+
+
+IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
+
+
+class _NullHildonProgram(object):
+
+       def add_window(self, window):
+               pass
+
+
+def _hildon_get_app_class():
+       return hildon.Program
+
+
+def _null_get_app_class():
+       return _NullHildonProgram
+
+
+try:
+       hildon.Program
+       get_app_class = _hildon_get_app_class
+except AttributeError:
+       get_app_class = _null_get_app_class
+
+
+def _hildon_set_application_title(window, title):
+       pass
+
+
+def _null_set_application_title(window, title):
+       window.set_title(title)
+
+
+if IS_HILDON_SUPPORTED:
+       set_application_title = _hildon_set_application_title
+else:
+       set_application_title = _null_set_application_title
+
+
+def _fremantle_hildonize_window(app, window):
+       oldWindow = window
+       newWindow = hildon.StackableWindow()
+       oldWindow.get_child().reparent(newWindow)
+       app.add_window(newWindow)
+       return newWindow
+
+
+def _hildon_hildonize_window(app, window):
+       oldWindow = window
+       newWindow = hildon.Window()
+       oldWindow.get_child().reparent(newWindow)
+       app.add_window(newWindow)
+       return newWindow
+
+
+def _null_hildonize_window(app, window):
+       return window
+
+
+try:
+       hildon.StackableWindow
+       hildonize_window = _fremantle_hildonize_window
+except AttributeError:
+       try:
+               hildon.Window
+               hildonize_window = _hildon_hildonize_window
+       except AttributeError:
+               hildonize_window = _null_hildonize_window
+
+
+def _fremantle_hildonize_menu(window, gtkMenu):
+       appMenu = hildon.AppMenu()
+       window.set_app_menu(appMenu)
+       gtkMenu.get_parent().remove(gtkMenu)
+       return appMenu
+
+
+def _hildon_hildonize_menu(window, gtkMenu):
+       hildonMenu = gtk.Menu()
+       for child in gtkMenu.get_children():
+               child.reparent(hildonMenu)
+       window.set_menu(hildonMenu)
+       gtkMenu.destroy()
+       return hildonMenu
+
+
+def _null_hildonize_menu(window, gtkMenu):
+       return gtkMenu
+
+
+try:
+       hildon.AppMenu
+       GTK_MENU_USED = False
+       IS_FREMANTLE_SUPPORTED = True
+       hildonize_menu = _fremantle_hildonize_menu
+except AttributeError:
+       GTK_MENU_USED = True
+       IS_FREMANTLE_SUPPORTED = False
+       if IS_HILDON_SUPPORTED:
+               hildonize_menu = _hildon_hildonize_menu
+       else:
+               hildonize_menu = _null_hildonize_menu
+
+
+def _hildon_set_button_auto_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
+
+
+def _null_set_button_auto_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_AUTO_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_auto_selectable = _hildon_set_button_auto_selectable
+except AttributeError:
+       set_button_auto_selectable = _null_set_button_auto_selectable
+
+
+def _hildon_set_button_finger_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
+
+
+def _null_set_button_finger_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_FINGER_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_finger_selectable = _hildon_set_button_finger_selectable
+except AttributeError:
+       set_button_finger_selectable = _null_set_button_finger_selectable
+
+
+def _hildon_set_button_thumb_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
+
+
+def _null_set_button_thumb_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_THUMB_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_thumb_selectable = _hildon_set_button_thumb_selectable
+except AttributeError:
+       set_button_thumb_selectable = _null_set_button_thumb_selectable
+
+
+def _hildon_set_cell_thumb_selectable(renderer):
+       renderer.set_property("scale", 1.5)
+
+
+def _null_set_cell_thumb_selectable(renderer):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
+else:
+       set_cell_thumb_selectable = _null_set_cell_thumb_selectable
+
+
+def _hildon_set_pix_cell_thumb_selectable(renderer):
+       renderer.set_property("stock-size", 48)
+
+
+def _null_set_pix_cell_thumb_selectable(renderer):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
+else:
+       set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
+
+
+def _fremantle_show_information_banner(parent, message):
+       hildon.hildon_banner_show_information(parent, "", message)
+
+
+def _hildon_show_information_banner(parent, message):
+       hildon.hildon_banner_show_information(parent, None, message)
+
+
+def _null_show_information_banner(parent, message):
+       pass
+
+
+if IS_FREMANTLE_SUPPORTED:
+       show_information_banner = _fremantle_show_information_banner
+else:
+       try:
+               hildon.hildon_banner_show_information
+               show_information_banner = _hildon_show_information_banner
+       except AttributeError:
+               show_information_banner = _null_show_information_banner
+
+
+def _fremantle_show_busy_banner_start(parent, message):
+       hildon.hildon_gtk_window_set_progress_indicator(parent, True)
+       return parent
+
+
+def _fremantle_show_busy_banner_end(banner):
+       hildon.hildon_gtk_window_set_progress_indicator(banner, False)
+
+
+def _hildon_show_busy_banner_start(parent, message):
+       return hildon.hildon_banner_show_animation(parent, None, message)
+
+
+def _hildon_show_busy_banner_end(banner):
+       banner.destroy()
+
+
+def _null_show_busy_banner_start(parent, message):
+       return None
+
+
+def _null_show_busy_banner_end(banner):
+       assert banner is None
+
+
+try:
+       hildon.hildon_gtk_window_set_progress_indicator
+       show_busy_banner_start = _fremantle_show_busy_banner_start
+       show_busy_banner_end = _fremantle_show_busy_banner_end
+except AttributeError:
+       try:
+               hildon.hildon_banner_show_animation
+               show_busy_banner_start = _hildon_show_busy_banner_start
+               show_busy_banner_end = _hildon_show_busy_banner_end
+       except AttributeError:
+               show_busy_banner_start = _null_show_busy_banner_start
+               show_busy_banner_end = _null_show_busy_banner_end
+
+
+def _hildon_hildonize_text_entry(textEntry):
+       textEntry.set_property('hildon-input-mode', 7)
+
+
+def _null_hildonize_text_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_text_entry = _hildon_hildonize_text_entry
+else:
+       hildonize_text_entry = _null_hildonize_text_entry
+
+
+def _hildon_window_to_portrait(window):
+       # gtk documentation is unclear whether this does a "=" or a "|="
+       flags = hildon.PORTRAIT_MODE_SUPPORT | hildon.PORTRAIT_MODE_REQUEST
+       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _hildon_window_to_landscape(window):
+       # gtk documentation is unclear whether this does a "=" or a "&= ~"
+       flags = hildon.PORTRAIT_MODE_SUPPORT
+       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _null_window_to_portrait(window):
+       pass
+
+
+def _null_window_to_landscape(window):
+       pass
+
+
+try:
+       hildon.PORTRAIT_MODE_SUPPORT
+       hildon.PORTRAIT_MODE_REQUEST
+       hildon.hildon_gtk_window_set_portrait_flags
+
+       window_to_portrait = _hildon_window_to_portrait
+       window_to_landscape = _hildon_window_to_landscape
+except AttributeError:
+       window_to_portrait = _null_window_to_portrait
+       window_to_landscape = _null_window_to_landscape
+
+
+def get_device_orientation():
+       bus = dbus.SystemBus()
+       try:
+               rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
+               mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
+               orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
+       except dbus.exception.DBusException:
+               # catching for documentation purposes that when a system doesn't
+               # support this, this is what to expect
+               raise
+
+       if orientation == "":
+               return gtk.ORIENTATION_HORIZONTAL
+       elif orientation == "":
+               return gtk.ORIENTATION_VERTICAL
+       else:
+               raise RuntimeError("Unknown orientation: %s" % orientation)
+
+
+def _hildon_hildonize_password_entry(textEntry):
+       textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
+
+
+def _null_hildonize_password_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_password_entry = _hildon_hildonize_password_entry
+else:
+       hildonize_password_entry = _null_hildonize_password_entry
+
+
+def _hildon_hildonize_combo_entry(comboEntry):
+       comboEntry.set_property('hildon-input-mode', 1 << 4)
+
+
+def _null_hildonize_combo_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_combo_entry = _hildon_hildonize_combo_entry
+else:
+       hildonize_combo_entry = _null_hildonize_combo_entry
+
+
+def _fremantle_hildonize_scrollwindow(scrolledWindow):
+       pannableWindow = hildon.PannableArea()
+
+       child = scrolledWindow.get_child()
+       scrolledWindow.remove(child)
+       pannableWindow.add(child)
+
+       parent = scrolledWindow.get_parent()
+       if parent is not None:
+               parent.remove(scrolledWindow)
+               parent.add(pannableWindow)
+
+       return pannableWindow
+
+
+def _hildon_hildonize_scrollwindow(scrolledWindow):
+       hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
+       return scrolledWindow
+
+
+def _null_hildonize_scrollwindow(scrolledWindow):
+       return scrolledWindow
+
+
+try:
+       hildon.PannableArea
+       hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
+       hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+except AttributeError:
+       try:
+               hildon.hildon_helper_set_thumb_scrollbar
+               hildonize_scrollwindow = _hildon_hildonize_scrollwindow
+               hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+       except AttributeError:
+               hildonize_scrollwindow = _null_hildonize_scrollwindow
+               hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
+
+
+def _hildon_request_number(parent, title, range, default):
+       spinner = hildon.NumberEditor(*range)
+       spinner.set_value(default)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(spinner)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return spinner.get_value()
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+def _null_request_number(parent, title, range, default):
+       adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
+       spinner = gtk.SpinButton(adjustment, 0, 0)
+       spinner.set_wrap(False)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(spinner)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return spinner.get_value_as_int()
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.NumberEditor # TODO deprecated in fremantle
+       request_number = _hildon_request_number
+except AttributeError:
+       request_number = _null_request_number
+
+
+def _hildon_touch_selector(parent, title, items, defaultIndex):
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       for item in items:
+               model.append((item, ))
+
+       selector = hildon.TouchSelector()
+       selector.append_text_column(model, True)
+       selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+       selector.set_active(0, defaultIndex)
+
+       dialog = hildon.PickerDialog(parent)
+       dialog.set_selector(selector)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return selector.get_active(0)
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
+       dialog.response(gtk.RESPONSE_OK)
+       pathData[0] = path
+
+
+def _null_touch_selector(parent, title, items, defaultIndex = -1):
+       parentSize = parent.get_size()
+
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       for item in items:
+               model.append((item, ))
+
+       cell = gtk.CellRendererText()
+       set_cell_thumb_selectable(cell)
+       column = gtk.TreeViewColumn(title)
+       column.pack_start(cell, expand=True)
+       column.add_attribute(cell, "text", 0)
+
+       treeView = gtk.TreeView()
+       treeView.set_model(model)
+       treeView.append_column(column)
+       selection = treeView.get_selection()
+       selection.set_mode(gtk.SELECTION_SINGLE)
+       if 0 < defaultIndex:
+               selection.select_path((defaultIndex, ))
+
+       scrolledWin = gtk.ScrolledWindow()
+       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+       scrolledWin.add(treeView)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(scrolledWin)
+       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+       scrolledWin = hildonize_scrollwindow(scrolledWin)
+       pathData = [None]
+       treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       if pathData[0] is None:
+                               raise RuntimeError("No selection made")
+                       return pathData[0][0]
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.PickerDialog
+       hildon.TouchSelector
+       touch_selector = _hildon_touch_selector
+except AttributeError:
+       touch_selector = _null_touch_selector
+
+
+def _hildon_touch_selector_entry(parent, title, items, defaultItem):
+       # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
+       try:
+               selector = hildon.TouchSelectorEntry(text=True)
+       except TypeError:
+               selector = hildon.hildon_touch_selector_entry_new_text()
+       defaultIndex = -1
+       for i, item in enumerate(items):
+               selector.append_text(item)
+               if item == defaultItem:
+                       defaultIndex = i
+
+       dialog = hildon.PickerDialog(parent)
+       dialog.set_selector(selector)
+
+       if 0 < defaultIndex:
+               selector.set_active(0, defaultIndex)
+       else:
+               selector.get_entry().set_text(defaultItem)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+       finally:
+               dialog.hide()
+
+       if response == gtk.RESPONSE_OK:
+               return selector.get_entry().get_text()
+       elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+               raise RuntimeError("User cancelled request")
+       else:
+               raise RuntimeError("Unrecognized response %r", response)
+
+
+def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
+       custom = entry.get_text().strip()
+       if custom:
+               result[0] = custom
+               selection.unselect_all()
+       else:
+               result[0] = None
+               selection.select_path((defaultIndex, ))
+
+
+def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
+       dialog.response(gtk.RESPONSE_OK)
+       result[0] = customEntry.get_text()
+
+
+def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
+       dialog.response(gtk.RESPONSE_OK)
+       model = treeView.get_model()
+       itr = model.get_iter(path)
+       if itr is not None:
+               result[0] = model.get_value(itr, 0)
+
+
+def _null_touch_selector_entry(parent, title, items, defaultItem):
+       parentSize = parent.get_size()
+
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       defaultIndex = -1
+       for i, item in enumerate(items):
+               model.append((item, ))
+               if item == defaultItem:
+                       defaultIndex = i
+
+       cell = gtk.CellRendererText()
+       set_cell_thumb_selectable(cell)
+       column = gtk.TreeViewColumn(title)
+       column.pack_start(cell, expand=True)
+       column.add_attribute(cell, "text", 0)
+
+       treeView = gtk.TreeView()
+       treeView.set_model(model)
+       treeView.append_column(column)
+       selection = treeView.get_selection()
+       selection.set_mode(gtk.SELECTION_SINGLE)
+
+       scrolledWin = gtk.ScrolledWindow()
+       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+       scrolledWin.add(treeView)
+
+       customEntry = gtk.Entry()
+
+       layout = gtk.VBox()
+       layout.pack_start(customEntry, expand=False)
+       layout.pack_start(scrolledWin)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(layout)
+       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+       scrolledWin = hildonize_scrollwindow(scrolledWin)
+
+       result = [None]
+       if 0 < defaultIndex:
+               selection.select_path((defaultIndex, ))
+               result[0] = defaultItem
+       else:
+               customEntry.set_text(defaultItem)
+
+       customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
+       customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
+       treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       _, itr = selection.get_selected()
+                       if itr is not None:
+                               return model.get_value(itr, 0)
+                       else:
+                               enteredText = customEntry.get_text().strip()
+                               if enteredText:
+                                       return enteredText
+                               elif result[0] is not None:
+                                       return result[0]
+                               else:
+                                       raise RuntimeError("No selection made")
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.PickerDialog
+       hildon.TouchSelectorEntry
+       touch_selector_entry = _hildon_touch_selector_entry
+except AttributeError:
+       touch_selector_entry = _null_touch_selector_entry
+
+
+if __name__ == "__main__":
+       app = get_app_class()()
+
+       label = gtk.Label("Hello World from a Label!")
+
+       win = gtk.Window()
+       win.add(label)
+       win = hildonize_window(app, win)
+       if False and IS_FREMANTLE_SUPPORTED:
+               appMenu = hildon.AppMenu()
+               for i in xrange(5):
+                       b = gtk.Button(str(i))
+                       appMenu.append(b)
+               win.set_app_menu(appMenu)
+               win.show_all()
+               appMenu.show_all()
+               gtk.main()
+       elif False:
+               print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
+       elif False:
+               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
+               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
+       elif False:
+               import pprint
+               name, value = "", ""
+               goodLocals = [
+                       (name, value) for (name, value) in locals().iteritems()
+                       if not name.startswith("_")
+               ]
+               pprint.pprint(goodLocals)
+       elif False:
+               import time
+               show_information_banner(win, "Hello World")
+               time.sleep(5)
+       elif False:
+               import time
+               banner = show_busy_banner_start(win, "Hello World")
+               time.sleep(5)
+               show_busy_banner_end(banner)
index 654c72d..9ea4623 100644 (file)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
 
 
-import gobject
-import time
 import logging
 
 import gtk
 
-class Bottombar(gtk.HBox):
-       
+import gtk_toolbox
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class Bottombar(gtk.VBox):
+
        __gsignals__ = {
-               'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,gobject.TYPE_STRING)),
-               #'changedCategory': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,gobject.TYPE_STRING))
-       }
-
-               
-       def new_item(self,widget=None,data1=None,data2=None):
-               dialog = gtk.Dialog(_("New item name:"),None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
-               
-               dialog.set_position(gtk.WIN_POS_CENTER)
-               entryKlasse=gtk.Entry()
+       }
+
+       def __init__(self, db, view, isHildon):
+               gtk.VBox.__init__(self, homogeneous = False, spacing = 3)
+
+               self.db = db
+               self.isHildon = isHildon
+               self.view = view
+
+               _moduleLogger.info("libBottomBar, init")
+
+               buttonHBox = gtk.HBox()
+               self.pack_start(buttonHBox, expand = False, fill = True, padding = 3)
+
+               button = gtk.Button(stock = gtk.STOCK_ADD)
+               button.connect("clicked", self.new_item, None)
+               buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
+
+               button = gtk.Button(stock = gtk.STOCK_DELETE)
+               button.connect("clicked", self.del_item, None)
+               buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
+
+       def set_orientation(self, orientation):
+               if orientation == gtk.ORIENTATION_HORIZONTAL:
+                       pass
+               elif orientation == gtk.ORIENTATION_VERTICAL:
+                       pass
+               else:
+                       raise NotImplementedError(orientation)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def new_item(self, widget = None, data1 = None, data2 = None):
+               window = gtk_toolbox.find_parent_window(self)
+               dialog = gtk.Dialog(
+                       _("New item name:"),
+                       window,
+                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                       (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
+               )
+
+               entryKlasse = gtk.Entry()
                entryKlasse.set_text("")
-               
                dialog.vbox.pack_start(entryKlasse, True, True, 0)
-               
-               dialog.vbox.show_all()
-               #dialog.set_size_request(400,300)
 
+               dialog.vbox.show_all()
                if dialog.run() == gtk.RESPONSE_ACCEPT:
-                       #logging.info("new category name "+entryKlasse.get_text())
-                       #self.view.liststorehandler.rename_category(entryKlasse.get_text())
                        self.view.liststorehandler.add_row(entryKlasse.get_text())
                dialog.destroy()
 
-               
-       def del_item(self,widget=None,data1=None,data2=None):
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def del_item(self, widget = None, data1 = None, data2 = None):
+               window = gtk_toolbox.find_parent_window(self)
                path, col = self.view.treeview.get_cursor()
-               if path!=None:
-                       mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO,_("Delete current item?")) 
-                       response=mbox.run() 
-                       mbox.hide() 
-                       mbox.destroy() 
-                       if response==gtk.RESPONSE_YES:
-                               self.view.del_active_row()
-               else:
-                       mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_OK,_("No item selected!")) 
-                       response=mbox.run() 
-                       mbox.hide() 
-                       mbox.destroy()                  
-               
-               
-       def checkout_items(self,widget=None,data1=None,data2=None):
-               #self.view.del_active_row()
-               mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO,(_("Really checkout all items?"))) 
-               response=mbox.run() 
-               mbox.hide() 
-               mbox.destroy() 
-               if response==gtk.RESPONSE_YES:
-                       self.view.liststorehandler.checkout_rows()
-                       #n=len(self.view.liststorehandler.get_liststore())
-                       #for i in range(n):
-                       #       self.view.liststorehandler.checkout_rows()
-                       #       #print i
-                       
-       def search_list(self,widget=None,data1=None,data2=None):
-               self.view.liststorehandler.get_liststore(widget.get_text())
-                       
-       
-       def rename_category(self,widget=None,data1=None,data2=None):
-               dialog = gtk.Dialog(_("New category name:"),None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
-               
-               dialog.set_position(gtk.WIN_POS_CENTER)
-               entryKlasse=gtk.Entry()
+               if path is None:
+                       mbox = gtk.MessageDialog(window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("No item selected!"))
+                       response = mbox.run()
+                       mbox.hide()
+                       mbox.destroy()
+                       return
+
+               mbox = gtk.MessageDialog(window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Delete current item?"))
+               response = mbox.run()
+               mbox.hide()
+               mbox.destroy()
+               if response == gtk.RESPONSE_YES:
+                       self.view.del_active_row()
+
+       def rename_category(self, widget = None, data1 = None, data2 = None):
+               window = gtk_toolbox.find_parent_window(self)
+               dialog = gtk.Dialog(
+                       _("New category name:"),
+                       window,
+                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                       (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
+               )
+
+               entryKlasse = gtk.Entry()
                entryKlasse.set_text(self.view.liststorehandler.selection.get_category())
-               
                dialog.vbox.pack_start(entryKlasse, True, True, 0)
-               
-               dialog.vbox.show_all()
-               #dialog.set_size_request(400,300)
 
+               dialog.vbox.show_all()
                if dialog.run() == gtk.RESPONSE_ACCEPT:
-                       logging.info("new category name "+entryKlasse.get_text())
+                       _moduleLogger.info("new category name "+entryKlasse.get_text())
                        self.view.liststorehandler.rename_category(entryKlasse.get_text())
                else:
-                       #print "Cancel",res
                        pass
-               dialog.destroy()
-               
-               
-       def rename_list(self,widget=None,data1=None,data2=None):
-               dialog = gtk.Dialog(_("New list name:"),None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
-               
-               dialog.set_position(gtk.WIN_POS_CENTER)
-               entryKlasse=gtk.Entry()
+               dialog.destroy()
+
+       def rename_list(self, widget = None, data1 = None, data2 = None):
+               window = gtk_toolbox.find_parent_window(self)
+               dialog = gtk.Dialog(
+                       _("New list name:"),
+                       window,
+                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                       (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
+               )
+
+               entryKlasse = gtk.Entry()
                entryKlasse.set_text(self.view.liststorehandler.selection.get_list())
-               
                dialog.vbox.pack_start(entryKlasse, True, True, 0)
-               
-               dialog.vbox.show_all()
-               #dialog.set_size_request(400,300)
 
+               dialog.vbox.show_all()
                if dialog.run() == gtk.RESPONSE_ACCEPT:
-                       logging.info("new list name "+entryKlasse.get_text())
+                       _moduleLogger.info("new list name "+entryKlasse.get_text())
                        self.view.liststorehandler.rename_list(entryKlasse.get_text())
                else:
-                       #print "Cancel",res
                        pass
-               dialog.destroy()
-       
-       def __init__(self,db,view,isHildon):
-               gtk.HBox.__init__(self,homogeneous=False, spacing=3)
-               
-               self.db=db
-               self.isHildon=isHildon
-               self.view=view
-               
-               logging.info("libBottomBar, init")
-                       
-               
-               button=gtk.Button(_("New item"))
-               button.connect("clicked",self.new_item)
-               self.pack_start(button, expand=False, fill=True, padding=0)
-               
-               label=gtk.Label("  ")
-               self.pack_start(label, expand=True, fill=True, padding=0)
-               
-               label=gtk.Label(_("Search:"))
-               self.pack_start(label, expand=False, fill=True, padding=0)
-               searchEntry=gtk.Entry()
-               searchEntry.connect("changed",self.search_list)
-               self.pack_start(searchEntry, expand=True, fill=True, padding=0)
-               
-               label=gtk.Label("  ")
-               self.pack_start(label, expand=True, fill=True, padding=0)
-               
-               button=gtk.Button(_("Checkout all items"))
-               button.connect("clicked",self.checkout_items)
-               self.pack_start(button, expand=False, fill=True, padding=0)
-               
-               button=gtk.Button(_("Del item"))
-               button.connect("clicked",self.del_item)
-               self.pack_start(button, expand=False, fill=True, padding=0)
-               
-               
-               
+               dialog.destroy()
index 933a90c..835c4a6 100644 (file)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
 
-import gtk
-import gobject
-import libspeichern
 import logging
 
+import gtk
+
+import gtk_toolbox
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class Liststorehandler(object):
+
+       SHOW_ALL = "all"
+       SHOW_NEW = "-1"
+       SHOW_ACTIVE = "0"
+       SHOW_COMPLETE = "1"
+       ALL_FILTERS = (SHOW_ALL, SHOW_NEW, SHOW_ACTIVE, SHOW_COMPLETE)
+
+       def __init__(self, db, selection):
+               self.db = db
+               self.__filter = self.SHOW_ALL
+               self.liststore = None
+               self.unitsstore = None
+               self.selection = selection
+               self.collist = ("uid", "status", "title", "quantitiy", "unit", "price", "priority", "date", "private", "stores", "note", "custom1", "custom2")
+
+               sql = "CREATE TABLE items (uid TEXT, list TEXT, category TEXT, status TEXT, title TEXT, quantitiy TEXT, unit TEXT, price TEXT, priority TEXT, date TEXT, pcdate TEXT, private TEXT, stores TEXT, note TEXT, custom1 TEXT, custom2 TEXT)"
+               self.db.speichereSQL(sql)
+
+               self.selection.load()
+               self.selection.connect("changed", self.update_list)
+               #self.selection.connect("changedCategory", self.update_category)
+
+       def set_filter(self, filter):
+               assert filter in self.ALL_FILTERS
+               self.__filter = filter
+               self.update_list()
+
+       def get_filter(self):
+               return self.__filter
 
-class Liststorehandler():
-       
        def get_unitsstore(self):
-               if (self.unitsstore==None):
-                       self.unitsstore=gtk.ListStore(str, str, str,str,str,  str,str, str, str,str, str, str,str)
+               if self.unitsstore is None:
+                       self.unitsstore = gtk.ListStore(str, str, str, str, str,  str, str, str, str, str, str, str, str)
                self.unitsstore.clear()
                #row(3) quantities
                #row 4 units
                #row 6 priority
-               self.unitsstore.append(["-1","-1","","","","","","","","","","",""])    
-               self.unitsstore.append(["-1","-1","","1","g","","0","","","","","",""]) 
-               self.unitsstore.append(["-1","-1","","2","kg","","1","","","","","",""])        
-               self.unitsstore.append(["-1","-1","","3","liter","","2","","","","","",""])     
-               self.unitsstore.append(["-1","-1","","4","packs","","3","","","","","",""])     
-               self.unitsstore.append(["-1","-1","","5","","","4","","","","","",""])  
-               self.unitsstore.append(["-1","-1","","6","","","5","","","","","",""])  
-               self.unitsstore.append(["-1","-1","","7","","","6","","","","","",""])  
-               self.unitsstore.append(["-1","-1","","8","","","7","","","","","",""])  
-               self.unitsstore.append(["-1","-1","","9","","","8","","","","","",""])  
-               self.unitsstore.append(["-1","-1","","","","","9","","","","","",""])   
-               
+               self.unitsstore.append(["-1", "-1", "", "", "", "", "", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "1", "g", "", "0", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "2", "kg", "", "1", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "3", "liter", "", "2", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "4", "packs", "", "3", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "5", "", "", "4", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "6", "", "", "5", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "7", "", "", "6", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "8", "", "", "7", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "9", "", "", "8", "", "", "", "", "", ""])
+               self.unitsstore.append(["-1", "-1", "", "", "", "", "9", "", "", "", "", "", ""])
+
                return self.unitsstore
-               
-               
-       
-       
-       def get_liststore(self,titlesearch=""):
-               if (self.liststore==None):
-                       self.liststore=gtk.ListStore(str, str, str,str,str,  str,str, str, str,str, str, str,str)
+
+       def __calculate_status(self):
+               if self.__filter == self.SHOW_ALL:
+                       status = self.SHOW_NEW
+               else:
+                       status = self.__filter
+               return status
+
+       def get_liststore(self, titlesearch = ""):
+               if (self.liststore == None):
+                       self.liststore = gtk.ListStore(str, str, str, str, str,  str, str, str, str, str, str, str, str)
                self.liststore.clear()
-               
-               titlesearch=titlesearch+"%"
-               
-               
-               if (self.selection.get_status()=="0"): #only 0 and 1 (active items)
-                       sql="SELECT uid,status,title,quantitiy,unit,price,priority,date,private,stores,note,custom1,custom2 FROM items WHERE list=? AND category LIKE ? AND status>=? AND title like ? ORDER BY category, status, title"
-                       rows=self.db.ladeSQL(sql,(self.selection.get_list(),self.selection.get_category(True),self.selection.get_status(),titlesearch))
+
+               titlesearch = titlesearch+"%"
+
+               if self.__filter != self.SHOW_ALL:
+                       status = self.__calculate_status()
+                       sql = "SELECT uid, status, title, quantitiy, unit, price, priority, date, private, stores, note, custom1, custom2 FROM items WHERE list = ? AND category LIKE ? AND status = ? AND title like ? ORDER BY category, status, title"
+                       rows = self.db.ladeSQL(sql, (self.selection.get_list(), self.selection.get_category(True), status, titlesearch))
                else:
-                       sql="SELECT uid,status,title,quantitiy,unit,price,priority,date,private,stores,note,custom1,custom2 FROM items WHERE list=? AND category LIKE ? AND title LIKE ? ORDER BY category, title ASC"
-                       rows=self.db.ladeSQL(sql,(self.selection.get_list(),self.selection.get_category(True),titlesearch))
-                       
-               #print rows
-               if ((rows!=None)and(len(rows)>0)):
+                       sql = "SELECT uid, status, title, quantitiy, unit, price, priority, date, private, stores, note, custom1, custom2 FROM items WHERE list = ? AND category LIKE ? AND title LIKE ? ORDER BY category, title ASC"
+                       rows = self.db.ladeSQL(sql, (self.selection.get_list(), self.selection.get_category(True), titlesearch))
+
+               if rows is not None:
                        for row in rows:
-                               uid,status,title,quantitiy,unit,price,priority,date,private,stores,note,custom1,custom2 = row
-                               if unit==None:
+                               uid, status, title, quantitiy, unit, price, priority, date, private, stores, note, custom1, custom2 = row
+                               if unit == None:
                                        pass
-                                       #unit=""
-                               self.liststore.append([uid,status,title,quantitiy,unit,price,priority,date,private,stores,note,custom1,custom2])
-                       #else:
-                       #self.liststore.append(["-1","-1",""," ","","","","","","","","",""])   
-               #import uuid
-               #self.liststore.append(["-1","-1","","","","","","","","","","",""])
-               
+                                       #unit = ""
+                               self.liststore.append([uid, status, title, quantitiy, unit, price, priority, date, private, stores, note, custom1, custom2])
+
                return self.liststore
-       
-       
+
        def emptyValueExists(self):
                for child in self.liststore:
-                       if child[2]=="":
+                       if child[2] == "":
                                return True
                return False
-               
-       
-
-       def update_row(self,irow,icol,new_text):
-               #print "liststore 1"
-               #for x in self.liststore:
-               #       print x[0],x[2]
-               
-               if (irow>-1)and(self.liststore[irow][0]!="-1")and(self.liststore[irow][0]!=None):
-                       sql = "UPDATE items SET "+self.collist[icol]+"=? WHERE uid=?"
-                       self.db.speichereSQL(sql,(new_text,self.liststore[irow][0]),rowid=self.liststore[irow][0])
-                       
-                       logging.info("Updated row: "+self.collist[icol]+" new text "+new_text+" Titel: "+str(self.liststore[irow][2])+" with uid "+str(self.liststore[irow][0]))
-                       
-                       self.liststore[irow][icol]=new_text 
+
+       def update_row(self, irow, icol, new_text):
+               if -1 < irow and self.liststore[irow][0] != "-1" and self.liststore[irow][0] is not None:
+                       sql = "UPDATE items SET "+self.collist[icol]+" = ? WHERE uid = ?"
+                       self.db.speichereSQL(sql, (new_text, self.liststore[irow][0]), rowid = self.liststore[irow][0])
+
+                       _moduleLogger.info("Updated row: "+self.collist[icol]+" new text "+new_text+" Titel: "+str(self.liststore[irow][2])+" with uid "+str(self.liststore[irow][0]))
+
+                       self.liststore[irow][icol] = new_text
                else:
-                       logging.warning("update_row: row does not exist")
+                       _moduleLogger.warning("update_row: row does not exist")
                        return
-                       #if (self.emptyValueExists()==True)and(icol<2):
-                       #       #print "letzter Eintrag ohne inhalt"
-                       #       return
-                       
-               #print "liststore 2"
-               #for x in self.liststore:
-               #       print x[0],x[2]
-               
-               
+
        def checkout_rows(self):
-               sql = "UPDATE items SET status=? WHERE list=? AND category LIKE ? AND status=?"
-               self.db.speichereSQL(sql,("-1",self.selection.get_list(),self.selection.get_category(True),"1"))
+               sql = "UPDATE items SET status = ? WHERE list = ? AND category LIKE ? AND status = ?"
+               self.db.speichereSQL(sql, (self.SHOW_NEW, self.selection.get_list(), self.selection.get_category(True), self.SHOW_COMPLETE))
                for i in range(len(self.liststore)):
-                       if self.liststore[i][1]=="1":
-                               self.liststore[i][1]="-1"
-                       
-                       
-               
-               
-       def add_row(self,title=""):
-               #self.update_row(-1,1,"-1")
-               #for x in self.liststore:
-               #       print x[0],x[2]
-               status=self.selection.get_status()
+                       if self.liststore[i][1] == self.SHOW_COMPLETE:
+                               self.liststore[i][1] = self.SHOW_NEW
+
+       def add_row(self, title = ""):
+               status = self.__calculate_status()
                import uuid
-               uid=str(uuid.uuid4())
-               sql = "INSERT INTO items (uid,list,category,status, title) VALUES (?,?,?,?,?)"
-               self.db.speichereSQL(sql,(uid,self.selection.get_list(),self.selection.get_category(),status,title),rowid=uid)
-               logging.info("Insertet row: status = "+status+" with uid "+str(uid))
-                       #self.liststore[irow][0]=str(uuid.uuid4())
-                       
-               self.liststore.append([uid,status,title," ","","","","","","","","",""])
+               uid = str(uuid.uuid4())
+               sql = "INSERT INTO items (uid, list, category, status, title) VALUES (?, ?, ?, ?, ?)"
+               self.db.speichereSQL(sql, (uid, self.selection.get_list(), self.selection.get_category(), status, title), rowid = uid)
+               _moduleLogger.info("Insertet row: status = "+status+" with uid "+str(uid))
+
+               self.liststore.append([uid, status, title, " ", "", "", "", "", "", "", "", "", ""])
                self.selection.comboLists_check_for_update()
-               #       if (irow>-1):
-               #               self.liststore[irow][icol]=new_text
-               #               self.liststore[irow][0]=uid
-               #       else:
-               #               self.liststore.append([uid,"-1",""," ","","","","","","","","",""])
-                               #print "xy",self.liststore[len(self.liststore)-1][0]
-                       #Check if a new list/category is opened
-               #       self.selection.comboLists_check_for_update()
-               
-       def del_row(self,irow,row_iter):
-               uid=self.liststore[irow][0]
+
+       def del_row(self, irow, row_iter):
+               uid = self.liststore[irow][0]
                self.liststore.remove(row_iter)
-               sql = "DELETE FROM items WHERE uid=?"
-               self.db.speichereSQL(sql,(uid,))
-               #
-               
-               
-       def get_colname(self,i):
-               if i<len(self.collist):
+               sql = "DELETE FROM items WHERE uid = ?"
+               self.db.speichereSQL(sql, (uid, ))
+
+       def get_colname(self, i):
+               if i < len(self.collist):
                        return self.collist[i]
                else:
                        return None
-               
+
        def get_colcount(self):
                return len(self.collist)
 
-       
-       def rename_category(self,new_name):
-               sql = "UPDATE items SET category=? WHERE list=? AND category=?"
-               self.db.speichereSQL(sql,(new_name,self.selection.get_list(),self.selection.get_category()))
-               self.selection.comboList_changed()
+       def rename_category(self, new_name):
+               sql = "UPDATE items SET category = ? WHERE list = ? AND category = ?"
+               self.db.speichereSQL(sql, (new_name, self.selection.get_list(), self.selection.get_category()))
+               self.selection.update_categories()
                self.selection.set_category(new_name)
-                               
-       def rename_list(self,new_name):
-               sql = "UPDATE items SET list=? WHERE list=?"
-               self.db.speichereSQL(sql,(new_name,self.selection.get_list(),))
+
+       def rename_list(self, new_name):
+               sql = "UPDATE items SET list = ? WHERE list = ?"
+               self.db.speichereSQL(sql, (new_name, self.selection.get_list(), ))
                self.selection.load()
-               self.selection.set_list(new_name)       
-       
-       
-       #def update_category(self,widget=None,data=None,data2=None,data3=None):
+               self.selection.set_list(new_name)
+
+       #@gtk_toolbox.log_exception(_moduleLogger)
+       #def update_category(self, widget = None, data = None, data2 = None, data3 = None):
        #       self.get_liststore()
-               
-       def update_list(self,widget=None,data=None,data2=None,data3=None):
-               self.get_liststore()
-               
-       def __init__(self,db,selection):
-               self.db=db
-               self.liststore=None
-               self.unitsstore=None
-               self.selection=selection
-               self.collist=("uid","status","title","quantitiy","unit","price","priority","date","private","stores","note","custom1","custom2")
-               
-               #sql="DROP TABLE items"
-               #self.db.speichereSQL(sql)
-               
-               sql = "CREATE TABLE items (uid TEXT, list TEXT, category TEXT, status TEXT, title TEXT, quantitiy TEXT, unit TEXT, price TEXT, priority TEXT, date TEXT, pcdate TEXT, private TEXT, stores TEXT, note TEXT, custom1 TEXT, custom2 TEXT)"
-               self.db.speichereSQL(sql)
-               
-               
-               self.selection.load()
-               self.selection.connect("changed",self.update_list)
-               #self.selection.connect("changedCategory",self.update_category)
-               
 
-               """
-               sql = "INSERT INTO items (uid,list,category,title) VALUES (?,?,?,?)"
-               import uuid
-               self.db.speichereSQL(sql,(str(uuid.uuid4()),"default","default","atitel1"))
-               self.db.speichereSQL(sql,(str(uuid.uuid4()),"default","default","btitel2"))
-               self.db.speichereSQL(sql,(str(uuid.uuid4()),"default","default","ctitel3"))
-               
-               print "inserted"
-               """
-
-               
-               
\ No newline at end of file
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def update_list(self, widget = None, data = None, data2 = None, data3 = None):
+               self.get_liststore()
index 9ab8651..b846f68 100644 (file)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
 
 
-import gobject
-import time
 import logging
 
+import gobject
 import gtk
 
+import gtk_toolbox
+import hildonize
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
 class Selection(gtk.HBox):
-       
+
        __gsignals__ = {
-               'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,gobject.TYPE_STRING)),
-               #'changedCategory': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,gobject.TYPE_STRING))
-       }
+               'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING)),
+               #'changedCategory': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING))
+       }
+
+       def __init__(self, db, isHildon):
+               gtk.HBox.__init__(self, homogeneous = False, spacing = 3)
+
+               self.db = db
+               self.isHildon = isHildon
+
+               _moduleLogger.info("libSelection, init")
+
+               self.__listLabel = gtk.Label(_("List:"))
+               self.pack_start(self.__listLabel, expand = False, fill = True, padding = 0)
+
+               self.__lists = []
+               self.__listButton = gtk.Button("")
+               self.__listButton.connect("clicked", self._on_list_selector)
+               self.pack_start(self.__listButton, expand = True, fill = True, padding = 0)
+
+               self.__catLabel = gtk.Label(_("  Category:"))
+               self.pack_start(self.__catLabel, expand = False, fill = True, padding = 0)
+
+               self.__categories = []
+               self.__categoryButton = gtk.Button("")
+               self.__categoryButton.connect("clicked", self._on_category_selector)
+               self.pack_start(self.__categoryButton, expand = True, fill = True, padding = 0)
+
+       def set_orientation(self, orientation):
+               if orientation == gtk.ORIENTATION_HORIZONTAL:
+                       self.__listLabel.show()
+                       self.__catLabel.show()
+               elif orientation == gtk.ORIENTATION_VERTICAL:
+                       self.__listLabel.hide()
+                       self.__catLabel.hide()
+               else:
+                       raise NotImplementedError(orientation)
 
        def load(self):
-               model=self.comboList.get_model()
-               model.clear()
-               #self.comboList.remove(0)
-                       
-               
-               sql="SELECT DISTINCT list FROM items ORDER BY list"
-               rows=self.db.ladeSQL(sql)
-               if ((rows!=None)and(len(rows)>0)):
+               del self.__lists[:]
+
+               sql = "SELECT DISTINCT list FROM items ORDER BY list"
+               rows = self.db.ladeSQL(sql)
+               if rows is not None:
                        for row in rows:
-                               self.comboList.append_text(row[0])
-               else:
-                       self.comboList.append_text("default")
-                       
-               s=self.db.ladeDirekt("comboListText")
-               if s!="":
-                       self.comboList.get_child().set_text(s)
+                               self.__lists.append(row[0])
+               if not self.__lists:
+                       self.__lists.append("default")
+
+               s = self.db.ladeDirekt("comboListText")
+               if s != "":
+                       self.__listButton.set_label(s)
                else:
-                       self.comboList.set_active(0)
-
-       def comboList_changed(self, widget=None, data=None):
-               #self.comboCategory.set_model(None)
-               #print "reload categories"
-               while len(self.comboCategory.get_model())>0:
-                       self.comboCategory.remove_text(0)
-               
-               sql="SELECT DISTINCT category FROM items WHERE list=? ORDER BY category"
-               rows=self.db.ladeSQL(sql,(self.get_list(),))
-               
-               self.comboCategory.append_text(_("all"))
-               if ((rows!=None)and(len(rows)>0)):
+                       self.__listButton.set_label(self.__lists[0])
+
+               self.update_categories()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_category_selector(self, *args):
+               window = gtk_toolbox.find_parent_window(self)
+               userSelection = hildonize.touch_selector_entry(
+                       window,
+                       "Categories",
+                       self.__categories,
+                       self.__categoryButton.get_label(),
+               )
+               self.set_category(userSelection)
+               self.emit("changed", "category", "")
+               self.db.speichereDirekt("comboCategoryText"+self.__listButton.get_label(), self.__categoryButton.get_label())
+               self.update_categories()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_list_selector(self, *args):
+               window = gtk_toolbox.find_parent_window(self)
+               userSelection = hildonize.touch_selector_entry(
+                       window,
+                       "Lists",
+                       self.__lists,
+                       self.__listButton.get_label(),
+               )
+               self.set_list(userSelection)
+
+               self.update_categories()
+
+               self.emit("changed", "list", "")
+               self.db.speichereDirekt("comboListText", self.__listButton.get_label())
+
+       def update_categories(self):
+               del self.__categories[:]
+
+               sql = "SELECT DISTINCT category FROM items WHERE list = ? ORDER BY category"
+               rows = self.db.ladeSQL(sql, (self.get_list(), ))
+
+               self.__categories.append(_("all"))
+               if rows is not None:
                        for row in rows:
-                               if (row[0]!=_("all")):
-                                       self.comboCategory.append_text(row[0])
-               
-               s=self.db.ladeDirekt("comboCategoryText"+self.comboList.get_child().get_text())
+                               if (row[0] != _("all")):
+                                       self.__categories.append(row[0])
+
+               s = self.db.ladeDirekt("comboCategoryText"+self.__listButton.get_label())
                if len(s)>0:
-                       self.comboCategory.get_child().set_text(s)
+                       self.__categoryButton.set_label(s)
                else:
-                       self.comboCategory.set_active(0)
-               
-               self.emit("changed","list","")
-               self.db.speichereDirekt("comboListText",self.comboList.get_child().get_text())
-               
-
-               
-       def comboCategory_changed(self, widget=None, data=None):
-               #logging.info("Klasse geaendert zu ")
-               #self.hauptRegister.set_current_page(0)
-               self.emit("changed","category","")
-               if self.comboCategory.get_active()>-1:
-                       self.db.speichereDirekt("comboCategoryText"+self.comboList.get_child().get_text(),self.comboCategory.get_child().get_text())
-               
-       def radioActive_changed(self, widget, data=None):
-               self.emit("changed","radio","")
+                       self.__categoryButton.set_label(self.__categories[0])
 
        def comboLists_check_for_update(self):
-               if self.comboCategory.get_active()==-1:
-                       model=self.comboCategory.get_model()
-                       found=False
-                       cat=self.get_category()
-                       for x in model:
-                               if x[0]==cat:
-                                       found=True
-                       if found==False:
-                               self.comboCategory.append_text(self.get_category())
-                               self.comboCategory.set_active(len(self.comboCategory.get_model())-1)
-               if self.comboList.get_active()==-1:
-                       model=self.comboList.get_model()
-                       found=False
-                       list=self.get_list()
-                       for x in model:
-                               if x[0]==list:
-                                       found=True
-                       if found==False:
-                               self.comboList.append_text(self.get_list())
-                               self.comboList.set_active(len(self.comboList.get_model())-1)
-               
+               categoryName = self.__categoryButton.get_label()
+               if categoryName not in self.__categories:
+                       self.__categories.append(categoryName)
+
+               listName = self.__listButton.get_label()
+               if listName not in self.__lists:
+                       self.__lists.append(listName)
 
        def lade(self):
-               logging.warning("Laden der aktuellen position noch nicht implementiert")
+               _moduleLogger.warning("Laden der aktuellen position noch nicht implementiert")
 
-       
        def speichere(self):
-               logging.warning("Speichern der aktuellen position noch nicht implementiert")
-       
-       
+               _moduleLogger.warning("Speichern der aktuellen position noch nicht implementiert")
+
        def getIsHildon(self):
                return self.isHildon
-       
-       def get_category(self,select=False):
-               s=self.comboCategory.get_child().get_text()
-               if s==_("all"):
-                       if (select==False):
+
+       def get_category(self, select = False):
+               s = self.__categoryButton.get_label()
+               if s == _("all"):
+                       if not select:
                                return "undefined"
                        else:
                                return "%"
                else:
                        return s
-       def set_category(self,category):
-               self.comboCategory.get_child().set_text(category)
-                       
-       def set_list(self,listname):
-               self.comboList.get_child().set_text(listname)
-               
-       def get_list(self):
-               return self.comboList.get_child().get_text()
 
+       def set_category(self, category):
+               # @bug the old code might have relied on this firing a combo change event
+               self.__categoryButton.set_label(category)
 
-       
-       def get_status(self):
-               #return self.comboCategory.get_child().get_text()
-               if self.radio_all.get_active()==True:
-                       return "-1"
-               else:
-                       return "0"
-               
-       
-       def __init__(self,db,isHildon):
-               gtk.HBox.__init__(self,homogeneous=False, spacing=3)
-               
-               self.db=db
-               self.isHildon=isHildon
-               
-               logging.info("libSelection, init")
-                       
-               
-               label=gtk.Label(_("List:"))
-               self.pack_start(label, expand=False, fill=True, padding=0)
-               
-               self.comboList = gtk.combo_box_entry_new_text()
-               self.comboList.set_size_request(180,-1)
-               self.pack_start(self.comboList, expand=False, fill=True, padding=0)
-                       
-               label=gtk.Label(_("  Category:"))
-               self.pack_start(label, expand=False, fill=True, padding=0)
-               
-               self.comboCategory = gtk.combo_box_entry_new_text()
-               self.comboCategory.set_size_request(180,-1)
-               self.pack_start(self.comboCategory, expand=False, fill=True, padding=0)
-               
-               self.comboList.connect("changed", self.comboList_changed, None)
-               self.comboCategory.connect("changed", self.comboCategory_changed, None)
-               
-               label=gtk.Label(_("  View:"))
-               self.pack_start(label, expand=False, fill=True, padding=0)
-               
-               self.radio_all=gtk.RadioButton(group=None, label=_("All"), use_underline=True)
-               self.pack_start(self.radio_all, expand=False, fill=True, padding=0)
-               self.radio_active=gtk.RadioButton(group=self.radio_all, label=_("Active"), use_underline=True)
-               self.pack_start(self.radio_active, expand=False, fill=True, padding=0)
-               self.radio_all.connect("toggled",self.radioActive_changed, None)
-               
-               
-               
+       def set_list(self, listname):
+               # @bug the old code might have relied on this firing a combo change event
+               self.__listButton.set_label(listname)
+
+       def get_list(self):
+               return self.__listButton.get_label()
index e887340..ebe815b 100644 (file)
@@ -1,23 +1,23 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
 
 import time
@@ -29,96 +29,23 @@ import shutil
 import os
 import logging
 
-class Speichern():
-       def speichereDirekt(self,schluessel,daten):
-               self.d[schluessel]=daten
-               logging.info("speichereDirekt "+str(schluessel)+" "+str(daten)+" lesen: "+str(self.d[schluessel]))
-
-       
-       def ladeDirekt(self,schluessel,default=""):
-               #print "ladeDirekt",schluessel, "Schluessel vorhanden",self.d.has_key(schluessel)
-               if (self.d.has_key(schluessel)==True):
-                       data=self.d[schluessel]
-                       #print data
-                       return data
-               else:
-                       return default
-                               
-                               
-       def speichereSQL(self,sql,tupel=None,commit=True,host="self",log=True,pcdatum=None,rowid=""):
-               #print "speichereSQL:",sql,tupel
-               try:
-                       programSQLError=True
-                       if (tupel==None):
-                               self.cur.execute(sql)
-                       else:
-                               self.cur.execute(sql,tupel)
-                       programSQLError=False   
-                       
-                       #print int(time.time()), sql, pickle.dumps(tupel), host
-                       if (log==True):
-                               strtupel=[]
-                               if (tupel!=None):
-                                       for t in tupel:
-                                               strtupel.append(str(t))
+try:
+       _
+except NameError:
+       _ = lambda x: x
 
 
-                               if pcdatum==None: pcdatum=int(time.time())
-                               self.cur.execute("INSERT INTO logtable ( pcdatum,sql,param,host,rowid ) VALUES (?,?,?,?,?)",(pcdatum, sql, string.join(strtupel," <<Tren-ner>> "), host,str(rowid) ))
-                       if (commit==True): self.conn.commit()
-                       
-                       return True
-               except:
-                       s=str(sys.exc_info())
-                       if (s.find(" already exists")==-1):
-                       #if len(s)>0:
-                               if (programSQLError==True):
-                                       logging.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
-                               else:
-                                       logging.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
-                       return False
+_moduleLogger = logging.getLogger(__name__)
+
+
+class Speichern(object):
+
+       def __init__(self):
+               home_dir = os.path.expanduser('~')
+               filename = os.path.join(home_dir, ".multilist.dat")
+               self.d = shelve.open(filename)
+               self.openDB()
 
-       def commitSQL(self):
-               self.conn.commit()
-               
-               
-       def ladeSQL(self,sql,tupel=None):
-               #print sql,tupel
-               try:
-                       if (tupel==None):
-                               self.cur.execute(sql)
-                       else:
-                               self.cur.execute(sql,tupel)
-                       return self.cur.fetchall()
-               except:
-                       logging.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
-                       return ()
-               
-       def ladeHistory(self,sql_condition,param_condition):
-               sql="SELECT * FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%'"
-               rows=self.ladeSQL(sql)
-               #print rows 
-               i=0
-               erg=[]
-               while i<len(rows):
-                       datum=time.strftime("%d.%m.%y %H:%M:%S", (time.localtime(rows[i][1])))
-                       erg.append([rows[i][1],datum,rows[i][2],rows[i][3],rows[i][3].split(" <<Tren-ner>> ")])
-                                       #pcdatum #datum #sql # Param_org #param 
-                       
-                       i+=1
-                       
-               return erg
-               
-       def delHistory(self,sql_condition,param_condition,exceptTheLastXSeconds=0):
-               pcdatum=int(time.time())-exceptTheLastXSeconds
-               sql="DELETE FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%' AND pcdatum<?"
-               self.speichereSQL(sql,(pcdatum,))
-               
-       def delHistoryWithRowID(self,rowid,sql_condition=" ",exceptTheLastXSeconds=0):
-               pcdatum=int(time.time())-exceptTheLastXSeconds
-               sql="DELETE FROM logtable WHERE rowid=? AND pcdatum<? AND sql LIKE '%"+str(sql_condition)+"%'"
-               self.speichereSQL(sql,(rowid,pcdatum,))
-               
        def openDB(self):
                try:
                        self.cur.close()
@@ -128,50 +55,36 @@ class Speichern():
                        self.conn.close()
                except:
                        pass
-               
-               db=self.ladeDirekt("datenbank")
-               if db=="": 
+
+               db = self.ladeDirekt("datenbank")
+               if db == "":
                        home_dir = os.path.expanduser('~')
-                       db=os.path.join(home_dir, "multilist.s3db") 
-                       
-               
-               datum=time.strftime("%Y-%m-%d--", (time.localtime(time.time())))+str(int(time.time()))+"--"
-               if (os.path.exists(db))and(os.path.exists(os.path.dirname(db)+os.sep+"backup/")):
+                       db = os.path.join(home_dir, "multilist.s3db")
+
+               datum = time.strftime("%Y-%m-%d--", (time.localtime(time.time())))+str(int(time.time()))+"--"
+               if os.path.exists(db) and os.path.exists(os.path.dirname(db)+os.sep+"backup"):
                        try:
-                               shutil.copyfile(db,str(os.path.dirname(db))+os.sep+"backup"+os.sep+datum+os.path.basename(db))
-                               #logging.debug(str(os.path.dirname(db))+os.sep+"backup"+os.sep+datum+os.path.basename(db))
+                               shutil.copyfile(db, str(os.path.dirname(db))+os.sep+"backup"+os.sep+datum+os.path.basename(db))
                        except:
-                               logging.info("Achtung Backup-Datei NICHT (!!!) angelegt!")
-                               #print db,str(os.path.dirname(db))+os.sep+"backup"+os.sep+datum+os.path.basename(db)
-               
-               self.conn = sqlite3.connect(db)         
-               self.cur = self.conn.cursor()
+                               _moduleLogger.info("Achtung Backup-Datei NICHT (!!!) angelegt!")
+
+               self.conn = sqlite3.connect(db)
+               self.cur = self.conn.cursor()
                try:
-                       sql="CREATE TABLE logtable (id INTEGER PRIMARY KEY AUTOINCREMENT, pcdatum INTEGER ,sql TEXT, param TEXT, host TEXT, rowid TEXT)"
+                       sql = "CREATE TABLE logtable (id INTEGER PRIMARY KEY AUTOINCREMENT, pcdatum INTEGER , sql TEXT, param TEXT, host TEXT, rowid TEXT)"
                        self.cur.execute(sql)
-                       self.conn.commit()
+                       self.conn.commit()
                except:
                        pass
-               
+
                #Add rowid line (not in old versions included)
                try:
-                       sql="ALTER TABLE logtable ADD rowid TEXT"
+                       sql = "ALTER TABLE logtable ADD rowid TEXT"
                        self.cur.execute(sql)
-                       self.conn.commit()
+                       self.conn.commit()
                except:
                        pass
-               
-               
-       def __init__(self):
-               home_dir = os.path.expanduser('~')
-               filename=os.path.join(home_dir, ".multilist.dat") 
-               self.d = shelve.open(filename)
-               self.openDB()
 
-       
-
-               
-               
        def close(self):
                try:
                        self.d.close()
@@ -185,7 +98,83 @@ class Speichern():
                        self.conn.close()
                except:
                        pass
-               logging.info("Alle Daten gespeichert")
-               
+               _moduleLogger.info("Alle Daten gespeichert")
+
        def __del__(self):
-               self.close()
\ No newline at end of file
+               self.close()
+
+       def speichereDirekt(self, schluessel, daten):
+               self.d[schluessel] = daten
+               _moduleLogger.info("speichereDirekt "+str(schluessel)+" "+str(daten)+" lesen: "+str(self.d[schluessel]))
+
+       def ladeDirekt(self, schluessel, default = ""):
+               if self.d.has_key(schluessel):
+                       data = self.d[schluessel]
+                       return data
+               else:
+                       return default
+
+       def speichereSQL(self, sql, tupel = None, commit = True, host = "self", log = True, pcdatum = None, rowid = ""):
+               try:
+                       programSQLError = True
+                       if tupel is None:
+                               self.cur.execute(sql)
+                       else:
+                               self.cur.execute(sql, tupel)
+                       programSQLError = False
+
+                       if log:
+                               strtupel = []
+                               if tupel is not None:
+                                       for t in tupel:
+                                               strtupel.append(str(t))
+
+                               if pcdatum is None:
+                                       pcdatum = int(time.time())
+                               self.cur.execute("INSERT INTO logtable ( pcdatum, sql, param, host, rowid ) VALUES (?, ?, ?, ?, ?)", (pcdatum, sql, string.join(strtupel, " <<Tren-ner>> "), host, str(rowid) ))
+                       if commit:
+                               self.conn.commit()
+                       return True
+               except:
+                       s = str(sys.exc_info())
+                       if s.find(" already exists") == -1:
+                               if programSQLError:
+                                       _moduleLogger.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+                               else:
+                                       _moduleLogger.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+                       return False
+
+       def commitSQL(self):
+               self.conn.commit()
+
+       def ladeSQL(self, sql, tupel = None):
+               try:
+                       if tupel is None:
+                               self.cur.execute(sql)
+                       else:
+                               self.cur.execute(sql, tupel)
+                       return self.cur.fetchall()
+               except:
+                       _moduleLogger.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+                       return ()
+
+       def ladeHistory(self, sql_condition, param_condition):
+               sql = "SELECT * FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%'"
+               rows = self.ladeSQL(sql)
+
+               erg = []
+               for row in rows:
+                       datum = time.strftime("%d.%m.%y %H:%M:%S", (time.localtime(row[1])))
+                       erg.append([row[1], datum, row[2], row[3], row[3].split(" <<Tren-ner>> ")])
+
+               return erg
+
+       def delHistory(self, sql_condition, param_condition, exceptTheLastXSeconds = 0):
+               pcdatum = int(time.time())-exceptTheLastXSeconds
+               sql = "DELETE FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%' AND pcdatum<?"
+               self.speichereSQL(sql, (pcdatum, ))
+
+       def delHistoryWithRowID(self, rowid, sql_condition = " ", exceptTheLastXSeconds = 0):
+               pcdatum = int(time.time())-exceptTheLastXSeconds
+               sql = "DELETE FROM logtable WHERE rowid = ? AND pcdatum<? AND sql LIKE '%"+str(sql_condition)+"%'"
+               self.speichereSQL(sql, (rowid, pcdatum, ))
index a793a16..7851b13 100755 (executable)
 # -*- coding: utf-8 -*-
 
 """
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-import gobject
-import time
-import string
-from SimpleXMLRPCServer import SimpleXMLRPCServer 
-import random
-import socket 
-socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen 
-import xmlrpclib 
+import sys
 import select
-#import fcntl
-import struct
-import gtk
 import uuid
-import sys
+import time
+import string
+from SimpleXMLRPCServer import SimpleXMLRPCServer
+import socket
+import xmlrpclib
 import logging
 
-import libspeichern 
+import gobject
+import gtk
+
+import gtk_toolbox
+
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen 
+
+
 class ProgressDialog(gtk.Dialog):
-       
-       def pulse(self):
-               #self.progressbar.pulse()
-               pass
-       
-       def __init__(self,title=_("Sync process"), parent=None):
-               gtk.Dialog.__init__(self,title,parent,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,())
-               
-               logging.info("ProgressDialog, init")
-               
-               label=gtk.Label(_("Sync process running...please wait"))
+
+       def __init__(self, title = _("Sync process"), parent = None):
+               gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ())
+
+               _moduleLogger.info("ProgressDialog, init")
+
+               label = gtk.Label(_("Sync process running...please wait"))
                self.vbox.pack_start(label, True, True, 0)
-               label=gtk.Label(_("(this can take some minutes)"))
+               label = gtk.Label(_("(this can take some minutes)"))
                self.vbox.pack_start(label, True, True, 0)
-               
-               #self.progressbar=gtk.ProgressBar()
+
+               #self.progressbar = gtk.ProgressBar()
                #self.vbox.pack_start(self.progressbar, True, True, 0)
-               
+
                #self.set_keep_above(True)
-               self.vbox.show_all()
+               self.vbox.show_all()
                self.show()
-class Sync(gtk.VBox): 
-       
+
+       def pulse(self):
+               #self.progressbar.pulse()
+               pass
+
+
+class Sync(gtk.VBox):
+
        __gsignals__ = {
-               'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
-               'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
-       }
-       
-       def changeSyncStatus(self,active,title):
+               'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
+               'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
+       }
+
+       def __init__(self, db, parentwindow, port):
+               gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
+
+               _moduleLogger.info("Sync, init")
+               self.db = db
+               self.progress = None
+               self.server = None
+               self.port = int(port)
+               self.parentwindow = parentwindow
+               self.concernedRows = None
+
+               #print "Sync, 2"
+               #sql = "DROP TABLE sync"
+               #self.db.speichereSQL(sql, log = False)
+
+               sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
+               self.db.speichereSQL(sql, log = False)
+
+               #print "Sync, 3"
+
+               sql = "SELECT uuid, pcdatum FROM sync WHERE syncpartner = ?"
+               rows = self.db.ladeSQL(sql, ("self", )) #Eigene Id feststellen
+
+               #print "Sync, 3a"
+               if (rows == None)or(len(rows) != 1):
+                       sql = "DELETE FROM sync WHERE syncpartner = ?"
+                       self.db.speichereSQL(sql, ("self", ), log = False)
+
+                       #uuid1 = uuid()
+                       #print "Sync, 3b"
+
+                       #print "Sync, 3bb"
+                       self.sync_uuid = str(uuid.uuid4())
+                       sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
+                       self.db.speichereSQL(sql, ("self", str(self.sync_uuid), int(time.time())), log = False)
+                       #print "Sync, 3c"
+               else:
+                       sync_uuid, pcdatum = rows[0]
+                       self.sync_uuid = sync_uuid
+               #print "x1"
+               #print "Sync, 4"
+
+               frame = gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
+               self.comboIP = gtk.combo_box_entry_new_text()
+               self.comboIP.append_text("") #self.get_ip_address("eth0"))
+               #self.comboIP.append_text(self.get_ip_address("eth1")) #fixme
+               #self.comboIP.append_text(self.get_ip_address("eth2"))
+               #self.comboIP.append_text(self.get_ip_address("eth3"))
+               #print "Sync, 4d"
+               #self.comboIP.append_text(self.get_ip_address("wlan0"))
+               #self.comboIP.append_text(self.get_ip_address("wlan1"))
+
+               #print "Sync, 4e"
+
+               frame.add(self.comboIP)
+               serverbutton = gtk.ToggleButton(_("Start SyncServer"))
+               serverbutton.connect("clicked", self.startServer, (None, ))
+               self.pack_start(frame, expand = False, fill = True, padding = 1)
+               self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
+               self.syncServerStatusLabel = gtk.Label(_("Syncserver not running"))
+               self.pack_start(self.syncServerStatusLabel, expand = False, fill = True, padding = 1)
+
+               frame = gtk.Frame(_("RemoteSync-Server (Port ")+str(self.port)+")")
+               self.comboRemoteIP = gtk.combo_box_entry_new_text()
+               self.comboRemoteIP.append_text("192.168.0.?")
+               self.comboRemoteIP.append_text("192.168.1.?")
+               self.comboRemoteIP.append_text("192.168.176.?")
+               frame.add(self.comboRemoteIP)
+               syncbutton = gtk.Button(_("Connect to remote SyncServer"))
+               syncbutton.connect("clicked", self.syncButton, (None, ))
+               self.pack_start(frame, expand = False, fill = True, padding = 1)
+               self.pack_start(syncbutton, expand = False, fill = True, padding = 1)
+               self.syncStatusLabel = gtk.Label(_("no sync process (at the moment)"))
+               self.pack_start(self.syncStatusLabel, expand = False, fill = True, padding = 1)
+
+               #self.comboRemoteIP.set_text_column("Test")
+               self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
+               self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
+
+               #load
+               if (self.db.ladeDirekt("startSyncServer", False) == True):
+                       serverbutton.set_active(True)
+
+       def changeSyncStatus(self, active, title):
                self.syncStatusLabel.set_text(title)
-               if active==True:
-                       if self.progress==None:
-                               self.progress=ProgressDialog(parent=self.parentwindow)
-                               self.emit("syncBeforeStart","syncBeforeStart")
-                               
-                               
+               if active == True:
+                       if self.progress == None:
+                               self.progress = ProgressDialog(parent = self.parentwindow)
+                               self.emit("syncBeforeStart", "syncBeforeStart")
                else:
-                       if self.progress!=None:
-                               self.progress.hide()            
+                       if self.progress is not None:
+                               self.progress.hide()
                                self.progress.destroy()
-                               self.progress=None
-                               self.emit("syncFinished","syncFinished")
-       
+                               self.progress = None
+                               self.emit("syncFinished", "syncFinished")
+
        def pulse(self):
-               if self.progress!=None:
+               if self.progress is not None:
                        self.progress.pulse()
-               #if self.server!=None:
+               #if self.server is not None:
                #       self.server.pulse()
-               
-       
+
        def getUeberblickBox(self):
-               frame=gtk.Frame(_("Query"))
+               frame = gtk.Frame(_("Query"))
                return frame
-                       
+
        def handleRPC(self):
                try:
-                       if (self.rpcserver==None): return False
+                       if self.rpcserver is None:
+                               return False
                except:
                        return False
-                       
-               while (len(self.poll.poll(0))>0):
-                       self.rpcserver.handle_request()
+
+               while 0 < len(self.poll.poll(0)):
+                       self.rpcserver.hande_request()
                return True
 
-       def get_ip_address(self,ifname):
+       def get_ip_address(self, ifname):
                return socket.gethostbyname(socket.gethostname())
                #try:
                #       s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-               #       ip=socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack('256s', ifname[:15]))[20:24])
+               #       ip = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
                #       s.close()
                #except:
-               #       ip=socket.gethostbyname(socket.gethostname())
+               #       ip = socket.gethostbyname(socket.gethostname())
                #       s.close()
-               
+
                #return ip FixME
-               
-       def getLastSyncDate(self,sync_uuid):
-               sql="SELECT syncpartner,pcdatum FROM sync WHERE uuid=?"
-               rows=self.db.ladeSQL(sql,(sync_uuid,))
-               if (rows!=None)and(len(rows)==1): 
-                       syncpartner,pcdatum = rows[0]
+
+       def getLastSyncDate(self, sync_uuid):
+               sql = "SELECT syncpartner, pcdatum FROM sync WHERE uuid = ?"
+               rows = self.db.ladeSQL(sql, (sync_uuid, ))
+               if (rows is not None)and(len(rows) == 1):
+                       syncpartner, pcdatum = rows[0]
                else:
-                       pcdatum=-1
-               logging.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
+                       pcdatum = -1
+               _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
                return pcdatum
-               
-               
-       def check4commit(self,newSQL,lastdate):
-               logging.info("check4commit 1")
-               if self.concernedRows==None:
-                       logging.info("check4commit Updatung concernedRows")
-                       sql="SELECT pcdatum,rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
-                       self.concernedRows=self.db.ladeSQL(sql,(lastdate,))
-                       
-                       
-               if (self.concernedRows!=None)and(len(self.concernedRows)>0):
-                       #logging.info("check4commit 2")
-                       id1, pcdatum,sql, param, host, rowid = newSQL
-                       
+
+       def check4commit(self, newSQL, lastdate):
+               _moduleLogger.info("check4commit 1")
+               if self.concernedRows == None:
+                       _moduleLogger.info("check4commit Updatung concernedRows")
+                       sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
+                       self.concernedRows = self.db.ladeSQL(sql, (lastdate, ))
+
+               if (self.concernedRows is not None)and(len(self.concernedRows)>0):
+                       #_moduleLogger.info("check4commit 2")
+                       id1, pcdatum, sql, param, host, rowid = newSQL
+
                        if len(rowid)>0:
                                for x in self.concernedRows:
-                                       #logging.info("check4commit 3")
-                                       if (x[1]==rowid):
+                                       #_moduleLogger.info("check4commit 3")
+                                       if (x[1] == rowid):
                                                if (x[0]>pcdatum):
-                                                       logging.info("newer sync entry, ignoring old one")
-                                                       #logging.info("check4commit 9.1")
+                                                       _moduleLogger.info("newer sync entry, ignoring old one")
+                                                       #_moduleLogger.info("check4commit 9.1")
                                                        return False
                                                else:
-                                                       #logging.info("check4commit 9.2")
+                                                       #_moduleLogger.info("check4commit 9.2")
                                                        return True
-                                                       
-               #logging.info("check4commit 9.3")
+
+               #_moduleLogger.info("check4commit 9.3")
                return True
-       
-       def writeSQLTupel(self,newSQLs,lastdate):
-               if (newSQLs==None):
-                        return
-               
-               self.concernedRows=None
-               pausenzaehler=0
-               logging.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
+
+       def writeSQLTupel(self, newSQLs, lastdate):
+               if newSQLs is None:
+                       return
+
+               self.concernedRows = None
+               pausenzaehler = 0
+               _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
                for newSQL in newSQLs:
                        #print ""
-                       #print "SQL1: ",newSQL[1]
-                       #print "SQL2: ",newSQL[2]
-                       #print "SQL3: ",newSQL[3]
-                       #print "Param:",string.split(newSQL[3]," <<Tren-ner>> ")
+                       #print "SQL1: ", newSQL[1]
+                       #print "SQL2: ", newSQL[2]
+                       #print "SQL3: ", newSQL[3]
+                       #print "Param:", string.split(newSQL[3], " <<Tren-ner>> ")
                        #print ""
-                       if (newSQL[3]!=""):
-                               param=string.split(newSQL[3]," <<Tren-ner>> ")
+                       if (newSQL[3] != ""):
+                               param = string.split(newSQL[3], " <<Tren-ner>> ")
                        else:
-                               param=None
-               
+                               param = None
+
                        if (len(newSQL)>2):
-                               commitSQL=True
-
-                               if (newSQL[5]!=None)and(len(newSQL[5])>0):
-                                       commitSQL=self.check4commit(newSQL,lastdate)
-                                       
-                               if (commitSQL==True):
-                                       self.db.speichereSQL(newSQL[2],param,commit=False,pcdatum=newSQL[1],rowid=newSQL[5])
-                       else: 
-                               logging.error("writeSQLTupel: Error")
-                               
-                       pausenzaehler+=1
-                       if (pausenzaehler % 10)==0:
+                               commitSQL = True
+
+                               if (newSQL[5] is not None)and(len(newSQL[5])>0):
+                                       commitSQL = self.check4commit(newSQL, lastdate)
+
+                               if commitSQL:
+                                       self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
+                       else:
+                               _moduleLogger.error("writeSQLTupel: Error")
+
+                       pausenzaehler += 1
+                       if (pausenzaehler % 10) == 0:
                                self.pulse()
-                               while (gtk.events_pending()):
-                                       gtk.main_iteration();
-                               
-               logging.info("Alle SQLs an sqlite geschickt, commiting now")
+                               while gtk.events_pending():
+                                       gtk.main_iteration()
+
+               _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now")
                self.db.commitSQL()
-               logging.info("Alle SQLs commited")
-               
-       
-       def doSync(self,sync_uuid,pcdatum,newSQLs,pcdatumjetzt):
-               #print uuid,pcdatum,newSQLs
-               #logging.info("doSync 0")
-               self.changeSyncStatus(True,_("sync process running"))
+               _moduleLogger.info("Alle SQLs commited")
+
+       def doSync(self, sync_uuid, pcdatum, newSQLs, pcdatumjetzt):
+               #print uuid, pcdatum, newSQLs
+               #_moduleLogger.info("doSync 0")
+               self.changeSyncStatus(True, _("sync process running"))
                self.pulse()
-               #logging.info("doSync 1")
-               
-               while (gtk.events_pending()):
-                       gtk.main_iteration();
-               diff=time.time()-pcdatumjetzt
-               if diff<0:
-                       diff=diff*(-1)
-               if diff>30:
+               #_moduleLogger.info("doSync 1")
+
+               while gtk.events_pending():
+                       gtk.main_iteration();
+               diff = abs(time.time() - pcdatumjetzt)
+               if 30 < diff:
                        return -1
-               
-               logging.info("doSync read sqls")
-               sql="SELECT * FROM logtable WHERE pcdatum>?"
-               rows=self.db.ladeSQL(sql,(pcdatum,))
-               logging.info("doSync read sqls")
-               self.writeSQLTupel(newSQLs,pcdatum)
-               logging.info("doSync wrote "+str(len(newSQLs))+" sqls")
-               logging.info("doSync sending "+str(len(rows))+" sqls")
-               i=0
+
+               _moduleLogger.info("doSync read sqls")
+               sql = "SELECT * FROM logtable WHERE pcdatum>?"
+               rows = self.db.ladeSQL(sql, (pcdatum, ))
+               _moduleLogger.info("doSync read sqls")
+               self.writeSQLTupel(newSQLs, pcdatum)
+               _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls")
+               _moduleLogger.info("doSync sending "+str(len(rows))+" sqls")
                return rows
-               
+
        def getRemoteSyncUUID(self):
                return self.sync_uuid
-       
-       
-       def startServer(self, widget, data=None):
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def startServer(self, widget, data = None):
                #Starte RPCServer
-               self.db.speichereDirekt("syncServerIP",self.comboIP.get_child().get_text())
-               
-               if (widget.get_active()==True):
-                       logging.info("Starting Server")
-                       
+               self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text())
+
+               if (widget.get_active() == True):
+                       _moduleLogger.info("Starting Server")
+
                        try:
-                               ip=self.comboIP.get_child().get_text()
-                               self.rpcserver = SimpleXMLRPCServer((ip, self.port),allow_none=True) 
+                               ip = self.comboIP.get_child().get_text()
+                               self.rpcserver = SimpleXMLRPCServer((ip, self.port), allow_none = True)
                                self.rpcserver.register_function(pow)
                                self.rpcserver.register_function(self.getLastSyncDate)
                                self.rpcserver.register_function(self.doSync)
                                self.rpcserver.register_function(self.getRemoteSyncUUID)
                                self.rpcserver.register_function(self.doSaveFinalTime)
                                self.rpcserver.register_function(self.pulse)
-                               self.poll=select.poll()
+                               self.poll = select.poll()
                                self.poll.register(self.rpcserver.fileno())
                                gobject.timeout_add(1000, self.handleRPC)
                                self.syncServerStatusLabel.set_text(_("Syncserver running..."))
-                       
+
                                #save
-                               self.db.speichereDirekt("startSyncServer",True)
-                       
+                               self.db.speichereDirekt("startSyncServer", True)
+
                        except:
-                               s=str(sys.exc_info())
-                               logging.error("libsync: could not start server. Error: "+s)
-                               mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_OK,_("Sync server could not start. Please check IP and port.")) #gtk.DIALOG_MODAL
+                               s = str(sys.exc_info())
+                               _moduleLogger.error("libsync: could not start server. Error: "+s)
+                               mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Sync server could not start. Please check IP and port.")) #gtk.DIALOG_MODAL
                                mbox.set_modal(False)
-                               response=mbox.run() 
-                               mbox.hide() 
-                               mbox.destroy() 
+                               response = mbox.run()
+                               mbox.hide()
+                               mbox.destroy()
                                widget.set_active(False)
-                               
                else:
-                       logging.info("Stopping Server")
+                       _moduleLogger.info("Stopping Server")
                        try:
-                               del self.rpcserver      
+                               del self.rpcserver
                        except:
                                pass
                        self.syncServerStatusLabel.set_text(_("Syncserver not running..."))
                        #save
-                       self.db.speichereDirekt("startSyncServer",False)
-               
-       def doSaveFinalTime(self,sync_uuid,pcdatum=None):
-               if (pcdatum==None): pcdatum=int(time.time())
+                       self.db.speichereDirekt("startSyncServer", False)
+
+       def doSaveFinalTime(self, sync_uuid, pcdatum = None):
+               if pcdatum is None:
+                       pcdatum = int(time.time())
                if (time.time()>pcdatum):
-                       pcdatum=int(time.time()) #größere Zeit nehmen
-                       
+                       pcdatum = int(time.time()) #größere Zeit nehmen
+
                self.pulse()
-               
+
                #fime save time+uuid
-               sql="DELETE FROM sync WHERE uuid=?"
-               self.db.speichereSQL(sql,(sync_uuid,),log=False)
-               sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
-               self.db.speichereSQL(sql,("x",str(sync_uuid),pcdatum),log=False)
+               sql = "DELETE FROM sync WHERE uuid = ?"
+               self.db.speichereSQL(sql, (sync_uuid, ), log = False)
+               sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
+               self.db.speichereSQL(sql, ("x", str(sync_uuid), pcdatum), log = False)
                self.pulse()
-               self.changeSyncStatus(False,_("no sync process (at the moment)"))
-               return (self.sync_uuid,pcdatum)
-               
-       
-       def syncButton(self, widget, data=None):
-               logging.info("Syncing")
-               #sql="DELETE FROM logtable WHERE sql LIKE externeStundenplanung"
+               self.changeSyncStatus(False, _("no sync process (at the moment)"))
+               return (self.sync_uuid, pcdatum)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def syncButton(self, widget, data = None):
+               _moduleLogger.info("Syncing")
+               #sql = "DELETE FROM logtable WHERE sql LIKE externeStundenplanung"
                #self.db.speichereSQL(sql)
-               
-               self.changeSyncStatus(True,_("sync process running"))
+
+               self.changeSyncStatus(True, _("sync process running"))
                while (gtk.events_pending()):
-                       gtk.main_iteration();
+                       gtk.main_iteration()
 
-               self.db.speichereDirekt("syncRemoteIP",self.comboRemoteIP.get_child().get_text())
+               self.db.speichereDirekt("syncRemoteIP", self.comboRemoteIP.get_child().get_text())
                try:
-                       self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port),allow_none=True) 
-                       #lastDate=server.getLastSyncDate(str(self.sync_uuid))
-                       server_sync_uuid=self.server.getRemoteSyncUUID()
-                       lastDate=self.getLastSyncDate(str(server_sync_uuid))
-                       
+                       self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port), allow_none = True)
+                       #lastDate = server.getLastSyncDate(str(self.sync_uuid))
+                       server_sync_uuid = self.server.getRemoteSyncUUID()
+                       lastDate = self.getLastSyncDate(str(server_sync_uuid))
+
                        #print ("LastSyncDate: "+str(lastDate)+" Now: "+str(int(time.time())))
-               
-                       sql="SELECT * FROM logtable WHERE pcdatum>?"
-                       rows=self.db.ladeSQL(sql,(lastDate,))
-                       
-                       logging.info("loaded concerned rows")
-               
-                       newSQLs=self.server.doSync(self.sync_uuid,lastDate,rows,time.time())
-               
-                       logging.info("did do sync, processing sqls now")
-                       if newSQLs!=-1:
-                               self.writeSQLTupel(newSQLs,lastDate)
-       
-                               sync_uuid, finalpcdatum=self.server.doSaveFinalTime(self.sync_uuid)
-                               self.doSaveFinalTime(sync_uuid, finalpcdatum)
-                       
-                               self.changeSyncStatus(False,_("no sync process (at the moment)"))
-                               
-                               mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("Synchronization successfully completed"))
-                               response = mbox.run() 
-                               mbox.hide() 
-                               mbox.destroy() 
-                       else:
-                               logging.warning("Zeitdiff zu groß/oder anderer db-Fehler")
-                               self.changeSyncStatus(False,_("no sync process (at the moment)"))
-                               mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("The clocks are not synchronized between stations"))
-                               response = mbox.run() 
-                               mbox.hide() 
-                               mbox.destroy() 
-               except:
-                               logging.warning("Sync connect failed")
-                               self.changeSyncStatus(False,_("no sync process (at the moment)"))
-                               mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]))
-                               response = mbox.run() 
-                               mbox.hide() 
-                               mbox.destroy() 
-                               self.server=None
-               self.server=None
-                               
-
-                       
-       
-       def __init__(self,db,parentwindow,port):
-               gtk.VBox.__init__(self,homogeneous=False, spacing=0)
-               
-               logging.info("Sync, init")
-               self.db=db
-               self.progress=None
-               self.server=None
-               self.port=int(port)
-               self.parentwindow=parentwindow
-               self.concernedRows=None
-               
-               #print "Sync, 2"
-               #sql = "DROP TABLE sync"
-               #self.db.speichereSQL(sql,log=False)
-               
-               sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
-               self.db.speichereSQL(sql,log=False)
-               
-               #print "Sync, 3"
-               
-               sql="SELECT uuid,pcdatum FROM sync WHERE syncpartner=?"
-               rows=self.db.ladeSQL(sql,("self",)) #Eigene Id feststellen
-               
-               #print "Sync, 3a"
-               if (rows==None)or(len(rows)!=1):
-                       sql="DELETE FROM sync WHERE syncpartner=?"
-                       self.db.speichereSQL(sql,("self",),log=False)
 
-                       #uuid1=uuid()
-                       #print "Sync, 3b"
-                       
-                       #print "Sync, 3bb"
-                       self.sync_uuid=str(uuid.uuid4())
-                       sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
-                       self.db.speichereSQL(sql,("self",str(self.sync_uuid),int(time.time())),log=False)
-                       #print "Sync, 3c"
-               else:
-                       sync_uuid,pcdatum = rows[0]
-                       self.sync_uuid=sync_uuid
-               #print "x1"
-               
-               
-               
-               #print "Sync, 4"
+                       sql = "SELECT * FROM logtable WHERE pcdatum>?"
+                       rows = self.db.ladeSQL(sql, (lastDate, ))
 
-               
-               frame=gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
-       
-               
-               
-               self.comboIP=gtk.combo_box_entry_new_text()
-               
-               
-               self.comboIP.append_text("") #self.get_ip_address("eth0"))
-               #self.comboIP.append_text(self.get_ip_address("eth1")) #fixme
-               #self.comboIP.append_text(self.get_ip_address("eth2"))
-               #self.comboIP.append_text(self.get_ip_address("eth3"))
-               #print "Sync, 4d"
-               #self.comboIP.append_text(self.get_ip_address("wlan0"))
-               #self.comboIP.append_text(self.get_ip_address("wlan1"))
-               
-               #print "Sync, 4e"
-               
-               frame.add(self.comboIP)
-               serverbutton=gtk.ToggleButton(_("Start SyncServer"))
-               serverbutton.connect("clicked",self.startServer,(None,))
-               self.pack_start(frame, expand=False, fill=True, padding=1)
-               self.pack_start(serverbutton, expand=False, fill=True, padding=1)
-               self.syncServerStatusLabel=gtk.Label(_("Syncserver not running"))
-               self.pack_start(self.syncServerStatusLabel, expand=False, fill=True, padding=1)         
-                               
-               frame=gtk.Frame(_("RemoteSync-Server (Port ")+str(self.port)+")")
-               self.comboRemoteIP=gtk.combo_box_entry_new_text()
-               self.comboRemoteIP.append_text("192.168.0.?")
-               self.comboRemoteIP.append_text("192.168.1.?")
-               self.comboRemoteIP.append_text("192.168.176.?")
-               frame.add(self.comboRemoteIP)
-               syncbutton=gtk.Button(_("Connect to remote SyncServer"))
-               syncbutton.connect("clicked",self.syncButton,(None,))
-               self.pack_start(frame, expand=False, fill=True, padding=1)
-               self.pack_start(syncbutton, expand=False, fill=True, padding=1)
-               self.syncStatusLabel=gtk.Label(_("no sync process (at the moment)"))
-               self.pack_start(self.syncStatusLabel, expand=False, fill=True, padding=1)
+                       _moduleLogger.info("loaded concerned rows")
 
+                       newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time())
 
-               #self.comboRemoteIP.set_text_column("Test")
-               self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
-               self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
-               
-               #load
-               if (self.db.ladeDirekt("startSyncServer",False)==True):
-                       serverbutton.set_active(True)
-                       
-               #print "Sync, 9"
+                       _moduleLogger.info("did do sync, processing sqls now")
+                       if newSQLs != -1:
+                               self.writeSQLTupel(newSQLs, lastDate)
+
+                               sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid)
+                               self.doSaveFinalTime(sync_uuid, finalpcdatum)
+
+                               self.changeSyncStatus(False, _("no sync process (at the moment)"))
+
+                               mbox =  gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed"))
+                               response = mbox.run()
+                               mbox.hide()
+                               mbox.destroy()
+                       else:
+                               _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler")
+                               self.changeSyncStatus(False, _("no sync process (at the moment)"))
+                               mbox =  gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations"))
+                               response = mbox.run()
+                               mbox.hide()
+                               mbox.destroy()
+               except:
+                       _moduleLogger.warning("Sync connect failed")
+                       self.changeSyncStatus(False, _("no sync process (at the moment)"))
+                       mbox =  gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]))
+                       response = mbox.run()
+                       mbox.hide()
+                       mbox.destroy()
+                       self.server = None
+               self.server = None
index 481464c..7ded416 100644 (file)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
-  
+
+import logging
+
 import gtk
 import gobject
-import logging
-import pango
+
+import gtk_toolbox
 import libliststorehandler
-  
-
-class Columns_dialog(gtk.VBox):
-       
-       def is_col_selected(self, icol):
-               children=self.framebox.get_children()
-               if icol<len(children):
-                       return children[icol].get_active()
-               else:
-                       return None
-       
-       def save_column_setting(self):
-               i=1 #uid can not be shown
-               while self.liststorehandler.get_colname(i)!=None:
-                       name=str(self.liststorehandler.get_colname(i))
-                       if self.is_col_selected(i-1)==True:
-                               self.db.speichereDirekt("showcol_"+name,"1")
-                       else:
-                               self.db.speichereDirekt("showcol_"+name,"0")
-                       i=i+1
-               
-       
-
-       
-       def __init__(self,db,liststorehandler):
-               gtk.VBox.__init__(self,homogeneous=False, spacing=0)
-               
-               self.db=db
-               self.liststorehandler=liststorehandler
-               
-               #serverbutton=gtk.ToggleButton("SyncServer starten")
-               #serverbutton.connect("clicked",self.startServer,(None,))
-               #self.pack_start(serverbutton, expand=False, fill=True, padding=1)
-               #print "x1"
-               
-               frame=gtk.Frame(_("Columns"))
-               self.framebox=gtk.VBox(homogeneous=False, spacing=0)
-               
-               self.scrolled_window = gtk.ScrolledWindow()
-               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
-
-               self.scrolled_window.add_with_viewport(self.framebox)
-               
-               
-               i=1 #uid can not be shown
-               while self.liststorehandler.get_colname(i)!=None:
-                       name=str(self.liststorehandler.get_colname(i))
-                       checkbutton=gtk.CheckButton(name)
-                       if self.db.ladeDirekt("showcol_"+name)=="1":
-                               checkbutton.set_active(True)
-                               
-                       self.framebox.pack_start(checkbutton)
-                       i=i+1
-               
-               frame.add(self.scrolled_window)
-               self.pack_start(frame, expand=True, fill=True, padding=1)
-               
-               
-               
-       
-
-
-class CellRendererTriple(gtk.GenericCellRenderer):
-       __gproperties__ = {
-                "status": (gobject.TYPE_STRING, "Status",
-                "Status", "", gobject.PARAM_READWRITE),
-        }
-       
-       __gsignals__ = {
-               'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_INT,gobject.TYPE_STRING)),
-       }
 
 
-       def __init__(self):
-               #self.__gobject_init__()
-               #gtk.GenericCellRenderer.__init__(self,*args,**kwargs)
-               gtk.GenericCellRenderer.__init__(self)
-               #self.__gobject_init__()
-               self.status=-1
-               self.xpad = 2
-               self.ypad = 2
-               self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
-               self.xpad = -2; self.ypad = -2
-               self.xalign = 0.5; self.yalign = 0.5
-               self.active = 0
-               self.widget=None
-               self.last_cell=None
-               self.connect('editing-started', self.on_clicked)
-
-       def do_set_property(self,property,value):
-               setattr(self, property.name, value)
+try:
+       _
+except NameError:
+       _ = lambda x: x
 
-       def do_get_property(self, property):
-               return getattr(self, property.name)
 
-       def get_layout(self, widget):
-               '''Gets the Pango layout used in the cell in a TreeView widget.'''
-
-               layout = pango.Layout(widget.get_pango_context())
-               layout.set_width(-1)    # Do not wrap text.
-
-               layout.set_text('  ')
-
-               return layout
-
-       def on_get_size(self, widget, cell_area=None):
-               xpad = 2
-               ypad = 2
-
-               xalign = 0
-               yalign = 0.5
-
-               layout = self.get_layout(widget)
-               width, height = layout.get_pixel_size()
-
-               x_offset = xpad
-               y_offset = ypad
-
-               if cell_area:
-
-                       x_offset = xalign * (cell_area.width - width)
-                       x_offset = max(x_offset, xpad)
-                       x_offset = int(round(x_offset, 0))
-
-                       y_offset = yalign * (cell_area.height - height)
-                       y_offset = max(y_offset, ypad)
-                       y_offset = int(round(y_offset, 0))
-
-               width  = width  + (xpad * 2)
-               height = height + (ypad * 2)
-
-               
-               return x_offset, y_offset, width, height
-               
-       def on_clicked(self,  widget, data):
-               print widget,data
-
-       def clicked(self, widget, data1=None):
-               x,y=widget.get_pointer()
-               widget.realize()
-               
-               path=widget.get_path_at_pos(x,y)
-               
-               #print "a",widget.get_cursor()
-               #print path
-               
-       
-               
-               path=widget.get_cursor()[0]
-               
-               if path!=None:
-                       irow=path[0]    #path[0][0]-1
-                       rect=widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x<rect.x+rect.width:
-                               self.emit("status_changed",irow,self.status)
-               else:
-                       return
-               
-               
-                       #workarround -1 means last item, because bug in treeview?!
-                       #print "not in list"
-                       rect=widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
-                       #print rect.x,rect.y,rect.width,rect.height,x,y
-                       irow=-1
-                       rect=widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x<rect.x+rect.width:
-                               self.emit("status_changed",irow,"-1")
-               
-
-       def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
-               if (self.widget==None):
-                       #print widget
-                       self.widget=widget
-                       self.widget.connect("cursor-changed",self.clicked) #button-press-event
-               
-               self.last_cell=cell_area
-               
-               x=int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
-               y=int(cell_area.y+1)
-               height=int(cell_area.height-2)
-               width=int(height)
-
-               if (self.status=="1"):
-                       widget.style.paint_check(window,gtk.STATE_NORMAL, gtk.SHADOW_IN,cell_area, widget, "cellradio",x,y,width,height)
-               elif (self.status=="0"):
-                       #width=height
-                       height=height-3
-                       width=height
-                       
-                       widget.style.paint_flat_box(window, gtk.STATE_NORMAL, gtk.SHADOW_NONE, cell_area, widget, "cellunselected",x,y,width,height)
-                       
-                       widget.style.paint_hline(window, gtk.STATE_NORMAL,cell_area, widget, "cellunselected",x,x+width,y)
-                       widget.style.paint_hline(window, gtk.STATE_NORMAL,cell_area, widget, "cellunselected",x,x+width,y+height)
-                       widget.style.paint_vline(window, gtk.STATE_NORMAL,cell_area, widget, "cellunselected",y,y+height,x)
-                       widget.style.paint_vline(window, gtk.STATE_NORMAL,cell_area, widget, "cellunselected",y,y+height,x+width)
-                       
-               else:
-                       widget.style.paint_diamond(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellunselected",x,y,width,height)
-                       
-               #widget.show_all()
-               #print "render"
-               pass
-    
-       def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
-               print "on_start_editing",path
-               return None
-       
-       
-       def on_activate(self, event, widget, path, background_area, cell_area, flags):
-               print "activate",path
-               return False
-
-               
-               
-class CellRendererCombo2(gtk.GenericCellRenderer):
+_moduleLogger = logging.getLogger(__name__)
+
+
+class TripleToggleCellRenderer(gtk.CellRendererToggle):
+
        __gproperties__ = {
-                "text": (gobject.TYPE_STRING, "text",
-                "Text", "", gobject.PARAM_READWRITE),
-        }
-       
-       __gsignals__ = {
-               'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_INT,gobject.TYPE_STRING)),
-       }
+               "status": (gobject.TYPE_STRING, "Status",
+               "Status", "", gobject.PARAM_READWRITE),
+       }
 
+       __gsignals__ = {
+               'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
+       }
 
        def __init__(self):
-               #self.__gobject_init__()
-               #gtk.GenericCellRenderer.__init__(self,*args,**kwargs)
-               gtk.GenericCellRenderer.__init__(self)
-               #self.__gobject_init__()
-               self.status=-1
-               self.xpad = 2
-               self.ypad = 2
-               self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
-               self.xpad = -2; self.ypad = -2
-               self.xalign = 0.5; self.yalign = 0.5
-               self.active = 0
-               self.widget=None
-               self.last_cell=None
-               self.text="(none)"
-               self.connect('editing-started', self.on_clicked)
-
-       def do_set_property(self,property,value):
-               #print property,value
+               gtk.CellRendererToggle.__init__(self)
+               self.set_property("activatable", True)
+               self.connect('toggled', self._on_toggled)
+               self.status = libliststorehandler.Liststorehandler.SHOW_NEW
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def do_set_property(self, property, value):
+               if getattr(self, property.name) == value or value is None:
+                       return
+
                setattr(self, property.name, value)
 
+               if property.name == "status":
+                       active, inconsistent = {
+                               libliststorehandler.Liststorehandler.SHOW_NEW: (False, False),
+                               libliststorehandler.Liststorehandler.SHOW_ACTIVE: (False, True),
+                               libliststorehandler.Liststorehandler.SHOW_COMPLETE: (True, False),
+                       }[value]
+                       self.set_property("active", active)
+                       self.set_property("inconsistent", inconsistent)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
        def do_get_property(self, property):
                return getattr(self, property.name)
 
-       def get_layout(self, widget):
-               '''Gets the Pango layout used in the cell in a TreeView widget.'''
-
-               layout = pango.Layout(widget.get_pango_context())
-               layout.set_width(-1)    # Do not wrap text.
-
-               layout.set_text(self.text)
-
-               return layout
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_toggled(self, widget, path):
+               self.emit("status_changed", int(path), "-1")
 
-       def on_get_size(self, widget, cell_area=None):
-               xpad = 2
-               ypad = 2
 
-               xalign = 0
-               yalign = 0.5
+gobject.type_register(TripleToggleCellRenderer)
 
-               layout = self.get_layout(widget)
-               width, height = layout.get_pixel_size()
 
-               x_offset = xpad
-               y_offset = ypad
-
-               if cell_area:
+class View(gtk.VBox):
 
-                       x_offset = xalign * (cell_area.width - width)
-                       x_offset = max(x_offset, xpad)
-                       x_offset = int(round(x_offset, 0))
+       def __init__(self, db, liststorehandler, parent_window):
+               self.db = db
+               self.parent_window = parent_window
+               self.liststorehandler = liststorehandler
 
-                       y_offset = yalign * (cell_area.height - height)
-                       y_offset = max(y_offset, ypad)
-                       y_offset = int(round(y_offset, 0))
+               gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
 
-               width  = width  + (xpad * 2)
-               height = height + (ypad * 2)
+               logging.info("libview, init")
 
-               
-               return x_offset, y_offset, width, height
-               
-       def on_clicked(self,  widget, data):
-               print widget,data
+               self.scrolled_window = None
+               self.reload_view()
 
-       def clicked(self, widget, data1=None):
-               return
-               x,y=widget.get_pointer()
-               widget.realize()
-               
-               #path=widget.get_path_at_pos(x,y)
-               
-               path=widget.get_cursor()[0]
-               
-               if path!=None:
-                       irow=path[0]    #path[0][0]-1
-                       rect=widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x<rect.x+rect.width:
-                               self.emit("status_changed",irow,self.status)
-               else:
-                       return
-               
-               
-                       #workarround -1 means last item, because bug in treeview?!
-                       #print "not in list"
-                       rect=widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
-                       #print rect.x,rect.y,rect.width,rect.height,x,y
-                       irow=-1
-                       rect=widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x<rect.x+rect.width:
-                               self.emit("status_changed",irow,"-1")
-               
-
-       def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
-               if (self.widget==None):
-                       self.widget=widget
-                       self.widget.connect("cursor-changed",self.clicked) #button-press-event
-               
-               self.last_cell=cell_area
-               
-               x=int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
-               y=int(cell_area.y+1)
-               height=int(cell_area.height-2)
-               width=int(height)
-               
-               widget.style.paint_layout(window,gtk.STATE_NORMAL, True, cell_area, widget, "cellradio",x,y,self.get_layout(widget))
-                       
-               #widget.show_all()
-    
-       def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
-               print "on_start_editing",path
-               return None
-       
-       
-       def on_activate(self, event, widget, path, background_area, cell_area, flags):
-               print "activate",path
-               return False
-
-
-gobject.type_register(CellRendererCombo2)
-gobject.type_register(CellRendererTriple)
-
-       
-  
-class View(gtk.VBox):
-       
        def loadList(self):
-               ls=self.liststorehandler.get_liststore()
+               ls = self.liststorehandler.get_liststore()
                self.treeview.set_model(ls)
-               #self.tvcolumn[i].add_attribute( self.cell[i], "active", 1)
-               #print "setup",ls
-               
-               
-       
-       
-       def col_edited(self,cell, irow, new_text,icol=None):
-               if (irow!=4):
-                       self.liststorehandler.update_row(irow,icol,new_text)
-               else:
-                       print cell, irow, new_text,icol
-               
-       def col_toggled(self,widget,irow, status ):
-               #print irow,ls[irow][1],status
-               ls=self.treeview.get_model()
-               
-               if self.liststorehandler.selection.get_status()=="0":
-                       if ls[irow][1]=="0":
-                               self.liststorehandler.update_row(irow,1,"1")
-                       else:
-                               self.liststorehandler.update_row(irow,1,"0")
-               else:
-                       if ls[irow][1]=="1":
-                               self.liststorehandler.update_row(irow,1,"-1")
-                       elif ls[irow][1]=="0":
-                               self.liststorehandler.update_row(irow,1,"1")
-                       else:
-                               self.liststorehandler.update_row(irow,1,"0")
-                       
-               #self.tvcolumn[i].set_attributes( self.cell[i], active=i)
-               
-               
-       
-       def convert(self,s):
-               #print s
-               if (s=="1"):
-                       return 1
-               else:
-                       return 0
-               
-               
+
        def del_active_row(self):
                path, col = self.treeview.get_cursor()
-               #print path, col
-               if path!=None:
-                       irow=path[0]
-                       row_iter=self.treeview.get_model().get_iter(path)
-                       self.liststorehandler.del_row(irow,row_iter)
-
-                       
-               #treemodel.get_iter()
-               
-               
-               
-       def sort_func_function(self,model, iter1, iter2, data=None):
-               print "sorting"
-               
-               
+               if path is not None:
+                       irow = path[0]
+                       row_iter = self.treeview.get_model().get_iter(path)
+                       self.liststorehandler.del_row(irow, row_iter)
+
        def reload_view(self):
-               # create the TreeView using liststore
+               # create the TreeView using liststore
                self.modelsort = gtk.TreeModelSort(self.liststorehandler.get_liststore())
                self.modelsort.set_sort_column_id(2, gtk.SORT_ASCENDING)
-               
-               self.treeview = gtk.TreeView(self.modelsort)
+
+               self.treeview = gtk.TreeView(self.modelsort)
                self.treeview.set_headers_visible(True)
-               
-               
-               self.cell=range(self.liststorehandler.get_colcount())
-               self.tvcolumn=range(self.liststorehandler.get_colcount())
+               self.treeview.set_reorderable(False)
+
+               self.cell = range(self.liststorehandler.get_colcount())
+               self.tvcolumn = range(self.liststorehandler.get_colcount())
 
-               
                m = self.liststorehandler.get_unitsstore()
-               
+
                for i in range(self.liststorehandler.get_colcount()):
-                       
-                       if i>5:
-                               default="0"
+                       if i in [1, 2]:
+                               default = "1"
                        else:
-                               default="1"
-                       if self.db.ladeDirekt("showcol_"+str(self.liststorehandler.get_colname(i)),default)=="1":
-
-                               if (i==1):
-                                       self.cell[i] = CellRendererTriple()
-                                       self.tvcolumn[i] =      gtk.TreeViewColumn(self.liststorehandler.get_colname(i),self.cell[i])
-                                       self.cell[i].connect( 'status_changed', self.col_toggled)
-                                       self.tvcolumn[i].set_attributes( self.cell[i], status=i)
-                               
-                               elif (i==3)or(i==4)or(i==6):
+                               default = "0"
+                       if self.db.ladeDirekt("showcol_"+str(self.liststorehandler.get_colname(i)), default) == "1":
+                               if i in [1]:
+                                       self.cell[i] = TripleToggleCellRenderer()
+                                       self.tvcolumn[i] = gtk.TreeViewColumn("", self.cell[i])
+                                       self.cell[i].connect( 'status_changed', self._on_col_toggled)
+                                       self.tvcolumn[i].set_attributes( self.cell[i], status = i)
+                               elif i in [3, 6]:
                                        self.cell[i] = gtk.CellRendererCombo()
-                                       self.tvcolumn[i] =      gtk.TreeViewColumn(self.liststorehandler.get_colname(i),self.cell[i])
-                                       self.cell[i].set_property("model",m)
+                                       self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
+                                       self.cell[i].set_property("model", m)
                                        self.cell[i].set_property('text-column', i)
-                                       self.cell[i].set_property('editable',True)
-                                       self.cell[i].connect("edited", self.col_edited,i) 
-                                       self.tvcolumn[i].set_attributes( self.cell[i], text=i)
+                                       self.cell[i].set_property('editable', True)
+                                       self.cell[i].connect("edited", self._on_col_edited, i)
+                                       self.tvcolumn[i].set_attributes( self.cell[i], text = i)
                                else:
                                        self.cell[i] = gtk.CellRendererText()
-                                       self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i),self.cell[i])
-                                       self.cell[i].set_property('editable',True)
-                                       self.cell[i].set_property('editable-set',True)
-                                       self.cell[i].connect("edited", self.col_edited,i) 
-                                       #self.cell[i].connect("editing-canceled", self.col_edited2,i) 
-                                       self.tvcolumn[i].set_attributes(self.cell[i], text=i)
-
-                               self.cell[i].set_property('cell-background', 'lightgray')
+                                       self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
+                                       self.cell[i].set_property('editable', True)
+                                       self.cell[i].set_property('editable-set', True)
+                                       self.cell[i].connect("edited", self._on_col_edited, i)
+                                       self.tvcolumn[i].set_attributes(self.cell[i], text = i)
+
                                self.tvcolumn[i].set_sort_column_id(i)
                                self.tvcolumn[i].set_resizable(True)
-                               
-                               
-                               if (i>0):
-                                       self.treeview.append_column(self.tvcolumn[i])
-                               
-               
-               # Allow NOT drag and drop reordering of rows
-               self.treeview.set_reorderable(False)
-               
-               
-               if self.scrolled_window != None:
+                               self.treeview.append_column(self.tvcolumn[i])
+
+               if self.scrolled_window is not None:
                        self.scrolled_window.destroy()
-               
+
                self.scrolled_window = gtk.ScrolledWindow()
-               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
+               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
                self.scrolled_window.add(self.treeview)
-               self.pack_start(self.scrolled_window, expand=True, fill=True, padding=0)
+               self.pack_start(self.scrolled_window, expand = True, fill = True, padding = 0)
                self.loadList()
-               
+
                self.show_all()
-       
-       def __init__(self,db,liststorehandler,parent_window):
-               
-               self.db=db
-               self.parent_window=parent_window
-               self.liststorehandler = liststorehandler
-               
-               
-               gtk.VBox.__init__(self,homogeneous=False, spacing=0)
-               
-               logging.info("libview, init")
 
-               self.scrolled_window = None
-               self.reload_view()
-               
-               
-               
-               
-               
-               """
-               bearbeitenFrame=gtk.Frame("Verteilung kopieren nach")
-               bearbeitenvBox=gtk.VBox(homogeneous=False, spacing=0)
-               
-               bearbeitenhBox=gtk.HBox(homogeneous=False, spacing=0)
-               self.comboKlassen = gtk.combo_box_new_text()
-               bearbeitenhBox.pack_start(self.comboKlassen, expand=False, fill=True, padding=0)
-               button=gtk.Button("Kopieren")
-               button.connect("clicked", self.kopiereStoffverteilung, None)
-               bearbeitenhBox.pack_start(button, expand=False, fill=True, padding=0)
-               
-               label=gtk.Label("   ")
-               bearbeitenhBox.pack_start(label, expand=False, fill=True, padding=0)
-               
-               button=gtk.Button("Export in CSV-Datei")
-               button.connect("clicked", self.exportStoffverteilung, None)
-               bearbeitenhBox.pack_start(button, expand=False, fill=True, padding=0)
-               
-               bearbeitenvBox.pack_start(bearbeitenhBox, expand=False, fill=True, padding=0)
-               
-       
-               bearbeitenFrame.add(bearbeitenvBox)
-               self.pack_start(bearbeitenFrame, expand=False, fill=True, padding=0)
-               """
-               
-               #self.connect("unmap", self.speichere) 
-               #self.connect("map", self.ladeWirklich) 
-
-               #self.show_all()
-               
-               
-
-               #print "libstoffverteilung 9: ",time.clock()
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_col_edited(self, cell, irow, new_text, icol = None):
+               if (irow != 4):
+                       self.liststorehandler.update_row(irow, icol, new_text)
+               else:
+                       print cell, irow, new_text, icol
 
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_col_toggled(self, widget, irow, status):
+               ls = self.treeview.get_model()
+
+               if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
+                       if ls[irow][1] == "0":
+                               self.liststorehandler.update_row(irow, 1, "1")
+                       else:
+                               self.liststorehandler.update_row(irow, 1, "0")
+               else:
+                       if ls[irow][1] == "1":
+                               self.liststorehandler.update_row(irow, 1, "-1")
+                       elif ls[irow][1] == "0":
+                               self.liststorehandler.update_row(irow, 1, "1")
+                       else:
+                               self.liststorehandler.update_row(irow, 1, "0")
index aa7cc92..abd6963 100755 (executable)
@@ -1,64 +1,38 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
-"""
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+"""
+Copyright (C) 2008 Christoph Würstle
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
 """
 
 import os
 import sys
-
-##
-## I18N
-##
-import locale
+import logging
 import gettext
-gettext.install('multilist', unicode=1)
-                       
+
+_moduleLogger = logging.getLogger(__name__)
+gettext.install('multilist', unicode = 1)
+sys.path.append('/usr/lib/multilist')
+
+
+import constants
+import multilist_gtk
+
+
 if __name__ == "__main__":
-       
        try:
-               import tempfile
-               import gtk
-               tmpdir=tempfile.gettempdir()
-               
-               os.mkdir(os.path.join(tmpdir, "multilist_lock"))
-       except OSError:
-               ## Failed: another instance is running
-               
-               mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_YES_NO,_("Multilist is already running. Start anyway? (Could result in db problems!)")) 
-               response=mbox.run() 
-               mbox.hide() 
-               mbox.destroy() 
-               if response==gtk.RESPONSE_NO:
-                       sys.exit()
+               os.makedirs(constants._data_path_)
+       except OSError, e:
+               if e.errno != 17:
+                       raise
 
-       try:
-               
-               from multilistclasses import libmultilist
-               #print dir(eggtimerclasses)
-               app = libmultilist.multilistclass() 
-               app.main() 
-   
-       finally:
-               ## Remove the PID file
-               # (...)
-               ## Delete directory
-               os.rmdir(os.path.join(tmpdir, "multilist_lock"))
-               
-       
+       logging.basicConfig(level = logging.DEBUG, filename = constants._user_logpath_)
+       _moduleLogger.info("multilist %s-%s" % (constants.__version__, constants.__build__))
+       _moduleLogger.info("OS: %s" % (os.uname()[0], ))
+       _moduleLogger.info("Kernel: %s (%s) for %s" % os.uname()[2:])
+       _moduleLogger.info("Hostname: %s" % os.uname()[1])
+
+       multilist_gtk.run_multilist()
index 69321c6..ea1a930 100755 (executable)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
-"""
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+
+from __future__ import with_statement
+
 """
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
 
-#/scratchbox/login
-#Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac
-#af-sb-init.sh start
-#run-standalone.sh ./eggtimer.py
-#
-#https://stage.maemo.org/svn/maemo/projects/haf/trunk/
-#http://www.maemo.org/platform/docs/pymaemo/pyosso_context.html
-#http://maemo-hackers.org/apt/
+Copyright (C) 2008 Christoph Würstle
+"""
 
-import time
 import os
-import sys
 import logging
+import ConfigParser
+
+import gtk
 
 try:
-        import gtk
-        #import gtk.glade
+       import hildon
+       isHildon = True
 except:
-       print "gtk import failed"
-        sys.exit(1)
-       
+       isHildon = False
+
 try:
-       import hildon
        import osso
-       isHildon=True
-except:
-       isHildon=False
-       class hildon():
-               def __init__(self):
-                       print "PseudoClass hildon"
-               class Program():
-                       def __init__(self):
-                               print "PseudoClass hildon.Program"
-
-#import libextdatei
+except ImportError:
+       osso = None
+
+import constants
+import hildonize
+import gtk_toolbox
+
 import libspeichern
-import libsqldialog
+import search
+import sqldialog
+import settings
 import libselection
 import libview
 import libliststorehandler
 import libsync
 import libbottombar
 
-version = "0.3.0"
-app_name = "multilist"
+try:
+       _
+except NameError:
+       _ = lambda x: x
 
-               
-       
 
-class multilistclass(hildon.Program):
-               
-       def on_key_press(self, widget, event, *args):
-               #Hildon Fullscreen Modus
-               if (isHildon==False): return
-               if event.keyval == gtk.keysyms.F6: 
-                       # The "Full screen" hardware key has been pressed 
-                       if self.window_in_fullscreen: 
-                               self.window.unfullscreen () 
-                       else: 
-                               self.window.fullscreen () 
-               
-       def on_window_state_change(self, widget, event, *args): 
-               if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: 
-                       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")
-
-
-       def sync_finished(self,data=None,data2=None):
-               self.selection.comboList_changed()
-               self.selection.comboCategory_changed()
-               self.liststorehandler.update_list()
-               
-       
-       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)
-               self.sync_dialog.vbox.pack_start(sync, True, True, 0)
-               self.sync_dialog.set_size_request(500,350)
-               self.sync_dialog.vbox.show_all()
-               sync.connect("syncFinished",self.sync_finished)
-       
-       
-       def sync_notes(self,widget=None,data=None):
-               if self.sync_dialog==None:
-                       self.prepare_sync_dialog()
-               self.sync_dialog.run()
-               self.sync_dialog.hide()
-
-
-       def show_columns_dialog(self,widget=None,data=None):
-               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))
-               
-               col_dialog.set_position(gtk.WIN_POS_CENTER)
-               cols=libview.Columns_dialog(self.db,self.liststorehandler)
-
-               col_dialog.vbox.pack_start(cols, True, True, 0)
-               col_dialog.set_size_request(500,350)
-               col_dialog.vbox.show_all()
-               
-               resp=col_dialog.run()
-               col_dialog.hide()
-               if resp==gtk.RESPONSE_ACCEPT:
-                       logging.info("changing columns")
-                       cols.save_column_setting()
-                       self.view.reload_view()
-                       #children=self.vbox.get_children()
-                       #while len(children)>1:
-                       #       self.vbox.remove(children[1])
-
-                       #self.vbox.pack_end(self.bottombar, expand=True, fill=True, padding=0)
-                       #self.vbox.pack_end(view, expand=True, fill=True, padding=0)
-                       #self.vbox.pack_end(self.selection, expand=False, fill=True, padding=0)
-                       
-
-               col_dialog.destroy()
-               
+_moduleLogger = logging.getLogger(__name__)
+PROFILE_STARTUP = False
+
+
+class Multilist(hildonize.get_app_class()):
 
+       _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
+       _user_settings = "%s/settings.ini" % _user_data
 
        def __init__(self):
-               home_dir = os.path.expanduser('~')
-               dblog=os.path.join(home_dir, "multilist.log") 
-               logging.basicConfig(level=logging.INFO,format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename=dblog,filemode='a')
-               #logging.getLogger('').addHandler(console)
-               
-               # define a Handler which writes INFO messages or higher to the sys.stderr
-               console = logging.StreamHandler()
-               console.setLevel(logging.INFO)
-               # set a format which is simpler for console use
-               formatter = logging.Formatter('%(asctime)s  %(levelname)-8s %(message)s')
-               # tell the handler to use this format
-               console.setFormatter(formatter)
-               # add the handler to the root logger
-               logging.getLogger('').addHandler(console)
-               
+               super(Multilist, self).__init__()
+               self._clipboard = gtk.clipboard_get()
+
                logging.info('Starting Multilist')
-               
-               if (isHildon==True): 
-                       logging.info('Hildon erkannt, rufe Hildon constructor auf')
-                       hildon.Program.__init__(self)
-                               
-                #Get the Main Window, and connect the "destroy" event
-               if (isHildon==False):
-                       self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
-                       self.window.set_default_size(700,500)
-               else:
-                       self.window = hildon.Window()
-                       self.add_window(self.window)
-                       
-               #print "1b: ",time.clock() 
-               
-                if (self.window):
-                       self.window.connect("delete_event", self.delete_event)
-                       self.window.connect("destroy", self.destroy)
-                       self.window.set_title("Multilist")
-                       
-                       
-                       
-                       if (isHildon==True): self.window.connect("key-press-event", self.on_key_press) 
-                       self.window.connect("window-state-event", self.on_window_state_change) 
-                       self.window_in_fullscreen = False #The window isn't in full screen mode initially.
-
-
-               self.db=libspeichern.Speichern()
-               
-               self.selection=libselection.Selection(self.db,isHildon)
-               self.liststorehandler=libliststorehandler.Liststorehandler(self.db,self.selection)
-               self.view=libview.View(self.db,self.liststorehandler,self.window)
-               self.bottombar=libbottombar.Bottombar(self.db,self.view,isHildon)
-               
+
+               try:
+                       os.makedirs(self._user_data)
+               except OSError, e:
+                       if e.errno != 17:
+                               raise
+
+               self.db = libspeichern.Speichern()
+               self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
+               self.__isPortrait = False
+
                #Haupt vbox für alle Elemente
-               self.vbox = gtk.VBox(homogeneous=False, spacing=0)
-               
-               
-               
+               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)
+               self._search = search.Search()
+               self.liststorehandler = libliststorehandler.Liststorehandler(self.db, self.selection)
+               self.view = libview.View(self.db, self.liststorehandler, self.window)
+               self.bottombar = libbottombar.Bottombar(self.db, self.view, isHildon)
+
                #Menue
-               dateimenu = gtk.Menu()
-               
-               menu_items = gtk.MenuItem(_("Choose database file"))
-               dateimenu.append(menu_items)
-               menu_items.connect("activate", self.select_db_dialog, None)
-               
-               menu_items = gtk.MenuItem(_("SQL history"))
-               dateimenu.append(menu_items)
-               menu_items.connect("activate", self.view_sql_history, None)
-               
-               menu_items = gtk.MenuItem(_("SQL optimize"))
-               dateimenu.append(menu_items)
-               menu_items.connect("activate", self.optimizeSQL, None)
-               
-               menu_items = gtk.MenuItem(_("Sync items"))
-               self.prepare_sync_dialog()
-               dateimenu.append(menu_items)
-               menu_items.connect("activate", self.sync_notes, None)
-               
-               
-               menu_items = gtk.MenuItem(_("Quit"))
-               dateimenu.append(menu_items)
-               menu_items.connect("activate", self.destroy, None)
-               #menu_items.show()
-               
-               datei_menu = gtk.MenuItem(_("File"))
-               datei_menu.show()
-               datei_menu.set_submenu(dateimenu)
-               
-               
-               toolsmenu = gtk.Menu()
-               
-               
-               menu_items = gtk.MenuItem(_("Choose columns"))
-               toolsmenu.append(menu_items)
-               menu_items.connect("activate", self.show_columns_dialog, None)
-               
-               menu_items = gtk.MenuItem(_("Rename Category"))
-               toolsmenu.append(menu_items)
-               menu_items.connect("activate", self.bottombar.rename_category, None)
-               
-               menu_items = gtk.MenuItem(_("Rename List"))
-               toolsmenu.append(menu_items)
-               menu_items.connect("activate", self.bottombar.rename_list, None)
-               
-               tools_menu = gtk.MenuItem(_("Tools"))
-               tools_menu.show()
-               tools_menu.set_submenu(toolsmenu)
-               
-               
-               hilfemenu = gtk.Menu()
-               menu_items = gtk.MenuItem(_("About"))
-               hilfemenu.append(menu_items)
-               menu_items.connect("activate", self.show_about, None)
-               
-               hilfe_menu = gtk.MenuItem(_("Help"))
-               hilfe_menu.show()
-               hilfe_menu.set_submenu(hilfemenu)
-               
-               menu_bar = gtk.MenuBar()
-               menu_bar.show()
-               menu_bar.append (datei_menu)
-               menu_bar.append (tools_menu)
-               # unten -> damit als letztes menu_bar.append (hilfe_menu)
-               #Als letztes menü
-               menu_bar.append (hilfe_menu)
-               
-               if (isHildon==True):
-                       menu = gtk.Menu() 
-                       for child in menu_bar.get_children():
-                               child.reparent(menu) 
-                       self.window.set_menu(menu)
-                       menu_bar.destroy()
+               if hildonize.GTK_MENU_USED:
+                       fileMenu = gtk.Menu()
+
+                       menu_items = gtk.MenuItem(_("Choose database file"))
+                       menu_items.connect("activate", self._on_select_db, None)
+                       fileMenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("SQL history"))
+                       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._on_optimize_sql, None)
+                       fileMenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("Sync items"))
+                       menu_items.connect("activate", self.sync_notes, None)
+                       fileMenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("Quit"))
+                       menu_items.connect("activate", self._on_destroy, None)
+                       fileMenu.append(menu_items)
+
+                       fileMenuItem = gtk.MenuItem(_("File"))
+                       fileMenuItem.show()
+                       fileMenuItem.set_submenu(fileMenu)
+
+                       listmenu = gtk.Menu()
+
+                       menu_items = gtk.MenuItem(_("Search"))
+                       menu_items.connect("activate", self._on_toggle_search)
+                       listmenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("Checkout All"))
+                       menu_items.connect("activate", self._on_checkout_all)
+                       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)
+                       listmenu.append(menu_items)
+
+                       listMenuItem = gtk.MenuItem(_("List"))
+                       listMenuItem.show()
+                       listMenuItem.set_submenu(listmenu)
+
+                       viewMenu = gtk.Menu()
+
+                       menu_items = gtk.MenuItem(_("Show Active"))
+                       menu_items.connect("activate", self._on_toggle_filter, None)
+                       viewMenu.append(menu_items)
+
+                       menu_items = gtk.MenuItem(_("Settings"))
+                       menu_items.connect("activate", self._on_settings, None)
+                       viewMenu.append(menu_items)
+
+                       viewMenuItem = gtk.MenuItem(_("View"))
+                       viewMenuItem.show()
+                       viewMenuItem.set_submenu(viewMenu)
+
+                       helpMenu = gtk.Menu()
+                       menu_items = gtk.MenuItem(_("About"))
+                       helpMenu.append(menu_items)
+                       menu_items.connect("activate", self._on_about, None)
+
+                       helpMenuItem = gtk.MenuItem(_("Help"))
+                       helpMenuItem.show()
+                       helpMenuItem.set_submenu(helpMenu)
+
+                       menuBar = gtk.MenuBar()
+                       menuBar.show()
+                       menuBar.append (fileMenuItem)
+                       menuBar.append (listMenuItem)
+                       menuBar.append (viewMenuItem)
+                       # unten -> damit als letztes menuBar.append (helpMenuItem)
+                       #Als letztes menü
+                       menuBar.append (helpMenuItem)
+
+                       self.vbox.pack_start(menuBar, False, False, 0)
                else:
-                       self.vbox.pack_start(menu_bar, False, False, 2)
-               
-               
-               
+                       menuBar = gtk.MenuBar()
+                       menuBar.show()
+                       self.vbox.pack_start(menuBar, False, False, 0)
 
                #add to vbox below (to get it on top)
-               
-               
-               
-               self.vbox.pack_end(self.bottombar, expand=False, fill=True, padding=0)
-               self.vbox.pack_end(self.view, expand=True, fill=True, padding=0)
-               self.vbox.pack_end(self.selection, expand=False, fill=True, padding=0)
-               
-
-               if (isHildon==True): self.osso_c = osso.Context(app_name, version, False)
+               self.vbox.pack_end(self._search, expand = False, fill = True)
+               self.vbox.pack_end(self.bottombar, expand = False, fill = True, padding = 0)
+               self.vbox.pack_end(self.view, expand = True, fill = True, padding = 0)
+               self.vbox.pack_end(self.selection, expand = False, fill = True, padding = 0)
+
+               #Get the Main Window, and connect the "destroy" event
                self.window.add(self.vbox)
+
+               self.window = hildonize.hildonize_window(self, self.window)
+               hildonize.set_application_title(self.window, "%s" % constants.__pretty_app_name__)
+               menuBar = hildonize.hildonize_menu(
+                       self.window,
+                       menuBar,
+               )
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, None)
+                       button.set_label("All")
+                       menuBar.add_filter(button)
+                       button.connect("clicked", self._on_click_menu_filter, self.liststorehandler.SHOW_ALL)
+                       button.set_mode(False)
+                       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)
+
+                       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)
+
+                       searchButton= gtk.Button(_("Settings"))
+                       searchButton.connect("clicked", self._on_settings)
+                       menuBar.append(searchButton)
+
+                       menuBar.show_all()
+
+               if not hildonize.IS_HILDON_SUPPORTED:
+                       _moduleLogger.info("No hildonization support")
+
+               if osso is not None:
+                       self.osso_c = osso.Context(
+                               constants.__app_name__,
+                               constants.__version__,
+                               False
+                       )
+               else:
+                       _moduleLogger.info("No osso support")
+                       self._osso_c = None
+
+               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._search.connect("search_changed", self._on_search)
+
                self.window.show_all()
-               
-               #print "8a"
-               self.ladeAlles()
-               
-               
-               #print "9: ",time.clock()
-                       
-       def main(self):
-               gtk.main()
-               if (isHildon==True): self.osso_c.close()
-               
-       def destroy(self, widget=None, data=None):
-               self.speichereAlles()
-               self.db.close()
-               gtk.main_quit()
-               
-               
-       def delete_event(self, widget, event, data=None):
-               #print "delete event occurred"
-               return False
-       
-       def dlg_delete(self,widget,event,data=None):
-               return False
+               self._search.hide()
+               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):
+               self.liststorehandler.checkout_rows()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_search(self, widget):
+               self.liststorehandler.get_liststore(self._search.get_search_pattern())
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_click_menu_filter(self, button, val):
+               self.liststorehandler.set_filter(val)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_toggle_search(self, *args):
+               self._toggle_search()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_toggle_filter(self, *args):
+               if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ALL:
+                       self.liststorehandler.set_filter(self.liststorehandler.SHOW_ACTIVE)
+               elif self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
+                       self.liststorehandler.set_filter(self.liststorehandler.SHOW_ALL)
+               else:
+                       assert False, "Unknown"
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def on_key_press(self, widget, event, *args):
+               RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
+               isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
+               if (
+                       event.keyval == gtk.keysyms.F6 or
+                       event.keyval in RETURN_TYPES and isCtrl
+               ):
+                       # The "Full screen" hardware key has been pressed 
+                       if self.__window_in_fullscreen:
+                               self.window.unfullscreen ()
+                       else:
+                               self.window.fullscreen ()
+                       return True
+               elif event.keyval == gtk.keysyms.o and isCtrl:
+                       self._toggle_rotate()
+                       return True
+               elif event.keyval == gtk.keysyms.f and isCtrl:
+                       self._toggle_search()
+                       return True
+               elif (
+                       event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
+                       event.get_state() & gtk.gdk.CONTROL_MASK
+               ):
+                       self.window.destroy()
+               elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
+                       with open(constants._user_logpath_, "r") as f:
+                               logLines = f.xreadlines()
+                               log = "".join(logLines)
+                               self._clipboard.set_text(str(log))
+                       return True
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_window_state_change(self, widget, event, *args):
+               if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
+                       self.__window_in_fullscreen = True
+               else:
+                       self.__window_in_fullscreen = False
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       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):
+               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._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 is None:
+                       self._prepare_sync_dialog()
+               self.sync_dialog.run()
+               self.sync_dialog.hide()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_settings(self, *args):
+               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()
+
+       @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)
+
+               return True
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_destroy(self, widget = None, data = None):
+               try:
+                       self.db.close()
+                       self._save_settings()
+
+                       try:
+                               self._osso_c.close()
+                       except AttributeError:
+                               pass # Either None or close was removed (in Fremantle)
+               finally:
+                       gtk.main_quit()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_delete_event(self, widget, event, data = None):
+               return False
 
-       def show_about(self, widget=None,data=None):
-               dialog = gtk.AboutDialog()
-               dialog.set_position(gtk.WIN_POS_CENTER)
-               dialog.set_name(app_name)
-               dialog.set_version(version)
-               dialog.set_copyright("")
-               dialog.set_website("http://axique.de/f=Multilist")
-               comments = "%s is a program to handle multiple lists." % app_name
-               dialog.set_comments(comments)        
-               dialog.run()     
-               dialog.destroy()
-       
-       def on_info1_activate(self,menuitem):
-               self.show_about(menuitem)
-
-  
-       def view_sql_history(self,widget=None,data=None,data2=None):
-               sqldiag=libsqldialog.sqlDialog(self.db)
-               res=sqldiag.run()
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_view_sql_history(self, widget = None, data = None, data2 = None):
+               sqldiag = sqldialog.SqlDialog(self.db)
+               res = sqldiag.run()
                sqldiag.hide()
-               if res==444:
+
+               try:
+                       if res != gtk.RESPONSE_OK:
+                               return
                        logging.info("exporting sql")
-                       
-                       if (isHildon==False):
-                               dlg = gtk.FileChooserDialog(parent = self.window, action = gtk.FILE_CHOOSER_ACTION_SAVE)
+
+                       if not isHildon:
+                               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)
+                               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)
-                       
+                               dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_SAVE)
+
                        dlg.set_title(_("Select SQL export file"))
-                       if dlg.run() == gtk.RESPONSE_OK:
-                               fileName = dlg.get_filename()
-                               dlg.destroy()
-                               sqldiag.exportSQL(fileName)
-                       else:
+                       exportFileResponse = dlg.run()
+                       try:
+                               if exportFileResponse == gtk.RESPONSE_OK:
+                                       fileName = dlg.get_filename()
+                                       sqldiag.exportSQL(fileName)
+                       finally:
                                dlg.destroy()
-                               
-               sqldiag.destroy()
+               finally:
+                       sqldiag.destroy()
 
-               
-       def optimizeSQL(self,widget=None,data=None,data2=None): 
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_optimize_sql(self, widget = None, data = None, data2 = None):
                #optimiere sql
-               self.db.speichereSQL("VACUUM",log=False)
-               
-  
-
-  
-       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)
-                       
-               
-               if self.db.ladeDirekt('datenbank'):
+               self.db.speichereSQL("VACUUM", log = False)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       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():
+       if hildonize.IS_HILDON_SUPPORTED:
+               gtk.set_application_name(constants.__pretty_app_name__)
+       app = Multilist()
+       if not PROFILE_STARTUP:
+               gtk.main()
+
 
+if __name__ == "__main__":
+       logging.basicConfig(level = logging.DEBUG)
+       run_multilist()
diff --git a/src/search.py b/src/search.py
new file mode 100644 (file)
index 0000000..fab6710
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+
+import logging
+
+import gobject
+import gtk
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class Search(gtk.HBox):
+
+       __gsignals__ = {
+               'search_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+       }
+
+       def __init__(self):
+               _moduleLogger.info("search, init")
+               gtk.HBox.__init__(self, homogeneous = False, spacing = 3)
+               self.connect("hide", self._on_hide)
+               self.connect("show", self._on_show)
+
+               label = gtk.Label(_("Search:  "))
+
+               self._searchEntry = gtk.Entry()
+               self._searchEntry.connect("changed", self._on_search_entry_changed, None)
+
+               closeImage = gtk.Image()
+               closeImage.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
+               closeSearch = gtk.Button()
+               closeSearch.set_image(closeImage)
+               closeSearch.connect("clicked", self._on_close)
+
+               searchHBox = gtk.HBox()
+               searchHBox.pack_start(label, expand = False, fill = False)
+               searchHBox.pack_start(self._searchEntry, expand = True, fill = True)
+               searchHBox.pack_start(closeSearch, expand = False, fill = False)
+               self.pack_start(searchHBox, expand = True, fill = True)
+
+       def get_search_pattern(self):
+               return self._searchEntry.get_text()
+
+       def _on_search_entry_changed(self, widget = None, data = None):
+               self.emit("search_changed")
+
+       def _on_close(self, *args):
+               self.hide()
+
+       def _on_show(self, *args):
+               self._searchEntry.grab_focus()
+
+       def _on_hide(self, *args):
+               # HACK Disabled for now.  Clearing this resets the note list which
+               # causes the current note to lose focus.
+               # self._searchEntry.set_text("")
+               pass
diff --git a/src/settings.py b/src/settings.py
new file mode 100644 (file)
index 0000000..f88fa8e
--- /dev/null
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
+"""
+
+import logging
+
+import gtk
+
+import hildonize
+
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class SettingsDialog(object):
+
+       def __init__(self, parent, db, liststorehandler):
+               self.__listStore = liststorehandler
+
+               self.__columnsSection = gtk.VBox()
+               for i, name in enumerate(self._iter_columns()):
+                       checkbutton = gtk.CheckButton(name)
+
+                       if i in [0, 1]:
+                               default = "1"
+                       else:
+                               default = "0"
+                       if db.ladeDirekt("showcol_"+name, default) == "1":
+                               checkbutton.set_active(True)
+
+                       self.__columnsSection.pack_start(checkbutton)
+
+               columnsFrame = gtk.Frame(_("Visible Columns"))
+               columnsFrame.add(self.__columnsSection)
+
+               self.__rotationSection = gtk.VBox()
+
+               self.__isPortraitCheckbutton = gtk.CheckButton(_("Portrait Mode"))
+               self.__rotationSection.pack_start(self.__isPortraitCheckbutton)
+
+               rotationFrame = gtk.Frame(_("Rotation"))
+               rotationFrame.add(self.__rotationSection)
+
+               settingsBox = gtk.VBox()
+               settingsBox.pack_start(rotationFrame)
+               settingsBox.pack_start(columnsFrame)
+               settingsView = gtk.Viewport()
+               settingsView.add(settingsBox)
+               settingsScrollView = gtk.ScrolledWindow()
+               settingsScrollView.add(settingsView)
+               settingsScrollView.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+               parent.pack_start(settingsScrollView)
+
+               settingsScrollView = hildonize.hildonize_scrollwindow(settingsScrollView)
+
+       def set_portrait_state(self, isPortrait):
+               self.__isPortraitCheckbutton.set_active(isPortrait)
+
+       def is_portrait(self):
+               return self.__isPortraitCheckbutton.get_active()
+
+       def is_col_selected(self, icol):
+               children = self.__columnsSection.get_children()
+               if icol < len(children):
+                       return children[icol].get_active()
+               else:
+                       return None
+
+       def save(self, db):
+               for i, name in enumerate(self._iter_columns()):
+                       if self.is_col_selected(i) == True:
+                               db.speichereDirekt("showcol_"+name, "1")
+                       else:
+                               db.speichereDirekt("showcol_"+name, "0")
+
+       def _iter_columns(self):
+               for i in xrange(self.__listStore.get_colcount()):
+                       name = self.__listStore.get_colname(i)
+                       assert name is not None
+                       if name == "uid":
+                               continue
+
+                       yield name
index 2f384a8..0a16f95 100755 (executable)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-  
+
 """
-    This file is part of Multilist.
-
-    Multilist is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    Multilist is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-    
-    Copyright (C) 2008 Christoph Würstle
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
 """
 
-import gobject
+from __future__ import with_statement
+
 import time
-import string
-import gtk
-import sys
 import logging
 
-import libspeichern 
-class sqlDialog(gtk.Dialog):
-       
-       def exportSQL(self,filename):
-               f = open(filename, 'w')
-               msgstring=""
-               sql="SELECT pcdatum,sql,param FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
-               rows=self.db.ladeSQL(sql,(time.time()-2*24*3600,))
-               for row in rows:
-                       pcdatum,sql,param = row
-                       datum=str(time.strftime("%d.%m.%y %H:%M:%S ", (time.localtime(pcdatum))))
-                       f.write( datum +"\t" + sql + "\t\t" + param+ "\n")
-                       
-                       
-               f.close()
-               
-       
-       def __init__(self,db):
-               self.db=db
-               
-               logging.info("sqldialog, init")
-               
-               gtk.Dialog.__init__(self,_("SQL History (the past two days):"),None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
-               
-               
-               self.add_button(_("Export"), 444)
-               self.set_position(gtk.WIN_POS_CENTER)
-               
-               
+import gtk
+
+import gtk_toolbox
+
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class SqlDialog(gtk.Dialog):
+
+       def __init__(self, db):
+               self.db = db
+
+               _moduleLogger.info("sqldialog, init")
+
+               gtk.Dialog.__init__(
+                       self,
+                       _("SQL History (the past two days):"),
+                       None,
+                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                       (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
+               )
+
+               self.add_button(_("Export"), gtk.RESPONSE_OK)
+               self.set_position(gtk.WIN_POS_CENTER)
+
                self.liststore = gtk.ListStore(str, str, str)
 
-               # create the TreeView using liststore
-               self.treeview = gtk.TreeView(self.liststore)
-               
+               # create the TreeView using liststore
+               self.treeview = gtk.TreeView(self.liststore)
+
                # create a CellRenderers to render the data
-               self.cell1 = gtk.CellRendererText()
-               self.cell2 = gtk.CellRendererText()
+               self.cell1 = gtk.CellRendererText()
+               self.cell2 = gtk.CellRendererText()
                self.cell3 = gtk.CellRendererText()
                #self.cell1.set_property('markup', 1)
-               
-               # create the TreeViewColumns to display the data
-               self.tvcolumn1 = gtk.TreeViewColumn(_('Date'))
-               self.tvcolumn2 = gtk.TreeViewColumn(_('SQL'))
+
+               # create the TreeViewColumns to display the data
+               self.tvcolumn1 = gtk.TreeViewColumn(_('Date'))
+               self.tvcolumn2 = gtk.TreeViewColumn(_('SQL'))
                self.tvcolumn3 = gtk.TreeViewColumn(_('Parameter'))
-               
-               # add columns to treeview
-               self.treeview.append_column(self.tvcolumn1)
-               self.treeview.append_column(self.tvcolumn2)
+
+               # add columns to treeview
+               self.treeview.append_column(self.tvcolumn1)
+               self.treeview.append_column(self.tvcolumn2)
                self.treeview.append_column(self.tvcolumn3)
-               
-               
+
                self.tvcolumn1.pack_start(self.cell1, True)
-               self.tvcolumn2.pack_start(self.cell2, True)
+               self.tvcolumn2.pack_start(self.cell2, True)
                self.tvcolumn3.pack_start(self.cell3, True)
-               
-               self.tvcolumn1.set_attributes(self.cell1, text=0) #Spalten setzten hier!!!!
-               self.tvcolumn2.set_attributes(self.cell2, text=1)
-               self.tvcolumn3.set_attributes(self.cell3, text=2)
 
-               # make treeview searchable
-               #self.treeview.set_search_column(0)
+               self.tvcolumn1.set_attributes(self.cell1, text = 0) #Spalten setzten hier!!!!
+               self.tvcolumn2.set_attributes(self.cell2, text = 1)
+               self.tvcolumn3.set_attributes(self.cell3, text = 2)
+
+               # make treeview searchable
+               #self.treeview.set_search_column(0)
                #self.tvcolumn.set_sort_column_id(0)
-               
+
                # Allow NOT drag and drop reordering of rows
-               self.treeview.set_reorderable(False)
-               
+               self.treeview.set_reorderable(False)
+
                scrolled_window = gtk.ScrolledWindow()
-               scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
+               scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                scrolled_window.add(self.treeview)
-               #self.pack_start(scrolled_window, expand=True, fill=True, padding=0)
-               
-               
+               #self.pack_start(scrolled_window, expand = True, fill = True, padding = 0)
+
                self.vbox.pack_start(scrolled_window, True, True, 0)
-               
-               self.vbox.show_all()
-               
-               msgstring=""
-               sql="SELECT pcdatum,sql,param FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
-               rows=db.ladeSQL(sql,(time.time()-3*24*3600,))
-               i=0
-               for row in rows:
-                       pcdatum,sql,param = row
-                       datum=str(time.strftime("%d.%m.%y %H:%M:%S ", (time.localtime(pcdatum))))
-                       if len(param)>100:
-                               param=param[:20]+_(" (Reduced parameter) ")+param[20:]
-                       self.liststore.append([datum, sql,param])
-                       i+=1
+
+               self.vbox.show_all()
+
+               msgstring = ""
+               sql = "SELECT pcdatum, sql, param FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
+               rows = db.ladeSQL(sql, (time.time()-3*24*3600, ))
+               for i, row in enumerate(rows):
                        if (i>50):
                                break
-                       
-               self.set_size_request(500,400)
-               
-               
-               
+
+                       pcdatum, sql, param = row
+                       datum = str(time.strftime("%d.%m.%y %H:%M:%S ", (time.localtime(pcdatum))))
+                       if 100 < len(param):
+                               param = param[:20]+_(" (Reduced parameter) ")+param[20:]
+                       self.liststore.append([datum, sql, param])
+
+               self.set_size_request(500, 400)
+
+       def exportSQL(self, filename):
+               with open(filename, 'w') as f:
+                       msgstring = ""
+                       sql = "SELECT pcdatum, sql, param FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
+                       rows = self.db.ladeSQL(sql, (time.time()-2*24*3600, ))
+                       for row in rows:
+                               pcdatum, sql, param = row
+                               datum = str(time.strftime("%d.%m.%y %H:%M:%S ", (time.localtime(pcdatum))))
+                               f.write( datum +"\t" + sql + "\t\t" + param+ "\n")