More cleanup
authorEd Page <eopage@byu.net>
Thu, 18 Mar 2010 22:57:45 +0000 (17:57 -0500)
committerEd Page <eopage@byu.net>
Thu, 18 Mar 2010 22:57:45 +0000 (17:57 -0500)
32 files changed:
Makefile
data/multilist.desktop
src/__init__.py [new file with mode: 0755]
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 [new file with mode: 0644]
src/libliststorehandler.py [new file with mode: 0644]
src/libmultilist.py [new file with mode: 0755]
src/libselection.py [new file with mode: 0644]
src/libspeichern.py [new file with mode: 0644]
src/libsqldialog.py [new file with mode: 0755]
src/libsync.py [new file with mode: 0755]
src/libview.py [new file with mode: 0644]
src/multilist [deleted file]
src/multilist.py [new file with mode: 0755]
src/multilistclasses/__init__.py [deleted file]
src/multilistclasses/libbottombar.py [deleted file]
src/multilistclasses/libliststorehandler.py [deleted file]
src/multilistclasses/libmultilist.py [deleted file]
src/multilistclasses/libselection.py [deleted file]
src/multilistclasses/libspeichern.py [deleted file]
src/multilistclasses/libsqldialog.py [deleted file]
src/multilistclasses/libsync.py [deleted file]
src/multilistclasses/libview.py [deleted file]
src/upload.sh [deleted file]
support/builddeb.py [new file with mode: 0755]
support/fake_py2deb.py [new file with mode: 0644]
support/py2deb.py [new file with mode: 0644]
support/pylint.rc [new file with mode: 0644]
support/test_syntax.py [new file with mode: 0755]
support/todo.py [new file with mode: 0755]

index ab363c7..7c8aef1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,45 @@
-all: build_mo
-       python2.5 setup.py build  
-clean: 
-       rm -rf ./locale ./po/templates.pot
-       python2.5 setup.py clean --all
-install: build_mo
-       python2.5 setup.py install --root $(DESTDIR) 
+PROJECT_NAME=multilist
+PROJECT_VERSION=0.3.1
+SOURCE_PATH=src
+SOURCE=$(shell find $(SOURCE_PATH) -iname "*.py")
+LOCALE_PATH=locale
+LOCALE_FILES=$(shell find $(LOCALE_PATH) -iname "*.mo")
+PROGRAM=$(SOURCE_PATH)/$(PROJECT_NAME).py
+OBJ=$(SOURCE:.py=.pyc)
+BUILD_PATH=./builddeb/
 
