l10n: Updated Russian (ru) translation to 100%
[maepad.git] / src / ui / callbacks.c
blob95000fb9509d8966defe8e6fcb17949f4b4ce302
1 /*
2 * This file is part of MaePad
3 * Copyright (c) 2010 Thomas Perl <thp.io/about>
4 * http://thp.io/2010/maepad/
6 * Based on Maemopad+:
7 * Copyright (c) 2006-2008 Kemal Hadimli
8 * Copyright (c) 2008 Thomas Perl
10 * This software is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1 of
13 * the License, or (at your option) any later version.
15 * This software is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this software; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
27 #include <ui/callbacks.h>
28 #include <ui/interface.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <libintl.h>
33 #include <glib.h>
36 * strlen needed from string.h
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <config.h>
45 #include <time.h>
47 #include <hildon/hildon.h>
48 #include <hildon/hildon-banner.h>
49 #include <hildon/hildon-note.h>
50 #include <hildon/hildon-font-selection-dialog.h>
51 #include <tablet-browser-interface.h>
53 #include <libgnomevfs/gnome-vfs.h>
55 #include <sharingdialog/sharing-dialog.h>
57 #include "sketchwidget.h"
59 #include "../he/he-about-dialog.h"
60 #include "../he/he-simple-color-dialog.h"
63 * "Busy" status handling
65 * Use "busy_reset" to reset the busy status (turn off)
66 * Use "busy_enter" when starting time-consuming processing
67 * Use "busy_leave" when processing has been finished
69 typedef enum {
70 BUSY_RESET = 0,
71 BUSY_INCREMENT,
72 BUSY_DECREMENT,
73 } SetBusyType;
75 /* Don't use this directly, but make use of the macros defined below */
76 void set_busy(MainView* mainview, SetBusyType update);
78 #define busy_reset(mainview) set_busy(mainview, BUSY_RESET)
79 #define busy_enter(mainview) set_busy(mainview, BUSY_INCREMENT)
80 #define busy_leave(mainview) set_busy(mainview, BUSY_DECREMENT)
84 * Privates:
86 void checklist_abort_longpress(MainView* mainview);
87 gboolean read_file_to_buffer(MainView * mainview);
88 void write_buffer_to_file(MainView * mainview);
89 void new_node_dialog(nodeType typ, MainView * mainview);
90 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview);
91 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop);
92 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter);
93 gboolean exec_command_on_db(MainView *mainview,char sql_string[]);
94 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter);
95 gint get_branch_node_index(GtkTreePath *path);
96 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter);
97 gboolean show_confirmation(MainView* mainview, gchar* question);
101 gboolean callback_node_view_window_state(GtkWidget* window,
102 GdkEventWindowState* event, gpointer user_data)
104 MainView* mainview = (MainView*)user_data;
105 GtkWidget* sketch_scroll = NULL;
106 nodeData *nd = getSelectedNode(mainview);
108 if (mainview->toolbar == NULL || mainview->sk == NULL) {
109 return FALSE;
112 sketch_scroll = GTK_WIDGET(sketchwidget_get_mainwidget(mainview->sk));
114 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
115 if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
116 gtk_widget_hide(mainview->toolbar);
117 gtk_scrolled_window_set_policy(
118 GTK_SCROLLED_WINDOW(sketch_scroll),
119 GTK_POLICY_NEVER,
120 GTK_POLICY_NEVER);
121 } else {
122 gtk_widget_show(mainview->toolbar);
123 gtk_scrolled_window_set_policy(
124 GTK_SCROLLED_WINDOW(sketch_scroll),
125 GTK_POLICY_AUTOMATIC,
126 GTK_POLICY_AUTOMATIC);
130 return FALSE;
133 void set_busy(MainView* mainview, SetBusyType update)
135 switch (update) {
136 case BUSY_RESET:
137 mainview->busyrefcount = 0;
138 break;
139 case BUSY_INCREMENT:
140 mainview->busyrefcount++;
141 break;
142 case BUSY_DECREMENT:
143 if (mainview->busyrefcount > 0) {
144 mainview->busyrefcount--;
146 break;
147 default:
148 g_assert_not_reached();
149 return;
152 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->main_view), (mainview->busyrefcount > 0));
153 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->node_view), (mainview->busyrefcount > 0));
156 void prepareUIforNodeChange(MainView * mainview, nodeType typ)
158 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), TRUE);
159 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), TRUE);
161 if (typ == NODE_TEXT)
163 gtk_widget_show(GTK_WIDGET(mainview->font_tb));
164 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
165 gtk_widget_show(GTK_WIDGET(mainview->italic_tb));
166 gtk_widget_show(GTK_WIDGET(mainview->underline_tb));
167 gtk_widget_show(GTK_WIDGET(mainview->bullet_tb));
168 gtk_widget_show(mainview->tools_font);
170 else
172 gtk_widget_hide(GTK_WIDGET(mainview->font_tb));
173 gtk_widget_hide(GTK_WIDGET(mainview->bold_tb));
174 gtk_widget_hide(GTK_WIDGET(mainview->italic_tb));
175 gtk_widget_hide(GTK_WIDGET(mainview->underline_tb));
176 gtk_widget_hide(GTK_WIDGET(mainview->bullet_tb));
177 gtk_widget_hide(mainview->tools_font);
180 if (typ == NODE_SKETCH)
182 /* gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));*/
183 gtk_widget_show(GTK_WIDGET(mainview->eraser_tb));
184 gtk_widget_show(GTK_WIDGET(mainview->brushsize_tb));
185 gtk_widget_show(GTK_WIDGET(mainview->sketchlines_tb));
186 gtk_widget_show(GTK_WIDGET(mainview->shape_tb));
187 gtk_widget_show(GTK_WIDGET(mainview->sharing_tb));
188 gtk_widget_show(mainview->tools_color);
189 gtk_widget_show(mainview->tools_brushsize);
190 gtk_widget_show(mainview->tools_pagestyle);
191 gtk_widget_show(mainview->tools_shape);
192 gtk_widget_show(mainview->tools_pressure);
194 else
196 /* gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));*/
197 gtk_widget_hide(GTK_WIDGET(mainview->eraser_tb));
198 gtk_widget_hide(GTK_WIDGET(mainview->brushsize_tb));
199 gtk_widget_hide(GTK_WIDGET(mainview->sketchlines_tb));
200 gtk_widget_hide(GTK_WIDGET(mainview->shape_tb));
201 gtk_widget_hide(GTK_WIDGET(mainview->sharing_tb));
202 gtk_widget_hide(mainview->tools_color);
203 gtk_widget_hide(mainview->tools_brushsize);
204 gtk_widget_hide(mainview->tools_pagestyle);
205 gtk_widget_hide(mainview->tools_shape);
206 gtk_widget_hide(mainview->tools_pressure);
209 if (typ == NODE_CHECKLIST)
211 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
212 gtk_widget_show(GTK_WIDGET(mainview->strikethru_tb));
213 gtk_widget_show(GTK_WIDGET(mainview->check_tb));
214 gtk_widget_show(GTK_WIDGET(mainview->checkadd_tb));
215 gtk_widget_show(GTK_WIDGET(mainview->checkedit_tb));
216 gtk_widget_show(GTK_WIDGET(mainview->checkdel_tb));
217 gtk_widget_hide(GTK_WIDGET(mainview->undo_tb));
218 gtk_widget_hide(GTK_WIDGET(mainview->redo_tb));
220 else
222 gtk_widget_hide(GTK_WIDGET(mainview->strikethru_tb));
223 gtk_widget_hide(GTK_WIDGET(mainview->check_tb));
224 gtk_widget_hide(GTK_WIDGET(mainview->checkadd_tb));
225 gtk_widget_hide(GTK_WIDGET(mainview->checkedit_tb));
226 gtk_widget_hide(GTK_WIDGET(mainview->checkdel_tb));
227 gtk_widget_show(GTK_WIDGET(mainview->undo_tb));
228 gtk_widget_show(GTK_WIDGET(mainview->redo_tb));
231 if (typ == NODE_TEXT)
233 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
234 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
235 gtk_widget_hide(mainview->checklist_content);
236 gtk_widget_show(GTK_WIDGET(mainview->scrolledwindow));
237 gtk_widget_show(mainview->tools_item);
239 else if (typ == NODE_SKETCH)
241 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
242 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
243 gtk_widget_hide(mainview->checklist_content);
244 gtk_widget_show(sketchwidget_get_mainwidget(mainview->sk));
245 gtk_widget_show(mainview->tools_item);
247 else if (typ == NODE_CHECKLIST)
249 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
250 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
251 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
252 gtk_widget_hide(mainview->tools_item);
253 gtk_widget_show(mainview->checklist_content);
255 else
257 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
258 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
259 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
260 gtk_widget_hide(mainview->tools_item);
261 gtk_widget_hide(mainview->checklist_content);
265 nodeData *getSelectedNode(MainView * mainview)
267 GtkTreeIter iter;
268 GtkTreeModel *model;
270 nodeData *nd;
272 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
274 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
275 return (NULL);
277 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
279 return (nd);
282 void saveCurrentData(MainView * mainview)
284 nodeData *selnode = getSelectedNode(mainview);
285 saveDataToNode(mainview, selnode);
288 void saveDataToNode(MainView * mainview, nodeData *selnode)
290 if (selnode == NULL)
291 return;
293 if (
294 (selnode->typ == NODE_SKETCH && sketchwidget_get_edited(mainview->sk) == FALSE) ||
295 (selnode->typ == NODE_TEXT && wp_text_buffer_is_modified(mainview->buffer)==FALSE) ||
296 (selnode->typ == NODE_CHECKLIST && mainview->checklist_edited==FALSE)
299 maepad_message("node not edited, not saving");
300 return;
303 mainview->file_edited = TRUE;
305 busy_enter(mainview);
306 maepad_debug("saveDataToNode working");
308 gboolean goterr = TRUE;
309 gchar *textdata = NULL;
310 GdkPixbuf *pixbuf = NULL;
311 gchar *sketchdata = NULL;
312 gsize datalen = 0;
313 char tq[512];
315 if (selnode->typ == NODE_TEXT)
317 #if 0
318 GtkTextIter start, end;
319 gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(mainview->buffer), &start, &end);
320 textdata = gtk_text_buffer_serialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &start, &end, &datalen);
321 #endif
323 GString *gstr=g_string_sized_new(4096);
324 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
326 datalen=gstr->len;
327 textdata=g_string_free(gstr, FALSE);
329 /* g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, bodyblob=NULL, body=?, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);*/
330 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, bodyblob=?, body=NULL, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
332 else if (selnode->typ == NODE_SKETCH)
334 GError *err = NULL;
335 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
336 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
338 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
339 if (pixbuf == NULL)
341 maepad_warning("error saving: pixbuf is null");
343 else
345 double w, h;
346 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, skdr->allocation.width, skdr->allocation.height, &w, &h, FALSE);
348 if (pixbuf2!=NULL)
350 if (gdk_pixbuf_save_to_buffer(pixbuf2, &sketchdata, &datalen, "png", &err, NULL) == FALSE)
352 sketchdata = NULL;
353 datalen = 0;
354 maepad_warning("Error saving sketch: %s", err->message);
355 g_error_free(err);
357 gdk_pixbuf_unref(pixbuf2);
360 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, body=NULL, bodyblob=?, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
361 maepad_debug("storing sketch in db: %d bytes", datalen);
362 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
364 else if (selnode->typ == NODE_CHECKLIST)
366 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, body=NULL, bodyblob=NULL, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
371 sqlite3_stmt *stmt = NULL;
372 const char *dum;
373 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
375 if (rc)
377 maepad_warning("Error updating: %s", sqlite3_errmsg(mainview->db));
378 break;
380 if (selnode->typ == NODE_TEXT)
381 sqlite3_bind_text(stmt, 1, textdata, datalen, /*strlen(textdata),*/ SQLITE_TRANSIENT);
382 else if (selnode->typ == NODE_SKETCH)
383 sqlite3_bind_blob(stmt, 1, sketchdata, datalen, SQLITE_TRANSIENT);
385 rc = SQLITE_BUSY;
386 while(rc == SQLITE_BUSY)
388 rc = sqlite3_step(stmt);
389 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
390 break;
392 sqlite3_finalize(stmt);
394 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
396 maepad_warning("Error saving node: %s", sqlite3_errmsg(mainview->db));
398 else
400 if (selnode->typ == NODE_TEXT)
401 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE);
402 else if (selnode->typ == NODE_SKETCH)
403 sketchwidget_set_edited(mainview->sk, FALSE);
404 else if (selnode->typ == NODE_CHECKLIST)
405 mainview->checklist_edited = FALSE;
406 goterr = FALSE;
408 }while(FALSE);
410 while(goterr==FALSE && selnode->typ == NODE_CHECKLIST)
412 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
414 char tq[512];
415 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d", checklisttable_tmpname, selnode->sql3id);
416 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
418 GtkTreeIter iter;
419 if (gtk_tree_model_get_iter_first(model, &iter)==FALSE) break;
423 gint styletoset_weight;
424 gboolean styletoset_strike;
425 gboolean ischecked;
426 gchar *text;
427 gchar *color;
428 unsigned long col=0;
430 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, CHECKNODE_TEXT, &text, CHECKNODE_COLOR, &color, -1);
432 GdkColor tmpcol;
433 if (color!=NULL && strcmp(color, "(null)")!=0 && gdk_color_parse(color, &tmpcol))
435 col=((tmpcol.red>>8)<<16)|((tmpcol.green>>8)<<8)|(tmpcol.blue>>8);
438 gint style=0;
439 if (ischecked) style|=CHECKSTYLE_CHECKED;
440 if (styletoset_weight==PANGO_WEIGHT_BOLD) style|=CHECKSTYLE_BOLD;
441 if (styletoset_strike) style|=CHECKSTYLE_STRIKE;
443 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (nodeid, name, style, color, ord) VALUES(%d, ?, %d, %lu, 0)", checklisttable_tmpname, selnode->sql3id, style, col);
444 sqlite3_stmt *stmt = NULL;
445 const char *dum;
446 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
448 if (rc)
450 goterr=TRUE;
451 maepad_warning("Error while saving checklist: %s", sqlite3_errmsg(mainview->db));
452 break;
454 sqlite3_bind_text(stmt, 1, text, strlen(text), SQLITE_TRANSIENT);
456 rc = SQLITE_BUSY;
457 while(rc == SQLITE_BUSY)
459 rc = sqlite3_step(stmt);
460 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
461 break;
463 sqlite3_finalize(stmt);
465 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
467 goterr=TRUE;
468 maepad_warning("Error while saving checklist (2): %s", sqlite3_errmsg(mainview->db));
471 g_free(color);
472 g_free(text);
474 }while(gtk_tree_model_iter_next(model, &iter)==TRUE);
476 break;
479 if (textdata)
480 g_free(textdata);
481 if (sketchdata)
482 g_free(sketchdata);
483 if (goterr == TRUE)
485 show_banner(mainview, _("Error saving memo"));
487 busy_leave(mainview);
490 gboolean callback_treeview_button_press(GtkTreeView* treeview, GdkEventButton* event, gpointer user_data)
492 MainView* mainview = (MainView*)user_data;
493 GtkTreePath* path;
495 if (mainview->node_list_longpress_path != NULL) {
496 /* Forget old, remembered tree path for longpress */
497 gtk_tree_path_free(mainview->node_list_longpress_path);
498 mainview->node_list_longpress_path = NULL;
501 if (gtk_tree_view_get_path_at_pos(treeview,
502 event->x, event->y, &path, NULL, NULL, NULL)) {
504 * Save this path in case we open the longpress menu to
505 * set the cursor in the treeview to the correct row.
507 * See on_node_menu_show() on how this is further used.
509 mainview->node_list_longpress_path = path;
512 mainview->can_show_node_view = TRUE;
514 return FALSE;
517 void callback_treeview_celldatafunc(GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data)
519 MainView *mainview = ( MainView * ) data;
520 g_assert(mainview != NULL && mainview->data != NULL );
522 nodeData *nd;
524 gtk_tree_model_get(tree_model, iter, NODE_DATA, &nd, -1);
525 if (nd == NULL)
526 return;
528 if (nd->namepix == NULL)
530 g_object_set(cell, "visible", FALSE, NULL);
532 else
534 g_object_set(cell, "visible", TRUE, NULL);
535 g_object_set(cell, "width", SKETCHNODE_RX, NULL);
536 g_object_set(cell, "height", SKETCHNODE_RY, NULL);
540 void callback_treeview_change(GtkTreeSelection * selection, gpointer data)
542 MainView *mainview = (MainView *) data;
543 g_assert(mainview != NULL && mainview->data != NULL);
545 nodeData *nd = getSelectedNode(mainview);
547 gchar* nodeName = _("View memo");
549 if (nd != NULL && nd->name != NULL) {
550 nodeName = nd->name;
553 /* Show node view with selected node */
554 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view),
555 nodeName);
557 if (mainview->can_show_node_view) {
558 gtk_widget_show(GTK_WIDGET(mainview->data->node_view));
561 /* Make sure we don't accidentally collapse any nodes */
562 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
564 guint tm=time(NULL);
565 if (mainview->cansel_time>0 && mainview->cansel_time+1.0<tm) mainview->cansel_node=NULL;
567 if (nd==NULL)
569 if (mainview->cansel_node!=NULL)
571 maepad_debug("[SELLOGIC] saving %d to unselect all nodes", (mainview->cansel_node)->sql3id);
572 saveDataToNode(mainview, (mainview->cansel_node));
573 mainview->cansel_node=NULL;
575 return;
578 if (mainview->cansel_node!=NULL)
580 if (nd->sql3id == (mainview->cansel_node)->sql3id)
582 mainview->cansel_node=NULL;
583 maepad_debug("[SELLOGIC] doubly selected %d, doing nothing", nd->sql3id);
584 prepareUIforNodeChange(mainview, nd->typ);
585 return;
587 else
589 maepad_debug("[SELLOGIC] saving %d to load new node", (mainview->cansel_node)->sql3id);
590 saveDataToNode(mainview, (mainview->cansel_node));
591 mainview->cansel_node=NULL;
595 if (nd == NULL) return;
597 busy_enter(mainview);
599 gboolean goterr = TRUE;
600 char *textdata = NULL;
601 char *blob = NULL;
602 int blobsize = 0, textsize = 0;
604 char tq[512];
606 g_snprintf(tq, sizeof(tq), "SELECT bodytype, body, bodyblob, flags FROM %s WHERE nodeid=%d", datatable_tmpname, nd->sql3id);
607 sqlite3_stmt *stmt = NULL;
608 const char *dum;
609 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
611 if (rc)
613 maepad_warning("Error reading (1): %s", sqlite3_errmsg(mainview->db));
615 else
617 rc = SQLITE_BUSY;
618 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
620 rc = sqlite3_step(stmt);
621 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
622 break;
623 else if (rc == SQLITE_ROW)
625 nd->typ = sqlite3_column_int(stmt, 0);
626 nd->flags = sqlite3_column_int(stmt, 3);
628 prepareUIforNodeChange(mainview, nd->typ);
629 if (nd->typ == NODE_TEXT)
631 gboolean file_edited_backup = mainview->file_edited;
633 blobsize = sqlite3_column_bytes(stmt, 2);
634 blob = (char *)sqlite3_column_blob(stmt, 2);
636 textdata = (char *)sqlite3_column_text(stmt, 1);
637 textsize = sqlite3_column_bytes(stmt, 1);
639 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);*/
640 wp_text_buffer_reset_buffer(mainview->buffer, TRUE);
642 gboolean richtext=FALSE;
644 if (blob != NULL)
646 #if 0
647 gboolean oldway=FALSE;
648 if (blobsize>8)
650 char tst[8];
651 strncpy(tst, blob, 8);
652 tst[8]=0;
653 if (strcmp(tst, "RICHTEXT")==0) oldway=TRUE;
655 if (oldway)
657 GError *err = NULL;
658 GtkTextIter iter;
659 gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(mainview->buffer), &iter);
660 gtk_text_buffer_deserialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &iter, blob, blobsize, TRUE, &err);
661 if (err != NULL)
663 g_error_free(err);
665 else
667 richtext=TRUE;
670 #endif
672 if (richtext==FALSE)
674 wp_text_buffer_load_document_begin(mainview->buffer, TRUE);
675 wp_text_buffer_load_document_write(mainview->buffer, blob, blobsize);
676 wp_text_buffer_load_document_end(mainview->buffer);
677 richtext=TRUE;
680 if (richtext==FALSE && !(textdata == NULL || g_utf8_validate(textdata, textsize, NULL) == FALSE))
682 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), textdata, textsize);*/
683 wp_text_buffer_load_document_begin(mainview->buffer, FALSE);
684 wp_text_buffer_load_document_write(mainview->buffer, textdata, textsize);
685 wp_text_buffer_load_document_end(mainview->buffer);
688 wp_text_buffer_enable_rich_text(mainview->buffer, TRUE);
689 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap),
690 (nd->flags & NODEFLAG_WORDWRAP)?(TRUE):(FALSE));
692 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE); /*we probably don't need this*/
694 callback_undotoggle((gpointer)mainview->buffer, FALSE, mainview); /*we need these*/
695 callback_redotoggle((gpointer)mainview->buffer, FALSE, mainview);
697 if (file_edited_backup==FALSE) mainview->file_edited=FALSE; /*textview changed event toggles this?*/
698 goterr = FALSE;
700 else if (nd->typ == NODE_SKETCH)
702 sketchwidget_wipe_undo(mainview->sk);
704 /* Disable squared and filled mode when opening a sketch */
705 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_square), FALSE);
706 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_filled), FALSE);
708 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[1]), TRUE);
709 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[0]), TRUE);
711 blobsize = sqlite3_column_bytes(stmt, 2);
712 blob = (char *)sqlite3_column_blob(stmt, 2);
713 gboolean clear = TRUE;
715 if (blob == NULL)
716 goterr = FALSE;
717 if (blob != NULL)
719 maepad_debug("blob size: %d", blobsize);
720 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
721 GError *err = NULL;
723 gdk_pixbuf_loader_write(pl, (guchar *) blob, blobsize, &err);
724 if (err != NULL)
726 maepad_warning("Error loading sketch: %s", err->message);
727 g_error_free(err);
728 err = NULL;
730 gdk_pixbuf_loader_close(pl, NULL);
731 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
733 if (GDK_IS_PIXBUF(pixbuf))
735 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
736 GtkPixmap *skpix = (GtkPixmap *) sketchwidget_get_Pixmap(mainview->sk);
738 int w=gdk_pixbuf_get_width(pixbuf);
739 int h=gdk_pixbuf_get_height(pixbuf);
740 if (w!=skdr->allocation.width || h!=skdr->allocation.height)
742 if (w>skdr->allocation.width) w=skdr->allocation.width;
743 if (h>skdr->allocation.height) h=skdr->allocation.height;
744 sketchwidget_clear_real(mainview->sk);
746 gdk_draw_pixbuf(GDK_DRAWABLE(skpix), NULL, pixbuf, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0);
748 clear = FALSE;
749 goterr = FALSE;
751 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
753 else
755 maepad_warning("Error loading pixbuf");
757 g_object_unref(pl);
759 if (clear == TRUE)
761 maepad_message("Clearing sketch widget");
762 sketchwidget_clear_real(mainview->sk);
764 gtk_widget_queue_draw(sketchwidget_get_drawingarea(mainview->sk));
766 else if (nd->typ == NODE_CHECKLIST)
768 mainview->checklist_edited = FALSE;
769 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
770 g_object_ref(model);
771 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), NULL);
772 gtk_list_store_clear(GTK_LIST_STORE(model));
774 g_snprintf(tq, sizeof(tq), "SELECT name, style, color FROM %s WHERE nodeid=%d ORDER BY ord, idx", checklisttable_tmpname, nd->sql3id);
775 sqlite3_stmt *stmt2 = NULL;
776 const char *dum;
777 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt2, &dum);
778 if (rc)
780 maepad_warning("Error reading checklist (1) %s", sqlite3_errmsg(mainview->db));
782 else
784 goterr=FALSE;
785 rc = SQLITE_BUSY;
786 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
788 rc = sqlite3_step(stmt2);
789 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
790 break;
791 else if (rc == SQLITE_ROW)
793 char *textdata = (char *)sqlite3_column_text(stmt2, 0);
794 int style = sqlite3_column_int(stmt2, 1);
795 unsigned long col = sqlite3_column_int(stmt2, 2);
797 GtkTreeIter toplevel;
798 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
799 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_TEXT, textdata, CHECKNODE_CHECKED, FALSE, -1);
800 if ((style & CHECKSTYLE_CHECKED)>0) {
801 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, TRUE, -1);
802 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
804 if ((style & CHECKSTYLE_BOLD)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_BOLD, PANGO_WEIGHT_BOLD, -1);
805 if ((style & CHECKSTYLE_STRIKE)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_STRIKE, TRUE, -1);
807 if (col>0)
809 char tmp[10];
810 g_snprintf(tmp, sizeof(tmp), "#%02lx%02lx%02lx", ((col & 0xFF0000) >> 16), ((col & 0xFF00) >> 8), (col & 0xFF));
811 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_COLOR, tmp, -1);
816 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
818 maepad_warning("Error reading checklist (2): %s", sqlite3_errmsg(mainview->db));
819 goterr=TRUE;
822 sqlite3_finalize(stmt2);
825 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), model);
826 g_object_unref(model);
829 if ((nd->flags & NODEFLAG_SKETCHLINES) > 0)
830 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[1]), TRUE);
831 else if ((nd->flags & NODEFLAG_SKETCHGRAPH) > 0)
832 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[2]), TRUE);
833 else
835 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[0]), TRUE);
836 callback_sketchlines(NULL, mainview->sketchlinesmenuitems[0]); /*FIXME:ugly */
838 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure), TRUE);
840 break;
843 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
844 maepad_warning("Error reading (2): %s", sqlite3_errmsg(mainview->db));
847 sqlite3_finalize(stmt);
850 busy_leave(mainview);
852 /* Show / hide the sketch-related menu widgets */
853 if (nd->typ == NODE_SKETCH) {
854 gtk_widget_show(mainview->menu_button_square);
855 gtk_widget_show(mainview->menu_button_filled);
856 } else {
857 gtk_widget_hide(mainview->menu_button_square);
858 gtk_widget_hide(mainview->menu_button_filled);
861 /* Show/hide the rich text-related menu widgets */
862 if (nd->typ == NODE_TEXT) {
863 gtk_widget_show(mainview->menu_button_wordwrap);
864 } else {
865 gtk_widget_hide(mainview->menu_button_wordwrap);
868 /* Show/hide the checklist-related menu widgets */
869 if (nd->typ == NODE_CHECKLIST) {
870 gtk_widget_show(mainview->menu_button_remove_checked);
871 } else {
872 gtk_widget_hide(mainview->menu_button_remove_checked);
875 if (goterr == TRUE)
877 show_banner(mainview, _("Error loading memo"));
881 gboolean treeview_canselect(GtkTreeSelection * selection, GtkTreeModel * model, GtkTreePath * path, gboolean path_currently_selected, gpointer userdata)
883 MainView *mainview = (MainView *) userdata;
884 g_assert(mainview != NULL && mainview->data != NULL);
886 if (path_currently_selected)
888 GtkTreeIter iter;
889 gtk_tree_model_get_iter(model, &iter, path);
891 gtk_tree_model_get(model, &iter, NODE_DATA, &(mainview->cansel_node), -1);
892 mainview->cansel_time=time(NULL);
895 return (TRUE);
898 gboolean newnodedlg_key_press_cb(GtkWidget * widget, GdkEventKey * event, GtkWidget * dlg)
900 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dlg), "sk");
902 switch (event->keyval)
904 case GDK_F7:
905 sketchwidget_redo(s);
906 return TRUE;
907 case GDK_F8:
908 sketchwidget_undo(s);
909 return TRUE;
911 return FALSE;
915 /* This struct will hold all our toggle buttons, so we can
916 * only allow one to be active at a time (i.e. radio buttons) */
917 typedef struct _newNodeToggleButtons newNodeToggleButtons;
918 struct _newNodeToggleButtons
920 GtkWidget *rbt; /* Text */
921 GtkWidget *rbs; /* Sketch */
922 GtkWidget *rbc; /* Checklist */
925 void show_sketch_widget(GtkWidget *widget, gpointer user_data)
927 GtkWidget *dialog = (GtkWidget*)user_data;
929 /* Show the sketch widget and hide the entry + draw button */
930 gtk_widget_show(gtk_object_get_data(GTK_OBJECT(dialog), "al"));
931 gtk_widget_hide(gtk_object_get_data(GTK_OBJECT(dialog), "draw_button"));
932 gtk_widget_hide(gtk_object_get_user_data(GTK_OBJECT(dialog)));
935 void new_node_dialog(nodeType typ, MainView * mainview)
937 GtkWidget *dialog, *entry, *but_ok, *vbox, *hbox, *al;
938 GtkWidget *rb1, *rb2, *rb3;
939 GtkWidget *hb;
940 gchar datetime_str[200];
941 time_t t_now;
942 struct tm *tm_now;
943 gboolean datetime_written = FALSE;
945 t_now = time(NULL);
946 tm_now = localtime(&t_now);
948 if (tm_now != NULL) {
949 if (strftime(datetime_str, sizeof(datetime_str), "%y-%m-%d %H:%M", tm_now) != 0) {
950 datetime_written = TRUE;
954 if (datetime_written == FALSE) {
955 /* Was not able to determine a datetime string - use default */
956 maepad_warning("Cannot determine current time");
957 strncpy(datetime_str, _("New memo"), sizeof(datetime_str));
958 datetime_str[sizeof(datetime_str)-1] = '\0';
961 newNodeToggleButtons *nntb = g_malloc(sizeof(newNodeToggleButtons));
963 dialog = gtk_dialog_new();
964 gtk_window_set_title(GTK_WINDOW(dialog), _("Add new memo"));
965 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
966 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
968 g_signal_connect(G_OBJECT(dialog), "key_press_event", G_CALLBACK(newnodedlg_key_press_cb), dialog);
970 vbox = gtk_vbox_new(FALSE, 0);
972 hbox = gtk_hbox_new(TRUE, 0);
974 /* Text note toggle button */
975 rb1 = hildon_gtk_radio_button_new(HILDON_SIZE_FINGER_HEIGHT, NULL);
976 gtk_button_set_label(GTK_BUTTON(rb1), _("Rich text"));
977 gtk_button_set_image(GTK_BUTTON(rb1), gtk_image_new_from_file(PIXMAPDIR "/text.png"));
978 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb1), TRUE, TRUE, 0);
979 nntb->rbt = rb1;
981 /* Sketch toggle button */
982 rb2 = hildon_gtk_radio_button_new_from_widget(HILDON_SIZE_FINGER_HEIGHT, GTK_RADIO_BUTTON(rb1));
983 gtk_button_set_label(GTK_BUTTON(rb2), _("Sketch"));
984 gtk_button_set_image(GTK_BUTTON(rb2), gtk_image_new_from_file(PIXMAPDIR "/sketch.png"));
985 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb2), TRUE, TRUE, 0);
986 nntb->rbs = rb2;
988 /* Checklist toggle button */
989 rb3 = hildon_gtk_radio_button_new_from_widget(HILDON_SIZE_FINGER_HEIGHT, GTK_RADIO_BUTTON(rb1));
990 gtk_button_set_label(GTK_BUTTON(rb3), _("Checklist"));
991 gtk_button_set_image(GTK_BUTTON(rb3), gtk_image_new_from_file(PIXMAPDIR "/checklist.png"));
992 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb3), TRUE, TRUE, 0);
993 nntb->rbc = rb3;
995 /* Set mode to 0 to get correct styling */
996 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb1), FALSE);
997 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb2), FALSE);
998 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb3), FALSE);
1000 /* Remember "new note toggle buttons" list */
1001 gtk_object_set_data(GTK_OBJECT(dialog), "nntb", nntb);
1003 if (typ == NODE_TEXT) {
1004 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb1), TRUE);
1005 } else if (typ == NODE_SKETCH) {
1006 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb2), TRUE);
1007 } else {
1008 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb3), TRUE);
1011 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1013 but_ok = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Add"), GTK_RESPONSE_OK);
1014 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
1015 g_signal_connect(G_OBJECT(but_ok), "clicked", G_CALLBACK(callback_new_node_real), dialog);
1017 gtk_object_set_data(GTK_OBJECT(dialog), "m", mainview);
1019 hb = gtk_hbox_new(FALSE, 10);
1020 gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("Name:")), FALSE, FALSE, 0);
1021 entry = hildon_entry_new(HILDON_SIZE_AUTO);
1022 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
1023 gtk_object_set_user_data(GTK_OBJECT(dialog), entry);
1024 gtk_entry_set_text(GTK_ENTRY(entry), datetime_str);
1025 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1026 gtk_box_pack_start(GTK_BOX(hb), entry, TRUE, TRUE, 0);
1028 /* Sketch widget, hidden by default */
1029 al = gtk_alignment_new(0.5, 0.5, 0, 0);
1030 SketchWidget *s = sketchwidget_new(SKETCHNODE_X, SKETCHNODE_Y, TRUE);
1031 gtk_object_set_data(GTK_OBJECT(dialog), "sk", s);
1032 gtk_object_set_data(GTK_OBJECT(dialog), "al", al);
1033 sketchwidget_set_brushsize(s, 2);
1034 sketchwidget_set_backstyle(s, SKETCHBACK_GRAPH);
1035 gtk_widget_set_size_request(sketchwidget_get_mainwidget(s), SKETCHNODE_X, SKETCHNODE_Y);
1036 gtk_container_add(GTK_CONTAINER(al), sketchwidget_get_mainwidget(s));
1037 gtk_box_pack_start(GTK_BOX(hb), al, FALSE, FALSE, 0);
1039 /*but_sketch = hildon_button_new_with_text(
1040 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
1041 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
1042 _("Use sketch label"), NULL);
1044 gtk_object_set_data(GTK_OBJECT(dialog), "draw_button", but_sketch);
1045 gtk_signal_connect(GTK_OBJECT(but_sketch), "clicked", G_CALLBACK(show_sketch_widget), dialog);
1046 gtk_box_pack_start(GTK_BOX(hb), but_sketch, FALSE, TRUE, 0);*/
1047 gtk_box_pack_start(GTK_BOX(vbox), hb, TRUE, FALSE, 0);
1049 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
1051 gtk_widget_grab_focus(entry);
1053 gtk_widget_show_all(dialog);
1055 /* Hide the sketch widget at first */
1056 gtk_widget_hide(al);
1057 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1060 void add_new_node(nodeData * node, MainView * mainview, gboolean ischild)
1062 GtkTreeIter parentiter, newiter;
1063 GtkTreeIter parentiterFilter, newiterFilter;
1064 GtkTreeModel *model;
1065 GtkTreeIter *ptr = NULL;
1066 gboolean setPtr = FALSE;
1068 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1070 if (gtk_tree_selection_get_selected(selection, &model, &parentiterFilter)) {
1071 setPtr = TRUE;
1074 model = GTK_TREE_MODEL(mainview->main_view_tree_store);
1075 gtk_tree_model_filter_convert_iter_to_child_iter(
1076 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1077 &parentiter,
1078 &parentiterFilter);
1080 if (setPtr) {
1081 ptr = &parentiter;
1084 GtkTreePath *path = NULL;
1086 unsigned int parentnodeid = 0;
1088 if (ptr != NULL)
1090 path = gtk_tree_model_get_path(model, &parentiter);
1092 if (ischild == FALSE)
1094 gtk_tree_path_up(path);
1096 if (gtk_tree_path_get_depth(path) == 0)
1098 /* Selected node is a root node */
1099 ptr = NULL; /* New node can not have a Parent node */
1100 gtk_tree_path_down(path); /*restore path so expand() works */
1102 else if (gtk_tree_path_get_depth(path) > 0)
1104 /* Selected node is a child node */
1105 if (gtk_tree_model_get_iter(model, &parentiter, path))
1106 ptr = &parentiter;
1111 if (ptr != NULL)
1113 nodeData *nd;
1115 gtk_tree_model_get(model, ptr, NODE_DATA, &nd, -1);
1116 if (nd)
1117 parentnodeid = nd->sql3id;
1120 node->sql3id = 0;
1123 sqlite3_stmt *stmt = NULL;
1124 const char *dum;
1125 char tq[512];
1128 * FIXME: ord
1130 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (parent, bodytype, name, nameblob, ord) VALUES (%d, %d, ?, ?, 0);", datatable_tmpname, parentnodeid, node->typ);
1131 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1133 if (rc)
1135 maepad_warning("Error inserting (1): %s", sqlite3_errmsg(mainview->db));
1136 break;
1138 if (node->name != NULL)
1139 sqlite3_bind_text(stmt, 1, node->name, strlen(node->name), SQLITE_TRANSIENT);
1140 else
1141 sqlite3_bind_text(stmt, 1, NULL, 0, SQLITE_TRANSIENT);
1143 if (node->namepix != NULL)
1145 gchar *namepixdata = NULL;
1146 gsize datalen = 0;
1148 GError *err = NULL;
1150 if (gdk_pixbuf_save_to_buffer(node->namepix, &namepixdata, &datalen, "png", &err, NULL) == FALSE)
1152 namepixdata = NULL;
1153 datalen = 0;
1154 maepad_warning("Error saving name: %s", err->message);
1155 g_error_free(err);
1157 sqlite3_bind_blob(stmt, 2, namepixdata, datalen, SQLITE_TRANSIENT);
1159 else
1160 sqlite3_bind_blob(stmt, 2, NULL, 0, SQLITE_TRANSIENT);
1162 rc = SQLITE_BUSY;
1163 while(rc == SQLITE_BUSY)
1165 rc = sqlite3_step(stmt);
1166 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1167 break;
1169 sqlite3_finalize(stmt);
1170 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
1172 maepad_warning("Error inserting (2): %s", sqlite3_errmsg(mainview->db));
1173 break;
1175 node->sql3id = sqlite3_last_insert_rowid(mainview->db);
1177 while(FALSE);
1179 if (node->sql3id == 0)
1181 if (node->name)
1182 g_free(node->name);
1183 if (node->namepix)
1184 g_object_unref(node->namepix);
1185 g_free(node);
1186 if (path)
1187 gtk_tree_path_free(path);
1188 show_banner(mainview, _("Error creating memo"));
1189 return;
1192 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, ptr);
1194 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter,
1195 NODE_NAME, format_overview_name(node, NULL),
1196 NODE_PIXBUF, node->namepix,
1197 NODE_DATA, node,
1198 -1);
1200 if (path)
1202 mainview->loading=TRUE; /*only when we have a valid parent*/
1203 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);
1204 gtk_tree_path_free(path);
1207 if (gtk_tree_model_filter_convert_child_iter_to_iter(
1208 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1209 &newiterFilter,
1210 &newiter)) {
1211 /* Only set the selection if the new item is visible -
1212 * it could be invisible if the filter doesn't show it */
1213 gtk_tree_selection_select_iter(selection, &newiterFilter);
1216 mainview->loading=FALSE;
1219 void callback_new_node_real(GtkAction * action, gpointer data)
1221 MainView *mainview;
1223 GtkWidget *dialog = data;
1224 GtkWidget *entry = gtk_object_get_user_data(GTK_OBJECT(dialog));
1226 mainview = gtk_object_get_data(GTK_OBJECT(dialog), "m");
1227 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dialog), "sk");
1228 newNodeToggleButtons *nntb = gtk_object_get_data(GTK_OBJECT(dialog), "nntb");
1230 nodeType typ = NODE_TEXT;
1231 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbs))) {
1232 typ = NODE_SKETCH;
1233 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbc))) {
1234 typ = NODE_CHECKLIST;
1236 g_free(nntb);
1238 gchar *txt = NULL;
1240 /*if (GTK_WIDGET_VISIBLE(entry))
1242 txt = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1243 if (strcmp(txt, "") == 0)
1245 g_free(txt);
1246 return;
1249 else
1251 GtkWidget *sdr = sketchwidget_get_drawingarea(s);
1253 GdkPixmap *spix = sketchwidget_get_Pixmap(s);
1255 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(spix), NULL, 0, 0, 0, 0, sdr->allocation.width, sdr->allocation.height);
1256 g_object_unref(spix);
1257 double w, h;
1258 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, SKETCHNODE_X, SKETCHNODE_Y, &w,
1259 &h, TRUE);
1260 if (pixbuf2==NULL) return;
1262 GdkPixbuf *pixbuf3 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, SKETCHNODE_RX,
1263 SKETCHNODE_RY);
1265 gdk_pixbuf_fill(pixbuf3, 0xffffffff);
1267 if (w <= SKETCHNODE_RX && h <= SKETCHNODE_RY)
1269 gdk_pixbuf_copy_area(pixbuf2, 0, 0, w, h, pixbuf3, 0, (SKETCHNODE_RY - h) / 2);
1271 else
1273 double neww, newh;
1275 if (w > h)
1277 neww = SKETCHNODE_RX;
1278 newh = (h / w) * SKETCHNODE_RX;
1280 else
1282 newh = SKETCHNODE_RY;
1283 neww = (w / h) * SKETCHNODE_RY;
1285 if (newh > SKETCHNODE_RY)
1286 newh = SKETCHNODE_RY;
1288 GdkPixbuf *tmpbuf = gdk_pixbuf_scale_simple(pixbuf2, neww, newh,
1289 GDK_INTERP_BILINEAR);
1291 gdk_pixbuf_copy_area(tmpbuf, 0, 0, neww, newh, pixbuf3, 0, (SKETCHNODE_RY - newh) / 2);
1293 gdk_pixbuf_unref(tmpbuf);
1296 pixbuf = pixbuf3;
1297 gdk_pixbuf_unref(pixbuf2);
1300 nodeData *node;
1302 node = g_malloc(sizeof(nodeData));
1303 node->typ = typ;
1304 node->name = txt;
1305 node->namepix = NULL;
1307 /*if (GTK_WIDGET_VISIBLE(entry))
1309 node->name = txt;
1311 else
1313 node->namepix = pixbuf;
1316 node->lastMod = 0;
1317 node->flags = 0;
1318 node->sql3id = 0;
1320 mainview->newnodedialog_createchild = FALSE;
1321 add_new_node(node, mainview, FALSE);
1323 sketchwidget_destroy(s);
1324 gtk_widget_destroy(dialog);
1325 mainview->file_edited = TRUE;
1329 * delete node
1331 void callback_file_delete_node(GtkAction * action, gpointer data)
1333 MainView *mainview = (MainView *) data;
1334 g_assert(mainview != NULL && mainview->data != NULL);
1336 if (getSelectedNode(mainview) == NULL) {
1337 show_banner(mainview, _("Select a memo first"));
1338 return;
1341 if (show_confirmation(mainview, _("Delete selected memo?"))) {
1342 mainview->can_show_node_view = FALSE;
1343 callback_delete_node_real(mainview);
1344 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
1349 * Callback for Rename Menuitem
1351 void callback_file_rename_node(GtkAction * action, gpointer data)
1353 MainView *mainview = (MainView*)data;
1354 g_assert(mainview != NULL && mainview->data != NULL);
1356 /* Get the selected node */
1357 nodeData *sel_node = getSelectedNode(mainview);
1358 if (sel_node == NULL) {
1359 /* Do nothing, if no node has been selected */
1360 show_banner(mainview, _("Select a memo first"));
1361 return;
1364 if (sel_node->namepix != NULL) {
1365 /* the memo has a graphical label, cannot edit! */
1366 show_banner(mainview, _("Cannot rename memos with sketch name"));
1367 return;
1370 gchar* new_name = show_line_edit_dialog(mainview, _("Rename memo"), _("New name:"), _("Rename"), sel_node->name);
1372 /* Only rename node when user accepted the new name */
1373 if (new_name != NULL) {
1374 callback_rename_node_real(mainview, new_name);
1375 g_free(new_name);
1379 void callback_rename_node_real(MainView* mainview, gchar* new_name)
1381 GtkTreeIter iter, filterIter;
1382 GtkTreeModel *model;
1383 nodeData *nd = NULL;
1385 /* Get the selected node */
1386 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1388 if (!gtk_tree_selection_get_selected(selection, &model, &filterIter)) {
1389 return;
1392 /* Convert filter iter to (backend) model iter for rename */
1393 model = GTK_TREE_MODEL(mainview->main_view_tree_store);
1394 gtk_tree_model_filter_convert_iter_to_child_iter(
1395 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1396 &iter,
1397 &filterIter);
1399 gtk_tree_model_get (model, &iter, NODE_DATA, &nd, -1);
1401 if (nd == NULL) {
1402 return;
1405 /* Update the database */
1406 sqlite3_stmt *stmt = NULL;
1408 char* sql = sqlite3_mprintf("UPDATE %s SET name='%q' WHERE nodeid=%d", datatable_tmpname, new_name, nd->sql3id);
1410 int rc = sqlite3_prepare(mainview->db, sql, strlen(sql), &stmt, NULL);
1411 if (rc == SQLITE_OK) {
1412 rc = SQLITE_BUSY;
1413 while (rc == SQLITE_BUSY) {
1414 rc = sqlite3_step(stmt);
1415 if (rc == SQLITE_DONE) {
1416 /* Update in the database was successful - now update the rest */
1418 /* Update the noteData */
1419 g_free(nd->name);
1420 nd->name = g_strdup(new_name);
1422 /* Update the window title of node_view */
1423 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view), nd->name);
1425 /* Update the value in the tree store */
1426 gtk_tree_store_set (GTK_TREE_STORE(model), &iter, NODE_NAME, format_overview_name(nd, new_name), -1);
1428 break;
1429 } else if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
1430 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1431 break;
1434 sqlite3_finalize(stmt);
1435 } else {
1436 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1439 sqlite3_free(sql);
1441 mainview->file_edited = TRUE;
1444 void callback_file_export_node(GtkAction * action, gpointer data)
1446 MainView *mainview = (MainView *) data;
1447 g_assert(mainview != NULL && mainview->data != NULL);
1449 nodeData *nd=getSelectedNode(mainview);
1450 if (nd == NULL)
1452 show_banner(mainview, _("Select a memo first"));
1453 return;
1456 gchar *nodename=nd->name;
1457 if (nodename==NULL) nodename=_("saved memo");
1459 if (nd->typ == NODE_TEXT)
1462 GtkTextIter begin, end;
1463 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER(mainview->buffer), &begin, &end);
1464 gchar *text = gtk_text_buffer_get_slice(GTK_TEXT_BUFFER(mainview->buffer), &begin, &end, TRUE);
1466 GString *gstr=g_string_sized_new(4096);
1467 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
1468 gint textlen=gstr->len;
1469 gchar *text=g_string_free(gstr, FALSE);
1471 if (text==NULL || !strcmp(text, ""))
1473 show_banner(mainview, _("Memo is empty"));
1475 else
1477 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "html");
1478 if (fn!=NULL)
1480 GnomeVFSResult vfs_result;
1481 GnomeVFSHandle *handle = NULL;
1482 GnomeVFSFileSize out_bytes;
1483 vfs_result = gnome_vfs_create(&handle, fn, GNOME_VFS_OPEN_WRITE, 0, 0600);
1484 if ( vfs_result != GNOME_VFS_OK ) {
1485 show_banner(mainview, _("Export failed"));
1487 else
1489 gnome_vfs_write(handle, text, textlen, &out_bytes);
1490 gnome_vfs_close(handle);
1491 if (out_bytes==strlen(text)) show_banner(mainview, _("Exported"));
1492 else show_banner(mainview, _("Export incomplete"));
1494 g_free(fn);
1497 g_free(text);
1499 else if (nd->typ == NODE_SKETCH)
1501 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
1502 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
1503 GdkPixbuf *pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
1504 if (pixbuf==NULL)
1506 show_banner(mainview, _("Memo is empty"));
1508 else
1510 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "png");
1511 if (fn!=NULL)
1513 if (gdk_pixbuf_save(pixbuf, fn, "png", NULL, NULL)==FALSE)
1515 show_banner(mainview, _("Export failed"));
1517 else
1519 show_banner(mainview, _("Exported"));
1521 g_free(fn);
1524 g_object_unref(skpix);
1526 else if (nd->typ == NODE_CHECKLIST)
1528 show_banner(mainview, _("Export of checklists not possible yet"));
1533 * callback from menu item
1534 * move selected node down (switch node with next sibling), don't change level of node
1536 void callback_move_down_node(GtkAction * action, gpointer data)
1538 GtkTreeIter iter, filterIter;
1539 GtkTreeModel *model;
1541 MainView *mainview = (MainView *) data;
1542 g_assert(mainview != NULL && mainview->data != NULL);
1544 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1545 gtk_tree_selection_get_selected(selection, &model, &filterIter);
1547 model = GTK_TREE_MODEL(mainview->main_view_tree_store);
1548 gtk_tree_model_filter_convert_iter_to_child_iter(
1549 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1550 &iter,
1551 &filterIter);
1553 GtkTreeIter old_iter = iter;/*save pointer to old iter, we will need it during swap nodes*/
1555 if (gtk_tree_model_iter_next(model,&iter)==FALSE)/*get next node*/
1556 return;
1558 GtkTreeStore *treeStore = GTK_TREE_STORE(model);
1559 gtk_tree_store_swap(treeStore,&iter,&old_iter);
1561 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1565 * callback from menu item
1566 * move selected node down (switch node with prev sibling), don't change level of node
1568 void callback_move_up_node(GtkAction * action, gpointer data)
1570 GtkTreeIter iter, filterIter;
1571 GtkTreeModel *model;
1573 MainView *mainview = (MainView *) data;
1574 g_assert(mainview != NULL && mainview->data != NULL);
1576 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1577 gtk_tree_selection_get_selected(selection, &model, &filterIter);
1579 model = GTK_TREE_MODEL(mainview->main_view_tree_store);
1580 gtk_tree_model_filter_convert_iter_to_child_iter(
1581 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1582 &iter,
1583 &filterIter);
1585 GtkTreeIter old_iter=iter;/*save pointer to old iter, we will need it during swap nodes*/
1587 if (tree_model_iter_prev(model,&iter)==FALSE)/*get previous node*/
1588 return;
1590 GtkTreeStore *treeStore = GTK_TREE_STORE(model);
1591 gtk_tree_store_swap(treeStore,&old_iter,&iter);/*do move*/
1593 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1598 * simple execute of sql command which is stored in sql_string[]
1600 gboolean exec_command_on_db(MainView *mainview,char sql_string[])
1602 sqlite3_stmt *stmt = NULL;
1603 const char* dum;
1604 gboolean db_query_result = FALSE;
1606 int rc = sqlite3_prepare (mainview->db, sql_string, strlen(sql_string), &stmt, &dum);
1608 if (rc) {
1609 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1610 return FALSE;
1613 rc = SQLITE_BUSY;
1614 while (rc == SQLITE_BUSY) {
1615 rc = sqlite3_step (stmt);
1616 if (rc == SQLITE_DONE) {
1617 db_query_result = TRUE;
1618 break;
1620 else if(rc == SQLITE_ERROR || rc== SQLITE_MISUSE) {
1621 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1622 break;
1624 sqlite3_finalize(stmt);
1626 return TRUE;
1630 * it is used in gtk_tree_model_foreach function to update ord value for all nodes (it's usefull for move up, move down node)
1632 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview)
1634 nodeData *node;
1635 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1636 /*we need index of node on actual level*/
1637 gint index=get_branch_node_index(path);
1639 /*prepare to execute update command,and exec it*/
1640 char sql_command[512];
1641 g_snprintf (sql_command, sizeof(sql_command), "UPDATE %s SET ord=\"%d\" WHERE nodeid=%d",datatable_tmpname, index, node->sql3id);
1642 exec_command_on_db(mainview,sql_command);
1644 /*we don't want break gtk_tree_model_foreach function,until we call this func on each node - so we return always FALSE*/
1645 return FALSE;
1649 * return id number of iter (id number which is used to identify in sql database of nodes)
1651 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter)
1653 if (iter==NULL)
1654 return 0;/*we got ROOT parent here*/
1656 nodeData *node;
1657 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1658 return node->sql3id;
1662 * get index of node in current branch
1664 gint get_branch_node_index(GtkTreePath *path)
1666 int depth=gtk_tree_path_get_depth(path);
1667 gint *indicies = gtk_tree_path_get_indices(path);
1669 return indicies[depth-1];
1673 * similiar with gtk_tree_model_iter_next (), but opposite
1675 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter)
1677 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
1679 if (path==NULL){
1680 fprintf(stderr,"Error: path is null\n");
1681 return FALSE;
1684 if (gtk_tree_path_prev(path)==FALSE)
1685 return FALSE;
1687 gtk_tree_model_get_iter(tree_model, iter,path);
1689 return TRUE;
1692 gboolean ref2iter(GtkTreeModel * model, GtkTreeRowReference * ref, GtkTreeIter * iter)
1694 gboolean res = FALSE;
1695 GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
1697 if (gtk_tree_model_get_iter(model, iter, path))
1699 res = TRUE;
1701 gtk_tree_path_free(path);
1702 return (res);
1705 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter)
1707 GtkTreeRowReference *ref;
1709 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
1711 ref = gtk_tree_row_reference_new(model, path);
1712 gtk_tree_path_free(path);
1713 return (ref);
1716 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop)
1718 GtkTreeIter topiter;
1720 if (ref2iter(model, topnode, &topiter) == FALSE)
1721 return;
1723 GtkTreeIter child;
1725 if (gtk_tree_model_iter_children(model, &child, &topiter))
1727 GtkTreeRowReference *ref;
1728 GList *rr_list = NULL, *node;
1732 ref = iter2ref(model, &child);
1733 rr_list = g_list_append(rr_list, ref);
1735 while(gtk_tree_model_iter_next(model, &child));
1738 * got a reflist for all children
1741 for(node = rr_list; node; node = node->next)
1743 ref = (GtkTreeRowReference *) (node->data);
1744 if (ref2iter(model, ref, &child))
1746 GtkTreeIter newtopiter, newiter;
1747 GtkTreeIter *newtopiterptr;
1749 if (ref2iter(model, newtop, &newtopiter))
1750 newtopiterptr = &newtopiter;
1751 else
1752 newtopiterptr = NULL;
1754 nodeData *node;
1756 gtk_tree_model_get(model, &child, NODE_DATA, &node, -1);
1758 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, newtopiterptr);
1759 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, format_overview_name(node, NULL), NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1761 GtkTreeRowReference *newref = iter2ref(model, &newiter);
1763 move_nodes_up(model, ref, newref);
1764 gtk_tree_row_reference_free(newref);
1766 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
1768 gtk_tree_row_reference_free(ref);
1771 g_list_free(rr_list);
1776 void callback_delete_node_real(MainView* mainview)
1778 GtkTreeIter iter, filterIter;
1779 GtkTreeModel *model;
1781 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1783 if (!gtk_tree_selection_get_selected(selection, &model, &filterIter))
1784 return;
1786 /* Convert filter iter to (backend) model iter */
1787 model = GTK_TREE_MODEL(mainview->main_view_tree_store);
1788 gtk_tree_model_filter_convert_iter_to_child_iter(
1789 GTK_TREE_MODEL_FILTER(mainview->main_view_tree_filter),
1790 &iter,
1791 &filterIter);
1793 nodeData *nd;
1795 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
1796 if (!nd)
1797 return;
1799 mainview->file_edited = TRUE;
1801 unsigned int sql3id = nd->sql3id;
1803 if (nd->name)
1804 g_free(nd->name);
1807 * g_free(nd->data);
1808 * if (nd->pix) g_object_unref(nd->pix);
1810 g_free(nd);
1812 GtkTreeRowReference *upref = NULL, *ref = NULL;
1814 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1816 ref = gtk_tree_row_reference_new(model, path);
1817 if (gtk_tree_path_up(path))
1818 upref = gtk_tree_row_reference_new(model, path);
1819 gtk_tree_path_free(path);
1821 g_object_ref(mainview->main_view_tree_filter);
1822 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
1824 move_nodes_up(model, ref, upref);
1826 if (ref2iter(model, ref, &iter))
1828 char tq[512];
1830 g_snprintf(tq, sizeof(tq), "SELECT parent FROM %s WHERE nodeid=%d", datatable_tmpname, sql3id);
1831 sqlite3_stmt *stmt = NULL;
1832 const char *dum;
1833 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1834 unsigned int sql3parentid = 0;
1836 if (rc)
1838 maepad_warning("Error finding children for delete: %s", sqlite3_errmsg(mainview->db));
1840 else
1842 rc = SQLITE_BUSY;
1843 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
1845 rc = sqlite3_step(stmt);
1846 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1847 break;
1848 else if (rc == SQLITE_ROW)
1850 sql3parentid = sqlite3_column_int(stmt, 0);
1851 break;
1854 sqlite3_finalize(stmt);
1856 g_snprintf(tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE parent=%d;", datatable_tmpname, sql3parentid, sql3id);
1857 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1858 maepad_warning("Error moving nodes up one level");
1859 } else
1861 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d;", datatable_tmpname, sql3id);
1862 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1863 maepad_warning("Error deleting node");
1866 /* Delete all checklist items that do not have
1867 * a node anymore (= orphaned checklist items) */
1868 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid NOT IN (SELECT nodeid FROM %s);", checklisttable_tmpname, datatable_tmpname);
1869 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1870 maepad_warning("Error deleting orphaned checklist items");
1874 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
1877 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview),
1878 GTK_TREE_MODEL(mainview->main_view_tree_filter));
1879 g_object_unref(mainview->main_view_tree_filter);
1881 /* Carry out a refilter to show/hide remaining items */
1882 gtk_tree_model_filter_refilter(mainview->main_view_tree_filter);
1884 gtk_tree_row_reference_free(ref);
1885 gtk_tree_row_reference_free(upref);
1887 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
1891 void callback_edit_clear(GtkAction * action, gpointer data)
1893 MainView *mainview = (MainView *) data;
1894 g_assert(mainview != NULL && mainview->data != NULL);
1895 nodeData *nd = getSelectedNode(mainview);
1897 if (show_confirmation(mainview, _("Remove all contents of this memo?"))) {
1898 switch (nd->typ) {
1899 case NODE_TEXT:
1900 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", 0);
1901 break;
1902 case NODE_SKETCH:
1903 sketchwidget_clear(mainview->sk);
1904 break;
1905 case NODE_CHECKLIST:
1906 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview))));
1907 break;
1908 default:
1909 g_assert_not_reached();
1915 * cut
1917 void callback_edit_cut(GtkAction * action, gpointer data)
1919 MainView *mainview = (MainView *) data;
1920 g_assert(mainview != NULL && mainview->data != NULL);
1922 nodeData *nd = getSelectedNode(mainview);
1924 if (nd->typ == NODE_TEXT)
1925 gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, TRUE);
1926 else if (nd->typ == NODE_SKETCH)
1928 if (sketchwidget_cut(mainview->sk, mainview->clipboard)==FALSE)
1929 show_banner(mainview, _("Error cutting"));
1931 else if (nd->typ == NODE_CHECKLIST)
1932 show_banner(mainview, _("Unimplemented"));
1937 * copy
1939 void callback_edit_copy(GtkAction * action, gpointer data)
1941 MainView *mainview = (MainView *) data;
1942 g_assert(mainview != NULL && mainview->data != NULL);
1944 nodeData *nd = getSelectedNode(mainview);
1946 if (nd->typ == NODE_TEXT)
1947 gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard);
1948 else if (nd->typ == NODE_SKETCH)
1950 if (sketchwidget_copy(mainview->sk, mainview->clipboard)==FALSE)
1951 show_banner(mainview, _("Error copying"));
1953 else if (nd->typ == NODE_CHECKLIST)
1955 /* Copy all selected entries as multiline text (1 line per entry) */
1956 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
1957 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
1959 gint selected_rows = gtk_tree_selection_count_selected_rows(selection);
1960 GList* l = gtk_tree_selection_get_selected_rows(selection, NULL);
1962 GtkTreeIter iter;
1963 gchar *str_data;
1965 gchar **entries = g_malloc0(sizeof(gchar*)*selected_rows+1);
1966 gint entries_idx = 0;
1968 GList* cur = l;
1969 while(cur) {
1970 GtkTreePath *path = cur->data;
1972 if (gtk_tree_model_get_iter(model, &iter, path)) {
1973 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_TEXT, &(entries[entries_idx++]), -1);
1975 gtk_tree_path_free(path);
1977 cur = cur->next;
1980 g_list_free(l);
1981 str_data = g_strjoinv("\n", entries);
1982 g_strfreev(entries);
1983 gtk_clipboard_set_text(mainview->clipboard, str_data, -1);
1984 g_free(str_data);
1986 str_data = g_strdup_printf(_("Copied %d entries"), selected_rows);
1987 show_banner(mainview, str_data);
1988 g_free(str_data);
1994 * paste
1996 void callback_edit_paste(GtkAction * action, gpointer data)
1998 MainView *mainview = (MainView *) data;
1999 g_assert(mainview != NULL && mainview->data != NULL);
2001 nodeData *nd = getSelectedNode(mainview);
2003 if (nd->typ == NODE_TEXT)
2004 gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, NULL, TRUE);
2005 else if (nd->typ == NODE_SKETCH)
2007 if (sketchwidget_paste(mainview->sk, mainview->clipboard)==FALSE)
2008 show_banner(mainview, _("Error pasting"));
2010 else if (nd->typ == NODE_CHECKLIST) {
2011 /* Paste string from clipboard as new item */
2012 callback_checklist_paste(mainview);
2015 mainview->file_edited = TRUE;
2018 gint cb_popup(GtkWidget * widget, GdkEvent * event)
2020 GtkMenu *menu;
2021 GdkEventButton *event_button;
2024 * The "widget" is the menu that was supplied when
2025 * * g_signal_connect_swapped() was called.
2027 menu = GTK_MENU(widget);
2028 event_button = (GdkEventButton *) event;
2029 if (event->type == GDK_BUTTON_PRESS && event_button->button == 3)
2031 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
2032 return TRUE;
2034 return FALSE;
2039 * on_node_menu_show(GtkWidget*, gpointer)
2041 * This is called when the longpress menu is shown in the main
2042 * window. In the Hildon UI mode that we are using, this does
2043 * not automatically select the touched node, so we need to set
2044 * the cursor here so that the functions in the menu operate on
2045 * the node that the user touched (i.e. the expected one).
2047 * The value of mainview->node_list_longpress_path has been set
2048 * by callback_treeview_button_press on the buttn press event.
2050 void
2051 on_node_menu_show(GtkWidget* nodemenu, gpointer user_data)
2053 MainView* mainview = (MainView*)user_data;
2055 if (mainview->node_list_longpress_path != NULL) {
2056 /* Set the cursor, but don't open the node view */
2057 mainview->can_show_node_view = FALSE;
2058 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
2059 mainview->node_list_longpress_path, NULL, FALSE);
2061 /* Dispose the path (we don't need it anymore) */
2062 gtk_tree_path_free(mainview->node_list_longpress_path);
2063 mainview->node_list_longpress_path = NULL;
2068 * close
2070 gboolean closefile(MainView * mainview)
2072 saveCurrentData(mainview);
2074 if (mainview->file_edited)
2076 HildonNote *hn = HILDON_NOTE(hildon_note_new_confirmation_add_buttons(GTK_WINDOW(mainview->data->main_view), _("Save changes?"), _("Yes"), CONFRESP_YES, _("No"), CONFRESP_NO, _("Cancel"), CONFRESP_CANCEL, NULL, NULL));
2077 gint answer = gtk_dialog_run(GTK_DIALOG(hn));
2078 gtk_widget_destroy(GTK_WIDGET(hn));
2080 if (answer == CONFRESP_CANCEL)
2081 return (FALSE);
2082 else if (answer == CONFRESP_YES)
2084 if (mainview->file_name == NULL)
2086 mainview->file_name = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2088 write_buffer_to_file(mainview);
2092 if (mainview->db)
2093 sqlite3_close(mainview->db);
2094 mainview->db = NULL;
2095 return (TRUE);
2098 gboolean callback_file_close(GtkAction * action, gpointer data)
2101 MainView *mainview = (MainView *) data;
2102 g_assert(mainview != NULL && mainview->data != NULL);
2103 if (closefile(mainview) == FALSE)
2104 return(FALSE);
2106 gtk_main_quit();
2107 return(TRUE);
2110 void callback_file_new_node(GtkAction * action, gpointer data)
2112 MainView *mainview = (MainView *) data;
2113 g_assert(mainview != NULL && mainview->data != NULL);
2115 nodeType typ = NODE_SKETCH;
2117 nodeData *nd = getSelectedNode(mainview);
2119 if (nd != NULL)
2120 typ = nd->typ;
2122 new_node_dialog(typ, mainview);
2126 * new
2128 void callback_file_new(GtkAction * action, gpointer data)
2130 MainView *mainview = (MainView *) data;
2131 g_assert(mainview != NULL && mainview->data != NULL);
2133 gchar *filename = NULL;
2135 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "memos", "db");
2136 if (filename == NULL) {
2137 return;
2140 if (closefile(mainview) == FALSE) {
2141 return;
2144 new_file(mainview);
2148 busy_enter(mainview);
2150 int rc;
2152 rc = sqlite3_open(filename, &mainview->db);
2153 if (rc)
2155 show_banner(mainview, _("Cannot create database"));
2156 maepad_warning("Can't create database %s: %s", filename, sqlite3_errmsg(mainview->db));
2157 break;
2160 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
2162 char tq[512];
2164 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
2165 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
2167 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
2168 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2170 maepad_warning("Cannot create data table");
2171 show_banner(mainview, _("Error creating data table"));
2172 break;
2175 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
2176 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2178 maepad_warning("Cannot create checklist table");
2179 show_banner(mainview, _("Error creating checklist table"));
2180 break;
2183 if (mainview->db)
2184 sqlite3_close(mainview->db);
2185 mainview->db = NULL;
2187 mainview->file_name = filename;
2188 mainview->file_edited = FALSE;
2189 read_file_to_buffer(mainview);
2191 /*add a starter memo*/
2192 nodeData *node;
2193 node = g_malloc(sizeof(nodeData));
2194 node->typ = NODE_SKETCH;
2195 node->name = g_strdup(_("My first memo"));
2196 node->namepix = NULL;
2197 node->lastMod = 0;
2198 node->flags = 0;
2199 node->sql3id = 0;
2200 add_new_node(node, mainview, TRUE);
2201 /*gtk_paned_set_position(GTK_PANED(mainview->hpaned), 180);*/
2202 write_buffer_to_file(mainview);
2204 }while(FALSE);
2205 busy_reset(mainview);
2208 gboolean reset_ctree(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
2210 nodeData *node;
2212 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
2213 if (node)
2215 if (node->name)
2216 g_free(node->name);
2217 if (node->namepix)
2218 g_object_unref(node->namepix);
2219 g_free(node);
2221 gtk_tree_store_set(GTK_TREE_STORE(model), iter, NODE_DATA, NULL, -1);
2223 return (FALSE);
2226 void new_file(MainView * mainview)
2228 busy_enter(mainview);
2230 * clear buffer, filename and free buffer text
2232 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);
2233 mainview->file_name = NULL;
2234 mainview->file_edited = FALSE;
2235 mainview->newnodedialog_createchild = TRUE;
2237 /* The filter is the "filtered down" list that's displayed in the
2238 * treeview and the model is the underlying real data */
2239 GtkTreeModel *filter = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
2240 GtkTreeModel *model = GTK_TREE_MODEL(mainview->main_view_tree_store);
2242 g_object_ref(filter);
2243 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
2245 gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) reset_ctree, (gpointer) mainview);
2248 * crashing bastard
2249 * gtk_tree_store_clear(GTK_TREE_STORE(model));
2251 GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
2252 GtkTreeIter iter;
2254 if (gtk_tree_model_get_iter(model, &iter, path))
2258 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2260 while(gtk_tree_store_iter_is_valid(GTK_TREE_STORE(model), &iter));
2262 gtk_tree_path_free(path);
2264 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), filter);
2265 g_object_unref(filter);
2267 busy_leave(mainview);
2271 * open
2273 void callback_file_open(GtkAction * action, gpointer data)
2275 gchar *filename = NULL;
2276 MainView *mainview = (MainView *) data;
2277 g_assert(mainview != NULL && mainview->data != NULL);
2279 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
2280 if (filename == NULL) {
2281 return;
2284 if (closefile(mainview) == FALSE) {
2285 return;
2288 open_file(filename, mainview);
2289 g_free(filename);
2292 gboolean open_file(gchar * filename, MainView * mainview)
2294 gboolean ret=FALSE;
2296 /* Don't open nodes when opening a file */
2297 mainview->can_show_node_view = FALSE;
2299 busy_enter(mainview);
2301 while(filename != NULL)
2303 struct stat s;
2305 if (stat(filename, &s) == -1) break;
2307 mainview->file_name = g_strdup(filename);
2308 gboolean res = read_file_to_buffer(mainview);
2310 if (res == FALSE)
2312 g_free(mainview->file_name);
2313 mainview->file_name = NULL;
2314 break;
2316 mainview->file_edited = FALSE;
2317 ret=TRUE;
2318 break;
2321 busy_leave(mainview);
2322 return(ret);
2325 void callback_about_link(GtkAboutDialog *about, const gchar *link, gpointer data)
2327 MainView *mainview = (MainView *) data;
2328 g_assert(mainview != NULL && mainview->data != NULL);
2329 osso_rpc_run_with_defaults(mainview->data->osso, "osso_browser", OSSO_BROWSER_OPEN_NEW_WINDOW_REQ, NULL,
2330 DBUS_TYPE_STRING, link, DBUS_TYPE_INVALID);
2333 void callback_about(GtkAction * action, gpointer data)
2335 MainView* mainview = (MainView *)data;
2336 he_about_dialog_present(mainview_get_dialog_parent(mainview),
2337 NULL /* auto-detect app name */,
2338 "maepad",
2339 VERSION,
2340 _("A node-based memory pad for Maemo"),
2341 _("(c) 2010 Thomas Perl"),
2342 "http://thp.io/2010/maepad/",
2343 "https://garage.maemo.org/tracker/?group_id=1291",
2344 "http://thp.io/2010/maepad/donate");
2347 gboolean callback_live_search_refilter(HildonLiveSearch *livesearch, gpointer user_data)
2349 MainView *mainview = (MainView*)user_data;
2350 /* Avoid showing the node view when filtering */
2351 mainview->can_show_node_view = FALSE;
2352 return FALSE;
2356 * save
2358 void callback_file_save(GtkAction * action, gpointer data)
2360 gchar *filename = NULL;
2361 MainView *mainview = (MainView *) data;
2362 g_assert(mainview != NULL && mainview->data != NULL);
2365 * check is we had a new file
2367 if (mainview->file_name != NULL)
2369 write_buffer_to_file(mainview);
2371 else
2373 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2375 * if we got a file name from chooser -> save file
2377 if (filename != NULL)
2379 mainview->file_name = filename;
2380 write_buffer_to_file(mainview);
2381 mainview->file_edited = FALSE;
2386 void callback_shapemenu(GtkAction * action, GtkWidget * wid)
2388 gint style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(wid)));
2389 MainView* mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2390 g_assert(mainview != NULL);
2392 if (style >= 0 && style < SKETCHSHAPE_COUNT) {
2393 /* We use the sketch widget's enum for available styles */
2394 sketchwidget_set_shape(mainview->sk, style);
2396 /* Draw the correct indicator for the current shape */
2397 GtkWidget* pix = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(wid), "i"));
2398 g_assert(pix != NULL);
2399 gtk_widget_show(pix);
2400 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->shape_tb), pix);
2401 } else {
2402 /* Fail. We shouldn't get here at all! */
2403 g_error("Invalid style ID from shape menu: %d", style);
2409 void callback_eraser(GtkAction * action, MainView * mainview)
2411 g_assert(mainview != NULL && mainview->data != NULL);
2413 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb))) {
2414 /* Eraser on: Set pen color to white */
2415 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };
2416 sketchwidget_set_brushcolor(mainview->sk, white);
2417 } else {
2418 /* Eraser off: Set default color again (or black) */
2419 GdkColor black = {0, 0, 0, 0};
2420 if (mainview->current_color == NULL) {
2421 mainview->current_color = gdk_color_copy(&black);
2423 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2427 void callback_menu(GtkAction * action, GtkWidget * menu)
2429 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
2432 void callback_brushsizetb(GtkAction * action, MainView *mainview)
2434 g_assert(mainview != NULL && mainview->data != NULL);
2435 callback_menu(NULL, mainview->brushsizemenu);
2438 void callback_brushsize(GtkAction * action, GtkWidget * wid)
2440 int bsize = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2441 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2443 g_assert(mainview != NULL && mainview->data != NULL);
2445 sketchwidget_set_brushsize(mainview->sk, bsize);
2447 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2449 gtk_widget_show(pix);
2450 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->brushsize_tb), pix);
2453 void callback_sketchlines(GtkAction * action, GtkWidget * wid)
2455 int style = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2456 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2458 g_assert(mainview != NULL);
2460 nodeData *nd = getSelectedNode(mainview);
2461 gboolean doit = FALSE;
2463 if (nd != NULL && nd->typ == NODE_SKETCH)
2465 nd->flags &= ~NODEFLAG_SKETCHLINES;
2466 nd->flags &= ~NODEFLAG_SKETCHGRAPH;
2467 /* sketchwidget_set_edited(mainview->sk, TRUE);*/ /*we call this on openfile, so this messes things up*/
2468 doit = TRUE;
2471 if (style == 0)
2473 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_NONE);
2475 else if (style == 1)
2477 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_LINES);
2478 if (doit == TRUE)
2479 nd->flags |= NODEFLAG_SKETCHLINES;
2481 else if (style == 2)
2483 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_GRAPH);
2484 if (doit == TRUE)
2485 nd->flags |= NODEFLAG_SKETCHGRAPH;
2488 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2490 gtk_widget_show(pix);
2491 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->sketchlines_tb), pix);
2494 void callback_color(GtkAction* action, MainView* mainview)
2496 g_assert(mainview != NULL && mainview->data != NULL);
2498 nodeData *nd = getSelectedNode(mainview);
2499 if (nd == NULL) return;
2501 HeSimpleColorDialog* dialog = HE_SIMPLE_COLOR_DIALOG(he_simple_color_dialog_new());
2502 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
2504 if (mainview->current_color) {
2505 he_simple_color_dialog_set_color(dialog, mainview->current_color);
2508 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
2509 gtk_widget_destroy(GTK_WIDGET(dialog));
2510 return;
2513 gdk_color_free(mainview->current_color);
2514 mainview->current_color = he_simple_color_dialog_get_color(dialog);
2516 gtk_widget_destroy(GTK_WIDGET(dialog));
2518 switch (nd->typ) {
2519 case NODE_SKETCH:
2520 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb), FALSE);
2521 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2522 break;
2523 case NODE_CHECKLIST:
2524 { /* Put in a separate block to allow new local variables */
2525 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2526 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2527 GList* selected = gtk_tree_selection_get_selected_rows(selection, NULL);
2529 gchar* color_string = g_strdup_printf("#%02x%02x%02x",
2530 mainview->current_color->red >> 8,
2531 mainview->current_color->green >> 8,
2532 mainview->current_color->blue >> 8);
2534 GList* cur = selected;
2535 while (cur != NULL) {
2536 GtkTreePath* path = cur->data;
2537 GtkTreeIter iter;
2538 if (gtk_tree_model_get_iter(model, &iter, path)) {
2539 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_COLOR, color_string, -1);
2541 gtk_tree_path_free(path);
2542 cur = cur->next;
2545 g_list_free(selected);
2546 g_free(color_string);
2548 break;
2549 default:
2550 g_assert_not_reached();
2554 void callback_color_invoke(GtkAction * action, gpointer data)
2556 MainView *mainview = (MainView *) data;
2557 g_assert(mainview != NULL && mainview->data != NULL);
2558 gtk_button_clicked(GTK_BUTTON(mainview->colorbutton_tb));
2563 void callback_pressure(GtkAction * action, MainView *mainview)
2565 g_assert(mainview != NULL && mainview->data != NULL);
2567 nodeData *nd = getSelectedNode(mainview);
2569 if (nd == NULL)
2570 return;
2571 if (nd->typ != NODE_SKETCH)
2572 return;
2574 /* pressure sensitivity disabled for now...
2575 mainview->sk->pressuresensitivity=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure));*/
2579 void callback_wordwrap(GtkWidget* widget, gpointer user_data)
2581 MainView* mainview = (MainView*)user_data;
2582 nodeData* nd = getSelectedNode(mainview);
2583 GtkWrapMode wrap_mode;
2585 if (nd == NULL || nd->typ != NODE_TEXT) {
2586 return;
2589 if (hildon_check_button_get_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap))) {
2590 nd->flags |= NODEFLAG_WORDWRAP;
2591 wrap_mode = GTK_WRAP_WORD_CHAR;
2592 } else {
2593 nd->flags &= ~NODEFLAG_WORDWRAP;
2594 wrap_mode = GTK_WRAP_NONE;
2597 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mainview->textview), wrap_mode);
2601 void callback_font(GtkAction * action, gpointer data)
2603 MainView *mainview = (MainView *) data;
2604 g_assert(mainview != NULL && mainview->data != NULL);
2606 nodeData *nd = getSelectedNode(mainview);
2608 if (nd == NULL)
2609 return;
2610 if (nd->typ != NODE_TEXT)
2611 return;
2613 HildonFontSelectionDialog *dialog = HILDON_FONT_SELECTION_DIALOG(hildon_font_selection_dialog_new(NULL, NULL));
2615 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2616 /*gotsel=FALSE;*/
2618 WPTextBufferFormat fmt;
2619 wp_text_buffer_get_attributes(mainview->buffer, &fmt, gotsel);
2621 gint ri=0;
2622 if (fmt.text_position==TEXT_POSITION_SUPERSCRIPT) ri=1;
2623 else if (fmt.text_position==TEXT_POSITION_SUBSCRIPT) ri=-1;
2625 g_object_set(G_OBJECT(dialog),
2626 "family-set", fmt.cs.font,
2627 "family", wp_get_font_name(fmt.font),
2628 "size-set", fmt.cs.font_size,
2629 "size", wp_font_size[fmt.font_size],
2630 "color-set", fmt.cs.color,
2631 "color", &fmt.color,
2632 "bold-set", fmt.cs.bold,
2633 "bold", fmt.bold,
2634 "italic-set", fmt.cs.italic,
2635 "italic", fmt.italic,
2636 "underline-set", fmt.cs.underline,
2637 "underline", fmt.underline,
2638 "strikethrough-set", fmt.cs.strikethrough,
2639 "strikethrough", fmt.strikethrough,
2640 "position-set", fmt.cs.text_position,
2641 "position", ri,
2642 NULL);
2644 gtk_widget_show_all(GTK_WIDGET(dialog));
2645 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2647 gboolean bold, italic, underline, strikethrough;
2648 gchar *family = NULL;
2649 gint size, position;
2650 GdkColor *color=NULL;
2651 gboolean set_family, set_size, set_bold, set_italic, set_underline, set_strikethrough, set_color, set_position;
2653 g_object_get(G_OBJECT(dialog), "family", &family, "size", &size, "bold", &bold, "italic", &italic,
2654 "underline", &underline, "strikethrough", &strikethrough,
2655 "family-set", &set_family, "size-set", &set_size, "bold-set", &set_bold, "italic-set", &set_italic,
2656 "underline-set", &set_underline, "strikethrough-set", &set_strikethrough,
2657 "color", &color, "color-set", &set_color, "position", &position, "position-set", &set_position,
2658 NULL);
2660 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE);
2661 fmt.cs.font=fmt.cs.font_size=fmt.cs.strikethrough=fmt.cs.color=fmt.cs.bold=fmt.cs.italic=fmt.cs.underline=fmt.cs.text_position=0;
2663 if (set_family) { fmt.font=wp_get_font_index(family, 1); fmt.cs.font=1; }
2664 if (set_size) { fmt.font_size=wp_get_font_size_index(size, 16); fmt.cs.font_size=1; }
2666 if (set_strikethrough)
2668 fmt.cs.strikethrough=1;
2669 fmt.strikethrough=strikethrough;
2672 if (set_color)
2675 GLIB WARNING ** GLib-GObject - IA__g_object_set_valist: object class `GtkTextTag' has no property named `'
2677 fmt.cs.color=1;
2678 fmt.color.pixel=color->pixel;
2679 fmt.color.red=color->red;
2680 fmt.color.green=color->green;
2681 fmt.color.blue=color->blue;
2684 if (set_position)
2686 if (position==1) ri=TEXT_POSITION_SUPERSCRIPT;
2687 else if (position==-1) ri=TEXT_POSITION_SUBSCRIPT;
2688 else ri=TEXT_POSITION_NORMAL;
2690 fmt.cs.text_position=1;
2691 fmt.text_position=ri;
2694 if (set_bold)
2696 fmt.cs.bold=1;
2697 fmt.bold=bold;
2699 if (set_italic)
2701 fmt.cs.italic=1;
2702 fmt.italic=italic;
2704 if (set_underline)
2706 fmt.cs.underline=1;
2707 fmt.underline=underline;
2710 wp_text_buffer_set_format(mainview->buffer, &fmt);
2713 gtk_widget_destroy(GTK_WIDGET(dialog));
2716 void callback_fontstyle(GtkAction * action, GtkWidget * wid)
2718 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2719 g_assert(mainview != NULL && mainview->data != NULL);
2721 nodeData *nd = getSelectedNode(mainview);
2723 if (nd == NULL)
2724 return;
2725 if (nd->typ == NODE_TEXT)
2727 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2729 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2730 wp_text_buffer_set_attribute(mainview->buffer, style, (gpointer)act);
2732 else if (nd->typ == NODE_CHECKLIST)
2734 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2735 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2736 if (style!=WPT_BOLD && style!=WPT_STRIKE && style!=WPT_LEFT) return;
2738 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2739 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
2741 gint styletoset_weight=PANGO_WEIGHT_NORMAL;
2742 gboolean styletoset_strike=FALSE;
2743 gboolean checkit=FALSE;
2745 if (style==WPT_BOLD && act==TRUE) styletoset_weight=PANGO_WEIGHT_BOLD;
2746 else if (style==WPT_STRIKE && act==TRUE) styletoset_strike=TRUE;
2747 else if (style==WPT_LEFT && act==TRUE) checkit=TRUE;
2749 GList* cur=l;
2750 while(cur)
2752 GtkTreePath *path=cur->data;
2754 GtkTreeIter iter;
2755 if (gtk_tree_model_get_iter(model, &iter, path))
2757 if (style==WPT_BOLD) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_BOLD, styletoset_weight, -1);
2758 else if (style==WPT_STRIKE) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_STRIKE, styletoset_strike, -1);
2759 else if (style==WPT_LEFT) {
2760 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_CHECKED, checkit, -1);
2761 if (checkit) {
2762 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
2763 } else {
2764 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, NULL, -1);
2768 gtk_tree_path_free(path);
2769 cur=cur->next;
2772 g_list_free(l);
2773 mainview->checklist_edited = TRUE;
2777 void
2778 callback_sharing(GtkWidget* widget, gpointer user_data)
2780 MainView* mainview = (MainView*)user_data;
2781 nodeData* nd = getSelectedNode(mainview);
2782 gchar* filename = g_strdup("/tmp/untitled.png");
2783 gchar* uri = NULL;
2785 if (nd == NULL || nd->typ != NODE_SKETCH) {
2786 show_banner(mainview, _("Only sketches can be shared"));
2787 return;
2790 if (nd->name != NULL) {
2791 g_free(filename);
2792 filename = g_strdup_printf("/tmp/%s.png", nd->name);
2795 busy_enter(mainview);
2796 GdkPixmap* skpix = sketchwidget_get_Pixmap(mainview->sk);
2797 GtkWidget* skdr = sketchwidget_get_drawingarea(mainview->sk);
2798 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL,
2799 GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0,
2800 skdr->allocation.width, skdr->allocation.height);
2802 if (pixbuf == NULL) {
2803 show_banner(mainview, _("Memo is empty"));
2804 goto cleanup;
2807 if (!gdk_pixbuf_save(pixbuf, filename, "png", NULL, NULL)) {
2808 show_banner(mainview, _("File export failed"));
2809 goto cleanup;
2812 uri = g_strdup_printf("file://%s", filename);
2814 sharing_dialog_with_file(mainview->data->osso,
2815 mainview_get_dialog_parent(mainview),
2816 uri);
2818 cleanup:
2819 g_object_unref(skpix);
2820 g_free(filename);
2821 g_free(uri);
2822 busy_leave(mainview);
2825 void
2826 callback_remove_checked(GtkWidget* widget, gpointer user_data)
2828 MainView* mainview = (MainView*)user_data;
2829 nodeData* nd = getSelectedNode(mainview);
2830 GtkTreeIter iter;
2831 GtkTreeModel* model = NULL;
2832 GList* checked_items = NULL;
2833 gchar* question = NULL;
2834 gint count = 0;
2836 if (nd == NULL || nd->typ != NODE_CHECKLIST) {
2837 return;
2840 /* Get a list of checked items */
2841 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2842 if (!gtk_tree_model_get_iter_first(model, &iter)) {
2843 return;
2846 busy_enter(mainview);
2847 do {
2848 gboolean checked = FALSE;
2849 gtk_tree_model_get(model, &iter, CHECKNODE_CHECKED, &checked, -1);
2851 if (checked) {
2852 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
2854 checked_items = g_list_append(checked_items,
2855 gtk_tree_row_reference_new(model, path));
2856 count++;
2858 gtk_tree_path_free(path);
2860 } while (gtk_tree_model_iter_next(model, &iter));
2861 busy_leave(mainview);
2863 if (checked_items == NULL) {
2864 show_banner(mainview, _("No checked items in checklist"));
2865 return;
2868 question = g_strdup_printf(N_("Remove %d checked item?", "Remove %d checked items?", count), count);
2869 if (show_confirmation(mainview, question)) {
2870 /* Remove the checklist items from the list */
2871 checklist_remove_rowrefs(mainview, checked_items, TRUE);
2872 } else {
2873 /* Free the allocated row references + list */
2874 GList* cur = checked_items;
2875 while (cur != NULL) {
2876 GtkTreeRowReference* rowref = cur->data;
2877 gtk_tree_row_reference_free(rowref);
2878 cur = cur->next;
2880 g_list_free(checked_items);
2882 g_free(question);
2885 void callback_textbuffer_move(WPTextBuffer *textbuffer, MainView *mainview)
2887 g_assert(mainview != NULL && mainview->data != NULL);
2890 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2892 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), gotsel);
2893 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), gotsel);
2894 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), gotsel);
2895 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), gotsel);
2897 WPTextBufferFormat fmt;
2898 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE/*gotsel*/);
2900 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
2901 g_signal_handlers_block_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
2902 g_signal_handlers_block_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
2903 g_signal_handlers_block_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
2905 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), fmt.bold);
2906 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), fmt.italic);
2907 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), fmt.underline);
2908 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), fmt.bullet);
2910 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
2911 g_signal_handlers_unblock_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
2912 g_signal_handlers_unblock_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
2913 g_signal_handlers_unblock_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
2916 gint wp_savecallback(const gchar *buffer, GString * gstr)
2918 gstr=g_string_append(gstr, buffer);
2919 return(0);
2922 void callback_undo(GtkAction * action, MainView * mainview)
2924 g_assert(mainview != NULL && mainview->data != NULL);
2926 nodeData *nd = getSelectedNode(mainview);
2928 if (nd == NULL) return;
2930 if (nd->typ == NODE_SKETCH) sketchwidget_undo(mainview->sk);
2931 else if (nd->typ == NODE_TEXT) wp_text_buffer_undo(mainview->buffer);
2934 void callback_redo(GtkAction * action, MainView * mainview)
2936 g_assert(mainview != NULL && mainview->data != NULL);
2938 nodeData *nd = getSelectedNode(mainview);
2940 if (nd == NULL) return;
2942 if (nd->typ == NODE_SKETCH) sketchwidget_redo(mainview->sk);
2943 else if (nd->typ == NODE_TEXT) wp_text_buffer_redo(mainview->buffer);
2946 void callback_undotoggle(gpointer widget, gboolean st, MainView * mainview)
2948 g_assert(mainview != NULL && mainview->data != NULL);
2950 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), st);
2953 void callback_redotoggle(gpointer widget, gboolean st, MainView * mainview)
2955 g_assert(mainview != NULL && mainview->data != NULL);
2957 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), st);
2960 gboolean close_cb(GtkWidget * widget, GdkEventAny * event, MainView * mainview)
2962 callback_file_close(NULL, mainview);
2963 return (TRUE);
2966 void
2967 mainview_click_on_current_node(MainView* mainview)
2969 GtkTreeSelection* selection = NULL;
2970 GtkTreeModel* model = NULL;
2971 GtkTreeIter iter;
2973 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
2974 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
2975 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
2977 mainview->can_show_node_view = TRUE;
2978 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
2979 path, NULL, FALSE);
2981 gtk_tree_path_free(path);
2985 gboolean
2986 on_main_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
2988 MainView* mainview = (MainView*)user_data;
2989 gboolean result = FALSE;
2990 gboolean visible = FALSE;
2992 g_object_get(G_OBJECT(mainview->main_view_live_search),
2993 "visible", &visible,
2994 NULL);
2996 if (visible) {
2997 /* Live search is active - only handle tree navigation */
2998 switch (event->keyval) {
2999 case GDK_KP_Enter:
3000 case GDK_Return:
3001 /* Open selected memo in node view */
3002 mainview_click_on_current_node(mainview);
3003 result = TRUE;
3004 break;
3005 case GDK_Down:
3006 /* Goto (=select) next memo */
3007 mainview->can_show_node_view = FALSE;
3008 nodelist_select(mainview, TREEVIEW_SELECT_NEXT);
3009 result = TRUE;
3010 break;
3011 case GDK_Up:
3012 /* Goto (=select) previous memo */
3013 mainview->can_show_node_view = FALSE;
3014 nodelist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3015 result = TRUE;
3016 break;
3017 default:
3018 break;
3021 /* Return early, so we don't handle normal input */
3022 return result;
3025 switch (event->keyval) {
3026 case GDK_KP_Enter:
3027 case GDK_Return:
3028 case GDK_l:
3029 case GDK_L:
3030 /* Open selected memo in node view */
3031 mainview_click_on_current_node(mainview);
3032 result = TRUE;
3033 break;
3034 case GDK_w:
3035 case GDK_W:
3036 /* Save changes to file ("write buffer") */
3037 callback_file_save(NULL, mainview);
3038 result = TRUE;
3039 break;
3040 case GDK_BackSpace:
3041 /* Delete selected node (with confirmation) */
3042 callback_file_delete_node(NULL, mainview);
3043 result = TRUE;
3044 break;
3045 case GDK_o:
3046 case GDK_O:
3047 /* Add new memo to list */
3048 callback_file_new_node(NULL, mainview);
3049 result = TRUE;
3050 break;
3051 case GDK_r:
3052 case GDK_R:
3053 /* Replace (edit) name of selected memo */
3054 callback_file_rename_node(NULL, mainview);
3055 result = TRUE;
3056 break;
3057 case GDK_g:
3058 if (mainview->main_view_prev_keyval == GDK_g) {
3059 /* Goto (=select) first memo */
3060 mainview->can_show_node_view = FALSE;
3061 nodelist_select(mainview, TREEVIEW_SELECT_FIRST);
3063 /* Don't remember this key for the next keypress */
3064 mainview->main_view_prev_keyval_reset = TRUE;
3066 result = TRUE;
3068 break;
3069 case GDK_G:
3070 /* Goto (=select) last memo */
3071 mainview->can_show_node_view = FALSE;
3072 nodelist_select(mainview, TREEVIEW_SELECT_LAST);
3073 result = TRUE;
3074 break;
3075 case GDK_j:
3076 case GDK_J:
3077 case GDK_Down:
3078 /* Goto (=select) next memo */
3079 mainview->can_show_node_view = FALSE;
3080 nodelist_select(mainview, TREEVIEW_SELECT_NEXT);
3081 result = TRUE;
3082 break;
3083 case GDK_k:
3084 case GDK_K:
3085 case GDK_Up:
3086 /* Goto (=select) previous memo */
3087 mainview->can_show_node_view = FALSE;
3088 nodelist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3089 result = TRUE;
3090 break;
3091 case GDK_slash:
3092 /* Start live search */
3093 gtk_widget_show(GTK_WIDGET(mainview->main_view_live_search));
3095 * TODO: It would be nice if we would focus the entry here
3096 * already, but the entry is private to HildonLiveSearch.
3098 * See Maemo bug 11458
3100 result = TRUE;
3101 break;
3102 default:
3103 /* Ignore keypress (consume it!) */
3104 result = TRUE;
3105 break;
3108 return result;
3111 gboolean
3112 on_node_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3114 MainView* mainview = (MainView*)user_data;
3115 nodeData* nd = getSelectedNode(mainview);
3116 gboolean result = FALSE;
3118 if (nd == NULL) {
3119 return FALSE;
3122 switch (event->keyval) {
3123 case GDK_w:
3124 case GDK_W:
3125 if (nd->typ != NODE_TEXT) {
3126 /* Save changes to file ("write buffer") */
3127 callback_file_save(NULL, mainview);
3128 result = TRUE;
3130 break;
3131 case GDK_BackSpace:
3132 if (event->state & GDK_SHIFT_MASK) {
3133 /* Remove current memo (with confirmation) */
3134 callback_file_delete_node(NULL, mainview);
3135 result = TRUE;
3136 } else if (nd->typ == NODE_CHECKLIST) {
3137 /* Remove current item (with confirmation) */
3138 callback_checklist_delete(NULL, mainview);
3139 result = TRUE;
3140 } else if (nd->typ == NODE_SKETCH) {
3141 /* Undo last sketch action */
3142 callback_undo(NULL, mainview);
3143 result = TRUE;
3145 break;
3146 case GDK_space:
3147 if (nd->typ == NODE_CHECKLIST) {
3148 /* Toggle check of current item */
3149 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3150 result = TRUE;
3151 } else if (nd->typ == NODE_SKETCH) {
3152 /* Toggle eraser tool */
3153 maepad_toggle_gtk_toggle_tool_button(mainview->eraser_tb);
3154 result = TRUE;
3156 break;
3157 case GDK_f:
3158 case GDK_F:
3159 if (nd->typ != NODE_TEXT) {
3160 /* Toggle fullscreen mode */
3161 callback_fullscreen(NULL, mainview);
3162 result = TRUE;
3164 break;
3165 case GDK_h:
3166 case GDK_H:
3167 if (nd->typ != NODE_TEXT) {
3168 /* Hide node view, go to main view ("left") */
3169 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
3170 result = TRUE;
3172 break;
3173 case GDK_o:
3174 case GDK_O:
3175 if (nd->typ == NODE_CHECKLIST) {
3176 /* Prepend if using uppercase "o" */
3177 mainview->checklist_prepend = ((event->keyval) == GDK_O);
3178 /* Insert new checklist item */
3179 callback_checklist_add(NULL, mainview);
3180 result = TRUE;
3182 break;
3183 case GDK_d:
3184 if (nd->typ == NODE_CHECKLIST) {
3185 if (mainview->node_view_prev_keyval == GDK_d) {
3186 /* Yank selected items, then remove them silently */
3187 callback_edit_copy(NULL, mainview);
3188 callback_checklist_delete_real(mainview);
3189 show_banner(mainview, _("Item yanked to clipboard"));
3191 /* Don't remember this key for the next keypress */
3192 mainview->node_view_prev_keyval_reset = TRUE;
3194 result = TRUE;
3197 break;
3198 case GDK_y:
3199 if (nd->typ == NODE_CHECKLIST) {
3200 if (mainview->node_view_prev_keyval == GDK_y) {
3201 /* Non-destructive yanking of items */
3202 callback_edit_copy(NULL, mainview);
3203 show_banner(mainview, _("Item yanked to clipboard"));
3205 /* Don't remember this key for the next keypress */
3206 mainview->node_view_prev_keyval_reset = TRUE;
3208 result = TRUE;
3211 break;
3212 case GDK_p:
3213 case GDK_P:
3214 if (nd->typ == NODE_CHECKLIST) {
3215 /* Prepend if using uppercase "P" */
3216 mainview->checklist_prepend = ((event->keyval) == GDK_P);
3217 /* Paste text in clipboard as items */
3218 callback_edit_paste(NULL, mainview);
3219 result = TRUE;
3221 break;
3222 case GDK_g:
3223 if (nd->typ == NODE_CHECKLIST) {
3224 if (mainview->node_view_prev_keyval == GDK_g) {
3225 /* Goto (=select) first item */
3226 checklist_select(mainview, TREEVIEW_SELECT_FIRST);
3228 /* Don't remember this key for the next keypress */
3229 mainview->node_view_prev_keyval_reset = TRUE;
3231 result = TRUE;
3234 break;
3235 case GDK_G:
3236 if (nd->typ == NODE_CHECKLIST) {
3237 /* Goto (=select) last item */
3238 checklist_select(mainview, TREEVIEW_SELECT_LAST);
3239 result = TRUE;
3241 break;
3242 case GDK_j:
3243 case GDK_J:
3244 case GDK_Down:
3245 if (nd->typ == NODE_CHECKLIST) {
3246 /* Goto (=select) next item */
3247 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
3248 result = TRUE;
3249 } else if (nd->typ == NODE_SKETCH) {
3250 /* Undo last sketch operation */
3251 callback_undo(NULL, mainview);
3252 result = TRUE;
3254 break;
3255 case GDK_k:
3256 case GDK_K:
3257 case GDK_Up:
3258 if (nd->typ == NODE_CHECKLIST) {
3259 /* Goto (=select) previous item */
3260 checklist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3261 result = TRUE;
3262 } else if (nd->typ == NODE_SKETCH) {
3263 /* Redo last sketch operation */
3264 callback_redo(NULL, mainview);
3265 result = TRUE;
3267 break;
3268 case GDK_a:
3269 case GDK_A:
3270 if (nd->typ == NODE_CHECKLIST) {
3271 /* Append text to current node */
3272 checklist_edit_selected(mainview, LINE_EDIT_MODE_APPEND);
3273 result = TRUE;
3275 break;
3276 case GDK_r:
3277 case GDK_R:
3278 case GDK_KP_Enter:
3279 case GDK_Return:
3280 if (nd->typ == NODE_CHECKLIST) {
3281 /* Replace (edit) text of current node */
3282 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
3283 result = TRUE;
3285 break;
3286 case GDK_i:
3287 case GDK_I:
3288 if (nd->typ == NODE_CHECKLIST) {
3289 /* Prepend (insert) text to current node */
3290 checklist_edit_selected(mainview, LINE_EDIT_MODE_PREPEND);
3291 result = TRUE;
3293 break;
3294 default:
3295 /* do nothing */
3296 break;
3299 return result;
3302 gboolean
3303 on_main_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3305 MainView* mainview = (MainView*)user_data;
3307 if (mainview->main_view_prev_keyval_reset) {
3308 /* Forget last-pressed key value */
3309 mainview->main_view_prev_keyval = GDK_VoidSymbol;
3310 mainview->main_view_prev_keyval_reset = FALSE;
3311 } else {
3312 /* Remember last keyval for double-press bindings */
3313 mainview->main_view_prev_keyval = event->keyval;
3316 return FALSE;
3319 gboolean
3320 on_node_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3322 MainView* mainview = (MainView*)user_data;
3324 if (mainview->node_view_prev_keyval_reset) {
3325 /* Forget last-pressed key value */
3326 mainview->node_view_prev_keyval = GDK_VoidSymbol;
3327 mainview->node_view_prev_keyval_reset = FALSE;
3328 } else {
3329 /* Remember last keyval for double-press bindings */
3330 mainview->node_view_prev_keyval = event->keyval;
3333 return FALSE;
3336 gboolean
3337 on_checklist_longpress_timeout(gpointer user_data)
3339 MainView* mainview = (MainView*)user_data;
3340 callback_checklist_edit(NULL, mainview);
3341 mainview->checklist_longpress_source_id = 0;
3342 return FALSE;
3345 gboolean
3346 on_checklist_button_press(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3348 MainView* mainview = (MainView*)user_data;
3349 GtkTreePath* path;
3350 GtkTreeViewColumn* column;
3351 GtkTreeSelection* selection;
3353 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
3354 event->x,
3355 event->y,
3356 &path,
3357 &column,
3358 NULL,
3359 NULL)) {
3360 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
3362 if (gtk_tree_selection_path_is_selected(selection, path)) {
3363 if (column == mainview->checklist_column_check) {
3364 /* Check column touched - toggle checklist item */
3365 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3366 } else if (column == mainview->checklist_column_text) {
3367 mainview->checklist_longpress_source_id = g_timeout_add(
3368 CHECKLIST_LONGPRESS_EDIT_DELAY,
3369 on_checklist_longpress_timeout,
3370 mainview);
3372 return TRUE;
3375 gtk_tree_path_free(path);
3378 return FALSE;
3381 void
3382 checklist_abort_longpress(MainView* mainview)
3384 /* Abort the longpress action on the checklist */
3385 if (mainview->checklist_longpress_source_id != 0) {
3386 g_source_remove(mainview->checklist_longpress_source_id);
3387 mainview->checklist_longpress_source_id = 0;
3391 gboolean
3392 on_checklist_button_release(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3394 MainView* mainview = (MainView*)user_data;
3395 checklist_abort_longpress(mainview);
3396 return FALSE;
3399 gboolean
3400 on_checklist_start_panning(HildonPannableArea* area, gpointer user_data)
3402 MainView* mainview = (MainView*)user_data;
3403 checklist_abort_longpress(mainview);
3404 return FALSE;
3407 void callback_fullscreen(GtkToolButton* tool_button, gpointer user_data)
3409 MainView* mainview = (MainView*)user_data;
3410 gtk_window_fullscreen(GTK_WINDOW(mainview->data->node_view));
3413 void
3414 callback_sketch_button_toggled(HildonCheckButton* button, gpointer user_data)
3416 MainView* mainview = (MainView*)user_data;
3417 gboolean active = hildon_check_button_get_active(button);
3419 if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_square)) {
3420 sketchwidget_set_shift(mainview->sk, active);
3421 } else if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_filled)) {
3422 sketchwidget_set_fillmode(mainview->sk, active);
3426 void callback_buffer_modified(GtkAction * action, gpointer data)
3428 MainView *mainview = (MainView *) data;
3429 g_assert(mainview != NULL && mainview->data != NULL);
3431 mainview->file_edited = TRUE;
3434 GtkTreeRowReference *read_sqlite3_data(MainView * mainview, unsigned int parentid, GtkTreeRowReference * parenttree, unsigned int selected, GtkTreeStore * model)
3436 GtkTreeRowReference *resref = NULL;
3438 char q[256];
3440 g_snprintf(q, sizeof(q), "SELECT nodeid, bodytype, name, nameblob, lastmodified, flags FROM %s WHERE parent=%d ORDER BY ord", datatable_tmpname, parentid);
3442 sqlite3_stmt *stmt = NULL;
3443 const char *dum;
3444 int rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3446 if (rc)
3448 maepad_warning("Error reading SQLite3 data: %s", sqlite3_errmsg(mainview->db));
3449 return (NULL);
3452 rc = SQLITE_BUSY;
3453 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3455 rc = sqlite3_step(stmt);
3456 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3457 break;
3458 else if (rc == SQLITE_ROW)
3460 int nodeid = sqlite3_column_int(stmt, 0);
3461 int typ = sqlite3_column_int(stmt, 1);
3462 const unsigned char *name = sqlite3_column_text(stmt, 2);
3463 const unsigned char *nameblob = sqlite3_column_text(stmt, 3);
3464 int lastmod = sqlite3_column_int(stmt, 4);
3465 int flags = sqlite3_column_int(stmt, 5);
3467 if ((typ != NODE_TEXT && typ != NODE_SKETCH && typ != NODE_CHECKLIST) || (name == NULL && nameblob == NULL)) {
3468 maepad_warning("Unknown node type in database: %d (skipping)", typ);
3469 continue;
3472 nodeData *node = g_malloc(sizeof(nodeData));
3474 node->sql3id = nodeid;
3475 node->typ = typ;
3476 node->flags = flags;
3477 node->name = NULL;
3478 node->namepix = NULL;
3479 if (name != NULL) {
3480 node->name = g_strdup((char *)name);
3481 } else {
3482 node->name = g_strdup(_("Unnamed memo"));
3484 /*if (nameblob != NULL)
3486 int blobsize = sqlite3_column_bytes(stmt, 3);
3488 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
3489 GError *err = NULL;
3491 gdk_pixbuf_loader_write(pl, (guchar *) nameblob, blobsize, &err);
3492 if (err != NULL)
3494 fprintf(stderr, "Error loading nodename! %s\n", err->message);
3495 g_error_free(err);
3496 err = NULL;
3498 gdk_pixbuf_loader_close(pl, NULL);
3499 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
3501 if (GDK_IS_PIXBUF(pixbuf))
3502 node->namepix = pixbuf;
3504 node->lastMod = lastmod;
3506 GtkTreeIter parentiter, newiter;
3507 void *par = NULL;
3509 if (parenttree != NULL)
3511 GtkTreePath *pa = gtk_tree_row_reference_get_path(parenttree);
3513 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parentiter, pa);
3514 gtk_tree_path_free(pa);
3515 par = &parentiter;
3518 gtk_tree_store_append(model, &newiter, par);
3519 gtk_tree_store_set(model, &newiter, NODE_NAME, format_overview_name(node, NULL), NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
3521 GtkTreePath *pa = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &newiter);
3523 GtkTreeRowReference *newref = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), pa);
3525 if (selected == nodeid)
3526 resref = newref;
3528 gtk_tree_path_free(pa);
3529 GtkTreeRowReference *r = read_sqlite3_data(mainview, nodeid, newref, selected,
3530 model);
3532 if (resref != newref)
3533 gtk_tree_row_reference_free(newref);
3535 if (r != NULL)
3537 if (resref == NULL)
3538 resref = r;
3539 else
3540 gtk_tree_row_reference_free(r); /*safeguard */
3545 if (stmt)
3546 sqlite3_finalize(stmt);
3548 return (resref); /*ref to supposed-to-be-selected treeitem */
3552 * read file
3554 gboolean read_file_to_buffer(MainView * mainview)
3556 char tq[512];
3558 g_assert(mainview != NULL);
3559 gboolean res = FALSE;
3561 gchar *filename = mainview->file_name;
3563 new_file(mainview);
3564 mainview->file_name = filename;
3565 mainview->loading=TRUE;
3567 maepad_message("Reading database file: %s", filename);
3569 int rc;
3570 sqlite3_stmt *stmt = NULL;
3572 rc = sqlite3_open(filename, &mainview->db);
3575 if (rc)
3577 maepad_warning("Cannot open database %s: %s", filename, sqlite3_errmsg(mainview->db));
3578 break;
3581 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
3583 char *q = "SELECT skey, sval FROM settings";
3584 const char *dum;
3586 rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3587 if (rc)
3589 maepad_warning("Error reading settings: %s", sqlite3_errmsg(mainview->db));
3590 break;
3593 unsigned int selectedCard = 0;
3594 unsigned int curDataVersion = 0;
3595 unsigned int curChecklistVersion = 0;
3597 rc = SQLITE_BUSY;
3598 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3600 rc = sqlite3_step(stmt);
3601 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3602 break;
3603 else if (rc == SQLITE_ROW)
3605 const gchar* col_key = (const gchar*)sqlite3_column_text(stmt, 0);
3606 const gchar* col_val = (const gchar*)sqlite3_column_text(stmt, 1);
3607 if (!strcmp(col_key, "selectedNode"))
3609 gint tmp = atoi((char *)col_val);
3611 if (tmp > 0)
3612 selectedCard = tmp;
3614 if (!strcmp(col_key, "dataVersion"))
3616 gint tmp = atoi((char *)col_val);
3618 if (tmp > 0)
3619 curDataVersion = tmp;
3621 if (!strcmp(col_key, "checklistVersion"))
3623 gint tmp = atoi((char *)col_val);
3625 if (tmp > 0)
3626 curChecklistVersion = tmp;
3628 if (!strcmp(col_key, "newNodeDlgCreateChild"))
3630 gint tmp = atoi((char *)col_val);
3632 mainview->newnodedialog_createchild = TRUE;
3633 if (tmp == 0)
3634 mainview->newnodedialog_createchild = FALSE;
3636 if (!strcmp(col_key, "brushSize"))
3638 gint tmp = atoi((char *)col_val);
3639 if (tmp>0) sk_set_brushsize(mainview, tmp);
3641 if (!strcmp(col_key, "brushColor"))
3643 unsigned long tmp = atol((char *)col_val);
3644 GdkColor c2;
3646 c2.red = ((tmp & 0xFF0000) >> 16) << 8;
3647 c2.green = ((tmp & 0xFF00) >> 8) << 8;
3648 c2.blue = (tmp & 0xFF) << 8;
3649 sketchwidget_set_brushcolor(mainview->sk, c2);
3651 if (mainview->current_color != NULL) {
3652 gdk_color_free(mainview->current_color);
3654 mainview->current_color = gdk_color_copy(&c2);
3659 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
3661 maepad_warning("Error reading data: %s", sqlite3_errmsg(mainview->db));
3662 break;
3665 if (stmt) {
3666 sqlite3_finalize(stmt);
3667 stmt = NULL;
3670 gboolean resback = FALSE;
3672 while(curDataVersion < datatableversion)
3674 if (curDataVersion == 0)
3676 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3677 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3679 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_name, datatable_backupname);
3680 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3681 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3682 break;
3684 resback = TRUE;
3686 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
3687 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3688 maepad_warning("Error creating table: %s", datatable_name);
3689 break;
3691 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT nodeid, parent, bodytype, name, body, nameblob, bodyblob, lastmodified, ord, 0 FROM %s", datatable_name, datatable_backupname);
3692 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3693 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_backupname);
3694 break;
3697 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3698 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3700 curDataVersion = datatableversion;
3702 break;
3705 if (curDataVersion != datatableversion)
3707 maepad_warning("Data table version mismatch: %d <=> %d", curDataVersion, datatableversion);
3709 if (resback == TRUE)
3711 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_name);
3712 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3713 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_backupname, datatable_name);
3714 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3717 break;
3721 while(curChecklistVersion < checklisttableversion)
3723 if (curChecklistVersion == 0) /*no checklisttable at all*/
3725 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
3726 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3727 maepad_warning("Error creating checklist table during schema upgrade");
3728 break;
3730 curChecklistVersion = checklisttableversion;
3732 break;
3736 GtkTreeStore *filter = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
3738 g_object_ref(filter);
3739 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
3743 char tq[512];
3745 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, datatable_tmpname, datatable);
3746 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3747 maepad_warning("Error creating temp table: %s", datatable_tmpname);
3748 break;
3750 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", datatable_tmpname, datatable_tmpname, dataindex);
3751 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3752 maepad_warning("Error creating temp index for %s", datatable_tmpname);
3753 break;
3755 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_tmpname, datatable_name);
3756 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3757 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_tmpname);
3758 break;
3761 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, checklisttable_tmpname, checklisttable);
3762 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3763 maepad_warning("Error creating temp table: %s", checklisttable_tmpname);
3764 break;
3766 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", checklisttable_tmpname, checklisttable_tmpname, checklistindex);
3767 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3768 maepad_warning("Error creating temp index for %s", checklisttable_tmpname);
3769 break;
3771 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_tmpname, checklisttable_name);
3772 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3773 maepad_warning("Error copying data from %s to %s", checklisttable_name, checklisttable_tmpname);
3774 break;
3777 while(FALSE);
3779 read_sqlite3_data(mainview, 0, NULL, selectedCard, mainview->main_view_tree_store);
3781 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), GTK_TREE_MODEL(filter));
3782 g_object_unref(filter);
3783 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
3785 res = TRUE;
3787 while(FALSE);
3789 if (stmt) {
3790 sqlite3_finalize(stmt);
3794 mainview->loading=FALSE;
3796 return (res);
3800 * write to file
3802 void write_buffer_to_file(MainView * mainview)
3804 maepad_message("Writing database to file: %s", mainview->file_name);
3805 saveCurrentData(mainview);
3807 /*update ord value in database for all nodes*/
3808 gtk_tree_model_foreach(GTK_TREE_MODEL(mainview->main_view_tree_store),
3809 (GtkTreeModelForeachFunc)foreach_func_update_ord, mainview);
3811 busy_enter(mainview);
3813 char tq[512];
3815 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", misctable_name);
3816 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3818 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
3819 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3821 gint nndcc = 1;
3823 if (mainview->newnodedialog_createchild == FALSE)
3824 nndcc = 0;
3825 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('newNodeDlgCreateChild', '%d');", misctable_name, nndcc);
3826 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3828 nodeData *node = getSelectedNode(mainview);
3830 if (node)
3832 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('selectedNode', '%d');", misctable_name, node->sql3id);
3833 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3836 guint bsize = sketchwidget_get_brushsize(mainview->sk);
3837 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushSize', '%d');", misctable_name, bsize);
3838 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3840 if (mainview->current_color == NULL) {
3841 GdkColor color = {0, 0, 0, 0};
3842 mainview->current_color = gdk_color_copy(&color);
3844 unsigned long bcol = ((mainview->current_color->red >> 8) << 16) |
3845 ((mainview->current_color->green >> 8) << 8) |
3846 ((mainview->current_color->blue) >> 8);
3848 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushColor', '%lu');", misctable_name, bcol);
3849 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3851 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('dataVersion', '%d');", misctable_name, datatableversion);
3852 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3854 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('checklistVersion', '%d');", misctable_name, checklisttableversion);
3855 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3857 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3858 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3859 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_backupname, datatable);
3860 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3862 maepad_warning("Error creating backup table: %s", datatable_backupname);
3863 show_banner(mainview, _("Error creating backup table"));
3865 busy_leave(mainview);
3866 return;
3868 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_backupname, datatable_name);
3869 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3871 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3872 show_banner(mainview, _("Error creating backup table"));
3874 busy_leave(mainview);
3875 return;
3877 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3878 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3880 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_tmpname);
3881 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3883 maepad_warning("Error saving table %s to %s", datatable_tmpname, datatable_name);
3884 show_banner(mainview, _("Error saving table"));
3886 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3887 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3889 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_backupname);
3890 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3891 maepad_warning("Error restoring backup. Data lost :(");
3894 busy_leave(mainview);
3895 return;
3898 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3899 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3901 /*checklist*/
3902 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3903 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3904 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_backupname, checklisttable);
3905 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3907 maepad_warning("Error creating backup table: %s", checklisttable_backupname);
3908 show_banner(mainview, _("Error creating checklist backup table"));
3910 busy_leave(mainview);
3911 return;
3914 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_backupname, checklisttable_name);
3915 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3917 maepad_warning("Error backing up table %s to %s", checklisttable_name, checklisttable_backupname);
3918 show_banner(mainview, _("Error creating checklist backup table"));
3920 busy_leave(mainview);
3921 return;
3923 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3924 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3926 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_tmpname);
3927 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3929 maepad_warning("Error saving table %s to %s", checklisttable_tmpname, checklisttable_name);
3930 show_banner(mainview, _("Error saving checklist table"));
3932 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3933 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3935 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_backupname);
3936 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3937 maepad_warning("Error restoring backup. Data lost :(");
3939 busy_leave(mainview);
3940 return;
3943 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3944 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3946 mainview->file_edited = FALSE;
3947 busy_leave(mainview);
3948 show_banner(mainview, _("Changes saved"));
3951 void callback_checklist_change(GtkTreeSelection *selection, MainView *mainview)
3953 GtkTreeIter iter;
3955 g_assert(mainview != NULL && mainview->data != NULL);
3957 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3958 g_signal_handlers_block_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
3959 g_signal_handlers_block_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
3961 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), FALSE);
3962 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), FALSE);
3963 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), FALSE);
3965 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
3967 if (gtk_tree_model_get_iter_first(model, &iter)) {
3968 gtk_widget_show(mainview->listscroll);
3969 gtk_widget_hide(mainview->checklist_empty_label);
3970 } else {
3971 gtk_widget_hide(mainview->listscroll);
3972 gtk_widget_show(mainview->checklist_empty_label);
3975 GList* l=gtk_tree_selection_get_selected_rows(selection, NULL);
3977 gboolean gotit=FALSE;
3979 GList* cur=l;
3980 while(cur)
3982 GtkTreePath *path=cur->data;
3984 if (!gotit)
3986 GtkTreeIter iter;
3987 if (gtk_tree_model_get_iter(model, &iter, path))
3989 gint styletoset_weight;
3990 gboolean styletoset_strike;
3991 gboolean ischecked;
3993 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, -1);
3994 if (styletoset_weight==PANGO_WEIGHT_BOLD) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), TRUE);
3995 if (styletoset_strike==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), TRUE);
3996 if (ischecked==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), TRUE);
3997 gotit=TRUE;
4000 gtk_tree_path_free(path);
4001 cur=cur->next;
4004 g_list_free(l);
4006 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
4007 g_signal_handlers_unblock_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
4008 g_signal_handlers_unblock_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
4011 void callback_checklist_paste(MainView *mainview)
4013 g_assert(mainview != NULL && mainview->data != NULL);
4014 gchar **entries;
4015 gboolean append = FALSE;
4016 guint i;
4018 gchar *pasted_text = gtk_clipboard_wait_for_text(mainview->clipboard);
4019 entries = g_strsplit(pasted_text, "\n", 0);
4021 GtkTreeSelection *selection;
4022 GtkTreeModel *model;
4023 GtkTreeIter current, insert;
4025 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4026 if (gtk_tree_selection_get_selected(selection, &model, &current)) {
4027 /* Insert after current (selected) item */
4028 append = FALSE;
4029 } else {
4030 /* Insert at end */
4031 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4032 append = TRUE;
4035 for (i=0; i<g_strv_length(entries); i++) {
4036 if (append) {
4037 gtk_list_store_append(GTK_LIST_STORE(model),
4038 &insert);
4039 } else {
4040 if (i == 0 && mainview->checklist_prepend) {
4041 gtk_list_store_insert_before(GTK_LIST_STORE(model),
4042 &insert,
4043 &current);
4044 } else {
4045 gtk_list_store_insert_after(GTK_LIST_STORE(model),
4046 &insert,
4047 &current);
4049 current = insert;
4052 gtk_list_store_set(GTK_LIST_STORE(model),
4053 &insert,
4054 CHECKNODE_CHECKED, FALSE,
4055 CHECKNODE_TEXT, entries[i],
4056 -1);
4059 mainview->checklist_edited = TRUE;
4061 g_strfreev(entries);
4062 g_free(pasted_text);
4065 void callback_checklist_add(GtkAction *action, MainView *mainview)
4067 g_assert(mainview != NULL && mainview->data != NULL);
4069 if (action != NULL) {
4070 /* If coming from the tool button, always append */
4071 mainview->checklist_prepend = FALSE;
4074 gchar* text = show_line_edit_dialog(mainview, _("Add new checklist item"), _("Name:"), _("Add"), "");
4076 if (text != NULL) {
4077 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4078 GtkTreeModel *model;
4079 GtkTreeIter current, insert;
4081 if (gtk_tree_selection_get_selected(selection, &model, &current)) {
4082 /* Something is selected */
4083 if (mainview->checklist_prepend) {
4084 /* User wants to insert before current item */
4085 gtk_list_store_insert_before(GTK_LIST_STORE(model),
4086 &insert,
4087 &current);
4088 } else {
4089 /* User wants to insert after current item */
4090 gtk_list_store_insert_after(GTK_LIST_STORE(model),
4091 &insert,
4092 &current);
4094 } else {
4095 /* Nothing is selected - just append at the end */
4096 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4097 gtk_list_store_append(GTK_LIST_STORE(model), &insert);
4100 gtk_list_store_set(GTK_LIST_STORE(model),
4101 &insert,
4102 CHECKNODE_CHECKED, FALSE,
4103 CHECKNODE_TEXT, text,
4104 -1);
4106 GtkTreePath *path = gtk_tree_model_get_path(model, &insert);
4107 if (path) {
4108 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->listview), path, mainview->checklist_column_text, FALSE);
4109 gtk_tree_path_free(path);
4112 mainview->checklist_edited = TRUE;
4116 void
4117 checklist_edit_selected(MainView* mainview, LineEditMode mode)
4119 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4121 if (gtk_tree_selection_count_selected_rows(selection) == 0) {
4122 show_banner(mainview, _("Select items first"));
4123 return;
4126 GtkTreeModel* model;
4127 GtkTreeIter iter;
4129 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4130 gchar* old_text = NULL;
4131 gtk_tree_model_get(model, &iter, CHECKNODE_TEXT, &old_text, -1);
4133 gchar* new_text = show_line_edit_dialog_full(mainview, _("Edit checklist item"), _("New name:"), _("Save"), old_text, mode);
4135 if (new_text != NULL) {
4136 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_TEXT, new_text, -1);
4137 mainview->checklist_edited = TRUE;
4138 g_free(new_text);
4141 g_free(old_text);
4145 void callback_checklist_edit(GtkAction *action, MainView *mainview)
4147 g_assert(mainview != NULL && mainview->data != NULL);
4148 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
4151 void callback_checklist_delete(GtkAction *action, MainView *mainview)
4153 g_assert(mainview != NULL && mainview->data != NULL);
4155 if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)))==0) {
4156 show_banner(mainview, _("Select items first"));
4157 return;
4160 if (show_confirmation(mainview, _("Delete selected checklist item?"))) {
4161 callback_checklist_delete_real(mainview);
4165 void callback_checklist_delete_real(MainView* mainview)
4167 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4168 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
4170 /* Select the item after the selection */
4171 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
4173 GList* rowrefs=NULL;
4174 GList* cur=l;
4175 while(cur)
4177 GtkTreePath *path=cur->data;
4179 GtkTreeIter iter;
4180 if (gtk_tree_model_get_iter(model, &iter, path))
4182 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, path);
4183 rowrefs=g_list_append(rowrefs, rowref);
4185 gtk_tree_path_free(path);
4186 cur=cur->next;
4188 g_list_free(l);
4189 checklist_remove_rowrefs(mainview, rowrefs, FALSE);
4192 void
4193 checklist_remove_rowrefs(MainView* mainview, GList* rowrefs, gboolean show_result)
4195 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4196 GList* cur = rowrefs;
4197 gint count = 0;
4199 busy_enter(mainview);
4201 while (cur) {
4202 GtkTreeRowReference* rowref = cur->data;
4203 GtkTreePath* path = gtk_tree_row_reference_get_path(rowref);
4204 if (path != NULL) {
4205 GtkTreeIter iter;
4206 if (gtk_tree_model_get_iter(model, &iter, path)) {
4207 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
4208 count++;
4210 gtk_tree_path_free(path);
4212 gtk_tree_row_reference_free(rowref);
4213 cur = cur->next;
4215 g_list_free(rowrefs);
4217 busy_leave(mainview);
4219 if (count && show_result) {
4220 gchar* message = g_strdup_printf(N_("%d item removed", "%d items removed", count), count);
4221 show_banner(mainview, message);
4222 g_free(message);
4225 mainview->checklist_edited = TRUE;
4228 /* Private callback for show_confirmation() - handle keyboard input */
4229 gboolean
4230 on_confirmation_key_press_event(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
4232 GtkDialog* dialog = GTK_DIALOG(widget);
4234 switch (event->keyval) {
4235 /* Positive response - Enter, Return or y */
4236 case GDK_KP_Enter:
4237 case GDK_Return:
4238 case GDK_y:
4239 case GDK_Y:
4240 gtk_dialog_response(dialog, GTK_RESPONSE_OK);
4241 return TRUE;
4243 /* Negative response - Backspace, Escape or n */
4244 case GDK_BackSpace:
4245 case GDK_Escape:
4246 case GDK_n:
4247 case GDK_N:
4248 gtk_dialog_response(dialog, GTK_RESPONSE_CANCEL);
4249 return TRUE;
4251 /* Don't handle the rest of the keys */
4252 default:
4253 return FALSE;
4258 /* Ask the user for confirmation of a specific action */
4259 gboolean
4260 show_confirmation(MainView* mainview, gchar* question)
4262 GtkDialog* dialog = GTK_DIALOG(hildon_note_new_confirmation(
4263 GTK_WINDOW(mainview->data->main_view), question));
4264 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
4265 g_signal_connect(G_OBJECT(dialog), "key-press-event",
4266 G_CALLBACK(on_confirmation_key_press_event), NULL);
4268 gint response = gtk_dialog_run(dialog);
4269 gtk_widget_destroy(GTK_WIDGET(dialog));
4271 return (response == GTK_RESPONSE_OK);
4274 /* Show a information banner to the user (non-modal) */
4275 void
4276 show_banner(MainView* mainview, const gchar* text)
4278 hildon_banner_show_information(GTK_WIDGET(mainview_get_dialog_parent(mainview)), NULL, text);
4281 typedef struct {
4282 GtkWidget* dialog;
4283 gboolean can_close_window;
4284 } LineEditDialogData;
4286 /* Helper function to close line edit dialog on Backspace */
4287 gboolean
4288 line_edit_dialog_key_press(GtkWidget* w, GdkEventKey* event, gpointer user_data)
4290 LineEditDialogData* dialogdata = (LineEditDialogData*)user_data;
4291 GtkEntry* entry = GTK_ENTRY(w);
4293 if (event->keyval == GDK_BackSpace &&
4294 dialogdata->can_close_window &&
4295 strcmp(gtk_entry_get_text(entry), "") == 0) {
4296 gtk_dialog_response(GTK_DIALOG(dialogdata->dialog), GTK_RESPONSE_CANCEL);
4297 return TRUE;
4300 return FALSE;
4303 /* Let the user enter or edit a line of text */
4304 gchar*
4305 show_line_edit_dialog_full(MainView* mainview, const gchar* title,
4306 const gchar* label_text, const gchar* action, const gchar* text,
4307 LineEditMode mode)
4309 GtkWidget* edit_dialog;
4310 GtkWidget* label;
4311 GtkWidget* entry;
4312 GtkWidget* hbox;
4313 gchar* result = NULL;
4314 LineEditDialogData dialogdata;
4316 edit_dialog = GTK_WIDGET(gtk_dialog_new());
4317 gtk_window_set_title(GTK_WINDOW(edit_dialog), title);
4318 gtk_window_set_transient_for(GTK_WINDOW(edit_dialog), mainview_get_dialog_parent(mainview));
4320 label = GTK_WIDGET(gtk_label_new(label_text));
4322 entry = hildon_entry_new(HILDON_SIZE_AUTO);
4323 gtk_entry_set_text(GTK_ENTRY(entry), text);
4324 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
4325 switch (mode) {
4326 case LINE_EDIT_MODE_DEFAULT:
4327 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
4328 break;
4329 case LINE_EDIT_MODE_APPEND:
4330 gtk_editable_select_region(GTK_EDITABLE(entry), -1, -1);
4331 break;
4332 case LINE_EDIT_MODE_PREPEND:
4333 gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
4334 break;
4335 default:
4336 break;
4339 gtk_dialog_add_button(GTK_DIALOG(edit_dialog), action, GTK_RESPONSE_OK);
4340 gtk_dialog_set_default_response(GTK_DIALOG(edit_dialog), GTK_RESPONSE_OK);
4342 dialogdata.dialog = edit_dialog;
4343 dialogdata.can_close_window = (strcmp(text, "") == 0);
4344 g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(line_edit_dialog_key_press), &dialogdata);
4346 hbox = GTK_WIDGET(gtk_hbox_new(FALSE, 10));
4348 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(edit_dialog))), GTK_WIDGET(hbox));
4349 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
4350 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
4352 gtk_widget_show_all(GTK_WIDGET(hbox));
4354 while (TRUE) {
4355 if (gtk_dialog_run(GTK_DIALOG(edit_dialog)) == GTK_RESPONSE_OK) {
4356 result = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
4357 if (strcmp(result, "") != 0) {
4358 break;
4359 } else {
4360 show_banner(mainview, _("Please enter a non-empty text"));
4361 g_free(result);
4362 result = NULL;
4364 } else {
4365 result = NULL;
4366 break;
4370 gtk_widget_destroy(GTK_WIDGET(edit_dialog));
4371 return result;
4374 void
4375 treeview_scroll_to_selection(MainView* mainview, TreeViewType type)
4377 GtkTreeView* treeview = NULL;
4378 HildonPannableArea* pannable_area = NULL;
4379 GtkTreeModel* model = NULL;
4380 GtkTreeSelection* selection = NULL;
4381 GtkTreePath* path = NULL;
4382 GtkTreeIter iter;
4383 GdkRectangle rect;
4384 gint y;
4386 switch (type) {
4387 case TREEVIEW_MAINVIEW:
4388 treeview = GTK_TREE_VIEW(mainview->treeview);
4389 pannable_area = HILDON_PANNABLE_AREA(mainview->scrolledtree);
4390 break;
4391 case TREEVIEW_CHECKLIST:
4392 treeview = GTK_TREE_VIEW(mainview->listview);
4393 pannable_area = HILDON_PANNABLE_AREA(mainview->listscroll);
4394 break;
4395 default:
4396 g_assert_not_reached();
4397 break;
4400 /* Let the view scroll so that the selected item is visible */
4401 selection = gtk_tree_view_get_selection(treeview);
4402 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4403 path = gtk_tree_model_get_path(model, &iter);
4405 gtk_tree_view_get_background_area(treeview, path, NULL, &rect);
4406 gtk_tree_view_convert_bin_window_to_tree_coords(treeview,
4407 0, rect.y, NULL, &y);
4408 hildon_pannable_area_scroll_to(pannable_area, -1, y);
4410 gtk_tree_path_free(path);
4414 gboolean
4415 checklist_scroll_to_selection(gpointer user_data)
4417 MainView* mainview = (MainView*)user_data;
4418 treeview_scroll_to_selection(mainview, TREEVIEW_CHECKLIST);
4419 return FALSE;
4422 gboolean
4423 nodelist_scroll_to_selection(gpointer user_data)
4425 MainView* mainview = (MainView*)user_data;
4426 treeview_scroll_to_selection(mainview, TREEVIEW_MAINVIEW);
4427 return FALSE;
4430 void
4431 checklist_select(MainView* mainview, TreeviewSelectType type)
4433 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4434 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4435 GtkTreeIter iter;
4436 GtkTreeIter last;
4437 GtkTreePath* path;
4439 switch (type) {
4440 case TREEVIEW_SELECT_FIRST:
4441 if (gtk_tree_model_get_iter_first(model, &iter)) {
4442 path = gtk_tree_model_get_path(model, &iter);
4443 gtk_tree_selection_select_path(selection, path);
4444 gtk_tree_path_free(path);
4446 break;
4447 case TREEVIEW_SELECT_LAST:
4448 if (gtk_tree_model_get_iter_first(model, &iter)) {
4449 do {
4450 last = iter;
4451 } while (gtk_tree_model_iter_next(model, &iter));
4452 path = gtk_tree_model_get_path(model, &last);
4453 gtk_tree_selection_select_path(selection, path);
4454 gtk_tree_path_free(path);
4456 break;
4457 case TREEVIEW_SELECT_PREVIOUS:
4458 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4459 path = gtk_tree_model_get_path(model, &iter);
4460 if (gtk_tree_path_prev(path)) {
4461 gtk_tree_selection_select_path(selection, path);
4463 gtk_tree_path_free(path);
4465 break;
4466 case TREEVIEW_SELECT_NEXT:
4467 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4468 path = gtk_tree_model_get_path(model, &iter);
4469 gtk_tree_path_next(path);
4470 gtk_tree_selection_select_path(selection, path);
4471 gtk_tree_path_free(path);
4473 break;
4474 default:
4475 g_assert_not_reached();
4476 break;
4479 checklist_scroll_to_selection(mainview);
4482 * This is a workaround: The HildonPannableArea does not seem to
4483 * scroll to the right position (especially when going to the first
4484 * or last item in the list), so we simply scroll again after 500ms.
4486 g_timeout_add(500, checklist_scroll_to_selection, mainview);
4489 void
4490 nodelist_select(MainView* mainview, TreeviewSelectType type)
4492 GtkTreeView* treeview = GTK_TREE_VIEW(mainview->treeview);
4493 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
4494 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
4495 GtkTreeIter iter;
4496 GtkTreeIter last;
4497 GtkTreeIter child;
4498 GtkTreePath* path;
4500 switch (type) {
4501 case TREEVIEW_SELECT_FIRST:
4502 if (gtk_tree_model_get_iter_first(model, &iter)) {
4503 path = gtk_tree_model_get_path(model, &iter);
4504 gtk_tree_selection_select_path(selection, path);
4505 gtk_tree_path_free(path);
4507 break;
4508 case TREEVIEW_SELECT_LAST:
4509 if (gtk_tree_model_get_iter_first(model, &iter)) {
4510 do {
4511 last = iter;
4512 if (gtk_tree_model_iter_children(model, &child, &last)) {
4513 do {
4514 last = child;
4515 } while (gtk_tree_model_iter_next(model, &child));
4517 } while (gtk_tree_model_iter_next(model, &iter));
4518 path = gtk_tree_model_get_path(model, &last);
4519 gtk_tree_selection_select_path(selection, path);
4520 gtk_tree_path_free(path);
4522 break;
4523 case TREEVIEW_SELECT_PREVIOUS:
4524 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4525 path = gtk_tree_model_get_path(model, &iter);
4526 if (gtk_tree_path_prev(path)) {
4527 gtk_tree_selection_select_path(selection, path);
4528 } else if (gtk_tree_path_up(path)) {
4529 gtk_tree_selection_select_path(selection, path);
4531 gtk_tree_path_free(path);
4532 } else {
4533 nodelist_select(mainview, TREEVIEW_SELECT_FIRST);
4535 break;
4536 case TREEVIEW_SELECT_NEXT:
4537 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4538 path = gtk_tree_model_get_path(model, &iter);
4539 gtk_tree_path_down(path);
4540 while (!gtk_tree_model_get_iter(model, &iter, path)) {
4541 /* Child item does not exist - bubble up to next item */
4542 gtk_tree_path_up(path);
4543 gtk_tree_path_next(path);
4545 if (gtk_tree_path_get_depth(path) == 0) {
4546 /* avoid infinite loops */
4547 break;
4551 if (gtk_tree_model_get_iter(model, &iter, path)) {
4552 gtk_tree_selection_select_path(selection, path);
4555 gtk_tree_path_free(path);
4556 } else {
4557 nodelist_select(mainview, TREEVIEW_SELECT_FIRST);
4559 break;
4560 default:
4561 g_assert_not_reached();
4562 break;
4565 nodelist_scroll_to_selection(mainview);
4568 * This is a workaround: The HildonPannableArea does not seem to
4569 * scroll to the right position (especially when going to the first
4570 * or last item in the list), so we simply scroll again after 500ms.
4572 g_timeout_add(500, nodelist_scroll_to_selection, mainview);
4576 const gchar *
4577 format_overview_name(nodeData *nd, const gchar *name)
4579 static gchar *tmp;
4580 gchar *font_desc, *font_color;
4582 if (tmp != NULL) {
4583 g_free(tmp);
4586 if (name == NULL) {
4587 name = nd->name;
4590 font_desc = he_get_logical_font_desc("SmallSystemFont");
4591 font_color = he_get_logical_font_color("SecondaryTextColor");
4593 tmp = g_markup_printf_escaped("%s\n<span font_desc=\"%s\" foreground=\"%s\">%s</span>",
4594 name,
4595 font_desc,
4596 font_color,
4597 (nd->typ==NODE_CHECKLIST)?(_("Checklist")):
4598 ((nd->typ==NODE_TEXT)?(_("Rich text")):
4599 ((nd->typ==NODE_SKETCH)?(_("Sketch")):(""))));
4601 g_free(font_desc);
4602 g_free(font_color);
4604 return tmp;
4608 gchar *
4609 he_get_logical_font_desc(const gchar *name)
4611 GtkSettings *settings = gtk_settings_get_default();
4612 GtkStyle *style = gtk_rc_get_style_by_paths(settings,
4613 name, NULL, G_TYPE_NONE);
4615 return pango_font_description_to_string(style->font_desc);
4618 gchar *
4619 he_get_logical_font_color(const gchar *name)
4621 GdkColor color;
4622 GtkSettings *settings = gtk_settings_get_default();
4623 GtkStyle *style = gtk_rc_get_style_by_paths(settings,
4624 "GtkButton", "osso-logical-colors", GTK_TYPE_BUTTON);
4626 if (gtk_style_lookup_color(style, name, &color)) {
4627 return gdk_color_to_string(&color);
4628 } else {
4629 return NULL;