Merge lp:~midori/midori/notes-extension into lp:midori
- notes-extension
- Merge into trunk
Proposed by
Paweł Forysiuk
Status: | Merged |
---|---|
Approved by: | Cris Dywan |
Approved revision: | 6539 |
Merged at revision: | 6548 |
Proposed branch: | lp:~midori/midori/notes-extension |
Merge into: | lp:midori |
Diff against target: |
520 lines (+479/-1) 5 files modified
data/notes/Create.sql (+8/-0) extensions/notes.vala (+467/-0) midori/midori-database.vala (+2/-1) midori/midori.vapi (+1/-0) po/POTFILES.in (+1/-0) |
To merge this branch: | bzr merge lp:~midori/midori/notes-extension |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
Review via email: mp+196160@code.launchpad.net |
Commit message
Implement notes extension
Description of the change
This is a work in progress. Could use some refactoring too.
"Works":
- adding selected text to notes from websites (not in frames - unrelated bug)
- removing note
- renaming note
- adding non-webpage specific note from sidepanel
- adding/changing note content
- show note on 1 click
- go to page on double click
- sorting by title
FIXME:
- resizing/
- no feedback when saving note
Wishlist/TODO:
- copy note content to pastebin?
- Support importing/editing xfce notes?
- Support importing opera notes?
- notes should have tags?
- some kind of searching?
To post a comment you must log in.
Revision history for this message
RabbitBot (rabbitbot-a) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'data/notes' | |||
2 | === added file 'data/notes/Create.sql' | |||
3 | --- data/notes/Create.sql 1970-01-01 00:00:00 +0000 | |||
4 | +++ data/notes/Create.sql 2014-01-26 22:03:24 +0000 | |||
5 | @@ -0,0 +1,8 @@ | |||
6 | 1 | CREATE TABLE IF NOT EXISTS notes | ||
7 | 2 | ( | ||
8 | 3 | id INTEGER PRIMARY KEY, | ||
9 | 4 | uri TEXT, | ||
10 | 5 | title TEXT, | ||
11 | 6 | note_content TEXT, | ||
12 | 7 | tstamp INTEGER | ||
13 | 8 | ); | ||
14 | 0 | 9 | ||
15 | === added file 'extensions/notes.vala' | |||
16 | --- extensions/notes.vala 1970-01-01 00:00:00 +0000 | |||
17 | +++ extensions/notes.vala 2014-01-26 22:03:24 +0000 | |||
18 | @@ -0,0 +1,467 @@ | |||
19 | 1 | /* | ||
20 | 2 | Copyright (C) 2013 Paweł Forysiuk <tuxator@o2.pl> | ||
21 | 3 | |||
22 | 4 | This library is free software; you can redistribute it and/or | ||
23 | 5 | modify it under the terms of the GNU Lesser General Public | ||
24 | 6 | License as published by the Free Software Foundation; either | ||
25 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
26 | 8 | |||
27 | 9 | See the file COPYING for the full license text. | ||
28 | 10 | */ | ||
29 | 11 | |||
30 | 12 | using Gtk; | ||
31 | 13 | using Midori; | ||
32 | 14 | using WebKit; | ||
33 | 15 | using Sqlite; | ||
34 | 16 | |||
35 | 17 | namespace ClipNotes { | ||
36 | 18 | |||
37 | 19 | Midori.Database database; | ||
38 | 20 | unowned Sqlite.Database db; | ||
39 | 21 | Gtk.ListStore notes_list_store; | ||
40 | 22 | int64 last_used_id; | ||
41 | 23 | |||
42 | 24 | class Note : GLib.Object { | ||
43 | 25 | public int64 id { get; set; } | ||
44 | 26 | public string title { get; set; } | ||
45 | 27 | public string? uri { get; set; default = null; } | ||
46 | 28 | public string content { get; set; default = ""; } | ||
47 | 29 | |||
48 | 30 | public void add (string title, string? uri, string note_content) | ||
49 | 31 | { | ||
50 | 32 | GLib.DateTime time = new DateTime.now_local (); | ||
51 | 33 | string sqlcmd = "INSERT INTO `notes` (`uri`, `title`, `note_content`, `tstamp` ) VALUES (:uri, :title, :note_content, :tstamp);"; | ||
52 | 34 | Midori.DatabaseStatement statement; | ||
53 | 35 | try { | ||
54 | 36 | statement = database.prepare (sqlcmd, | ||
55 | 37 | ":uri", typeof (string), uri, | ||
56 | 38 | ":title", typeof (string), title, | ||
57 | 39 | ":note_content", typeof (string), note_content, | ||
58 | 40 | ":tstamp", typeof (int64), time.to_unix ()); | ||
59 | 41 | |||
60 | 42 | statement.step (); | ||
61 | 43 | |||
62 | 44 | append_note (this); | ||
63 | 45 | } catch (Error error) { | ||
64 | 46 | critical (_("Failed to add new note to database: %s\n"), error.message); | ||
65 | 47 | } | ||
66 | 48 | |||
67 | 49 | this.id = db.last_insert_rowid (); | ||
68 | 50 | this.uri = uri; | ||
69 | 51 | this.title = title; | ||
70 | 52 | this.content = note_content; | ||
71 | 53 | } | ||
72 | 54 | |||
73 | 55 | public void remove () | ||
74 | 56 | { | ||
75 | 57 | string sqlcmd = "DELETE FROM `notes` WHERE id= :id;"; | ||
76 | 58 | Midori.DatabaseStatement statement; | ||
77 | 59 | try { | ||
78 | 60 | statement = database.prepare (sqlcmd, | ||
79 | 61 | ":id", typeof (int64), this.id); | ||
80 | 62 | |||
81 | 63 | statement.step (); | ||
82 | 64 | remove_note (this.id); | ||
83 | 65 | } catch (Error error) { | ||
84 | 66 | critical (_("Falied to remove note from database: %s\n"), error.message); | ||
85 | 67 | } | ||
86 | 68 | } | ||
87 | 69 | |||
88 | 70 | public void rename (string new_title) | ||
89 | 71 | { | ||
90 | 72 | string sqlcmd = "UPDATE `notes` SET title= :title WHERE id = :id;"; | ||
91 | 73 | Midori.DatabaseStatement statement; | ||
92 | 74 | try { | ||
93 | 75 | statement = database.prepare (sqlcmd, | ||
94 | 76 | ":id", typeof (int64), this.id, | ||
95 | 77 | ":title", typeof (string), new_title); | ||
96 | 78 | statement.step (); | ||
97 | 79 | } catch (Error error) { | ||
98 | 80 | critical (_("Falied to rename note: %s\n"), error.message); | ||
99 | 81 | } | ||
100 | 82 | |||
101 | 83 | this.title = new_title; | ||
102 | 84 | } | ||
103 | 85 | |||
104 | 86 | public void update (string new_content) | ||
105 | 87 | { | ||
106 | 88 | string sqlcmd = "UPDATE `notes` SET note_content= :content WHERE id = :id;"; | ||
107 | 89 | Midori.DatabaseStatement statement; | ||
108 | 90 | try { | ||
109 | 91 | statement = database.prepare (sqlcmd, | ||
110 | 92 | ":id", typeof (int64), this.id, | ||
111 | 93 | ":content", typeof (string), new_content); | ||
112 | 94 | statement.step (); | ||
113 | 95 | } catch (Error error) { | ||
114 | 96 | critical (_("Falied to update note: %s\n"), error.message); | ||
115 | 97 | } | ||
116 | 98 | this.content = new_content; | ||
117 | 99 | } | ||
118 | 100 | } | ||
119 | 101 | |||
120 | 102 | void append_note (Note note) | ||
121 | 103 | { | ||
122 | 104 | /* Strip LRE leading character */ | ||
123 | 105 | if (note.title != null && note.title.has_prefix ("")) | ||
124 | 106 | note.title = note.title.replace ("", ""); | ||
125 | 107 | |||
126 | 108 | Gtk.TreeIter iter; | ||
127 | 109 | notes_list_store.append (out iter); | ||
128 | 110 | notes_list_store.set (iter, 0, note); | ||
129 | 111 | } | ||
130 | 112 | |||
131 | 113 | void remove_note (int64 id) | ||
132 | 114 | { | ||
133 | 115 | Gtk.TreeIter iter; | ||
134 | 116 | if (notes_list_store.iter_children (out iter, null)) { | ||
135 | 117 | do { | ||
136 | 118 | Note note; | ||
137 | 119 | notes_list_store.get (iter, 0, out note); | ||
138 | 120 | if (id == note.id) { | ||
139 | 121 | notes_list_store.remove (iter); | ||
140 | 122 | } | ||
141 | 123 | } while (notes_list_store.iter_next (ref iter)); | ||
142 | 124 | } | ||
143 | 125 | } | ||
144 | 126 | |||
145 | 127 | |||
146 | 128 | private class Sidebar : Gtk.VBox, Midori.Viewable { | ||
147 | 129 | Gtk.Toolbar? toolbar = null; | ||
148 | 130 | Gtk.Label note_label; | ||
149 | 131 | Gtk.TreeView notes_tree_view; | ||
150 | 132 | Gtk.TextView note_text_view = new Gtk.TextView (); | ||
151 | 133 | |||
152 | 134 | public unowned string get_stock_id () { | ||
153 | 135 | return Gtk.STOCK_EDIT; | ||
154 | 136 | } | ||
155 | 137 | |||
156 | 138 | public unowned string get_label () { | ||
157 | 139 | return _("Notes"); | ||
158 | 140 | } | ||
159 | 141 | |||
160 | 142 | public Gtk.Widget get_toolbar () { | ||
161 | 143 | if (toolbar == null) { | ||
162 | 144 | toolbar = new Gtk.Toolbar (); | ||
163 | 145 | var new_note_button = new Gtk.ToolButton.from_stock (Gtk.STOCK_EDIT); | ||
164 | 146 | new_note_button.label = _("New Note"); | ||
165 | 147 | new_note_button.tooltip_text = _("Creates a new empty note, urelated to opened pages"); | ||
166 | 148 | new_note_button.use_underline = true; | ||
167 | 149 | new_note_button.is_important = true; | ||
168 | 150 | new_note_button.show (); | ||
169 | 151 | new_note_button.clicked.connect (() => { | ||
170 | 152 | var note = new Note (); | ||
171 | 153 | note.add (_("New note"), null, ""); | ||
172 | 154 | }); | ||
173 | 155 | toolbar.insert (new_note_button, -1); | ||
174 | 156 | } | ||
175 | 157 | return toolbar; | ||
176 | 158 | } | ||
177 | 159 | |||
178 | 160 | public Sidebar () { | ||
179 | 161 | Gtk.TreeViewColumn column; | ||
180 | 162 | |||
181 | 163 | notes_list_store = new Gtk.ListStore (1, typeof (Note)); | ||
182 | 164 | notes_tree_view = new Gtk.TreeView.with_model (notes_list_store); | ||
183 | 165 | notes_tree_view.headers_visible = true; | ||
184 | 166 | notes_tree_view.button_press_event.connect (button_pressed); | ||
185 | 167 | |||
186 | 168 | notes_list_store.set_sort_column_id (0, Gtk.SortType.ASCENDING); | ||
187 | 169 | notes_list_store.set_sort_func (0, tree_sort_func); | ||
188 | 170 | |||
189 | 171 | column = new Gtk.TreeViewColumn (); | ||
190 | 172 | Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf (); | ||
191 | 173 | column.pack_start (renderer_icon, false); | ||
192 | 174 | column.set_cell_data_func (renderer_icon, on_render_icon); | ||
193 | 175 | notes_tree_view.append_column (column); | ||
194 | 176 | |||
195 | 177 | column = new Gtk.TreeViewColumn (); | ||
196 | 178 | Gtk.CellRendererText renderer_title = new Gtk.CellRendererText (); | ||
197 | 179 | column.set_title (_("Notes")); | ||
198 | 180 | column.pack_start (renderer_title, true); | ||
199 | 181 | column.set_cell_data_func (renderer_title, on_render_note_title); | ||
200 | 182 | notes_tree_view.append_column (column); | ||
201 | 183 | |||
202 | 184 | try { | ||
203 | 185 | string sqlcmd = "SELECT id, uri, title, note_content FROM notes"; | ||
204 | 186 | var statement = database.prepare (sqlcmd); | ||
205 | 187 | while (statement.step ()) { | ||
206 | 188 | var note = new Note (); | ||
207 | 189 | note.id = statement.get_int64 ("id"); | ||
208 | 190 | note.uri = statement.get_string ("uri"); | ||
209 | 191 | note.title = statement.get_string ("title"); | ||
210 | 192 | note.content = statement.get_string ("note_content"); | ||
211 | 193 | |||
212 | 194 | append_note (note); | ||
213 | 195 | } | ||
214 | 196 | } catch (Error error) { | ||
215 | 197 | critical (_("Failed to select from notes database: %s\n"), error.message); | ||
216 | 198 | } | ||
217 | 199 | |||
218 | 200 | notes_tree_view.show (); | ||
219 | 201 | pack_start (notes_tree_view, false, false, 0); | ||
220 | 202 | |||
221 | 203 | note_label = new Gtk.Label (null); | ||
222 | 204 | note_label.show (); | ||
223 | 205 | pack_start (note_label, false, false, 0); | ||
224 | 206 | |||
225 | 207 | note_text_view.set_wrap_mode (Gtk.WrapMode.WORD); | ||
226 | 208 | note_text_view.show (); | ||
227 | 209 | note_text_view.focus_out_event.connect (focus_lost); | ||
228 | 210 | pack_start (note_text_view, true, true, 0); | ||
229 | 211 | } | ||
230 | 212 | |||
231 | 213 | int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { | ||
232 | 214 | Note note1, note2; | ||
233 | 215 | model.get (a, 0, out note1); | ||
234 | 216 | model.get (b, 0, out note2); | ||
235 | 217 | return strcmp (note1.title, note2.title); | ||
236 | 218 | } | ||
237 | 219 | |||
238 | 220 | bool focus_lost (Gdk.EventFocus event) { | ||
239 | 221 | Gtk.TreePath? path; | ||
240 | 222 | notes_tree_view.get_cursor (out path, null); | ||
241 | 223 | return_val_if_fail (path != null, false); | ||
242 | 224 | Gtk.TreeIter iter; | ||
243 | 225 | if (notes_list_store.get_iter (out iter, path)) { | ||
244 | 226 | Note note; | ||
245 | 227 | notes_list_store.get (iter, 0, out note); | ||
246 | 228 | if (last_used_id == note.id) { | ||
247 | 229 | string note_content = note_text_view.buffer.text; | ||
248 | 230 | note.update (note_content); | ||
249 | 231 | } | ||
250 | 232 | } | ||
251 | 233 | return false; | ||
252 | 234 | } | ||
253 | 235 | |||
254 | 236 | private void on_render_note_title (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
255 | 237 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
256 | 238 | |||
257 | 239 | Note note; | ||
258 | 240 | model.get (iter, 0, out note); | ||
259 | 241 | renderer.set ("markup", GLib.Markup.printf_escaped ("%s", note.title), | ||
260 | 242 | "ellipsize", Pango.EllipsizeMode.END); | ||
261 | 243 | } | ||
262 | 244 | |||
263 | 245 | private void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
264 | 246 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
265 | 247 | |||
266 | 248 | Note note; | ||
267 | 249 | model.get (iter, 0, out note); | ||
268 | 250 | |||
269 | 251 | var pixbuf = Midori.Paths.get_icon (note.uri, null); | ||
270 | 252 | if (pixbuf != null) { | ||
271 | 253 | int icon_width = 16, icon_height = 16; | ||
272 | 254 | Gtk.icon_size_lookup_for_settings (get_settings (), | ||
273 | 255 | Gtk.IconSize.MENU, out icon_width, out icon_height); | ||
274 | 256 | pixbuf = pixbuf.scale_simple (icon_width, icon_height, Gdk.InterpType.TILES); | ||
275 | 257 | } | ||
276 | 258 | renderer.set ("pixbuf", pixbuf); | ||
277 | 259 | } | ||
278 | 260 | |||
279 | 261 | bool button_pressed (Gdk.EventButton event) { | ||
280 | 262 | if (event.button == 1) { | ||
281 | 263 | if (event.type == Gdk.EventType.2BUTTON_PRESS) { | ||
282 | 264 | return show_note_webpage_in_new_tab (event, false); | ||
283 | 265 | } else { | ||
284 | 266 | return show_note_content (event); | ||
285 | 267 | } | ||
286 | 268 | } | ||
287 | 269 | if (event.button == 2) | ||
288 | 270 | return show_note_webpage_in_new_tab (event, true); | ||
289 | 271 | if (event.button == 3) | ||
290 | 272 | return show_popup_menu (event); | ||
291 | 273 | return false; | ||
292 | 274 | } | ||
293 | 275 | |||
294 | 276 | bool show_note_content (Gdk.EventButton? event) { | ||
295 | 277 | Gtk.TreeIter iter; | ||
296 | 278 | if (notes_tree_view.get_selection ().get_selected (null, out iter)) { | ||
297 | 279 | Note note; | ||
298 | 280 | notes_list_store.get (iter, 0, out note); | ||
299 | 281 | |||
300 | 282 | if (last_used_id != note.id) { | ||
301 | 283 | note_text_view.buffer.text = note.content; | ||
302 | 284 | last_used_id = note.id; | ||
303 | 285 | } | ||
304 | 286 | |||
305 | 287 | return true; | ||
306 | 288 | } else { | ||
307 | 289 | note_text_view.buffer.text = ""; | ||
308 | 290 | } | ||
309 | 291 | return false; | ||
310 | 292 | } | ||
311 | 293 | |||
312 | 294 | bool show_note_webpage_in_new_tab (Gdk.EventButton? event, bool new_tab) { | ||
313 | 295 | Gtk.TreeIter iter; | ||
314 | 296 | if (notes_tree_view.get_selection ().get_selected (null, out iter)) { | ||
315 | 297 | Note note; | ||
316 | 298 | notes_list_store.get (iter, 0, out note); | ||
317 | 299 | if (note.uri != null) { | ||
318 | 300 | var browser = Midori.Browser.get_for_widget (notes_tree_view); | ||
319 | 301 | if (new_tab) { | ||
320 | 302 | browser.add_uri (note.uri); | ||
321 | 303 | } else { | ||
322 | 304 | var tab = browser.tab as Midori.View; | ||
323 | 305 | tab.set_uri (note.uri); | ||
324 | 306 | } | ||
325 | 307 | return true; | ||
326 | 308 | } | ||
327 | 309 | } | ||
328 | 310 | return false; | ||
329 | 311 | } | ||
330 | 312 | |||
331 | 313 | bool show_popup_menu (Gdk.EventButton? event) { | ||
332 | 314 | Gtk.TreeIter iter; | ||
333 | 315 | if (notes_tree_view.get_selection ().get_selected (null, out iter)) { | ||
334 | 316 | |||
335 | 317 | var menu = new Gtk.Menu (); | ||
336 | 318 | |||
337 | 319 | var menuitem = new Gtk.ImageMenuItem.with_label (_("Rename note")); | ||
338 | 320 | var image = new Gtk.Image.from_stock (Gtk.STOCK_EDIT, Gtk.IconSize.MENU); | ||
339 | 321 | menuitem.always_show_image = true; | ||
340 | 322 | menuitem.set_image (image); | ||
341 | 323 | menuitem.activate.connect (() => { | ||
342 | 324 | Note note; | ||
343 | 325 | notes_list_store.get (iter, 0, out note); | ||
344 | 326 | |||
345 | 327 | var dialog = new Gtk.Dialog. with_buttons (_("Rename note"), null, | ||
346 | 328 | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL, | ||
347 | 329 | Gtk.Stock.OK, Gtk.ResponseType.OK); | ||
348 | 330 | Gtk.Box content = (Gtk.Box) dialog.get_content_area (); | ||
349 | 331 | dialog.set_default_response (Gtk.ResponseType.OK); | ||
350 | 332 | dialog.resizable = false; | ||
351 | 333 | dialog.icon_name = Gtk.STOCK_EDIT; | ||
352 | 334 | |||
353 | 335 | var entry = new Gtk.Entry (); | ||
354 | 336 | entry.text = note.title; | ||
355 | 337 | entry.activates_default = true; | ||
356 | 338 | content.add (entry); | ||
357 | 339 | content.show_all (); | ||
358 | 340 | |||
359 | 341 | int response = dialog.run (); | ||
360 | 342 | dialog.hide (); | ||
361 | 343 | if (response == Gtk.ResponseType.OK) { | ||
362 | 344 | string new_title = entry.text; | ||
363 | 345 | if (entry.text != null && new_title != note.title) { | ||
364 | 346 | note.rename (new_title); | ||
365 | 347 | notes_list_store.set (iter, 0, note); | ||
366 | 348 | } | ||
367 | 349 | } | ||
368 | 350 | dialog.destroy (); | ||
369 | 351 | |||
370 | 352 | }); | ||
371 | 353 | menu.append (menuitem); | ||
372 | 354 | |||
373 | 355 | |||
374 | 356 | menuitem = new Gtk.ImageMenuItem.with_label (_("Copy note to clipboard")); | ||
375 | 357 | image = new Gtk.Image.from_stock (Gtk.STOCK_COPY, Gtk.IconSize.MENU); | ||
376 | 358 | menuitem.always_show_image = true; | ||
377 | 359 | menuitem.set_image (image); | ||
378 | 360 | menuitem.activate.connect (() => { | ||
379 | 361 | Note note; | ||
380 | 362 | notes_list_store.get (iter, 0, out note); | ||
381 | 363 | get_clipboard (Gdk.SELECTION_CLIPBOARD).set_text (note.content, -1); | ||
382 | 364 | }); | ||
383 | 365 | menu.append (menuitem); | ||
384 | 366 | |||
385 | 367 | |||
386 | 368 | menuitem = new Gtk.ImageMenuItem.with_label (_("Remove note")); | ||
387 | 369 | image = new Gtk.Image.from_stock (Gtk.STOCK_DELETE, Gtk.IconSize.MENU); | ||
388 | 370 | menuitem.always_show_image = true; | ||
389 | 371 | menuitem.set_image (image); | ||
390 | 372 | menuitem.activate.connect (() => { | ||
391 | 373 | Note note; | ||
392 | 374 | notes_list_store.get (iter, 0, out note); | ||
393 | 375 | note.remove (); | ||
394 | 376 | }); | ||
395 | 377 | menu.append (menuitem); | ||
396 | 378 | |||
397 | 379 | menu.show_all (); | ||
398 | 380 | Katze.widget_popup (notes_tree_view, menu, null, Katze.MenuPos.CURSOR); | ||
399 | 381 | return true; | ||
400 | 382 | } | ||
401 | 383 | return false; | ||
402 | 384 | } | ||
403 | 385 | } | ||
404 | 386 | |||
405 | 387 | |||
406 | 388 | private class Manager : Midori.Extension { | ||
407 | 389 | internal GLib.List<Gtk.Widget> widgets; | ||
408 | 390 | |||
409 | 391 | void tab_added (Midori.Browser browser, Midori.Tab tab) { | ||
410 | 392 | |||
411 | 393 | tab.context_menu.connect (add_menu_items); | ||
412 | 394 | |||
413 | 395 | } | ||
414 | 396 | |||
415 | 397 | void add_menu_items (Midori.Tab tab, WebKit.HitTestResult hit_test_result, Midori.ContextAction menu) { | ||
416 | 398 | if ((hit_test_result.context & WebKit.HitTestResultContext.SELECTION) == 0) | ||
417 | 399 | return; | ||
418 | 400 | |||
419 | 401 | var view = tab as Midori.View; | ||
420 | 402 | var action = new Gtk.Action ("Notes", _("Copy selection as note"), null, null); | ||
421 | 403 | action.activate.connect ((action)=> { | ||
422 | 404 | if (view.has_selection () == true) | ||
423 | 405 | { | ||
424 | 406 | string selected_text = view.get_selected_text (); | ||
425 | 407 | string uri = view.get_display_uri (); | ||
426 | 408 | string title = view.get_display_title (); | ||
427 | 409 | var note = new Note(); | ||
428 | 410 | note.add (title, uri, selected_text); | ||
429 | 411 | } | ||
430 | 412 | }); | ||
431 | 413 | |||
432 | 414 | menu.add (action); | ||
433 | 415 | } | ||
434 | 416 | |||
435 | 417 | void browser_added (Midori.Browser browser) { | ||
436 | 418 | var viewable = new Sidebar (); | ||
437 | 419 | viewable.show (); | ||
438 | 420 | browser.panel.append_page (viewable); | ||
439 | 421 | widgets.append (viewable); | ||
440 | 422 | |||
441 | 423 | foreach (var tab in browser.get_tabs ()) | ||
442 | 424 | tab_added (browser, tab); | ||
443 | 425 | |||
444 | 426 | browser.add_tab.connect (tab_added); | ||
445 | 427 | } | ||
446 | 428 | |||
447 | 429 | void activated (Midori.App app) { | ||
448 | 430 | string? config_path = this.get_config_dir (); | ||
449 | 431 | string? db_path = config_path != null ? GLib.Path.build_path (Path.DIR_SEPARATOR_S, config_path, "notes.db") : null; | ||
450 | 432 | try { | ||
451 | 433 | database = new Midori.Database (db_path); | ||
452 | 434 | } catch (Midori.DatabaseError schema_error) { | ||
453 | 435 | error (schema_error.message); | ||
454 | 436 | } | ||
455 | 437 | db = database.db; | ||
456 | 438 | |||
457 | 439 | widgets = new GLib.List<Gtk.Widget> (); | ||
458 | 440 | app.add_browser.connect (browser_added); | ||
459 | 441 | foreach (var browser in app.get_browsers ()) | ||
460 | 442 | browser_added (browser); | ||
461 | 443 | } | ||
462 | 444 | |||
463 | 445 | void deactivated () { | ||
464 | 446 | var app = get_app (); | ||
465 | 447 | app.add_browser.disconnect (browser_added); | ||
466 | 448 | foreach (var widget in widgets) | ||
467 | 449 | widget.destroy (); | ||
468 | 450 | } | ||
469 | 451 | |||
470 | 452 | internal Manager () { | ||
471 | 453 | GLib.Object (name: _("Notes"), | ||
472 | 454 | description: _("Save text clips from websites as notes"), | ||
473 | 455 | version: "0.1" + Midori.VERSION_SUFFIX, | ||
474 | 456 | authors: "Paweł Forysiuk"); | ||
475 | 457 | |||
476 | 458 | this.activate.connect (activated); | ||
477 | 459 | this.deactivate.connect (deactivated); | ||
478 | 460 | } | ||
479 | 461 | } | ||
480 | 462 | |||
481 | 463 | } | ||
482 | 464 | |||
483 | 465 | public Midori.Extension extension_init () { | ||
484 | 466 | return new ClipNotes.Manager (); | ||
485 | 467 | } | ||
486 | 0 | 468 | ||
487 | === modified file 'midori/midori-database.vala' | |||
488 | --- midori/midori-database.vala 2013-12-19 19:58:53 +0000 | |||
489 | +++ midori/midori-database.vala 2014-01-26 22:03:24 +0000 | |||
490 | @@ -95,7 +95,8 @@ | |||
491 | 95 | */ | 95 | */ |
492 | 96 | public string? get_string (string name) throws DatabaseError { | 96 | public string? get_string (string name) throws DatabaseError { |
493 | 97 | int index = column_index (name); | 97 | int index = column_index (name); |
495 | 98 | if (stmt.column_type (index) != Sqlite.TEXT) | 98 | int type = stmt.column_type (index); |
496 | 99 | if (stmt.column_type (index) != Sqlite.TEXT && type != Sqlite.NULL) | ||
497 | 99 | throw new DatabaseError.TYPE ("Getting '%s' with wrong type in row: %s".printf (name, query)); | 100 | throw new DatabaseError.TYPE ("Getting '%s' with wrong type in row: %s".printf (name, query)); |
498 | 100 | return stmt.column_text (index); | 101 | return stmt.column_text (index); |
499 | 101 | } | 102 | } |
500 | 102 | 103 | ||
501 | === modified file 'midori/midori.vapi' | |||
502 | --- midori/midori.vapi 2014-01-12 18:13:44 +0000 | |||
503 | +++ midori/midori.vapi 2014-01-26 22:03:24 +0000 | |||
504 | @@ -143,6 +143,7 @@ | |||
505 | 143 | public void set_boolean (string name, bool value); | 143 | public void set_boolean (string name, bool value); |
506 | 144 | public void set_integer (string name, int value); | 144 | public void set_integer (string name, int value); |
507 | 145 | public void set_string (string name, string value); | 145 | public void set_string (string name, string value); |
508 | 146 | public unowned string get_config_dir (); | ||
509 | 146 | 147 | ||
510 | 147 | [NoAccessorMethod] | 148 | [NoAccessorMethod] |
511 | 148 | public string? stock_id { get; set; } | 149 | public string? stock_id { get; set; } |
512 | 149 | 150 | ||
513 | === modified file 'po/POTFILES.in' | |||
514 | --- po/POTFILES.in 2013-12-12 19:10:59 +0000 | |||
515 | +++ po/POTFILES.in 2014-01-26 22:03:24 +0000 | |||
516 | @@ -91,3 +91,4 @@ | |||
517 | 91 | extensions/transfers.vala | 91 | extensions/transfers.vala |
518 | 92 | extensions/tabby.vala | 92 | extensions/tabby.vala |
519 | 93 | extensions/flummi.vala | 93 | extensions/flummi.vala |
520 | 94 | extensions/notes.vala |
Voting does not meet specified criteria. Required: Approve >= 1. Got: 1 Pending.