-TEXT_DOMAIN=multilist
-POTFILES=src/multilist $(wildcard src/multilistclasses/*.py)
+TEXT_DOMAIN=$(PROJECT_NAME)
+POTFILES=$(wildcard src/quicknoteclasses/*.py)
+TAG_FILE=~/.ctags/$(PROJECT_NAME).tags
+TODO_FILE=./TODO
+
+DEBUGGER=winpdb
+UNIT_TEST=nosetests --with-doctest -w .
+SYNTAX_TEST=support/test_syntax.py
+STYLE_TEST=../../Python/tools/pep8.py --ignore=W191,E501
+LINT_RC=./support/pylint.rc
+LINT=pylint --rcfile=$(LINT_RC)
+PROFILE_GEN=python -m cProfile -o .profile
+PROFILE_VIEW=python -m pstats .profile
+TODO_FINDER=support/todo.py
+CTAGS=ctags-exuberant
+
+.PHONY: all run profile debug test lint tags todo clean distclean install update_po build_mo
+
+all: test
+
+run: $(OBJ)
+       $(PROGRAM)
+
+profile: $(OBJ)
+       $(PROFILE_GEN) $(PROGRAM)
+       $(PROFILE_VIEW)
+
+debug: $(OBJ)
+       $(DEBUGGER) $(PROGRAM)
+
+test: $(OBJ)
+       $(UNIT_TEST)
 
 update_po: po/templates.pot
        @for lang in $(basename $(notdir $(wildcard po/*.po))); do \
@@ -23,4 +55,73 @@ build_mo:
                msgfmt --statistics -c -o locale/$$lang/LC_MESSAGES/$(TEXT_DOMAIN).mo po/$$lang.po; \
        done
 
-.PHONES: update_po build_mo
+package: $(OBJ) build_mo
+       rm -Rf $(BUILD_PATH)
+
+       mkdir -p $(BUILD_PATH)/generic
+       cp $(SOURCE_PATH)/constants.py $(BUILD_PATH)/generic
+       cp $(PROGRAM)  $(BUILD_PATH)/generic
+       $(foreach file, $(DATA), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
+       $(foreach file, $(SOURCE), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
+       #$(foreach file, $(OBJ), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
+       $(foreach file, $(LOCALE_FILES), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
+       cp data/$(PROJECT_NAME).desktop $(BUILD_PATH)/generic
+       cp data/$(PROJECT_NAME).service $(BUILD_PATH)/generic
+       cp data/26_$(PROJECT_NAME).png $(BUILD_PATH)/generic/26x26-$(PROJECT_NAME).png
+       cp data/40_$(PROJECT_NAME).png $(BUILD_PATH)/generic/40x40-$(PROJECT_NAME).png
+       cp data/64_$(PROJECT_NAME).png $(BUILD_PATH)/generic/scale-$(PROJECT_NAME).png
+       cp support/builddeb.py $(BUILD_PATH)/generic
+       cp support/py2deb.py $(BUILD_PATH)/generic
+       cp support/fake_py2deb.py $(BUILD_PATH)/generic
+
+       mkdir -p $(BUILD_PATH)/diablo
+       cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/diablo
+       cd $(BUILD_PATH)/diablo ; python builddeb.py diablo
+       mkdir -p $(BUILD_PATH)/fremantle
+       cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/fremantle
+       cd $(BUILD_PATH)/fremantle ; python builddeb.py fremantle
+       mkdir -p $(BUILD_PATH)/debian
+       cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/debian
+       cd $(BUILD_PATH)/debian ; python builddeb.py debian
+
+upload:
+       dput fremantle-extras-builder $(BUILD_PATH)/fremantle/$(PROJECT_NAME)*.changes
+       dput diablo-extras-builder $(BUILD_PATH)/diablo/$(PROJECT_NAME)*.changes
+       cp $(BUILD_PATH)/debian/*.deb ../www/$(PROJECT_NAME).deb
+
+lint: $(OBJ)
+       $(foreach file, $(SOURCE), $(LINT) $(file) ; )
+
+tags: $(TAG_FILE) 
+
+todo: $(TODO_FILE)
+
+clean:
+       rm -rf ./locale
+       rm -Rf $(OBJ)
+       rm -Rf $(BUILD_PATH)
+       rm -Rf $(TODO_FILE)
+
+distclean:
+       rm -Rf $(OBJ)
+       rm -Rf $(BUILD_PATH)
+       rm -Rf $(TAG_FILE)
+       find $(SOURCE_PATH) -name "*.*~" | xargs rm -f
+       find $(SOURCE_PATH) -name "*.swp" | xargs rm -f
+       find $(SOURCE_PATH) -name "*.bak" | xargs rm -f
+       find $(SOURCE_PATH) -name ".*.swp" | xargs rm -f
+
+$(TAG_FILE): $(OBJ)
+       mkdir -p $(dir $(TAG_FILE))
+       $(CTAGS) -o $(TAG_FILE) $(SOURCE)
+
+$(TODO_FILE): $(SOURCE)
+       @- $(TODO_FINDER) $(SOURCE) > $(TODO_FILE)
+
+%.pyc: %.py
+       $(SYNTAX_TEST) $<
+
+#Makefile Debugging
+#Target to print any variable, can be added to the dependencies of any other target
+#Userfule flags for make, -d, -p, -n
+print-%: ; @$(error $* is $($*) ($(value $*)) (from $(origin $*)))
index 0613db5..6db4c8e 100644 (file)
@@ -1,9 +1,11 @@
 [Desktop Entry]
-Version=0.3.0
 Encoding=UTF-8
-Name=Multilist
-Exec=/usr/bin/multilist
-Icon=multilist
+Name=quicknote
+Comment=quicknote
 Type=Application
-#X-Osso-Service=multilist
-X-Osso-Type=application/x-executable 
+Exec=/usr/bin/run-standalone.sh /usr/bin/multilist.py
+Icon=Quicknote
+X-Window-Icon=quicknote
+X-Window-Icon-Dimmed=quicknote
+#X-Osso-Service=quicknote
+X-Osso-Type=application/x-executable
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100755 (executable)
index 0000000..105eaaf
--- /dev/null
@@ -0,0 +1,21 @@
+#!/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
+""" 
diff --git a/src/constants.py b/src/constants.py
new file mode 100644 (file)
index 0000000..959dc09
--- /dev/null
@@ -0,0 +1,9 @@
+import os
+
+__pretty_app_name__ = "Multilist"
+__app_name__ = "multilist"
+__version__ = "0.3.2"
+__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..09ee705
--- /dev/null
@@ -0,0 +1,754 @@
+#!/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_mark_window_rotatable(window):
+       # gtk documentation is unclear whether this does a "=" or a "|="
+       window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
+
+
+def _null_mark_window_rotatable(window):
+       pass
+
+
+try:
+       hildon.HILDON_PORTRAIT_MODE_SUPPORT
+       mark_window_rotatable = _hildon_mark_window_rotatable
+except AttributeError:
+       mark_window_rotatable = _null_mark_window_rotatable
+
+
+def _hildon_window_to_portrait(window):
+       # gtk documentation is unclear whether this does a "=" or a "|="
+       window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
+
+
+def _hildon_window_to_landscape(window):
+       # gtk documentation is unclear whether this does a "=" or a "&= ~"
+       window.unset_flags(hildon.HILDON_PORTRAIT_MODE_REQUEST)
+
+
+def _null_window_to_portrait(window):
+       pass
+
+
+def _null_window_to_landscape(window):
+       pass
+
+
+try:
+       hildon.HILDON_PORTRAIT_MODE_SUPPORT
+       hildon.HILDON_PORTRAIT_MODE_REQUEST
+
+       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)
diff --git a/src/libbottombar.py b/src/libbottombar.py
new file mode 100644 (file)
index 0000000..654c72d
--- /dev/null
@@ -0,0 +1,166 @@
+#!/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 gobject
+import time
+import logging
+
+import gtk
+
+class Bottombar(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))
+       }
+
+               
+       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()
+               entryKlasse.set_text("")
+               
+               dialog.vbox.pack_start(entryKlasse, True, True, 0)
+               
+               dialog.vbox.show_all()
+               #dialog.set_size_request(400,300)
+
+               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):
+               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()
+               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)
+
+               if dialog.run() == gtk.RESPONSE_ACCEPT:
+                       logging.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()
+               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)
+
+               if dialog.run() == gtk.RESPONSE_ACCEPT:
+                       logging.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)
+               
+               
+               
diff --git a/src/libliststorehandler.py b/src/libliststorehandler.py
new file mode 100644 (file)
index 0000000..933a90c
--- /dev/null
@@ -0,0 +1,218 @@
+#!/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 gtk
+import gobject
+import libspeichern
+import logging
+
+
+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)
+               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","","","","","",""])   
+               
+               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)
+               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))
+               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)):
+                       for row in rows:
+                               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","","","","","","","","","","",""])
+               
+               return self.liststore
+       
+       
+       def emptyValueExists(self):
+               for child in self.liststore:
+                       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 
+               else:
+                       logging.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"))
+               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()
+               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," ","","","","","","","","",""])
+               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]
+               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):
+                       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()
+               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(),))
+               self.selection.load()
+               self.selection.set_list(new_name)       
+       
+       
+       #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
diff --git a/src/libmultilist.py b/src/libmultilist.py
new file mode 100755 (executable)
index 0000000..69321c6
--- /dev/null
@@ -0,0 +1,401 @@
+#!/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
+"""
+
+#/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/
+
+import time
+import os
+import sys
+import logging
+
+try:
+        import gtk
+        #import gtk.glade
+except:
+       print "gtk import failed"
+        sys.exit(1)
+       
+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
+import libspeichern
+import libsqldialog
+import libselection
+import libview
+import libliststorehandler
+import libsync
+import libbottombar
+
+version = "0.3.0"
+app_name = "multilist"
+
+               
+       
+
+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()
+               
+
+
+       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)
+               
+               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)
+               
+               #Haupt vbox für alle Elemente
+               self.vbox = gtk.VBox(homogeneous=False, spacing=0)
+               
+               
+               
+               #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()
+               else:
+                       self.vbox.pack_start(menu_bar, False, False, 2)
+               
+               
+               
+
+               #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.window.add(self.vbox)
+               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
+
+
+       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()
+               sqldiag.hide()
+               if res==444:
+                       logging.info("exporting sql")
+                       
+                       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)
+                       
+                       dlg.set_title(_("Select SQL export file"))
+                       if dlg.run() == gtk.RESPONSE_OK:
+                               fileName = dlg.get_filename()
+                               dlg.destroy()
+                               sqldiag.exportSQL(fileName)
+                       else:
+                               dlg.destroy()
+                               
+               sqldiag.destroy()
+
+               
+       def optimizeSQL(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'):
+                       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()
+               
+               
+               
+
diff --git a/src/libselection.py b/src/libselection.py
new file mode 100644 (file)
index 0000000..9ab8651
--- /dev/null
@@ -0,0 +1,191 @@
+#!/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 gobject
+import time
+import logging
+
+import gtk
+
+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))
+       }
+
+       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)):
+                       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)
+               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)):
+                       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 len(s)>0:
+                       self.comboCategory.get_child().set_text(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","")
+
+       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)
+               
+
+       def lade(self):
+               logging.warning("Laden der aktuellen position noch nicht implementiert")
+
+       
+       def speichere(self):
+               logging.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):
+                               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 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)
+               
+               
+               
diff --git a/src/libspeichern.py b/src/libspeichern.py
new file mode 100644 (file)
index 0000000..e887340
--- /dev/null
@@ -0,0 +1,191 @@
+#!/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 time
+import sqlite3
+import shelve
+import sys
+import string
+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))
+
+
+                               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
+
+       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()
+               except:
+                       pass
+               try:
+                       self.conn.close()
+               except:
+                       pass
+               
+               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/")):
+                       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))
+                       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()
+               try:
+                       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()
+               except:
+                       pass
+               
+               #Add rowid line (not in old versions included)
+               try:
+                       sql="ALTER TABLE logtable ADD rowid TEXT"
+                       self.cur.execute(sql)
+                       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()
+               except:
+                       pass
+               try:
+                       self.cur.close()
+               except:
+                       pass
+               try:
+                       self.conn.close()
+               except:
+                       pass
+               logging.info("Alle Daten gespeichert")
+               
+       def __del__(self):
+               self.close()
\ No newline at end of file
diff --git a/src/libsqldialog.py b/src/libsqldialog.py
new file mode 100755 (executable)
index 0000000..2f384a8
--- /dev/null
@@ -0,0 +1,125 @@
+#!/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 gobject
+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)
+               
+               
+               self.liststore = gtk.ListStore(str, str, str)
+
+               # 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.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'))
+               self.tvcolumn3 = gtk.TreeViewColumn(_('Parameter'))
+               
+               # 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.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.tvcolumn.set_sort_column_id(0)
+               
+               # Allow NOT drag and drop reordering of rows
+               self.treeview.set_reorderable(False)
+               
+               scrolled_window = gtk.ScrolledWindow()
+               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.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
+                       if (i>50):
+                               break
+                       
+               self.set_size_request(500,400)
+               
+               
+               
diff --git a/src/libsync.py b/src/libsync.py
new file mode 100755 (executable)
index 0000000..a793a16
--- /dev/null
@@ -0,0 +1,436 @@
+#!/usr/bin/env python
+# -*- 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/>.
+"""
+
+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 select
+#import fcntl
+import struct
+import gtk
+import uuid
+import sys
+import logging
+
+import libspeichern 
+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"))
+               self.vbox.pack_start(label, True, True, 0)
+               label=gtk.Label(_("(this can take some minutes)"))
+               self.vbox.pack_start(label, True, True, 0)
+               
+               #self.progressbar=gtk.ProgressBar()
+               #self.vbox.pack_start(self.progressbar, True, True, 0)
+               
+               #self.set_keep_above(True)
+               self.vbox.show_all()
+               self.show()
+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):
+               self.syncStatusLabel.set_text(title)
+               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()            
+                               self.progress.destroy()
+                               self.progress=None
+                               self.emit("syncFinished","syncFinished")
+       
+       def pulse(self):
+               if self.progress!=None:
+                       self.progress.pulse()
+               #if self.server!=None:
+               #       self.server.pulse()
+               
+       
+       def getUeberblickBox(self):
+               frame=gtk.Frame(_("Query"))
+               return frame
+                       
+       def handleRPC(self):
+               try:
+                       if (self.rpcserver==None): return False
+               except:
+                       return False
+                       
+               while (len(self.poll.poll(0))>0):
+                       self.rpcserver.handle_request()
+               return True
+
+       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])
+               #       s.close()
+               #except:
+               #       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]
+               else:
+                       pcdatum=-1
+               logging.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
+                       
+                       if len(rowid)>0:
+                               for x in self.concernedRows:
+                                       #logging.info("check4commit 3")
+                                       if (x[1]==rowid):
+                                               if (x[0]>pcdatum):
+                                                       logging.info("newer sync entry, ignoring old one")
+                                                       #logging.info("check4commit 9.1")
+                                                       return False
+                                               else:
+                                                       #logging.info("check4commit 9.2")
+                                                       return True
+                                                       
+               #logging.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")
+               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 ""
+                       if (newSQL[3]!=""):
+                               param=string.split(newSQL[3]," <<Tren-ner>> ")
+                       else:
+                               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:
+                               self.pulse()
+                               while (gtk.events_pending()):
+                                       gtk.main_iteration();
+                               
+               logging.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"))
+               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:
+                       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
+               return rows
+               
+       def getRemoteSyncUUID(self):
+               return self.sync_uuid
+       
+       
+       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")
+                       
+                       try:
+                               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.register(self.rpcserver.fileno())
+                               gobject.timeout_add(1000, self.handleRPC)
+                               self.syncServerStatusLabel.set_text(_("Syncserver running..."))
+                       
+                               #save
+                               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
+                               mbox.set_modal(False)
+                               response=mbox.run() 
+                               mbox.hide() 
+                               mbox.destroy() 
+                               widget.set_active(False)
+                               
+               else:
+                       logging.info("Stopping Server")
+                       try:
+                               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())
+               if (time.time()>pcdatum):
+                       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)
+               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.db.speichereSQL(sql)
+               
+               self.changeSyncStatus(True,_("sync process running"))
+               while (gtk.events_pending()):
+                       gtk.main_iteration();
+
+               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))
+                       
+                       #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"
+
+               
+               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)
+                       
+               #print "Sync, 9"
diff --git a/src/libview.py b/src/libview.py
new file mode 100644 (file)
index 0000000..481464c
--- /dev/null
@@ -0,0 +1,563 @@
+#!/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 gtk
+import gobject
+import logging
+import pango
+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)
+
+       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):
+       __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)),
+       }
+
+
+       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
+               setattr(self, property.name, value)
+
+       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
+
+       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):
+               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()
+               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"
+               
+               
+       def reload_view(self):
+               # 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.set_headers_visible(True)
+               
+               
+               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"
+                       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):
+                                       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.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)
+                               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].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.scrolled_window.destroy()
+               
+               self.scrolled_window = gtk.ScrolledWindow()
+               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.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()
+
diff --git a/src/multilist b/src/multilist
deleted file mode 100755 (executable)
index aa7cc92..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/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 os
-import sys
-
-##
-## I18N
-##
-import locale
-import gettext
-gettext.install('multilist', unicode=1)
-                       
-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()
-
-       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"))
-               
-       
diff --git a/src/multilist.py b/src/multilist.py
new file mode 100755 (executable)
index 0000000..aa7cc92
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 os
+import sys
+
+##
+## I18N
+##
+import locale
+import gettext
+gettext.install('multilist', unicode=1)
+                       
+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()
+
+       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"))
+               
+       
diff --git a/src/multilistclasses/__init__.py b/src/multilistclasses/__init__.py
deleted file mode 100755 (executable)
index 105eaaf..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/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
-""" 
diff --git a/src/multilistclasses/libbottombar.py b/src/multilistclasses/libbottombar.py
deleted file mode 100644 (file)
index 654c72d..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/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 gobject
-import time
-import logging
-
-import gtk
-
-class Bottombar(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))
-       }
-
-               
-       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()
-               entryKlasse.set_text("")
-               
-               dialog.vbox.pack_start(entryKlasse, True, True, 0)
-               
-               dialog.vbox.show_all()
-               #dialog.set_size_request(400,300)
-
-               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):
-               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()
-               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)
-
-               if dialog.run() == gtk.RESPONSE_ACCEPT:
-                       logging.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()
-               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)
-
-               if dialog.run() == gtk.RESPONSE_ACCEPT:
-                       logging.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)
-               
-               
-               
diff --git a/src/multilistclasses/libliststorehandler.py b/src/multilistclasses/libliststorehandler.py
deleted file mode 100644 (file)
index 933a90c..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/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 gtk
-import gobject
-import libspeichern
-import logging
-
-
-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)
-               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","","","","","",""])   
-               
-               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)
-               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))
-               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)):
-                       for row in rows:
-                               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","","","","","","","","","","",""])
-               
-               return self.liststore
-       
-       
-       def emptyValueExists(self):
-               for child in self.liststore:
-                       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 
-               else:
-                       logging.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"))
-               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()
-               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," ","","","","","","","","",""])
-               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]
-               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):
-                       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()
-               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(),))
-               self.selection.load()
-               self.selection.set_list(new_name)       
-       
-       
-       #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
diff --git a/src/multilistclasses/libmultilist.py b/src/multilistclasses/libmultilist.py
deleted file mode 100755 (executable)
index 69321c6..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-#!/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
-"""
-
-#/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/
-
-import time
-import os
-import sys
-import logging
-
-try:
-        import gtk
-        #import gtk.glade
-except:
-       print "gtk import failed"
-        sys.exit(1)
-       
-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
-import libspeichern
-import libsqldialog
-import libselection
-import libview
-import libliststorehandler
-import libsync
-import libbottombar
-
-version = "0.3.0"
-app_name = "multilist"
-
-               
-       
-
-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()
-               
-
-
-       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)
-               
-               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)
-               
-               #Haupt vbox für alle Elemente
-               self.vbox = gtk.VBox(homogeneous=False, spacing=0)
-               
-               
-               
-               #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()
-               else:
-                       self.vbox.pack_start(menu_bar, False, False, 2)
-               
-               
-               
-
-               #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.window.add(self.vbox)
-               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
-
-
-       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()
-               sqldiag.hide()
-               if res==444:
-                       logging.info("exporting sql")
-                       
-                       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)
-                       
-                       dlg.set_title(_("Select SQL export file"))
-                       if dlg.run() == gtk.RESPONSE_OK:
-                               fileName = dlg.get_filename()
-                               dlg.destroy()
-                               sqldiag.exportSQL(fileName)
-                       else:
-                               dlg.destroy()
-                               
-               sqldiag.destroy()
-
-               
-       def optimizeSQL(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'):
-                       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()
-               
-               
-               
-
diff --git a/src/multilistclasses/libselection.py b/src/multilistclasses/libselection.py
deleted file mode 100644 (file)
index 9ab8651..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/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 gobject
-import time
-import logging
-
-import gtk
-
-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))
-       }
-
-       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)):
-                       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)
-               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)):
-                       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 len(s)>0:
-                       self.comboCategory.get_child().set_text(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","")
-
-       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)
-               
-
-       def lade(self):
-               logging.warning("Laden der aktuellen position noch nicht implementiert")
-
-       
-       def speichere(self):
-               logging.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):
-                               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 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)
-               
-               
-               
diff --git a/src/multilistclasses/libspeichern.py b/src/multilistclasses/libspeichern.py
deleted file mode 100644 (file)
index e887340..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/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 time
-import sqlite3
-import shelve
-import sys
-import string
-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))
-
-
-                               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
-
-       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()
-               except:
-                       pass
-               try:
-                       self.conn.close()
-               except:
-                       pass
-               
-               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/")):
-                       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))
-                       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()
-               try:
-                       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()
-               except:
-                       pass
-               
-               #Add rowid line (not in old versions included)
-               try:
-                       sql="ALTER TABLE logtable ADD rowid TEXT"
-                       self.cur.execute(sql)
-                       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()
-               except:
-                       pass
-               try:
-                       self.cur.close()
-               except:
-                       pass
-               try:
-                       self.conn.close()
-               except:
-                       pass
-               logging.info("Alle Daten gespeichert")
-               
-       def __del__(self):
-               self.close()
\ No newline at end of file
diff --git a/src/multilistclasses/libsqldialog.py b/src/multilistclasses/libsqldialog.py
deleted file mode 100755 (executable)
index 2f384a8..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/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 gobject
-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)
-               
-               
-               self.liststore = gtk.ListStore(str, str, str)
-
-               # 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.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'))
-               self.tvcolumn3 = gtk.TreeViewColumn(_('Parameter'))
-               
-               # 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.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.tvcolumn.set_sort_column_id(0)
-               
-               # Allow NOT drag and drop reordering of rows
-               self.treeview.set_reorderable(False)
-               
-               scrolled_window = gtk.ScrolledWindow()
-               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.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
-                       if (i>50):
-                               break
-                       
-               self.set_size_request(500,400)
-               
-               
-               
diff --git a/src/multilistclasses/libsync.py b/src/multilistclasses/libsync.py
deleted file mode 100755 (executable)
index a793a16..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-#!/usr/bin/env python
-# -*- 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/>.
-"""
-
-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 select
-#import fcntl
-import struct
-import gtk
-import uuid
-import sys
-import logging
-
-import libspeichern 
-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"))
-               self.vbox.pack_start(label, True, True, 0)
-               label=gtk.Label(_("(this can take some minutes)"))
-               self.vbox.pack_start(label, True, True, 0)
-               
-               #self.progressbar=gtk.ProgressBar()
-               #self.vbox.pack_start(self.progressbar, True, True, 0)
-               
-               #self.set_keep_above(True)
-               self.vbox.show_all()
-               self.show()
-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):
-               self.syncStatusLabel.set_text(title)
-               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()            
-                               self.progress.destroy()
-                               self.progress=None
-                               self.emit("syncFinished","syncFinished")
-       
-       def pulse(self):
-               if self.progress!=None:
-                       self.progress.pulse()
-               #if self.server!=None:
-               #       self.server.pulse()
-               
-       
-       def getUeberblickBox(self):
-               frame=gtk.Frame(_("Query"))
-               return frame
-                       
-       def handleRPC(self):
-               try:
-                       if (self.rpcserver==None): return False
-               except:
-                       return False
-                       
-               while (len(self.poll.poll(0))>0):
-                       self.rpcserver.handle_request()
-               return True
-
-       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])
-               #       s.close()
-               #except:
-               #       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]
-               else:
-                       pcdatum=-1
-               logging.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
-                       
-                       if len(rowid)>0:
-                               for x in self.concernedRows:
-                                       #logging.info("check4commit 3")
-                                       if (x[1]==rowid):
-                                               if (x[0]>pcdatum):
-                                                       logging.info("newer sync entry, ignoring old one")
-                                                       #logging.info("check4commit 9.1")
-                                                       return False
-                                               else:
-                                                       #logging.info("check4commit 9.2")
-                                                       return True
-                                                       
-               #logging.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")
-               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 ""
-                       if (newSQL[3]!=""):
-                               param=string.split(newSQL[3]," <<Tren-ner>> ")
-                       else:
-                               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:
-                               self.pulse()
-                               while (gtk.events_pending()):
-                                       gtk.main_iteration();
-                               
-               logging.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"))
-               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:
-                       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
-               return rows
-               
-       def getRemoteSyncUUID(self):
-               return self.sync_uuid
-       
-       
-       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")
-                       
-                       try:
-                               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.register(self.rpcserver.fileno())
-                               gobject.timeout_add(1000, self.handleRPC)
-                               self.syncServerStatusLabel.set_text(_("Syncserver running..."))
-                       
-                               #save
-                               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
-                               mbox.set_modal(False)
-                               response=mbox.run() 
-                               mbox.hide() 
-                               mbox.destroy() 
-                               widget.set_active(False)
-                               
-               else:
-                       logging.info("Stopping Server")
-                       try:
-                               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())
-               if (time.time()>pcdatum):
-                       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)
-               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.db.speichereSQL(sql)
-               
-               self.changeSyncStatus(True,_("sync process running"))
-               while (gtk.events_pending()):
-                       gtk.main_iteration();
-
-               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))
-                       
-                       #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"
-
-               
-               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)
-                       
-               #print "Sync, 9"
diff --git a/src/multilistclasses/libview.py b/src/multilistclasses/libview.py
deleted file mode 100644 (file)
index 481464c..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-#!/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 gtk
-import gobject
-import logging
-import pango
-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)
-
-       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):
-       __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)),
-       }
-
-
-       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
-               setattr(self, property.name, value)
-
-       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
-
-       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):
-               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()
-               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"
-               
-               
-       def reload_view(self):
-               # 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.set_headers_visible(True)
-               
-               
-               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"
-                       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):
-                                       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.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)
-                               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].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.scrolled_window.destroy()
-               
-               self.scrolled_window = gtk.ScrolledWindow()
-               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.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()
-
diff --git a/src/upload.sh b/src/upload.sh
deleted file mode 100755 (executable)
index 3a3fd46..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-scp ../../multilist_0.3.0_all.deb user@192.168.0.34:/media/mmc2/
-
-
-
-
diff --git a/support/builddeb.py b/support/builddeb.py
new file mode 100755 (executable)
index 0000000..363f470
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/python2.5
+
+import os
+import sys
+
+try:
+       import py2deb
+except ImportError:
+       import fake_py2deb as py2deb
+
+import constants
+
+
+__appname__ = constants.__app_name__
+__description__ = """Simple list management application
+.
+Homepage: http://multilist.garage.maemo.org/
+"""
+__author__ = "Christoph Wurstle"
+__email__ = "n800@axique.net"
+__version__ = constants.__version__
+__build__ = constants.__build__
+__changelog__ = """
+0.3.1
+  * I18N, extract de.po, add ru.po.
+0.3.0
+  * Initial Release.
+"""
+
+
+__postinstall__ = """#!/bin/sh -e
+
+gtk-update-icon-cache -f /usr/share/icons/hicolor
+rm -f ~/.multilist/multilist.log
+"""
+
+
+def find_files(path, root):
+       print path, root
+       for unusedRoot, dirs, files in os.walk(path):
+               for file in files:
+                       if file.startswith(root+"-"):
+                               print "\t", root, file
+                               fileParts = file.split("-")
+                               unused, relPathParts, newName = fileParts[0], fileParts[1:-1], fileParts[-1]
+                               assert unused == root
+                               relPath = os.sep.join(relPathParts)
+                               yield relPath, file, newName
+
+
+def unflatten_files(files):
+       d = {}
+       for relPath, oldName, newName in files:
+               if relPath not in d:
+                       d[relPath] = []
+               d[relPath].append((oldName, newName))
+       return d
+
+
+def build_package(distribution):
+       try:
+               os.chdir(os.path.dirname(sys.argv[0]))
+       except:
+               pass
+
+       py2deb.Py2deb.SECTIONS = py2deb.SECTIONS_BY_POLICY[distribution]
+       p = py2deb.Py2deb(__appname__)
+       p.prettyName = constants.__pretty_app_name__
+       p.description = __description__
+       p.bugTracker = "https://bugs.maemo.org/enter_bug.cgi?product=quicknote"
+       p.upgradeDescription = __changelog__.split("\n\n", 1)[0]
+       p.author = __author__
+       p.mail = __email__
+       p.license = "gpl"
+       p.depends = ", ".join([
+               "python2.6 | python2.5",
+               "python-gtk2 | python2.5-gtk2",
+               "python-xml | python2.5-xml",
+               "python-dbus | python2.5-dbus",
+       ])
+       maemoSpecificDepends = ", python-osso | python2.5-osso, python-hildon | python2.5-hildon"
+       p.depends += {
+               "debian": ", python-glade2",
+               "diablo": maemoSpecificDepends,
+               "fremantle": maemoSpecificDepends + ", python-glade2",
+       }[distribution]
+       p.section = {
+               "debian": "editors",
+               "diablo": "user/office",
+               "fremantle": "user/office",
+       }[distribution]
+       p.arch = "all"
+       p.urgency = "low"
+       p.distribution = "diablo fremantle debian"
+       p.repository = "extras"
+       p.changelog = __changelog__
+       p.postinstall = __postinstall__
+       p.icon = {
+               "debian": "26x26-multilist.png",
+               "diablo": "26x26-multilist.png",
+               "fremantle": "48x48-multilist.png", # Fremantle natively uses 48x48
+       }[distribution]
+       p["/usr/bin"] = [ "multilist.py" ]
+       for relPath, files in unflatten_files(find_files(".", "locale")).iteritems():
+               fullPath = "/usr/share/locale"
+               if relPath:
+                       fullPath += os.sep+relPath
+               p[fullPath] = list(
+                       "|".join((oldName, newName))
+                       for (oldName, newName) in files
+               )
+       for relPath, files in unflatten_files(find_files(".", "src")).iteritems():
+               fullPath = "/usr/lib/multilist"
+               if relPath:
+                       fullPath += os.sep+relPath
+               p[fullPath] = list(
+                       "|".join((oldName, newName))
+                       for (oldName, newName) in files
+               )
+       p["/usr/share/applications/hildon"] = ["multilist.desktop"]
+       p["/usr/share/icons/hicolor/26x26/hildon"] = ["26x26-multilist.png|multilist.png"]
+       p["/usr/share/icons/hicolor/40x40/hildon"] = ["40x40-multilist.png|multilist.png"]
+       p["/usr/share/icons/hicolor/scalable/hildon"] = ["scale-multilist.png|multilist.png"]
+
+       if distribution == "debian":
+               print p
+               print p.generate(
+                       version="%s-%s" % (__version__, __build__),
+                       changelog=__changelog__,
+                       build=True,
+                       tar=False,
+                       changes=False,
+                       dsc=False,
+               )
+               print "Building for %s finished" % distribution
+       else:
+               print p
+               print p.generate(
+                       version="%s-%s" % (__version__, __build__),
+                       changelog=__changelog__,
+                       build=False,
+                       tar=True,
+                       changes=True,
+                       dsc=True,
+               )
+               print "Building for %s finished" % distribution
+
+
+if __name__ == "__main__":
+       if len(sys.argv) > 1:
+               try:
+                       import optparse
+               except ImportError:
+                       optparse = None
+
+               if optparse is not None:
+                       parser = optparse.OptionParser()
+                       (commandOptions, commandArgs) = parser.parse_args()
+       else:
+               commandArgs = None
+               commandArgs = ["diablo"]
+       build_package(commandArgs[0])
diff --git a/support/fake_py2deb.py b/support/fake_py2deb.py
new file mode 100644 (file)
index 0000000..5d6149d
--- /dev/null
@@ -0,0 +1,56 @@
+import pprint
+
+
+class Py2deb(object):
+
+       def __init__(self, appName):
+               self._appName = appName
+               self.description = ""
+               self.author = ""
+               self.mail = ""
+               self.license = ""
+               self.depends = ""
+               self.section = ""
+               self.arch = ""
+               self.ugency = ""
+               self.distribution = ""
+               self.repository = ""
+               self.changelog = ""
+               self.postinstall = ""
+               self.icon = ""
+               self._install = {}
+
+       def generate(self, appVersion, appBuild, changelog, tar, dsc, changes, build, src):
+               return """
+Package: %s
+version: %s-%s
+Changes:
+%s
+
+Build Options:
+       Tar: %s
+       Dsc: %s
+       Changes: %s
+       Build: %s
+       Src: %s
+               """ % (
+                       self._appName, appVersion, appBuild, changelog, tar, dsc, changes, build, src
+               )
+
+       def __str__(self):
+               parts = []
+               parts.append("%s Package Settings:" % (self._appName, ))
+               for settingName in dir(self):
+                       if settingName.startswith("_"):
+                               continue
+                       parts.append("\t%s: %s" % (settingName, getattr(self, settingName)))
+
+               parts.append(pprint.pformat(self._install))
+
+               return "\n".join(parts)
+
+       def __getitem__(self, key):
+               return self._install[key]
+
+       def __setitem__(self, key, item):
+               self._install[key] = item
diff --git a/support/py2deb.py b/support/py2deb.py
new file mode 100644 (file)
index 0000000..4a47513
--- /dev/null
@@ -0,0 +1,991 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##
+##    Copyright (C) 2009 manatlan manatlan[at]gmail(dot)com
+##
+## 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; version 2 only.
+##
+## 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.
+##
+"""
+Known limitations :
+- don't sign package (-us -uc)
+- no distinctions between author and maintainer(packager)
+
+depends on :
+- dpkg-dev (dpkg-buildpackage)
+- alien
+- python
+- fakeroot
+
+changelog
+ - ??? ?/??/20?? (By epage)
+    - PEP8
+    - added recommends
+    - fixed bug where it couldn't handle the contents of the pre/post scripts being specified
+    - Added customization based on the targeted policy for sections (Maemo support)
+    - Added maemo specific tarball, dsc, changes file generation support (including icon support)
+    - Added armel architecture
+    - Reduced the size of params being passed around by reducing the calls to locals()
+    - Added respository, distribution, priority
+    - Made setting control file a bit more flexible
+ - 0.5 05/09/2009
+    - pre/post install/remove scripts enabled
+    - deb package install py2deb in dist-packages for py2.6
+ - 0.4 14/10/2008
+    - use os.environ USERNAME or USER (debian way)
+    - install on py 2.(4,5,6) (*FIX* do better here)
+
+"""
+
+import os
+import hashlib
+import sys
+import shutil
+import time
+import string
+import StringIO
+import stat
+import commands
+import base64
+import tarfile
+from glob import glob
+from datetime import datetime
+import socket # gethostname()
+from subprocess import Popen, PIPE
+
+#~ __version__ = "0.4"
+__version__ = "0.5"
+__author__ = "manatlan"
+__mail__ = "manatlan@gmail.com"
+
+
+PERMS_URW_GRW_OR = stat.S_IRUSR | stat.S_IWUSR | \
+                   stat.S_IRGRP | stat.S_IWGRP | \
+                   stat.S_IROTH
+
+UID_ROOT = 0
+GID_ROOT = 0
+
+
+def run(cmds):
+    p = Popen(cmds, shell=False, stdout=PIPE, stderr=PIPE)
+    time.sleep(0.01)    # to avoid "IOError: [Errno 4] Interrupted system call"
+    out = string.join(p.stdout.readlines()).strip()
+    outerr = string.join(p.stderr.readlines()).strip()
+    return out
+
+
+def deb2rpm(file):
+    txt=run(['alien', '-r', file])
+    return txt.split(" generated")[0]
+
+
+def py2src(TEMP, name):
+    l=glob("%(TEMP)s/%(name)s*.tar.gz" % locals())
+    if len(l) != 1:
+        raise Py2debException("don't find source package tar.gz")
+
+    tar = os.path.basename(l[0])
+    shutil.move(l[0], tar)
+
+    return tar
+
+
+def md5sum(filename):
+    f = open(filename, "r")
+    try:
+        return hashlib.md5(f.read()).hexdigest()
+    finally:
+        f.close()
+
+
+class Py2changes(object):
+
+    def __init__(self, ChangedBy, description, changes, files, category, repository, **kwargs):
+      self.options = kwargs # TODO: Is order important?
+      self.description = description
+      self.changes=changes
+      self.files=files
+      self.category=category
+      self.repository=repository
+      self.ChangedBy=ChangedBy
+
+    def getContent(self):
+        content = ["%s: %s" % (k, v)
+                   for k,v in self.options.iteritems()]
+
+        if self.description:
+            description=self.description.replace("\n","\n ")
+            content.append('Description: ')
+            content.append(' %s' % description)
+        if self.changes:
+            changes=self.changes.replace("\n","\n ")
+            content.append('Changes: ')
+            content.append(' %s' % changes)
+        if self.ChangedBy:
+            content.append("Changed-By: %s" % self.ChangedBy)
+
+        content.append('Files:')
+
+        for onefile in self.files:
+            md5 = md5sum(onefile)
+            size = os.stat(onefile).st_size.__str__()
+            content.append(' ' + md5 + ' ' + size + ' ' + self.category +' '+self.repository+' '+os.path.basename(onefile))
+
+        return "\n".join(content) + "\n\n"
+
+
+def py2changes(params):
+    changescontent = Py2changes(
+        "%(author)s <%(mail)s>" % params,
+        "%(description)s" % params,
+        "%(changelog)s" % params,
+        (
+            "%(TEMP)s/%(name)s_%(version)s.tar.gz" % params,
+            "%(TEMP)s/%(name)s_%(version)s.dsc" % params,
+        ),
+        "%(section)s" % params,
+        "%(repository)s" % params,
+        Format='1.7',
+        Date=time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()),
+        Source="%(name)s" % params,
+        Architecture="%(arch)s" % params,
+        Version="%(version)s" % params,
+        Distribution="%(distribution)s" % params,
+        Urgency="%(urgency)s" % params,
+        Maintainer="%(author)s <%(mail)s>" % params
+    )
+    f = open("%(TEMP)s/%(name)s_%(version)s.changes" % params,"wb")
+    f.write(changescontent.getContent())
+    f.close()
+
+    fileHandle = open('/tmp/py2deb2.tmp', 'w')
+    fileHandle.write('#!/bin/sh\n')
+    fileHandle.write("cd " +os.getcwd()+ "\n")
+    # TODO Renable signing
+    # fileHandle.write("gpg --local-user %(mail)s --clearsign %(TEMP)s/%(name)s_%(version)s.changes\n" % params)
+    fileHandle.write("mv %(TEMP)s/%(name)s_%(version)s.changes.asc %(TEMP)s/%(name)s_%(version)s.changes\n" % params)
+    fileHandle.write('\nexit')
+    fileHandle.close()
+    commands.getoutput("chmod 777 /tmp/py2deb2.tmp")
+    commands.getoutput("/tmp/py2deb2.tmp")
+
+    ret = []
+
+    l=glob("%(TEMP)s/%(name)s*.tar.gz" % params)
+    if len(l)!=1:
+        raise Py2debException("don't find source package tar.gz")
+    tar = os.path.basename(l[0])
+    shutil.move(l[0],tar)
+    ret.append(tar)
+
+    l=glob("%(TEMP)s/%(name)s*.dsc" % params)
+    if len(l)!=1:
+        raise Py2debException("don't find source package dsc")
+    tar = os.path.basename(l[0])
+    shutil.move(l[0],tar)
+    ret.append(tar)
+
+    l = glob("%(TEMP)s/%(name)s*.changes" % params)
+    if len(l)!=1:
+        raise Py2debException("don't find source package changes")
+    tar = os.path.basename(l[0])
+    shutil.move(l[0],tar)
+    ret.append(tar)
+
+    return ret
+
+
+class Py2dsc(object):
+
+    def __init__(self, StandardsVersion, BuildDepends, files, **kwargs):
+      self.options = kwargs # TODO: Is order important?
+      self.StandardsVersion = StandardsVersion
+      self.BuildDepends=BuildDepends
+      self.files=files
+
+    @property
+    def content(self):
+        content = ["%s: %s" % (k, v)
+                   for k,v in self.options.iteritems()]
+
+        if self.BuildDepends:
+            content.append("Build-Depends: %s" % self.BuildDepends)
+        if self.StandardsVersion:
+            content.append("Standards-Version: %s" % self.StandardsVersion)
+
+        content.append('Files:')
+
+        for onefile in self.files:
+            print onefile
+            md5 = md5sum(onefile)
+            size = os.stat(onefile).st_size.__str__()
+            content.append(' '+md5 + ' ' + size +' '+os.path.basename(onefile))
+
+        return "\n".join(content)+"\n\n"
+
+
+def py2dsc(TEMP, name, version, depends, author, mail, arch):
+    dsccontent = Py2dsc(
+        "%(version)s" % locals(),
+        "%(depends)s" % locals(),
+        ("%(TEMP)s/%(name)s_%(version)s.tar.gz" % locals(),),
+        Format='1.0',
+        Source="%(name)s" % locals(),
+        Version="%(version)s" % locals(),
+        Maintainer="%(author)s <%(mail)s>" % locals(),
+        Architecture="%(arch)s" % locals(),
+    )
+
+    filename = "%(TEMP)s/%(name)s_%(version)s.dsc" % locals()
+
+    f = open(filename, "wb")
+    try:
+        f.write(dsccontent.content)
+    finally:
+        f.close()
+
+    fileHandle = open('/tmp/py2deb.tmp', 'w')
+    try:
+        fileHandle.write('#!/bin/sh\n')
+        fileHandle.write("cd " + os.getcwd() + "\n")
+        # TODO Renable signing
+        # fileHandle.write("gpg --local-user %(mail)s --clearsign %(TEMP)s/%(name)s_%(version)s.dsc\n" % locals())
+        fileHandle.write("mv %(TEMP)s/%(name)s_%(version)s.dsc.asc %(filename)s\n" % locals())
+        fileHandle.write('\nexit')
+        fileHandle.close()
+    finally:
+        f.close()
+
+    commands.getoutput("chmod 777 /tmp/py2deb.tmp")
+    commands.getoutput("/tmp/py2deb.tmp")
+
+    return filename
+
+
+class Py2tar(object):
+
+    def __init__(self, dataDirectoryPath):
+        self._dataDirectoryPath = dataDirectoryPath
+
+    def packed(self):
+        return self._getSourcesFiles()
+
+    def _getSourcesFiles(self):
+        directoryPath = self._dataDirectoryPath
+
+        outputFileObj = StringIO.StringIO() # TODO: Do more transparently?
+
+        tarOutput = tarfile.TarFile.open('sources',
+                                 mode = "w:gz",
+                                 fileobj = outputFileObj)
+
+        # Note: We can't use this because we need to fiddle permissions:
+        #       tarOutput.add(directoryPath, arcname = "")
+
+        for root, dirs, files in os.walk(directoryPath):
+            archiveRoot = root[len(directoryPath):]
+
+            tarinfo = tarOutput.gettarinfo(root, archiveRoot)
+            # TODO: Make configurable?
+            tarinfo.uid = UID_ROOT
+            tarinfo.gid = GID_ROOT
+            tarinfo.uname = ""
+            tarinfo.gname = ""
+            tarOutput.addfile(tarinfo)
+
+            for f in  files:
+                tarinfo = tarOutput.gettarinfo(os.path.join(root, f),
+                                               os.path.join(archiveRoot, f))
+                tarinfo.uid = UID_ROOT
+                tarinfo.gid = GID_ROOT
+                tarinfo.uname = ""
+                tarinfo.gname = ""
+                tarOutput.addfile(tarinfo, file(os.path.join(root, f)))
+
+        tarOutput.close()
+
+        data_tar_gz = outputFileObj.getvalue()
+
+        return data_tar_gz
+
+
+def py2tar(DEST, TEMP, name, version):
+    tarcontent = Py2tar("%(DEST)s" % locals())
+    filename = "%(TEMP)s/%(name)s_%(version)s.tar.gz" % locals()
+    f = open(filename, "wb")
+    try:
+        f.write(tarcontent.packed())
+    finally:
+        f.close()
+    return filename
+
+
+class Py2debException(Exception):
+    pass
+
+
+SECTIONS_BY_POLICY = {
+    # http://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
+    "debian": "admin, base, comm, contrib, devel, doc, editors, electronics, embedded, games, gnome, graphics, hamradio, interpreters, kde, libs, libdevel, mail, math, misc, net, news, non-free, oldlibs, otherosfs, perl, python, science, shells, sound, tex, text, utils, web, x11",
+    # http://maemo.org/forrest-images/pdf/maemo-policy.pdf
+    "chinook": "accessories, communication, games, multimedia, office, other, programming, support, themes, tools",
+    # http://wiki.maemo.org/Task:Package_categories
+    "diablo": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+    # http://wiki.maemo.org/Task:Fremantle_application_categories
+    "mer": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+    # http://wiki.maemo.org/Task:Fremantle_application_categories
+    "fremantle": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+}
+
+
+LICENSE_AGREEMENT = {
+        "gpl": """
+    This package 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 2 of the License, or
+    (at your option) any later version.
+
+    This package 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 package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+""",
+        "lgpl":"""
+    This package is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This package 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU Lesser General
+Public License can be found in `/usr/share/common-licenses/LGPL'.
+""",
+        "bsd": """
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted under the terms of the BSD License.
+
+    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+On Debian systems, the complete text of the BSD License can be
+found in `/usr/share/common-licenses/BSD'.
+""",
+        "artistic": """
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the "Artistic License" which comes with Debian.
+
+    THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
+    OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+On Debian systems, the complete text of the Artistic License
+can be found in `/usr/share/common-licenses/Artistic'.
+"""
+}
+
+
+class Py2deb(object):
+    """
+    heavily based on technic described here :
+    http://wiki.showmedo.com/index.php?title=LinuxJensMakingDeb
+    """
+    ## STATICS
+    clear = False  # clear build folder after py2debianization
+
+    SECTIONS = SECTIONS_BY_POLICY["debian"]
+
+    #http://www.debian.org/doc/debian-policy/footnotes.html#f69
+    ARCHS = "all i386 ia64 alpha amd64 armeb arm hppa m32r m68k mips mipsel powerpc ppc64 s390 s390x sh3 sh3eb sh4 sh4eb sparc darwin-i386 darwin-ia64 darwin-alpha darwin-amd64 darwin-armeb darwin-arm darwin-hppa darwin-m32r darwin-m68k darwin-mips darwin-mipsel darwin-powerpc darwin-ppc64 darwin-s390 darwin-s390x darwin-sh3 darwin-sh3eb darwin-sh4 darwin-sh4eb darwin-sparc freebsd-i386 freebsd-ia64 freebsd-alpha freebsd-amd64 freebsd-armeb freebsd-arm freebsd-hppa freebsd-m32r freebsd-m68k freebsd-mips freebsd-mipsel freebsd-powerpc freebsd-ppc64 freebsd-s390 freebsd-s390x freebsd-sh3 freebsd-sh3eb freebsd-sh4 freebsd-sh4eb freebsd-sparc kfreebsd-i386 kfreebsd-ia64 kfreebsd-alpha kfreebsd-amd64 kfreebsd-armeb kfreebsd-arm kfreebsd-hppa kfreebsd-m32r kfreebsd-m68k kfreebsd-mips kfreebsd-mipsel kfreebsd-powerpc kfreebsd-ppc64 kfreebsd-s390 kfreebsd-s390x kfreebsd-sh3 kfreebsd-sh3eb kfreebsd-sh4 kfreebsd-sh4eb kfreebsd-sparc knetbsd-i386 knetbsd-ia64 knetbsd-alpha knetbsd-amd64 knetbsd-armeb knetbsd-arm knetbsd-hppa knetbsd-m32r knetbsd-m68k knetbsd-mips knetbsd-mipsel knetbsd-powerpc knetbsd-ppc64 knetbsd-s390 knetbsd-s390x knetbsd-sh3 knetbsd-sh3eb knetbsd-sh4 knetbsd-sh4eb knetbsd-sparc netbsd-i386 netbsd-ia64 netbsd-alpha netbsd-amd64 netbsd-armeb netbsd-arm netbsd-hppa netbsd-m32r netbsd-m68k netbsd-mips netbsd-mipsel netbsd-powerpc netbsd-ppc64 netbsd-s390 netbsd-s390x netbsd-sh3 netbsd-sh3eb netbsd-sh4 netbsd-sh4eb netbsd-sparc openbsd-i386 openbsd-ia64 openbsd-alpha openbsd-amd64 openbsd-armeb openbsd-arm openbsd-hppa openbsd-m32r openbsd-m68k openbsd-mips openbsd-mipsel openbsd-powerpc openbsd-ppc64 openbsd-s390 openbsd-s390x openbsd-sh3 openbsd-sh3eb openbsd-sh4 openbsd-sh4eb openbsd-sparc hurd-i386 hurd-ia64 hurd-alpha hurd-amd64 hurd-armeb hurd-arm hurd-hppa hurd-m32r hurd-m68k hurd-mips hurd-mipsel hurd-powerpc hurd-ppc64 hurd-s390 hurd-s390x hurd-sh3 hurd-sh3eb hurd-sh4 hurd-sh4eb hurd-sparc armel".split(" ")
+
+    # license terms taken from dh_make
+    LICENSES = list(LICENSE_AGREEMENT.iterkeys())
+
+    def __setitem__(self, path, files):
+
+        if not type(files)==list:
+            raise Py2debException("value of key path '%s' is not a list"%path)
+        if not files:
+            raise Py2debException("value of key path '%s' should'nt be empty"%path)
+        if not path.startswith("/"):
+            raise Py2debException("key path '%s' malformed (don't start with '/')"%path)
+        if path.endswith("/"):
+            raise Py2debException("key path '%s' malformed (shouldn't ends with '/')"%path)
+
+        nfiles=[]
+        for file in files:
+
+            if ".." in file:
+                raise Py2debException("file '%s' contains '..', please avoid that!"%file)
+
+
+            if "|" in file:
+                if file.count("|")!=1:
+                    raise Py2debException("file '%s' is incorrect (more than one pipe)"%file)
+
+                file, nfile = file.split("|")
+            else:
+                nfile=file  # same localisation
+
+            if os.path.isdir(file):
+                raise Py2debException("file '%s' is a folder, and py2deb refuse folders !"%file)
+
+            if not os.path.isfile(file):
+                raise Py2debException("file '%s' doesn't exist"%file)
+
+            if file.startswith("/"):    # if an absolute file is defined
+                if file==nfile:         # and not renamed (pipe trick)
+                    nfile=os.path.basename(file)   # it's simply copied to 'path'
+
+            nfiles.append((file, nfile))
+
+        nfiles.sort(lambda a, b: cmp(a[1], b[1]))    #sort according new name (nfile)
+
+        self.__files[path]=nfiles
+
+    def __delitem__(self, k):
+        del self.__files[k]
+
+    def __init__(self,
+                    name,
+                    description="no description",
+                    license="gpl",
+                    depends="",
+                    section="utils",
+                    arch="all",
+
+                    url="",
+                    author = None,
+                    mail = None,
+
+                    preinstall = None,
+                    postinstall = None,
+                    preremove = None,
+                    postremove = None
+                ):
+
+        if author is None:
+            author = ("USERNAME" in os.environ) and os.environ["USERNAME"] or None
+            if author is None:
+                author = ("USER" in os.environ) and os.environ["USER"] or "unknown"
+
+        if mail is None:
+            mail = author+"@"+socket.gethostname()
+
+        self.name = name
+        self.prettyName = ""
+        self.description = description
+        self.upgradeDescription = ""
+        self.bugTracker = ""
+        self.license = license
+        self.depends = depends
+        self.recommends = ""
+        self.section = section
+        self.arch = arch
+        self.url = url
+        self.author = author
+        self.mail = mail
+        self.icon = ""
+        self.distribution = ""
+        self.respository = ""
+        self.urgency = "low"
+
+        self.preinstall = preinstall
+        self.postinstall = postinstall
+        self.preremove = preremove
+        self.postremove = postremove
+
+        self.__files={}
+
+    def __repr__(self):
+        name = self.name
+        license = self.license
+        description = self.description
+        depends = self.depends
+        recommends = self.recommends
+        section = self.section
+        arch = self.arch
+        url = self.url
+        author = self.author
+        mail = self.mail
+
+        preinstall = self.preinstall
+        postinstall = self.postinstall
+        preremove = self.preremove
+        postremove = self.postremove
+
+        paths=self.__files.keys()
+        paths.sort()
+        files=[]
+        for path in paths:
+            for file, nfile in self.__files[path]:
+                #~ rfile=os.path.normpath(os.path.join(path, nfile))
+                rfile=os.path.join(path, nfile)
+                if nfile==file:
+                    files.append(rfile)
+                else:
+                    files.append(rfile + " (%s)"%file)
+
+        files.sort()
+        files = "\n".join(files)
+
+
+        lscripts = [    preinstall and "preinst",
+                        postinstall and "postinst",
+                        preremove and "prerm",
+                        postremove and "postrm",
+                    ]
+        scripts = lscripts and ", ".join([i for i in lscripts if i]) or "None"
+        return """
+----------------------------------------------------------------------
+NAME        : %(name)s
+----------------------------------------------------------------------
+LICENSE     : %(license)s
+URL         : %(url)s
+AUTHOR      : %(author)s
+MAIL        : %(mail)s
+----------------------------------------------------------------------
+DEPENDS     : %(depends)s
+RECOMMENDS  : %(recommends)s
+ARCH        : %(arch)s
+SECTION     : %(section)s
+----------------------------------------------------------------------
+DESCRIPTION :
+%(description)s
+----------------------------------------------------------------------
+SCRIPTS : %(scripts)s
+----------------------------------------------------------------------
+FILES :
+%(files)s
+""" % locals()
+
+    def generate(self, version, changelog="", rpm=False, src=False, build=True, tar=False, changes=False, dsc=False):
+        """ generate a deb of version 'version', with or without 'changelog', with or without a rpm
+            (in the current folder)
+            return a list of generated files
+        """
+        if not sum([len(i) for i in self.__files.values()])>0:
+            raise Py2debException("no files are defined")
+
+        if not changelog:
+            changelog="* no changelog"
+
+        name = self.name
+        description = self.description
+        license = self.license
+        depends = self.depends
+        recommends = self.recommends
+        section = self.section
+        arch = self.arch
+        url = self.url
+        distribution = self.distribution
+        repository = self.repository
+        urgency = self.urgency
+        author = self.author
+        mail = self.mail
+        files = self.__files
+        preinstall = self.preinstall
+        postinstall = self.postinstall
+        preremove = self.preremove
+        postremove = self.postremove
+
+        if section not in Py2deb.SECTIONS:
+            raise Py2debException("section '%s' is unknown (%s)" % (section, str(Py2deb.SECTIONS)))
+
+        if arch not in Py2deb.ARCHS:
+            raise Py2debException("arch '%s' is unknown (%s)"% (arch, str(Py2deb.ARCHS)))
+
+        if license not in Py2deb.LICENSES:
+            raise Py2debException("License '%s' is unknown (%s)" % (license, str(Py2deb.LICENSES)))
+
+        # create dates (buildDate, buildDateYear)
+        d=datetime.now()
+        buildDate=d.strftime("%a, %d %b %Y %H:%M:%S +0000")
+        buildDateYear=str(d.year)
+
+        #clean description (add a space before each next lines)
+        description=description.replace("\r", "").strip()
+        description = "\n ".join(description.split("\n"))
+
+        #clean changelog (add 2 spaces before each next lines)
+        changelog=changelog.replace("\r", "").strip()
+        changelog = "\n  ".join(changelog.split("\n"))
+
+        TEMP = ".py2deb_build_folder"
+        DEST = os.path.join(TEMP, name)
+        DEBIAN = os.path.join(DEST, "debian")
+
+        packageContents = locals()
+
+        # let's start the process
+        try:
+            shutil.rmtree(TEMP)
+        except:
+            pass
+
+        os.makedirs(DEBIAN)
+        try:
+            rules=[]
+            dirs=[]
+            for path in files:
+                for ofile, nfile in files[path]:
+                    if os.path.isfile(ofile):
+                        # it's a file
+
+                        if ofile.startswith("/"): # if absolute path
+                            # we need to change dest
+                            dest=os.path.join(DEST, nfile)
+                        else:
+                            dest=os.path.join(DEST, ofile)
+
+                        # copy file to be packaged
+                        destDir = os.path.dirname(dest)
+                        if not os.path.isdir(destDir):
+                            os.makedirs(destDir)
+
+                        shutil.copy2(ofile, dest)
+
+                        ndir = os.path.join(path, os.path.dirname(nfile))
+                        nname = os.path.basename(nfile)
+
+                        # make a line RULES to be sure the destination folder is created
+                        # and one for copying the file
+                        fpath = "/".join(["$(CURDIR)", "debian", name+ndir])
+                        rules.append('mkdir -p "%s"' % fpath)
+                        rules.append('cp -a "%s" "%s"' % (ofile, os.path.join(fpath, nname)))
+
+                        # append a dir
+                        dirs.append(ndir)
+
+                    else:
+                        raise Py2debException("unknown file '' "%ofile) # shouldn't be raised (because controlled before)
+
+            # make rules right
+            rules= "\n\t".join(rules) + "\n"
+            packageContents["rules"] = rules
+
+            # make dirs right
+            dirs= [i[1:] for i in set(dirs)]
+            dirs.sort()
+
+            #==========================================================================
+            # CREATE debian/dirs
+            #==========================================================================
+            open(os.path.join(DEBIAN, "dirs"), "w").write("\n".join(dirs))
+
+            #==========================================================================
+            # CREATE debian/changelog
+            #==========================================================================
+            clog="""%(name)s (%(version)s) stable; urgency=low
+
+  %(changelog)s
+
+ -- %(author)s <%(mail)s>  %(buildDate)s
+""" % packageContents
+
+            open(os.path.join(DEBIAN, "changelog"), "w").write(clog)
+
+            #==========================================================================
+            #Create pre/post install/remove
+            #==========================================================================
+            def mkscript(name, dest):
+                if name and name.strip()!="":
+                    if os.path.isfile(name):    # it's a file
+                        content = file(name).read()
+                    else:   # it's a script
+                        content = name
+                    open(os.path.join(DEBIAN, dest), "w").write(content)
+
+            mkscript(preinstall, "preinst")
+            mkscript(postinstall, "postinst")
+            mkscript(preremove, "prerm")
+            mkscript(postremove, "postrm")
+
+
+            #==========================================================================
+            # CREATE debian/compat
+            #==========================================================================
+            open(os.path.join(DEBIAN, "compat"), "w").write("5\n")
+
+            #==========================================================================
+            # CREATE debian/control
+            #==========================================================================
+            generalParagraphFields = [
+                "Source: %(name)s",
+                "Maintainer: %(author)s <%(mail)s>",
+                "Section: %(section)s",
+                "Priority: extra",
+                "Build-Depends: debhelper (>= 5)",
+                "Standards-Version: 3.7.2",
+            ]
+
+            specificParagraphFields = [
+                "Package: %(name)s",
+                "Architecture: %(arch)s",
+                "Depends: %(depends)s",
+                "Recommends: %(recommends)s",
+                "Description: %(description)s",
+            ]
+
+            if self.prettyName:
+                prettyName = "XSBC-Maemo-Display-Name: %s" % self.prettyName.strip()
+                specificParagraphFields.append("\n  ".join(prettyName.split("\n")))
+
+            if self.bugTracker:
+                bugTracker = "XSBC-Bugtracker: %s" % self.bugTracker.strip()
+                specificParagraphFields.append("\n  ".join(bugTracker.split("\n")))
+
+            if self.upgradeDescription:
+                upgradeDescription = "XSBC-Maemo-Upgrade-Description: %s" % self.upgradeDescription.strip()
+                specificParagraphFields.append("\n  ".join(upgradeDescription.split("\n")))
+
+            if self.icon:
+                f = open(self.icon, "rb")
+                try:
+                    rawIcon = f.read()
+                finally:
+                    f.close()
+                uueIcon = base64.b64encode(rawIcon)
+                uueIconLines = []
+                for i, c in enumerate(uueIcon):
+                    if i % 60 == 0:
+                        uueIconLines.append("")
+                    uueIconLines[-1] += c
+                uueIconLines[0:0] = ("XSBC-Maemo-Icon-26:", )
+                specificParagraphFields.append("\n  ".join(uueIconLines))
+
+            generalParagraph = "\n".join(generalParagraphFields)
+            specificParagraph = "\n".join(specificParagraphFields)
+            controlContent = "\n\n".join((generalParagraph, specificParagraph)) % packageContents
+            open(os.path.join(DEBIAN, "control"), "w").write(controlContent)
+
+            #==========================================================================
+            # CREATE debian/copyright
+            #==========================================================================
+            packageContents["txtLicense"] = LICENSE_AGREEMENT[license]
+            packageContents["pv"] =__version__
+            txt="""This package was py2debianized(%(pv)s) by %(author)s <%(mail)s> on
+%(buildDate)s.
+
+It was downloaded from %(url)s
+
+Upstream Author: %(author)s <%(mail)s>
+
+Copyright: %(buildDateYear)s by %(author)s
+
+License:
+
+%(txtLicense)s
+
+The Debian packaging is (C) %(buildDateYear)s, %(author)s <%(mail)s> and
+is licensed under the GPL, see above.
+
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+""" % packageContents
+            open(os.path.join(DEBIAN, "copyright"), "w").write(txt)
+
+            #==========================================================================
+            # CREATE debian/rules
+            #==========================================================================
+            txt="""#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+       CFLAGS += -O0
+else
+       CFLAGS += -O2
+endif
+
+configure: configure-stamp
+configure-stamp:
+       dh_testdir
+       # Add here commands to configure the package.
+
+       touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+       dh_testdir
+       touch build-stamp
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp configure-stamp
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+
+       # ======================================================
+       #$(MAKE) DESTDIR="$(CURDIR)/debian/%(name)s" install
+       mkdir -p "$(CURDIR)/debian/%(name)s"
+
+       %(rules)s
+       # ======================================================
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs debian/changelog
+       dh_installdocs
+       dh_installexamples
+#      dh_install
+#      dh_installmenu
+#      dh_installdebconf
+#      dh_installlogrotate
+#      dh_installemacsen
+#      dh_installpam
+#      dh_installmime
+#      dh_python
+#      dh_installinit
+#      dh_installcron
+#      dh_installinfo
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+#      dh_perl
+#      dh_makeshlibs
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+""" % packageContents
+            open(os.path.join(DEBIAN, "rules"), "w").write(txt)
+            os.chmod(os.path.join(DEBIAN, "rules"), 0755)
+
+            ###########################################################################
+            ###########################################################################
+            ###########################################################################
+
+            generatedFiles = []
+
+            if build:
+                #http://www.debian.org/doc/manuals/maint-guide/ch-build.fr.html
+                ret = os.system('cd "%(DEST)s"; dpkg-buildpackage -tc -rfakeroot -us -uc' % packageContents)
+                if ret != 0:
+                    raise Py2debException("buildpackage failed (see output)")
+
+                l=glob("%(TEMP)s/%(name)s*.deb" % packageContents)
+                if len(l) != 1:
+                    raise Py2debException("didn't find builded deb")
+
+                tdeb = l[0]
+                deb = os.path.basename(tdeb)
+                shutil.move(tdeb, deb)
+
+                generatedFiles = [deb, ]
+
+                if rpm:
+                    rpmFilename = deb2rpm(deb)
+                    generatedFiles.append(rpmFilename)
+
+                if src:
+                    tarFilename = py2src(TEMP, name)
+                    generatedFiles.append(tarFilename)
+
+            if tar:
+                tarFilename = py2tar(DEST, TEMP, name, version)
+                generatedFiles.append(tarFilename)
+
+            if dsc:
+                dscFilename = py2dsc(TEMP, name, version, depends, author, mail, arch)
+                generatedFiles.append(dscFilename)
+
+            if changes:
+                changesFilenames = py2changes(packageContents)
+                generatedFiles.extend(changesFilenames)
+
+            return generatedFiles
+
+        #~ except Exception,m:
+            #~ raise Py2debException("build error :"+str(m))
+
+        finally:
+            if Py2deb.clear:
+                shutil.rmtree(TEMP)
+
+
+if __name__ == "__main__":
+    try:
+        os.chdir(os.path.dirname(sys.argv[0]))
+    except:
+        pass
+
+    p=Py2deb("python-py2deb")
+    p.description="Generate simple deb(/rpm/tgz) from python (2.4, 2.5 and 2.6)"
+    p.url = "http://www.manatlan.com/page/py2deb"
+    p.author=__author__
+    p.mail=__mail__
+    p.depends = "dpkg-dev, fakeroot, alien, python"
+    p.section="python"
+    p["/usr/lib/python2.6/dist-packages"] = ["py2deb.py", ]
+    p["/usr/lib/python2.5/site-packages"] = ["py2deb.py", ]
+    p["/usr/lib/python2.4/site-packages"] = ["py2deb.py", ]
+    #~ p.postinstall = "s.py"
+    #~ p.preinstall = "s.py"
+    #~ p.postremove = "s.py"
+    #~ p.preremove = "s.py"
+    print p
+    print p.generate(__version__, changelog = __doc__, src=True)
diff --git a/support/pylint.rc b/support/pylint.rc
new file mode 100644 (file)
index 0000000..2a371a1
--- /dev/null
@@ -0,0 +1,305 @@
+# lint Python modules using external checkers.
+#
+# This is the main checker controling the other ones and the reports
+# generation. It is itself both a raw checker and an astng checker in order
+# to:
+# * handle message activation / deactivation at the module level
+# * handle some basic but necessary stats'data (number of classes, methods...)
+#
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Set the cache size for astng objects.
+cache-size=500
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable only checker(s) with the given id(s). This option conflicts with the
+# disable-checker option
+#enable-checker=
+
+# Enable all checker(s) except those with the given id(s). This option
+# conflicts with the enable-checker option
+#disable-checker=
+
+# Enable all messages in the listed categories.
+#enable-msg-cat=
+
+# Disable all messages in the listed categories.
+#disable-msg-cat=
+
+# Enable the message(s) with the given id(s).
+#enable-msg=
+
+# Disable the message(s) with the given id(s).
+disable-msg=W0403,W0612,W0613,C0103,C0111,C0301,R0903,W0142,W0603,R0904,R0921,R0201
+
+[REPORTS]
+
+# set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html
+output-format=colorized
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells wether to display a full report or only the messages
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note).You have access to the variables errors warning, statement which
+# respectivly contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (R0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (R0004).
+comment=no
+
+# Enable the report(s) with the given id(s).
+#enable-report=
+
+# Disable the report(s) with the given id(s).
+#disable-report=
+
+
+# checks for
+# * unused variables / imports
+# * undefined variables
+# * redefinition of variable from builtins or from an outer scope
+# * use of variable before assigment
+#
+[VARIABLES]
+
+# Tells wether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching names used for dummy variables (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+# checks for :
+# * doc strings
+# * modules / classes / functions / methods / arguments / variables name
+# * number of arguments, local variables, branchs, returns and statements in
+# functions, methods
+# * required module attributes
+# * dangerous default values as arguments
+# * redefinition of function / method / class
+# * uses of the global statement
+#
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-zA-Z0-9_]{2,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-zA-Z0-9_]{2,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-zA-Z0-9_]{2,30}$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+
+# try to find bugs in the code using type inference
+# 
+[TYPECHECK]
+
+# Tells wether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# When zope mode is activated, consider the acquired-members option to ignore
+# access to some undefined attributes.
+zope=no
+
+# List of members which are usually get through zope's acquisition mecanism and
+# so shouldn't trigger E0201 when accessed (need zope=yes to be considered).
+acquired-members=REQUEST,acl_users,aq_parent
+
+
+# checks for sign of poor/misdesign:
+# * number of methods, attributes, local variables...
+# * size, complexity of functions, methods
+#
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branchs=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=15
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=1
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+# checks for :
+# * methods without self as first argument
+# * overridden methods signature
+# * access only to existant members via self
+# * attributes not defined in the __init__ method
+# * supported interfaces implementation
+# * unreachable code
+#
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+
+# checks for
+# * external modules dependencies
+# * relative / wildcard imports
+# * cyclic imports
+# * uses of deprecated modules
+#
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report R0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report R0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report R0402 must
+# not be disabled)
+int-import-graph=
+
+
+# checks for similarities and duplicated code. This computation may be
+# memory / CPU intensive, so you should disable it if you experiments some
+# problems.
+#
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+
+# checks for:
+# * warning notes in the code like FIXME, XXX
+# * PEP 263: source code with non ascii character but no encoding declaration
+#
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+# checks for :
+# * unauthorized constructions
+# * strict indentation
+# * line length
+# * use of <> instead of !=
+#
+[FORMAT]
+
+# Maximum number of characters on a single line.
+# @note Limiting this to the most extreme cases
+max-line-length=100
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='\t'
diff --git a/support/test_syntax.py b/support/test_syntax.py
new file mode 100755 (executable)
index 0000000..65a373c
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+import commands
+
+
+verbose = False
+
+
+def syntax_test(file):
+       commandTemplate = """
+       python -t -t -W all -c "import py_compile; py_compile.compile ('%(filename)s', doraise=False)" """
+       compileCommand = commandTemplate % {"filename": file}
+       (status, text) = commands.getstatusoutput (compileCommand)
+       text = text.rstrip()
+       passed = len(text) == 0
+
+       if passed:
+               output = ("Syntax is correct for "+file) if verbose else ""
+       else:
+               output = ("Syntax is invalid for %s\n" % file) if verbose else ""
+               output += text
+       return (passed, output)
+
+
+if __name__ == "__main__":
+       import sys
+       import os
+       import optparse
+
+       opar = optparse.OptionParser()
+       opar.add_option("-v", "--verbose", dest="verbose", help="Toggle verbosity", action="store_true", default=False)
+       options, args = opar.parse_args(sys.argv[1:])
+       verbose = options.verbose
+
+       completeOutput = []
+       allPassed = True
+       for filename in args:
+               passed, output = syntax_test(filename)
+               if not passed:
+                       allPassed = False
+               if output.strip():
+                       completeOutput.append(output)
+       print "\n".join(completeOutput)
+
+       sys.exit(0 if allPassed else 1);
diff --git a/support/todo.py b/support/todo.py
new file mode 100755 (executable)
index 0000000..90cbd04
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+from __future__ import with_statement
+import itertools
+
+
+verbose = False
+
+
+def tag_parser(file, tag):
+       """
+       >>> nothing = []
+       >>> for todo in tag_parser(nothing, "@todo"):
+       ...     print todo
+       ...
+       >>> one = ["@todo Help!"]
+       >>> for todo in tag_parser(one, "@todo"):
+       ...     print todo
+       ...
+       1: @todo Help!
+       >>> mixed = ["one", "@todo two", "three"]
+       >>> for todo in tag_parser(mixed, "@todo"):
+       ...     print todo
+       ...
+       2: @todo two
+       >>> embedded = ["one @todo two", "three"]
+       >>> for todo in tag_parser(embedded, "@todo"):
+       ...     print todo
+       ...
+       1: @todo two
+       >>> continuation = ["one", "@todo two", " three"]
+       >>> for todo in tag_parser(continuation, "@todo"):
+       ...     print todo
+       ...
+       2: @todo two three
+       >>> series = ["one", "@todo two", "@todo three"]
+       >>> for todo in tag_parser(series, "@todo"):
+       ...     print todo
+       ...
+       2: @todo two
+       3: @todo three
+       """
+       currentTodo = []
+       prefix = None
+       for lineNumber, line in enumerate(file):
+               column = line.find(tag)
+               if column != -1:
+                       if currentTodo:
+                               yield "\n".join (currentTodo)
+                       prefix = line[0:column]
+                       currentTodo = ["%d: %s" % (lineNumber+1, line[column:].strip())]
+               elif prefix is not None and len(prefix)+1 < len(line) and line.startswith(prefix) and line[len(prefix)].isspace():
+                       currentTodo.append (line[len(prefix):].rstrip())
+               elif currentTodo:
+                       yield "\n".join (currentTodo)
+                       currentTodo = []
+                       prefix = None
+       if currentTodo:
+               yield "\n".join (currentTodo)
+
+
+def tag_finder(filename, tag):
+       todoList = []
+
+       with open(filename) as file:
+               body = "\n".join (tag_parser(file, tag))
+       passed = not body
+       if passed:
+               output = "No %s's for %s" % (tag, filename) if verbose else ""
+       else:
+               header = "%s's for %s:\n" % (tag, filename) if verbose else ""
+               output = header + body
+               output += "\n" if verbose else ""
+
+       return (passed, output)
+
+
+if __name__ == "__main__":
+       import sys
+       import os
+       import optparse
+
+       opar = optparse.OptionParser()
+       opar.add_option("-v", "--verbose", dest="verbose", help="Toggle verbosity", action="store_true", default=False)
+       options, args = opar.parse_args(sys.argv[1:])
+       verbose = options.verbose
+
+       bugsAsError = True
+       todosAsError = False
+
+       completeOutput = []
+       allPassed = True
+       for filename in args:
+               bugPassed, bugOutput = tag_finder(filename, "@bug")
+               todoPassed, todoOutput = tag_finder(filename, "@todo")
+               output = "\n".join ([bugOutput, todoOutput])
+               if (not bugPassed and bugsAsError) or (not todoPassed and todosAsError):
+                       allPassed = False
+               output = output.strip()
+               if output:
+                       completeOutput.append(filename+":\n"+output+"\n\n")
+       print "\n".join(completeOutput)
+       
+       sys.exit(0 if allPassed else 1);