From 125b4fc6cc659ccd8ea0d83e4d7bc9e408cd35ed Mon Sep 17 00:00:00 2001 From: epage Date: Wed, 28 Oct 2009 01:51:55 +0000 Subject: [PATCH] Renames and making Speichern a new style object git-svn-id: file:///svnroot/quicknote/trunk@60 bb7704e3-badb-4cfa-9ab3-9374dc87eaa2 --- src/history.py | 85 ++++++++++ src/kopfzeile.py | 146 ++++++++++++++++++ src/libhistory.py | 85 ---------- src/libkopfzeile.py | 143 ----------------- src/libnotizen.py | 270 -------------------------------- src/libquicknote.py | 420 -------------------------------------------------- src/libspeichern.py | 208 ------------------------- src/libsqldialog.py | 105 ------------- src/libsync.py | 368 ------------------------------------------- src/notizen.py | 270 ++++++++++++++++++++++++++++++++ src/quicknote.py | 4 +- src/quicknote_gtk.py | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/speichern.py | 208 +++++++++++++++++++++++++ src/sqldialog.py | 105 +++++++++++++ src/sync.py | 368 +++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 1604 insertions(+), 1601 deletions(-) create mode 100644 src/history.py create mode 100644 src/kopfzeile.py delete mode 100644 src/libhistory.py delete mode 100644 src/libkopfzeile.py delete mode 100644 src/libnotizen.py delete mode 100644 src/libquicknote.py delete mode 100644 src/libspeichern.py delete mode 100755 src/libsqldialog.py delete mode 100755 src/libsync.py create mode 100644 src/notizen.py create mode 100644 src/quicknote_gtk.py create mode 100644 src/speichern.py create mode 100755 src/sqldialog.py create mode 100755 src/sync.py diff --git a/src/history.py b/src/history.py new file mode 100644 index 0000000..c897cd9 --- /dev/null +++ b/src/history.py @@ -0,0 +1,85 @@ +#!/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 gtk + + +try: + _ +except NameError: + _ = lambda x: x + + +_moduleLogger = logging.getLogger("history") + + +class Dialog(gtk.Dialog): + + def __init__(self, daten = None): + super(Dialog, self).__init__( + _("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.noteHistory = gtk.ListStore( + int, #pcdatum + str, #datum + str, #sql + str, #param + str #param schön + ) + + # create the TreeView using liststore + self._historyView = gtk.TreeView(self.noteHistory) + self._historyView.set_rules_hint(True) + # create a CellRenderers to render the data + self._timestampCell = gtk.CellRendererText() + self._noteCell = gtk.CellRendererText() + + # create the TreeViewColumns to display the data + self._timestampColumn = gtk.TreeViewColumn(_('Timestamp')) + self._noteColumn = gtk.TreeViewColumn(_('Note')) + # add columns to treeview + self._historyView.append_column(self._timestampColumn) + self._historyView.append_column(self._noteColumn) + + # add the cells to the columns - 2 in the first + self._timestampColumn.pack_start(self._timestampCell, True) + self._noteColumn.pack_start(self._noteCell, True) + self._timestampColumn.set_attributes(self._timestampCell, text = 1) #Spalten setzten hier!!!! + self._noteColumn.set_attributes(self._noteCell, text = 4) + + self._historyView.set_reorderable(False) + + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window.add(self._historyView) + self.vbox.pack_start(scrolled_window, expand = True, fill = True, padding = 0) + + self.noteHistory.clear() + + if daten is not None: + for data in daten: + self.noteHistory.append(data) + + def get_selected_row(self): + path = self._historyView.get_cursor()[0] + if path is None or path == "": + return None + + iter1 = self._historyView.get_model().get_iter(path) + return self._historyView.get_model().get(iter1, 0, 1, 2, 3, 4) diff --git a/src/kopfzeile.py b/src/kopfzeile.py new file mode 100644 index 0000000..d3dc00b --- /dev/null +++ b/src/kopfzeile.py @@ -0,0 +1,146 @@ +#!/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 + + +_moduleLogger = logging.getLogger("kopfzeile") + + +class Kopfzeile(gtk.HBox): + """ + Category/Search box + """ + + __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) + _moduleLogger.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.categoryCombo = gtk.combo_box_entry_new_text() + categoryHBox.pack_start(self.categoryCombo, expand = True, fill = True, padding = 0) + self.load_categories() + self.categoryCombo.connect("changed", self.category_combo_changed, 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.search_entry_changed, None) + + def category_combo_changed(self, widget = None, data = None): + _moduleLogger.debug("comboCategoryChanged") + if self._lastCategory != self.categoryCombo.get_active(): + sql = "UPDATE categories SET liste = ? WHERE id = 1" + self._db.speichereSQL(sql, (self.categoryCombo.get_active(), )) + + self.emit("reload_notes") + + def search_entry_changed(self, widget = None, data = None): + _moduleLogger.debug("search_entry_changed") + self.emit("reload_notes") + + def get_category(self): + entry = self.categoryCombo.get_child() + category = entry.get_text() + if category == _("all"): + category = "%" + if category == "": + category = "undefined" + self.categoryCombo.set_active(1) + self.categoryCombo.show() + return category + + def define_this_category(self): + category = self.get_category() + + model = self.categoryCombo.get_model() + n = len(self.categoryCombo.get_model()) + i = 0 + active = -1 + cats = [] + for i, row in enumerate(model): + if row[0] == category: + active = i + if row[0] != "%": + cats.append(row[0]) + + if active == -1 and category != "%": + self.categoryCombo.append_text(category) + sql = "INSERT INTO categories (id, liste) VALUES (0, ?)" + self._db.speichereSQL(sql, (category, )) + self.categoryCombo.set_active(i) + + def get_search_pattern(self): + return self._searchEntry.get_text() + + def load_categories(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.categoryCombo.clear() + while 0 < len(self.categoryCombo.get_model()): + self.categoryCombo.remove_text(0) + + self.categoryCombo.append_text(_('all')) + self.categoryCombo.append_text('undefined') + + if cats is not None and 0 < len(cats): + for cat in cats: + self.categoryCombo.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.categoryCombo.set_active(int(rows[0][1])) + else: + self.categoryCombo.set_active(1) + + self._lastCategory = self.categoryCombo.get_active() diff --git a/src/libhistory.py b/src/libhistory.py deleted file mode 100644 index c897cd9..0000000 --- a/src/libhistory.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/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 gtk - - -try: - _ -except NameError: - _ = lambda x: x - - -_moduleLogger = logging.getLogger("history") - - -class Dialog(gtk.Dialog): - - def __init__(self, daten = None): - super(Dialog, self).__init__( - _("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.noteHistory = gtk.ListStore( - int, #pcdatum - str, #datum - str, #sql - str, #param - str #param schön - ) - - # create the TreeView using liststore - self._historyView = gtk.TreeView(self.noteHistory) - self._historyView.set_rules_hint(True) - # create a CellRenderers to render the data - self._timestampCell = gtk.CellRendererText() - self._noteCell = gtk.CellRendererText() - - # create the TreeViewColumns to display the data - self._timestampColumn = gtk.TreeViewColumn(_('Timestamp')) - self._noteColumn = gtk.TreeViewColumn(_('Note')) - # add columns to treeview - self._historyView.append_column(self._timestampColumn) - self._historyView.append_column(self._noteColumn) - - # add the cells to the columns - 2 in the first - self._timestampColumn.pack_start(self._timestampCell, True) - self._noteColumn.pack_start(self._noteCell, True) - self._timestampColumn.set_attributes(self._timestampCell, text = 1) #Spalten setzten hier!!!! - self._noteColumn.set_attributes(self._noteCell, text = 4) - - self._historyView.set_reorderable(False) - - scrolled_window = gtk.ScrolledWindow() - scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled_window.add(self._historyView) - self.vbox.pack_start(scrolled_window, expand = True, fill = True, padding = 0) - - self.noteHistory.clear() - - if daten is not None: - for data in daten: - self.noteHistory.append(data) - - def get_selected_row(self): - path = self._historyView.get_cursor()[0] - if path is None or path == "": - return None - - iter1 = self._historyView.get_model().get_iter(path) - return self._historyView.get_model().get(iter1, 0, 1, 2, 3, 4) diff --git a/src/libkopfzeile.py b/src/libkopfzeile.py deleted file mode 100644 index 017d22b..0000000 --- a/src/libkopfzeile.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/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 - - -_moduleLogger = logging.getLogger("kopfzeile") - - -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) - _moduleLogger.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.categoryCombo = gtk.combo_box_entry_new_text() - categoryHBox.pack_start(self.categoryCombo, expand = True, fill = True, padding = 0) - self.load_categories() - self.categoryCombo.connect("changed", self.category_combo_changed, 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.search_entry_changed, None) - - def category_combo_changed(self, widget = None, data = None): - _moduleLogger.debug("comboCategoryChanged") - if self._lastCategory != self.categoryCombo.get_active(): - sql = "UPDATE categories SET liste = ? WHERE id = 1" - self._db.speichereSQL(sql, (self.categoryCombo.get_active(), )) - - self.emit("reload_notes") - - def search_entry_changed(self, widget = None, data = None): - _moduleLogger.debug("search_entry_changed") - self.emit("reload_notes") - - def get_category(self): - entry = self.categoryCombo.get_child() - category = entry.get_text() - if category == _("all"): - category = "%" - if category == "": - category = "undefined" - self.categoryCombo.set_active(1) - self.categoryCombo.show() - return category - - def define_this_category(self): - category = self.get_category() - - model = self.categoryCombo.get_model() - n = len(self.categoryCombo.get_model()) - i = 0 - active = -1 - cats = [] - for i, row in enumerate(model): - if row[0] == category: - active = i - if row[0] != "%": - cats.append(row[0]) - - if active == -1 and category != "%": - self.categoryCombo.append_text(category) - sql = "INSERT INTO categories (id, liste) VALUES (0, ?)" - self._db.speichereSQL(sql, (category, )) - self.categoryCombo.set_active(i) - - def get_search_pattern(self): - return self._searchEntry.get_text() - - def load_categories(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.categoryCombo.clear() - while 0 < len(self.categoryCombo.get_model()): - self.categoryCombo.remove_text(0) - - self.categoryCombo.append_text(_('all')) - self.categoryCombo.append_text('undefined') - - if cats is not None and 0 < len(cats): - for cat in cats: - self.categoryCombo.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.categoryCombo.set_active(int(rows[0][1])) - else: - self.categoryCombo.set_active(1) - - self._lastCategory = self.categoryCombo.get_active() diff --git a/src/libnotizen.py b/src/libnotizen.py deleted file mode 100644 index b18e599..0000000 --- a/src/libnotizen.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/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 time -import logging -import uuid - -import gobject -import gtk -try: - import gtkspell -except ImportError: - gtkspell = None - -import simple_list - - -try: - _ -except NameError: - _ = lambda x: x - - -_moduleLogger = logging.getLogger("notizen") - - -class Notizen(gtk.HBox): - - def __init__(self, db, topBox): - self._db = db - self._topBox = topBox - self.noteId = -1 - self._pos = -1 - self._noteBody = None #Last notetext - self._categoryName = "" - - gtk.HBox.__init__(self, homogeneous = False, spacing = 0) - _moduleLogger.info("libnotizen, init") - - self._noteslist = simple_list.SimpleList() - self._noteslist.set_eventfunction_cursor_changed(self._update_noteslist) - - 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._on_add_note, None) - buttonHBox.pack_start(button, expand = True, fill = True, padding = 3) - - button = gtk.Button(stock = gtk.STOCK_DELETE) - button.connect("clicked", self._on_delete_note, None) - buttonHBox.pack_start(button, expand = True, fill = True, padding = 3) - - self.pack_start(vbox, expand = False, fill = True, padding = 3) - - self._noteBodyView = gtk.TextView() - self._noteBodyView.connect("focus-out-event", self.save_note, "focus-out-event") - buf = self._noteBodyView.get_buffer() - buf.set_text("") - buf.connect("changed", self._on_note_changed, None) - if gtkspell is not None: - self._noteBodySpellChecker = gtkspell.Spell(self._noteBodyView) - else: - self._noteBodySpellChecker = None - - #self.textviewNotiz.set_size_request(-1, 50) - self._noteScrollWindow = gtk.ScrolledWindow() - self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - self._noteScrollWindow.add(self._noteBodyView) - - frame = gtk.Frame(_("Note")) - frame.add(self._noteScrollWindow) - - vbox = gtk.VBox(homogeneous = False, spacing = 0) - vbox.pack_start(frame, expand = True, fill = True, padding = 3) - - self._historyBox = gtk.HBox(homogeneous = False, spacing = 0) - - self._historyStatusLabel = gtk.Label(_("No History")) - self._historyStatusLabel.set_alignment(0.0, 0.5) - self._historyBox.pack_start(self._historyStatusLabel, expand = True, fill = True, padding = 3) - - button = gtk.Button(_("History")) - button.connect("clicked", self._on_show_history, None) - self._historyBox.pack_start(button, expand = True, fill = True, padding = 3) - - vbox.pack_start(self._historyBox, expand = False, fill = True, padding = 3) - - self.pack_start(vbox, expand = True, fill = True, padding = 3) - - self.load_notes() - self._topBox.connect("reload_notes", self.load_notes) - - def set_wordwrap(self, enableWordWrap): - if enableWordWrap: - self._noteScrollWindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - self._noteBodyView.set_wrap_mode(gtk.WRAP_WORD) - else: - self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - self._noteBodyView.set_wrap_mode(gtk.WRAP_NONE) - - def show_history_area(self, visible): - if visible: - self._historyBox.show() - else: - self._historyBox.hide() - - def load_notes(self, data = None): - _moduleLogger.info("load_notes params: pos:"+str(self._pos)+" noteid:"+str(self.noteId)) - self._noteslist.clear_items() - self._noteslist.append_item(_("New Note..."), "new") - - self._categoryName = self._topBox.get_category() - search = self._topBox.get_search_pattern() - notes = self._db.searchNotes(search, self._categoryName) - - if notes is not None: - for note in notes: - noteid, category, noteText = note - title = self._get_title(noteText) - self._noteslist.append_item(title, noteid) - - self.noteId = -1 - self._pos = -1 - self._noteBodyView.get_buffer().set_text("") - - def save_note(self, widget = None, data = None, data2 = None): - _moduleLogger.info("save_note params: pos:"+str(self._pos)+" noteid:"+str(self.noteId)) - #print "params:", data, data2 - buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter()) - if buf is None or len(buf) == 0: - return - - if buf == self._noteBody: - return - - _moduleLogger.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._categoryName) - self._noteslist.append_item(self._get_title(buf), self.noteId) - self._pos = self._noteslist.select_last_item() - else: - self._db.saveNote(self.noteId, buf, self._categoryName) - - self._topBox.define_this_category() - - def _get_title(self, buf): - """ - @returns the title of the current note - """ - eol = buf.find("\n") - if -1 == eol: - eol = len(buf) - title = buf[:eol] - return title - - def _set_focus(self): - self._noteBodyView.grab_focus() - return False - - def _update_noteslist(self, data = None, data2 = None): - if self._pos != -1: - self.save_note() - - 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._categoryName) - self._pos = -1 - self._noteslist.append_item("", self.noteId) - self._noteBodyView.get_buffer().set_text("") - self._pos = self._noteslist.select_last_item() - else: - self._pos = pos - self.noteId, pcdatum, self._categoryName, self._noteBody = self._db.loadNote(key) - self._historyStatusLabel.set_text(time.strftime(_("Last change: %d.%m.%y %H:%M"), time.localtime(pcdatum))) - buf = self._noteBodyView.get_buffer() - buf.set_text(self._noteBody) - - gobject.timeout_add(200, self._set_focus) - - def _on_note_changed(self, widget = None, data = None): - if self._pos == -1 or self.noteId == -1: - return - - buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter()) - - title = self._get_title(buf) - value, key = self._noteslist.get_item(self._pos) - - if value != title: - self._noteslist.change_item(self._pos, title, self.noteId) - - def _on_add_note(self, widget = None, data = None): - self._update_noteslist("new") - - def _on_delete_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._noteBodyView.get_buffer().set_text("") - - def _on_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: - daten = row[4][1] - if daten != "" and lastNoteStr != daten: - lastNoteStr = daten - dialog.noteHistory.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.save_note() - data = dialog.get_selected_row() - if data is not None: - self._db.speichereSQL(data[2], data[3].split(" <> "), rowid = self.noteId) - _moduleLogger.info("loading History") - self._update_noteslist() - - dialog.destroy() diff --git a/src/libquicknote.py b/src/libquicknote.py deleted file mode 100644 index d44925f..0000000 --- a/src/libquicknote.py +++ /dev/null @@ -1,420 +0,0 @@ -#!/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. - -@todo Add Note Export (txt File) and Export All (json dump?) -@todo Remove confirmation on deleting empty notes -@todo Try to switch to more passive notifications (rather than message boxes) -""" - -from __future__ import with_statement - -import os -import gc -import logging -import warnings -import ConfigParser - -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 constants - -import libspeichern -import libkopfzeile -import libnotizen -import libsync - - -try: - _ -except NameError: - _ = lambda x: x - - -_moduleLogger = logging.getLogger("quick") - - -class QuicknoteProgram(hildon.Program): - - _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__) - _user_settings = "%s/settings.ini" % _user_data - - def __init__(self): - super(QuicknoteProgram, self).__init__() - if IS_HILDON: - gtk.set_application_name(constants.__pretty_app_name__) - - dblog = os.path.join(self._user_data, "quicknote.log") - - _moduleLogger.info('Starting quicknote') - - if osso is not None: - self._osso_c = osso.Context(constants.__app_name__, constants.__version__, False) - self._deviceState = osso.DeviceState(self._osso_c) - self._deviceState.set_device_state_callback(self._on_device_state_change, 0) - else: - self._osso_c = None - self._deviceState = None - - #Get the Main Window, and connect the "destroy" event - self._window = hildon.Window() - self.add_window(self._window) - - if not IS_HILDON: - self._window.set_title(constants.__pretty_app_name__) - self._window.connect("delete_event", self._on_delete_event) - self._window.connect("destroy", self._on_destroy) - self._window.connect("key-press-event", self._on_key_press) - self._window.connect("window-state-event", self._on_window_state_change) - self._window_in_fullscreen = False #The window isn't in full screen mode initially. - self._isZoomEnabled = False - - self._db = libspeichern.Speichern() - self._syncDialog = None - 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._on_view_sql_history, None) - - menu_items = gtk.MenuItem(_("Sync notes")) - filemenu.append(menu_items) - menu_items.connect("activate", self._on_sync_notes, None) - - menu_items = gtk.MenuItem(_("Quit")) - filemenu.append(menu_items) - menu_items.connect("activate", self._on_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._on_delete_category, None) - - menu_items = gtk.MenuItem(_("Move To Category")) - categorymenu.append(menu_items) - menu_items.connect("activate", self._on_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._on_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._on_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._on_toggle_word_wrap() - - try: - os.makedirs(self._user_data) - except OSError, e: - if e.errno != 17: - raise - self._window.show_all() - self._load_settings() - - def main(self): - gtk.main() - - def _save_settings(self): - config = ConfigParser.SafeConfigParser() - self.save_settings(config) - with open(self._user_settings, "wb") as configFile: - config.write(configFile) - - def save_settings(self, config): - config.add_section(constants.__pretty_app_name__) - config.set(constants.__pretty_app_name__, "wordwrap", str(self._wordWrapEnabled)) - config.set(constants.__pretty_app_name__, "zoom", str(self._isZoomEnabled)) - config.set(constants.__pretty_app_name__, "fullscreen", str(self._window_in_fullscreen)) - - def _load_settings(self): - config = ConfigParser.SafeConfigParser() - config.read(self._user_settings) - self.load_settings(config) - - def load_settings(self, config): - try: - self._wordWrapEnabled = config.getboolean(constants.__pretty_app_name__, "wordwrap") - self._isZoomEnabled = config.getboolean(constants.__pretty_app_name__, "zoom") - self._window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen") - except ConfigParser.NoSectionError, e: - warnings.warn( - "Settings file %s is missing section %s" % ( - self._user_settings, - e.section, - ), - stacklevel=2 - ) - - self._notizen.set_wordwrap(self._wordWrapEnabled) - - self.enable_zoom(self._isZoomEnabled) - - if self._window_in_fullscreen: - self._window.fullscreen() - else: - self._window.unfullscreen() - - 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.load_categories() - self._notizen.load_notes() - dlg.destroy() - - def _prepare_sync_dialog(self): - self._syncDialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) - - self._syncDialog.set_position(gtk.WIN_POS_CENTER) - sync = libsync.Sync(self._db, self._window, 50504) - self._syncDialog.vbox.pack_start(sync, True, True, 0) - self._syncDialog.set_size_request(500, 350) - self._syncDialog.vbox.show_all() - sync.connect("syncFinished", self._on_sync_finished) - - def enable_zoom(self, zoomEnabled): - self._isZoomEnabled = zoomEnabled - if zoomEnabled: - self._topBox.hide() - self._notizen.show_history_area(False) - else: - self._topBox.show() - self._notizen.show_history_area(True) - - 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: - self._save_settings() - - 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.enable_zoom(True) - elif event.keyval == gtk.keysyms.F8: - # Zoom Out - self.enable_zoom(False) - - def _on_view_sql_history(self, widget = None, data = None, data2 = None): - import libsqldialog - sqldiag = libsqldialog.SqlDialog(self._db) - res = sqldiag.run() - sqldiag.hide() - if res == sqldiag.EXPORT_RESPONSE: - _moduleLogger.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() - sqldiag.exportSQL(fileName) - dlg.destroy() - - sqldiag.destroy() - - def _on_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 -1 < n 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.category_combo_changed() - 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 _on_delete_category(self, widget = None, data = None): - if self._topBox.get_category() == "%" or self._topBox.get_category() == "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.get_category())) - sql = "DELETE FROM categories WHERE liste = ?" - self._db.speichereSQL(sql, (self._topBox.get_category(), )) - model = self._topBox.categoryCombo.get_model() - pos = self._topBox.categoryCombo.get_active() - if (pos>1): - self._topBox.categoryCombo.remove_text(pos) - self._topBox.categoryCombo.set_active(0) - - def _on_sync_finished(self, data = None, data2 = None): - self._topBox.load_categories() - self._notizen.load_notes() - - def _on_sync_notes(self, widget = None, data = None): - self._syncDialog.run() - self._syncDialog.hide() - - def _on_toggle_word_wrap(self, *args): - self._wordWrapEnabled = not self._wordWrapEnabled - self._notizen.set_wordwrap(self._wordWrapEnabled) - - def _on_delete_event(self, widget, event, data = None): - return False - - def _on_destroy(self, widget = None, data = None): - try: - self._save_settings() - self._db.close() - if self._osso_c: - self._osso_c.close() - finally: - gtk.main_quit() - - def _on_show_about(self, widget = None, data = None): - dialog = gtk.AboutDialog() - dialog.set_position(gtk.WIN_POS_CENTER) - dialog.set_name(constants.__pretty_app_name__) - dialog.set_version(constants.__version__) - dialog.set_copyright("") - dialog.set_website("http://axique.de/index.php?f=Quicknote") - comments = _("%s is a note taking program; it is optimised for quick save and search of notes") % constants.__pretty_app_name__ - dialog.set_comments(comments) - dialog.set_authors(["Christoph Wurstle ", "Ed Page (Blame him for the most recent bugs)"]) - dialog.run() - dialog.destroy() - - -if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG) - app = QuicknoteProgram() - app.main() diff --git a/src/libspeichern.py b/src/libspeichern.py deleted file mode 100644 index 44d1525..0000000 --- a/src/libspeichern.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/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 - - -_moduleLogger = logging.getLogger("speichern") - - -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 - _moduleLogger.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, " <> ".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): - _moduleLogger.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) - else: - _moduleLogger.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) - return False - - def commitSQL(self): - self.conn.commit() - - def ladeSQL(self, sql, tupel = None): - #print sql, tupel - try: - if tupel is None: - self.cur.execute(sql) - else: - self.cur.execute(sql, tupel) - return self.cur.fetchall() - except StandardError: - _moduleLogger.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) - return () - - def ladeHistory(self, sql_condition, param_condition): - sql = "SELECT * FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%'" - rows = self.ladeSQL(sql) - #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(" <> ")]) - - 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 - _moduleLogger.info("Alle Data saved") - - def __del__(self): - self.close() diff --git a/src/libsqldialog.py b/src/libsqldialog.py deleted file mode 100755 index a6cc2d6..0000000 --- a/src/libsqldialog.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/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 - - -_moduleLogger = logging.getLogger("sqldialog") - - -class SqlDialog(gtk.Dialog): - - EXPORT_RESPONSE = 444 - - def __init__(self, db): - self.db = db - - _moduleLogger.info("sqldialog, init") - - gtk.Dialog.__init__(self, _("SQL History (the past two days):"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - - self.add_button(_("Export"), self.EXPORT_RESPONSE) - self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) - 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) - self.treeview.set_rules_hint(True) - - # 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() diff --git a/src/libsync.py b/src/libsync.py deleted file mode 100755 index f8acdac..0000000 --- a/src/libsync.py +++ /dev/null @@ -1,368 +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 . -""" - - -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 - - -_moduleLogger = logging.getLogger("sync") - - -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, ()) - - _moduleLogger.info("ProgressDialog, init") - - label = gtk.Label(_("Sync process running...please wait")) - self.vbox.pack_start(label, True, True, 0) - label = gtk.Label(_("(this can take some minutes)")) - 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) - - _moduleLogger.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 - _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time()))) - return pcdatum - - def check4commit(self, newSQL, lastdate): - _moduleLogger.info("check4commit 1") - if self.concernedRows is None: - _moduleLogger.info("check4commit Updatung concernedRows") - sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC" - self.concernedRows = self.db.ladeSQL(sql, (lastdate, )) - - if self.concernedRows is not None and 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]: - _moduleLogger.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 - _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels") - for newSQL in newSQLs: - if newSQL[3] != "": - param = newSQL[3].split(" <> ") - 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: - _moduleLogger.error("writeSQLTupel: Error") - - pausenzaehler += 1 - if (pausenzaehler % 10) == 0: - self.pulse() - while gtk.events_pending(): - gtk.main_iteration() - - _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now") - self.db.commitSQL() - _moduleLogger.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 - - _moduleLogger.info("doSync read sqls") - sql = "SELECT * FROM logtable WHERE pcdatum>?" - rows = self.db.ladeSQL(sql, (pcdatum, )) - _moduleLogger.info("doSync read sqls") - self.writeSQLTupel(newSQLs, pcdatum) - _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls") - _moduleLogger.info("doSync sending "+str(len(rows))+" sqls") - return rows - - def getRemoteSyncUUID(self): - return self.sync_uuid - - def startServer(self, widget, data = None): - #Starte RPCServer - self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text()) - - if widget.get_active(): - _moduleLogger.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()) - _moduleLogger.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: - _moduleLogger.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): - _moduleLogger.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, )) - - _moduleLogger.info("loaded concerned rows") - - newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time()) - - _moduleLogger.info("did do sync, processing sqls now") - if newSQLs != -1: - self.writeSQLTupel(newSQLs, lastDate) - - sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid) - self.doSaveFinalTime(sync_uuid, finalpcdatum) - - self.changeSyncStatus(False, _("no sync process (at the moment)")) - - mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed")) - response = mbox.run() - mbox.hide() - mbox.destroy() - else: - _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler") - self.changeSyncStatus(False, _("no sync process (at the moment)")) - mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations")) - response = mbox.run() - mbox.hide() - mbox.destroy() - except StandardError: - _moduleLogger.warning("Sync connect failed") - self.changeSyncStatus(False, _("no sync process (at the moment)")) - mbox = gtk.MessageDialog( - None, - gtk.DIALOG_MODAL, - gtk.MESSAGE_INFO, - gtk.BUTTONS_OK, - _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]) - ) - response = mbox.run() - mbox.hide() - mbox.destroy() - self.server = None - self.server = None diff --git a/src/notizen.py b/src/notizen.py new file mode 100644 index 0000000..19bf8d1 --- /dev/null +++ b/src/notizen.py @@ -0,0 +1,270 @@ +#!/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 time +import logging +import uuid + +import gobject +import gtk +try: + import gtkspell +except ImportError: + gtkspell = None + +import simple_list + + +try: + _ +except NameError: + _ = lambda x: x + + +_moduleLogger = logging.getLogger("notizen") + + +class Notizen(gtk.HBox): + + def __init__(self, db, topBox): + self._db = db + self._topBox = topBox + self.noteId = -1 + self._pos = -1 + self._noteBody = None #Last notetext + self._categoryName = "" + + gtk.HBox.__init__(self, homogeneous = False, spacing = 0) + _moduleLogger.info("libnotizen, init") + + self._noteslist = simple_list.SimpleList() + self._noteslist.set_eventfunction_cursor_changed(self._update_noteslist) + + 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._on_add_note, None) + buttonHBox.pack_start(button, expand = True, fill = True, padding = 3) + + button = gtk.Button(stock = gtk.STOCK_DELETE) + button.connect("clicked", self._on_delete_note, None) + buttonHBox.pack_start(button, expand = True, fill = True, padding = 3) + + self.pack_start(vbox, expand = False, fill = True, padding = 3) + + self._noteBodyView = gtk.TextView() + self._noteBodyView.connect("focus-out-event", self.save_note, "focus-out-event") + buf = self._noteBodyView.get_buffer() + buf.set_text("") + buf.connect("changed", self._on_note_changed, None) + if gtkspell is not None: + self._noteBodySpellChecker = gtkspell.Spell(self._noteBodyView) + else: + self._noteBodySpellChecker = None + + #self.textviewNotiz.set_size_request(-1, 50) + self._noteScrollWindow = gtk.ScrolledWindow() + self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self._noteScrollWindow.add(self._noteBodyView) + + frame = gtk.Frame(_("Note")) + frame.add(self._noteScrollWindow) + + vbox = gtk.VBox(homogeneous = False, spacing = 0) + vbox.pack_start(frame, expand = True, fill = True, padding = 3) + + self._historyBox = gtk.HBox(homogeneous = False, spacing = 0) + + self._historyStatusLabel = gtk.Label(_("No History")) + self._historyStatusLabel.set_alignment(0.0, 0.5) + self._historyBox.pack_start(self._historyStatusLabel, expand = True, fill = True, padding = 3) + + button = gtk.Button(_("History")) + button.connect("clicked", self._on_show_history, None) + self._historyBox.pack_start(button, expand = True, fill = True, padding = 3) + + vbox.pack_start(self._historyBox, expand = False, fill = True, padding = 3) + + self.pack_start(vbox, expand = True, fill = True, padding = 3) + + self.load_notes() + self._topBox.connect("reload_notes", self.load_notes) + + def set_wordwrap(self, enableWordWrap): + if enableWordWrap: + self._noteScrollWindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self._noteBodyView.set_wrap_mode(gtk.WRAP_WORD) + else: + self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self._noteBodyView.set_wrap_mode(gtk.WRAP_NONE) + + def show_history_area(self, visible): + if visible: + self._historyBox.show() + else: + self._historyBox.hide() + + def load_notes(self, data = None): + _moduleLogger.info("load_notes params: pos:"+str(self._pos)+" noteid:"+str(self.noteId)) + self._noteslist.clear_items() + self._noteslist.append_item(_("New Note..."), "new") + + self._categoryName = self._topBox.get_category() + search = self._topBox.get_search_pattern() + notes = self._db.searchNotes(search, self._categoryName) + + if notes is not None: + for note in notes: + noteid, category, noteText = note + title = self._get_title(noteText) + self._noteslist.append_item(title, noteid) + + self.noteId = -1 + self._pos = -1 + self._noteBodyView.get_buffer().set_text("") + + def save_note(self, widget = None, data = None, data2 = None): + _moduleLogger.info("save_note params: pos:"+str(self._pos)+" noteid:"+str(self.noteId)) + #print "params:", data, data2 + buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter()) + if buf is None or len(buf) == 0: + return + + if buf == self._noteBody: + return + + _moduleLogger.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._categoryName) + self._noteslist.append_item(self._get_title(buf), self.noteId) + self._pos = self._noteslist.select_last_item() + else: + self._db.saveNote(self.noteId, buf, self._categoryName) + + self._topBox.define_this_category() + + def _get_title(self, buf): + """ + @returns the title of the current note + """ + eol = buf.find("\n") + if -1 == eol: + eol = len(buf) + title = buf[:eol] + return title + + def _set_focus(self): + self._noteBodyView.grab_focus() + return False + + def _update_noteslist(self, data = None, data2 = None): + if self._pos != -1: + self.save_note() + + 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._categoryName) + self._pos = -1 + self._noteslist.append_item("", self.noteId) + self._noteBodyView.get_buffer().set_text("") + self._pos = self._noteslist.select_last_item() + else: + self._pos = pos + self.noteId, pcdatum, self._categoryName, self._noteBody = self._db.loadNote(key) + self._historyStatusLabel.set_text(time.strftime(_("Last change: %d.%m.%y %H:%M"), time.localtime(pcdatum))) + buf = self._noteBodyView.get_buffer() + buf.set_text(self._noteBody) + + gobject.timeout_add(200, self._set_focus) + + def _on_note_changed(self, widget = None, data = None): + if self._pos == -1 or self.noteId == -1: + return + + buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter()) + + title = self._get_title(buf) + value, key = self._noteslist.get_item(self._pos) + + if value != title: + self._noteslist.change_item(self._pos, title, self.noteId) + + def _on_add_note(self, widget = None, data = None): + self._update_noteslist("new") + + def _on_delete_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._noteBodyView.get_buffer().set_text("") + + def _on_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 history + dialog = history.Dialog() + + lastNoteStr = "" + for row in rows: + daten = row[4][1] + if daten != "" and lastNoteStr != daten: + lastNoteStr = daten + dialog.noteHistory.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.save_note() + data = dialog.get_selected_row() + if data is not None: + self._db.speichereSQL(data[2], data[3].split(" <> "), rowid = self.noteId) + _moduleLogger.info("loading History") + self._update_noteslist() + + dialog.destroy() diff --git a/src/quicknote.py b/src/quicknote.py index 9410944..10b6149 100755 --- a/src/quicknote.py +++ b/src/quicknote.py @@ -19,7 +19,7 @@ sys.path.append('/usr/lib/quicknote') import constants -import libquicknote +import quicknote_gtk if __name__ == "__main__": @@ -33,5 +33,5 @@ if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG, filename=userLogPath) _moduleLogger.info("quicknote %s-%s" % (constants.__version__, constants.__build__)) - app = libquicknote.QuicknoteProgram() + app = quicknote_gtk.QuicknoteProgram() app.main() diff --git a/src/quicknote_gtk.py b/src/quicknote_gtk.py new file mode 100644 index 0000000..c89f704 --- /dev/null +++ b/src/quicknote_gtk.py @@ -0,0 +1,420 @@ +#!/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. + +@todo Add Note Export (txt File) and Export All (json dump?) +@todo Remove confirmation on deleting empty notes +@todo Try to switch to more passive notifications (rather than message boxes) +""" + +from __future__ import with_statement + +import os +import gc +import logging +import warnings +import ConfigParser + +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 constants + +import speichern +import kopfzeile +import notizen +import sync + + +try: + _ +except NameError: + _ = lambda x: x + + +_moduleLogger = logging.getLogger("quick") + + +class QuicknoteProgram(hildon.Program): + + _user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__) + _user_settings = "%s/settings.ini" % _user_data + + def __init__(self): + super(QuicknoteProgram, self).__init__() + if IS_HILDON: + gtk.set_application_name(constants.__pretty_app_name__) + + dblog = os.path.join(self._user_data, "quicknote.log") + + _moduleLogger.info('Starting quicknote') + + if osso is not None: + self._osso_c = osso.Context(constants.__app_name__, constants.__version__, False) + self._deviceState = osso.DeviceState(self._osso_c) + self._deviceState.set_device_state_callback(self._on_device_state_change, 0) + else: + self._osso_c = None + self._deviceState = None + + #Get the Main Window, and connect the "destroy" event + self._window = hildon.Window() + self.add_window(self._window) + + if not IS_HILDON: + self._window.set_title(constants.__pretty_app_name__) + self._window.connect("delete_event", self._on_delete_event) + self._window.connect("destroy", self._on_destroy) + self._window.connect("key-press-event", self._on_key_press) + self._window.connect("window-state-event", self._on_window_state_change) + self._window_in_fullscreen = False #The window isn't in full screen mode initially. + self._isZoomEnabled = False + + self._db = speichern.Speichern() + self._syncDialog = None + 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._on_view_sql_history, None) + + menu_items = gtk.MenuItem(_("Sync notes")) + filemenu.append(menu_items) + menu_items.connect("activate", self._on_sync_notes, None) + + menu_items = gtk.MenuItem(_("Quit")) + filemenu.append(menu_items) + menu_items.connect("activate", self._on_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._on_delete_category, None) + + menu_items = gtk.MenuItem(_("Move To Category")) + categorymenu.append(menu_items) + menu_items.connect("activate", self._on_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._on_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._on_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 = kopfzeile.Kopfzeile(self._db) + vbox.pack_start(self._topBox, False, False, 0) + + self._notizen = notizen.Notizen(self._db, self._topBox) + vbox.pack_start(self._notizen, True, True, 0) + self._window.add(vbox) + + self._on_toggle_word_wrap() + + try: + os.makedirs(self._user_data) + except OSError, e: + if e.errno != 17: + raise + self._window.show_all() + self._load_settings() + + def main(self): + gtk.main() + + def _save_settings(self): + config = ConfigParser.SafeConfigParser() + self.save_settings(config) + with open(self._user_settings, "wb") as configFile: + config.write(configFile) + + def save_settings(self, config): + config.add_section(constants.__pretty_app_name__) + config.set(constants.__pretty_app_name__, "wordwrap", str(self._wordWrapEnabled)) + config.set(constants.__pretty_app_name__, "zoom", str(self._isZoomEnabled)) + config.set(constants.__pretty_app_name__, "fullscreen", str(self._window_in_fullscreen)) + + def _load_settings(self): + config = ConfigParser.SafeConfigParser() + config.read(self._user_settings) + self.load_settings(config) + + def load_settings(self, config): + try: + self._wordWrapEnabled = config.getboolean(constants.__pretty_app_name__, "wordwrap") + self._isZoomEnabled = config.getboolean(constants.__pretty_app_name__, "zoom") + self._window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen") + except ConfigParser.NoSectionError, e: + warnings.warn( + "Settings file %s is missing section %s" % ( + self._user_settings, + e.section, + ), + stacklevel=2 + ) + + self._notizen.set_wordwrap(self._wordWrapEnabled) + + self.enable_zoom(self._isZoomEnabled) + + if self._window_in_fullscreen: + self._window.fullscreen() + else: + self._window.unfullscreen() + + 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.load_categories() + self._notizen.load_notes() + dlg.destroy() + + def _prepare_sync_dialog(self): + self._syncDialog = gtk.Dialog(_("Sync"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + + self._syncDialog.set_position(gtk.WIN_POS_CENTER) + syncer = sync.Sync(self._db, self._window, 50504) + self._syncDialog.vbox.pack_start(syncer, True, True, 0) + self._syncDialog.set_size_request(500, 350) + self._syncDialog.vbox.show_all() + syncer.connect("syncFinished", self._on_sync_finished) + + def enable_zoom(self, zoomEnabled): + self._isZoomEnabled = zoomEnabled + if zoomEnabled: + self._topBox.hide() + self._notizen.show_history_area(False) + else: + self._topBox.show() + self._notizen.show_history_area(True) + + 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: + self._save_settings() + + 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.enable_zoom(True) + elif event.keyval == gtk.keysyms.F8: + # Zoom Out + self.enable_zoom(False) + + def _on_view_sql_history(self, widget = None, data = None, data2 = None): + import sqldialog + sqldiag = sqldialog.SqlDialog(self._db) + res = sqldiag.run() + sqldiag.hide() + if res == sqldiag.EXPORT_RESPONSE: + _moduleLogger.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() + sqldiag.exportSQL(fileName) + dlg.destroy() + + sqldiag.destroy() + + def _on_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 -1 < n 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.category_combo_changed() + 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 _on_delete_category(self, widget = None, data = None): + if self._topBox.get_category() == "%" or self._topBox.get_category() == "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.get_category())) + sql = "DELETE FROM categories WHERE liste = ?" + self._db.speichereSQL(sql, (self._topBox.get_category(), )) + model = self._topBox.categoryCombo.get_model() + pos = self._topBox.categoryCombo.get_active() + if (pos>1): + self._topBox.categoryCombo.remove_text(pos) + self._topBox.categoryCombo.set_active(0) + + def _on_sync_finished(self, data = None, data2 = None): + self._topBox.load_categories() + self._notizen.load_notes() + + def _on_sync_notes(self, widget = None, data = None): + self._syncDialog.run() + self._syncDialog.hide() + + def _on_toggle_word_wrap(self, *args): + self._wordWrapEnabled = not self._wordWrapEnabled + self._notizen.set_wordwrap(self._wordWrapEnabled) + + def _on_delete_event(self, widget, event, data = None): + return False + + def _on_destroy(self, widget = None, data = None): + try: + self._save_settings() + self._db.close() + if self._osso_c: + self._osso_c.close() + finally: + gtk.main_quit() + + def _on_show_about(self, widget = None, data = None): + dialog = gtk.AboutDialog() + dialog.set_position(gtk.WIN_POS_CENTER) + dialog.set_name(constants.__pretty_app_name__) + dialog.set_version(constants.__version__) + dialog.set_copyright("") + dialog.set_website("http://axique.de/index.php?f=Quicknote") + comments = _("%s is a note taking program; it is optimised for quick save and search of notes") % constants.__pretty_app_name__ + dialog.set_comments(comments) + dialog.set_authors(["Christoph Wurstle ", "Ed Page (Blame him for the most recent bugs)"]) + dialog.run() + dialog.destroy() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + app = QuicknoteProgram() + app.main() diff --git a/src/speichern.py b/src/speichern.py new file mode 100644 index 0000000..c66e811 --- /dev/null +++ b/src/speichern.py @@ -0,0 +1,208 @@ +#!/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 + + +_moduleLogger = logging.getLogger("speichern") + + +class Speichern(object): + + 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 + _moduleLogger.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, " <> ".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): + _moduleLogger.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) + else: + _moduleLogger.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) + return False + + def commitSQL(self): + self.conn.commit() + + def ladeSQL(self, sql, tupel = None): + #print sql, tupel + try: + if tupel is None: + self.cur.execute(sql) + else: + self.cur.execute(sql, tupel) + return self.cur.fetchall() + except StandardError: + _moduleLogger.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel)) + return () + + def ladeHistory(self, sql_condition, param_condition): + sql = "SELECT * FROM logtable WHERE sql LIKE '%"+str(sql_condition)+"%' AND param LIKE '%"+str(param_condition)+"%'" + rows = self.ladeSQL(sql) + #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(" <> ")]) + + 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 + _moduleLogger.info("Alle Data saved") + + def __del__(self): + self.close() diff --git a/src/sqldialog.py b/src/sqldialog.py new file mode 100755 index 0000000..a6cc2d6 --- /dev/null +++ b/src/sqldialog.py @@ -0,0 +1,105 @@ +#!/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 + + +_moduleLogger = logging.getLogger("sqldialog") + + +class SqlDialog(gtk.Dialog): + + EXPORT_RESPONSE = 444 + + def __init__(self, db): + self.db = db + + _moduleLogger.info("sqldialog, init") + + gtk.Dialog.__init__(self, _("SQL History (the past two days):"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + + self.add_button(_("Export"), self.EXPORT_RESPONSE) + self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) + 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) + self.treeview.set_rules_hint(True) + + # 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() diff --git a/src/sync.py b/src/sync.py new file mode 100755 index 0000000..f8acdac --- /dev/null +++ b/src/sync.py @@ -0,0 +1,368 @@ +#!/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 . +""" + + +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 + + +_moduleLogger = logging.getLogger("sync") + + +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, ()) + + _moduleLogger.info("ProgressDialog, init") + + label = gtk.Label(_("Sync process running...please wait")) + self.vbox.pack_start(label, True, True, 0) + label = gtk.Label(_("(this can take some minutes)")) + 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) + + _moduleLogger.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 + _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time()))) + return pcdatum + + def check4commit(self, newSQL, lastdate): + _moduleLogger.info("check4commit 1") + if self.concernedRows is None: + _moduleLogger.info("check4commit Updatung concernedRows") + sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC" + self.concernedRows = self.db.ladeSQL(sql, (lastdate, )) + + if self.concernedRows is not None and 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]: + _moduleLogger.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 + _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels") + for newSQL in newSQLs: + if newSQL[3] != "": + param = newSQL[3].split(" <> ") + 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: + _moduleLogger.error("writeSQLTupel: Error") + + pausenzaehler += 1 + if (pausenzaehler % 10) == 0: + self.pulse() + while gtk.events_pending(): + gtk.main_iteration() + + _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now") + self.db.commitSQL() + _moduleLogger.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 + + _moduleLogger.info("doSync read sqls") + sql = "SELECT * FROM logtable WHERE pcdatum>?" + rows = self.db.ladeSQL(sql, (pcdatum, )) + _moduleLogger.info("doSync read sqls") + self.writeSQLTupel(newSQLs, pcdatum) + _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls") + _moduleLogger.info("doSync sending "+str(len(rows))+" sqls") + return rows + + def getRemoteSyncUUID(self): + return self.sync_uuid + + def startServer(self, widget, data = None): + #Starte RPCServer + self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text()) + + if widget.get_active(): + _moduleLogger.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()) + _moduleLogger.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: + _moduleLogger.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): + _moduleLogger.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, )) + + _moduleLogger.info("loaded concerned rows") + + newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time()) + + _moduleLogger.info("did do sync, processing sqls now") + if newSQLs != -1: + self.writeSQLTupel(newSQLs, lastDate) + + sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid) + self.doSaveFinalTime(sync_uuid, finalpcdatum) + + self.changeSyncStatus(False, _("no sync process (at the moment)")) + + mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed")) + response = mbox.run() + mbox.hide() + mbox.destroy() + else: + _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler") + self.changeSyncStatus(False, _("no sync process (at the moment)")) + mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations")) + response = mbox.run() + mbox.hide() + mbox.destroy() + except StandardError: + _moduleLogger.warning("Sync connect failed") + self.changeSyncStatus(False, _("no sync process (at the moment)")) + mbox = gtk.MessageDialog( + None, + gtk.DIALOG_MODAL, + gtk.MESSAGE_INFO, + gtk.BUTTONS_OK, + _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]) + ) + response = mbox.run() + mbox.hide() + mbox.destroy() + self.server = None + self.server = None -- 1.7.9.5