Display node type in overview list
[maepad.git] / src / ui / callbacks.c
bloba195c707d39d2eedf4286f289ff3a972d34cc5a5
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;
107 nodeData *nd = getSelectedNode(mainview);
109 if (mainview->toolbar == NULL || mainview->sk == NULL) {
110 return FALSE;
113 sketch_scroll = GTK_WIDGET(sketchwidget_get_mainwidget(mainview->sk));
115 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
116 if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
117 gtk_widget_hide(mainview->toolbar);
118 gtk_scrolled_window_set_policy(
119 GTK_SCROLLED_WINDOW(sketch_scroll),
120 GTK_POLICY_NEVER,
121 GTK_POLICY_NEVER);
122 if (nd->typ == NODE_CHECKLIST) {
123 /* Enable portrait mode when entering fullscreen */
124 hildon_gtk_window_set_portrait_flags(mainview_get_dialog_parent(mainview),
125 HILDON_PORTRAIT_MODE_REQUEST | HILDON_PORTRAIT_MODE_SUPPORT);
127 } else {
128 gtk_widget_show(mainview->toolbar);
129 gtk_scrolled_window_set_policy(
130 GTK_SCROLLED_WINDOW(sketch_scroll),
131 GTK_POLICY_AUTOMATIC,
132 GTK_POLICY_AUTOMATIC);
133 if (nd->typ == NODE_CHECKLIST) {
134 /* Disable portrait mode when leaving fullscreen */
135 hildon_gtk_window_set_portrait_flags(mainview_get_dialog_parent(mainview),
136 HILDON_PORTRAIT_MODE_SUPPORT);
141 return FALSE;
144 void set_busy(MainView* mainview, SetBusyType update)
146 switch (update) {
147 case BUSY_RESET:
148 mainview->busyrefcount = 0;
149 break;
150 case BUSY_INCREMENT:
151 mainview->busyrefcount++;
152 break;
153 case BUSY_DECREMENT:
154 if (mainview->busyrefcount > 0) {
155 mainview->busyrefcount--;
157 break;
158 default:
159 g_assert_not_reached();
160 return;
163 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->main_view), (mainview->busyrefcount > 0));
164 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->node_view), (mainview->busyrefcount > 0));
167 void prepareUIforNodeChange(MainView * mainview, nodeType typ)
169 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), TRUE);
170 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), TRUE);
172 if (typ == NODE_TEXT)
174 gtk_widget_show(GTK_WIDGET(mainview->font_tb));
175 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
176 gtk_widget_show(GTK_WIDGET(mainview->italic_tb));
177 gtk_widget_show(GTK_WIDGET(mainview->underline_tb));
178 gtk_widget_show(GTK_WIDGET(mainview->bullet_tb));
179 gtk_widget_show(mainview->tools_font);
181 else
183 gtk_widget_hide(GTK_WIDGET(mainview->font_tb));
184 gtk_widget_hide(GTK_WIDGET(mainview->bold_tb));
185 gtk_widget_hide(GTK_WIDGET(mainview->italic_tb));
186 gtk_widget_hide(GTK_WIDGET(mainview->underline_tb));
187 gtk_widget_hide(GTK_WIDGET(mainview->bullet_tb));
188 gtk_widget_hide(mainview->tools_font);
191 if (typ == NODE_SKETCH)
193 /* gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));*/
194 gtk_widget_show(GTK_WIDGET(mainview->eraser_tb));
195 gtk_widget_show(GTK_WIDGET(mainview->brushsize_tb));
196 gtk_widget_show(GTK_WIDGET(mainview->sketchlines_tb));
197 gtk_widget_show(GTK_WIDGET(mainview->shape_tb));
198 gtk_widget_show(GTK_WIDGET(mainview->sharing_tb));
199 gtk_widget_show(mainview->tools_color);
200 gtk_widget_show(mainview->tools_brushsize);
201 gtk_widget_show(mainview->tools_pagestyle);
202 gtk_widget_show(mainview->tools_shape);
203 gtk_widget_show(mainview->tools_pressure);
205 else
207 /* gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));*/
208 gtk_widget_hide(GTK_WIDGET(mainview->eraser_tb));
209 gtk_widget_hide(GTK_WIDGET(mainview->brushsize_tb));
210 gtk_widget_hide(GTK_WIDGET(mainview->sketchlines_tb));
211 gtk_widget_hide(GTK_WIDGET(mainview->shape_tb));
212 gtk_widget_hide(GTK_WIDGET(mainview->sharing_tb));
213 gtk_widget_hide(mainview->tools_color);
214 gtk_widget_hide(mainview->tools_brushsize);
215 gtk_widget_hide(mainview->tools_pagestyle);
216 gtk_widget_hide(mainview->tools_shape);
217 gtk_widget_hide(mainview->tools_pressure);
220 if (typ == NODE_CHECKLIST)
222 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
223 gtk_widget_show(GTK_WIDGET(mainview->strikethru_tb));
224 gtk_widget_show(GTK_WIDGET(mainview->check_tb));
225 gtk_widget_show(GTK_WIDGET(mainview->checkadd_tb));
226 gtk_widget_show(GTK_WIDGET(mainview->checkedit_tb));
227 gtk_widget_show(GTK_WIDGET(mainview->checkdel_tb));
228 gtk_widget_hide(GTK_WIDGET(mainview->undo_tb));
229 gtk_widget_hide(GTK_WIDGET(mainview->redo_tb));
231 else
233 gtk_widget_hide(GTK_WIDGET(mainview->strikethru_tb));
234 gtk_widget_hide(GTK_WIDGET(mainview->check_tb));
235 gtk_widget_hide(GTK_WIDGET(mainview->checkadd_tb));
236 gtk_widget_hide(GTK_WIDGET(mainview->checkedit_tb));
237 gtk_widget_hide(GTK_WIDGET(mainview->checkdel_tb));
238 gtk_widget_show(GTK_WIDGET(mainview->undo_tb));
239 gtk_widget_show(GTK_WIDGET(mainview->redo_tb));
242 if (typ == NODE_TEXT)
244 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
245 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
246 gtk_widget_hide(mainview->listscroll);
247 gtk_widget_show(GTK_WIDGET(mainview->scrolledwindow));
248 gtk_widget_show(mainview->tools_item);
250 else if (typ == NODE_SKETCH)
252 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
253 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
254 gtk_widget_hide(mainview->listscroll);
255 gtk_widget_show(sketchwidget_get_mainwidget(mainview->sk));
256 gtk_widget_show(mainview->tools_item);
258 else if (typ == NODE_CHECKLIST)
260 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
261 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
262 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
263 gtk_widget_hide(mainview->tools_item);
264 gtk_widget_show(mainview->listscroll);
266 else
268 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
269 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
270 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
271 gtk_widget_hide(mainview->tools_item);
272 gtk_widget_hide(mainview->listscroll);
276 nodeData *getSelectedNode(MainView * mainview)
278 GtkTreeIter iter;
279 GtkTreeModel *model;
281 nodeData *nd;
283 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
285 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
286 return (NULL);
288 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
290 return (nd);
293 void saveCurrentData(MainView * mainview)
295 nodeData *selnode = getSelectedNode(mainview);
296 saveDataToNode(mainview, selnode);
299 void saveDataToNode(MainView * mainview, nodeData *selnode)
301 if (selnode == NULL)
302 return;
304 if (
305 (selnode->typ == NODE_SKETCH && sketchwidget_get_edited(mainview->sk) == FALSE) ||
306 (selnode->typ == NODE_TEXT && wp_text_buffer_is_modified(mainview->buffer)==FALSE) ||
307 (selnode->typ == NODE_CHECKLIST && mainview->checklist_edited==FALSE)
310 maepad_message("node not edited, not saving");
311 return;
314 mainview->file_edited = TRUE;
316 busy_enter(mainview);
317 maepad_debug("saveDataToNode working");
319 gboolean goterr = TRUE;
320 gchar *textdata = NULL;
321 GdkPixbuf *pixbuf = NULL;
322 gchar *sketchdata = NULL;
323 gsize datalen = 0;
324 char tq[512];
326 if (selnode->typ == NODE_TEXT)
328 #if 0
329 GtkTextIter start, end;
330 gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(mainview->buffer), &start, &end);
331 textdata = gtk_text_buffer_serialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &start, &end, &datalen);
332 #endif
334 GString *gstr=g_string_sized_new(4096);
335 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
337 datalen=gstr->len;
338 textdata=g_string_free(gstr, FALSE);
340 /* 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);*/
341 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);
343 else if (selnode->typ == NODE_SKETCH)
345 GError *err = NULL;
346 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
347 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
349 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
350 if (pixbuf == NULL)
352 maepad_warning("error saving: pixbuf is null");
354 else
356 double w, h;
357 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, skdr->allocation.width, skdr->allocation.height, &w, &h, FALSE);
359 if (pixbuf2!=NULL)
361 if (gdk_pixbuf_save_to_buffer(pixbuf2, &sketchdata, &datalen, "png", &err, NULL) == FALSE)
363 sketchdata = NULL;
364 datalen = 0;
365 maepad_warning("Error saving sketch: %s", err->message);
366 g_error_free(err);
368 gdk_pixbuf_unref(pixbuf2);
371 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);
372 maepad_debug("storing sketch in db: %d bytes", datalen);
373 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
375 else if (selnode->typ == NODE_CHECKLIST)
377 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);
382 sqlite3_stmt *stmt = NULL;
383 const char *dum;
384 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
386 if (rc)
388 maepad_warning("Error updating: %s", sqlite3_errmsg(mainview->db));
389 break;
391 if (selnode->typ == NODE_TEXT)
392 sqlite3_bind_text(stmt, 1, textdata, datalen, /*strlen(textdata),*/ SQLITE_TRANSIENT);
393 else if (selnode->typ == NODE_SKETCH)
394 sqlite3_bind_blob(stmt, 1, sketchdata, datalen, SQLITE_TRANSIENT);
396 rc = SQLITE_BUSY;
397 while(rc == SQLITE_BUSY)
399 rc = sqlite3_step(stmt);
400 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
401 break;
403 sqlite3_finalize(stmt);
405 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
407 maepad_warning("Error saving node: %s", sqlite3_errmsg(mainview->db));
409 else
411 if (selnode->typ == NODE_TEXT)
412 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE);
413 else if (selnode->typ == NODE_SKETCH)
414 sketchwidget_set_edited(mainview->sk, FALSE);
415 else if (selnode->typ == NODE_CHECKLIST)
416 mainview->checklist_edited = FALSE;
417 goterr = FALSE;
419 }while(FALSE);
421 while(goterr==FALSE && selnode->typ == NODE_CHECKLIST)
423 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
425 char tq[512];
426 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d", checklisttable_tmpname, selnode->sql3id);
427 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
429 GtkTreeIter iter;
430 if (gtk_tree_model_get_iter_first(model, &iter)==FALSE) break;
434 gint styletoset_weight;
435 gboolean styletoset_strike;
436 gboolean ischecked;
437 gchar *text;
438 gchar *color;
439 unsigned long col=0;
441 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);
443 GdkColor tmpcol;
444 if (color!=NULL && strcmp(color, "(null)")!=0 && gdk_color_parse(color, &tmpcol))
446 col=((tmpcol.red>>8)<<16)|((tmpcol.green>>8)<<8)|(tmpcol.blue>>8);
449 gint style=0;
450 if (ischecked) style|=CHECKSTYLE_CHECKED;
451 if (styletoset_weight==PANGO_WEIGHT_BOLD) style|=CHECKSTYLE_BOLD;
452 if (styletoset_strike) style|=CHECKSTYLE_STRIKE;
454 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (nodeid, name, style, color, ord) VALUES(%d, ?, %d, %lu, 0)", checklisttable_tmpname, selnode->sql3id, style, col);
455 sqlite3_stmt *stmt = NULL;
456 const char *dum;
457 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
459 if (rc)
461 goterr=TRUE;
462 maepad_warning("Error while saving checklist: %s", sqlite3_errmsg(mainview->db));
463 break;
465 sqlite3_bind_text(stmt, 1, text, strlen(text), SQLITE_TRANSIENT);
467 rc = SQLITE_BUSY;
468 while(rc == SQLITE_BUSY)
470 rc = sqlite3_step(stmt);
471 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
472 break;
474 sqlite3_finalize(stmt);
476 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
478 goterr=TRUE;
479 maepad_warning("Error while saving checklist (2): %s", sqlite3_errmsg(mainview->db));
482 g_free(color);
483 g_free(text);
485 }while(gtk_tree_model_iter_next(model, &iter)==TRUE);
487 break;
490 if (textdata)
491 g_free(textdata);
492 if (sketchdata)
493 g_free(sketchdata);
494 if (goterr == TRUE)
496 show_banner(mainview, _("Error saving memo"));
498 busy_leave(mainview);
501 gboolean callback_treeview_button_press(GtkTreeView* treeview, GdkEventButton* event, gpointer user_data)
503 MainView* mainview = (MainView*)user_data;
504 GtkTreePath* path;
506 if (mainview->node_list_longpress_path != NULL) {
507 /* Forget old, remembered tree path for longpress */
508 gtk_tree_path_free(mainview->node_list_longpress_path);
509 mainview->node_list_longpress_path = NULL;
512 if (gtk_tree_view_get_path_at_pos(treeview,
513 event->x, event->y, &path, NULL, NULL, NULL)) {
515 * Save this path in case we open the longpress menu to
516 * set the cursor in the treeview to the correct row.
518 * See on_node_menu_show() on how this is further used.
520 mainview->node_list_longpress_path = path;
523 mainview->can_show_node_view = TRUE;
525 return FALSE;
528 void callback_treeview_celldatafunc(GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data)
530 MainView *mainview = ( MainView * ) data;
531 g_assert(mainview != NULL && mainview->data != NULL );
533 nodeData *nd;
535 gtk_tree_model_get(tree_model, iter, NODE_DATA, &nd, -1);
536 if (nd == NULL)
537 return;
539 if (nd->namepix == NULL)
541 g_object_set(cell, "visible", FALSE, NULL);
543 else
545 g_object_set(cell, "visible", TRUE, NULL);
546 g_object_set(cell, "width", SKETCHNODE_RX, NULL);
547 g_object_set(cell, "height", SKETCHNODE_RY, NULL);
551 void callback_treeview_change(GtkTreeSelection * selection, gpointer data)
553 MainView *mainview = (MainView *) data;
554 g_assert(mainview != NULL && mainview->data != NULL);
556 nodeData *nd = getSelectedNode(mainview);
558 gchar* nodeName = _("View memo");
560 if (nd != NULL && nd->name != NULL) {
561 nodeName = nd->name;
564 /* Show node view with selected node */
565 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view),
566 nodeName);
568 if (mainview->can_show_node_view) {
569 gtk_widget_show(GTK_WIDGET(mainview->data->node_view));
572 /* Make sure we don't accidentally collapse any nodes */
573 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
575 guint tm=time(NULL);
576 if (mainview->cansel_time>0 && mainview->cansel_time+1.0<tm) mainview->cansel_node=NULL;
578 if (nd==NULL)
580 if (mainview->cansel_node!=NULL)
582 maepad_debug("[SELLOGIC] saving %d to unselect all nodes", (mainview->cansel_node)->sql3id);
583 saveDataToNode(mainview, (mainview->cansel_node));
584 mainview->cansel_node=NULL;
586 return;
589 if (mainview->cansel_node!=NULL)
591 if (nd->sql3id == (mainview->cansel_node)->sql3id)
593 mainview->cansel_node=NULL;
594 maepad_debug("[SELLOGIC] doubly selected %d, doing nothing", nd->sql3id);
595 prepareUIforNodeChange(mainview, nd->typ);
596 return;
598 else
600 maepad_debug("[SELLOGIC] saving %d to load new node", (mainview->cansel_node)->sql3id);
601 saveDataToNode(mainview, (mainview->cansel_node));
602 mainview->cansel_node=NULL;
606 if (nd == NULL) return;
608 busy_enter(mainview);
610 gboolean goterr = TRUE;
611 char *textdata = NULL;
612 char *blob = NULL;
613 int blobsize = 0, textsize = 0;
615 char tq[512];
617 g_snprintf(tq, sizeof(tq), "SELECT bodytype, body, bodyblob, flags FROM %s WHERE nodeid=%d", datatable_tmpname, nd->sql3id);
618 sqlite3_stmt *stmt = NULL;
619 const char *dum;
620 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
622 if (rc)
624 maepad_warning("Error reading (1): %s", sqlite3_errmsg(mainview->db));
626 else
628 rc = SQLITE_BUSY;
629 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
631 rc = sqlite3_step(stmt);
632 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
633 break;
634 else if (rc == SQLITE_ROW)
636 nd->typ = sqlite3_column_int(stmt, 0);
637 nd->flags = sqlite3_column_int(stmt, 3);
639 prepareUIforNodeChange(mainview, nd->typ);
640 if (nd->typ == NODE_TEXT)
642 gboolean file_edited_backup = mainview->file_edited;
644 blobsize = sqlite3_column_bytes(stmt, 2);
645 blob = (char *)sqlite3_column_blob(stmt, 2);
647 textdata = (char *)sqlite3_column_text(stmt, 1);
648 textsize = sqlite3_column_bytes(stmt, 1);
650 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);*/
651 wp_text_buffer_reset_buffer(mainview->buffer, TRUE);
653 gboolean richtext=FALSE;
655 if (blob != NULL)
657 #if 0
658 gboolean oldway=FALSE;
659 if (blobsize>8)
661 char tst[8];
662 strncpy(tst, blob, 8);
663 tst[8]=0;
664 if (strcmp(tst, "RICHTEXT")==0) oldway=TRUE;
666 if (oldway)
668 GError *err = NULL;
669 GtkTextIter iter;
670 gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(mainview->buffer), &iter);
671 gtk_text_buffer_deserialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &iter, blob, blobsize, TRUE, &err);
672 if (err != NULL)
674 g_error_free(err);
676 else
678 richtext=TRUE;
681 #endif
683 if (richtext==FALSE)
685 wp_text_buffer_load_document_begin(mainview->buffer, TRUE);
686 wp_text_buffer_load_document_write(mainview->buffer, blob, blobsize);
687 wp_text_buffer_load_document_end(mainview->buffer);
688 richtext=TRUE;
691 if (richtext==FALSE && !(textdata == NULL || g_utf8_validate(textdata, textsize, NULL) == FALSE))
693 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), textdata, textsize);*/
694 wp_text_buffer_load_document_begin(mainview->buffer, FALSE);
695 wp_text_buffer_load_document_write(mainview->buffer, textdata, textsize);
696 wp_text_buffer_load_document_end(mainview->buffer);
699 wp_text_buffer_enable_rich_text(mainview->buffer, TRUE);
700 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap),
701 (nd->flags & NODEFLAG_WORDWRAP)?(TRUE):(FALSE));
703 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE); /*we probably don't need this*/
705 callback_undotoggle((gpointer)mainview->buffer, FALSE, mainview); /*we need these*/
706 callback_redotoggle((gpointer)mainview->buffer, FALSE, mainview);
708 if (file_edited_backup==FALSE) mainview->file_edited=FALSE; /*textview changed event toggles this?*/
709 goterr = FALSE;
711 else if (nd->typ == NODE_SKETCH)
713 sketchwidget_wipe_undo(mainview->sk);
715 /* Disable squared and filled mode when opening a sketch */
716 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_square), FALSE);
717 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_filled), FALSE);
719 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[1]), TRUE);
720 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[0]), TRUE);
722 blobsize = sqlite3_column_bytes(stmt, 2);
723 blob = (char *)sqlite3_column_blob(stmt, 2);
724 gboolean clear = TRUE;
726 if (blob == NULL)
727 goterr = FALSE;
728 if (blob != NULL)
730 maepad_debug("blob size: %d", blobsize);
731 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
732 GError *err = NULL;
734 gdk_pixbuf_loader_write(pl, (guchar *) blob, blobsize, &err);
735 if (err != NULL)
737 maepad_warning("Error loading sketch: %s", err->message);
738 g_error_free(err);
739 err = NULL;
741 gdk_pixbuf_loader_close(pl, NULL);
742 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
744 if (GDK_IS_PIXBUF(pixbuf))
746 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
747 GtkPixmap *skpix = (GtkPixmap *) sketchwidget_get_Pixmap(mainview->sk);
749 int w=gdk_pixbuf_get_width(pixbuf);
750 int h=gdk_pixbuf_get_height(pixbuf);
751 if (w!=skdr->allocation.width || h!=skdr->allocation.height)
753 if (w>skdr->allocation.width) w=skdr->allocation.width;
754 if (h>skdr->allocation.height) h=skdr->allocation.height;
755 sketchwidget_clear_real(mainview->sk);
757 gdk_draw_pixbuf(GDK_DRAWABLE(skpix), NULL, pixbuf, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0);
759 clear = FALSE;
760 goterr = FALSE;
762 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
764 else
766 maepad_warning("Error loading pixbuf");
768 g_object_unref(pl);
770 if (clear == TRUE)
772 maepad_message("Clearing sketch widget");
773 sketchwidget_clear_real(mainview->sk);
775 gtk_widget_queue_draw(sketchwidget_get_drawingarea(mainview->sk));
777 else if (nd->typ == NODE_CHECKLIST)
779 mainview->checklist_edited = FALSE;
780 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
781 g_object_ref(model);
782 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), NULL);
783 gtk_list_store_clear(GTK_LIST_STORE(model));
785 g_snprintf(tq, sizeof(tq), "SELECT name, style, color FROM %s WHERE nodeid=%d ORDER BY ord, idx", checklisttable_tmpname, nd->sql3id);
786 sqlite3_stmt *stmt2 = NULL;
787 const char *dum;
788 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt2, &dum);
789 if (rc)
791 maepad_warning("Error reading checklist (1) %s", sqlite3_errmsg(mainview->db));
793 else
795 goterr=FALSE;
796 rc = SQLITE_BUSY;
797 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
799 rc = sqlite3_step(stmt2);
800 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
801 break;
802 else if (rc == SQLITE_ROW)
804 char *textdata = (char *)sqlite3_column_text(stmt2, 0);
805 int style = sqlite3_column_int(stmt2, 1);
806 unsigned long col = sqlite3_column_int(stmt2, 2);
808 GtkTreeIter toplevel;
809 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
810 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_TEXT, textdata, CHECKNODE_CHECKED, FALSE, -1);
811 if ((style & CHECKSTYLE_CHECKED)>0) {
812 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, TRUE, -1);
813 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
815 if ((style & CHECKSTYLE_BOLD)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_BOLD, PANGO_WEIGHT_BOLD, -1);
816 if ((style & CHECKSTYLE_STRIKE)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_STRIKE, TRUE, -1);
818 if (col>0)
820 char tmp[10];
821 g_snprintf(tmp, sizeof(tmp), "#%02lx%02lx%02lx", ((col & 0xFF0000) >> 16), ((col & 0xFF00) >> 8), (col & 0xFF));
822 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_COLOR, tmp, -1);
827 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
829 maepad_warning("Error reading checklist (2): %s", sqlite3_errmsg(mainview->db));
830 goterr=TRUE;
833 sqlite3_finalize(stmt2);
836 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), model);
837 g_object_unref(model);
840 if ((nd->flags & NODEFLAG_SKETCHLINES) > 0)
841 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[1]), TRUE);
842 else if ((nd->flags & NODEFLAG_SKETCHGRAPH) > 0)
843 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[2]), TRUE);
844 else
846 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[0]), TRUE);
847 callback_sketchlines(NULL, mainview->sketchlinesmenuitems[0]); /*FIXME:ugly */
849 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure), TRUE);
851 break;
854 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
855 maepad_warning("Error reading (2): %s", sqlite3_errmsg(mainview->db));
858 sqlite3_finalize(stmt);
861 busy_leave(mainview);
863 /* Show / hide the sketch-related menu widgets */
864 if (nd->typ == NODE_SKETCH) {
865 gtk_widget_show(mainview->menu_button_square);
866 gtk_widget_show(mainview->menu_button_filled);
867 } else {
868 gtk_widget_hide(mainview->menu_button_square);
869 gtk_widget_hide(mainview->menu_button_filled);
872 /* Show/hide the rich text-related menu widgets */
873 if (nd->typ == NODE_TEXT) {
874 gtk_widget_show(mainview->menu_button_wordwrap);
875 } else {
876 gtk_widget_hide(mainview->menu_button_wordwrap);
879 /* Show/hide the checklist-related menu widgets */
880 if (nd->typ == NODE_CHECKLIST) {
881 gtk_widget_show(mainview->menu_button_remove_checked);
882 } else {
883 gtk_widget_hide(mainview->menu_button_remove_checked);
886 if (goterr == TRUE)
888 show_banner(mainview, _("Error loading memo"));
892 gboolean treeview_canselect(GtkTreeSelection * selection, GtkTreeModel * model, GtkTreePath * path, gboolean path_currently_selected, gpointer userdata)
894 MainView *mainview = (MainView *) userdata;
895 g_assert(mainview != NULL && mainview->data != NULL);
897 if (path_currently_selected)
899 GtkTreeIter iter;
900 gtk_tree_model_get_iter(model, &iter, path);
902 gtk_tree_model_get(model, &iter, NODE_DATA, &(mainview->cansel_node), -1);
903 mainview->cansel_time=time(NULL);
906 return (TRUE);
909 gboolean newnodedlg_key_press_cb(GtkWidget * widget, GdkEventKey * event, GtkWidget * dlg)
911 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dlg), "sk");
913 switch (event->keyval)
915 case GDK_F7:
916 sketchwidget_redo(s);
917 return TRUE;
918 case GDK_F8:
919 sketchwidget_undo(s);
920 return TRUE;
922 return FALSE;
926 /* This struct will hold all our toggle buttons, so we can
927 * only allow one to be active at a time (i.e. radio buttons) */
928 typedef struct _newNodeToggleButtons newNodeToggleButtons;
929 struct _newNodeToggleButtons
931 GtkWidget *rbt; /* Text */
932 GtkWidget *rbs; /* Sketch */
933 GtkWidget *rbc; /* Checklist */
936 void show_sketch_widget(GtkWidget *widget, gpointer user_data)
938 GtkWidget *dialog = (GtkWidget*)user_data;
940 /* Show the sketch widget and hide the entry + draw button */
941 gtk_widget_show(gtk_object_get_data(GTK_OBJECT(dialog), "al"));
942 gtk_widget_hide(gtk_object_get_data(GTK_OBJECT(dialog), "draw_button"));
943 gtk_widget_hide(gtk_object_get_user_data(GTK_OBJECT(dialog)));
946 void new_node_dialog(nodeType typ, MainView * mainview)
948 GtkWidget *dialog, *entry, *but_ok, *vbox, *hbox, *al, *cb;
949 GtkWidget *rb1, *rb2, *rb3;
950 GtkWidget *hb;
951 gchar datetime_str[200];
952 time_t t_now;
953 struct tm *tm_now;
954 gboolean datetime_written = FALSE;
956 t_now = time(NULL);
957 tm_now = localtime(&t_now);
959 if (tm_now != NULL) {
960 if (strftime(datetime_str, sizeof(datetime_str), "%y-%m-%d %H:%M", tm_now) != 0) {
961 datetime_written = TRUE;
965 if (datetime_written == FALSE) {
966 /* Was not able to determine a datetime string - use default */
967 maepad_warning("Cannot determine current time");
968 strncpy(datetime_str, _("New memo"), sizeof(datetime_str));
969 datetime_str[sizeof(datetime_str)-1] = '\0';
972 newNodeToggleButtons *nntb = g_malloc(sizeof(newNodeToggleButtons));
974 dialog = gtk_dialog_new();
975 gtk_window_set_title(GTK_WINDOW(dialog), _("Add new memo"));
976 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
977 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
979 g_signal_connect(G_OBJECT(dialog), "key_press_event", G_CALLBACK(newnodedlg_key_press_cb), dialog);
981 vbox = gtk_vbox_new(FALSE, 0);
983 hbox = gtk_hbox_new(TRUE, 0);
985 /* Text note toggle button */
986 rb1 = hildon_gtk_radio_button_new(HILDON_SIZE_FINGER_HEIGHT, NULL);
987 gtk_button_set_label(GTK_BUTTON(rb1), _("Rich text"));
988 gtk_button_set_image(GTK_BUTTON(rb1), gtk_image_new_from_file(PIXMAPDIR "/text.png"));
989 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb1), TRUE, TRUE, 0);
990 nntb->rbt = rb1;
992 /* Sketch toggle button */
993 rb2 = hildon_gtk_radio_button_new_from_widget(HILDON_SIZE_FINGER_HEIGHT, GTK_RADIO_BUTTON(rb1));
994 gtk_button_set_label(GTK_BUTTON(rb2), _("Sketch"));
995 gtk_button_set_image(GTK_BUTTON(rb2), gtk_image_new_from_file(PIXMAPDIR "/sketch.png"));
996 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb2), TRUE, TRUE, 0);
997 nntb->rbs = rb2;
999 /* Checklist toggle button */
1000 rb3 = hildon_gtk_radio_button_new_from_widget(HILDON_SIZE_FINGER_HEIGHT, GTK_RADIO_BUTTON(rb1));
1001 gtk_button_set_label(GTK_BUTTON(rb3), _("Checklist"));
1002 gtk_button_set_image(GTK_BUTTON(rb3), gtk_image_new_from_file(PIXMAPDIR "/checklist.png"));
1003 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(rb3), TRUE, TRUE, 0);
1004 nntb->rbc = rb3;
1006 /* Set mode to 0 to get correct styling */
1007 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb1), FALSE);
1008 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb2), FALSE);
1009 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(rb3), FALSE);
1011 /* Remember "new note toggle buttons" list */
1012 gtk_object_set_data(GTK_OBJECT(dialog), "nntb", nntb);
1014 if (typ == NODE_TEXT) {
1015 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb1), TRUE);
1016 } else if (typ == NODE_SKETCH) {
1017 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb2), TRUE);
1018 } else {
1019 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb3), TRUE);
1022 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1024 but_ok = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Add"), GTK_RESPONSE_OK);
1025 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
1026 g_signal_connect(G_OBJECT(but_ok), "clicked", G_CALLBACK(callback_new_node_real), dialog);
1028 gtk_object_set_data(GTK_OBJECT(dialog), "m", mainview);
1030 hb = gtk_hbox_new(FALSE, 10);
1031 gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("Name:")), FALSE, FALSE, 0);
1032 entry = hildon_entry_new(HILDON_SIZE_AUTO);
1033 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
1034 gtk_object_set_user_data(GTK_OBJECT(dialog), entry);
1035 gtk_entry_set_text(GTK_ENTRY(entry), datetime_str);
1036 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1037 gtk_box_pack_start(GTK_BOX(hb), entry, TRUE, TRUE, 0);
1039 /* Sketch widget, hidden by default */
1040 al = gtk_alignment_new(0.5, 0.5, 0, 0);
1041 SketchWidget *s = sketchwidget_new(SKETCHNODE_X, SKETCHNODE_Y, TRUE);
1042 gtk_object_set_data(GTK_OBJECT(dialog), "sk", s);
1043 gtk_object_set_data(GTK_OBJECT(dialog), "al", al);
1044 sketchwidget_set_brushsize(s, 2);
1045 sketchwidget_set_backstyle(s, SKETCHBACK_GRAPH);
1046 gtk_widget_set_size_request(sketchwidget_get_mainwidget(s), SKETCHNODE_X, SKETCHNODE_Y);
1047 gtk_container_add(GTK_CONTAINER(al), sketchwidget_get_mainwidget(s));
1048 gtk_box_pack_start(GTK_BOX(hb), al, FALSE, FALSE, 0);
1050 /*but_sketch = hildon_button_new_with_text(
1051 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
1052 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
1053 _("Use sketch label"), NULL);
1055 gtk_object_set_data(GTK_OBJECT(dialog), "draw_button", but_sketch);
1056 gtk_signal_connect(GTK_OBJECT(but_sketch), "clicked", G_CALLBACK(show_sketch_widget), dialog);
1057 gtk_box_pack_start(GTK_BOX(hb), but_sketch, FALSE, TRUE, 0);*/
1058 gtk_box_pack_start(GTK_BOX(vbox), hb, TRUE, FALSE, 0);
1060 cb = hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1061 gtk_button_set_label(GTK_BUTTON(cb), _("Add as child of selected memo"));
1062 hildon_check_button_set_active(HILDON_CHECK_BUTTON(cb), mainview->newnodedialog_createchild);
1063 gtk_box_pack_start(GTK_BOX(vbox), cb, FALSE, FALSE, 0);
1065 gtk_object_set_data(GTK_OBJECT(dialog), "cb", cb);
1067 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
1069 gtk_widget_grab_focus(entry);
1071 gtk_widget_show_all(dialog);
1073 /* Hide the sketch widget at first */
1074 gtk_widget_hide(al);
1075 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1078 void add_new_node(nodeData * node, MainView * mainview, gboolean ischild)
1080 GtkTreeIter parentiter, newiter;
1081 GtkTreeModel *model;
1082 void *ptr = NULL;
1084 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1086 if (gtk_tree_selection_get_selected(selection, &model, &parentiter))
1087 ptr = &parentiter;
1089 GtkTreePath *path = NULL;
1091 unsigned int parentnodeid = 0;
1093 if (ptr != NULL)
1095 path = gtk_tree_model_get_path(model, &parentiter);
1097 if (ischild == FALSE)
1099 gtk_tree_path_up(path);
1101 if (gtk_tree_path_get_depth(path) == 0)
1103 /* Selected node is a root node */
1104 ptr = NULL; /* New node can not have a Parent node */
1105 gtk_tree_path_down(path); /*restore path so expand() works */
1107 else if (gtk_tree_path_get_depth(path) > 0)
1109 /* Selected node is a child node */
1110 if (gtk_tree_model_get_iter(model, &parentiter, path))
1111 ptr = &parentiter;
1116 if (ptr != NULL)
1118 nodeData *nd;
1120 gtk_tree_model_get(model, ptr, NODE_DATA, &nd, -1);
1121 if (nd)
1122 parentnodeid = nd->sql3id;
1125 node->sql3id = 0;
1128 sqlite3_stmt *stmt = NULL;
1129 const char *dum;
1130 char tq[512];
1133 * FIXME: ord
1135 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (parent, bodytype, name, nameblob, ord) VALUES (%d, %d, ?, ?, 0);", datatable_tmpname, parentnodeid, node->typ);
1136 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1138 if (rc)
1140 maepad_warning("Error inserting (1): %s", sqlite3_errmsg(mainview->db));
1141 break;
1143 if (node->name != NULL)
1144 sqlite3_bind_text(stmt, 1, node->name, strlen(node->name), SQLITE_TRANSIENT);
1145 else
1146 sqlite3_bind_text(stmt, 1, NULL, 0, SQLITE_TRANSIENT);
1148 if (node->namepix != NULL)
1150 gchar *namepixdata = NULL;
1151 gsize datalen = 0;
1153 GError *err = NULL;
1155 if (gdk_pixbuf_save_to_buffer(node->namepix, &namepixdata, &datalen, "png", &err, NULL) == FALSE)
1157 namepixdata = NULL;
1158 datalen = 0;
1159 maepad_warning("Error saving name: %s", err->message);
1160 g_error_free(err);
1162 sqlite3_bind_blob(stmt, 2, namepixdata, datalen, SQLITE_TRANSIENT);
1164 else
1165 sqlite3_bind_blob(stmt, 2, NULL, 0, SQLITE_TRANSIENT);
1167 rc = SQLITE_BUSY;
1168 while(rc == SQLITE_BUSY)
1170 rc = sqlite3_step(stmt);
1171 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1172 break;
1174 sqlite3_finalize(stmt);
1175 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
1177 maepad_warning("Error inserting (2): %s", sqlite3_errmsg(mainview->db));
1178 break;
1180 node->sql3id = sqlite3_last_insert_rowid(mainview->db);
1182 while(FALSE);
1184 if (node->sql3id == 0)
1186 if (node->name)
1187 g_free(node->name);
1188 if (node->namepix)
1189 g_object_unref(node->namepix);
1190 g_free(node);
1191 if (path)
1192 gtk_tree_path_free(path);
1193 show_banner(mainview, _("Error creating memo"));
1194 return;
1197 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, ptr);
1199 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter,
1200 NODE_NAME, format_overview_name(node, NULL),
1201 NODE_PIXBUF, node->namepix,
1202 NODE_DATA, node,
1203 -1);
1205 if (path)
1207 mainview->loading=TRUE; /*only when we have a valid parent*/
1208 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);
1209 gtk_tree_path_free(path);
1212 gtk_tree_selection_select_iter(selection, &newiter);
1214 mainview->loading=FALSE;
1217 void callback_new_node_real(GtkAction * action, gpointer data)
1219 MainView *mainview;
1221 GtkWidget *dialog = data;
1222 GtkWidget *entry = gtk_object_get_user_data(GTK_OBJECT(dialog));
1224 mainview = gtk_object_get_data(GTK_OBJECT(dialog), "m");
1225 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dialog), "sk");
1226 GtkWidget *cb = gtk_object_get_data(GTK_OBJECT(dialog), "cb");
1227 newNodeToggleButtons *nntb = gtk_object_get_data(GTK_OBJECT(dialog), "nntb");
1229 nodeType typ = NODE_TEXT;
1230 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbs))) {
1231 typ = NODE_SKETCH;
1232 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbc))) {
1233 typ = NODE_CHECKLIST;
1235 g_free(nntb);
1237 gchar *txt = NULL;
1239 /*if (GTK_WIDGET_VISIBLE(entry))
1241 txt = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1242 if (strcmp(txt, "") == 0)
1244 g_free(txt);
1245 return;
1248 else
1250 GtkWidget *sdr = sketchwidget_get_drawingarea(s);
1252 GdkPixmap *spix = sketchwidget_get_Pixmap(s);
1254 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(spix), NULL, 0, 0, 0, 0, sdr->allocation.width, sdr->allocation.height);
1255 g_object_unref(spix);
1256 double w, h;
1257 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, SKETCHNODE_X, SKETCHNODE_Y, &w,
1258 &h, TRUE);
1259 if (pixbuf2==NULL) return;
1261 GdkPixbuf *pixbuf3 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, SKETCHNODE_RX,
1262 SKETCHNODE_RY);
1264 gdk_pixbuf_fill(pixbuf3, 0xffffffff);
1266 if (w <= SKETCHNODE_RX && h <= SKETCHNODE_RY)
1268 gdk_pixbuf_copy_area(pixbuf2, 0, 0, w, h, pixbuf3, 0, (SKETCHNODE_RY - h) / 2);
1270 else
1272 double neww, newh;
1274 if (w > h)
1276 neww = SKETCHNODE_RX;
1277 newh = (h / w) * SKETCHNODE_RX;
1279 else
1281 newh = SKETCHNODE_RY;
1282 neww = (w / h) * SKETCHNODE_RY;
1284 if (newh > SKETCHNODE_RY)
1285 newh = SKETCHNODE_RY;
1287 GdkPixbuf *tmpbuf = gdk_pixbuf_scale_simple(pixbuf2, neww, newh,
1288 GDK_INTERP_BILINEAR);
1290 gdk_pixbuf_copy_area(tmpbuf, 0, 0, neww, newh, pixbuf3, 0, (SKETCHNODE_RY - newh) / 2);
1292 gdk_pixbuf_unref(tmpbuf);
1295 pixbuf = pixbuf3;
1296 gdk_pixbuf_unref(pixbuf2);
1299 nodeData *node;
1301 node = g_malloc(sizeof(nodeData));
1302 node->typ = typ;
1303 node->name = txt;
1304 node->namepix = NULL;
1306 /*if (GTK_WIDGET_VISIBLE(entry))
1308 node->name = txt;
1310 else
1312 node->namepix = pixbuf;
1315 node->lastMod = 0;
1316 node->flags = 0;
1317 node->sql3id = 0;
1319 mainview->newnodedialog_createchild = hildon_check_button_get_active(HILDON_CHECK_BUTTON(cb));
1320 add_new_node(node, mainview, mainview->newnodedialog_createchild);
1322 sketchwidget_destroy(s);
1323 gtk_widget_destroy(dialog);
1324 mainview->file_edited = TRUE;
1328 * delete node
1330 void callback_file_delete_node(GtkAction * action, gpointer data)
1332 MainView *mainview = (MainView *) data;
1333 g_assert(mainview != NULL && mainview->data != NULL);
1335 if (getSelectedNode(mainview) == NULL) {
1336 show_banner(mainview, _("Select a memo first"));
1337 return;
1340 if (show_confirmation(mainview, _("Delete selected memo?"))) {
1341 mainview->can_show_node_view = FALSE;
1342 callback_delete_node_real(mainview);
1343 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
1348 * Callback for Rename Menuitem
1350 void callback_file_rename_node(GtkAction * action, gpointer data)
1352 MainView *mainview = (MainView*)data;
1353 g_assert(mainview != NULL && mainview->data != NULL);
1355 /* Get the selected node */
1356 nodeData *sel_node = getSelectedNode(mainview);
1357 if (sel_node == NULL) {
1358 /* Do nothing, if no node has been selected */
1359 show_banner(mainview, _("Select a memo first"));
1360 return;
1363 if (sel_node->namepix != NULL) {
1364 /* the memo has a graphical label, cannot edit! */
1365 show_banner(mainview, _("Cannot rename memos with sketch name"));
1366 return;
1369 gchar* new_name = show_line_edit_dialog(mainview, _("Rename memo"), _("New name:"), _("Rename"), sel_node->name);
1371 /* Only rename node when user accepted the new name */
1372 if (new_name != NULL) {
1373 callback_rename_node_real(mainview, new_name);
1374 g_free(new_name);
1378 void callback_rename_node_real(MainView* mainview, gchar* new_name)
1380 GtkTreeIter iter;
1381 GtkTreeModel *model;
1382 nodeData *nd = NULL;
1384 /* Get the selected node */
1385 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1387 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1388 return;
1391 gtk_tree_model_get (model, &iter, NODE_DATA, &nd, -1);
1393 if (nd == NULL) {
1394 return;
1397 /* Update the database */
1398 sqlite3_stmt *stmt = NULL;
1400 char* sql = sqlite3_mprintf("UPDATE %s SET name='%q' WHERE nodeid=%d", datatable_tmpname, new_name, nd->sql3id);
1402 int rc = sqlite3_prepare(mainview->db, sql, strlen(sql), &stmt, NULL);
1403 if (rc == SQLITE_OK) {
1404 rc = SQLITE_BUSY;
1405 while (rc == SQLITE_BUSY) {
1406 rc = sqlite3_step(stmt);
1407 if (rc == SQLITE_DONE) {
1408 /* Update in the database was successful - now update the rest */
1410 /* Update the noteData */
1411 g_free(nd->name);
1412 nd->name = g_strdup(new_name);
1414 /* Update the window title of node_view */
1415 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view), nd->name);
1417 /* Update the value in the tree store */
1418 gtk_tree_store_set (GTK_TREE_STORE(model), &iter, NODE_NAME, format_overview_name(nd, new_name), -1);
1420 break;
1421 } else if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
1422 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1423 break;
1426 sqlite3_finalize(stmt);
1427 } else {
1428 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1431 sqlite3_free(sql);
1433 mainview->file_edited = TRUE;
1436 void callback_file_export_node(GtkAction * action, gpointer data)
1438 MainView *mainview = (MainView *) data;
1439 g_assert(mainview != NULL && mainview->data != NULL);
1441 nodeData *nd=getSelectedNode(mainview);
1442 if (nd == NULL)
1444 show_banner(mainview, _("Select a memo first"));
1445 return;
1448 gchar *nodename=nd->name;
1449 if (nodename==NULL) nodename=_("saved memo");
1451 if (nd->typ == NODE_TEXT)
1454 GtkTextIter begin, end;
1455 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER(mainview->buffer), &begin, &end);
1456 gchar *text = gtk_text_buffer_get_slice(GTK_TEXT_BUFFER(mainview->buffer), &begin, &end, TRUE);
1458 GString *gstr=g_string_sized_new(4096);
1459 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
1460 gint textlen=gstr->len;
1461 gchar *text=g_string_free(gstr, FALSE);
1463 if (text==NULL || !strcmp(text, ""))
1465 show_banner(mainview, _("Memo is empty"));
1467 else
1469 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "html");
1470 if (fn!=NULL)
1472 GnomeVFSResult vfs_result;
1473 GnomeVFSHandle *handle = NULL;
1474 GnomeVFSFileSize out_bytes;
1475 vfs_result = gnome_vfs_create(&handle, fn, GNOME_VFS_OPEN_WRITE, 0, 0600);
1476 if ( vfs_result != GNOME_VFS_OK ) {
1477 show_banner(mainview, _("Export failed"));
1479 else
1481 gnome_vfs_write(handle, text, textlen, &out_bytes);
1482 gnome_vfs_close(handle);
1483 if (out_bytes==strlen(text)) show_banner(mainview, _("Exported"));
1484 else show_banner(mainview, _("Export incomplete"));
1486 g_free(fn);
1489 g_free(text);
1491 else if (nd->typ == NODE_SKETCH)
1493 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
1494 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
1495 GdkPixbuf *pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
1496 if (pixbuf==NULL)
1498 show_banner(mainview, _("Memo is empty"));
1500 else
1502 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "png");
1503 if (fn!=NULL)
1505 if (gdk_pixbuf_save(pixbuf, fn, "png", NULL, NULL)==FALSE)
1507 show_banner(mainview, _("Export failed"));
1509 else
1511 show_banner(mainview, _("Exported"));
1513 g_free(fn);
1516 g_object_unref(skpix);
1518 else if (nd->typ == NODE_CHECKLIST)
1520 show_banner(mainview, _("Export of checklists not possible yet"));
1525 * callback from menu item
1526 * move selected node down (switch node with next sibling), don't change level of node
1528 void callback_move_down_node(GtkAction * action, gpointer data)
1530 GtkTreeIter iter;
1531 GtkTreeModel *model;
1533 MainView *mainview = (MainView *) data;
1534 g_assert(mainview != NULL && mainview->data != NULL);
1536 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1537 gtk_tree_selection_get_selected(selection, &model, &iter);
1539 GtkTreeIter old_iter = iter;/*save pointer to old iter, we will need it during swap nodes*/
1541 if (gtk_tree_model_iter_next(model,&iter)==FALSE)/*get next node*/
1542 return;
1544 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1545 gtk_tree_store_swap(treeStore,&iter,&old_iter);
1547 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1551 * callback from menu item
1552 * move selected node down (switch node with prev sibling), don't change level of node
1554 void callback_move_up_node(GtkAction * action, gpointer data)
1556 GtkTreeIter iter;
1557 GtkTreeModel *model;
1559 MainView *mainview = (MainView *) data;
1560 g_assert(mainview != NULL && mainview->data != NULL);
1562 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1563 gtk_tree_selection_get_selected(selection, &model, &iter);
1565 GtkTreeIter old_iter=iter;/*save pointer to old iter, we will need it during swap nodes*/
1567 if (tree_model_iter_prev(model,&iter)==FALSE)/*get previous node*/
1568 return;
1570 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1571 gtk_tree_store_swap(treeStore,&old_iter,&iter);/*do move*/
1573 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1577 * callback from menu item
1578 * we change level of actual node with direction to top
1580 void callback_move_to_top_level_node(GtkAction * action, gpointer data)
1582 GtkTreeIter iter,new_parent;
1583 GtkTreeIter *p_new_parent;
1584 GtkTreeIter parent;
1585 GtkTreeModel *model;
1587 MainView *mainview = (MainView *) data;
1588 g_assert(mainview != NULL && mainview->data != NULL);
1590 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1591 gtk_tree_selection_get_selected(selection, &model, &iter);
1593 /*at first we need actual parent of selected node*/
1594 if (gtk_tree_model_iter_parent(model,&parent,&iter)==FALSE)
1596 /*if parent of selected node is ROOT we can't go higher*/
1597 return;
1599 /*we need also new parent, it's parent of actual parent*/
1600 if (gtk_tree_model_iter_parent(model,&new_parent,&parent)==FALSE)
1602 /*if our new parent is ROOT we got filled new_parent with invalid value,
1603 so we need set NULL value to p_new_parent (root item)*/
1604 p_new_parent=NULL;
1606 else
1608 p_new_parent=&new_parent;/*we only redirect pointer to treeiter*/
1611 saveCurrentData(mainview);/*we save changes in node befor move*/
1613 /*this move function provide move item with all his children, be careful iter value will change!*/
1614 if (move_node(mainview,p_new_parent,&iter,&parent)==TRUE){
1616 gint id_parent = get_node_id_on_tmp_db(model,p_new_parent);
1617 gint id_node = get_node_id_on_tmp_db(model,&iter);
1618 /*we need also update parent id of moved item*/
1619 char tq[512];
1620 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1621 exec_command_on_db(mainview,tq);
1623 /*select new created iter*/
1624 gtk_tree_selection_select_iter(selection,&iter);
1626 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1631 * callback from menu item
1632 * we change level of actual node with direction to bottom
1633 * previous node will be parent of our actual node
1635 void callback_move_to_bottom_level_node(GtkAction * action, gpointer data)
1637 GtkTreeIter iter;
1638 GtkTreeModel *model;
1640 MainView *mainview = (MainView *) data;
1641 g_assert(mainview != NULL && mainview->data != NULL);
1643 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1644 gtk_tree_selection_get_selected(selection, &model, &iter);
1646 GtkTreeIter move_iter=iter;/*save pointer to old iter*/
1648 /*we try to get previous node*/
1649 if (tree_model_iter_prev(model,&iter)==FALSE)
1650 return;/*if previous node on the same level doesn't exist we will exit*/
1652 saveCurrentData(mainview);/*we save changes in node befor move*/
1654 /*this move function provide move item with all his children, be careful move_iter value will change!*/
1655 if (move_node(mainview,&iter,&move_iter,NULL)==TRUE)
1657 gint id_parent = get_node_id_on_tmp_db(model,&iter);
1658 gint id_node = get_node_id_on_tmp_db(model,&move_iter);
1660 /*we need also update parent id of moved item*/
1661 char tq[512];
1662 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1663 exec_command_on_db(mainview,tq);
1665 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1666 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);/*expand parent node*/
1667 gtk_tree_path_free(path);
1669 /*select new created iter*/
1670 gtk_tree_selection_select_iter(selection,&move_iter);
1672 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1677 * move item_to_move to new_parent with his children, this function is designed for change level of node
1678 * we copy item_to_move with his children to new position (after item_befor if is not NULL) and then we
1679 * destroy old node with his children, so ! item_to_move is set with new iter, be careful on this!
1681 gboolean move_node(MainView *mainview,GtkTreeIter *new_parent,GtkTreeIter *item_to_move,GtkTreeIter *item_befor)
1683 GtkTreeModel *model;
1685 model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
1686 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1688 nodeData *node;
1689 gtk_tree_model_get(model, item_to_move, NODE_DATA, &node, -1);/*get data from actual iter*/
1690 if (node)
1692 GtkTreeIter new_iter;/*create new iter*/
1693 gtk_tree_store_append(treeStore,&new_iter,new_parent);/*append new iter to new parent*/
1695 if (item_befor!=NULL)
1696 gtk_tree_store_move_after(treeStore,&new_iter,item_befor);/*sometimes we need set position*/
1698 gtk_tree_store_set(treeStore, &new_iter, NODE_NAME, format_overview_name(node, NULL), NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);/*set data from old iter*/
1700 GtkTreeIter child;
1701 while (gtk_tree_model_iter_children(model, &child, item_to_move)==TRUE)/*move all childrens while some exits*/
1703 if (move_node(mainview,&new_iter,&child,NULL)==FALSE)/*use recursion on children*/
1704 return FALSE;
1707 gtk_tree_store_set(treeStore, item_to_move, NODE_DATA, NULL, -1);
1708 gtk_tree_store_remove(treeStore, item_to_move);/*remove node, data need't remove, they are stored in new node*/
1710 /*we need return new value of moved item, so we need assign new_iter to item_to_move*/
1711 /*this code is ugly : new_iter to path and back to item_to_move*/
1712 GtkTreePath *path=gtk_tree_model_get_path(model,&new_iter);
1713 gtk_tree_model_get_iter(model,item_to_move,path);
1714 gtk_tree_path_free(path);
1716 else
1718 fprintf(stderr,"Get data node failed!\n");
1719 return FALSE;
1722 return TRUE;
1726 * simple execute of sql command which is stored in sql_string[]
1728 gboolean exec_command_on_db(MainView *mainview,char sql_string[])
1730 sqlite3_stmt *stmt = NULL;
1731 const char* dum;
1732 gboolean db_query_result = FALSE;
1734 int rc = sqlite3_prepare (mainview->db, sql_string, strlen(sql_string), &stmt, &dum);
1736 if (rc) {
1737 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1738 return FALSE;
1741 rc = SQLITE_BUSY;
1742 while (rc == SQLITE_BUSY) {
1743 rc = sqlite3_step (stmt);
1744 if (rc == SQLITE_DONE) {
1745 db_query_result = TRUE;
1746 break;
1748 else if(rc == SQLITE_ERROR || rc== SQLITE_MISUSE) {
1749 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1750 break;
1752 sqlite3_finalize(stmt);
1754 return TRUE;
1758 * 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)
1760 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview)
1762 nodeData *node;
1763 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1764 /*we need index of node on actual level*/
1765 gint index=get_branch_node_index(path);
1767 /*prepare to execute update command,and exec it*/
1768 char sql_command[512];
1769 g_snprintf (sql_command, sizeof(sql_command), "UPDATE %s SET ord=\"%d\" WHERE nodeid=%d",datatable_tmpname, index, node->sql3id);
1770 exec_command_on_db(mainview,sql_command);
1772 /*we don't want break gtk_tree_model_foreach function,until we call this func on each node - so we return always FALSE*/
1773 return FALSE;
1777 * return id number of iter (id number which is used to identify in sql database of nodes)
1779 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter)
1781 if (iter==NULL)
1782 return 0;/*we got ROOT parent here*/
1784 nodeData *node;
1785 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1786 return node->sql3id;
1790 * get index of node in current branch
1792 gint get_branch_node_index(GtkTreePath *path)
1794 int depth=gtk_tree_path_get_depth(path);
1795 gint *indicies = gtk_tree_path_get_indices(path);
1797 return indicies[depth-1];
1801 * similiar with gtk_tree_model_iter_next (), but opposite
1803 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter)
1805 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
1807 if (path==NULL){
1808 fprintf(stderr,"Error: path is null\n");
1809 return FALSE;
1812 if (gtk_tree_path_prev(path)==FALSE)
1813 return FALSE;
1815 gtk_tree_model_get_iter(tree_model, iter,path);
1817 return TRUE;
1820 gboolean ref2iter(GtkTreeModel * model, GtkTreeRowReference * ref, GtkTreeIter * iter)
1822 gboolean res = FALSE;
1823 GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
1825 if (gtk_tree_model_get_iter(model, iter, path))
1827 res = TRUE;
1829 gtk_tree_path_free(path);
1830 return (res);
1833 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter)
1835 GtkTreeRowReference *ref;
1837 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
1839 ref = gtk_tree_row_reference_new(model, path);
1840 gtk_tree_path_free(path);
1841 return (ref);
1844 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop)
1846 GtkTreeIter topiter;
1848 if (ref2iter(model, topnode, &topiter) == FALSE)
1849 return;
1851 GtkTreeIter child;
1853 if (gtk_tree_model_iter_children(model, &child, &topiter))
1855 GtkTreeRowReference *ref;
1856 GList *rr_list = NULL, *node;
1860 ref = iter2ref(model, &child);
1861 rr_list = g_list_append(rr_list, ref);
1863 while(gtk_tree_model_iter_next(model, &child));
1866 * got a reflist for all children
1869 for(node = rr_list; node; node = node->next)
1871 ref = (GtkTreeRowReference *) (node->data);
1872 if (ref2iter(model, ref, &child))
1874 GtkTreeIter newtopiter, newiter;
1875 GtkTreeIter *newtopiterptr;
1877 if (ref2iter(model, newtop, &newtopiter))
1878 newtopiterptr = &newtopiter;
1879 else
1880 newtopiterptr = NULL;
1882 nodeData *node;
1884 gtk_tree_model_get(model, &child, NODE_DATA, &node, -1);
1886 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, newtopiterptr);
1887 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, format_overview_name(node, NULL), NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1889 GtkTreeRowReference *newref = iter2ref(model, &newiter);
1891 move_nodes_up(model, ref, newref);
1892 gtk_tree_row_reference_free(newref);
1894 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
1896 gtk_tree_row_reference_free(ref);
1899 g_list_free(rr_list);
1904 void callback_delete_node_real(MainView* mainview)
1906 GtkTreeIter iter;
1907 GtkTreeModel *model;
1909 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1911 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1912 return;
1914 nodeData *nd;
1916 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
1917 if (!nd)
1918 return;
1920 mainview->file_edited = TRUE;
1922 unsigned int sql3id = nd->sql3id;
1924 if (nd->name)
1925 g_free(nd->name);
1928 * g_free(nd->data);
1929 * if (nd->pix) g_object_unref(nd->pix);
1931 g_free(nd);
1933 GtkTreeRowReference *upref = NULL, *ref = NULL;
1935 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1937 ref = gtk_tree_row_reference_new(model, path);
1938 if (gtk_tree_path_up(path))
1939 upref = gtk_tree_row_reference_new(model, path);
1940 gtk_tree_path_free(path);
1942 g_object_ref(model);
1943 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
1945 move_nodes_up(model, ref, upref);
1947 if (ref2iter(model, ref, &iter))
1949 char tq[512];
1951 g_snprintf(tq, sizeof(tq), "SELECT parent FROM %s WHERE nodeid=%d", datatable_tmpname, sql3id);
1952 sqlite3_stmt *stmt = NULL;
1953 const char *dum;
1954 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1955 unsigned int sql3parentid = 0;
1957 if (rc)
1959 maepad_warning("Error finding children for delete: %s", sqlite3_errmsg(mainview->db));
1961 else
1963 rc = SQLITE_BUSY;
1964 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
1966 rc = sqlite3_step(stmt);
1967 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1968 break;
1969 else if (rc == SQLITE_ROW)
1971 sql3parentid = sqlite3_column_int(stmt, 0);
1972 break;
1975 sqlite3_finalize(stmt);
1977 g_snprintf(tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE parent=%d;", datatable_tmpname, sql3parentid, sql3id);
1978 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1979 maepad_warning("Error moving nodes up one level");
1980 } else
1982 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d;", datatable_tmpname, sql3id);
1983 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1984 maepad_warning("Error deleting node");
1987 /* Delete all checklist items that do not have
1988 * a node anymore (= orphaned checklist items) */
1989 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid NOT IN (SELECT nodeid FROM %s);", checklisttable_tmpname, datatable_tmpname);
1990 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1991 maepad_warning("Error deleting orphaned checklist items");
1995 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
1998 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
1999 g_object_unref(model);
2001 gtk_tree_row_reference_free(ref);
2002 gtk_tree_row_reference_free(upref);
2004 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
2008 void callback_edit_clear(GtkAction * action, gpointer data)
2010 MainView *mainview = (MainView *) data;
2011 g_assert(mainview != NULL && mainview->data != NULL);
2012 nodeData *nd = getSelectedNode(mainview);
2014 if (show_confirmation(mainview, _("Remove all contents of this memo?"))) {
2015 switch (nd->typ) {
2016 case NODE_TEXT:
2017 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", 0);
2018 break;
2019 case NODE_SKETCH:
2020 sketchwidget_clear(mainview->sk);
2021 break;
2022 case NODE_CHECKLIST:
2023 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview))));
2024 break;
2025 default:
2026 g_assert_not_reached();
2032 * cut
2034 void callback_edit_cut(GtkAction * action, gpointer data)
2036 MainView *mainview = (MainView *) data;
2037 g_assert(mainview != NULL && mainview->data != NULL);
2039 nodeData *nd = getSelectedNode(mainview);
2041 if (nd->typ == NODE_TEXT)
2042 gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, TRUE);
2043 else if (nd->typ == NODE_SKETCH)
2045 if (sketchwidget_cut(mainview->sk, mainview->clipboard)==FALSE)
2046 show_banner(mainview, _("Error cutting"));
2048 else if (nd->typ == NODE_CHECKLIST)
2049 show_banner(mainview, _("Unimplemented"));
2054 * copy
2056 void callback_edit_copy(GtkAction * action, gpointer data)
2058 MainView *mainview = (MainView *) data;
2059 g_assert(mainview != NULL && mainview->data != NULL);
2061 nodeData *nd = getSelectedNode(mainview);
2063 if (nd->typ == NODE_TEXT)
2064 gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard);
2065 else if (nd->typ == NODE_SKETCH)
2067 if (sketchwidget_copy(mainview->sk, mainview->clipboard)==FALSE)
2068 show_banner(mainview, _("Error copying"));
2070 else if (nd->typ == NODE_CHECKLIST)
2072 /* Copy all selected entries as multiline text (1 line per entry) */
2073 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2074 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2076 gint selected_rows = gtk_tree_selection_count_selected_rows(selection);
2077 GList* l = gtk_tree_selection_get_selected_rows(selection, NULL);
2079 GtkTreeIter iter;
2080 gchar *str_data;
2082 gchar **entries = g_malloc0(sizeof(gchar*)*selected_rows+1);
2083 gint entries_idx = 0;
2085 GList* cur = l;
2086 while(cur) {
2087 GtkTreePath *path = cur->data;
2089 if (gtk_tree_model_get_iter(model, &iter, path)) {
2090 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_TEXT, &(entries[entries_idx++]), -1);
2092 gtk_tree_path_free(path);
2094 cur = cur->next;
2097 g_list_free(l);
2098 str_data = g_strjoinv("\n", entries);
2099 g_strfreev(entries);
2100 gtk_clipboard_set_text(mainview->clipboard, str_data, -1);
2101 g_free(str_data);
2103 str_data = g_strdup_printf(_("Copied %d entries"), selected_rows);
2104 show_banner(mainview, str_data);
2105 g_free(str_data);
2111 * paste
2113 void callback_edit_paste(GtkAction * action, gpointer data)
2115 MainView *mainview = (MainView *) data;
2116 g_assert(mainview != NULL && mainview->data != NULL);
2118 nodeData *nd = getSelectedNode(mainview);
2120 if (nd->typ == NODE_TEXT)
2121 gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, NULL, TRUE);
2122 else if (nd->typ == NODE_SKETCH)
2124 if (sketchwidget_paste(mainview->sk, mainview->clipboard)==FALSE)
2125 show_banner(mainview, _("Error pasting"));
2127 else if (nd->typ == NODE_CHECKLIST) {
2128 /* Paste string from clipboard as new item */
2129 callback_checklist_paste(mainview);
2130 checklist_select(mainview, TREEVIEW_SELECT_LAST);
2133 mainview->file_edited = TRUE;
2136 gint cb_popup(GtkWidget * widget, GdkEvent * event)
2138 GtkMenu *menu;
2139 GdkEventButton *event_button;
2142 * The "widget" is the menu that was supplied when
2143 * * g_signal_connect_swapped() was called.
2145 menu = GTK_MENU(widget);
2146 event_button = (GdkEventButton *) event;
2147 if (event->type == GDK_BUTTON_PRESS && event_button->button == 3)
2149 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
2150 return TRUE;
2152 return FALSE;
2157 * on_node_menu_show(GtkWidget*, gpointer)
2159 * This is called when the longpress menu is shown in the main
2160 * window. In the Hildon UI mode that we are using, this does
2161 * not automatically select the touched node, so we need to set
2162 * the cursor here so that the functions in the menu operate on
2163 * the node that the user touched (i.e. the expected one).
2165 * The value of mainview->node_list_longpress_path has been set
2166 * by callback_treeview_button_press on the buttn press event.
2168 void
2169 on_node_menu_show(GtkWidget* nodemenu, gpointer user_data)
2171 MainView* mainview = (MainView*)user_data;
2173 if (mainview->node_list_longpress_path != NULL) {
2174 /* Set the cursor, but don't open the node view */
2175 mainview->can_show_node_view = FALSE;
2176 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
2177 mainview->node_list_longpress_path, NULL, FALSE);
2179 /* Dispose the path (we don't need it anymore) */
2180 gtk_tree_path_free(mainview->node_list_longpress_path);
2181 mainview->node_list_longpress_path = NULL;
2186 * close
2188 gboolean closefile(MainView * mainview)
2190 saveCurrentData(mainview);
2192 if (mainview->file_edited)
2194 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));
2195 gint answer = gtk_dialog_run(GTK_DIALOG(hn));
2196 gtk_widget_destroy(GTK_WIDGET(hn));
2198 if (answer == CONFRESP_CANCEL)
2199 return (FALSE);
2200 else if (answer == CONFRESP_YES)
2202 if (mainview->file_name == NULL)
2204 mainview->file_name = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2206 write_buffer_to_file(mainview);
2210 if (mainview->db)
2211 sqlite3_close(mainview->db);
2212 mainview->db = NULL;
2213 return (TRUE);
2216 gboolean callback_file_close(GtkAction * action, gpointer data)
2219 MainView *mainview = (MainView *) data;
2220 g_assert(mainview != NULL && mainview->data != NULL);
2221 if (closefile(mainview) == FALSE)
2222 return(FALSE);
2224 gtk_main_quit();
2225 return(TRUE);
2228 void callback_file_new_node(GtkAction * action, gpointer data)
2230 MainView *mainview = (MainView *) data;
2231 g_assert(mainview != NULL && mainview->data != NULL);
2233 nodeType typ = NODE_SKETCH;
2235 nodeData *nd = getSelectedNode(mainview);
2237 if (nd != NULL)
2238 typ = nd->typ;
2240 new_node_dialog(typ, mainview);
2244 * new
2246 void callback_file_new(GtkAction * action, gpointer data)
2248 MainView *mainview = (MainView *) data;
2249 g_assert(mainview != NULL && mainview->data != NULL);
2251 gchar *filename = NULL;
2253 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "memos", "db");
2254 if (filename == NULL) {
2255 return;
2258 if (closefile(mainview) == FALSE) {
2259 return;
2262 new_file(mainview);
2266 busy_enter(mainview);
2268 int rc;
2270 rc = sqlite3_open(filename, &mainview->db);
2271 if (rc)
2273 show_banner(mainview, _("Cannot create database"));
2274 maepad_warning("Can't create database %s: %s", filename, sqlite3_errmsg(mainview->db));
2275 break;
2278 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
2280 char tq[512];
2282 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
2283 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
2285 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
2286 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2288 maepad_warning("Cannot create data table");
2289 show_banner(mainview, _("Error creating data table"));
2290 break;
2293 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
2294 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2296 maepad_warning("Cannot create checklist table");
2297 show_banner(mainview, _("Error creating checklist table"));
2298 break;
2301 if (mainview->db)
2302 sqlite3_close(mainview->db);
2303 mainview->db = NULL;
2305 mainview->file_name = filename;
2306 mainview->file_edited = FALSE;
2307 read_file_to_buffer(mainview);
2309 /*add a starter memo*/
2310 nodeData *node;
2311 node = g_malloc(sizeof(nodeData));
2312 node->typ = NODE_SKETCH;
2313 node->name = _("My first memo");
2314 node->namepix = NULL;
2315 node->lastMod = 0;
2316 node->flags = 0;
2317 node->sql3id = 0;
2318 add_new_node(node, mainview, TRUE);
2319 /*gtk_paned_set_position(GTK_PANED(mainview->hpaned), 180);*/
2320 write_buffer_to_file(mainview);
2322 }while(FALSE);
2323 busy_reset(mainview);
2326 gboolean reset_ctree(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
2328 nodeData *node;
2330 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
2331 if (node)
2333 if (node->name)
2334 g_free(node->name);
2335 if (node->namepix)
2336 g_object_unref(node->namepix);
2337 g_free(node);
2339 gtk_tree_store_set(GTK_TREE_STORE(model), iter, NODE_DATA, NULL, -1);
2341 return (FALSE);
2344 void new_file(MainView * mainview)
2346 busy_enter(mainview);
2348 * clear buffer, filename and free buffer text
2350 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);
2351 mainview->file_name = NULL;
2352 mainview->file_edited = FALSE;
2353 mainview->newnodedialog_createchild = TRUE;
2355 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
2357 g_object_ref(model);
2358 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
2360 gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) reset_ctree, (gpointer) mainview);
2363 * crashing bastard
2364 * gtk_tree_store_clear(GTK_TREE_STORE(model));
2366 GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
2367 GtkTreeIter iter;
2369 if (gtk_tree_model_get_iter(model, &iter, path))
2373 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2375 while(gtk_tree_store_iter_is_valid(GTK_TREE_STORE(model), &iter));
2377 gtk_tree_path_free(path);
2379 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
2380 g_object_unref(model);
2382 busy_leave(mainview);
2386 * open
2388 void callback_file_open(GtkAction * action, gpointer data)
2390 gchar *filename = NULL;
2391 MainView *mainview = (MainView *) data;
2392 g_assert(mainview != NULL && mainview->data != NULL);
2394 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
2395 if (filename == NULL) {
2396 return;
2399 if (closefile(mainview) == FALSE) {
2400 return;
2403 open_file(filename, mainview);
2404 g_free(filename);
2407 gboolean open_file(gchar * filename, MainView * mainview)
2409 gboolean ret=FALSE;
2411 /* Don't open nodes when opening a file */
2412 mainview->can_show_node_view = FALSE;
2414 busy_enter(mainview);
2416 while(filename != NULL)
2418 struct stat s;
2420 if (stat(filename, &s) == -1) break;
2422 mainview->file_name = g_strdup(filename);
2423 gboolean res = read_file_to_buffer(mainview);
2425 if (res == FALSE)
2427 g_free(mainview->file_name);
2428 mainview->file_name = NULL;
2429 break;
2431 mainview->file_edited = FALSE;
2432 ret=TRUE;
2433 break;
2436 busy_leave(mainview);
2437 return(ret);
2440 void callback_about_link(GtkAboutDialog *about, const gchar *link, gpointer data)
2442 MainView *mainview = (MainView *) data;
2443 g_assert(mainview != NULL && mainview->data != NULL);
2444 osso_rpc_run_with_defaults(mainview->data->osso, "osso_browser", OSSO_BROWSER_OPEN_NEW_WINDOW_REQ, NULL,
2445 DBUS_TYPE_STRING, link, DBUS_TYPE_INVALID);
2448 void callback_about(GtkAction * action, gpointer data)
2450 MainView* mainview = (MainView *)data;
2451 he_about_dialog_present(mainview_get_dialog_parent(mainview),
2452 NULL /* auto-detect app name */,
2453 "maepad",
2454 VERSION,
2455 _("A node-based memory pad for Maemo"),
2456 _("(c) 2010 Thomas Perl"),
2457 "http://thpinfo.com/2010/maepad/",
2458 "https://garage.maemo.org/tracker/?group_id=1291",
2459 "http://thpinfo.com/2010/maepad/donate");
2463 * save
2465 void callback_file_save(GtkAction * action, gpointer data)
2467 gchar *filename = NULL;
2468 MainView *mainview = (MainView *) data;
2469 g_assert(mainview != NULL && mainview->data != NULL);
2472 * check is we had a new file
2474 if (mainview->file_name != NULL)
2476 write_buffer_to_file(mainview);
2478 else
2480 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2482 * if we got a file name from chooser -> save file
2484 if (filename != NULL)
2486 mainview->file_name = filename;
2487 write_buffer_to_file(mainview);
2488 mainview->file_edited = FALSE;
2493 void callback_shapemenu(GtkAction * action, GtkWidget * wid)
2495 gint style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(wid)));
2496 MainView* mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2497 g_assert(mainview != NULL);
2499 if (style >= 0 && style < SKETCHSHAPE_COUNT) {
2500 /* We use the sketch widget's enum for available styles */
2501 sketchwidget_set_shape(mainview->sk, style);
2503 /* Draw the correct indicator for the current shape */
2504 GtkWidget* pix = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(wid), "i"));
2505 g_assert(pix != NULL);
2506 gtk_widget_show(pix);
2507 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->shape_tb), pix);
2508 } else {
2509 /* Fail. We shouldn't get here at all! */
2510 g_error("Invalid style ID from shape menu: %d", style);
2516 void callback_eraser(GtkAction * action, MainView * mainview)
2518 g_assert(mainview != NULL && mainview->data != NULL);
2520 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb))) {
2521 /* Eraser on: Set pen color to white */
2522 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };
2523 sketchwidget_set_brushcolor(mainview->sk, white);
2524 } else {
2525 /* Eraser off: Set default color again (or black) */
2526 GdkColor black = {0, 0, 0, 0};
2527 if (mainview->current_color == NULL) {
2528 mainview->current_color = gdk_color_copy(&black);
2530 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2534 void callback_menu(GtkAction * action, GtkWidget * menu)
2536 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
2539 void callback_brushsizetb(GtkAction * action, MainView *mainview)
2541 g_assert(mainview != NULL && mainview->data != NULL);
2542 callback_menu(NULL, mainview->brushsizemenu);
2545 void callback_brushsize(GtkAction * action, GtkWidget * wid)
2547 int bsize = (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 && mainview->data != NULL);
2552 sketchwidget_set_brushsize(mainview->sk, bsize);
2554 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2556 gtk_widget_show(pix);
2557 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->brushsize_tb), pix);
2560 void callback_sketchlines(GtkAction * action, GtkWidget * wid)
2562 int style = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2563 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2565 g_assert(mainview != NULL);
2567 nodeData *nd = getSelectedNode(mainview);
2568 gboolean doit = FALSE;
2570 if (nd != NULL && nd->typ == NODE_SKETCH)
2572 nd->flags &= ~NODEFLAG_SKETCHLINES;
2573 nd->flags &= ~NODEFLAG_SKETCHGRAPH;
2574 /* sketchwidget_set_edited(mainview->sk, TRUE);*/ /*we call this on openfile, so this messes things up*/
2575 doit = TRUE;
2578 if (style == 0)
2580 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_NONE);
2582 else if (style == 1)
2584 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_LINES);
2585 if (doit == TRUE)
2586 nd->flags |= NODEFLAG_SKETCHLINES;
2588 else if (style == 2)
2590 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_GRAPH);
2591 if (doit == TRUE)
2592 nd->flags |= NODEFLAG_SKETCHGRAPH;
2595 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2597 gtk_widget_show(pix);
2598 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->sketchlines_tb), pix);
2601 void callback_color(GtkAction* action, MainView* mainview)
2603 g_assert(mainview != NULL && mainview->data != NULL);
2605 nodeData *nd = getSelectedNode(mainview);
2606 if (nd == NULL) return;
2608 HeSimpleColorDialog* dialog = HE_SIMPLE_COLOR_DIALOG(he_simple_color_dialog_new());
2609 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
2611 if (mainview->current_color) {
2612 he_simple_color_dialog_set_color(dialog, mainview->current_color);
2615 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
2616 gtk_widget_destroy(GTK_WIDGET(dialog));
2617 return;
2620 gdk_color_free(mainview->current_color);
2621 mainview->current_color = he_simple_color_dialog_get_color(dialog);
2623 gtk_widget_destroy(GTK_WIDGET(dialog));
2625 switch (nd->typ) {
2626 case NODE_SKETCH:
2627 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb), FALSE);
2628 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2629 break;
2630 case NODE_CHECKLIST:
2631 { /* Put in a separate block to allow new local variables */
2632 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2633 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2634 GList* selected = gtk_tree_selection_get_selected_rows(selection, NULL);
2636 gchar* color_string = g_strdup_printf("#%02x%02x%02x",
2637 mainview->current_color->red >> 8,
2638 mainview->current_color->green >> 8,
2639 mainview->current_color->blue >> 8);
2641 GList* cur = selected;
2642 while (cur != NULL) {
2643 GtkTreePath* path = cur->data;
2644 GtkTreeIter iter;
2645 if (gtk_tree_model_get_iter(model, &iter, path)) {
2646 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_COLOR, color_string, -1);
2648 gtk_tree_path_free(path);
2649 cur = cur->next;
2652 g_list_free(selected);
2653 g_free(color_string);
2655 break;
2656 default:
2657 g_assert_not_reached();
2661 void callback_color_invoke(GtkAction * action, gpointer data)
2663 MainView *mainview = (MainView *) data;
2664 g_assert(mainview != NULL && mainview->data != NULL);
2665 gtk_button_clicked(GTK_BUTTON(mainview->colorbutton_tb));
2670 void callback_pressure(GtkAction * action, MainView *mainview)
2672 g_assert(mainview != NULL && mainview->data != NULL);
2674 nodeData *nd = getSelectedNode(mainview);
2676 if (nd == NULL)
2677 return;
2678 if (nd->typ != NODE_SKETCH)
2679 return;
2681 /* pressure sensitivity disabled for now...
2682 mainview->sk->pressuresensitivity=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure));*/
2686 void callback_wordwrap(GtkWidget* widget, gpointer user_data)
2688 MainView* mainview = (MainView*)user_data;
2689 nodeData* nd = getSelectedNode(mainview);
2690 GtkWrapMode wrap_mode;
2692 if (nd == NULL || nd->typ != NODE_TEXT) {
2693 return;
2696 if (hildon_check_button_get_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap))) {
2697 nd->flags |= NODEFLAG_WORDWRAP;
2698 wrap_mode = GTK_WRAP_WORD_CHAR;
2699 } else {
2700 nd->flags &= ~NODEFLAG_WORDWRAP;
2701 wrap_mode = GTK_WRAP_NONE;
2704 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mainview->textview), wrap_mode);
2708 void callback_font(GtkAction * action, gpointer data)
2710 MainView *mainview = (MainView *) data;
2711 g_assert(mainview != NULL && mainview->data != NULL);
2713 nodeData *nd = getSelectedNode(mainview);
2715 if (nd == NULL)
2716 return;
2717 if (nd->typ != NODE_TEXT)
2718 return;
2720 HildonFontSelectionDialog *dialog = HILDON_FONT_SELECTION_DIALOG(hildon_font_selection_dialog_new(NULL, NULL));
2722 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2723 /*gotsel=FALSE;*/
2725 WPTextBufferFormat fmt;
2726 wp_text_buffer_get_attributes(mainview->buffer, &fmt, gotsel);
2728 gint ri=0;
2729 if (fmt.text_position==TEXT_POSITION_SUPERSCRIPT) ri=1;
2730 else if (fmt.text_position==TEXT_POSITION_SUBSCRIPT) ri=-1;
2732 g_object_set(G_OBJECT(dialog),
2733 "family-set", fmt.cs.font,
2734 "family", wp_get_font_name(fmt.font),
2735 "size-set", fmt.cs.font_size,
2736 "size", wp_font_size[fmt.font_size],
2737 "color-set", fmt.cs.color,
2738 "color", &fmt.color,
2739 "bold-set", fmt.cs.bold,
2740 "bold", fmt.bold,
2741 "italic-set", fmt.cs.italic,
2742 "italic", fmt.italic,
2743 "underline-set", fmt.cs.underline,
2744 "underline", fmt.underline,
2745 "strikethrough-set", fmt.cs.strikethrough,
2746 "strikethrough", fmt.strikethrough,
2747 "position-set", fmt.cs.text_position,
2748 "position", ri,
2749 NULL);
2751 gtk_widget_show_all(GTK_WIDGET(dialog));
2752 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2754 gboolean bold, italic, underline, strikethrough;
2755 gchar *family = NULL;
2756 gint size, position;
2757 GdkColor *color=NULL;
2758 gboolean set_family, set_size, set_bold, set_italic, set_underline, set_strikethrough, set_color, set_position;
2760 g_object_get(G_OBJECT(dialog), "family", &family, "size", &size, "bold", &bold, "italic", &italic,
2761 "underline", &underline, "strikethrough", &strikethrough,
2762 "family-set", &set_family, "size-set", &set_size, "bold-set", &set_bold, "italic-set", &set_italic,
2763 "underline-set", &set_underline, "strikethrough-set", &set_strikethrough,
2764 "color", &color, "color-set", &set_color, "position", &position, "position-set", &set_position,
2765 NULL);
2767 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE);
2768 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;
2770 if (set_family) { fmt.font=wp_get_font_index(family, 1); fmt.cs.font=1; }
2771 if (set_size) { fmt.font_size=wp_get_font_size_index(size, 16); fmt.cs.font_size=1; }
2773 if (set_strikethrough)
2775 fmt.cs.strikethrough=1;
2776 fmt.strikethrough=strikethrough;
2779 if (set_color)
2782 GLIB WARNING ** GLib-GObject - IA__g_object_set_valist: object class `GtkTextTag' has no property named `'
2784 fmt.cs.color=1;
2785 fmt.color.pixel=color->pixel;
2786 fmt.color.red=color->red;
2787 fmt.color.green=color->green;
2788 fmt.color.blue=color->blue;
2791 if (set_position)
2793 if (position==1) ri=TEXT_POSITION_SUPERSCRIPT;
2794 else if (position==-1) ri=TEXT_POSITION_SUBSCRIPT;
2795 else ri=TEXT_POSITION_NORMAL;
2797 fmt.cs.text_position=1;
2798 fmt.text_position=ri;
2801 if (set_bold)
2803 fmt.cs.bold=1;
2804 fmt.bold=bold;
2806 if (set_italic)
2808 fmt.cs.italic=1;
2809 fmt.italic=italic;
2811 if (set_underline)
2813 fmt.cs.underline=1;
2814 fmt.underline=underline;
2817 wp_text_buffer_set_format(mainview->buffer, &fmt);
2820 gtk_widget_destroy(GTK_WIDGET(dialog));
2823 void callback_fontstyle(GtkAction * action, GtkWidget * wid)
2825 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2826 g_assert(mainview != NULL && mainview->data != NULL);
2828 nodeData *nd = getSelectedNode(mainview);
2830 if (nd == NULL)
2831 return;
2832 if (nd->typ == NODE_TEXT)
2834 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2836 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2837 wp_text_buffer_set_attribute(mainview->buffer, style, (gpointer)act);
2839 else if (nd->typ == NODE_CHECKLIST)
2841 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2842 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2843 if (style!=WPT_BOLD && style!=WPT_STRIKE && style!=WPT_LEFT) return;
2845 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2846 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
2848 gint styletoset_weight=PANGO_WEIGHT_NORMAL;
2849 gboolean styletoset_strike=FALSE;
2850 gboolean checkit=FALSE;
2852 if (style==WPT_BOLD && act==TRUE) styletoset_weight=PANGO_WEIGHT_BOLD;
2853 else if (style==WPT_STRIKE && act==TRUE) styletoset_strike=TRUE;
2854 else if (style==WPT_LEFT && act==TRUE) checkit=TRUE;
2856 GList* cur=l;
2857 while(cur)
2859 GtkTreePath *path=cur->data;
2861 GtkTreeIter iter;
2862 if (gtk_tree_model_get_iter(model, &iter, path))
2864 if (style==WPT_BOLD) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_BOLD, styletoset_weight, -1);
2865 else if (style==WPT_STRIKE) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_STRIKE, styletoset_strike, -1);
2866 else if (style==WPT_LEFT) {
2867 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_CHECKED, checkit, -1);
2868 if (checkit) {
2869 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
2870 } else {
2871 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, NULL, -1);
2875 gtk_tree_path_free(path);
2876 cur=cur->next;
2879 g_list_free(l);
2880 mainview->checklist_edited = TRUE;
2884 void
2885 callback_sharing(GtkWidget* widget, gpointer user_data)
2887 MainView* mainview = (MainView*)user_data;
2888 nodeData* nd = getSelectedNode(mainview);
2889 gchar* filename = g_strdup("/tmp/untitled.png");
2890 gchar* uri = NULL;
2892 if (nd == NULL || nd->typ != NODE_SKETCH) {
2893 show_banner(mainview, _("Only sketches can be shared"));
2894 return;
2897 if (nd->name != NULL) {
2898 g_free(filename);
2899 filename = g_strdup_printf("/tmp/%s.png", nd->name);
2902 busy_enter(mainview);
2903 GdkPixmap* skpix = sketchwidget_get_Pixmap(mainview->sk);
2904 GtkWidget* skdr = sketchwidget_get_drawingarea(mainview->sk);
2905 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL,
2906 GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0,
2907 skdr->allocation.width, skdr->allocation.height);
2909 if (pixbuf == NULL) {
2910 show_banner(mainview, _("Memo is empty"));
2911 goto cleanup;
2914 if (!gdk_pixbuf_save(pixbuf, filename, "png", NULL, NULL)) {
2915 show_banner(mainview, _("File export failed"));
2916 goto cleanup;
2919 uri = g_strdup_printf("file://%s", filename);
2921 sharing_dialog_with_file(mainview->data->osso,
2922 mainview_get_dialog_parent(mainview),
2923 uri);
2925 cleanup:
2926 g_object_unref(skpix);
2927 g_free(filename);
2928 g_free(uri);
2929 busy_leave(mainview);
2932 void
2933 callback_remove_checked(GtkWidget* widget, gpointer user_data)
2935 MainView* mainview = (MainView*)user_data;
2936 nodeData* nd = getSelectedNode(mainview);
2937 GtkTreeIter iter;
2938 GtkTreeModel* model = NULL;
2939 GList* checked_items = NULL;
2940 gchar* question = NULL;
2941 gint count = 0;
2943 if (nd == NULL || nd->typ != NODE_CHECKLIST) {
2944 return;
2947 /* Get a list of checked items */
2948 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2949 if (!gtk_tree_model_get_iter_first(model, &iter)) {
2950 return;
2953 busy_enter(mainview);
2954 do {
2955 gboolean checked = FALSE;
2956 gtk_tree_model_get(model, &iter, CHECKNODE_CHECKED, &checked, -1);
2958 if (checked) {
2959 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
2961 checked_items = g_list_append(checked_items,
2962 gtk_tree_row_reference_new(model, path));
2963 count++;
2965 gtk_tree_path_free(path);
2967 } while (gtk_tree_model_iter_next(model, &iter));
2968 busy_leave(mainview);
2970 if (checked_items == NULL) {
2971 show_banner(mainview, _("No checked items in checklist"));
2972 return;
2975 question = g_strdup_printf(N_("Remove %d checked item?", "Remove %d checked items?", count), count);
2976 if (show_confirmation(mainview, question)) {
2977 /* Remove the checklist items from the list */
2978 checklist_remove_rowrefs(mainview, checked_items, TRUE);
2979 } else {
2980 /* Free the allocated row references + list */
2981 GList* cur = checked_items;
2982 while (cur != NULL) {
2983 GtkTreeRowReference* rowref = cur->data;
2984 gtk_tree_row_reference_free(rowref);
2985 cur = cur->next;
2987 g_list_free(checked_items);
2989 g_free(question);
2992 void callback_textbuffer_move(WPTextBuffer *textbuffer, MainView *mainview)
2994 g_assert(mainview != NULL && mainview->data != NULL);
2997 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2999 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), gotsel);
3000 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), gotsel);
3001 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), gotsel);
3002 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), gotsel);
3004 WPTextBufferFormat fmt;
3005 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE/*gotsel*/);
3007 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3008 g_signal_handlers_block_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
3009 g_signal_handlers_block_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
3010 g_signal_handlers_block_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
3012 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), fmt.bold);
3013 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), fmt.italic);
3014 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), fmt.underline);
3015 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), fmt.bullet);
3017 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3018 g_signal_handlers_unblock_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
3019 g_signal_handlers_unblock_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
3020 g_signal_handlers_unblock_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
3023 gint wp_savecallback(const gchar *buffer, GString * gstr)
3025 gstr=g_string_append(gstr, buffer);
3026 return(0);
3029 void callback_undo(GtkAction * action, MainView * mainview)
3031 g_assert(mainview != NULL && mainview->data != NULL);
3033 nodeData *nd = getSelectedNode(mainview);
3035 if (nd == NULL) return;
3037 if (nd->typ == NODE_SKETCH) sketchwidget_undo(mainview->sk);
3038 else if (nd->typ == NODE_TEXT) wp_text_buffer_undo(mainview->buffer);
3041 void callback_redo(GtkAction * action, MainView * mainview)
3043 g_assert(mainview != NULL && mainview->data != NULL);
3045 nodeData *nd = getSelectedNode(mainview);
3047 if (nd == NULL) return;
3049 if (nd->typ == NODE_SKETCH) sketchwidget_redo(mainview->sk);
3050 else if (nd->typ == NODE_TEXT) wp_text_buffer_redo(mainview->buffer);
3053 void callback_undotoggle(gpointer widget, gboolean st, MainView * mainview)
3055 g_assert(mainview != NULL && mainview->data != NULL);
3057 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), st);
3060 void callback_redotoggle(gpointer widget, gboolean st, MainView * mainview)
3062 g_assert(mainview != NULL && mainview->data != NULL);
3064 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), st);
3067 gboolean close_cb(GtkWidget * widget, GdkEventAny * event, MainView * mainview)
3069 callback_file_close(NULL, mainview);
3070 return (TRUE);
3073 void
3074 mainview_click_on_current_node(MainView* mainview)
3076 GtkTreeSelection* selection = NULL;
3077 GtkTreeModel* model = NULL;
3078 GtkTreeIter iter;
3080 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
3081 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
3082 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
3084 mainview->can_show_node_view = TRUE;
3085 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
3086 path, NULL, FALSE);
3088 gtk_tree_path_free(path);
3092 gboolean
3093 on_main_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3095 MainView* mainview = (MainView*)user_data;
3096 gboolean result = FALSE;
3098 switch (event->keyval) {
3099 case GDK_KP_Enter:
3100 case GDK_Return:
3101 case GDK_l:
3102 case GDK_L:
3103 /* Open selected memo in node view */
3104 mainview_click_on_current_node(mainview);
3105 result = TRUE;
3106 break;
3107 case GDK_w:
3108 case GDK_W:
3109 /* Save changes to file ("write buffer") */
3110 callback_file_save(NULL, mainview);
3111 result = TRUE;
3112 break;
3113 case GDK_BackSpace:
3114 /* Delete selected node (with confirmation) */
3115 callback_file_delete_node(NULL, mainview);
3116 result = TRUE;
3117 break;
3118 case GDK_o:
3119 case GDK_O:
3120 /* Add new memo to list */
3121 callback_file_new_node(NULL, mainview);
3122 result = TRUE;
3123 break;
3124 case GDK_r:
3125 case GDK_R:
3126 /* Replace (edit) name of selected memo */
3127 callback_file_rename_node(NULL, mainview);
3128 result = TRUE;
3129 break;
3130 case GDK_g:
3131 if (mainview->main_view_prev_keyval == GDK_g) {
3132 /* Goto (=select) first memo */
3133 mainview->can_show_node_view = FALSE;
3134 nodelist_select(mainview, TREEVIEW_SELECT_FIRST);
3136 /* Don't remember this key for the next keypress */
3137 mainview->main_view_prev_keyval_reset = TRUE;
3139 result = TRUE;
3141 break;
3142 case GDK_G:
3143 /* Goto (=select) last memo */
3144 mainview->can_show_node_view = FALSE;
3145 nodelist_select(mainview, TREEVIEW_SELECT_LAST);
3146 result = TRUE;
3147 break;
3148 case GDK_j:
3149 case GDK_J:
3150 case GDK_Down:
3151 /* Goto (=select) next memo */
3152 mainview->can_show_node_view = FALSE;
3153 nodelist_select(mainview, TREEVIEW_SELECT_NEXT);
3154 result = TRUE;
3155 break;
3156 case GDK_k:
3157 case GDK_K:
3158 case GDK_Up:
3159 /* Goto (=select) previous memo */
3160 mainview->can_show_node_view = FALSE;
3161 nodelist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3162 result = TRUE;
3163 break;
3164 default:
3165 /* do nothing */
3166 break;
3169 return result;
3172 gboolean
3173 on_node_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3175 MainView* mainview = (MainView*)user_data;
3176 nodeData* nd = getSelectedNode(mainview);
3177 gboolean result = FALSE;
3179 if (nd == NULL) {
3180 return FALSE;
3183 switch (event->keyval) {
3184 case GDK_w:
3185 case GDK_W:
3186 if (nd->typ != NODE_TEXT) {
3187 /* Save changes to file ("write buffer") */
3188 callback_file_save(NULL, mainview);
3189 result = TRUE;
3191 break;
3192 case GDK_BackSpace:
3193 if (event->state & GDK_SHIFT_MASK) {
3194 /* Remove current memo (with confirmation) */
3195 callback_file_delete_node(NULL, mainview);
3196 result = TRUE;
3197 } else if (nd->typ == NODE_CHECKLIST) {
3198 /* Remove current item (with confirmation) */
3199 callback_checklist_delete(NULL, mainview);
3200 result = TRUE;
3201 } else if (nd->typ == NODE_SKETCH) {
3202 /* Undo last sketch action */
3203 callback_undo(NULL, mainview);
3204 result = TRUE;
3206 break;
3207 case GDK_space:
3208 if (nd->typ == NODE_CHECKLIST) {
3209 /* Toggle check of current item */
3210 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3211 result = TRUE;
3212 } else if (nd->typ == NODE_SKETCH) {
3213 /* Toggle eraser tool */
3214 maepad_toggle_gtk_toggle_tool_button(mainview->eraser_tb);
3215 result = TRUE;
3217 break;
3218 case GDK_f:
3219 case GDK_F:
3220 if (nd->typ != NODE_TEXT) {
3221 /* Toggle fullscreen mode */
3222 callback_fullscreen(NULL, mainview);
3223 result = TRUE;
3225 break;
3226 case GDK_h:
3227 case GDK_H:
3228 if (nd->typ != NODE_TEXT) {
3229 /* Hide node view, go to main view ("left") */
3230 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
3231 result = TRUE;
3233 break;
3234 case GDK_o:
3235 case GDK_O:
3236 if (nd->typ == NODE_CHECKLIST) {
3237 /* Insert new checklist item */
3238 callback_checklist_add(NULL, mainview);
3239 result = TRUE;
3241 break;
3242 case GDK_d:
3243 if (nd->typ == NODE_CHECKLIST) {
3244 if (mainview->node_view_prev_keyval == GDK_d) {
3245 /* Yank selected items, then remove them silently */
3246 callback_edit_copy(NULL, mainview);
3247 callback_checklist_delete_real(mainview);
3248 show_banner(mainview, _("Item yanked to clipboard"));
3250 /* Don't remember this key for the next keypress */
3251 mainview->node_view_prev_keyval_reset = TRUE;
3253 result = TRUE;
3256 break;
3257 case GDK_y:
3258 if (nd->typ == NODE_CHECKLIST) {
3259 if (mainview->node_view_prev_keyval == GDK_y) {
3260 /* Non-destructive yanking of items */
3261 callback_edit_copy(NULL, mainview);
3262 show_banner(mainview, _("Item yanked to clipboard"));
3264 /* Don't remember this key for the next keypress */
3265 mainview->node_view_prev_keyval_reset = TRUE;
3267 result = TRUE;
3270 break;
3271 case GDK_p:
3272 case GDK_P:
3273 if (nd->typ == NODE_CHECKLIST) {
3274 /* Paste text in clipboard as items */
3275 callback_edit_paste(NULL, mainview);
3276 result = TRUE;
3278 break;
3279 case GDK_g:
3280 if (nd->typ == NODE_CHECKLIST) {
3281 if (mainview->node_view_prev_keyval == GDK_g) {
3282 /* Goto (=select) first item */
3283 checklist_select(mainview, TREEVIEW_SELECT_FIRST);
3285 /* Don't remember this key for the next keypress */
3286 mainview->node_view_prev_keyval_reset = TRUE;
3288 result = TRUE;
3291 break;
3292 case GDK_G:
3293 if (nd->typ == NODE_CHECKLIST) {
3294 /* Goto (=select) last item */
3295 checklist_select(mainview, TREEVIEW_SELECT_LAST);
3296 result = TRUE;
3298 break;
3299 case GDK_j:
3300 case GDK_J:
3301 case GDK_Down:
3302 if (nd->typ == NODE_CHECKLIST) {
3303 /* Goto (=select) next item */
3304 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
3305 result = TRUE;
3306 } else if (nd->typ == NODE_SKETCH) {
3307 /* Undo last sketch operation */
3308 callback_undo(NULL, mainview);
3309 result = TRUE;
3311 break;
3312 case GDK_k:
3313 case GDK_K:
3314 case GDK_Up:
3315 if (nd->typ == NODE_CHECKLIST) {
3316 /* Goto (=select) previous item */
3317 checklist_select(mainview, TREEVIEW_SELECT_PREVIOUS);
3318 result = TRUE;
3319 } else if (nd->typ == NODE_SKETCH) {
3320 /* Redo last sketch operation */
3321 callback_redo(NULL, mainview);
3322 result = TRUE;
3324 break;
3325 case GDK_a:
3326 case GDK_A:
3327 if (nd->typ == NODE_CHECKLIST) {
3328 /* Append text to current node */
3329 checklist_edit_selected(mainview, LINE_EDIT_MODE_APPEND);
3330 result = TRUE;
3332 break;
3333 case GDK_r:
3334 case GDK_R:
3335 case GDK_KP_Enter:
3336 case GDK_Return:
3337 if (nd->typ == NODE_CHECKLIST) {
3338 /* Replace (edit) text of current node */
3339 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
3340 result = TRUE;
3342 break;
3343 case GDK_i:
3344 case GDK_I:
3345 if (nd->typ == NODE_CHECKLIST) {
3346 /* Prepend (insert) text to current node */
3347 checklist_edit_selected(mainview, LINE_EDIT_MODE_PREPEND);
3348 result = TRUE;
3350 break;
3351 default:
3352 /* do nothing */
3353 break;
3356 return result;
3359 gboolean
3360 on_main_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3362 MainView* mainview = (MainView*)user_data;
3364 if (mainview->main_view_prev_keyval_reset) {
3365 /* Forget last-pressed key value */
3366 mainview->main_view_prev_keyval = GDK_VoidSymbol;
3367 mainview->main_view_prev_keyval_reset = FALSE;
3368 } else {
3369 /* Remember last keyval for double-press bindings */
3370 mainview->main_view_prev_keyval = event->keyval;
3373 return FALSE;
3376 gboolean
3377 on_node_view_key_release(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3379 MainView* mainview = (MainView*)user_data;
3381 if (mainview->node_view_prev_keyval_reset) {
3382 /* Forget last-pressed key value */
3383 mainview->node_view_prev_keyval = GDK_VoidSymbol;
3384 mainview->node_view_prev_keyval_reset = FALSE;
3385 } else {
3386 /* Remember last keyval for double-press bindings */
3387 mainview->node_view_prev_keyval = event->keyval;
3390 return FALSE;
3393 gboolean
3394 on_checklist_longpress_timeout(gpointer user_data)
3396 MainView* mainview = (MainView*)user_data;
3397 callback_checklist_edit(NULL, mainview);
3398 mainview->checklist_longpress_source_id = 0;
3399 return FALSE;
3402 gboolean
3403 on_checklist_button_press(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3405 MainView* mainview = (MainView*)user_data;
3406 GtkTreePath* path;
3407 GtkTreeViewColumn* column;
3408 GtkTreeSelection* selection;
3410 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
3411 event->x,
3412 event->y,
3413 &path,
3414 &column,
3415 NULL,
3416 NULL)) {
3417 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
3419 if (gtk_tree_selection_path_is_selected(selection, path)) {
3420 if (column == mainview->checklist_column_check) {
3421 /* Check column touched - toggle checklist item */
3422 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3423 } else if (column == mainview->checklist_column_text) {
3424 mainview->checklist_longpress_source_id = g_timeout_add(
3425 CHECKLIST_LONGPRESS_EDIT_DELAY,
3426 on_checklist_longpress_timeout,
3427 mainview);
3429 return TRUE;
3432 gtk_tree_path_free(path);
3435 return FALSE;
3438 void
3439 checklist_abort_longpress(MainView* mainview)
3441 /* Abort the longpress action on the checklist */
3442 if (mainview->checklist_longpress_source_id != 0) {
3443 g_source_remove(mainview->checklist_longpress_source_id);
3444 mainview->checklist_longpress_source_id = 0;
3448 gboolean
3449 on_checklist_button_release(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3451 MainView* mainview = (MainView*)user_data;
3452 checklist_abort_longpress(mainview);
3453 return FALSE;
3456 gboolean
3457 on_checklist_start_panning(HildonPannableArea* area, gpointer user_data)
3459 MainView* mainview = (MainView*)user_data;
3460 checklist_abort_longpress(mainview);
3461 return FALSE;
3464 void callback_fullscreen(GtkToolButton* tool_button, gpointer user_data)
3466 MainView* mainview = (MainView*)user_data;
3467 gtk_window_fullscreen(GTK_WINDOW(mainview->data->node_view));
3470 void
3471 callback_sketch_button_toggled(HildonCheckButton* button, gpointer user_data)
3473 MainView* mainview = (MainView*)user_data;
3474 gboolean active = hildon_check_button_get_active(button);
3476 if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_square)) {
3477 sketchwidget_set_shift(mainview->sk, active);
3478 } else if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_filled)) {
3479 sketchwidget_set_fillmode(mainview->sk, active);
3483 void callback_buffer_modified(GtkAction * action, gpointer data)
3485 MainView *mainview = (MainView *) data;
3486 g_assert(mainview != NULL && mainview->data != NULL);
3488 mainview->file_edited = TRUE;
3491 GtkTreeRowReference *read_sqlite3_data(MainView * mainview, unsigned int parentid, GtkTreeRowReference * parenttree, unsigned int selected, GtkTreeStore * model)
3493 GtkTreeRowReference *resref = NULL;
3495 char q[256];
3497 g_snprintf(q, sizeof(q), "SELECT nodeid, bodytype, name, nameblob, lastmodified, flags FROM %s WHERE parent=%d ORDER BY ord", datatable_tmpname, parentid);
3499 sqlite3_stmt *stmt = NULL;
3500 const char *dum;
3501 int rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3503 if (rc)
3505 maepad_warning("Error reading SQLite3 data: %s", sqlite3_errmsg(mainview->db));
3506 return (NULL);
3509 rc = SQLITE_BUSY;
3510 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3512 rc = sqlite3_step(stmt);
3513 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3514 break;
3515 else if (rc == SQLITE_ROW)
3517 int nodeid = sqlite3_column_int(stmt, 0);
3518 int typ = sqlite3_column_int(stmt, 1);
3519 const unsigned char *name = sqlite3_column_text(stmt, 2);
3520 const unsigned char *nameblob = sqlite3_column_text(stmt, 3);
3521 int lastmod = sqlite3_column_int(stmt, 4);
3522 int flags = sqlite3_column_int(stmt, 5);
3524 if ((typ != NODE_TEXT && typ != NODE_SKETCH && typ != NODE_CHECKLIST) || (name == NULL && nameblob == NULL)) {
3525 maepad_warning("Unknown node type in database: %d (skipping)", typ);
3526 continue;
3529 nodeData *node = g_malloc(sizeof(nodeData));
3531 node->sql3id = nodeid;
3532 node->typ = typ;
3533 node->flags = flags;
3534 node->name = NULL;
3535 node->namepix = NULL;
3536 if (name != NULL) {
3537 node->name = g_strdup((char *)name);
3538 } else {
3539 node->name = g_strdup(_("Unnamed memo"));
3541 /*if (nameblob != NULL)
3543 int blobsize = sqlite3_column_bytes(stmt, 3);
3545 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
3546 GError *err = NULL;
3548 gdk_pixbuf_loader_write(pl, (guchar *) nameblob, blobsize, &err);
3549 if (err != NULL)
3551 fprintf(stderr, "Error loading nodename! %s\n", err->message);
3552 g_error_free(err);
3553 err = NULL;
3555 gdk_pixbuf_loader_close(pl, NULL);
3556 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
3558 if (GDK_IS_PIXBUF(pixbuf))
3559 node->namepix = pixbuf;
3561 node->lastMod = lastmod;
3563 GtkTreeIter parentiter, newiter;
3564 void *par = NULL;
3566 if (parenttree != NULL)
3568 GtkTreePath *pa = gtk_tree_row_reference_get_path(parenttree);
3570 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parentiter, pa);
3571 gtk_tree_path_free(pa);
3572 par = &parentiter;
3575 gtk_tree_store_append(model, &newiter, par);
3576 gtk_tree_store_set(model, &newiter, NODE_NAME, format_overview_name(node, NULL), NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
3578 GtkTreePath *pa = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &newiter);
3580 GtkTreeRowReference *newref = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), pa);
3582 if (selected == nodeid)
3583 resref = newref;
3585 gtk_tree_path_free(pa);
3586 GtkTreeRowReference *r = read_sqlite3_data(mainview, nodeid, newref, selected,
3587 model);
3589 if (resref != newref)
3590 gtk_tree_row_reference_free(newref);
3592 if (r != NULL)
3594 if (resref == NULL)
3595 resref = r;
3596 else
3597 gtk_tree_row_reference_free(r); /*safeguard */
3602 if (stmt)
3603 sqlite3_finalize(stmt);
3605 return (resref); /*ref to supposed-to-be-selected treeitem */
3609 * read file
3611 gboolean read_file_to_buffer(MainView * mainview)
3613 char tq[512];
3615 g_assert(mainview != NULL);
3616 gboolean res = FALSE;
3618 gchar *filename = mainview->file_name;
3620 new_file(mainview);
3621 mainview->file_name = filename;
3622 mainview->loading=TRUE;
3624 maepad_message("Reading database file: %s", filename);
3626 int rc;
3627 sqlite3_stmt *stmt = NULL;
3629 rc = sqlite3_open(filename, &mainview->db);
3632 if (rc)
3634 maepad_warning("Cannot open database %s: %s", filename, sqlite3_errmsg(mainview->db));
3635 break;
3638 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
3640 char *q = "SELECT skey, sval FROM settings";
3641 const char *dum;
3643 rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3644 if (rc)
3646 maepad_warning("Error reading settings: %s", sqlite3_errmsg(mainview->db));
3647 break;
3650 unsigned int selectedCard = 0;
3651 unsigned int curDataVersion = 0;
3652 unsigned int curChecklistVersion = 0;
3654 rc = SQLITE_BUSY;
3655 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3657 rc = sqlite3_step(stmt);
3658 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3659 break;
3660 else if (rc == SQLITE_ROW)
3662 const gchar* col_key = (const gchar*)sqlite3_column_text(stmt, 0);
3663 const gchar* col_val = (const gchar*)sqlite3_column_text(stmt, 1);
3664 if (!strcmp(col_key, "selectedNode"))
3666 gint tmp = atoi((char *)col_val);
3668 if (tmp > 0)
3669 selectedCard = tmp;
3671 if (!strcmp(col_key, "dataVersion"))
3673 gint tmp = atoi((char *)col_val);
3675 if (tmp > 0)
3676 curDataVersion = tmp;
3678 if (!strcmp(col_key, "checklistVersion"))
3680 gint tmp = atoi((char *)col_val);
3682 if (tmp > 0)
3683 curChecklistVersion = tmp;
3685 if (!strcmp(col_key, "newNodeDlgCreateChild"))
3687 gint tmp = atoi((char *)col_val);
3689 mainview->newnodedialog_createchild = TRUE;
3690 if (tmp == 0)
3691 mainview->newnodedialog_createchild = FALSE;
3693 if (!strcmp(col_key, "brushSize"))
3695 gint tmp = atoi((char *)col_val);
3696 if (tmp>0) sk_set_brushsize(mainview, tmp);
3698 if (!strcmp(col_key, "brushColor"))
3700 unsigned long tmp = atol((char *)col_val);
3701 GdkColor c2;
3703 c2.red = ((tmp & 0xFF0000) >> 16) << 8;
3704 c2.green = ((tmp & 0xFF00) >> 8) << 8;
3705 c2.blue = (tmp & 0xFF) << 8;
3706 sketchwidget_set_brushcolor(mainview->sk, c2);
3708 if (mainview->current_color != NULL) {
3709 gdk_color_free(mainview->current_color);
3711 mainview->current_color = gdk_color_copy(&c2);
3716 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
3718 maepad_warning("Error reading data: %s", sqlite3_errmsg(mainview->db));
3719 break;
3722 if (stmt) {
3723 sqlite3_finalize(stmt);
3724 stmt = NULL;
3727 gboolean resback = FALSE;
3729 while(curDataVersion < datatableversion)
3731 if (curDataVersion == 0)
3733 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3734 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3736 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_name, datatable_backupname);
3737 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3738 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3739 break;
3741 resback = TRUE;
3743 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
3744 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3745 maepad_warning("Error creating table: %s", datatable_name);
3746 break;
3748 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);
3749 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3750 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_backupname);
3751 break;
3754 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3755 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3757 curDataVersion = datatableversion;
3759 break;
3762 if (curDataVersion != datatableversion)
3764 maepad_warning("Data table version mismatch: %d <=> %d", curDataVersion, datatableversion);
3766 if (resback == TRUE)
3768 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_name);
3769 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3770 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_backupname, datatable_name);
3771 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3774 break;
3778 while(curChecklistVersion < checklisttableversion)
3780 if (curChecklistVersion == 0) /*no checklisttable at all*/
3782 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
3783 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3784 maepad_warning("Error creating checklist table during schema upgrade");
3785 break;
3787 curChecklistVersion = checklisttableversion;
3789 break;
3793 GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
3795 g_object_ref(model);
3796 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
3800 char tq[512];
3802 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, datatable_tmpname, datatable);
3803 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3804 maepad_warning("Error creating temp table: %s", datatable_tmpname);
3805 break;
3807 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", datatable_tmpname, datatable_tmpname, dataindex);
3808 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3809 maepad_warning("Error creating temp index for %s", datatable_tmpname);
3810 break;
3812 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_tmpname, datatable_name);
3813 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3814 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_tmpname);
3815 break;
3818 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, checklisttable_tmpname, checklisttable);
3819 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3820 maepad_warning("Error creating temp table: %s", checklisttable_tmpname);
3821 break;
3823 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", checklisttable_tmpname, checklisttable_tmpname, checklistindex);
3824 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3825 maepad_warning("Error creating temp index for %s", checklisttable_tmpname);
3826 break;
3828 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_tmpname, checklisttable_name);
3829 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3830 maepad_warning("Error copying data from %s to %s", checklisttable_name, checklisttable_tmpname);
3831 break;
3834 while(FALSE);
3836 GtkTreeRowReference *selectedRef = read_sqlite3_data(mainview, 0, NULL, selectedCard, model);
3838 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), GTK_TREE_MODEL(model));
3839 g_object_unref(model);
3840 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
3842 if (selectedRef != NULL)
3844 GtkTreeIter seliter;
3846 if (ref2iter(GTK_TREE_MODEL(model), selectedRef, &seliter) == TRUE)
3848 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
3849 gtk_tree_selection_select_iter(selection, &seliter);
3852 gtk_tree_row_reference_free(selectedRef);
3854 res = TRUE;
3856 while(FALSE);
3858 if (stmt) {
3859 sqlite3_finalize(stmt);
3863 mainview->loading=FALSE;
3865 return (res);
3869 * write to file
3871 void write_buffer_to_file(MainView * mainview)
3873 maepad_message("Writing database to file: %s", mainview->file_name);
3874 saveCurrentData(mainview);
3876 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
3877 /*update ord value in database for all nodes*/
3878 gtk_tree_model_foreach(GTK_TREE_MODEL(model),(GtkTreeModelForeachFunc) foreach_func_update_ord,mainview);
3880 busy_enter(mainview);
3882 char tq[512];
3884 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", misctable_name);
3885 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3887 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
3888 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3890 gint nndcc = 1;
3892 if (mainview->newnodedialog_createchild == FALSE)
3893 nndcc = 0;
3894 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('newNodeDlgCreateChild', '%d');", misctable_name, nndcc);
3895 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3897 nodeData *node = getSelectedNode(mainview);
3899 if (node)
3901 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('selectedNode', '%d');", misctable_name, node->sql3id);
3902 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3905 guint bsize = sketchwidget_get_brushsize(mainview->sk);
3906 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushSize', '%d');", misctable_name, bsize);
3907 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3909 if (mainview->current_color == NULL) {
3910 GdkColor color = {0, 0, 0, 0};
3911 mainview->current_color = gdk_color_copy(&color);
3913 unsigned long bcol = ((mainview->current_color->red >> 8) << 16) |
3914 ((mainview->current_color->green >> 8) << 8) |
3915 ((mainview->current_color->blue) >> 8);
3917 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushColor', '%lu');", misctable_name, bcol);
3918 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3920 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('dataVersion', '%d');", misctable_name, datatableversion);
3921 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3923 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('checklistVersion', '%d');", misctable_name, checklisttableversion);
3924 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3926 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3927 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3928 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_backupname, datatable);
3929 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3931 maepad_warning("Error creating backup table: %s", datatable_backupname);
3932 show_banner(mainview, _("Error creating backup table"));
3934 busy_leave(mainview);
3935 return;
3937 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_backupname, datatable_name);
3938 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3940 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3941 show_banner(mainview, _("Error creating backup table"));
3943 busy_leave(mainview);
3944 return;
3946 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3947 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3949 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_tmpname);
3950 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3952 maepad_warning("Error saving table %s to %s", datatable_tmpname, datatable_name);
3953 show_banner(mainview, _("Error saving table"));
3955 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3956 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3958 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_backupname);
3959 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3960 maepad_warning("Error restoring backup. Data lost :(");
3963 busy_leave(mainview);
3964 return;
3967 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3968 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3970 /*checklist*/
3971 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3972 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3973 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_backupname, checklisttable);
3974 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3976 maepad_warning("Error creating backup table: %s", checklisttable_backupname);
3977 show_banner(mainview, _("Error creating checklist backup table"));
3979 busy_leave(mainview);
3980 return;
3983 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_backupname, checklisttable_name);
3984 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3986 maepad_warning("Error backing up table %s to %s", checklisttable_name, checklisttable_backupname);
3987 show_banner(mainview, _("Error creating checklist backup table"));
3989 busy_leave(mainview);
3990 return;
3992 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3993 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3995 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_tmpname);
3996 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3998 maepad_warning("Error saving table %s to %s", checklisttable_tmpname, checklisttable_name);
3999 show_banner(mainview, _("Error saving checklist table"));
4001 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
4002 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
4004 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_backupname);
4005 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
4006 maepad_warning("Error restoring backup. Data lost :(");
4008 busy_leave(mainview);
4009 return;
4012 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
4013 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
4015 mainview->file_edited = FALSE;
4016 busy_leave(mainview);
4017 show_banner(mainview, _("Changes saved"));
4020 void callback_checklist_change(GtkTreeSelection *selection, MainView *mainview)
4022 g_assert(mainview != NULL && mainview->data != NULL);
4024 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
4025 g_signal_handlers_block_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
4026 g_signal_handlers_block_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
4028 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), FALSE);
4029 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), FALSE);
4030 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), FALSE);
4032 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4033 GList* l=gtk_tree_selection_get_selected_rows(selection, NULL);
4035 gboolean gotit=FALSE;
4037 GList* cur=l;
4038 while(cur)
4040 GtkTreePath *path=cur->data;
4042 if (!gotit)
4044 GtkTreeIter iter;
4045 if (gtk_tree_model_get_iter(model, &iter, path))
4047 gint styletoset_weight;
4048 gboolean styletoset_strike;
4049 gboolean ischecked;
4051 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, -1);
4052 if (styletoset_weight==PANGO_WEIGHT_BOLD) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), TRUE);
4053 if (styletoset_strike==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), TRUE);
4054 if (ischecked==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), TRUE);
4055 gotit=TRUE;
4058 gtk_tree_path_free(path);
4059 cur=cur->next;
4062 g_list_free(l);
4064 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
4065 g_signal_handlers_unblock_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
4066 g_signal_handlers_unblock_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
4069 void callback_checklist_paste(MainView *mainview)
4071 g_assert(mainview != NULL && mainview->data != NULL);
4072 gchar **entries;
4073 gint length, i;
4075 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4076 GtkTreeIter toplevel;
4077 gchar *pasted_text = gtk_clipboard_wait_for_text(mainview->clipboard);
4079 entries = g_strsplit(pasted_text, "\n", 0);
4080 length = g_strv_length(entries);
4082 for (i=0; i<length; i++) {
4083 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
4084 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, FALSE, CHECKNODE_TEXT, entries[i], -1);
4087 mainview->checklist_edited = TRUE;
4088 g_free(pasted_text);
4089 g_strfreev(entries);
4092 void callback_checklist_add(GtkAction *action, MainView *mainview)
4094 g_assert(mainview != NULL && mainview->data != NULL);
4096 gchar* text = show_line_edit_dialog(mainview, _("Add new checklist item"), _("Name:"), _("Add"), "");
4098 if (text != NULL) {
4099 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4100 GtkTreeIter toplevel;
4101 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
4103 gtk_list_store_set(GTK_LIST_STORE(model),
4104 &toplevel,
4105 CHECKNODE_CHECKED, FALSE,
4106 CHECKNODE_TEXT, text,
4107 -1);
4109 GtkTreePath *path = gtk_tree_model_get_path(model, &toplevel);
4110 if (path) {
4111 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->listview), path, mainview->checklist_column_text, FALSE);
4112 gtk_tree_path_free(path);
4115 mainview->checklist_edited = TRUE;
4119 void
4120 checklist_edit_selected(MainView* mainview, LineEditMode mode)
4122 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4124 if (gtk_tree_selection_count_selected_rows(selection) == 0) {
4125 show_banner(mainview, _("Select items first"));
4126 return;
4129 GtkTreeModel* model;
4130 GtkTreeIter iter;
4132 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4133 gchar* old_text = NULL;
4134 gtk_tree_model_get(model, &iter, CHECKNODE_TEXT, &old_text, -1);
4136 gchar* new_text = show_line_edit_dialog_full(mainview, _("Edit checklist item"), _("New name:"), _("Save"), old_text, mode);
4138 if (new_text != NULL) {
4139 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_TEXT, new_text, -1);
4140 mainview->checklist_edited = TRUE;
4141 g_free(new_text);
4144 g_free(old_text);
4148 void callback_checklist_edit(GtkAction *action, MainView *mainview)
4150 g_assert(mainview != NULL && mainview->data != NULL);
4151 checklist_edit_selected(mainview, LINE_EDIT_MODE_DEFAULT);
4154 void callback_checklist_delete(GtkAction *action, MainView *mainview)
4156 g_assert(mainview != NULL && mainview->data != NULL);
4158 if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)))==0) {
4159 show_banner(mainview, _("Select items first"));
4160 return;
4163 if (show_confirmation(mainview, _("Delete selected checklist item?"))) {
4164 callback_checklist_delete_real(mainview);
4168 void callback_checklist_delete_real(MainView* mainview)
4170 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4171 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
4173 /* Select the item after the selection */
4174 checklist_select(mainview, TREEVIEW_SELECT_NEXT);
4176 GList* rowrefs=NULL;
4177 GList* cur=l;
4178 while(cur)
4180 GtkTreePath *path=cur->data;
4182 GtkTreeIter iter;
4183 if (gtk_tree_model_get_iter(model, &iter, path))
4185 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, path);
4186 rowrefs=g_list_append(rowrefs, rowref);
4188 gtk_tree_path_free(path);
4189 cur=cur->next;
4191 g_list_free(l);
4192 checklist_remove_rowrefs(mainview, rowrefs, FALSE);
4195 void
4196 checklist_remove_rowrefs(MainView* mainview, GList* rowrefs, gboolean show_result)
4198 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4199 GList* cur = rowrefs;
4200 gint count = 0;
4202 busy_enter(mainview);
4204 while (cur) {
4205 GtkTreeRowReference* rowref = cur->data;
4206 GtkTreePath* path = gtk_tree_row_reference_get_path(rowref);
4207 if (path != NULL) {
4208 GtkTreeIter iter;
4209 if (gtk_tree_model_get_iter(model, &iter, path)) {
4210 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
4211 count++;
4213 gtk_tree_path_free(path);
4215 gtk_tree_row_reference_free(rowref);
4216 cur = cur->next;
4218 g_list_free(rowrefs);
4220 busy_leave(mainview);
4222 if (count && show_result) {
4223 gchar* message = g_strdup_printf(N_("%d item removed", "%d items removed", count), count);
4224 show_banner(mainview, message);
4225 g_free(message);
4228 mainview->checklist_edited = TRUE;
4231 /* Private callback for show_confirmation() - handle keyboard input */
4232 gboolean
4233 on_confirmation_key_press_event(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
4235 GtkDialog* dialog = GTK_DIALOG(widget);
4237 switch (event->keyval) {
4238 /* Positive response - Enter, Return or y */
4239 case GDK_KP_Enter:
4240 case GDK_Return:
4241 case GDK_y:
4242 case GDK_Y:
4243 gtk_dialog_response(dialog, GTK_RESPONSE_OK);
4244 return TRUE;
4246 /* Negative response - Backspace, Escape or n */
4247 case GDK_BackSpace:
4248 case GDK_Escape:
4249 case GDK_n:
4250 case GDK_N:
4251 gtk_dialog_response(dialog, GTK_RESPONSE_CANCEL);
4252 return TRUE;
4254 /* Don't handle the rest of the keys */
4255 default:
4256 return FALSE;
4261 /* Ask the user for confirmation of a specific action */
4262 gboolean
4263 show_confirmation(MainView* mainview, gchar* question)
4265 GtkDialog* dialog = GTK_DIALOG(hildon_note_new_confirmation(
4266 GTK_WINDOW(mainview->data->main_view), question));
4267 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
4268 g_signal_connect(G_OBJECT(dialog), "key-press-event",
4269 G_CALLBACK(on_confirmation_key_press_event), NULL);
4271 gint response = gtk_dialog_run(dialog);
4272 gtk_widget_destroy(GTK_WIDGET(dialog));
4274 return (response == GTK_RESPONSE_OK);
4277 /* Show a information banner to the user (non-modal) */
4278 void
4279 show_banner(MainView* mainview, const gchar* text)
4281 hildon_banner_show_information(GTK_WIDGET(mainview_get_dialog_parent(mainview)), NULL, text);
4284 typedef struct {
4285 GtkWidget* dialog;
4286 gboolean can_close_window;
4287 } LineEditDialogData;
4289 /* Helper function to close line edit dialog on Backspace */
4290 gboolean
4291 line_edit_dialog_key_press(GtkWidget* w, GdkEventKey* event, gpointer user_data)
4293 LineEditDialogData* dialogdata = (LineEditDialogData*)user_data;
4294 GtkEntry* entry = GTK_ENTRY(w);
4296 if (event->keyval == GDK_BackSpace &&
4297 dialogdata->can_close_window &&
4298 strcmp(gtk_entry_get_text(entry), "") == 0) {
4299 gtk_dialog_response(GTK_DIALOG(dialogdata->dialog), GTK_RESPONSE_CANCEL);
4300 return TRUE;
4303 return FALSE;
4306 /* Let the user enter or edit a line of text */
4307 gchar*
4308 show_line_edit_dialog_full(MainView* mainview, const gchar* title,
4309 const gchar* label_text, const gchar* action, const gchar* text,
4310 LineEditMode mode)
4312 GtkWidget* edit_dialog;
4313 GtkWidget* label;
4314 GtkWidget* entry;
4315 GtkWidget* hbox;
4316 gchar* result = NULL;
4317 LineEditDialogData dialogdata;
4319 edit_dialog = GTK_WIDGET(gtk_dialog_new());
4320 gtk_window_set_title(GTK_WINDOW(edit_dialog), title);
4321 gtk_window_set_transient_for(GTK_WINDOW(edit_dialog), mainview_get_dialog_parent(mainview));
4323 label = GTK_WIDGET(gtk_label_new(label_text));
4325 entry = hildon_entry_new(HILDON_SIZE_AUTO);
4326 gtk_entry_set_text(GTK_ENTRY(entry), text);
4327 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
4328 switch (mode) {
4329 case LINE_EDIT_MODE_DEFAULT:
4330 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
4331 break;
4332 case LINE_EDIT_MODE_APPEND:
4333 gtk_editable_select_region(GTK_EDITABLE(entry), -1, -1);
4334 break;
4335 case LINE_EDIT_MODE_PREPEND:
4336 gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
4337 break;
4338 default:
4339 break;
4342 gtk_dialog_add_button(GTK_DIALOG(edit_dialog), action, GTK_RESPONSE_OK);
4343 gtk_dialog_set_default_response(GTK_DIALOG(edit_dialog), GTK_RESPONSE_OK);
4345 dialogdata.dialog = edit_dialog;
4346 dialogdata.can_close_window = (strcmp(text, "") == 0);
4347 g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(line_edit_dialog_key_press), &dialogdata);
4349 hbox = GTK_WIDGET(gtk_hbox_new(FALSE, 10));
4351 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(edit_dialog))), GTK_WIDGET(hbox));
4352 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
4353 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
4355 gtk_widget_show_all(GTK_WIDGET(hbox));
4357 while (TRUE) {
4358 if (gtk_dialog_run(GTK_DIALOG(edit_dialog)) == GTK_RESPONSE_OK) {
4359 result = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
4360 if (strcmp(result, "") != 0) {
4361 break;
4362 } else {
4363 show_banner(mainview, _("Please enter a non-empty text"));
4364 g_free(result);
4365 result = NULL;
4367 } else {
4368 result = NULL;
4369 break;
4373 gtk_widget_destroy(GTK_WIDGET(edit_dialog));
4374 return result;
4377 void
4378 treeview_scroll_to_selection(MainView* mainview, TreeViewType type)
4380 GtkTreeView* treeview = NULL;
4381 HildonPannableArea* pannable_area = NULL;
4382 GtkTreeModel* model = NULL;
4383 GtkTreeSelection* selection = NULL;
4384 GtkTreePath* path = NULL;
4385 GtkTreeIter iter;
4386 GdkRectangle rect;
4387 gint y;
4389 switch (type) {
4390 case TREEVIEW_MAINVIEW:
4391 treeview = GTK_TREE_VIEW(mainview->treeview);
4392 pannable_area = HILDON_PANNABLE_AREA(mainview->scrolledtree);
4393 break;
4394 case TREEVIEW_CHECKLIST:
4395 treeview = GTK_TREE_VIEW(mainview->listview);
4396 pannable_area = HILDON_PANNABLE_AREA(mainview->listscroll);
4397 break;
4398 default:
4399 g_assert_not_reached();
4400 break;
4403 /* Let the view scroll so that the selected item is visible */
4404 selection = gtk_tree_view_get_selection(treeview);
4405 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
4406 path = gtk_tree_model_get_path(model, &iter);
4408 gtk_tree_view_get_background_area(treeview, path, NULL, &rect);
4409 gtk_tree_view_convert_bin_window_to_tree_coords(treeview,
4410 0, rect.y, NULL, &y);
4411 hildon_pannable_area_scroll_to(pannable_area, -1, y);
4413 gtk_tree_path_free(path);
4417 gboolean
4418 checklist_scroll_to_selection(gpointer user_data)
4420 MainView* mainview = (MainView*)user_data;
4421 treeview_scroll_to_selection(mainview, TREEVIEW_CHECKLIST);
4422 return FALSE;
4425 gboolean
4426 nodelist_scroll_to_selection(gpointer user_data)
4428 MainView* mainview = (MainView*)user_data;
4429 treeview_scroll_to_selection(mainview, TREEVIEW_MAINVIEW);
4430 return FALSE;
4433 void
4434 checklist_select(MainView* mainview, TreeviewSelectType type)
4436 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
4437 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
4438 GtkTreeIter iter;
4439 GtkTreeIter last;
4440 GtkTreePath* path;
4442 switch (type) {
4443 case TREEVIEW_SELECT_FIRST:
4444 if (gtk_tree_model_get_iter_first(model, &iter)) {
4445 path = gtk_tree_model_get_path(model, &iter);
4446 gtk_tree_selection_select_path(selection, path);
4447 gtk_tree_path_free(path);
4449 break;
4450 case TREEVIEW_SELECT_LAST:
4451 if (gtk_tree_model_get_iter_first(model, &iter)) {
4452 do {
4453 last = iter;
4454 } while (gtk_tree_model_iter_next(model, &iter));
4455 path = gtk_tree_model_get_path(model, &last);
4456 gtk_tree_selection_select_path(selection, path);
4457 gtk_tree_path_free(path);
4459 break;
4460 case TREEVIEW_SELECT_PREVIOUS:
4461 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4462 path = gtk_tree_model_get_path(model, &iter);
4463 if (gtk_tree_path_prev(path)) {
4464 gtk_tree_selection_select_path(selection, path);
4466 gtk_tree_path_free(path);
4468 break;
4469 case TREEVIEW_SELECT_NEXT:
4470 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4471 path = gtk_tree_model_get_path(model, &iter);
4472 gtk_tree_path_next(path);
4473 gtk_tree_selection_select_path(selection, path);
4474 gtk_tree_path_free(path);
4476 break;
4477 default:
4478 g_assert_not_reached();
4479 break;
4482 checklist_scroll_to_selection(mainview);
4485 * This is a workaround: The HildonPannableArea does not seem to
4486 * scroll to the right position (especially when going to the first
4487 * or last item in the list), so we simply scroll again after 500ms.
4489 g_timeout_add(500, checklist_scroll_to_selection, mainview);
4492 void
4493 nodelist_select(MainView* mainview, TreeviewSelectType type)
4495 GtkTreeView* treeview = GTK_TREE_VIEW(mainview->treeview);
4496 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
4497 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
4498 GtkTreeIter iter;
4499 GtkTreeIter last;
4500 GtkTreeIter child;
4501 GtkTreePath* path;
4503 switch (type) {
4504 case TREEVIEW_SELECT_FIRST:
4505 if (gtk_tree_model_get_iter_first(model, &iter)) {
4506 path = gtk_tree_model_get_path(model, &iter);
4507 gtk_tree_selection_select_path(selection, path);
4508 gtk_tree_path_free(path);
4510 break;
4511 case TREEVIEW_SELECT_LAST:
4512 if (gtk_tree_model_get_iter_first(model, &iter)) {
4513 do {
4514 last = iter;
4515 if (gtk_tree_model_iter_children(model, &child, &last)) {
4516 do {
4517 last = child;
4518 } while (gtk_tree_model_iter_next(model, &child));
4520 } while (gtk_tree_model_iter_next(model, &iter));
4521 path = gtk_tree_model_get_path(model, &last);
4522 gtk_tree_selection_select_path(selection, path);
4523 gtk_tree_path_free(path);
4525 break;
4526 case TREEVIEW_SELECT_PREVIOUS:
4527 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4528 path = gtk_tree_model_get_path(model, &iter);
4529 if (gtk_tree_path_prev(path)) {
4530 gtk_tree_selection_select_path(selection, path);
4531 } else if (gtk_tree_path_up(path)) {
4532 gtk_tree_selection_select_path(selection, path);
4534 gtk_tree_path_free(path);
4536 break;
4537 case TREEVIEW_SELECT_NEXT:
4538 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
4539 path = gtk_tree_model_get_path(model, &iter);
4540 gtk_tree_path_down(path);
4541 while (!gtk_tree_model_get_iter(model, &iter, path)) {
4542 /* Child item does not exist - bubble up to next item */
4543 gtk_tree_path_up(path);
4544 gtk_tree_path_next(path);
4546 if (gtk_tree_path_get_depth(path) == 0) {
4547 /* avoid infinite loops */
4548 break;
4552 if (gtk_tree_model_get_iter(model, &iter, path)) {
4553 gtk_tree_selection_select_path(selection, path);
4556 gtk_tree_path_free(path);
4558 break;
4559 default:
4560 g_assert_not_reached();
4561 break;
4564 nodelist_scroll_to_selection(mainview);
4567 * This is a workaround: The HildonPannableArea does not seem to
4568 * scroll to the right position (especially when going to the first
4569 * or last item in the list), so we simply scroll again after 500ms.
4571 g_timeout_add(500, nodelist_scroll_to_selection, mainview);
4575 const gchar *
4576 format_overview_name(nodeData *nd, const gchar *name)
4578 static gchar *tmp;
4579 gchar *font_desc, *font_color;
4581 if (tmp != NULL) {
4582 g_free(tmp);
4585 if (name == NULL) {
4586 name = nd->name;
4589 font_desc = he_get_logical_font_desc("SmallSystemFont");
4590 font_color = he_get_logical_font_color("SecondaryTextColor");
4592 tmp = g_markup_printf_escaped("%s\n<span font_desc=\"%s\" foreground=\"%s\">%s</span>",
4593 name,
4594 font_desc,
4595 font_color,
4596 (nd->typ==NODE_CHECKLIST)?(_("Checklist")):
4597 ((nd->typ==NODE_TEXT)?(_("Rich text")):
4598 ((nd->typ==NODE_SKETCH)?(_("Sketch")):(""))));
4600 g_free(font_desc);
4601 g_free(font_color);
4603 return tmp;
4607 gchar *
4608 he_get_logical_font_desc(const gchar *name)
4610 GtkSettings *settings = gtk_settings_get_default();
4611 GtkStyle *style = gtk_rc_get_style_by_paths(settings,
4612 name, NULL, G_TYPE_NONE);
4614 return pango_font_description_to_string(style->font_desc);
4617 gchar *
4618 he_get_logical_font_color(const gchar *name)
4620 GdkColor color;
4621 GtkSettings *settings = gtk_settings_get_default();
4622 GtkStyle *style = gtk_rc_get_style_by_paths(settings,
4623 "GtkButton", "osso-logical-colors", GTK_TYPE_BUTTON);
4625 if (gtk_style_lookup_color(style, name, &color)) {
4626 return gdk_color_to_string(&color);
4627 } else {
4628 return NULL;