Handle "w" (Save file) in node view
[maepad.git] / src / ui / callbacks.c
blob0f3c3b9cab285260486254e3a4f69bba1f6134ba
1 /*
2 * This file is part of MaePad
3 * Copyright (c) 2010 Thomas Perl <thp@thpinfo.com>
4 * http://thpinfo.com/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 move_node(MainView *mainview,GtkTreeIter *new_parent,GtkTreeIter *item_to_move,GtkTreeIter *item_befor);
97 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter);
98 gboolean show_confirmation(MainView* mainview, gchar* question);
102 gboolean callback_node_view_window_state(GtkWidget* window,
103 GdkEventWindowState* event, gpointer user_data)
105 MainView* mainview = (MainView*)user_data;
106 GtkWidget* sketch_scroll = NULL;
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->listscroll);
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->listscroll);
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->listscroll);
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->listscroll);
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, *cb;
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 cb = hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1050 gtk_button_set_label(GTK_BUTTON(cb), _("Add as child of selected memo"));
1051 hildon_check_button_set_active(HILDON_CHECK_BUTTON(cb), mainview->newnodedialog_createchild);
1052 gtk_box_pack_start(GTK_BOX(vbox), cb, FALSE, FALSE, 0);
1054 gtk_object_set_data(GTK_OBJECT(dialog), "cb", cb);
1056 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
1058 gtk_widget_grab_focus(entry);
1060 gtk_widget_show_all(dialog);
1062 /* Hide the sketch widget at first */
1063 gtk_widget_hide(al);
1064 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1067 void add_new_node(nodeData * node, MainView * mainview, gboolean ischild)
1069 GtkTreeIter parentiter, newiter;
1070 GtkTreeModel *model;
1071 void *ptr = NULL;
1073 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1075 if (gtk_tree_selection_get_selected(selection, &model, &parentiter))
1076 ptr = &parentiter;
1078 GtkTreePath *path = NULL;
1080 unsigned int parentnodeid = 0;
1082 if (ptr != NULL)
1084 path = gtk_tree_model_get_path(model, &parentiter);
1086 if (ischild == FALSE)
1088 gtk_tree_path_up(path);
1090 if (gtk_tree_path_get_depth(path) == 0)
1092 /* Selected node is a root node */
1093 ptr = NULL; /* New node can not have a Parent node */
1094 gtk_tree_path_down(path); /*restore path so expand() works */
1096 else if (gtk_tree_path_get_depth(path) > 0)
1098 /* Selected node is a child node */
1099 if (gtk_tree_model_get_iter(model, &parentiter, path))
1100 ptr = &parentiter;
1105 if (ptr != NULL)
1107 nodeData *nd;
1109 gtk_tree_model_get(model, ptr, NODE_DATA, &nd, -1);
1110 if (nd)
1111 parentnodeid = nd->sql3id;
1114 node->sql3id = 0;
1117 sqlite3_stmt *stmt = NULL;
1118 const char *dum;
1119 char tq[512];
1122 * FIXME: ord
1124 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (parent, bodytype, name, nameblob, ord) VALUES (%d, %d, ?, ?, 0);", datatable_tmpname, parentnodeid, node->typ);
1125 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1127 if (rc)
1129 maepad_warning("Error inserting (1): %s", sqlite3_errmsg(mainview->db));
1130 break;
1132 if (node->name != NULL)
1133 sqlite3_bind_text(stmt, 1, node->name, strlen(node->name), SQLITE_TRANSIENT);
1134 else
1135 sqlite3_bind_text(stmt, 1, NULL, 0, SQLITE_TRANSIENT);
1137 if (node->namepix != NULL)
1139 gchar *namepixdata = NULL;
1140 gsize datalen = 0;
1142 GError *err = NULL;
1144 if (gdk_pixbuf_save_to_buffer(node->namepix, &namepixdata, &datalen, "png", &err, NULL) == FALSE)
1146 namepixdata = NULL;
1147 datalen = 0;
1148 maepad_warning("Error saving name: %s", err->message);
1149 g_error_free(err);
1151 sqlite3_bind_blob(stmt, 2, namepixdata, datalen, SQLITE_TRANSIENT);
1153 else
1154 sqlite3_bind_blob(stmt, 2, NULL, 0, SQLITE_TRANSIENT);
1156 rc = SQLITE_BUSY;
1157 while(rc == SQLITE_BUSY)
1159 rc = sqlite3_step(stmt);
1160 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1161 break;
1163 sqlite3_finalize(stmt);
1164 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
1166 maepad_warning("Error inserting (2): %s", sqlite3_errmsg(mainview->db));
1167 break;
1169 node->sql3id = sqlite3_last_insert_rowid(mainview->db);
1171 while(FALSE);
1173 if (node->sql3id == 0)
1175 if (node->name)
1176 g_free(node->name);
1177 if (node->namepix)
1178 g_object_unref(node->namepix);
1179 g_free(node);
1180 if (path)
1181 gtk_tree_path_free(path);
1182 show_banner(mainview, _("Error creating memo"));
1183 return;
1186 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, ptr);
1188 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1190 if (path)
1192 mainview->loading=TRUE; /*only when we have a valid parent*/
1193 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);
1194 gtk_tree_path_free(path);
1197 gtk_tree_selection_select_iter(selection, &newiter);
1199 mainview->loading=FALSE;
1202 void callback_new_node_real(GtkAction * action, gpointer data)
1204 MainView *mainview;
1206 GtkWidget *dialog = data;
1207 GtkWidget *entry = gtk_object_get_user_data(GTK_OBJECT(dialog));
1209 mainview = gtk_object_get_data(GTK_OBJECT(dialog), "m");
1210 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dialog), "sk");
1211 GtkWidget *cb = gtk_object_get_data(GTK_OBJECT(dialog), "cb");
1212 newNodeToggleButtons *nntb = gtk_object_get_data(GTK_OBJECT(dialog), "nntb");
1214 nodeType typ = NODE_TEXT;
1215 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbs))) {
1216 typ = NODE_SKETCH;
1217 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbc))) {
1218 typ = NODE_CHECKLIST;
1220 g_free(nntb);
1222 gchar *txt = NULL;
1224 /*if (GTK_WIDGET_VISIBLE(entry))
1226 txt = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1227 if (strcmp(txt, "") == 0)
1229 g_free(txt);
1230 return;
1233 else
1235 GtkWidget *sdr = sketchwidget_get_drawingarea(s);
1237 GdkPixmap *spix = sketchwidget_get_Pixmap(s);
1239 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(spix), NULL, 0, 0, 0, 0, sdr->allocation.width, sdr->allocation.height);
1240 g_object_unref(spix);
1241 double w, h;
1242 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, SKETCHNODE_X, SKETCHNODE_Y, &w,
1243 &h, TRUE);
1244 if (pixbuf2==NULL) return;
1246 GdkPixbuf *pixbuf3 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, SKETCHNODE_RX,
1247 SKETCHNODE_RY);
1249 gdk_pixbuf_fill(pixbuf3, 0xffffffff);
1251 if (w <= SKETCHNODE_RX && h <= SKETCHNODE_RY)
1253 gdk_pixbuf_copy_area(pixbuf2, 0, 0, w, h, pixbuf3, 0, (SKETCHNODE_RY - h) / 2);
1255 else
1257 double neww, newh;
1259 if (w > h)
1261 neww = SKETCHNODE_RX;
1262 newh = (h / w) * SKETCHNODE_RX;
1264 else
1266 newh = SKETCHNODE_RY;
1267 neww = (w / h) * SKETCHNODE_RY;
1269 if (newh > SKETCHNODE_RY)
1270 newh = SKETCHNODE_RY;
1272 GdkPixbuf *tmpbuf = gdk_pixbuf_scale_simple(pixbuf2, neww, newh,
1273 GDK_INTERP_BILINEAR);
1275 gdk_pixbuf_copy_area(tmpbuf, 0, 0, neww, newh, pixbuf3, 0, (SKETCHNODE_RY - newh) / 2);
1277 gdk_pixbuf_unref(tmpbuf);
1280 pixbuf = pixbuf3;
1281 gdk_pixbuf_unref(pixbuf2);
1284 nodeData *node;
1286 node = g_malloc(sizeof(nodeData));
1287 node->typ = typ;
1288 node->name = txt;
1289 node->namepix = NULL;
1291 /*if (GTK_WIDGET_VISIBLE(entry))
1293 node->name = txt;
1295 else
1297 node->namepix = pixbuf;
1300 node->lastMod = 0;
1301 node->flags = 0;
1302 node->sql3id = 0;
1304 mainview->newnodedialog_createchild = hildon_check_button_get_active(HILDON_CHECK_BUTTON(cb));
1305 add_new_node(node, mainview, mainview->newnodedialog_createchild);
1307 sketchwidget_destroy(s);
1308 gtk_widget_destroy(dialog);
1309 mainview->file_edited = TRUE;
1313 * delete node
1315 void callback_file_delete_node(GtkAction * action, gpointer data)
1317 MainView *mainview = (MainView *) data;
1318 g_assert(mainview != NULL && mainview->data != NULL);
1320 if (getSelectedNode(mainview) == NULL) {
1321 show_banner(mainview, _("Select a memo first"));
1322 return;
1325 if (show_confirmation(mainview, _("Delete selected memo?"))) {
1326 mainview->can_show_node_view = FALSE;
1327 callback_delete_node_real(mainview);
1328 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
1333 * Callback for Rename Menuitem
1335 void callback_file_rename_node(GtkAction * action, gpointer data)
1337 MainView *mainview = (MainView*)data;
1338 g_assert(mainview != NULL && mainview->data != NULL);
1340 /* Get the selected node */
1341 nodeData *sel_node = getSelectedNode(mainview);
1342 if (sel_node == NULL) {
1343 /* Do nothing, if no node has been selected */
1344 show_banner(mainview, _("Select a memo first"));
1345 return;
1348 if (sel_node->namepix != NULL) {
1349 /* the memo has a graphical label, cannot edit! */
1350 show_banner(mainview, _("Cannot rename memos with sketch name"));
1351 return;
1354 gchar* new_name = show_line_edit_dialog(mainview, _("Rename memo"), _("New name:"), _("Rename"), sel_node->name);
1356 /* Only rename node when user accepted the new name */
1357 if (new_name != NULL) {
1358 callback_rename_node_real(mainview, new_name);
1359 g_free(new_name);
1363 void callback_rename_node_real(MainView* mainview, gchar* new_name)
1365 GtkTreeIter iter;
1366 GtkTreeModel *model;
1367 nodeData *nd = NULL;
1369 /* Get the selected node */
1370 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1372 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1373 return;
1376 gtk_tree_model_get (model, &iter, NODE_DATA, &nd, -1);
1378 if (nd == NULL) {
1379 return;
1382 /* Update the database */
1383 sqlite3_stmt *stmt = NULL;
1385 char* sql = sqlite3_mprintf("UPDATE %s SET name='%q' WHERE nodeid=%d", datatable_tmpname, new_name, nd->sql3id);
1387 int rc = sqlite3_prepare(mainview->db, sql, strlen(sql), &stmt, NULL);
1388 if (rc == SQLITE_OK) {
1389 rc = SQLITE_BUSY;
1390 while (rc == SQLITE_BUSY) {
1391 rc = sqlite3_step(stmt);
1392 if (rc == SQLITE_DONE) {
1393 /* Update in the database was successful - now update the rest */
1395 /* Update the noteData */
1396 g_free(nd->name);
1397 nd->name = g_strdup(new_name);
1399 /* Update the window title of node_view */
1400 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view), nd->name);
1402 /* Update the value in the tree store */
1403 gtk_tree_store_set (GTK_TREE_STORE(model), &iter, NODE_NAME, new_name, -1);
1405 break;
1406 } else if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
1407 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1408 break;
1411 sqlite3_finalize(stmt);
1412 } else {
1413 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1416 sqlite3_free(sql);
1418 mainview->file_edited = TRUE;
1421 void callback_file_export_node(GtkAction * action, gpointer data)
1423 MainView *mainview = (MainView *) data;
1424 g_assert(mainview != NULL && mainview->data != NULL);
1426 nodeData *nd=getSelectedNode(mainview);
1427 if (nd == NULL)
1429 show_banner(mainview, _("Select a memo first"));
1430 return;
1433 gchar *nodename=nd->name;
1434 if (nodename==NULL) nodename=_("saved memo");
1436 if (nd->typ == NODE_TEXT)
1439 GtkTextIter begin, end;
1440 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER(mainview->buffer), &begin, &end);
1441 gchar *text = gtk_text_buffer_get_slice(GTK_TEXT_BUFFER(mainview->buffer), &begin, &end, TRUE);
1443 GString *gstr=g_string_sized_new(4096);
1444 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
1445 gint textlen=gstr->len;
1446 gchar *text=g_string_free(gstr, FALSE);
1448 if (text==NULL || !strcmp(text, ""))
1450 show_banner(mainview, _("Memo is empty"));
1452 else
1454 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "html");
1455 if (fn!=NULL)
1457 GnomeVFSResult vfs_result;
1458 GnomeVFSHandle *handle = NULL;
1459 GnomeVFSFileSize out_bytes;
1460 vfs_result = gnome_vfs_create(&handle, fn, GNOME_VFS_OPEN_WRITE, 0, 0600);
1461 if ( vfs_result != GNOME_VFS_OK ) {
1462 show_banner(mainview, _("Export failed"));
1464 else
1466 gnome_vfs_write(handle, text, textlen, &out_bytes);
1467 gnome_vfs_close(handle);
1468 if (out_bytes==strlen(text)) show_banner(mainview, _("Exported"));
1469 else show_banner(mainview, _("Export incomplete"));
1471 g_free(fn);
1474 g_free(text);
1476 else if (nd->typ == NODE_SKETCH)
1478 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
1479 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
1480 GdkPixbuf *pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
1481 if (pixbuf==NULL)
1483 show_banner(mainview, _("Memo is empty"));
1485 else
1487 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "png");
1488 if (fn!=NULL)
1490 if (gdk_pixbuf_save(pixbuf, fn, "png", NULL, NULL)==FALSE)
1492 show_banner(mainview, _("Export failed"));
1494 else
1496 show_banner(mainview, _("Exported"));
1498 g_free(fn);
1501 g_object_unref(skpix);
1503 else if (nd->typ == NODE_CHECKLIST)
1505 show_banner(mainview, _("Export of checklists not possible yet"));
1510 * callback from menu item
1511 * move selected node down (switch node with next sibling), don't change level of node
1513 void callback_move_down_node(GtkAction * action, gpointer data)
1515 GtkTreeIter iter;
1516 GtkTreeModel *model;
1518 MainView *mainview = (MainView *) data;
1519 g_assert(mainview != NULL && mainview->data != NULL);
1521 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1522 gtk_tree_selection_get_selected(selection, &model, &iter);
1524 GtkTreeIter old_iter = iter;/*save pointer to old iter, we will need it during swap nodes*/
1526 if (gtk_tree_model_iter_next(model,&iter)==FALSE)/*get next node*/
1527 return;
1529 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1530 gtk_tree_store_swap(treeStore,&iter,&old_iter);
1532 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1536 * callback from menu item
1537 * move selected node down (switch node with prev sibling), don't change level of node
1539 void callback_move_up_node(GtkAction * action, gpointer data)
1541 GtkTreeIter iter;
1542 GtkTreeModel *model;
1544 MainView *mainview = (MainView *) data;
1545 g_assert(mainview != NULL && mainview->data != NULL);
1547 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1548 gtk_tree_selection_get_selected(selection, &model, &iter);
1550 GtkTreeIter old_iter=iter;/*save pointer to old iter, we will need it during swap nodes*/
1552 if (tree_model_iter_prev(model,&iter)==FALSE)/*get previous node*/
1553 return;
1555 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1556 gtk_tree_store_swap(treeStore,&old_iter,&iter);/*do move*/
1558 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1562 * callback from menu item
1563 * we change level of actual node with direction to top
1565 void callback_move_to_top_level_node(GtkAction * action, gpointer data)
1567 GtkTreeIter iter,new_parent;
1568 GtkTreeIter *p_new_parent;
1569 GtkTreeIter parent;
1570 GtkTreeModel *model;
1572 MainView *mainview = (MainView *) data;
1573 g_assert(mainview != NULL && mainview->data != NULL);
1575 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1576 gtk_tree_selection_get_selected(selection, &model, &iter);
1578 /*at first we need actual parent of selected node*/
1579 if (gtk_tree_model_iter_parent(model,&parent,&iter)==FALSE)
1581 /*if parent of selected node is ROOT we can't go higher*/
1582 return;
1584 /*we need also new parent, it's parent of actual parent*/
1585 if (gtk_tree_model_iter_parent(model,&new_parent,&parent)==FALSE)
1587 /*if our new parent is ROOT we got filled new_parent with invalid value,
1588 so we need set NULL value to p_new_parent (root item)*/
1589 p_new_parent=NULL;
1591 else
1593 p_new_parent=&new_parent;/*we only redirect pointer to treeiter*/
1596 saveCurrentData(mainview);/*we save changes in node befor move*/
1598 /*this move function provide move item with all his children, be careful iter value will change!*/
1599 if (move_node(mainview,p_new_parent,&iter,&parent)==TRUE){
1601 gint id_parent = get_node_id_on_tmp_db(model,p_new_parent);
1602 gint id_node = get_node_id_on_tmp_db(model,&iter);
1603 /*we need also update parent id of moved item*/
1604 char tq[512];
1605 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1606 exec_command_on_db(mainview,tq);
1608 /*select new created iter*/
1609 gtk_tree_selection_select_iter(selection,&iter);
1611 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1616 * callback from menu item
1617 * we change level of actual node with direction to bottom
1618 * previous node will be parent of our actual node
1620 void callback_move_to_bottom_level_node(GtkAction * action, gpointer data)
1622 GtkTreeIter iter;
1623 GtkTreeModel *model;
1625 MainView *mainview = (MainView *) data;
1626 g_assert(mainview != NULL && mainview->data != NULL);
1628 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1629 gtk_tree_selection_get_selected(selection, &model, &iter);
1631 GtkTreeIter move_iter=iter;/*save pointer to old iter*/
1633 /*we try to get previous node*/
1634 if (tree_model_iter_prev(model,&iter)==FALSE)
1635 return;/*if previous node on the same level doesn't exist we will exit*/
1637 saveCurrentData(mainview);/*we save changes in node befor move*/
1639 /*this move function provide move item with all his children, be careful move_iter value will change!*/
1640 if (move_node(mainview,&iter,&move_iter,NULL)==TRUE)
1642 gint id_parent = get_node_id_on_tmp_db(model,&iter);
1643 gint id_node = get_node_id_on_tmp_db(model,&move_iter);
1645 /*we need also update parent id of moved item*/
1646 char tq[512];
1647 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1648 exec_command_on_db(mainview,tq);
1650 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1651 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);/*expand parent node*/
1652 gtk_tree_path_free(path);
1654 /*select new created iter*/
1655 gtk_tree_selection_select_iter(selection,&move_iter);
1657 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1662 * move item_to_move to new_parent with his children, this function is designed for change level of node
1663 * we copy item_to_move with his children to new position (after item_befor if is not NULL) and then we
1664 * destroy old node with his children, so ! item_to_move is set with new iter, be careful on this!
1666 gboolean move_node(MainView *mainview,GtkTreeIter *new_parent,GtkTreeIter *item_to_move,GtkTreeIter *item_befor)
1668 GtkTreeModel *model;
1670 model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
1671 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1673 nodeData *node;
1674 gtk_tree_model_get(model, item_to_move, NODE_DATA, &node, -1);/*get data from actual iter*/
1675 if (node)
1677 GtkTreeIter new_iter;/*create new iter*/
1678 gtk_tree_store_append(treeStore,&new_iter,new_parent);/*append new iter to new parent*/
1680 if (item_befor!=NULL)
1681 gtk_tree_store_move_after(treeStore,&new_iter,item_befor);/*sometimes we need set position*/
1683 gtk_tree_store_set(treeStore, &new_iter, NODE_NAME, node->name,NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);/*set data from old iter*/
1685 GtkTreeIter child;
1686 while (gtk_tree_model_iter_children(model, &child, item_to_move)==TRUE)/*move all childrens while some exits*/
1688 if (move_node(mainview,&new_iter,&child,NULL)==FALSE)/*use recursion on children*/
1689 return FALSE;
1692 gtk_tree_store_set(treeStore, item_to_move, NODE_DATA, NULL, -1);
1693 gtk_tree_store_remove(treeStore, item_to_move);/*remove node, data need't remove, they are stored in new node*/
1695 /*we need return new value of moved item, so we need assign new_iter to item_to_move*/
1696 /*this code is ugly : new_iter to path and back to item_to_move*/
1697 GtkTreePath *path=gtk_tree_model_get_path(model,&new_iter);
1698 gtk_tree_model_get_iter(model,item_to_move,path);
1699 gtk_tree_path_free(path);
1701 else
1703 fprintf(stderr,"Get data node failed!\n");
1704 return FALSE;
1707 return TRUE;
1711 * simple execute of sql command which is stored in sql_string[]
1713 gboolean exec_command_on_db(MainView *mainview,char sql_string[])
1715 sqlite3_stmt *stmt = NULL;
1716 const char* dum;
1717 gboolean db_query_result = FALSE;
1719 int rc = sqlite3_prepare (mainview->db, sql_string, strlen(sql_string), &stmt, &dum);
1721 if (rc) {
1722 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1723 return FALSE;
1726 rc = SQLITE_BUSY;
1727 while (rc == SQLITE_BUSY) {
1728 rc = sqlite3_step (stmt);
1729 if (rc == SQLITE_DONE) {
1730 db_query_result = TRUE;
1731 break;
1733 else if(rc == SQLITE_ERROR || rc== SQLITE_MISUSE) {
1734 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1735 break;
1737 sqlite3_finalize(stmt);
1739 return TRUE;
1743 * 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)
1745 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview)
1747 nodeData *node;
1748 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1749 /*we need index of node on actual level*/
1750 gint index=get_branch_node_index(path);
1752 /*prepare to execute update command,and exec it*/
1753 char sql_command[512];
1754 g_snprintf (sql_command, sizeof(sql_command), "UPDATE %s SET ord=\"%d\" WHERE nodeid=%d",datatable_tmpname, index, node->sql3id);
1755 exec_command_on_db(mainview,sql_command);
1757 /*we don't want break gtk_tree_model_foreach function,until we call this func on each node - so we return always FALSE*/
1758 return FALSE;
1762 * return id number of iter (id number which is used to identify in sql database of nodes)
1764 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter)
1766 if (iter==NULL)
1767 return 0;/*we got ROOT parent here*/
1769 nodeData *node;
1770 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1771 return node->sql3id;
1775 * get index of node in current branch
1777 gint get_branch_node_index(GtkTreePath *path)
1779 int depth=gtk_tree_path_get_depth(path);
1780 gint *indicies = gtk_tree_path_get_indices(path);
1782 return indicies[depth-1];
1786 * similiar with gtk_tree_model_iter_next (), but opposite
1788 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter)
1790 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
1792 if (path==NULL){
1793 fprintf(stderr,"Error: path is null\n");
1794 return FALSE;
1797 if (gtk_tree_path_prev(path)==FALSE)
1798 return FALSE;
1800 gtk_tree_model_get_iter(tree_model, iter,path);
1802 return TRUE;
1805 gboolean ref2iter(GtkTreeModel * model, GtkTreeRowReference * ref, GtkTreeIter * iter)
1807 gboolean res = FALSE;
1808 GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
1810 if (gtk_tree_model_get_iter(model, iter, path))
1812 res = TRUE;
1814 gtk_tree_path_free(path);
1815 return (res);
1818 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter)
1820 GtkTreeRowReference *ref;
1822 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
1824 ref = gtk_tree_row_reference_new(model, path);
1825 gtk_tree_path_free(path);
1826 return (ref);
1829 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop)
1831 GtkTreeIter topiter;
1833 if (ref2iter(model, topnode, &topiter) == FALSE)
1834 return;
1836 GtkTreeIter child;
1838 if (gtk_tree_model_iter_children(model, &child, &topiter))
1840 GtkTreeRowReference *ref;
1841 GList *rr_list = NULL, *node;
1845 ref = iter2ref(model, &child);
1846 rr_list = g_list_append(rr_list, ref);
1848 while(gtk_tree_model_iter_next(model, &child));
1851 * got a reflist for all children
1854 for(node = rr_list; node; node = node->next)
1856 ref = (GtkTreeRowReference *) (node->data);
1857 if (ref2iter(model, ref, &child))
1859 GtkTreeIter newtopiter, newiter;
1860 GtkTreeIter *newtopiterptr;
1862 if (ref2iter(model, newtop, &newtopiter))
1863 newtopiterptr = &newtopiter;
1864 else
1865 newtopiterptr = NULL;
1867 nodeData *node;
1869 gtk_tree_model_get(model, &child, NODE_DATA, &node, -1);
1871 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, newtopiterptr);
1872 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1874 GtkTreeRowReference *newref = iter2ref(model, &newiter);
1876 move_nodes_up(model, ref, newref);
1877 gtk_tree_row_reference_free(newref);
1879 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
1881 gtk_tree_row_reference_free(ref);
1884 g_list_free(rr_list);
1889 void callback_delete_node_real(MainView* mainview)
1891 GtkTreeIter iter;
1892 GtkTreeModel *model;
1894 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1896 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1897 return;
1899 nodeData *nd;
1901 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
1902 if (!nd)
1903 return;
1905 mainview->file_edited = TRUE;
1907 unsigned int sql3id = nd->sql3id;
1909 if (nd->name)
1910 g_free(nd->name);
1913 * g_free(nd->data);
1914 * if (nd->pix) g_object_unref(nd->pix);
1916 g_free(nd);
1918 GtkTreeRowReference *upref = NULL, *ref = NULL;
1920 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1922 ref = gtk_tree_row_reference_new(model, path);
1923 if (gtk_tree_path_up(path))
1924 upref = gtk_tree_row_reference_new(model, path);
1925 gtk_tree_path_free(path);
1927 g_object_ref(model);
1928 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
1930 move_nodes_up(model, ref, upref);
1932 if (ref2iter(model, ref, &iter))
1934 char tq[512];
1936 g_snprintf(tq, sizeof(tq), "SELECT parent FROM %s WHERE nodeid=%d", datatable_tmpname, sql3id);
1937 sqlite3_stmt *stmt = NULL;
1938 const char *dum;
1939 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1940 unsigned int sql3parentid = 0;
1942 if (rc)
1944 maepad_warning("Error finding children for delete: %s", sqlite3_errmsg(mainview->db));
1946 else
1948 rc = SQLITE_BUSY;
1949 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
1951 rc = sqlite3_step(stmt);
1952 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1953 break;
1954 else if (rc == SQLITE_ROW)
1956 sql3parentid = sqlite3_column_int(stmt, 0);
1957 break;
1960 sqlite3_finalize(stmt);
1962 g_snprintf(tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE parent=%d;", datatable_tmpname, sql3parentid, sql3id);
1963 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1964 maepad_warning("Error moving nodes up one level");
1965 } else
1967 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d;", datatable_tmpname, sql3id);
1968 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1969 maepad_warning("Error deleting node");
1972 /* Delete all checklist items that do not have
1973 * a node anymore (= orphaned checklist items) */
1974 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid NOT IN (SELECT nodeid FROM %s);", checklisttable_tmpname, datatable_tmpname);
1975 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1976 maepad_warning("Error deleting orphaned checklist items");
1980 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
1983 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
1984 g_object_unref(model);
1986 gtk_tree_row_reference_free(ref);
1987 gtk_tree_row_reference_free(upref);
1989 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
1993 void callback_edit_clear(GtkAction * action, gpointer data)
1995 MainView *mainview = (MainView *) data;
1996 g_assert(mainview != NULL && mainview->data != NULL);
1997 nodeData *nd = getSelectedNode(mainview);
1999 if (show_confirmation(mainview, _("Remove all contents of this memo?"))) {
2000 switch (nd->typ) {
2001 case NODE_TEXT:
2002 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", 0);
2003 break;
2004 case NODE_SKETCH:
2005 sketchwidget_clear(mainview->sk);
2006 break;
2007 case NODE_CHECKLIST:
2008 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview))));
2009 break;
2010 default:
2011 g_assert_not_reached();
2017 * cut
2019 void callback_edit_cut(GtkAction * action, gpointer data)
2021 MainView *mainview = (MainView *) data;
2022 g_assert(mainview != NULL && mainview->data != NULL);
2024 nodeData *nd = getSelectedNode(mainview);
2026 if (nd->typ == NODE_TEXT)
2027 gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, TRUE);
2028 else if (nd->typ == NODE_SKETCH)
2030 if (sketchwidget_cut(mainview->sk, mainview->clipboard)==FALSE)
2031 show_banner(mainview, _("Error cutting"));
2033 else if (nd->typ == NODE_CHECKLIST)
2034 show_banner(mainview, _("Unimplemented"));
2039 * copy
2041 void callback_edit_copy(GtkAction * action, gpointer data)
2043 MainView *mainview = (MainView *) data;
2044 g_assert(mainview != NULL && mainview->data != NULL);
2046 nodeData *nd = getSelectedNode(mainview);
2048 if (nd->typ == NODE_TEXT)
2049 gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard);
2050 else if (nd->typ == NODE_SKETCH)
2052 if (sketchwidget_copy(mainview->sk, mainview->clipboard)==FALSE)
2053 show_banner(mainview, _("Error copying"));
2055 else if (nd->typ == NODE_CHECKLIST)
2057 /* Copy all selected entries as multiline text (1 line per entry) */
2058 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2059 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2061 gint selected_rows = gtk_tree_selection_count_selected_rows(selection);
2062 GList* l = gtk_tree_selection_get_selected_rows(selection, NULL);
2064 GtkTreeIter iter;
2065 gchar *str_data;
2067 gchar **entries = g_malloc0(sizeof(gchar*)*selected_rows+1);
2068 gint entries_idx = 0;
2070 GList* cur = l;
2071 while(cur) {
2072 GtkTreePath *path = cur->data;
2074 if (gtk_tree_model_get_iter(model, &iter, path)) {
2075 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_TEXT, &(entries[entries_idx++]), -1);
2077 gtk_tree_path_free(path);
2079 cur = cur->next;
2082 g_list_free(l);
2083 str_data = g_strjoinv("\n", entries);
2084 g_strfreev(entries);
2085 gtk_clipboard_set_text(mainview->clipboard, str_data, -1);
2086 g_free(str_data);
2088 str_data = g_strdup_printf(_("Copied %d entries"), selected_rows);
2089 show_banner(mainview, str_data);
2090 g_free(str_data);
2096 * paste
2098 void callback_edit_paste(GtkAction * action, gpointer data)
2100 MainView *mainview = (MainView *) data;
2101 g_assert(mainview != NULL && mainview->data != NULL);
2103 nodeData *nd = getSelectedNode(mainview);
2105 if (nd->typ == NODE_TEXT)
2106 gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, NULL, TRUE);
2107 else if (nd->typ == NODE_SKETCH)
2109 if (sketchwidget_paste(mainview->sk, mainview->clipboard)==FALSE)
2110 show_banner(mainview, _("Error pasting"));
2112 else if (nd->typ == NODE_CHECKLIST) {
2113 /* Paste string from clipboard as new item */
2114 callback_checklist_paste(mainview);
2115 checklist_select(mainview, TREEVIEW_SELECT_LAST);
2118 mainview->file_edited = TRUE;
2121 gint cb_popup(GtkWidget * widget, GdkEvent * event)
2123 GtkMenu *menu;
2124 GdkEventButton *event_button;
2127 * The "widget" is the menu that was supplied when
2128 * * g_signal_connect_swapped() was called.
2130 menu = GTK_MENU(widget);
2131 event_button = (GdkEventButton *) event;
2132 if (event->type == GDK_BUTTON_PRESS && event_button->button == 3)
2134 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
2135 return TRUE;
2137 return FALSE;
2142 * on_node_menu_show(GtkWidget*, gpointer)
2144 * This is called when the longpress menu is shown in the main
2145 * window. In the Hildon UI mode that we are using, this does
2146 * not automatically select the touched node, so we need to set
2147 * the cursor here so that the functions in the menu operate on
2148 * the node that the user touched (i.e. the expected one).
2150 * The value of mainview->node_list_longpress_path has been set
2151 * by callback_treeview_button_press on the buttn press event.
2153 void
2154 on_node_menu_show(GtkWidget* nodemenu, gpointer user_data)
2156 MainView* mainview = (MainView*)user_data;
2158 if (mainview->node_list_longpress_path != NULL) {
2159 /* Set the cursor, but don't open the node view */
2160 mainview->can_show_node_view = FALSE;
2161 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
2162 mainview->node_list_longpress_path, NULL, FALSE);
2164 /* Dispose the path (we don't need it anymore) */
2165 gtk_tree_path_free(mainview->node_list_longpress_path);
2166 mainview->node_list_longpress_path = NULL;
2171 * close
2173 gboolean closefile(MainView * mainview)
2175 saveCurrentData(mainview);
2177 if (mainview->file_edited)
2179 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));
2180 gint answer = gtk_dialog_run(GTK_DIALOG(hn));
2181 gtk_widget_destroy(GTK_WIDGET(hn));
2183 if (answer == CONFRESP_CANCEL)
2184 return (FALSE);
2185 else if (answer == CONFRESP_YES)
2187 if (mainview->file_name == NULL)
2189 mainview->file_name = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2191 write_buffer_to_file(mainview);
2195 if (mainview->db)
2196 sqlite3_close(mainview->db);
2197 mainview->db = NULL;
2198 return (TRUE);
2201 gboolean callback_file_close(GtkAction * action, gpointer data)
2204 MainView *mainview = (MainView *) data;
2205 g_assert(mainview != NULL && mainview->data != NULL);
2206 if (closefile(mainview) == FALSE)
2207 return(FALSE);
2209 gtk_main_quit();
2210 return(TRUE);
2213 void callback_file_new_node(GtkAction * action, gpointer data)
2215 MainView *mainview = (MainView *) data;
2216 g_assert(mainview != NULL && mainview->data != NULL);
2218 nodeType typ = NODE_SKETCH;
2220 nodeData *nd = getSelectedNode(mainview);
2222 if (nd != NULL)
2223 typ = nd->typ;
2225 new_node_dialog(typ, mainview);
2229 * new
2231 void callback_file_new(GtkAction * action, gpointer data)
2233 MainView *mainview = (MainView *) data;
2234 g_assert(mainview != NULL && mainview->data != NULL);
2236 gchar *filename = NULL;
2238 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "memos", "db");
2239 if (filename == NULL) {
2240 return;
2243 if (closefile(mainview) == FALSE) {
2244 return;
2247 new_file(mainview);
2251 busy_enter(mainview);
2253 int rc;
2255 rc = sqlite3_open(filename, &mainview->db);
2256 if (rc)
2258 show_banner(mainview, _("Cannot create database"));
2259 maepad_warning("Can't create database %s: %s", filename, sqlite3_errmsg(mainview->db));
2260 break;
2263 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
2265 char tq[512];
2267 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
2268 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
2270 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
2271 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2273 maepad_warning("Cannot create data table");
2274 show_banner(mainview, _("Error creating data table"));
2275 break;
2278 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
2279 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2281 maepad_warning("Cannot create checklist table");
2282 show_banner(mainview, _("Error creating checklist table"));
2283 break;
2286 if (mainview->db)
2287 sqlite3_close(mainview->db);
2288 mainview->db = NULL;
2290 mainview->file_name = filename;
2291 mainview->file_edited = FALSE;
2292 read_file_to_buffer(mainview);
2294 /*add a starter memo*/
2295 nodeData *node;
2296 node = g_malloc(sizeof(nodeData));
2297 node->typ = NODE_SKETCH;
2298 node->name = _("My first memo");
2299 node->namepix = NULL;
2300 node->lastMod = 0;
2301 node->flags = 0;
2302 node->sql3id = 0;
2303 add_new_node(node, mainview, TRUE);
2304 /*gtk_paned_set_position(GTK_PANED(mainview->hpaned), 180);*/
2305 write_buffer_to_file(mainview);
2307 }while(FALSE);
2308 busy_reset(mainview);
2311 gboolean reset_ctree(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
2313 nodeData *node;
2315 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
2316 if (node)
2318 if (node->name)
2319 g_free(node->name);
2320 if (node->namepix)
2321 g_object_unref(node->namepix);
2322 g_free(node);
2324 gtk_tree_store_set(GTK_TREE_STORE(model), iter, NODE_DATA, NULL, -1);
2326 return (FALSE);
2329 void new_file(MainView * mainview)
2331 busy_enter(mainview);
2333 * clear buffer, filename and free buffer text
2335 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);
2336 mainview->file_name = NULL;
2337 mainview->file_edited = FALSE;
2338 mainview->newnodedialog_createchild = TRUE;
2340 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
2342 g_object_ref(model);
2343 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
2345 gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) reset_ctree, (gpointer) mainview);
2348 * crashing bastard
2349 * gtk_tree_store_clear(GTK_TREE_STORE(model));
2351 GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
2352 GtkTreeIter iter;
2354 if (gtk_tree_model_get_iter(model, &iter, path))
2358 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2360 while(gtk_tree_store_iter_is_valid(GTK_TREE_STORE(model), &iter));
2362 gtk_tree_path_free(path);
2364 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
2365 g_object_unref(model);
2367 busy_leave(mainview);
2371 * open
2373 void callback_file_open(GtkAction * action, gpointer data)
2375 gchar *filename = NULL;
2376 MainView *mainview = (MainView *) data;
2377 g_assert(mainview != NULL && mainview->data != NULL);
2379 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
2380 if (filename == NULL) {
2381 return;
2384 if (closefile(mainview) == FALSE) {
2385 return;
2388 open_file(filename, mainview);
2389 g_free(filename);
2392 gboolean open_file(gchar * filename, MainView * mainview)
2394 gboolean ret=FALSE;
2396 /* Don't open nodes when opening a file */
2397 mainview->can_show_node_view = FALSE;
2399 busy_enter(mainview);
2401 while(filename != NULL)
2403 struct stat s;
2405 if (stat(filename, &s) == -1) break;
2407 mainview->file_name = g_strdup(filename);
2408 gboolean res = read_file_to_buffer(mainview);
2410 if (res == FALSE)
2412 g_free(mainview->file_name);
2413 mainview->file_name = NULL;
2414 break;
2416 mainview->file_edited = FALSE;
2417 ret=TRUE;
2418 break;
2421 busy_leave(mainview);
2422 return(ret);
2425 void callback_about_link(GtkAboutDialog *about, const gchar *link, gpointer data)
2427 MainView *mainview = (MainView *) data;
2428 g_assert(mainview != NULL && mainview->data != NULL);
2429 osso_rpc_run_with_defaults(mainview->data->osso, "osso_browser", OSSO_BROWSER_OPEN_NEW_WINDOW_REQ, NULL,
2430 DBUS_TYPE_STRING, link, DBUS_TYPE_INVALID);
2433 void callback_about(GtkAction * action, gpointer data)
2435 MainView* mainview = (MainView *)data;
2436 he_about_dialog_present(mainview_get_dialog_parent(mainview),
2437 NULL /* auto-detect app name */,
2438 "maepad",
2439 VERSION,
2440 _("A node-based memory pad for Maemo"),
2441 _("(c) 2010 Thomas Perl"),
2442 "http://thpinfo.com/2010/maepad/",
2443 "https://garage.maemo.org/tracker/?group_id=1291",
2444 "http://thpinfo.com/2010/maepad/donate");
2448 * save
2450 void callback_file_save(GtkAction * action, gpointer data)
2452 gchar *filename = NULL;
2453 MainView *mainview = (MainView *) data;
2454 g_assert(mainview != NULL && mainview->data != NULL);
2457 * check is we had a new file
2459 if (mainview->file_name != NULL)
2461 write_buffer_to_file(mainview);
2463 else
2465 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2467 * if we got a file name from chooser -> save file
2469 if (filename != NULL)
2471 mainview->file_name = filename;
2472 write_buffer_to_file(mainview);
2473 mainview->file_edited = FALSE;
2478 void callback_shapemenu(GtkAction * action, GtkWidget * wid)
2480 gint style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(wid)));
2481 MainView* mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2482 g_assert(mainview != NULL);
2484 if (style >= 0 && style < SKETCHSHAPE_COUNT) {
2485 /* We use the sketch widget's enum for available styles */
2486 sketchwidget_set_shape(mainview->sk, style);
2488 /* Draw the correct indicator for the current shape */
2489 GtkWidget* pix = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(wid), "i"));
2490 g_assert(pix != NULL);
2491 gtk_widget_show(pix);
2492 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->shape_tb), pix);
2493 } else {
2494 /* Fail. We shouldn't get here at all! */
2495 g_error("Invalid style ID from shape menu: %d", style);
2501 void callback_eraser(GtkAction * action, MainView * mainview)
2503 g_assert(mainview != NULL && mainview->data != NULL);
2505 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb))) {
2506 /* Eraser on: Set pen color to white */
2507 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };
2508 sketchwidget_set_brushcolor(mainview->sk, white);
2509 } else {
2510 /* Eraser off: Set default color again (or black) */
2511 GdkColor black = {0, 0, 0, 0};
2512 if (mainview->current_color == NULL) {
2513 mainview->current_color = gdk_color_copy(&black);
2515 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2519 void callback_menu(GtkAction * action, GtkWidget * menu)
2521 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
2524 void callback_brushsizetb(GtkAction * action, MainView *mainview)
2526 g_assert(mainview != NULL && mainview->data != NULL);
2527 callback_menu(NULL, mainview->brushsizemenu);
2530 void callback_brushsize(GtkAction * action, GtkWidget * wid)
2532 int bsize = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2533 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2535 g_assert(mainview != NULL && mainview->data != NULL);
2537 sketchwidget_set_brushsize(mainview->sk, bsize);
2539 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2541 gtk_widget_show(pix);
2542 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->brushsize_tb), pix);
2545 void callback_sketchlines(GtkAction * action, GtkWidget * wid)
2547 int style = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2548 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2550 g_assert(mainview != NULL);
2552 nodeData *nd = getSelectedNode(mainview);
2553 gboolean doit = FALSE;
2555 if (nd != NULL && nd->typ == NODE_SKETCH)
2557 nd->flags &= ~NODEFLAG_SKETCHLINES;
2558 nd->flags &= ~NODEFLAG_SKETCHGRAPH;
2559 /* sketchwidget_set_edited(mainview->sk, TRUE);*/ /*we call this on openfile, so this messes things up*/
2560 doit = TRUE;
2563 if (style == 0)
2565 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_NONE);
2567 else if (style == 1)
2569 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_LINES);
2570 if (doit == TRUE)
2571 nd->flags |= NODEFLAG_SKETCHLINES;
2573 else if (style == 2)
2575 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_GRAPH);
2576 if (doit == TRUE)
2577 nd->flags |= NODEFLAG_SKETCHGRAPH;
2580 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2582 gtk_widget_show(pix);
2583 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->sketchlines_tb), pix);
2586 void callback_color(GtkAction* action, MainView* mainview)
2588 g_assert(mainview != NULL && mainview->data != NULL);
2590 nodeData *nd = getSelectedNode(mainview);
2591 if (nd == NULL) return;
2593 HeSimpleColorDialog* dialog = HE_SIMPLE_COLOR_DIALOG(he_simple_color_dialog_new());
2594 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
2596 if (mainview->current_color) {
2597 he_simple_color_dialog_set_color(dialog, mainview->current_color);
2600 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
2601 gtk_widget_destroy(GTK_WIDGET(dialog));
2602 return;
2605 gdk_color_free(mainview->current_color);
2606 mainview->current_color = he_simple_color_dialog_get_color(dialog);
2608 gtk_widget_destroy(GTK_WIDGET(dialog));
2610 switch (nd->typ) {
2611 case NODE_SKETCH:
2612 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb), FALSE);
2613 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2614 break;
2615 case NODE_CHECKLIST:
2616 { /* Put in a separate block to allow new local variables */
2617 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2618 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2619 GList* selected = gtk_tree_selection_get_selected_rows(selection, NULL);
2621 gchar* color_string = g_strdup_printf("#%02x%02x%02x",
2622 mainview->current_color->red >> 8,
2623 mainview->current_color->green >> 8,
2624 mainview->current_color->blue >> 8);
2626 GList* cur = selected;
2627 while (cur != NULL) {
2628 GtkTreePath* path = cur->data;
2629 GtkTreeIter iter;
2630 if (gtk_tree_model_get_iter(model, &iter, path)) {
2631 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_COLOR, color_string, -1);
2633 gtk_tree_path_free(path);
2634 cur = cur->next;
2637 g_list_free(selected);
2638 g_free(color_string);
2640 break;
2641 default:
2642 g_assert_not_reached();
2646 void callback_color_invoke(GtkAction * action, gpointer data)
2648 MainView *mainview = (MainView *) data;
2649 g_assert(mainview != NULL && mainview->data != NULL);
2650 gtk_button_clicked(GTK_BUTTON(mainview->colorbutton_tb));
2655 void callback_pressure(GtkAction * action, MainView *mainview)
2657 g_assert(mainview != NULL && mainview->data != NULL);
2659 nodeData *nd = getSelectedNode(mainview);
2661 if (nd == NULL)
2662 return;
2663 if (nd->typ != NODE_SKETCH)
2664 return;
2666 /* pressure sensitivity disabled for now...
2667 mainview->sk->pressuresensitivity=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure));*/
2671 void callback_wordwrap(GtkWidget* widget, gpointer user_data)
2673 MainView* mainview = (MainView*)user_data;
2674 nodeData* nd = getSelectedNode(mainview);
2675 GtkWrapMode wrap_mode;
2677 if (nd == NULL || nd->typ != NODE_TEXT) {
2678 return;
2681 if (hildon_check_button_get_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap))) {
2682 nd->flags |= NODEFLAG_WORDWRAP;
2683 wrap_mode = GTK_WRAP_WORD_CHAR;
2684 } else {
2685 nd->flags &= ~NODEFLAG_WORDWRAP;
2686 wrap_mode = GTK_WRAP_NONE;
2689 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mainview->textview), wrap_mode);
2693 void callback_font(GtkAction * action, gpointer data)
2695 MainView *mainview = (MainView *) data;
2696 g_assert(mainview != NULL && mainview->data != NULL);
2698 nodeData *nd = getSelectedNode(mainview);
2700 if (nd == NULL)
2701 return;
2702 if (nd->typ != NODE_TEXT)
2703 return;
2705 HildonFontSelectionDialog *dialog = HILDON_FONT_SELECTION_DIALOG(hildon_font_selection_dialog_new(NULL, NULL));
2707 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2708 /*gotsel=FALSE;*/
2710 WPTextBufferFormat fmt;
2711 wp_text_buffer_get_attributes(mainview->buffer, &fmt, gotsel);
2713 gint ri=0;
2714 if (fmt.text_position==TEXT_POSITION_SUPERSCRIPT) ri=1;
2715 else if (fmt.text_position==TEXT_POSITION_SUBSCRIPT) ri=-1;
2717 g_object_set(G_OBJECT(dialog),
2718 "family-set", fmt.cs.font,
2719 "family", wp_get_font_name(fmt.font),
2720 "size-set", fmt.cs.font_size,
2721 "size", wp_font_size[fmt.font_size],
2722 "color-set", fmt.cs.color,
2723 "color", &fmt.color,
2724 "bold-set", fmt.cs.bold,
2725 "bold", fmt.bold,
2726 "italic-set", fmt.cs.italic,
2727 "italic", fmt.italic,
2728 "underline-set", fmt.cs.underline,
2729 "underline", fmt.underline,
2730 "strikethrough-set", fmt.cs.strikethrough,
2731 "strikethrough", fmt.strikethrough,
2732 "position-set", fmt.cs.text_position,
2733 "position", ri,
2734 NULL);
2736 gtk_widget_show_all(GTK_WIDGET(dialog));
2737 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2739 gboolean bold, italic, underline, strikethrough;
2740 gchar *family = NULL;
2741 gint size, position;
2742 GdkColor *color=NULL;
2743 gboolean set_family, set_size, set_bold, set_italic, set_underline, set_strikethrough, set_color, set_position;
2745 g_object_get(G_OBJECT(dialog), "family", &family, "size", &size, "bold", &bold, "italic", &italic,
2746 "underline", &underline, "strikethrough", &strikethrough,
2747 "family-set", &set_family, "size-set", &set_size, "bold-set", &set_bold, "italic-set", &set_italic,
2748 "underline-set", &set_underline, "strikethrough-set", &set_strikethrough,
2749 "color", &color, "color-set", &set_color, "position", &position, "position-set", &set_position,
2750 NULL);
2752 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE);
2753 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;
2755 if (set_family) { fmt.font=wp_get_font_index(family, 1); fmt.cs.font=1; }
2756 if (set_size) { fmt.font_size=wp_get_font_size_index(size, 16); fmt.cs.font_size=1; }
2758 if (set_strikethrough)
2760 fmt.cs.strikethrough=1;
2761 fmt.strikethrough=strikethrough;
2764 if (set_color)
2767 GLIB WARNING ** GLib-GObject - IA__g_object_set_valist: object class `GtkTextTag' has no property named `'
2769 fmt.cs.color=1;
2770 fmt.color.pixel=color->pixel;
2771 fmt.color.red=color->red;
2772 fmt.color.green=color->green;
2773 fmt.color.blue=color->blue;
2776 if (set_position)
2778 if (position==1) ri=TEXT_POSITION_SUPERSCRIPT;
2779 else if (position==-1) ri=TEXT_POSITION_SUBSCRIPT;
2780 else ri=TEXT_POSITION_NORMAL;
2782 fmt.cs.text_position=1;
2783 fmt.text_position=ri;
2786 if (set_bold)
2788 fmt.cs.bold=1;
2789 fmt.bold=bold;
2791 if (set_italic)
2793 fmt.cs.italic=1;
2794 fmt.italic=italic;
2796 if (set_underline)
2798 fmt.cs.underline=1;
2799 fmt.underline=underline;
2802 wp_text_buffer_set_format(mainview->buffer, &fmt);
2805 gtk_widget_destroy(GTK_WIDGET(dialog));
2808 void callback_fontstyle(GtkAction * action, GtkWidget * wid)
2810 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2811 g_assert(mainview != NULL && mainview->data != NULL);
2813 nodeData *nd = getSelectedNode(mainview);
2815 if (nd == NULL)
2816 return;
2817 if (nd->typ == NODE_TEXT)
2819 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2821 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2822 wp_text_buffer_set_attribute(mainview->buffer, style, (gpointer)act);
2824 else if (nd->typ == NODE_CHECKLIST)
2826 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2827 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2828 if (style!=WPT_BOLD && style!=WPT_STRIKE && style!=WPT_LEFT) return;
2830 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2831 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
2833 gint styletoset_weight=PANGO_WEIGHT_NORMAL;
2834 gboolean styletoset_strike=FALSE;
2835 gboolean checkit=FALSE;
2837 if (style==WPT_BOLD && act==TRUE) styletoset_weight=PANGO_WEIGHT_BOLD;
2838 else if (style==WPT_STRIKE && act==TRUE) styletoset_strike=TRUE;
2839 else if (style==WPT_LEFT && act==TRUE) checkit=TRUE;
2841 GList* cur=l;
2842 while(cur)
2844 GtkTreePath *path=cur->data;
2846 GtkTreeIter iter;
2847 if (gtk_tree_model_get_iter(model, &iter, path))
2849 if (style==WPT_BOLD) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_BOLD, styletoset_weight, -1);
2850 else if (style==WPT_STRIKE) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_STRIKE, styletoset_strike, -1);
2851 else if (style==WPT_LEFT) {
2852 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_CHECKED, checkit, -1);
2853 if (checkit) {
2854 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
2855 } else {
2856 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, NULL, -1);
2860 gtk_tree_path_free(path);
2861 cur=cur->next;
2864 g_list_free(l);
2865 mainview->checklist_edited = TRUE;
2869 void
2870 callback_sharing(GtkWidget* widget, gpointer user_data)
2872 MainView* mainview = (MainView*)user_data;
2873 nodeData* nd = getSelectedNode(mainview);
2874 gchar* filename = g_strdup("/tmp/untitled.png");
2875 gchar* uri = NULL;
2877 if (nd == NULL || nd->typ != NODE_SKETCH) {
2878 show_banner(mainview, _("Only sketches can be shared"));
2879 return;
2882 if (nd->name != NULL) {
2883 g_free(filename);
2884 filename = g_strdup_printf("/tmp/%s.png", nd->name);
2887 busy_enter(mainview);
2888 GdkPixmap* skpix = sketchwidget_get_Pixmap(mainview->sk);
2889 GtkWidget* skdr = sketchwidget_get_drawingarea(mainview->sk);
2890 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL,
2891 GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0,
2892 skdr->allocation.width, skdr->allocation.height);
2894 if (pixbuf == NULL) {
2895 show_banner(mainview, _("Memo is empty"));
2896 goto cleanup;
2899 if (!gdk_pixbuf_save(pixbuf, filename, "png", NULL, NULL)) {
2900 show_banner(mainview, _("File export failed"));
2901 goto cleanup;
2904 uri = g_strdup_printf("file://%s", filename);
2906 sharing_dialog_with_file(mainview->data->osso,
2907 mainview_get_dialog_parent(mainview),
2908 uri);
2910 cleanup:
2911 g_object_unref(skpix);
2912 g_free(filename);
2913 g_free(uri);
2914 busy_leave(mainview);
2917 void
2918 callback_remove_checked(GtkWidget* widget, gpointer user_data)
2920 MainView* mainview = (MainView*)user_data;
2921 nodeData* nd = getSelectedNode(mainview);
2922 GtkTreeIter iter;
2923 GtkTreeModel* model = NULL;
2924 GList* checked_items = NULL;
2925 gchar* question = NULL;
2926 gint count = 0;
2928 if (nd == NULL || nd->typ != NODE_CHECKLIST) {
2929 return;
2932 /* Get a list of checked items */
2933 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2934 if (!gtk_tree_model_get_iter_first(model, &iter)) {
2935 return;
2938 busy_enter(mainview);
2939 do {
2940 gboolean checked = FALSE;
2941 gtk_tree_model_get(model, &iter, CHECKNODE_CHECKED, &checked, -1);
2943 if (checked) {
2944 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
2946 checked_items = g_list_append(checked_items,
2947 gtk_tree_row_reference_new(model, path));
2948 count++;
2950 gtk_tree_path_free(path);
2952 } while (gtk_tree_model_iter_next(model, &iter));
2953 busy_leave(mainview);
2955 if (checked_items == NULL) {
2956 show_banner(mainview, _("No checked items in checklist"));
2957 return;
2960 question = g_strdup_printf(N_("Remove %d checked item?", "Remove %d checked items?", count), count);
2961 if (show_confirmation(mainview, question)) {
2962 /* Remove the checklist items from the list */
2963 checklist_remove_rowrefs(mainview, checked_items, TRUE);
2964 } else {
2965 /* Free the allocated row references + list */
2966 GList* cur = checked_items;
2967 while (cur != NULL) {
2968 GtkTreeRowReference* rowref = cur->data;
2969 gtk_tree_row_reference_free(rowref);
2970 cur = cur->next;
2972 g_list_free(checked_items);
2974 g_free(question);
2977 void callback_textbuffer_move(WPTextBuffer *textbuffer, MainView *mainview)
2979 g_assert(mainview != NULL && mainview->data != NULL);
2982 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2984 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), gotsel);
2985 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), gotsel);
2986 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), gotsel);
2987 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), gotsel);
2989 WPTextBufferFormat fmt;
2990 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE/*gotsel*/);
2992 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
2993 g_signal_handlers_block_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
2994 g_signal_handlers_block_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
2995 g_signal_handlers_block_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
2997 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), fmt.bold);
2998 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), fmt.italic);
2999 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), fmt.underline);
3000 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), fmt.bullet);
3002 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3003 g_signal_handlers_unblock_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
3004 g_signal_handlers_unblock_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
3005 g_signal_handlers_unblock_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
3008 gint wp_savecallback(const gchar *buffer, GString * gstr)
3010 gstr=g_string_append(gstr, buffer);
3011 return(0);
3014 void callback_undo(GtkAction * action, MainView * mainview)
3016 g_assert(mainview != NULL && mainview->data != NULL);
3018 nodeData *nd = getSelectedNode(mainview);
3020 if (nd == NULL) return;
3022 if (nd->typ == NODE_SKETCH) sketchwidget_undo(mainview->sk);
3023 else if (nd->typ == NODE_TEXT) wp_text_buffer_undo(mainview->buffer);
3026 void callback_redo(GtkAction * action, MainView * mainview)
3028 g_assert(mainview != NULL && mainview->data != NULL);
3030 nodeData *nd = getSelectedNode(mainview);
3032 if (nd == NULL) return;
3034 if (nd->typ == NODE_SKETCH) sketchwidget_redo(mainview->sk);
3035 else if (nd->typ == NODE_TEXT) wp_text_buffer_redo(mainview->buffer);
3038 void callback_undotoggle(gpointer widget, gboolean st, MainView * mainview)
3040 g_assert(mainview != NULL && mainview->data != NULL);
3042 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), st);
3045 void callback_redotoggle(gpointer widget, gboolean st, MainView * mainview)
3047 g_assert(mainview != NULL && mainview->data != NULL);
3049 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), st);
3052 gboolean close_cb(GtkWidget * widget, GdkEventAny * event, MainView * mainview)
3054 callback_file_close(NULL, mainview);
3055 return (TRUE);
3058 void
3059 mainview_click_on_current_node(MainView* mainview)
3061 GtkTreeSelection* selection = NULL;
3062 GtkTreeModel* model = NULL;
3063 GtkTreeIter iter;
3065 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
3066 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
3067 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
3069 mainview->can_show_node_view = TRUE;
3070 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
3071 path, NULL, FALSE);
3073 gtk_tree_path_free(path);
3077 gboolean
3078 on_main_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3080 MainView* mainview = (MainView*)user_data;
3081 gboolean result = FALSE;
3083 switch (event->keyval) {
3084 case GDK_KP_Enter:
3085 case GDK_Return:
3086 case GDK_l:
3087 case GDK_L:
3088 /* Open selected memo in node view */
3089 mainview_click_on_current_node(mainview);
3090 result = TRUE;
3091 break;
3092 case GDK_w:
3093 case GDK_W:
3094 /* Save changes to file ("write buffer") */
3095 callback_file_save(NULL, mainview);
3096 result = TRUE;
3097 break;
3098 case GDK_BackSpace:
3099 /* Delete selected node (with confirmation) */
3100 callback_file_delete_node(NULL, mainview);
3101 result = TRUE;
3102 break;
3103 case GDK_o:
3104 case GDK_O:
3105 /* Add new memo to list */
3106 callback_file_new_node(NULL, mainview);
3107 result = TRUE;
3108 break;
3109 case GDK_r:
3110 case GDK_R:
3111 /* Replace (edit) name of selected memo */
3112 callback_file_rename_node(NULL, mainview);
3113 result = TRUE;
3114 break;
3115 case GDK_g:
3116 if (mainview->main_view_prev_keyval == GDK_g) {
3117 /* Goto (=select) first memo */
3118 mainview->can_show_node_view = FALSE;
3119 nodelist_select(mainview, TREEVIEW_SELECT_FIRST);
3121 /* Don't remember this key for the next keypress */
3122 mainview->main_view_prev_keyval_reset = TRUE;
3124 result = TRUE;
3126 break;
3127 case GDK_G:
3128 /* Goto (=select) last memo */
3129 mainview->can_show_node_view = FALSE;
3130 nodelist_select(mainview, TREEVIEW_SELECT_LAST);
3131 result = TRUE;
3132 break;
3133 case GDK_j:
3134 case GDK_J:
3135 case GDK_Down:
3136 /* Goto (=select) next memo */
3137 mainview->can_show_node_view = FALSE;
3138 nodelist_select(mainview, TREEVIEW_SELECT_NEXT);
3139 result = TRUE;
3140 break;
3141 case GDK_k:
3142 case GDK_K:
3143 case GDK_Up:
3144 /* Goto (=select) previous memo */
3145 mainview->can_show_node_view = FALSE;
3146 nodelist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3147 result = TRUE;
3148 break;
3149 default:
3150 /* do nothing */
3151 break;
3154 return result;
3157 gboolean
3158 on_node_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3160 MainView* mainview = (MainView*)user_data;
3161 nodeData* nd = getSelectedNode(mainview);
3162 gboolean result = FALSE;
3164 if (nd == NULL) {
3165 return FALSE;
3168 switch (event->keyval) {
3169 case GDK_w:
3170 case GDK_W:
3171 if (nd->typ != NODE_TEXT) {
3172 /* Save changes to file ("write buffer") */
3173 callback_file_save(NULL, mainview);
3174 result = TRUE;
3176 break;
3177 case GDK_BackSpace:
3178 if (event->state & GDK_SHIFT_MASK) {
3179 /* Remove current memo (with confirmation) */
3180 callback_file_delete_node(NULL, mainview);
3181 result = TRUE;
3182 } else if (nd->typ == NODE_CHECKLIST) {
3183 /* Remove current item (with confirmation) */
3184 callback_checklist_delete(NULL, mainview);
3185 result = TRUE;
3186 } else if (nd->typ == NODE_SKETCH) {
3187 /* Undo last sketch action */
3188 callback_undo(NULL, mainview);
3189 result = TRUE;
3191 break;
3192 case GDK_space:
3193 if (nd->typ == NODE_CHECKLIST) {
3194 /* Toggle check of current item */
3195 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3196 result = TRUE;
3197 } else if (nd->typ == NODE_SKETCH) {
3198 /* Toggle eraser tool */
3199 maepad_toggle_gtk_toggle_tool_button(mainview->eraser_tb);
3200 result = TRUE;
3202 break;
3203 case GDK_f:
3204 case GDK_F:
3205 if (nd->typ != NODE_TEXT) {
3206 /* Toggle fullscreen mode */
3207 callback_fullscreen(NULL, mainview);
3208 result = TRUE;
3210 break;
3211 case GDK_h:
3212 case GDK_H:
3213 if (nd->typ != NODE_TEXT) {
3214 /* Hide node view, go to main view ("left") */
3215 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
3216 result = TRUE;
3218 break;
3219 case GDK_o:
3220 case GDK_O:
3221 if (nd->typ == NODE_CHECKLIST) {
3222 /* Insert new checklist item */
3223 callback_checklist_add(NULL, mainview);
3224 result = TRUE;
3226 break;
3227 case GDK_d:
3228 if (nd->typ == NODE_CHECKLIST) {
3229 if (mainview->node_view_prev_keyval == GDK_d) {
3230 /* Yank selected items, then remove them silently */
3231 callback_edit_copy(NULL, mainview);
3232 callback_checklist_delete_real(mainview);
3233 show_banner(mainview, _("Item yanked to clipboard"));
3235 /* Don't remember this key for the next keypress */
3236 mainview->node_view_prev_keyval_reset = TRUE;
3238 result = TRUE;
3241 break;
3242 case GDK_y:
3243 if (nd->typ == NODE_CHECKLIST) {
3244 if (mainview->node_view_prev_keyval == GDK_y) {
3245 /* Non-destructive yanking of items */
3246 callback_edit_copy(NULL, mainview);
3247 show_banner(mainview, _("Item yanked to clipboard"));
3249 /* Don't remember this key for the next keypress */
3250 mainview->node_view_prev_keyval_reset = TRUE;
3252 result = TRUE;
3255 break;
3256 case GDK_p:
3257 case GDK_P:
3258 if (nd->typ == NODE_CHECKLIST) {
3259 /* Paste text in clipboard as items */
3260 callback_edit_paste(NULL, mainview);
3261 result = TRUE;
3263 break;
3264 case GDK_g:
3265 if (nd->typ == NODE_CHECKLIST) {
3266 if (mainview->node_view_prev_keyval == GDK_g) {
3267 /* Goto (=select) first item */
3268 checklist_select(mainview, TREEVIEW_SELECT_FIRST);
3270 /* Don't remember this key for the next keypress */
3271 mainview->node_view_prev_keyval_reset = TRUE;
3273 result = TRUE;
3276 break;
3277 case GDK_G:
3278 if (nd->typ == NODE_CHECKLIST) {
3279 /* Goto (=select) last item */
3280 checklist_select(mainview, TREEVIEW_SELECT_LAST);
3281 result = TRUE;
3283 break;
3284 case GDK_j:
3285 case GDK_J:
3286 case GDK_Down:
3287 if (nd->typ == NODE_CHECKLIST) {
3288 /* Goto (=select) next item */
3289 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
3290 result = TRUE;
3291 } else if (nd->typ == NODE_SKETCH) {
3292 /* Undo last sketch operation */
3293 callback_undo(NULL, mainview);
3294 result = TRUE;
3296 break;
3297 case GDK_k:
3298 case GDK_K:
3299 case GDK_Up:
3300 if (nd->typ == NODE_CHECKLIST) {
3301 /* Goto (=select) previous item */
3302 checklist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3303 result = TRUE;
3304 } else if (nd->typ == NODE_SKETCH) {
3305 /* Redo last sketch operation */
3306 callback_redo(NULL, mainview);
3307 result = TRUE;
3309 break;
3310 case GDK_a:
3311 case GDK_A:
3312 if (nd->typ == NODE_CHECKLIST) {
3313 /* Append text to current node */
3314 checklist_edit_selected(mainview, LINE_EDIT_MODE_APPEND);
3315 result = TRUE;
3317 break;
3318 case GDK_r:
3319 case GDK_R:
3320 case GDK_KP_Enter:
3321 case GDK_Return:
3322 if (nd->typ == NODE_CHECKLIST) {
3323 /* Replace (edit) text of current node */
3324 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
3325 result = TRUE;
3327 break;
3328 case GDK_i:
3329 case GDK_I:
3330 if (nd->typ == NODE_CHECKLIST) {
3331 /* Prepend (insert) text to current node */
3332 checklist_edit_selected(mainview, LINE_EDIT_MODE_PREPEND);
3333 result = TRUE;
3335 break;
3336 default:
3337 /* do nothing */
3338 break;
3341 return result;
3344 gboolean
3345 on_main_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3347 MainView* mainview = (MainView*)user_data;
3349 if (mainview->main_view_prev_keyval_reset) {
3350 /* Forget last-pressed key value */
3351 mainview->main_view_prev_keyval = GDK_VoidSymbol;
3352 mainview->main_view_prev_keyval_reset = FALSE;
3353 } else {
3354 /* Remember last keyval for double-press bindings */
3355 mainview->main_view_prev_keyval = event->keyval;
3358 return FALSE;
3361 gboolean
3362 on_node_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3364 MainView* mainview = (MainView*)user_data;
3366 if (mainview->node_view_prev_keyval_reset) {
3367 /* Forget last-pressed key value */
3368 mainview->node_view_prev_keyval = GDK_VoidSymbol;
3369 mainview->node_view_prev_keyval_reset = FALSE;
3370 } else {
3371 /* Remember last keyval for double-press bindings */
3372 mainview->node_view_prev_keyval = event->keyval;
3375 return FALSE;
3378 gboolean
3379 on_checklist_longpress_timeout(gpointer user_data)
3381 MainView* mainview = (MainView*)user_data;
3382 callback_checklist_edit(NULL, mainview);
3383 mainview->checklist_longpress_source_id = 0;
3384 return FALSE;
3387 gboolean
3388 on_checklist_button_press(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3390 MainView* mainview = (MainView*)user_data;
3391 GtkTreePath* path;
3392 GtkTreeViewColumn* column;
3393 GtkTreeSelection* selection;
3395 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
3396 event->x,
3397 event->y,
3398 &path,
3399 &column,
3400 NULL,
3401 NULL)) {
3402 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
3404 if (gtk_tree_selection_path_is_selected(selection, path)) {
3405 if (column == mainview->checklist_column_check) {
3406 /* Check column touched - toggle checklist item */
3407 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3408 } else if (column == mainview->checklist_column_text) {
3409 mainview->checklist_longpress_source_id = g_timeout_add(
3410 CHECKLIST_LONGPRESS_EDIT_DELAY,
3411 on_checklist_longpress_timeout,
3412 mainview);
3414 return TRUE;
3417 gtk_tree_path_free(path);
3420 return FALSE;
3423 void
3424 checklist_abort_longpress(MainView* mainview)
3426 /* Abort the longpress action on the checklist */
3427 if (mainview->checklist_longpress_source_id != 0) {
3428 g_source_remove(mainview->checklist_longpress_source_id);
3429 mainview->checklist_longpress_source_id = 0;
3433 gboolean
3434 on_checklist_button_release(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3436 MainView* mainview = (MainView*)user_data;
3437 checklist_abort_longpress(mainview);
3438 return FALSE;
3441 gboolean
3442 on_checklist_start_panning(HildonPannableArea* area, gpointer user_data)
3444 MainView* mainview = (MainView*)user_data;
3445 checklist_abort_longpress(mainview);
3446 return FALSE;
3449 void callback_fullscreen(GtkToolButton* tool_button, gpointer user_data)
3451 MainView* mainview = (MainView*)user_data;
3452 gtk_window_fullscreen(GTK_WINDOW(mainview->data->node_view));
3455 void
3456 callback_sketch_button_toggled(HildonCheckButton* button, gpointer user_data)
3458 MainView* mainview = (MainView*)user_data;
3459 gboolean active = hildon_check_button_get_active(button);
3461 if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_square)) {
3462 sketchwidget_set_shift(mainview->sk, active);
3463 } else if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_filled)) {
3464 sketchwidget_set_fillmode(mainview->sk, active);
3468 void callback_buffer_modified(GtkAction * action, gpointer data)
3470 MainView *mainview = (MainView *) data;
3471 g_assert(mainview != NULL && mainview->data != NULL);
3473 mainview->file_edited = TRUE;
3476 GtkTreeRowReference *read_sqlite3_data(MainView * mainview, unsigned int parentid, GtkTreeRowReference * parenttree, unsigned int selected, GtkTreeStore * model)
3478 GtkTreeRowReference *resref = NULL;
3480 char q[256];
3482 g_snprintf(q, sizeof(q), "SELECT nodeid, bodytype, name, nameblob, lastmodified, flags FROM %s WHERE parent=%d ORDER BY ord", datatable_tmpname, parentid);
3484 sqlite3_stmt *stmt = NULL;
3485 const char *dum;
3486 int rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3488 if (rc)
3490 maepad_warning("Error reading SQLite3 data: %s", sqlite3_errmsg(mainview->db));
3491 return (NULL);
3494 rc = SQLITE_BUSY;
3495 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3497 rc = sqlite3_step(stmt);
3498 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3499 break;
3500 else if (rc == SQLITE_ROW)
3502 int nodeid = sqlite3_column_int(stmt, 0);
3503 int typ = sqlite3_column_int(stmt, 1);
3504 const unsigned char *name = sqlite3_column_text(stmt, 2);
3505 const unsigned char *nameblob = sqlite3_column_text(stmt, 3);
3506 int lastmod = sqlite3_column_int(stmt, 4);
3507 int flags = sqlite3_column_int(stmt, 5);
3509 if ((typ != NODE_TEXT && typ != NODE_SKETCH && typ != NODE_CHECKLIST) || (name == NULL && nameblob == NULL)) {
3510 maepad_warning("Unknown node type in database: %d (skipping)", typ);
3511 continue;
3514 nodeData *node = g_malloc(sizeof(nodeData));
3516 node->sql3id = nodeid;
3517 node->typ = typ;
3518 node->flags = flags;
3519 node->name = NULL;
3520 node->namepix = NULL;
3521 if (name != NULL) {
3522 node->name = g_strdup((char *)name);
3523 } else {
3524 node->name = g_strdup(_("Unnamed memo"));
3526 /*if (nameblob != NULL)
3528 int blobsize = sqlite3_column_bytes(stmt, 3);
3530 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
3531 GError *err = NULL;
3533 gdk_pixbuf_loader_write(pl, (guchar *) nameblob, blobsize, &err);
3534 if (err != NULL)
3536 fprintf(stderr, "Error loading nodename! %s\n", err->message);
3537 g_error_free(err);
3538 err = NULL;
3540 gdk_pixbuf_loader_close(pl, NULL);
3541 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
3543 if (GDK_IS_PIXBUF(pixbuf))
3544 node->namepix = pixbuf;
3546 node->lastMod = lastmod;
3548 GtkTreeIter parentiter, newiter;
3549 void *par = NULL;
3551 if (parenttree != NULL)
3553 GtkTreePath *pa = gtk_tree_row_reference_get_path(parenttree);
3555 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parentiter, pa);
3556 gtk_tree_path_free(pa);
3557 par = &parentiter;
3560 gtk_tree_store_append(model, &newiter, par);
3561 gtk_tree_store_set(model, &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
3563 GtkTreePath *pa = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &newiter);
3565 GtkTreeRowReference *newref = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), pa);
3567 if (selected == nodeid)
3568 resref = newref;
3570 gtk_tree_path_free(pa);
3571 GtkTreeRowReference *r = read_sqlite3_data(mainview, nodeid, newref, selected,
3572 model);
3574 if (resref != newref)
3575 gtk_tree_row_reference_free(newref);
3577 if (r != NULL)
3579 if (resref == NULL)
3580 resref = r;
3581 else
3582 gtk_tree_row_reference_free(r); /*safeguard */
3587 if (stmt)
3588 sqlite3_finalize(stmt);
3590 return (resref); /*ref to supposed-to-be-selected treeitem */
3594 * read file
3596 gboolean read_file_to_buffer(MainView * mainview)
3598 char tq[512];
3600 g_assert(mainview != NULL);
3601 gboolean res = FALSE;
3603 gchar *filename = mainview->file_name;
3605 new_file(mainview);
3606 mainview->file_name = filename;
3607 mainview->loading=TRUE;
3609 maepad_message("Reading database file: %s", filename);
3611 int rc;
3612 sqlite3_stmt *stmt = NULL;
3614 rc = sqlite3_open(filename, &mainview->db);
3617 if (rc)
3619 maepad_warning("Cannot open database %s: %s", filename, sqlite3_errmsg(mainview->db));
3620 break;
3623 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
3625 char *q = "SELECT skey, sval FROM settings";
3626 const char *dum;
3628 rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3629 if (rc)
3631 maepad_warning("Error reading settings: %s", sqlite3_errmsg(mainview->db));
3632 break;
3635 unsigned int selectedCard = 0;
3636 unsigned int curDataVersion = 0;
3637 unsigned int curChecklistVersion = 0;
3639 rc = SQLITE_BUSY;
3640 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3642 rc = sqlite3_step(stmt);
3643 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3644 break;
3645 else if (rc == SQLITE_ROW)
3647 const gchar* col_key = (const gchar*)sqlite3_column_text(stmt, 0);
3648 const gchar* col_val = (const gchar*)sqlite3_column_text(stmt, 1);
3649 if (!strcmp(col_key, "selectedNode"))
3651 gint tmp = atoi((char *)col_val);
3653 if (tmp > 0)
3654 selectedCard = tmp;
3656 if (!strcmp(col_key, "dataVersion"))
3658 gint tmp = atoi((char *)col_val);
3660 if (tmp > 0)
3661 curDataVersion = tmp;
3663 if (!strcmp(col_key, "checklistVersion"))
3665 gint tmp = atoi((char *)col_val);
3667 if (tmp > 0)
3668 curChecklistVersion = tmp;
3670 if (!strcmp(col_key, "newNodeDlgCreateChild"))
3672 gint tmp = atoi((char *)col_val);
3674 mainview->newnodedialog_createchild = TRUE;
3675 if (tmp == 0)
3676 mainview->newnodedialog_createchild = FALSE;
3678 if (!strcmp(col_key, "brushSize"))
3680 gint tmp = atoi((char *)col_val);
3681 if (tmp>0) sk_set_brushsize(mainview, tmp);
3683 if (!strcmp(col_key, "brushColor"))
3685 unsigned long tmp = atol((char *)col_val);
3686 GdkColor c2;
3688 c2.red = ((tmp & 0xFF0000) >> 16) << 8;
3689 c2.green = ((tmp & 0xFF00) >> 8) << 8;
3690 c2.blue = (tmp & 0xFF) << 8;
3691 sketchwidget_set_brushcolor(mainview->sk, c2);
3693 if (mainview->current_color != NULL) {
3694 gdk_color_free(mainview->current_color);
3696 mainview->current_color = gdk_color_copy(&c2);
3701 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
3703 maepad_warning("Error reading data: %s", sqlite3_errmsg(mainview->db));
3704 break;
3707 if (stmt) {
3708 sqlite3_finalize(stmt);
3709 stmt = NULL;
3712 gboolean resback = FALSE;
3714 while(curDataVersion < datatableversion)
3716 if (curDataVersion == 0)
3718 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3719 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3721 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_name, datatable_backupname);
3722 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3723 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3724 break;
3726 resback = TRUE;
3728 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
3729 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3730 maepad_warning("Error creating table: %s", datatable_name);
3731 break;
3733 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);
3734 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3735 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_backupname);
3736 break;
3739 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3740 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3742 curDataVersion = datatableversion;
3744 break;
3747 if (curDataVersion != datatableversion)
3749 maepad_warning("Data table version mismatch: %d <=> %d", curDataVersion, datatableversion);
3751 if (resback == TRUE)
3753 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_name);
3754 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3755 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_backupname, datatable_name);
3756 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3759 break;
3763 while(curChecklistVersion < checklisttableversion)
3765 if (curChecklistVersion == 0) /*no checklisttable at all*/
3767 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
3768 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3769 maepad_warning("Error creating checklist table during schema upgrade");
3770 break;
3772 curChecklistVersion = checklisttableversion;
3774 break;
3778 GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
3780 g_object_ref(model);
3781 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
3785 char tq[512];
3787 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, datatable_tmpname, datatable);
3788 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3789 maepad_warning("Error creating temp table: %s", datatable_tmpname);
3790 break;
3792 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", datatable_tmpname, datatable_tmpname, dataindex);
3793 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3794 maepad_warning("Error creating temp index for %s", datatable_tmpname);
3795 break;
3797 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_tmpname, datatable_name);
3798 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3799 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_tmpname);
3800 break;
3803 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, checklisttable_tmpname, checklisttable);
3804 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3805 maepad_warning("Error creating temp table: %s", checklisttable_tmpname);
3806 break;
3808 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", checklisttable_tmpname, checklisttable_tmpname, checklistindex);
3809 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3810 maepad_warning("Error creating temp index for %s", checklisttable_tmpname);
3811 break;
3813 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_tmpname, checklisttable_name);
3814 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3815 maepad_warning("Error copying data from %s to %s", checklisttable_name, checklisttable_tmpname);
3816 break;
3819 while(FALSE);
3821 GtkTreeRowReference *selectedRef = read_sqlite3_data(mainview, 0, NULL, selectedCard, model);
3823 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), GTK_TREE_MODEL(model));
3824 g_object_unref(model);
3825 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
3827 if (selectedRef != NULL)
3829 GtkTreeIter seliter;
3831 if (ref2iter(GTK_TREE_MODEL(model), selectedRef, &seliter) == TRUE)
3833 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
3834 gtk_tree_selection_select_iter(selection, &seliter);
3837 gtk_tree_row_reference_free(selectedRef);
3839 res = TRUE;
3841 while(FALSE);
3843 if (stmt) {
3844 sqlite3_finalize(stmt);
3848 mainview->loading=FALSE;
3850 return (res);
3854 * write to file
3856 void write_buffer_to_file(MainView * mainview)
3858 maepad_message("Writing database to file: %s", mainview->file_name);
3859 saveCurrentData(mainview);
3861 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
3862 /*update ord value in database for all nodes*/
3863 gtk_tree_model_foreach(GTK_TREE_MODEL(model),(GtkTreeModelForeachFunc) foreach_func_update_ord,mainview);
3865 busy_enter(mainview);
3867 char tq[512];
3869 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", misctable_name);
3870 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3872 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
3873 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3875 gint nndcc = 1;
3877 if (mainview->newnodedialog_createchild == FALSE)
3878 nndcc = 0;
3879 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('newNodeDlgCreateChild', '%d');", misctable_name, nndcc);
3880 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3882 nodeData *node = getSelectedNode(mainview);
3884 if (node)
3886 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('selectedNode', '%d');", misctable_name, node->sql3id);
3887 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3890 guint bsize = sketchwidget_get_brushsize(mainview->sk);
3891 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushSize', '%d');", misctable_name, bsize);
3892 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3894 if (mainview->current_color == NULL) {
3895 GdkColor color = {0, 0, 0, 0};
3896 mainview->current_color = gdk_color_copy(&color);
3898 unsigned long bcol = ((mainview->current_color->red >> 8) << 16) |
3899 ((mainview->current_color->green >> 8) << 8) |
3900 ((mainview->current_color->blue) >> 8);
3902 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushColor', '%lu');", misctable_name, bcol);
3903 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3905 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('dataVersion', '%d');", misctable_name, datatableversion);
3906 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3908 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('checklistVersion', '%d');", misctable_name, checklisttableversion);
3909 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3911 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3912 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3913 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_backupname, datatable);
3914 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3916 maepad_warning("Error creating backup table: %s", datatable_backupname);
3917 show_banner(mainview, _("Error creating backup table"));
3919 busy_leave(mainview);
3920 return;
3922 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_backupname, datatable_name);
3923 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3925 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3926 show_banner(mainview, _("Error creating backup table"));
3928 busy_leave(mainview);
3929 return;
3931 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3932 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3934 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_tmpname);
3935 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3937 maepad_warning("Error saving table %s to %s", datatable_tmpname, datatable_name);
3938 show_banner(mainview, _("Error saving table"));
3940 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3941 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3943 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_backupname);
3944 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3945 maepad_warning("Error restoring backup. Data lost :(");
3948 busy_leave(mainview);
3949 return;
3952 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3953 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3955 /*checklist*/
3956 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3957 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3958 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_backupname, checklisttable);
3959 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3961 maepad_warning("Error creating backup table: %s", checklisttable_backupname);
3962 show_banner(mainview, _("Error creating checklist backup table"));
3964 busy_leave(mainview);
3965 return;
3968 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_backupname, checklisttable_name);
3969 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3971 maepad_warning("Error backing up table %s to %s", checklisttable_name, checklisttable_backupname);
3972 show_banner(mainview, _("Error creating checklist backup table"));
3974 busy_leave(mainview);
3975 return;
3977 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3978 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3980 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_tmpname);
3981 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3983 maepad_warning("Error saving table %s to %s", checklisttable_tmpname, checklisttable_name);
3984 show_banner(mainview, _("Error saving checklist table"));
3986 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3987 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3989 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_backupname);
3990 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3991 maepad_warning("Error restoring backup. Data lost :(");
3993 busy_leave(mainview);
3994 return;
3997 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3998 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
4000 mainview->file_edited = FALSE;
4001 busy_leave(mainview);
4002 show_banner(mainview, _("Changes saved"));
4005 void callback_checklist_change(GtkTreeSelection *selection, MainView *mainview)
4007 g_assert(mainview != NULL && mainview->data != NULL);
4009 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
4010 g_signal_handlers_block_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
4011 g_signal_handlers_block_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
4013 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), FALSE);
4014 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), FALSE);
4015 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), FALSE);
4017 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4018 GList* l=gtk_tree_selection_get_selected_rows(selection, NULL);
4020 gboolean gotit=FALSE;
4022 GList* cur=l;
4023 while(cur)
4025 GtkTreePath *path=cur->data;
4027 if (!gotit)
4029 GtkTreeIter iter;
4030 if (gtk_tree_model_get_iter(model, &iter, path))
4032 gint styletoset_weight;
4033 gboolean styletoset_strike;
4034 gboolean ischecked;
4036 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, -1);
4037 if (styletoset_weight==PANGO_WEIGHT_BOLD) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), TRUE);
4038 if (styletoset_strike==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), TRUE);
4039 if (ischecked==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), TRUE);
4040 gotit=TRUE;
4043 gtk_tree_path_free(path);
4044 cur=cur->next;
4047 g_list_free(l);
4049 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
4050 g_signal_handlers_unblock_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
4051 g_signal_handlers_unblock_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
4054 void callback_checklist_paste(MainView *mainview)
4056 g_assert(mainview != NULL && mainview->data != NULL);
4057 gchar **entries;
4058 gint length, i;
4060 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4061 GtkTreeIter toplevel;
4062 gchar *pasted_text = gtk_clipboard_wait_for_text(mainview->clipboard);
4064 entries = g_strsplit(pasted_text, "\n", 0);
4065 length = g_strv_length(entries);
4067 for (i=0; i<length; i++) {
4068 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
4069 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, FALSE, CHECKNODE_TEXT, entries[i], -1);
4072 mainview->checklist_edited = TRUE;
4073 g_free(pasted_text);
4074 g_strfreev(entries);
4077 void callback_checklist_add(GtkAction *action, MainView *mainview)
4079 g_assert(mainview != NULL && mainview->data != NULL);
4081 gchar* text = show_line_edit_dialog(mainview, _("Add new checklist item"), _("Name:"), _("Add"), "");
4083 if (text != NULL) {
4084 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4085 GtkTreeIter toplevel;
4086 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
4088 gtk_list_store_set(GTK_LIST_STORE(model),
4089 &toplevel,
4090 CHECKNODE_CHECKED, FALSE,
4091 CHECKNODE_TEXT, text,
4092 -1);
4094 GtkTreePath *path = gtk_tree_model_get_path(model, &toplevel);
4095 if (path) {
4096 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->listview), path, mainview->checklist_column_text, FALSE);
4097 gtk_tree_path_free(path);
4100 mainview->checklist_edited = TRUE;
4104 void
4105 checklist_edit_selected(MainView* mainview, LineEditMode mode)
4107 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4109 if (gtk_tree_selection_count_selected_rows(selection) == 0) {
4110 show_banner(mainview, _("Select items first"));
4111 return;
4114 GtkTreeModel* model;
4115 GtkTreeIter iter;
4117 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4118 gchar* old_text = NULL;
4119 gtk_tree_model_get(model, &iter, CHECKNODE_TEXT, &old_text, -1);
4121 gchar* new_text = show_line_edit_dialog_full(mainview, _("Edit checklist item"), _("New name:"), _("Save"), old_text, mode);
4123 if (new_text != NULL) {
4124 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_TEXT, new_text, -1);
4125 mainview->checklist_edited = TRUE;
4126 g_free(new_text);
4129 g_free(old_text);
4133 void callback_checklist_edit(GtkAction *action, MainView *mainview)
4135 g_assert(mainview != NULL && mainview->data != NULL);
4136 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
4139 void callback_checklist_delete(GtkAction *action, MainView *mainview)
4141 g_assert(mainview != NULL && mainview->data != NULL);
4143 if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)))==0) {
4144 show_banner(mainview, _("Select items first"));
4145 return;
4148 if (show_confirmation(mainview, _("Delete selected checklist item?"))) {
4149 callback_checklist_delete_real(mainview);
4153 void callback_checklist_delete_real(MainView* mainview)
4155 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4156 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
4158 /* Select the item after the selection */
4159 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
4161 GList* rowrefs=NULL;
4162 GList* cur=l;
4163 while(cur)
4165 GtkTreePath *path=cur->data;
4167 GtkTreeIter iter;
4168 if (gtk_tree_model_get_iter(model, &iter, path))
4170 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, path);
4171 rowrefs=g_list_append(rowrefs, rowref);
4173 gtk_tree_path_free(path);
4174 cur=cur->next;
4176 g_list_free(l);
4177 checklist_remove_rowrefs(mainview, rowrefs, FALSE);
4180 void
4181 checklist_remove_rowrefs(MainView* mainview, GList* rowrefs, gboolean show_result)
4183 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4184 GList* cur = rowrefs;
4185 gint count = 0;
4187 busy_enter(mainview);
4189 while (cur) {
4190 GtkTreeRowReference* rowref = cur->data;
4191 GtkTreePath* path = gtk_tree_row_reference_get_path(rowref);
4192 if (path != NULL) {
4193 GtkTreeIter iter;
4194 if (gtk_tree_model_get_iter(model, &iter, path)) {
4195 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
4196 count++;
4198 gtk_tree_path_free(path);
4200 gtk_tree_row_reference_free(rowref);
4201 cur = cur->next;
4203 g_list_free(rowrefs);
4205 busy_leave(mainview);
4207 if (count && show_result) {
4208 gchar* message = g_strdup_printf(N_("%d item removed", "%d items removed", count), count);
4209 show_banner(mainview, message);
4210 g_free(message);
4213 mainview->checklist_edited = TRUE;
4216 /* Private callback for show_confirmation() - handle keyboard input */
4217 gboolean
4218 on_confirmation_key_press_event(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
4220 GtkDialog* dialog = GTK_DIALOG(widget);
4222 switch (event->keyval) {
4223 /* Positive response - Enter, Return or y */
4224 case GDK_KP_Enter:
4225 case GDK_Return:
4226 case GDK_y:
4227 case GDK_Y:
4228 gtk_dialog_response(dialog, GTK_RESPONSE_OK);
4229 return TRUE;
4231 /* Negative response - Backspace, Escape or n */
4232 case GDK_BackSpace:
4233 case GDK_Escape:
4234 case GDK_n:
4235 case GDK_N:
4236 gtk_dialog_response(dialog, GTK_RESPONSE_CANCEL);
4237 return TRUE;
4239 /* Don't handle the rest of the keys */
4240 default:
4241 return FALSE;
4246 /* Ask the user for confirmation of a specific action */
4247 gboolean
4248 show_confirmation(MainView* mainview, gchar* question)
4250 GtkDialog* dialog = GTK_DIALOG(hildon_note_new_confirmation(
4251 GTK_WINDOW(mainview->data->main_view), question));
4252 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
4253 g_signal_connect(G_OBJECT(dialog), "key-press-event",
4254 G_CALLBACK(on_confirmation_key_press_event), NULL);
4256 gint response = gtk_dialog_run(dialog);
4257 gtk_widget_destroy(GTK_WIDGET(dialog));
4259 return (response == GTK_RESPONSE_OK);
4262 /* Show a information banner to the user (non-modal) */
4263 void
4264 show_banner(MainView* mainview, const gchar* text)
4266 hildon_banner_show_information(GTK_WIDGET(mainview_get_dialog_parent(mainview)), NULL, text);
4269 typedef struct {
4270 GtkWidget* dialog;
4271 gboolean can_close_window;
4272 } LineEditDialogData;
4274 /* Helper function to close line edit dialog on Backspace */
4275 gboolean
4276 line_edit_dialog_key_press(GtkWidget* w, GdkEventKey* event, gpointer user_data)
4278 LineEditDialogData* dialogdata = (LineEditDialogData*)user_data;
4279 GtkEntry* entry = GTK_ENTRY(w);
4281 if (event->keyval == GDK_BackSpace &&
4282 dialogdata->can_close_window &&
4283 strcmp(gtk_entry_get_text(entry), "") == 0) {
4284 gtk_dialog_response(GTK_DIALOG(dialogdata->dialog), GTK_RESPONSE_CANCEL);
4285 return TRUE;
4288 return FALSE;
4291 /* Let the user enter or edit a line of text */
4292 gchar*
4293 show_line_edit_dialog_full(MainView* mainview, const gchar* title,
4294 const gchar* label_text, const gchar* action, const gchar* text,
4295 LineEditMode mode)
4297 GtkWidget* edit_dialog;
4298 GtkWidget* label;
4299 GtkWidget* entry;
4300 GtkWidget* hbox;
4301 gchar* result = NULL;
4302 LineEditDialogData dialogdata;
4304 edit_dialog = GTK_WIDGET(gtk_dialog_new());
4305 gtk_window_set_title(GTK_WINDOW(edit_dialog), title);
4306 gtk_window_set_transient_for(GTK_WINDOW(edit_dialog), mainview_get_dialog_parent(mainview));
4308 label = GTK_WIDGET(gtk_label_new(label_text));
4310 entry = hildon_entry_new(HILDON_SIZE_AUTO);
4311 gtk_entry_set_text(GTK_ENTRY(entry), text);
4312 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
4313 switch (mode) {
4314 case LINE_EDIT_MODE_DEFAULT:
4315 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
4316 break;
4317 case LINE_EDIT_MODE_APPEND:
4318 gtk_editable_select_region(GTK_EDITABLE(entry), -1, -1);
4319 break;
4320 case LINE_EDIT_MODE_PREPEND:
4321 gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
4322 break;
4323 default:
4324 break;
4327 gtk_dialog_add_button(GTK_DIALOG(edit_dialog), action, GTK_RESPONSE_OK);
4328 gtk_dialog_set_default_response(GTK_DIALOG(edit_dialog), GTK_RESPONSE_OK);
4330 dialogdata.dialog = edit_dialog;
4331 dialogdata.can_close_window = (strcmp(text, "") == 0);
4332 g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(line_edit_dialog_key_press), &dialogdata);
4334 hbox = GTK_WIDGET(gtk_hbox_new(FALSE, 10));
4336 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(edit_dialog))), GTK_WIDGET(hbox));
4337 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
4338 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
4340 gtk_widget_show_all(GTK_WIDGET(hbox));
4342 while (TRUE) {
4343 if (gtk_dialog_run(GTK_DIALOG(edit_dialog)) == GTK_RESPONSE_OK) {
4344 result = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
4345 if (strcmp(result, "") != 0) {
4346 break;
4347 } else {
4348 show_banner(mainview, _("Please enter a non-empty text"));
4349 g_free(result);
4350 result = NULL;
4352 } else {
4353 result = NULL;
4354 break;
4358 gtk_widget_destroy(GTK_WIDGET(edit_dialog));
4359 return result;
4362 void
4363 treeview_scroll_to_selection(MainView* mainview, TreeViewType type)
4365 GtkTreeView* treeview = NULL;
4366 HildonPannableArea* pannable_area = NULL;
4367 GtkTreeModel* model = NULL;
4368 GtkTreeSelection* selection = NULL;
4369 GtkTreePath* path = NULL;
4370 GtkTreeIter iter;
4371 GdkRectangle rect;
4372 gint y;
4374 switch (type) {
4375 case TREEVIEW_MAINVIEW:
4376 treeview = GTK_TREE_VIEW(mainview->treeview);
4377 pannable_area = HILDON_PANNABLE_AREA(mainview->scrolledtree);
4378 break;
4379 case TREEVIEW_CHECKLIST:
4380 treeview = GTK_TREE_VIEW(mainview->listview);
4381 pannable_area = HILDON_PANNABLE_AREA(mainview->listscroll);
4382 break;
4383 default:
4384 g_assert_not_reached();
4385 break;
4388 /* Let the view scroll so that the selected item is visible */
4389 selection = gtk_tree_view_get_selection(treeview);
4390 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4391 path = gtk_tree_model_get_path(model, &iter);
4393 gtk_tree_view_get_background_area(treeview, path, NULL, &rect);
4394 gtk_tree_view_convert_bin_window_to_tree_coords(treeview,
4395 0, rect.y, NULL, &y);
4396 hildon_pannable_area_scroll_to(pannable_area, -1, y);
4398 gtk_tree_path_free(path);
4402 gboolean
4403 checklist_scroll_to_selection(gpointer user_data)
4405 MainView* mainview = (MainView*)user_data;
4406 treeview_scroll_to_selection(mainview, TREEVIEW_CHECKLIST);
4407 return FALSE;
4410 gboolean
4411 nodelist_scroll_to_selection(gpointer user_data)
4413 MainView* mainview = (MainView*)user_data;
4414 treeview_scroll_to_selection(mainview, TREEVIEW_MAINVIEW);
4415 return FALSE;
4418 void
4419 checklist_select(MainView* mainview, TreeviewSelectType type)
4421 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4422 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4423 GtkTreeIter iter;
4424 GtkTreeIter last;
4425 GtkTreePath* path;
4427 switch (type) {
4428 case TREEVIEW_SELECT_FIRST:
4429 if (gtk_tree_model_get_iter_first(model, &iter)) {
4430 path = gtk_tree_model_get_path(model, &iter);
4431 gtk_tree_selection_select_path(selection, path);
4432 gtk_tree_path_free(path);
4434 break;
4435 case TREEVIEW_SELECT_LAST:
4436 if (gtk_tree_model_get_iter_first(model, &iter)) {
4437 do {
4438 last = iter;
4439 } while (gtk_tree_model_iter_next(model, &iter));
4440 path = gtk_tree_model_get_path(model, &last);
4441 gtk_tree_selection_select_path(selection, path);
4442 gtk_tree_path_free(path);
4444 break;
4445 case TREEVIEW_SELECT_PREVIOUS:
4446 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4447 path = gtk_tree_model_get_path(model, &iter);
4448 if (gtk_tree_path_prev(path)) {
4449 gtk_tree_selection_select_path(selection, path);
4451 gtk_tree_path_free(path);
4453 break;
4454 case TREEVIEW_SELECT_NEXT:
4455 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4456 path = gtk_tree_model_get_path(model, &iter);
4457 gtk_tree_path_next(path);
4458 gtk_tree_selection_select_path(selection, path);
4459 gtk_tree_path_free(path);
4461 break;
4462 default:
4463 g_assert_not_reached();
4464 break;
4467 checklist_scroll_to_selection(mainview);
4470 * This is a workaround: The HildonPannableArea does not seem to
4471 * scroll to the right position (especially when going to the first
4472 * or last item in the list), so we simply scroll again after 500ms.
4474 g_timeout_add(500, checklist_scroll_to_selection, mainview);
4477 void
4478 nodelist_select(MainView* mainview, TreeviewSelectType type)
4480 GtkTreeView* treeview = GTK_TREE_VIEW(mainview->treeview);
4481 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
4482 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
4483 GtkTreeIter iter;
4484 GtkTreeIter last;
4485 GtkTreeIter child;
4486 GtkTreePath* path;
4488 switch (type) {
4489 case TREEVIEW_SELECT_FIRST:
4490 if (gtk_tree_model_get_iter_first(model, &iter)) {
4491 path = gtk_tree_model_get_path(model, &iter);
4492 gtk_tree_selection_select_path(selection, path);
4493 gtk_tree_path_free(path);
4495 break;
4496 case TREEVIEW_SELECT_LAST:
4497 if (gtk_tree_model_get_iter_first(model, &iter)) {
4498 do {
4499 last = iter;
4500 if (gtk_tree_model_iter_children(model, &child, &last)) {
4501 do {
4502 last = child;
4503 } while (gtk_tree_model_iter_next(model, &child));
4505 } while (gtk_tree_model_iter_next(model, &iter));
4506 path = gtk_tree_model_get_path(model, &last);
4507 gtk_tree_selection_select_path(selection, path);
4508 gtk_tree_path_free(path);
4510 break;
4511 case TREEVIEW_SELECT_PREVIOUS:
4512 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4513 path = gtk_tree_model_get_path(model, &iter);
4514 if (gtk_tree_path_prev(path)) {
4515 gtk_tree_selection_select_path(selection, path);
4516 } else if (gtk_tree_path_up(path)) {
4517 gtk_tree_selection_select_path(selection, path);
4519 gtk_tree_path_free(path);
4521 break;
4522 case TREEVIEW_SELECT_NEXT:
4523 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4524 path = gtk_tree_model_get_path(model, &iter);
4525 gtk_tree_path_down(path);
4526 while (!gtk_tree_model_get_iter(model, &iter, path)) {
4527 /* Child item does not exist - bubble up to next item */
4528 gtk_tree_path_up(path);
4529 gtk_tree_path_next(path);
4531 if (gtk_tree_path_get_depth(path) == 0) {
4532 /* avoid infinite loops */
4533 break;
4537 if (gtk_tree_model_get_iter(model, &iter, path)) {
4538 gtk_tree_selection_select_path(selection, path);
4541 gtk_tree_path_free(path);
4543 break;
4544 default:
4545 g_assert_not_reached();
4546 break;
4549 nodelist_scroll_to_selection(mainview);
4552 * This is a workaround: The HildonPannableArea does not seem to
4553 * scroll to the right position (especially when going to the first
4554 * or last item in the list), so we simply scroll again after 500ms.
4556 g_timeout_add(500, nodelist_scroll_to_selection, mainview);