--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import logging
+
+import 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)
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import logging
+
+import gobject
+import gtk
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+_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()
+++ /dev/null
-#!/usr/bin/env python2.5
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-"""
-
-
-import logging
-
-import 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)
+++ /dev/null
-#!/usr/bin/env python2.5
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-"""
-
-
-import logging
-
-import gobject
-import gtk
-
-
-try:
- _
-except NameError:
- _ = lambda x: x
-
-
-_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()
+++ /dev/null
-#!/usr/bin/env python2.5
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-"""
-
-import 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(" <<Tren-ner>> "), rowid = self.noteId)
- _moduleLogger.info("loading History")
- self._update_noteslist()
-
- dialog.destroy()
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-@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 <n800@axique.net>", "Ed Page <edpage@byu.net> (Blame him for the most recent bugs)"])
- dialog.run()
- dialog.destroy()
-
-
-if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
- app = QuicknoteProgram()
- app.main()
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-"""
-
-
-import sys
-import os
-import time
-import sqlite3
-import shelve
-import logging
-
-
-try:
- _
-except NameError:
- _ = lambda x: x
-
-
-_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, " <<Tren-ner>> ".join(strtupel), host, str(rowid) ))
- if commit:
- self.conn.commit()
-
- return True
- except StandardError:
- s = str(sys.exc_info())
- if s.find(" already exists") == -1:
- if (programSQLError == True):
- _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(" <<Tren-ner>> ")])
-
- return erg
-
- def openDB(self):
- try:
- self.cur.close()
- except StandardError:
- pass
- try:
- self.conn.close()
- except StandardError:
- pass
-
- db = self.ladeDirekt("datenbank")
- if db == "":
- home_dir = os.path.expanduser('~')
-
- #on hildon user not home-dir but /home/user/MyDocs
- if home_dir == "/home/user":
- if os.path.exists(home_dir+os.sep+"MyDocs/"):
- home_dir = home_dir+os.sep+"MyDocs/"
- db = os.path.join(home_dir, "quicknote.s3db")
-
- self.conn = sqlite3.connect(db)
- self.cur = self.conn.cursor()
- try:
- sql = "CREATE TABLE logtable (id INTEGER PRIMARY KEY AUTOINCREMENT, pcdatum INTEGER , sql TEXT, param TEXT, host TEXT, rowid TEXT)"
- self.cur.execute(sql)
- self.conn.commit()
- except StandardError:
- pass
-
- #Add rowid line (not in old versions included)
- try:
- sql = "ALTER TABLE logtable ADD rowid TEXT"
- self.cur.execute(sql)
- self.conn.commit()
- except StandardError:
- pass
-
- #Create notes table
- try:
- sql = "CREATE TABLE notes (noteid TEXT, pcdatum INTEGER , category TEXT, note TEXT)"
- self.cur.execute(sql)
- self.conn.commit()
- except StandardError:
- pass
-
- def saveNote(self, noteid, note, category, pcdatum = None):
- if category == "%":
- category = ""
- sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
- rows = self.ladeSQL(sql, (noteid, ))
-
- if rows is None or len(rows) == 0:
- sql = "INSERT INTO notes (noteid, pcdatum, category, note) VALUES (?, ?, ?, ?)"
- if pcdatum is None:
- pcdatum = int(time.time())
- self.speichereSQL(sql, (noteid, pcdatum, category, note), rowid = noteid)
- else:
- sql = "UPDATE notes SET category = ?, note = ?, pcdatum = ? WHERE noteid = ?"
- self.speichereSQL(sql, (category, note, str(int(time.time())), noteid), rowid = noteid)
-
- def loadNote(self, noteid):
- if noteid is None or str(noteid) == "":
- return (None, None, None)
- sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
- rows = self.ladeSQL(sql, (noteid, ))
- if rows is None or len(rows) == 0:
- return None
- else:
- noteid, pcdatum, category, note = rows[0]
- return (noteid, pcdatum, category, note)
-
- def delNote(self, noteid):
- sql = "DELETE FROM notes WHERE noteid = ?"
- self.speichereSQL(sql, (noteid, ), rowid = noteid)
-
- def searchNotes(self, searchstring, category):
- sql = "SELECT noteid, category, note FROM notes WHERE note like ? AND category like ? ORDER BY note"
- rows = self.ladeSQL(sql, ("%"+searchstring+"%", category))
- if rows is None or len(rows) == 0:
- return None
- else:
- return rows
-
- def getNoteHistory(self, noteid):
- return self.ladeHistory("UPDATE notes ", noteid)
-
- def close(self):
- try:
- self.d.close()
- except StandardError:
- pass
- try:
- self.cur.close()
- except StandardError:
- pass
- try:
- self.conn.close()
- except StandardError:
- pass
- _moduleLogger.info("Alle Data saved")
-
- def __del__(self):
- self.close()
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
- Copyright (C) 2007 Christoph Würstle
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-"""
-
-
-import time
-import logging
-
-import gtk
-
-
-try:
- _
-except NameError:
- _ = lambda x: x
-
-
-_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()
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-
-import sys
-import time
-import SimpleXMLRPCServer
-import xmlrpclib
-import select
-#import fcntl
-import uuid
-import logging
-import socket
-socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
-
-import gtk
-import gobject
-
-
-try:
- _
-except NameError:
- _ = lambda x: x
-
-
-_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(" <<Tren-ner>> ")
- else:
- param = None
-
- if 2 < len(newSQL):
- commitSQL = True
-
- if (newSQL[5]!= None)and(len(newSQL[5])>0):
- commitSQL = self.check4commit(newSQL, lastdate)
-
- if (commitSQL == True):
- self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
- else:
- _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
--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+import 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(" <<Tren-ner>> "), rowid = self.noteId)
+ _moduleLogger.info("loading History")
+ self._update_noteslist()
+
+ dialog.destroy()
import constants
-import libquicknote
+import quicknote_gtk
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()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+@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 <n800@axique.net>", "Ed Page <edpage@byu.net> (Blame him for the most recent bugs)"])
+ dialog.run()
+ dialog.destroy()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+ app = QuicknoteProgram()
+ app.main()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import sys
+import os
+import time
+import sqlite3
+import shelve
+import logging
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+_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, " <<Tren-ner>> ".join(strtupel), host, str(rowid) ))
+ if commit:
+ self.conn.commit()
+
+ return True
+ except StandardError:
+ s = str(sys.exc_info())
+ if s.find(" already exists") == -1:
+ if (programSQLError == True):
+ _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(" <<Tren-ner>> ")])
+
+ return erg
+
+ def openDB(self):
+ try:
+ self.cur.close()
+ except StandardError:
+ pass
+ try:
+ self.conn.close()
+ except StandardError:
+ pass
+
+ db = self.ladeDirekt("datenbank")
+ if db == "":
+ home_dir = os.path.expanduser('~')
+
+ #on hildon user not home-dir but /home/user/MyDocs
+ if home_dir == "/home/user":
+ if os.path.exists(home_dir+os.sep+"MyDocs/"):
+ home_dir = home_dir+os.sep+"MyDocs/"
+ db = os.path.join(home_dir, "quicknote.s3db")
+
+ self.conn = sqlite3.connect(db)
+ self.cur = self.conn.cursor()
+ try:
+ sql = "CREATE TABLE logtable (id INTEGER PRIMARY KEY AUTOINCREMENT, pcdatum INTEGER , sql TEXT, param TEXT, host TEXT, rowid TEXT)"
+ self.cur.execute(sql)
+ self.conn.commit()
+ except StandardError:
+ pass
+
+ #Add rowid line (not in old versions included)
+ try:
+ sql = "ALTER TABLE logtable ADD rowid TEXT"
+ self.cur.execute(sql)
+ self.conn.commit()
+ except StandardError:
+ pass
+
+ #Create notes table
+ try:
+ sql = "CREATE TABLE notes (noteid TEXT, pcdatum INTEGER , category TEXT, note TEXT)"
+ self.cur.execute(sql)
+ self.conn.commit()
+ except StandardError:
+ pass
+
+ def saveNote(self, noteid, note, category, pcdatum = None):
+ if category == "%":
+ category = ""
+ sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
+ rows = self.ladeSQL(sql, (noteid, ))
+
+ if rows is None or len(rows) == 0:
+ sql = "INSERT INTO notes (noteid, pcdatum, category, note) VALUES (?, ?, ?, ?)"
+ if pcdatum is None:
+ pcdatum = int(time.time())
+ self.speichereSQL(sql, (noteid, pcdatum, category, note), rowid = noteid)
+ else:
+ sql = "UPDATE notes SET category = ?, note = ?, pcdatum = ? WHERE noteid = ?"
+ self.speichereSQL(sql, (category, note, str(int(time.time())), noteid), rowid = noteid)
+
+ def loadNote(self, noteid):
+ if noteid is None or str(noteid) == "":
+ return (None, None, None)
+ sql = "SELECT noteid, pcdatum, category, note FROM notes WHERE noteid = ?"
+ rows = self.ladeSQL(sql, (noteid, ))
+ if rows is None or len(rows) == 0:
+ return None
+ else:
+ noteid, pcdatum, category, note = rows[0]
+ return (noteid, pcdatum, category, note)
+
+ def delNote(self, noteid):
+ sql = "DELETE FROM notes WHERE noteid = ?"
+ self.speichereSQL(sql, (noteid, ), rowid = noteid)
+
+ def searchNotes(self, searchstring, category):
+ sql = "SELECT noteid, category, note FROM notes WHERE note like ? AND category like ? ORDER BY note"
+ rows = self.ladeSQL(sql, ("%"+searchstring+"%", category))
+ if rows is None or len(rows) == 0:
+ return None
+ else:
+ return rows
+
+ def getNoteHistory(self, noteid):
+ return self.ladeHistory("UPDATE notes ", noteid)
+
+ def close(self):
+ try:
+ self.d.close()
+ except StandardError:
+ pass
+ try:
+ self.cur.close()
+ except StandardError:
+ pass
+ try:
+ self.conn.close()
+ except StandardError:
+ pass
+ _moduleLogger.info("Alle Data saved")
+
+ def __del__(self):
+ self.close()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+ Copyright (C) 2007 Christoph Würstle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+"""
+
+
+import time
+import logging
+
+import gtk
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+_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()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+
+import sys
+import time
+import SimpleXMLRPCServer
+import xmlrpclib
+import select
+#import fcntl
+import uuid
+import logging
+import socket
+socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
+
+import gtk
+import gobject
+
+
+try:
+ _
+except NameError:
+ _ = lambda x: x
+
+
+_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(" <<Tren-ner>> ")
+ else:
+ param = None
+
+ if 2 < len(newSQL):
+ commitSQL = True
+
+ if (newSQL[5]!= None)and(len(newSQL[5])>0):
+ commitSQL = self.check4commit(newSQL, lastdate)
+
+ if (commitSQL == True):
+ self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
+ else:
+ _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