2a9ccff001e1ef714f79146b3d36a785b5346556
[quicknote] / src / notizen.py
1 #!/usr/bin/env python2.5
2 # -*- coding: utf-8 -*-
3
4 """
5  Copyright (C) 2007 Christoph Würstle
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
10
11 @todo It would be nice to move the category selector to the category list's column and search below everything.
12 @todo Search would be activated by menu or CTRL+F rather than zoom
13 """
14
15 import time
16 import logging
17 import uuid
18
19 import gobject
20 import gtk
21 try:
22         import gtkspell
23 except ImportError:
24         gtkspell = None
25
26 import hildonize
27 import gtk_toolbox
28 import simple_list
29
30
31 try:
32         _
33 except NameError:
34         _ = lambda x: x
35
36
37 _moduleLogger = logging.getLogger("notizen")
38
39
40 class Notizen(gtk.HBox):
41
42         def __init__(self, db, topBox):
43                 self._db = db
44                 self._topBox = topBox
45                 self.noteId = -1
46                 self._pos = -1
47                 self._noteBody = None #Last notetext
48                 self._categoryName = ""
49
50                 gtk.HBox.__init__(self, homogeneous = False, spacing = 0)
51                 _moduleLogger.info("libnotizen, init")
52
53                 # Note list
54                 self._noteslist = simple_list.SimpleList()
55                 self._noteslist.set_eventfunction_cursor_changed(self._update_noteslist)
56                 self._noteslist.widget.set_size_request(250, -1)
57
58                 buttonHBox = gtk.HBox()
59
60                 button = gtk.Button(stock = gtk.STOCK_ADD)
61                 button.connect("clicked", self._on_add_note, None)
62                 buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
63
64                 button = gtk.Button(stock = gtk.STOCK_DELETE)
65                 button.connect("clicked", self._on_delete_note, None)
66                 buttonHBox.pack_start(button, expand = True, fill = True, padding = 3)
67
68                 listVbox = gtk.VBox(homogeneous = False, spacing = 0)
69                 listVbox.pack_start(self._noteslist.widget, expand = True, fill = True, padding = 3)
70                 listVbox.pack_start(buttonHBox, expand = False, fill = True, padding = 3)
71                 self.pack_start(listVbox, expand = False, fill = True, padding = 3)
72
73                 # Note view
74                 self._noteBodyView = gtk.TextView()
75                 self._noteBodyView.connect("focus-out-event", self.save_note, "focus-out-event")
76                 buf = self._noteBodyView.get_buffer()
77                 buf.set_text("")
78                 buf.connect("changed", self._on_note_changed, None)
79                 if gtkspell is not None:
80                         self._noteBodySpellChecker = gtkspell.Spell(self._noteBodyView)
81                 else:
82                         self._noteBodySpellChecker = None
83
84                 self._noteScrollWindow = gtk.ScrolledWindow()
85                 self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
86                 self._noteScrollWindow.add(self._noteBodyView)
87                 hildonize.hildonize_scrollwindow_with_viewport(self._noteScrollWindow)
88
89                 # History
90                 self._historyBox = gtk.HBox(homogeneous = False, spacing = 0)
91
92                 self._historyStatusLabel = gtk.Label(_("No History"))
93                 self._historyStatusLabel.set_alignment(0.0, 0.5)
94                 self._historyBox.pack_start(self._historyStatusLabel, expand = True, fill = True, padding = 3)
95
96                 button = gtk.Button(_("History"))
97                 button.connect("clicked", self._on_show_history, None)
98                 self._historyBox.pack_start(button, expand = True, fill = True, padding = 3)
99
100                 # Note and history stuff in same column
101                 noteVbox = gtk.VBox(homogeneous = False, spacing = 0)
102                 noteVbox.pack_start(self._noteScrollWindow, expand = True, fill = True, padding = 3)
103                 noteVbox.pack_start(self._historyBox, expand = False, fill = True, padding = 3)
104                 self.pack_start(noteVbox, expand = True, fill = True, padding = 3)
105
106                 self.load_notes()
107                 self._topBox.connect("reload_notes", self.load_notes)
108
109         def set_wordwrap(self, enableWordWrap):
110                 if enableWordWrap:
111                         self._noteScrollWindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
112                         self._noteBodyView.set_wrap_mode(gtk.WRAP_WORD)
113                 else:
114                         self._noteScrollWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
115                         self._noteBodyView.set_wrap_mode(gtk.WRAP_NONE)
116
117         def show_history_area(self, visible):
118                 if visible:
119                         self._historyBox.show()
120                 else:
121                         self._historyBox.hide()
122
123         def load_notes(self, data = None):
124                 _moduleLogger.info("load_notes params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
125                 self._noteslist.clear_items()
126
127                 self._categoryName = self._topBox.get_category()
128                 search = self._topBox.get_search_pattern()
129                 notes = self._db.searchNotes(search, self._categoryName)
130
131                 if notes is not None:
132                         for note in notes:
133                                 noteid, category, noteText = note
134                                 title = self._get_title(noteText)
135                                 self._noteslist.append_item(title, noteid)
136
137                 self.noteId = -1
138                 self._pos = -1
139                 self._noteBodyView.get_buffer().set_text("")
140
141         def save_note(self, widget = None, data = None, data2 = None):
142                 _moduleLogger.info("save_note params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
143                 #print "params:", data, data2
144                 buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter())
145                 if buf is None or len(buf) == 0:
146                         return
147
148                 if buf == self._noteBody:
149                         return
150
151                 title = self._get_title(buf)
152                 _moduleLogger.info("Saving note: " + title)
153                 if self._pos == -1 or self.noteId == -1:
154                         self._pos = -1
155                         self.noteId = str(uuid.uuid4())
156                         self._db.saveNote(self.noteId, buf, self._categoryName)
157                         self._noteslist.append_item(title, self.noteId)
158                         self._pos = self._noteslist.select_last_item()
159                 else:
160                         self._db.saveNote(self.noteId, buf, self._categoryName)
161
162                 self._topBox.define_this_category()
163
164         def _get_title(self, buf):
165                 """
166                 @returns the title of the current note
167                 """
168                 eol = buf.find("\n")
169                 if -1 == eol:
170                         eol = len(buf)
171                 title = buf[:eol]
172                 return title
173
174         def _set_focus(self):
175                 self._noteBodyView.grab_focus()
176                 return False
177
178         def _update_noteslist(self, *args):
179                 if self._pos != -1:
180                         self.save_note()
181
182                 if args:
183                         data = args[0]
184                 else:
185                         data = None
186
187                 try:
188                         (pos, key, value) = self._noteslist.get_selection_data()
189                         if pos == -1:
190                                 return
191                 except StandardError:
192                         if data != "new":
193                                 return
194                         key = None
195
196                 if key == "new" or data == "new":
197                         #both methods supported click add note or new note (first one disabled)
198                         self.noteId = str(uuid.uuid4())
199                         self._db.saveNote(self.noteId, "", self._categoryName)
200                         self._pos = -1
201                         self._noteslist.append_item("", self.noteId)
202                         self._noteBodyView.get_buffer().set_text("")
203                         self._pos = self._noteslist.select_last_item()
204                 else:
205                         self._pos = pos
206                         self.noteId, pcdatum, self._categoryName, self._noteBody = self._db.loadNote(key)
207                         self._historyStatusLabel.set_text(time.strftime(_("Last change: %d.%m.%y %H:%M"), time.localtime(pcdatum)))
208                         buf = self._noteBodyView.get_buffer()
209                         buf.set_text(self._noteBody)
210
211                 gobject.timeout_add(200, self._set_focus)
212
213         @gtk_toolbox.log_exception(_moduleLogger)
214         def _on_note_changed(self, widget = None, data = None):
215                 if self._pos == -1 or self.noteId == -1:
216                         return
217
218                 buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter())
219
220                 title = self._get_title(buf)
221                 value, key = self._noteslist.get_item(self._pos)
222
223                 if value != title:
224                         self._noteslist.change_item(self._pos, title, self.noteId)
225
226         @gtk_toolbox.log_exception(_moduleLogger)
227         def _on_add_note(self, widget = None, data = None):
228                 self._update_noteslist("new")
229
230         @gtk_toolbox.log_exception(_moduleLogger)
231         def _on_delete_note(self, widget = None, data = None):
232                 if (self.noteId == -1):
233                         return
234                 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, _("Really delete?"))
235                 response = mbox.run()
236                 mbox.hide()
237                 mbox.destroy()
238                 if response == gtk.RESPONSE_YES:
239                         self._db.delNote(self.noteId)
240                         self.noteId = -1
241                         self._noteslist.remove_item(self._pos)
242                         self._pos = -1
243                         self._noteBodyView.get_buffer().set_text("")
244
245         @gtk_toolbox.log_exception(_moduleLogger)
246         def _on_show_history(self, widget = None, data = None, label = None):
247                 if self.noteId == -1:
248                         mbox =  gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("No note selected."))
249                         response = mbox.run()
250                         mbox.hide()
251                         mbox.destroy()
252                         return
253
254                 rows = self._db.getNoteHistory(self.noteId)
255
256                 import history
257                 dialog = history.Dialog()
258
259                 lastNoteStr = ""
260                 for row in rows:
261                         daten = row[4][1]
262                         if daten != "" and lastNoteStr != daten:
263                                 lastNoteStr = daten
264                                 dialog.noteHistory.append([row[0], row[1], row[2], row[3], daten+"\n"])
265
266                 dialog.vbox.show_all()
267                 dialog.set_size_request(600, 380)
268
269                 if dialog.run() == gtk.RESPONSE_ACCEPT:
270                         print "saving"
271                         self.save_note()
272                         data = dialog.get_selected_row()
273                         if data is not None:
274                                 self._db.speichereSQL(data[2], data[3].split(" <<Tren-ner>> "), rowid = self.noteId)
275                                 _moduleLogger.info("loading History")
276                                 self._update_noteslist()
277
278                 dialog.destroy()