--- /dev/null
+PROJECT_NAME=quicknote
+PROJECT_VERSION=0.7.4
+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=$(PROJECT_NAME)
+POTFILES=$(wildcard src/quicknoteclasses/*.py)
+
+UNIT_TEST=nosetests --with-doctest -w .
+SYNTAX_TEST=support/test_syntax.py
+LINT_RC=./support/pylint.rc
+LINT=pylint --rcfile=$(LINT_RC)
+PROFILE_GEN=python -m cProfile -o .profile
+PROFILE_VIEW=python -m pstats .profile
+
+.PHONY: all run profile test lint clean distclean install update_po build_mo
+
+all: build_mo
+ python2.5 setup.py build
+
+run:
+ $(PROGRAM)
+
+profile:
+ $(PROFILE_GEN) $(PROGRAM)
+ $(PROFILE_VIEW)
+
+test: $(OBJ)
+ $(UNIT_TEST)
+
+package: clean $(OBJ) all
+ dpkg-buildpackage -rfakeroot
+ dpkg -i ../$(PROJECT_NAME)_$(PROJECT_VERSION)_all.deb
+
+update_po: po/templates.pot
+ @for lang in $(basename $(notdir $(wildcard po/*.po))); do \
+ msgmerge -U --strict --no-wrap po/$$lang.po po/templates.pot; \
+ done
+
+po/templates.pot: $(POTFILES)
+ xgettext --language=Python --strict --no-wrap --output=$@ $(POTFILES)
+
+build_mo:
+ @for lang in $(basename $(notdir $(wildcard po/*.po))); do \
+ mkdir -p locale/$$lang/LC_MESSAGES; \
+ msgfmt --statistics -c -o locale/$$lang/LC_MESSAGES/$(TEXT_DOMAIN).mo po/$$lang.po; \
+ done
+
+build: $(OBJ) build_mo
+ rm -Rf $(BUILD_PATH)
+ mkdir $(BUILD_PATH)
+ cp $(PROGRAM) $(BUILD_PATH)
+ $(foreach file, $(DATA), cp $(file) $(BUILD_PATH)/$(subst /,-,$(file)) ; )
+ $(foreach file, $(SOURCE), cp $(file) $(BUILD_PATH)/$(subst /,-,$(file)) ; )
+ $(foreach file, $(OBJ), cp $(file) $(BUILD_PATH)/$(subst /,-,$(file)) ; )
+ $(foreach file, $(LOCALE_FILES), cp $(file) $(BUILD_PATH)/$(subst /,-,$(file)) ; )
+ cp data/$(PROJECT_NAME).desktop $(BUILD_PATH)
+ cp data/$(PROJECT_NAME).service $(BUILD_PATH)
+ cp data/low/$(PROJECT_NAME).png $(BUILD_PATH)/26x26-$(PROJECT_NAME).png
+ cp data/40/$(PROJECT_NAME).png $(BUILD_PATH)/40x40-$(PROJECT_NAME).png
+ cp data/48/$(PROJECT_NAME).png $(BUILD_PATH)/48x48-$(PROJECT_NAME).png
+ cp data/scale/$(PROJECT_NAME).png $(BUILD_PATH)/scale-$(PROJECT_NAME).png
+ cp support/builddeb.py $(BUILD_PATH)
+ cp support/fake_py2deb.py $(BUILD_PATH)
+
+lint: $(OBJ)
+ $(foreach file, $(SOURCE), $(LINT) $(file) ; )
+
+clean:
+ rm -rf ./locale
+ rm -rf $(OBJ)
+ rm -Rf $(BUILD_PATH)
+ python2.5 setup.py clean --all
+
+distclean: clean
+ 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
+
+install: build_mo
+ python2.5 setup.py install --root $(DESTDIR)
+
+%.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 $*)))
--- /dev/null
+[Desktop Entry]
+Encoding=UTF-8
+Name=Quicknote
+Comment=Quicknote
+Type=Application
+Exec=/usr/bin/quicknote.py
+Icon=quicknote
+X-Window-Icon=quicknote
+X-Window-Icon-Dimmed=quicknote
+#X-Osso-Service=quicknote
+X-Osso-Type=application/x-executable
--- /dev/null
+[D-BUS Service]
+Name=com.nokia.quicknote
+Exec=/usr/bin/quicknote.py
--- /dev/null
+quicknote (0.7.4) unstable; urgency=low
+
+ * fixed small bugs
+ * move category
+
+ -- unknown <n800@axique.de> Thu, 22 May 2008 08:12:53 +0100
+
+
+quicknote (0.7.3) unstable; urgency=low
+
+ * fixed small bugs
+ * move category
+
+ -- unknown <n800@axique.de> Wed, 28 Jan 2008 08:12:53 +0100
+
+quicknote (0.7.2) unstable; urgency=low
+
+ * improved sync, fixed a small bug
+
+ -- unknown <n800@axique.de> Wed, 26 Nov 2007 08:12:53 +0100
+
+quicknote (0.7.1) unstable; urgency=low
+
+ * improved sync
+
+ -- unknown <n800@axique.de> Wed, 7 Nov 2007 08:12:53 +0100
+
+
+
+quicknote (0.7.0) unstable; urgency=low
+
+ * Initial Release.
+
+ -- unknown <n800@axique.de> Mon, 6 Nov 2007 08:12:53 +0100
+
--- /dev/null
+Source: quicknote
+Section: user/other
+Priority: optional
+Maintainer: Christoph Würstle <n800 at axique de>
+Build-Depends: debhelper (>= 4.0.0), python2.5
+Standards-Version: 3.6.1
+
+Package: quicknote
+Architecture: all
+Depends: python2.5-hildon, python2.5-gtk2, python2.5-osso, python2.5-runtime
+Description: Quicknote
+XB-Maemo-Icon-26:
+ iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
+ /wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9cLAwkANf/o52QAAAAddEVYdENv
+ bW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAARNJREFUSMfNlsENhCAQRT9oPFiDmFCN
+ iRW7DViBnj1gEXog7AkXERUQk/0nCMpzZr4DRCkFAGjbVg3DgLIs8VRSSlBK0XUd4ZwDAHK9OI4j
+ +r5HKtV1jWVZtjnVgxSR2KKUHkFv6xLEGANj7F2QDyDkQ/IriBDiFqqfiQLZL/tuFl2jUDWsigfZ
+ aYs1SO67uRDiUDvfaE5Brs1ckIZV+Ih5m5vjKDPcGcIGvm6GIJDvj+pbm9PUmUV3pc1c+4jZG0Sv
+ amR3hivXRdnbhpn/jg25M8Et6G9aUGiHyEOOCbNmLtM8PibOIghJaZLOEFQjKWXybqCvcruIsixL
+ dj/QIoT8xpo6TZNa13W3+FScc1IUBQDgC9noggh/sT9oAAAAAElFTkSuQmCC
+
--- /dev/null
+This package was debianized by Christoph Würstle <n800 !at! axique .dotx de> on
+Mon, 22 Jan 2007 22:44:33 +0200.
+
+It was downloaded from <fill in ftp site>
+
+Copyright:
+
+Upstream Author(s): <put author(s) name and email here>
+
+License:
+
+Special drop a mail
--- /dev/null
+usr/bin
+usr/sbin
--- /dev/null
+README
+TODO
--- /dev/null
+#!/bin/sh -e
+gtk-update-icon-cache -f /usr/share/icons/hicolor
+exit 0
\ No newline at end of file
--- /dev/null
+#!/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
+
+
+
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+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
+
+ # Add here commands to compile the package.
+ $(MAKE)
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) clean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/quicknote
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/quicknote
+
+
+# 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
+# dh_installdocs
+ dh_installexamples
+# dh_install
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+ dh_installman
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_python
+# 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
--- /dev/null
+# German translations for quicknote package
+# German messages for quicknote.
+# Copyright (C) 2008 THE quicknote'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the quicknote package.
+# Christoph Würstle <chris@axique.de>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: quicknote\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-03 16:25+0400\n"
+"PO-Revision-Date: 2008-06-03 16:07+0400\n"
+"Last-Translator: Christoph Würstle <chris@axique.de>\n"
+"Language-Team: German\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 30
+msgid "History:"
+msgstr "Historie:"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 43
+# File: src/quicknoteclasses/libsqldialog.py, line: 65
+msgid "Timestamp"
+msgstr "Zeitstempel"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 44
+# File: src/quicknoteclasses/libnotizen.py, line: 234
+msgid "Note"
+msgstr "Notiz"
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 48
+# File: src/quicknoteclasses/libkopfzeile.py, line: 106
+msgid "all"
+msgstr "alle"
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 131
+msgid "Search: "
+msgstr "Suche:"
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 141
+msgid "Category: "
+msgstr "Kategorie"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 105
+msgid "Last change: %d.%m.%y %H:%M"
+msgstr "Letzte Änderung: %d.%m.%y %H:%M"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 116
+msgid "Really delete?"
+msgstr "Wirklich löschen?"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 131
+msgid "new Note"
+msgstr "neue Notiz"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 150
+# File: src/quicknoteclasses/libquicknote.py, line: 183
+msgid "No note selected."
+msgstr "Keine Notiz markiert"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 209
+msgid "Titles"
+msgstr "Titel"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 213
+msgid "add note"
+msgstr "Notiz hinzufügen"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 217
+msgid "del note"
+msgstr "Notiz löschen"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 247
+msgid "History"
+msgstr "Historie"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 78
+msgid "Choose database file"
+msgstr "Datenbankdatei auswählen"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 95
+#, python-format
+msgid "%s is a note taking program; it is optimised for quick save and search of notes"
+msgstr "%s ist ein Programm um Notizen zu verwaltn; es ist für schnelles speichern und finden optimiert"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 117
+msgid "Select SQL export file"
+msgstr "Wähle SQL-Export-Datei"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 130
+msgid "This category can not be deleted"
+msgstr "Diese Kategorie kann nicht gelöscht werden"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 136
+msgid "Are you sure to delete the current category?"
+msgstr "Wirklich aktuell gewählte Kategorie löschen?"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 152
+msgid "Choose category"
+msgstr "Wähle Kategorie"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 196
+msgid "Sync"
+msgstr "Syncronisation"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 269
+msgid "Set DB file"
+msgstr "Setzte Datenbaknkdatei"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 273
+msgid "SQL History"
+msgstr "SQL Historie"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 277
+msgid "Sync notes"
+msgstr "Syncronisiere Notizen"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 281
+msgid "Quit"
+msgstr "Beenden"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 285
+msgid "File"
+msgstr "Datei"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 296
+msgid "delete"
+msgstr "löschen"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 300
+msgid "move to category"
+msgstr "verschiebe zu Kategorie"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 304
+msgid "Category"
+msgstr "Kategorie"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 310
+msgid "About"
+msgstr "Über"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 314
+msgid "Help"
+msgstr "Hilfe"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 46
+msgid "SQL History (the past two days):"
+msgstr "SQL Historie (der letzten 2 Tage):"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 67
+msgid "Parameter"
+msgstr "Parameter"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 105
+msgid "%d.%m.%y %H:%M:%S "
+msgstr "%d.%m.%y %H:%M:%S "
+#
+# File: src/quicknoteclasses/libsync.py, line: 43
+msgid "Sync process"
+msgstr "Syncronisationsprozess"
+#
+# File: src/quicknoteclasses/libsync.py, line: 48
+msgid "Sync process running...please wait"
+msgstr "Syncronisationsprozess läuft...bitte warten"
+#
+# File: src/quicknoteclasses/libsync.py, line: 50
+msgid "(this can take some minutes)"
+msgstr "(dies kann einige Minuten dauern)"
+#
+# File: src/quicknoteclasses/libsync.py, line: 90
+msgid "Query"
+msgstr "Anfrage"
+#
+# File: src/quicknoteclasses/libsync.py, line: 242
+msgid "Syncserver running..."
+msgstr "Syncronisationsprozess läuft..."
+#
+# File: src/quicknoteclasses/libsync.py, line: 250
+msgid "Could not start SyncServer. Check IP, port settings."
+msgstr "Konnte Syncronisationsserver nicht starten. Bitte IP und Port-Einstellungen überprüfen."
+#
+# File: src/quicknoteclasses/libsync.py, line: 263
+# File: src/quicknoteclasses/libsync.py, line: 409
+msgid "SyncServer stopped"
+msgstr "Syncronisationsprozess gestoppt."
+#
+# File: src/quicknoteclasses/libsync.py, line: 280
+# File: src/quicknoteclasses/libsync.py, line: 316
+# File: src/quicknoteclasses/libsync.py, line: 324
+# File: src/quicknoteclasses/libsync.py, line: 331
+# File: src/quicknoteclasses/libsync.py, line: 422
+msgid "no sync process (at the moment)"
+msgstr "Kein Syncronisationsprozess (im Moment)"
+#
+# File: src/quicknoteclasses/libsync.py, line: 289
+msgid "sync process running"
+msgstr "Syncronisationsprozess läuft"
+#
+# File: src/quicknoteclasses/libsync.py, line: 318
+msgid "Synchronization successfully completed"
+msgstr "Synchronisation erfolgreich beendet"
+#
+# File: src/quicknoteclasses/libsync.py, line: 325
+msgid "The clocks are not synchronized between stations"
+msgstr "Zeit differiert zu viel zwischen den Systemen"
+#
+# File: src/quicknoteclasses/libsync.py, line: 332
+msgid "Sync failed, reason: "
+msgstr "Sync gescheitert. Fehler:"
+#
+# File: src/quicknoteclasses/libsync.py, line: 387
+msgid "Local SyncServer (port "
+msgstr "LokalerSync-Server (Port "
+#
+# File: src/quicknoteclasses/libsync.py, line: 405
+msgid "Start/Stop SyncServer"
+msgstr "SyncServer starten/stoppen"
+#
+# File: src/quicknoteclasses/libsync.py, line: 412
+msgid "Remote SyncServer (port "
+msgstr "RemoteSync-Server (Port "
+#
+# File: src/quicknoteclasses/libsync.py, line: 418
+msgid "Connect to remote SyncServer"
+msgstr "Verbinde zu Remote-SyncServer"
--- /dev/null
+# Russian translations for quicknote package
+# Copyright (C) 2008 THE quicknote'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the quicknote package.
+# Nikolay Logvinov <NLogvinov@gmail.com>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: quicknote\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-03 16:25+0400\n"
+"PO-Revision-Date: 2008-06-03 15:38+0400\n"
+"Last-Translator: Nikolay Logvinov <NLogvinov@gmail.com>\n"
+"Language-Team: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 30
+msgid "History:"
+msgstr "История изменений"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 43
+# File: src/quicknoteclasses/libsqldialog.py, line: 65
+msgid "Timestamp"
+msgstr "Время"
+#
+# File: src/quicknoteclasses/libhistory.py, line: 44
+# File: src/quicknoteclasses/libnotizen.py, line: 234
+msgid "Note"
+msgstr "Заметка"
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 48
+# File: src/quicknoteclasses/libkopfzeile.py, line: 106
+msgid "all"
+msgstr "все"
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 131
+msgid "Search: "
+msgstr "Поиск: "
+#
+# File: src/quicknoteclasses/libkopfzeile.py, line: 141
+msgid "Category: "
+msgstr "Категория: "
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 105
+msgid "Last change: %d.%m.%y %H:%M"
+msgstr "Редактировалась %d.%m.%y в %H:%M"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 116
+msgid "Really delete?"
+msgstr "Всё-таки удалять?"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 131
+msgid "new Note"
+msgstr "__ новая __"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 150
+# File: src/quicknoteclasses/libquicknote.py, line: 183
+msgid "No note selected."
+msgstr "Выберите сначала заметку"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 209
+msgid "Titles"
+msgstr "Заголовки"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 213
+msgid "add note"
+msgstr "добавить Заметку"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 217
+msgid "del note"
+msgstr "удалить Заметку"
+#
+# File: src/quicknoteclasses/libnotizen.py, line: 247
+msgid "History"
+msgstr "История изменений"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 78
+msgid "Choose database file"
+msgstr "Выберите файл для хранения заметок"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 95
+msgid "%s is a note taking program; it is optimised for quick save and search of notes"
+msgstr "%s - приложение для создания, хранения и быстрого поиска заметок"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 117
+msgid "Select SQL export file"
+msgstr "Выберите файл для экспорта запросов SQL"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 130
+msgid "This category can not be deleted"
+msgstr "Эту категорию нельзя удалять"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 136
+msgid "Are you sure to delete the current category?"
+msgstr "Вы уверены в удалении текущей категории?"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 152
+msgid "Choose category"
+msgstr "Категория:"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 196
+msgid "Sync"
+msgstr "Синхронизация"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 269
+msgid "Set DB file"
+msgstr "Хранилище"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 273
+msgid "SQL History"
+msgstr "SQL запросы"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 277
+msgid "Sync notes"
+msgstr "Синхронизация"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 281
+msgid "Quit"
+msgstr "Выход"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 285
+msgid "File"
+msgstr "Файл"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 296
+msgid "delete"
+msgstr "убрать"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 300
+msgid "move to category"
+msgstr "назначить"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 304
+msgid "Category"
+msgstr "Категория"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 310
+msgid "About"
+msgstr "О программе"
+#
+# File: src/quicknoteclasses/libquicknote.py, line: 314
+msgid "Help"
+msgstr "Справка"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 46
+msgid "SQL History (the past two days):"
+msgstr "SQL запросы (за 2 последних дня)"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 67
+msgid "Parameter"
+msgstr "Параметры"
+#
+# File: src/quicknoteclasses/libsqldialog.py, line: 105
+msgid "%d.%m.%y %H:%M:%S "
+msgstr "%d.%m.%y %H:%M:%S "
+#
+# File: src/quicknoteclasses/libsync.py, line: 43
+msgid "Sync process"
+msgstr "Синхронизация"
+#
+# File: src/quicknoteclasses/libsync.py, line: 48
+msgid "Sync process running...please wait"
+msgstr "Синхронизируются заметки, подождите ..."
+#
+# File: src/quicknoteclasses/libsync.py, line: 50
+msgid "(this can take some minutes)"
+msgstr "(некоторое время)"
+#
+# File: src/quicknoteclasses/libsync.py, line: 90
+msgid "Query"
+msgstr "Запрос"
+#
+# File: src/quicknoteclasses/libsync.py, line: 242
+msgid "Syncserver running..."
+msgstr "Сервер синхронизации работает ..."
+#
+# File: src/quicknoteclasses/libsync.py, line: 250
+msgid "Could not start SyncServer. Check IP, port settings."
+msgstr "Не удаётся стартовать Сервер синхронизации. Проверьте IP-адрес и порт."
+#
+# File: src/quicknoteclasses/libsync.py, line: 263
+# File: src/quicknoteclasses/libsync.py, line: 409
+msgid "SyncServer stopped"
+msgstr "Сервер синхронизации остановлен"
+#
+# File: src/quicknoteclasses/libsync.py, line: 280
+# File: src/quicknoteclasses/libsync.py, line: 316
+# File: src/quicknoteclasses/libsync.py, line: 324
+# File: src/quicknoteclasses/libsync.py, line: 331
+# File: src/quicknoteclasses/libsync.py, line: 422
+msgid "no sync process (at the moment)"
+msgstr "сейчас синхронизация не выполняется"
+#
+# File: src/quicknoteclasses/libsync.py, line: 289
+msgid "sync process running"
+msgstr "идёт синхронизация"
+#
+# File: src/quicknoteclasses/libsync.py, line: 318
+msgid "Synchronization successfully completed"
+msgstr "Синхронизация успешно завершенa"
+#
+# File: src/quicknoteclasses/libsync.py, line: 325
+msgid "The clocks are not synchronized between stations"
+msgstr "Согласуйте время между системами"
+#
+# File: src/quicknoteclasses/libsync.py, line: 332
+msgid "Sync failed, reason: "
+msgstr "Синхронизовать заметки не удалось по причине: "
+#
+# File: src/quicknoteclasses/libsync.py, line: 387
+msgid "Local SyncServer (port "
+msgstr "Местный сервер синхронизации (порт "
+#
+# File: src/quicknoteclasses/libsync.py, line: 405
+msgid "Start/Stop SyncServer"
+msgstr "Запуск/Остановка сервера синхронизации"
+#
+# File: src/quicknoteclasses/libsync.py, line: 412
+msgid "Remote SyncServer (port "
+msgstr "Удалённый сервер синхронизации (порт "
+#
+# File: src/quicknoteclasses/libsync.py, line: 418
+msgid "Connect to remote SyncServer"
+msgstr "Установить соединение"
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+
+from distutils.core import setup
+
+
+setup(
+ name='quicknote',
+ version='1.0',
+ scripts=['src/quicknote.py'],
+ packages=['quicknote'],
+ package_dir={'quicknote': 'src/'},
+ data_files = [
+ ('share/icons/hicolor/26x26/hildon', ['data/low/quicknote.png']),
+ ('share/icons/hicolor/40x40/hildon', ['data/40/quicknote.png']),
+ #('share/icons/hicolor/48x48/apps', ['data/48/quicknote.png']),
+ ('share/icons/hicolor/scalable/hildon', ['data/scale/quicknote.png']),
+ ('share/applications/hildon', ['data/quicknote.desktop']),
+ ('share/dbus-1/services', ['data/quicknote.service']),
+ # I18N
+ ('share/locale/de/LC_MESSAGES', ['locale/de/LC_MESSAGES/quicknote.mo']),
+ ('share/locale/ru/LC_MESSAGES', ['locale/ru/LC_MESSAGES/quicknote.mo']),
+ ]
+)
--- /dev/null
+#/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+import gtk
+
+
+class FileChooserDialog(gtk.FileChooserDialog):
+ """
+ @bug The buttons currently don't do anything
+ """
+
+ def __init__(self, *args, **kwds):
+ super(FileChooserDialog, self).__init__(*args, **kwds)
+ self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+ self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+
+
+class Window(gtk.Window):
+
+ def __init__(self):
+ super(Window, self).__init__(gtk.WINDOW_TOPLEVEL)
+ self.set_default_size(700, 500)
+
+
+class Program(object):
+
+ def __init__(self):
+ pass
+
+ def add_window(self, window):
+ pass
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import gtk
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class Dialog(gtk.Dialog):
+
+ def __init__(self, daten = None):
+ gtk.Dialog.__init__(self, _("History:"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ self.set_position(gtk.WIN_POS_CENTER)
+
+ self.liststore = gtk.ListStore(int, str, str, str, str)
+ #pcdatum, datum, sql, param # param schön
+
+ # 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()
+
+ # create the TreeViewColumns to display the data
+ self.tvcolumn1 = gtk.TreeViewColumn(_('Timestamp'))
+ self.tvcolumn2 = gtk.TreeViewColumn(_('Note'))
+ # add columns to treeview
+ self.treeview.append_column(self.tvcolumn1)
+ self.treeview.append_column(self.tvcolumn2)
+
+ # add the cells to the columns - 2 in the first
+ self.tvcolumn1.pack_start(self.cell1, True)
+ self.tvcolumn2.pack_start(self.cell2, True)
+ self.tvcolumn1.set_attributes(self.cell1, text = 1) #Spalten setzten hier!!!!
+ self.tvcolumn2.set_attributes(self.cell2, text = 4)
+
+ 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.vbox.pack_start(scrolled_window, expand = True, fill = True, padding = 0)
+
+ self.liststore.clear()
+
+ if daten is not None:
+ for data in daten:
+ self.liststore.append(data)
+
+ def get_selected_row(self):
+ path = self.treeview.get_cursor()[0]
+ if path is None or path == "":
+ return None
+
+ iter1 = self.treeview.get_model().get_iter(path)
+ return self.treeview.get_model().get(iter1, 0, 1, 2, 3, 4)
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import logging
+
+import gobject
+import gtk
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class Kopfzeile(gtk.HBox):
+
+ __gsignals__ = {
+ 'reload_notes' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+ }
+
+ def __init__(self, db):
+ self.lastCategory = ""
+ self.db = db
+
+ gtk.HBox.__init__(self, homogeneous = False, spacing = 3)
+ logging.info("libkopfzeile, init")
+
+ categoryHBox = gtk.HBox()
+ self.pack_start(categoryHBox, expand = False, fill = True, padding = 0)
+
+ label = gtk.Label(_("Category: "))
+ categoryHBox.pack_start(label, expand = False, fill = True, padding = 0)
+
+ self.comboCategory = gtk.combo_box_entry_new_text()
+ categoryHBox.pack_start(self.comboCategory, expand = True, fill = True, padding = 0)
+ self.loadCategories()
+ self.comboCategory.connect("changed", self.comboCategoryChanged, None)
+
+ searchHBox = gtk.HBox()
+ self.pack_start(searchHBox, expand = True, fill = True, padding = 0)
+
+ label = gtk.Label(_("Search: "))
+ searchHBox.pack_start(label, expand = False, fill = True, padding = 0)
+
+ self.searchEntry = gtk.Entry()
+ searchHBox.pack_start(self.searchEntry, expand = True, fill = True, padding = 0)
+ self.searchEntry.connect("changed", self.searchEntryChanged, None)
+
+ def comboCategoryChanged(self, widget = None, data = None):
+ logging.debug("comboCategoryChanged")
+ if self.lastCategory != self.comboCategory.get_active():
+ sql = "UPDATE categories SET liste = ? WHERE id = 1"
+ self.db.speichereSQL(sql, (self.comboCategory.get_active(), ))
+
+ self.emit("reload_notes")
+
+ def searchEntryChanged(self, widget = None, data = None):
+ logging.debug("searchEntryChanged")
+ self.emit("reload_notes")
+
+ def getCategory(self):
+ entry = self.comboCategory.get_child()
+ category = entry.get_text()
+ if category == _("all"):
+ category = "%"
+ if category == "":
+ category = "undefined"
+ self.comboCategory.set_active(1)
+ self.comboCategory.show()
+ return category
+
+ def defineThisCategory(self):
+ category = self.getCategory()
+
+ model = self.comboCategory.get_model()
+ n = len(self.comboCategory.get_model())
+ i = 0
+ active = -1
+ cats = []
+ while i < n:
+ if (model[i][0] == category):
+ #self.comboCategory.set_active(i)
+ active = i
+ if (model[i][0]!= "%"):
+ cats.append(model[i][0])
+ i += 1
+
+ if (active == -1) and (category!= "%"):
+ self.comboCategory.append_text(category)
+ sql = "INSERT INTO categories (id, liste) VALUES (0, ?)"
+ self.db.speichereSQL(sql, (category, ))
+ self.comboCategory.set_active(i)
+
+ def getSearchPattern(self):
+ return self.searchEntry.get_text()
+
+ def loadCategories(self):
+ sql = "CREATE TABLE categories (id TEXT , liste TEXT)"
+ self.db.speichereSQL(sql)
+
+ sql = "SELECT id, liste FROM categories WHERE id = 0 ORDER BY liste"
+ rows = self.db.ladeSQL(sql)
+ cats = []
+ if rows is not None and 0 < len(rows):
+ for row in rows:
+ cats.append(row[1])
+
+ sql = "SELECT * FROM categories WHERE id = 1"
+ rows = self.db.ladeSQL(sql)
+ if rows is None or len(rows) == 0:
+ sql = "INSERT INTO categories (id, liste) VALUES (1, 1)"
+ self.db.speichereSQL(sql)
+
+ #self.comboCategory.clear()
+ while 0 < len(self.comboCategory.get_model()):
+ self.comboCategory.remove_text(0)
+
+ self.comboCategory.append_text(_('all'))
+ self.comboCategory.append_text('undefined')
+
+ if cats is not None and 0 < len(cats):
+ for cat in cats:
+ self.comboCategory.append_text(cat)
+
+ sql = "SELECT * FROM categories WHERE id = 1"
+ rows = self.db.ladeSQL(sql)
+ if rows is not None and 0 < len(rows):
+ self.comboCategory.set_active(int(rows[0][1]))
+ else:
+ self.comboCategory.set_active(1)
+
+ self.lastCategory = self.comboCategory.get_active()
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+@todo Add hiding of the history button on zoom
+"""
+
+import time
+import logging
+import uuid
+
+import gobject
+import gtk
+
+import simple_list
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class Notizen(gtk.HBox):
+
+ def __init__(self, db, topBox):
+ self.db = db
+ self.topBox = topBox
+ self.noteid = -1
+ self.pos = -1
+ self.note = None #Last notetext
+ self.category = ""
+
+ gtk.HBox.__init__(self, homogeneous = False, spacing = 0)
+ logging.info("libnotizen, init")
+
+ self.noteslist = simple_list.SimpleList()
+ self.noteslist.set_eventfunction__cursor_changed(self.noteslist_changed)
+
+ self.noteslist.set_size_request(250, -1)
+
+ vbox = gtk.VBox(homogeneous = False, spacing = 0)
+
+ frame = gtk.Frame(_("Titles"))
+ frame.add(self.noteslist)
+ vbox.pack_start(frame, expand = True, fill = True, padding = 3)
+
+ buttonHBox = gtk.HBox()
+ vbox.pack_start(buttonHBox, expand = False, fill = True, padding = 3)
+
+ button = gtk.Button(stock = gtk.STOCK_ADD)
+ button.connect("clicked", self.add_note, None)
+ buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
+
+ button = gtk.Button(stock = gtk.STOCK_DELETE)
+ button.connect("clicked", self.del_note, None)
+ buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
+
+ self.pack_start(vbox, expand = False, fill = True, padding = 3)
+
+ self.textviewNote = gtk.TextView()
+ self.textviewNote.connect("focus-out-event", self.saveNote, "focus-out-event")
+ buf = self.textviewNote.get_buffer()
+ buf.set_text("")
+ buf.connect("changed", self.noteChanged, None)
+
+ #self.textviewNotiz.set_size_request(-1, 50)
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.add(self.textviewNote)
+
+ frame = gtk.Frame(_("Note"))
+ frame.add(self.scrolled_window)
+
+ vbox = gtk.VBox(homogeneous = False, spacing = 0)
+ vbox.pack_start(frame, expand = True, fill = True, padding = 3)
+
+ hbox = gtk.HBox(homogeneous = False, spacing = 0)
+
+ self.statuslabel = gtk.Label("Test")
+ self.statuslabel.set_alignment(0.0, 0.5)
+ hbox.pack_start(self.statuslabel, expand = True, fill = True, padding = 3)
+
+ button = gtk.Button(_("History"))
+ button.connect("clicked", self.show_history, None)
+ hbox.pack_start(button, expand = True, fill = True, padding = 3)
+
+ vbox.pack_start(hbox, expand = False, fill = True, padding = 3)
+
+ self.pack_start(vbox, expand = True, fill = True, padding = 3)
+
+ self.loadNotes()
+ self.topBox.connect("reload_notes", self.loadNotes)
+
+ def set_wordwrap(self, enableWordWrap):
+ if enableWordWrap:
+ self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.textviewNote.set_wrap_mode(gtk.WRAP_WORD)
+ else:
+ self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.textviewNote.set_wrap_mode(gtk.WRAP_NONE)
+
+ def getTitle(self, buf):
+ eol = buf.find("\n")
+ if -1 == eol:
+ eol = len(buf)
+ title = buf[:eol]
+ return title
+
+ def noteChanged(self, widget = None, data = None):
+ if self.pos == -1 or self.noteid == -1:
+ return
+
+ buf = self.textviewNote.get_buffer().get_text(self.textviewNote.get_buffer().get_start_iter(), self.textviewNote.get_buffer().get_end_iter())
+
+ title = self.getTitle(buf)
+ value, key = self.noteslist.get_item(self.pos)
+
+ if value != title:
+ self.noteslist.change_item(self.pos, title, self.noteid)
+
+ def saveNote(self, widget = None, data = None, data2 = None):
+ logging.info("saveNote params: pos:"+str(self.pos)+" noteid:"+str(self.noteid))
+ #print "params:", data, data2
+ buf = self.textviewNote.get_buffer().get_text(self.textviewNote.get_buffer().get_start_iter(), self.textviewNote.get_buffer().get_end_iter())
+ if buf is None or len(buf) == 0:
+ return
+
+ if buf == self.note:
+ return
+
+ logging.info("Saving note: "+buf)
+ if self.pos == -1 or self.noteid == -1:
+ self.pos = -1
+ self.noteid = str(uuid.uuid4())
+ self.db.saveNote(self.noteid, buf, self.category)
+ self.noteslist.append_item(self.getTitle(buf), self.noteid)
+ self.pos = self.noteslist.select_last_item()
+ else:
+ self.db.saveNote(self.noteid, buf, self.category)
+
+ self.topBox.defineThisCategory()
+
+ def setFocus(self):
+ self.textviewNote.grab_focus()
+ return False
+
+ def noteslist_changed(self, data = None, data2 = None):
+ if self.pos != -1:
+ self.saveNote()
+
+ try:
+ (pos, key, value) = self.noteslist.get_selection_data()
+ if (pos == -1):
+ return
+ except StandardError:
+ if data != "new":
+ return
+ key = None
+
+ if key == "new" or data == "new":
+ #both methods supported click add note or new note (first one disabled)
+ self.noteid = str(uuid.uuid4())
+ self.db.saveNote(self.noteid, "", self.category)
+ self.pos = -1
+ self.noteslist.append_item("", self.noteid)
+ self.textviewNote.get_buffer().set_text("")
+ self.pos = self.noteslist.select_last_item()
+ else:
+ self.pos = pos
+ self.noteid, pcdatum, self.category, self.note = self.db.loadNote(key)
+ self.statuslabel.set_text(time.strftime(_("Last change: %d.%m.%y %H:%M"), time.localtime(pcdatum)))
+ buf = self.textviewNote.get_buffer()
+ buf.set_text(self.note)
+
+ gobject.timeout_add(200, self.setFocus)
+
+ def add_note(self, widget = None, data = None):
+ self.noteslist_changed("new")
+
+ def del_note(self, widget = None, data = None):
+ if (self.noteid == -1):
+ return
+ mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, _("Really delete?"))
+ response = mbox.run()
+ mbox.hide()
+ mbox.destroy()
+ if response == gtk.RESPONSE_YES:
+ self.db.delNote(self.noteid)
+ self.noteid = -1
+ self.noteslist.remove_item(self.pos)
+ self.pos = -1
+ self.textviewNote.get_buffer().set_text("")
+
+ def loadNotes(self, data = None):
+ logging.info("loadNotes params: pos:"+str(self.pos)+" noteid:"+str(self.noteid))
+ self.noteslist.clear_items()
+ self.noteslist.append_item(_("new Note"), "new")
+
+ self.category = self.topBox.getCategory()
+ search = self.topBox.getSearchPattern()
+ notes = self.db.searchNotes(search, self.category)
+
+ if notes is not None:
+ for note in notes:
+ noteid, category, noteText = note
+ title = self.getTitle(noteText)
+ self.noteslist.append_item(title, noteid)
+
+ self.noteid = -1
+ self.pos = -1
+ self.textviewNote.get_buffer().set_text("")
+
+ def show_history(self, widget = None, data = None, label = None):
+ if self.noteid == -1:
+ mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("No note selected."))
+ response = mbox.run()
+ mbox.hide()
+ mbox.destroy()
+ return
+
+ rows = self.db.getNoteHistory(self.noteid)
+
+ import libhistory
+ dialog = libhistory.Dialog()
+
+ lastNoteStr = ""
+ for row in rows:
+ #for x in row:
+ # print x
+ daten = row[4][1]
+ if (daten != "")and(lastNoteStr != daten):
+ lastNoteStr = daten
+ dialog.liststore.append([row[0], row[1], row[2], row[3], daten+"\n"])
+
+ dialog.vbox.show_all()
+ dialog.set_size_request(600, 380)
+
+ if dialog.run() == gtk.RESPONSE_ACCEPT:
+ print "saving"
+ self.saveNote()
+ data = dialog.get_selected_row()
+ if data is not None:
+ self.db.speichereSQL(data[2], data[3].split(" <<Tren-ner>> "), rowid = self.noteid)
+ logging.info("loading History")
+ self.noteslist_changed()
+
+ dialog.destroy()
--- /dev/null
+#/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+@todo Add an edit menu with select all, cut, copy, and paste
+@todo Add undo directly into the UI
+@todo Add Note Export (txt File) and Export All (json dump?)
+@todo Save word wrap and zoom setting
+"""
+
+
+import os
+import gc
+import logging
+
+import gtk
+
+try:
+ import hildon
+ IS_HILDON = True
+except ImportError:
+ import fakehildon as hildon
+ IS_HILDON = False
+
+try:
+ import osso
+except ImportError:
+ osso = None
+
+import libspeichern
+import libkopfzeile
+import libnotizen
+import libsync
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class quicknoteclass(hildon.Program):
+
+ __pretty_app_name__ = "quicknote"
+ __app_name__ = "quicknote"
+ __version__ = "0.7.5"
+
+ def __init__(self):
+ super(quicknoteclass, self).__init__()
+
+ home_dir = os.path.expanduser('~')
+ dblog = os.path.join(home_dir, "quicknote.log")
+
+ # define a Handler which writes INFO messages or higher to the sys.stderr
+ console = logging.StreamHandler()
+ console.setLevel(logging.DEBUG)
+ # 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 quicknote')
+
+ if osso is not None:
+ self._osso_c = osso.Context(self.__app_name__, self.__version__, False)
+ self.device = osso.DeviceState(self._osso_c)
+ self.device.set_device_state_callback(self._on_device_state_change, 0)
+ else:
+ self._osso_c = None
+
+ #Get the Main Window, and connect the "destroy" event
+ self.window = hildon.Window()
+ self.add_window(self.window)
+
+ self.window.set_title(self.__pretty_app_name__)
+ self.window.connect("delete_event", self.delete_event)
+ self.window.connect("destroy", self.destroy)
+ 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.prepare_sync_dialog()
+
+ #Create GUI main vbox
+ vbox = gtk.VBox(homogeneous = False, spacing = 0)
+
+ #Create Menu and apply it for hildon
+ filemenu = gtk.Menu()
+
+ menu_items = gtk.MenuItem(_("Set DB file"))
+ filemenu.append(menu_items)
+ menu_items.connect("activate", self.set_db_file, None)
+
+ menu_items = gtk.MenuItem(_("SQL History"))
+ filemenu.append(menu_items)
+ menu_items.connect("activate", self.view_sql_history, None)
+
+ menu_items = gtk.MenuItem(_("Sync notes"))
+ filemenu.append(menu_items)
+ menu_items.connect("activate", self.sync_notes, None)
+
+ menu_items = gtk.MenuItem(_("Quit"))
+ filemenu.append(menu_items)
+ menu_items.connect("activate", self.destroy, None)
+
+ file_menu = gtk.MenuItem(_("File"))
+ file_menu.show()
+ file_menu.set_submenu(filemenu)
+
+ categorymenu = gtk.Menu()
+
+ menu_items = gtk.MenuItem(_("delete"))
+ categorymenu.append(menu_items)
+ menu_items.connect("activate", self.delete_Category, None)
+
+ menu_items = gtk.MenuItem(_("move to category"))
+ categorymenu.append(menu_items)
+ menu_items.connect("activate", self.move_Category, None)
+
+ category_menu = gtk.MenuItem(_("Category"))
+ category_menu.show()
+ category_menu.set_submenu(categorymenu)
+
+ viewmenu = gtk.Menu()
+
+ menu_items = gtk.MenuItem(_("Word Wrap"))
+ viewmenu.append(menu_items)
+ menu_items.connect("activate", self.toggle_word_wrap, None)
+ self._wordWrapEnabled = False
+
+ view_menu = gtk.MenuItem(_("View"))
+ view_menu.show()
+ view_menu.set_submenu(viewmenu)
+
+ helpmenu = gtk.Menu()
+
+ menu_items = gtk.MenuItem(_("About"))
+ helpmenu.append(menu_items)
+ menu_items.connect("activate", self.show_about, None)
+
+ help_menu = gtk.MenuItem(_("Help"))
+ help_menu.show()
+ help_menu.set_submenu(helpmenu)
+
+ menu_bar = gtk.MenuBar()
+ menu_bar.show()
+ menu_bar.append (file_menu)
+ menu_bar.append (category_menu)
+ menu_bar.append (view_menu)
+ menu_bar.append (help_menu)
+
+ menu_bar.show()
+ if IS_HILDON:
+ menu = gtk.Menu()
+ for child in menu_bar.get_children():
+ child.reparent(menu)
+ self.window.set_menu(menu)
+ menu_bar.destroy()
+ else:
+ vbox.pack_start(menu_bar, False, False, 0)
+
+ #Create GUI elements
+ self.topBox = libkopfzeile.Kopfzeile(self.db)
+ vbox.pack_start(self.topBox, False, False, 0)
+
+ self.notizen = libnotizen.Notizen(self.db, self.topBox)
+ vbox.pack_start(self.notizen, True, True, 0)
+
+ self.window.add(vbox)
+ self.window.show_all()
+ self.toggle_word_wrap()
+
+ def set_db_file(self, widget = None, data = None):
+ dlg = hildon.FileChooserDialog(parent=self.window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
+
+ if self.db.ladeDirekt('datenbank'):
+ dlg.set_filename(self.db.ladeDirekt('datenbank'))
+
+ dlg.set_title(_("Choose database file"))
+ if dlg.run() == gtk.RESPONSE_OK:
+ fileName = dlg.get_filename()
+ self.db.speichereDirekt('datenbank', fileName)
+
+ self.db.openDB()
+ self.topBox.loadCategories()
+ self.notizen.loadNotes()
+ dlg.destroy()
+
+ def show_about(self, widget = None, data = None):
+ dialog = gtk.AboutDialog()
+ dialog.set_position(gtk.WIN_POS_CENTER)
+ dialog.set_name(self.__pretty_app_name__)
+ dialog.set_version(self.__version__)
+ dialog.set_copyright("")
+ dialog.set_website("http://axique.de/index.php?f=Quicknote")
+ comments = _("%s is a note taking program; it is optimised for quick save and search of notes") % self.__pretty_app_name__
+ dialog.set_comments(comments)
+ dialog.run()
+ dialog.destroy()
+
+ def view_sql_history(self, widget = None, data = None, data2 = None):
+ import libsqldialog
+ sqldiag = libsqldialog.sqlDialog(self.db)
+ res = sqldiag.run()
+ sqldiag.hide()
+ if res == 444:
+ logging.info("exporting sql")
+
+ dlg = hildon.FileChooserDialog(parent=self.window, action=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 delete_Category(self, widget = None, data = None):
+ if (self.topBox.getCategory() == "%") or (self.topBox.getCategory() == "undefined"):
+ mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("This category can not be deleted"))
+ response = mbox.run()
+ mbox.hide()
+ mbox.destroy()
+ return
+
+ mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, _("Are you sure to delete the current category?"))
+ response = mbox.run()
+ mbox.hide()
+ mbox.destroy()
+ if response == gtk.RESPONSE_YES:
+ sql = "UPDATE notes SET category = ? WHERE category = ?"
+ self.db.speichereSQL(sql, ("undefined", self.topBox.getCategory()))
+ sql = "DELETE FROM categories WHERE liste = ?"
+ self.db.speichereSQL(sql, (self.topBox.getCategory(), ))
+ model = self.topBox.comboCategory.get_model()
+ pos = self.topBox.comboCategory.get_active()
+ if (pos>1):
+ self.topBox.comboCategory.remove_text(pos)
+ self.topBox.comboCategory.set_active(0)
+
+ def move_Category(self, widget = None, data = None):
+ dialog = gtk.Dialog(_("Choose category"), self.window, 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)
+ comboCategory = gtk.combo_box_new_text()
+
+ comboCategory.append_text('undefined')
+ sql = "SELECT id, liste FROM categories WHERE id = 0 ORDER BY liste"
+ rows = self.db.ladeSQL(sql)
+ for row in rows:
+ comboCategory.append_text(row[1])
+
+ dialog.vbox.pack_start(comboCategory, True, True, 0)
+
+ dialog.vbox.show_all()
+ #dialog.set_size_request(400, 300)
+
+ if dialog.run() == gtk.RESPONSE_ACCEPT:
+ n = comboCategory.get_active()
+ if (n>-1) and (self.notizen.noteid!= -1):
+ model = comboCategory.get_model()
+ active = comboCategory.get_active()
+ if active < 0:
+ return None
+ cat_id = model[active][0]
+
+ noteid, category, note = self.db.loadNote(self.notizen.noteid)
+ #print noteid, category, cat_id
+ self.db.saveNote(noteid, note, cat_id, pcdatum = None)
+ self.topBox.comboCategoryChanged()
+ else:
+ mbox = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("No note selected."))
+ response = mbox.run()
+ mbox.hide()
+ mbox.destroy()
+
+ dialog.destroy()
+
+ def sync_finished(self, data = None, data2 = None):
+ self.topBox.loadCategories()
+ self.notizen.loadNotes()
+
+ 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, 50504)
+ 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):
+ self.sync_dialog.run()
+ self.sync_dialog.hide()
+
+ def toggle_word_wrap(self, *args):
+ self._wordWrapEnabled = not self._wordWrapEnabled
+ self.notizen.set_wordwrap(self._wordWrapEnabled)
+
+ def delete_event(self, widget, event, data = None):
+ return False
+
+ def destroy(self, widget = None, data = None):
+ self.db.close()
+ if self._osso_c:
+ self._osso_c.close()
+ gtk.main_quit()
+
+ def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
+ """
+ For system_inactivity, we have no background tasks to pause
+
+ @note Hildon specific
+ """
+ if memory_low:
+ gc.collect()
+
+ if save_unsaved_data or shutdown:
+ pass
+
+ 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 on_key_press(self, widget, event, *args):
+ 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 ()
+ elif event.keyval == gtk.keysyms.F7:
+ # Zoom In
+ self.topBox.hide()
+ elif event.keyval == gtk.keysyms.F8:
+ # Zoom Out
+ self.topBox.show()
+
+ def main(self):
+ gtk.main()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import sys
+import os
+import time
+import sqlite3
+import shelve
+import logging
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class Speichern():
+
+ def __init__(self):
+ home_dir = os.path.expanduser('~')
+ filename = os.path.join(home_dir, ".quicknote.dat")
+ self.d = shelve.open(filename)
+ self.openDB()
+
+ 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 = ""):
+ if (self.d.has_key(schluessel) == True):
+ data = self.d[schluessel]
+ return data
+ else:
+ return default
+
+ def speichereSQL(self, sql, tupel = None, commit = True, host = "self", log = True, pcdatum = None, rowid = ""):
+ try:
+ programSQLError = True
+ if tupel is None:
+ self.cur.execute(sql)
+ else:
+ self.cur.execute(sql, tupel)
+ programSQLError = False
+
+ if (log == True):
+ strtupel = []
+ if tupel is not None:
+ for t in tupel:
+ strtupel.append(str(t))
+
+ if pcdatum is None:
+ pcdatum = int(time.time())
+ self.cur.execute("INSERT INTO logtable ( pcdatum, sql, param, host, rowid ) VALUES (?, ?, ?, ?, ?)", (pcdatum, sql, " <<Tren-ner>> ".join(strtupel), host, str(rowid) ))
+ if commit:
+ self.conn.commit()
+
+ return True
+ except StandardError:
+ s = str(sys.exc_info())
+ if s.find(" already exists") == -1:
+ 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 is None:
+ self.cur.execute(sql)
+ else:
+ self.cur.execute(sql, tupel)
+ return self.cur.fetchall()
+ except StandardError:
+ 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
+ erg = []
+ for row in rows:
+ datum = time.strftime("%d.%m.%y %H:%M:%S", (time.localtime(row[1])))
+ erg.append([row[1], datum, row[2], row[3], row[3].split(" <<Tren-ner>> ")])
+
+ return erg
+
+ def openDB(self):
+ try:
+ self.cur.close()
+ except StandardError:
+ pass
+ try:
+ self.conn.close()
+ except StandardError:
+ pass
+
+ db = self.ladeDirekt("datenbank")
+ if db == "":
+ home_dir = os.path.expanduser('~')
+
+ #on hildon user not home-dir but /home/user/MyDocs
+ if home_dir == "/home/user":
+ if os.path.exists(home_dir+os.sep+"MyDocs/"):
+ home_dir = home_dir+os.sep+"MyDocs/"
+ db = os.path.join(home_dir, "quicknote.s3db")
+
+ 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 StandardError:
+ 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 StandardError:
+ pass
+
+ #Create notes table
+ try:
+ sql = "CREATE TABLE notes (noteid TEXT, pcdatum INTEGER , category TEXT, note TEXT)"
+ self.cur.execute(sql)
+ self.conn.commit()
+ except StandardError:
+ pass
+
+ def saveNote(self, noteid, note, category, pcdatum = None):
+ if category == "%":
+ category = ""
+ sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
+ rows = self.ladeSQL(sql, (noteid, ))
+
+ if rows is None or len(rows) == 0:
+ sql = "INSERT INTO notes (noteid, pcdatum, category, note) VALUES (?, ?, ?, ?)"
+ if pcdatum is None:
+ pcdatum = int(time.time())
+ self.speichereSQL(sql, (noteid, pcdatum, category, note), rowid = noteid)
+ else:
+ sql = "UPDATE notes SET category = ?, note = ?, pcdatum = ? WHERE noteid = ?"
+ self.speichereSQL(sql, (category, note, str(int(time.time())), noteid), rowid = noteid)
+
+ def loadNote(self, noteid):
+ if noteid is None or str(noteid) == "":
+ return (None, None, None)
+ sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
+ rows = self.ladeSQL(sql, (noteid, ))
+ if rows is None or len(rows) == 0:
+ return None
+ else:
+ noteid, pcdatum, category, note = rows[0]
+ return (noteid, pcdatum, category, note)
+
+ def delNote(self, noteid):
+ sql = "DELETE FROM notes WHERE noteid = ?"
+ self.speichereSQL(sql, (noteid, ), rowid = noteid)
+
+ def searchNotes(self, searchstring, category):
+ sql = "SELECT noteid, category, note FROM notes WHERE note like ? AND category like ? ORDER BY note"
+ rows = self.ladeSQL(sql, ("%"+searchstring+"%", category))
+ if rows is None or len(rows) == 0:
+ return None
+ else:
+ return rows
+
+ def getNoteHistory(self, noteid):
+ return self.ladeHistory("UPDATE notes ", noteid)
+
+ def close(self):
+ try:
+ self.d.close()
+ except StandardError:
+ pass
+ try:
+ self.cur.close()
+ except StandardError:
+ pass
+ try:
+ self.conn.close()
+ except StandardError:
+ pass
+ logging.info("Alle Data saved")
+
+ def __del__(self):
+ self.close()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import time
+import logging
+
+import gtk
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class sqlDialog(gtk.Dialog):
+
+ 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()
+
+ # create the TreeViewColumns to display the data
+ self.tvcolumn1 = gtk.TreeViewColumn(_('Timestamp'))
+ 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)
+
+ # 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.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, ))
+ for row in rows:
+ pcdatum, sql, param = row
+ datum = str(time.strftime(_("%d.%m.%y %H:%M:%S "), (time.localtime(pcdatum))))
+ self.liststore.append([datum, sql, param])
+
+ self.set_size_request(500, 400)
+
+ def exportSQL(self, filename):
+ f = open(filename, 'w')
+ try:
+ 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")
+ finally:
+ f.close()
--- /dev/null
+#!/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 sys
+import time
+import SimpleXMLRPCServer
+import xmlrpclib
+import select
+#import fcntl
+import uuid
+import logging
+import socket
+socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
+
+import gtk
+import gobject
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+class ProgressDialog(gtk.Dialog):
+
+ 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.vbox.show_all()
+ self.show()
+
+ def pulse(self):
+ pass
+
+
+class Sync(gtk.VBox):
+
+ __gsignals__ = {
+ 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
+ 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
+ }
+
+ def __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
+
+ sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
+ self.db.speichereSQL(sql, log = False)
+
+ sql = "SELECT uuid, pcdatum FROM sync WHERE syncpartner = ?"
+ rows = self.db.ladeSQL(sql, ("self", )) #Eigene Id feststellen
+
+ if (rows is None)or(len(rows)!= 1):
+ sql = "DELETE FROM sync WHERE syncpartner = ?"
+ self.db.speichereSQL(sql, ("self", ), log = False)
+
+ 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)
+ else:
+ sync_uuid, pcdatum = rows[0]
+ self.sync_uuid = sync_uuid
+
+ 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"))
+
+ frame.add(self.comboIP)
+ serverbutton = gtk.ToggleButton(_("Start/Stop 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 stopped"))
+ self.pack_start(self.syncServerStatusLabel, expand = False, fill = True, padding = 1)
+
+ frame = gtk.Frame(_("Remote SyncServer (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.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):
+ serverbutton.set_active(True)
+
+ def changeSyncStatus(self, active, title):
+ self.syncStatusLabel.set_text(title)
+ if active == True:
+ if self.progress is None:
+ self.progress = ProgressDialog(parent = self.parentwindow)
+ self.emit("syncBeforeStart", "syncBeforeStart")
+ else:
+ if self.progress is not None:
+ self.progress.hide()
+ self.progress.destroy()
+ self.progress = None
+ self.emit("syncFinished", "syncFinished")
+
+ def pulse(self):
+ if self.progress is not None:
+ self.progress.pulse()
+
+ def getUeberblickBox(self):
+ frame = gtk.Frame(_("Query"))
+ return frame
+
+ def handleRPC(self):
+ try:
+ if self.rpcserver is None:
+ return False
+ except StandardError:
+ return False
+
+ while 0 < len(self.poll.poll(0)):
+ self.rpcserver.handle_request()
+ return True
+
+ def get_ip_address(self, ifname):
+ return socket.gethostbyname(socket.gethostname())
+
+ def getLastSyncDate(self, sync_uuid):
+ sql = "SELECT syncpartner, pcdatum FROM sync WHERE uuid = ?"
+ rows = self.db.ladeSQL(sql, (sync_uuid, ))
+ if rows is not None and len(rows) == 1:
+ syncpartner, pcdatum = rows[0]
+ else:
+ pcdatum = -1
+ logging.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
+ return pcdatum
+
+ def check4commit(self, newSQL, lastdate):
+ logging.info("check4commit 1")
+ if self.concernedRows is 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 is not None and 0 < len(self.concernedRows):
+ id1, pcdatum, sql, param, host, rowid = newSQL
+
+ if 0 < len(rowid):
+ for x in self.concernedRows:
+ if x[1] == rowid:
+ if pcdatum < x[0]:
+ logging.info("newer sync entry, ignoring old one")
+ return False
+ else:
+ return True
+
+ return True
+
+ def writeSQLTupel(self, newSQLs, lastdate):
+ if newSQLs is None:
+ return
+
+ self.concernedRows = None
+ pausenzaehler = 0
+ logging.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
+ for newSQL in newSQLs:
+ if newSQL[3] != "":
+ param = newSQL[3].split(" <<Tren-ner>> ")
+ else:
+ param = None
+
+ if 2 < len(newSQL):
+ 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):
+ self.changeSyncStatus(True, "sync process running")
+ self.pulse()
+
+ while gtk.events_pending():
+ gtk.main_iteration()
+ diff = abs(time.time() - pcdatumjetzt)
+ if 30 < diff:
+ return -1
+
+ logging.info("doSync read sqls")
+ sql = "SELECT * FROM logtable WHERE pcdatum>?"
+ rows = self.db.ladeSQL(sql, (pcdatum, ))
+ logging.info("doSync read sqls")
+ self.writeSQLTupel(newSQLs, pcdatum)
+ logging.info("doSync wrote "+str(len(newSQLs))+" sqls")
+ logging.info("doSync sending "+str(len(rows))+" sqls")
+ 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():
+ logging.info("Starting Server")
+
+ try:
+ ip = self.comboIP.get_child().get_text()
+ self.rpcserver = SimpleXMLRPCServer.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 StandardError:
+ 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, _("Could not start SyncServer. Check IP, port settings.")) #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 StandardError:
+ pass
+ self.syncServerStatusLabel.set_text(_("SyncServer stopped"))
+ #save
+ self.db.speichereDirekt("startSyncServer", False)
+
+ def doSaveFinalTime(self, sync_uuid, pcdatum = None):
+ if pcdatum is None:
+ pcdatum = int(time.time())
+ if pcdatum < time.time():
+ 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")
+
+ 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)
+ server_sync_uuid = self.server.getRemoteSyncUUID()
+ lastDate = self.getLastSyncDate(str(server_sync_uuid))
+
+ 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 StandardError:
+ 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
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Copyright (C) 2007 Christoph Würstle
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+import os
+import sys
+sys.path.append('/usr/lib/quicknote')
+
+import locale
+import gettext
+gettext.install('quicknote', unicode = 1)
+
+import libquicknote
+
+if __name__ == "__main__":
+ app = libquicknote.quicknoteclass()
+ app.main()
--- /dev/null
+#!/usr/bin/env python2.5\r
+# -*- coding: utf-8 -*-\r
+\r
+"""\r
+ Copyright (C) 2007 Christoph Würstle and in big parts by Gerold Penz\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License version 2 as\r
+published by the Free Software Foundation.\r
+"""\r
+\r
+\r
+import pygtk\r
+pygtk.require("2.0")\r
+import gtk\r
+\r
+\r
+try:\r
+ _\r
+except NameError:\r
+ _ = lambda x: x\r
+\r
+\r
+class SimpleList(gtk.ScrolledWindow):\r
+ """\r
+ Stellt eine einfache Liste mit Laufbalken dar. Das wird mit\r
+ den Objekten ScrolledWindow und TreeView erreicht.\r
+ """\r
+\r
+ def __init__(self):\r
+ """\r
+ Initialisieren\r
+ """\r
+\r
+ gtk.ScrolledWindow.__init__(self)\r
+ self.selected_item = None # (<Position>, <Key>, <Value>)\r
+\r
+ # Liste\r
+ self.list_store = gtk.ListStore(str, str)\r
+\r
+ # ScrolledWindow\r
+ self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)\r
+ self.set_shadow_type(gtk.SHADOW_IN)\r
+\r
+ # Treeview\r
+ self.tree_view = gtk.TreeView(self.list_store)\r
+ self.tree_view.set_headers_visible(False)\r
+ self.tree_view.get_selection().set_mode(gtk.SELECTION_BROWSE)\r
+ self.tree_view.connect("cursor-changed", self._on_cursor_changed)\r
+ self.tree_view.connect("row-activated", self._on_row_activated)\r
+ self.tree_view.show()\r
+\r
+ # Key-Spalte hinzuf�gen\r
+ self.key_cell = gtk.CellRendererText()\r
+ self.key_column = gtk.TreeViewColumn("Key")\r
+ self.key_column.pack_start(self.key_cell, True)\r
+ self.key_column.add_attribute(self.key_cell, "text", 0)\r
+ self.key_column.set_visible(False)\r
+ self.tree_view.append_column(self.key_column)\r
+\r
+ # Value-Spalte hinzufügen\r
+ self.value_cell = gtk.CellRendererText()\r
+ self.value_column = gtk.TreeViewColumn("Caption")\r
+ self.value_column.pack_start(self.value_cell, True)\r
+ self.value_column.add_attribute(self.value_cell, "text", 1)\r
+ self.tree_view.append_column(self.value_column)\r
+\r
+ # Suchspalte setzen\r
+ # Leider funktioniert die Suche im Moment nicht so \r
+ # wie ich das möchte. Deshalb habe ich die Suche abgeschaltet.\r
+ self.tree_view.set_enable_search(False)\r
+\r
+ # Anzeigen\r
+ self.add(self.tree_view)\r
+ self.show()\r
+\r
+ def append_item(self, value, key = ""):\r
+ """\r
+ F�gt der Liste Werte und wenn gew�nscht, Schl�ssel hinzu.\r
+ """\r
+\r
+ self.list_store.append([key, value])\r
+\r
+ def select_last_item(self):\r
+ path = str(len(self.list_store)-1)\r
+ self.tree_view.set_cursor(path, self.value_column)\r
+ return len(self.list_store)-1\r
+\r
+ def change_item(self, pos, value, key = ""):\r
+ self.list_store[pos] = [key, value]\r
+\r
+ def remove_item(self, pos):\r
+ model = self.tree_view.get_model()\r
+ self.list_store.remove(model.get_iter(str(pos)))\r
+\r
+ def get_item(self, pos):\r
+ return self.list_store[pos]\r
+\r
+ def clear_items(self):\r
+ self.list_store.clear()\r
+\r
+ def _on_row_activated(self, treeview, path, view_column, data = None):\r
+ """\r
+ Setzt den Wert von self.selected_items. Dieser Wert kann\r
+ mit der Methode "get_selection_data" abgerufen werden.\r
+ """\r
+\r
+ iter = self.list_store.get_iter(path)\r
+\r
+ if iter:\r
+ self.selected_item = (\r
+ path[0], # Position\r
+ self.list_store.get_value(iter, 0), # Key\r
+ self.list_store.get_value(iter, 1) # Value\r
+ )\r
+\r
+ def _on_cursor_changed(self, widget, data1 = None, data2 = None):\r
+ """\r
+ Setzt den Wert von self.selected_items. Dieser Wert kann\r
+ mit der Methode "get_selection_data" abgerufen werden.\r
+ """\r
+\r
+ selection = widget.get_selection()\r
+ (model, iter) = selection.get_selected()\r
+\r
+ if iter:\r
+ self.selected_item = (\r
+ int(selection.get_selected_rows()[1][0][0]), # Position\r
+ str(model.get_value(iter, 0)), # Key\r
+ str(model.get_value(iter, 1)) # Value\r
+ )\r
+\r
+ def get_selection_data(self):\r
+ """\r
+ Gibt die Variable self.selected_item zur�ck.\r
+ Diese enth�lt ein Tupel. (<Position>, <Key>, <Value>)\r
+ """\r
+\r
+ return self.selected_item # (<Position>, <Key>, <Value>)\r
+\r
+ def set_eventfunction__cursor_changed(self, function):\r
+ """\r
+ Verbindet die �bergebene Funktion mit dem \r
+ Signal "cursor-changed".\r
+ """\r
+\r
+ self.tree_view.connect("cursor-changed", function)\r
--- /dev/null
+#!/usr/bin/python2.5
+
+import os
+
+try:
+ import py2deb
+except ImportError:
+ import fake_py2deb as py2deb
+
+
+__appname__ = "quicknote"
+__description__ = "Simple note taking application in a similar vein as PalmOS Memos"
+__author__ = "Christoph Wurstle"
+__email__ = "n800@axique.net"
+__version__ = "0.7.6"
+__build__ = 1
+__changelog__ = '''\
+0.7.6
+ * Line-wrap
+ * Zoom
+
+0.7.4
+ * fixed small bugs
+ * move category
+
+0.7.3
+ * fixed small bugs
+ * move category
+
+0.7.2
+ * improved sync, fixed a small bug
+
+0.7.1
+ * improved sync
+
+0.7.0
+ * Initial Release.
+'''
+
+
+__postinstall__ = '''#!/bin/sh -e
+
+gtk-update-icon-cache -f /usr/share/icons/hicolor
+exit 0
+'''
+
+
+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
+
+
+if __name__ == "__main__":
+ try:
+ os.chdir(os.path.dirname(sys.argv[0]))
+ except:
+ pass
+
+ p = py2deb.Py2deb(__appname__)
+ p.description = __description__
+ p.author = __author__
+ p.mail = __email__
+ p.license = "lgpl"
+ p.depends = "python2.5, python2.5-gtk2"
+ p.section = "user/other"
+ p.arch = "all"
+ p.urgency = "low"
+ p.distribution = "chinook diablo"
+ p.repository = "extras-devel"
+ p.changelog = __changelog__
+ p.postinstall = __postinstall__
+ p.icon = "26x26-quicknote.png"
+ p["/usr/bin"] = [ "quicknote.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/quicknote"
+ if relPath:
+ fullPath += os.sep+relPath
+ p[fullPath] = list(
+ "|".join((oldName, newName))
+ for (oldName, newName) in files
+ )
+ p["/usr/share/applications/hildon"] = ["quicknote.desktop"]
+ p["/usr/share/dbus-1/services"] = ["quicknote.service"]
+ p["/usr/share/icons/hicolor/26x26/hildon"] = ["26x26-quicknote.png|quicknote.png"]
+ p["/usr/share/icons/hicolor/40x40/hildon"] = ["40x40-quicknote.png|quicknote.png"]
+ p["/usr/share/icons/hicolor/48x48/hildon"] = ["48x48-quicknote.png|quicknote.png"]
+ p["/usr/share/icons/hicolor/scalable/hildon"] = ["scale-quicknote.png|quicknote.png"]
+
+ print p
+ print p.generate(
+ __version__, __build__, changelog=__changelog__,
+ tar=True, dsc=True, changes=True, build=False, src=True
+ )
--- /dev/null
+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
--- /dev/null
+# 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
+
+[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'
--- /dev/null
+#!/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);