Fix bug when closing the new/open dialogs
[maepad.git] / src / ui / callbacks.c
blobda4bb4e0f4aa342701add45b6236e68d59c50dab
1 /*
2 * This file is part of MaePad
3 * Copyright (c) 2010 Thomas Perl <thp@thpinfo.com>
4 * http://thpinfo.com/2010/maepad/
6 * Based on Maemopad+:
7 * Copyright (c) 2006-2008 Kemal Hadimli
8 * Copyright (c) 2008 Thomas Perl
10 * This software is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1 of
13 * the License, or (at your option) any later version.
15 * This software is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this software; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
27 #include <ui/callbacks.h>
28 #include <ui/interface.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <libintl.h>
33 #include <glib.h>
36 * strlen needed from string.h
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <config.h>
45 #include <time.h>
47 #include <hildon/hildon.h>
48 #include <hildon/hildon-banner.h>
49 #include <hildon/hildon-note.h>
50 #include <hildon/hildon-font-selection-dialog.h>
51 #include <tablet-browser-interface.h>
53 #include <libgnomevfs/gnome-vfs.h>
55 #include <sharingdialog/sharing-dialog.h>
57 #include "sketchwidget.h"
59 #include "../he/he-about-dialog.h"
60 #include "../he/he-simple-color-dialog.h"
63 * "Busy" status handling
65 * Use "busy_reset" to reset the busy status (turn off)
66 * Use "busy_enter" when starting time-consuming processing
67 * Use "busy_leave" when processing has been finished
69 typedef enum {
70 BUSY_RESET = 0,
71 BUSY_INCREMENT,
72 BUSY_DECREMENT,
73 } SetBusyType;
75 /* Don't use this directly, but make use of the macros defined below */
76 void set_busy(MainView* mainview, SetBusyType update);
78 #define busy_reset(mainview) set_busy(mainview, BUSY_RESET)
79 #define busy_enter(mainview) set_busy(mainview, BUSY_INCREMENT)
80 #define busy_leave(mainview) set_busy(mainview, BUSY_DECREMENT)
84 * Privates:
86 void checklist_abort_longpress(MainView* mainview);
87 gboolean read_file_to_buffer(MainView * mainview);
88 void write_buffer_to_file(MainView * mainview);
89 void new_node_dialog(nodeType typ, MainView * mainview);
90 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview);
91 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop);
92 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter);
93 gboolean exec_command_on_db(MainView *mainview,char sql_string[]);
94 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter);
95 gint get_branch_node_index(GtkTreePath *path);
96 gboolean move_node(MainView *mainview,GtkTreeIter *new_parent,GtkTreeIter *item_to_move,GtkTreeIter *item_befor);
97 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter);
98 gboolean show_confirmation(MainView* mainview, gchar* question);
102 gboolean callback_node_view_window_state(GtkWidget* window,
103 GdkEventWindowState* event, gpointer user_data)
105 MainView* mainview = (MainView*)user_data;
106 GtkWidget* sketch_scroll = NULL;
108 if (mainview->toolbar == NULL || mainview->sk == NULL) {
109 return FALSE;
112 sketch_scroll = GTK_WIDGET(sketchwidget_get_mainwidget(mainview->sk));
114 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
115 if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
116 gtk_widget_hide(mainview->toolbar);
117 gtk_scrolled_window_set_policy(
118 GTK_SCROLLED_WINDOW(sketch_scroll),
119 GTK_POLICY_NEVER,
120 GTK_POLICY_NEVER);
121 } else {
122 gtk_widget_show(mainview->toolbar);
123 gtk_scrolled_window_set_policy(
124 GTK_SCROLLED_WINDOW(sketch_scroll),
125 GTK_POLICY_AUTOMATIC,
126 GTK_POLICY_AUTOMATIC);
130 return FALSE;
133 void set_busy(MainView* mainview, SetBusyType update)
135 switch (update) {
136 case BUSY_RESET:
137 mainview->busyrefcount = 0;
138 break;
139 case BUSY_INCREMENT:
140 mainview->busyrefcount++;
141 break;
142 case BUSY_DECREMENT:
143 if (mainview->busyrefcount > 0) {
144 mainview->busyrefcount--;
146 break;
147 default:
148 g_assert_not_reached();
149 return;
152 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->main_view), (mainview->busyrefcount > 0));
153 hildon_gtk_window_set_progress_indicator(GTK_WINDOW(mainview->data->node_view), (mainview->busyrefcount > 0));
156 void prepareUIforNodeChange(MainView * mainview, nodeType typ)
158 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), TRUE);
159 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), TRUE);
161 if (typ == NODE_TEXT)
163 gtk_widget_show(GTK_WIDGET(mainview->font_tb));
164 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
165 gtk_widget_show(GTK_WIDGET(mainview->italic_tb));
166 gtk_widget_show(GTK_WIDGET(mainview->underline_tb));
167 gtk_widget_show(GTK_WIDGET(mainview->bullet_tb));
168 gtk_widget_show(mainview->tools_font);
170 else
172 gtk_widget_hide(GTK_WIDGET(mainview->font_tb));
173 gtk_widget_hide(GTK_WIDGET(mainview->bold_tb));
174 gtk_widget_hide(GTK_WIDGET(mainview->italic_tb));
175 gtk_widget_hide(GTK_WIDGET(mainview->underline_tb));
176 gtk_widget_hide(GTK_WIDGET(mainview->bullet_tb));
177 gtk_widget_hide(mainview->tools_font);
180 if (typ == NODE_SKETCH)
182 /* gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));*/
183 gtk_widget_show(GTK_WIDGET(mainview->eraser_tb));
184 gtk_widget_show(GTK_WIDGET(mainview->brushsize_tb));
185 gtk_widget_show(GTK_WIDGET(mainview->sketchlines_tb));
186 gtk_widget_show(GTK_WIDGET(mainview->shape_tb));
187 gtk_widget_show(GTK_WIDGET(mainview->sharing_tb));
188 gtk_widget_show(mainview->tools_color);
189 gtk_widget_show(mainview->tools_brushsize);
190 gtk_widget_show(mainview->tools_pagestyle);
191 gtk_widget_show(mainview->tools_shape);
192 gtk_widget_show(mainview->tools_pressure);
194 else
196 /* gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));*/
197 gtk_widget_hide(GTK_WIDGET(mainview->eraser_tb));
198 gtk_widget_hide(GTK_WIDGET(mainview->brushsize_tb));
199 gtk_widget_hide(GTK_WIDGET(mainview->sketchlines_tb));
200 gtk_widget_hide(GTK_WIDGET(mainview->shape_tb));
201 gtk_widget_hide(GTK_WIDGET(mainview->sharing_tb));
202 gtk_widget_hide(mainview->tools_color);
203 gtk_widget_hide(mainview->tools_brushsize);
204 gtk_widget_hide(mainview->tools_pagestyle);
205 gtk_widget_hide(mainview->tools_shape);
206 gtk_widget_hide(mainview->tools_pressure);
209 if (typ == NODE_CHECKLIST)
211 gtk_widget_show(GTK_WIDGET(mainview->bold_tb));
212 gtk_widget_show(GTK_WIDGET(mainview->strikethru_tb));
213 gtk_widget_show(GTK_WIDGET(mainview->check_tb));
214 gtk_widget_show(GTK_WIDGET(mainview->checkadd_tb));
215 gtk_widget_show(GTK_WIDGET(mainview->checkedit_tb));
216 gtk_widget_show(GTK_WIDGET(mainview->checkdel_tb));
217 gtk_widget_hide(GTK_WIDGET(mainview->undo_tb));
218 gtk_widget_hide(GTK_WIDGET(mainview->redo_tb));
220 else
222 gtk_widget_hide(GTK_WIDGET(mainview->strikethru_tb));
223 gtk_widget_hide(GTK_WIDGET(mainview->check_tb));
224 gtk_widget_hide(GTK_WIDGET(mainview->checkadd_tb));
225 gtk_widget_hide(GTK_WIDGET(mainview->checkedit_tb));
226 gtk_widget_hide(GTK_WIDGET(mainview->checkdel_tb));
227 gtk_widget_show(GTK_WIDGET(mainview->undo_tb));
228 gtk_widget_show(GTK_WIDGET(mainview->redo_tb));
231 if (typ == NODE_TEXT)
233 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
234 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
235 gtk_widget_hide(mainview->listscroll);
236 gtk_widget_show(GTK_WIDGET(mainview->scrolledwindow));
237 gtk_widget_show(mainview->tools_item);
239 else if (typ == NODE_SKETCH)
241 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
242 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
243 gtk_widget_hide(mainview->listscroll);
244 gtk_widget_show(sketchwidget_get_mainwidget(mainview->sk));
245 gtk_widget_show(mainview->tools_item);
247 else if (typ == NODE_CHECKLIST)
249 gtk_widget_show(GTK_WIDGET(mainview->colorbutton_tb));
250 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
251 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
252 gtk_widget_hide(mainview->tools_item);
253 gtk_widget_show(mainview->listscroll);
255 else
257 gtk_widget_hide(GTK_WIDGET(mainview->colorbutton_tb));
258 gtk_widget_hide(GTK_WIDGET(mainview->scrolledwindow));
259 gtk_widget_hide(sketchwidget_get_mainwidget(mainview->sk));
260 gtk_widget_hide(mainview->tools_item);
261 gtk_widget_hide(mainview->listscroll);
265 nodeData *getSelectedNode(MainView * mainview)
267 GtkTreeIter iter;
268 GtkTreeModel *model;
270 nodeData *nd;
272 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
274 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
275 return (NULL);
277 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
279 return (nd);
282 void saveCurrentData(MainView * mainview)
284 nodeData *selnode = getSelectedNode(mainview);
285 saveDataToNode(mainview, selnode);
288 void saveDataToNode(MainView * mainview, nodeData *selnode)
290 if (selnode == NULL)
291 return;
293 if (
294 (selnode->typ == NODE_SKETCH && sketchwidget_get_edited(mainview->sk) == FALSE) ||
295 (selnode->typ == NODE_TEXT && wp_text_buffer_is_modified(mainview->buffer)==FALSE) ||
296 (selnode->typ == NODE_CHECKLIST && mainview->checklist_edited==FALSE)
299 maepad_message("node not edited, not saving");
300 return;
303 mainview->file_edited = TRUE;
305 busy_enter(mainview);
306 maepad_debug("saveDataToNode working");
308 gboolean goterr = TRUE;
309 gchar *textdata = NULL;
310 GdkPixbuf *pixbuf = NULL;
311 gchar *sketchdata = NULL;
312 gsize datalen = 0;
313 char tq[512];
315 if (selnode->typ == NODE_TEXT)
317 #if 0
318 GtkTextIter start, end;
319 gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(mainview->buffer), &start, &end);
320 textdata = gtk_text_buffer_serialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &start, &end, &datalen);
321 #endif
323 GString *gstr=g_string_sized_new(4096);
324 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
326 datalen=gstr->len;
327 textdata=g_string_free(gstr, FALSE);
329 /* g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, bodyblob=NULL, body=?, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);*/
330 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, bodyblob=?, body=NULL, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
332 else if (selnode->typ == NODE_SKETCH)
334 GError *err = NULL;
335 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
336 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
338 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
339 if (pixbuf == NULL)
341 maepad_warning("error saving: pixbuf is null");
343 else
345 double w, h;
346 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, skdr->allocation.width, skdr->allocation.height, &w, &h, FALSE);
348 if (pixbuf2!=NULL)
350 if (gdk_pixbuf_save_to_buffer(pixbuf2, &sketchdata, &datalen, "png", &err, NULL) == FALSE)
352 sketchdata = NULL;
353 datalen = 0;
354 maepad_warning("Error saving sketch: %s", err->message);
355 g_error_free(err);
357 gdk_pixbuf_unref(pixbuf2);
360 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, body=NULL, bodyblob=?, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
361 maepad_debug("storing sketch in db: %d bytes", datalen);
362 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
364 else if (selnode->typ == NODE_CHECKLIST)
366 g_snprintf(tq, sizeof(tq), "UPDATE %s SET bodytype=%d, body=NULL, bodyblob=NULL, flags=%d WHERE nodeid=%d", datatable_tmpname, selnode->typ, selnode->flags, selnode->sql3id);
371 sqlite3_stmt *stmt = NULL;
372 const char *dum;
373 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
375 if (rc)
377 maepad_warning("Error updating: %s", sqlite3_errmsg(mainview->db));
378 break;
380 if (selnode->typ == NODE_TEXT)
381 sqlite3_bind_text(stmt, 1, textdata, datalen, /*strlen(textdata),*/ SQLITE_TRANSIENT);
382 else if (selnode->typ == NODE_SKETCH)
383 sqlite3_bind_blob(stmt, 1, sketchdata, datalen, SQLITE_TRANSIENT);
385 rc = SQLITE_BUSY;
386 while(rc == SQLITE_BUSY)
388 rc = sqlite3_step(stmt);
389 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
390 break;
392 sqlite3_finalize(stmt);
394 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
396 maepad_warning("Error saving node: %s", sqlite3_errmsg(mainview->db));
398 else
400 if (selnode->typ == NODE_TEXT)
401 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE);
402 else if (selnode->typ == NODE_SKETCH)
403 sketchwidget_set_edited(mainview->sk, FALSE);
404 else if (selnode->typ == NODE_CHECKLIST)
405 mainview->checklist_edited = FALSE;
406 goterr = FALSE;
408 }while(FALSE);
410 while(goterr==FALSE && selnode->typ == NODE_CHECKLIST)
412 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
414 char tq[512];
415 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d", checklisttable_tmpname, selnode->sql3id);
416 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
418 GtkTreeIter iter;
419 if (gtk_tree_model_get_iter_first(model, &iter)==FALSE) break;
423 gint styletoset_weight;
424 gboolean styletoset_strike;
425 gboolean ischecked;
426 gchar *text;
427 gchar *color;
428 unsigned long col=0;
430 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, CHECKNODE_TEXT, &text, CHECKNODE_COLOR, &color, -1);
432 GdkColor tmpcol;
433 if (color!=NULL && strcmp(color, "(null)")!=0 && gdk_color_parse(color, &tmpcol))
435 col=((tmpcol.red>>8)<<16)|((tmpcol.green>>8)<<8)|(tmpcol.blue>>8);
438 gint style=0;
439 if (ischecked) style|=CHECKSTYLE_CHECKED;
440 if (styletoset_weight==PANGO_WEIGHT_BOLD) style|=CHECKSTYLE_BOLD;
441 if (styletoset_strike) style|=CHECKSTYLE_STRIKE;
443 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (nodeid, name, style, color, ord) VALUES(%d, ?, %d, %lu, 0)", checklisttable_tmpname, selnode->sql3id, style, col);
444 sqlite3_stmt *stmt = NULL;
445 const char *dum;
446 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
448 if (rc)
450 goterr=TRUE;
451 maepad_warning("Error while saving checklist: %s", sqlite3_errmsg(mainview->db));
452 break;
454 sqlite3_bind_text(stmt, 1, text, strlen(text), SQLITE_TRANSIENT);
456 rc = SQLITE_BUSY;
457 while(rc == SQLITE_BUSY)
459 rc = sqlite3_step(stmt);
460 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
461 break;
463 sqlite3_finalize(stmt);
465 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
467 goterr=TRUE;
468 maepad_warning("Error while saving checklist (2): %s", sqlite3_errmsg(mainview->db));
471 g_free(color);
472 g_free(text);
474 }while(gtk_tree_model_iter_next(model, &iter)==TRUE);
476 break;
479 if (textdata)
480 g_free(textdata);
481 if (sketchdata)
482 g_free(sketchdata);
483 if (goterr == TRUE)
485 show_banner(mainview, _("Error saving memo"));
487 busy_leave(mainview);
490 gboolean callback_treeview_button_press(GtkTreeView* treeview, GdkEventButton* event, gpointer user_data)
492 MainView* mainview = (MainView*)user_data;
493 GtkTreePath* path;
495 if (mainview->node_list_longpress_path != NULL) {
496 /* Forget old, remembered tree path for longpress */
497 gtk_tree_path_free(mainview->node_list_longpress_path);
498 mainview->node_list_longpress_path = NULL;
501 if (gtk_tree_view_get_path_at_pos(treeview,
502 event->x, event->y, &path, NULL, NULL, NULL)) {
504 * Save this path in case we open the longpress menu to
505 * set the cursor in the treeview to the correct row.
507 * See on_node_menu_show() on how this is further used.
509 mainview->node_list_longpress_path = path;
512 mainview->can_show_node_view = TRUE;
514 return FALSE;
517 void callback_treeview_celldatafunc(GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data)
519 MainView *mainview = ( MainView * ) data;
520 g_assert(mainview != NULL && mainview->data != NULL );
522 nodeData *nd;
524 gtk_tree_model_get(tree_model, iter, NODE_DATA, &nd, -1);
525 if (nd == NULL)
526 return;
528 if (nd->namepix == NULL)
530 g_object_set(cell, "visible", FALSE, NULL);
532 else
534 g_object_set(cell, "visible", TRUE, NULL);
535 g_object_set(cell, "width", SKETCHNODE_RX, NULL);
536 g_object_set(cell, "height", SKETCHNODE_RY, NULL);
541 gboolean callback_treeview_testcollapse(GtkTreeView * treeview, GtkTreeIter * arg1, GtkTreePath * arg2, gpointer user_data)
543 return (FALSE);
546 void callback_treeview_change(GtkTreeSelection * selection, gpointer data)
548 MainView *mainview = (MainView *) data;
549 g_assert(mainview != NULL && mainview->data != NULL);
551 nodeData *nd = getSelectedNode(mainview);
553 gchar* nodeName = _("View node");
555 if (nd != NULL && nd->name != NULL) {
556 nodeName = nd->name;
559 /* Show node view with selected node */
560 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view),
561 nodeName);
563 if (mainview->can_show_node_view) {
564 gtk_widget_show(GTK_WIDGET(mainview->data->node_view));
567 /* Make sure we don't accidentally collapse any nodes */
568 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
570 #ifdef NEW_SEL_LOGIC
571 guint tm=time(NULL);
572 if (mainview->cansel_time>0 && mainview->cansel_time+1.0<tm) mainview->cansel_node=NULL;
574 if (nd==NULL)
576 if (mainview->cansel_node!=NULL)
578 maepad_debug("[SELLOGIC] saving %d to unselect all nodes", (mainview->cansel_node)->sql3id);
579 saveDataToNode(mainview, (mainview->cansel_node));
580 mainview->cansel_node=NULL;
582 return;
585 if (mainview->cansel_node!=NULL)
587 if (nd->sql3id == (mainview->cansel_node)->sql3id)
589 mainview->cansel_node=NULL;
590 maepad_debug("[SELLOGIC] doubly selected %d, doing nothing", nd->sql3id);
591 prepareUIforNodeChange(mainview, nd->typ);
592 return;
594 else
596 maepad_debug("[SELLOGIC] saving %d to load new node", (mainview->cansel_node)->sql3id);
597 saveDataToNode(mainview, (mainview->cansel_node));
598 mainview->cansel_node=NULL;
601 #endif
603 if (nd == NULL) return;
605 busy_enter(mainview);
607 gboolean goterr = TRUE;
608 char *textdata = NULL;
609 char *blob = NULL;
610 int blobsize = 0, textsize = 0;
612 char tq[512];
614 g_snprintf(tq, sizeof(tq), "SELECT bodytype, body, bodyblob, flags FROM %s WHERE nodeid=%d", datatable_tmpname, nd->sql3id);
615 sqlite3_stmt *stmt = NULL;
616 const char *dum;
617 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
619 if (rc)
621 maepad_warning("Error reading (1): %s", sqlite3_errmsg(mainview->db));
623 else
625 rc = SQLITE_BUSY;
626 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
628 rc = sqlite3_step(stmt);
629 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
630 break;
631 else if (rc == SQLITE_ROW)
633 nd->typ = sqlite3_column_int(stmt, 0);
634 nd->flags = sqlite3_column_int(stmt, 3);
636 prepareUIforNodeChange(mainview, nd->typ);
637 if (nd->typ == NODE_TEXT)
639 gboolean file_edited_backup = mainview->file_edited;
641 blobsize = sqlite3_column_bytes(stmt, 2);
642 blob = (char *)sqlite3_column_blob(stmt, 2);
644 textdata = (char *)sqlite3_column_text(stmt, 1);
645 textsize = sqlite3_column_bytes(stmt, 1);
647 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);*/
648 wp_text_buffer_reset_buffer(mainview->buffer, TRUE);
650 gboolean richtext=FALSE;
652 if (blob != NULL)
654 #if 0
655 gboolean oldway=FALSE;
656 if (blobsize>8)
658 char tst[8];
659 strncpy(tst, blob, 8);
660 tst[8]=0;
661 if (strcmp(tst, "RICHTEXT")==0) oldway=TRUE;
663 if (oldway)
665 GError *err = NULL;
666 GtkTextIter iter;
667 gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(mainview->buffer), &iter);
668 gtk_text_buffer_deserialize_rich_text(GTK_TEXT_BUFFER(mainview->buffer), &iter, blob, blobsize, TRUE, &err);
669 if (err != NULL)
671 g_error_free(err);
673 else
675 richtext=TRUE;
678 #endif
680 if (richtext==FALSE)
682 wp_text_buffer_load_document_begin(mainview->buffer, TRUE);
683 wp_text_buffer_load_document_write(mainview->buffer, blob, blobsize);
684 wp_text_buffer_load_document_end(mainview->buffer);
685 richtext=TRUE;
688 if (richtext==FALSE && !(textdata == NULL || g_utf8_validate(textdata, textsize, NULL) == FALSE))
690 /* gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), textdata, textsize);*/
691 wp_text_buffer_load_document_begin(mainview->buffer, FALSE);
692 wp_text_buffer_load_document_write(mainview->buffer, textdata, textsize);
693 wp_text_buffer_load_document_end(mainview->buffer);
696 wp_text_buffer_enable_rich_text(mainview->buffer, TRUE);
697 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap),
698 (nd->flags & NODEFLAG_WORDWRAP)?(TRUE):(FALSE));
700 gtk_text_buffer_set_modified(GTK_TEXT_BUFFER(mainview->buffer), FALSE); /*we probably don't need this*/
702 callback_undotoggle((gpointer)mainview->buffer, FALSE, mainview); /*we need these*/
703 callback_redotoggle((gpointer)mainview->buffer, FALSE, mainview);
705 if (file_edited_backup==FALSE) mainview->file_edited=FALSE; /*textview changed event toggles this?*/
706 goterr = FALSE;
708 else if (nd->typ == NODE_SKETCH)
710 sketchwidget_wipe_undo(mainview->sk);
712 /* Disable squared and filled mode when opening a sketch */
713 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_square), FALSE);
714 hildon_check_button_set_active(HILDON_CHECK_BUTTON(mainview->menu_button_filled), FALSE);
716 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[1]), TRUE);
717 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->shapemenuitems[0]), TRUE);
719 blobsize = sqlite3_column_bytes(stmt, 2);
720 blob = (char *)sqlite3_column_blob(stmt, 2);
721 gboolean clear = TRUE;
723 if (blob == NULL)
724 goterr = FALSE;
725 if (blob != NULL)
727 maepad_debug("blob size: %d", blobsize);
728 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
729 GError *err = NULL;
731 gdk_pixbuf_loader_write(pl, (guchar *) blob, blobsize, &err);
732 if (err != NULL)
734 maepad_warning("Error loading sketch: %s", err->message);
735 g_error_free(err);
736 err = NULL;
738 gdk_pixbuf_loader_close(pl, NULL);
739 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
741 if (GDK_IS_PIXBUF(pixbuf))
743 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
744 GtkPixmap *skpix = (GtkPixmap *) sketchwidget_get_Pixmap(mainview->sk);
746 int w=gdk_pixbuf_get_width(pixbuf);
747 int h=gdk_pixbuf_get_height(pixbuf);
748 if (w!=skdr->allocation.width || h!=skdr->allocation.height)
750 if (w>skdr->allocation.width) w=skdr->allocation.width;
751 if (h>skdr->allocation.height) h=skdr->allocation.height;
752 sketchwidget_clear_real(mainview->sk);
754 gdk_draw_pixbuf(GDK_DRAWABLE(skpix), NULL, pixbuf, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0);
756 clear = FALSE;
757 goterr = FALSE;
759 if (skpix && G_IS_OBJECT(skpix)) g_object_unref(skpix);
761 else
763 maepad_warning("Error loading pixbuf");
765 g_object_unref(pl);
767 if (clear == TRUE)
769 maepad_message("Clearing sketch widget");
770 sketchwidget_clear_real(mainview->sk);
772 gtk_widget_queue_draw(sketchwidget_get_drawingarea(mainview->sk));
774 else if (nd->typ == NODE_CHECKLIST)
776 mainview->checklist_edited = FALSE;
777 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
778 g_object_ref(model);
779 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), NULL);
780 gtk_list_store_clear(GTK_LIST_STORE(model));
782 g_snprintf(tq, sizeof(tq), "SELECT name, style, color FROM %s WHERE nodeid=%d ORDER BY ord, idx", checklisttable_tmpname, nd->sql3id);
783 sqlite3_stmt *stmt2 = NULL;
784 const char *dum;
785 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt2, &dum);
786 if (rc)
788 maepad_warning("Error reading checklist (1) %s", sqlite3_errmsg(mainview->db));
790 else
792 goterr=FALSE;
793 rc = SQLITE_BUSY;
794 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
796 rc = sqlite3_step(stmt2);
797 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
798 break;
799 else if (rc == SQLITE_ROW)
801 char *textdata = (char *)sqlite3_column_text(stmt2, 0);
802 int style = sqlite3_column_int(stmt2, 1);
803 unsigned long col = sqlite3_column_int(stmt2, 2);
805 GtkTreeIter toplevel;
806 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
807 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_TEXT, textdata, CHECKNODE_CHECKED, FALSE, -1);
808 if ((style & CHECKSTYLE_CHECKED)>0) {
809 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, TRUE, -1);
810 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
812 if ((style & CHECKSTYLE_BOLD)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_BOLD, PANGO_WEIGHT_BOLD, -1);
813 if ((style & CHECKSTYLE_STRIKE)>0) gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_STRIKE, TRUE, -1);
815 if (col>0)
817 char tmp[10];
818 g_snprintf(tmp, sizeof(tmp), "#%02lx%02lx%02lx", ((col & 0xFF0000) >> 16), ((col & 0xFF00) >> 8), (col & 0xFF));
819 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_COLOR, tmp, -1);
824 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
826 maepad_warning("Error reading checklist (2): %s", sqlite3_errmsg(mainview->db));
827 goterr=TRUE;
830 sqlite3_finalize(stmt2);
833 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), model);
834 g_object_unref(model);
837 if ((nd->flags & NODEFLAG_SKETCHLINES) > 0)
838 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[1]), TRUE);
839 else if ((nd->flags & NODEFLAG_SKETCHGRAPH) > 0)
840 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[2]), TRUE);
841 else
843 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->sketchlinesmenuitems[0]), TRUE);
844 callback_sketchlines(NULL, mainview->sketchlinesmenuitems[0]); /*FIXME:ugly */
846 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure), TRUE);
848 break;
851 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
852 maepad_warning("Error reading (2): %s", sqlite3_errmsg(mainview->db));
855 sqlite3_finalize(stmt);
858 busy_leave(mainview);
860 /* Show / hide the sketch-related menu widgets */
861 if (nd->typ == NODE_SKETCH) {
862 gtk_widget_show(mainview->menu_button_square);
863 gtk_widget_show(mainview->menu_button_filled);
864 } else {
865 gtk_widget_hide(mainview->menu_button_square);
866 gtk_widget_hide(mainview->menu_button_filled);
869 /* Show/hide the rich text-related menu widgets */
870 if (nd->typ == NODE_TEXT) {
871 gtk_widget_show(mainview->menu_button_wordwrap);
872 } else {
873 gtk_widget_hide(mainview->menu_button_wordwrap);
876 if (goterr == TRUE)
878 show_banner(mainview, _("Error loading memo"));
882 gboolean treeview_canselect(GtkTreeSelection * selection, GtkTreeModel * model, GtkTreePath * path, gboolean path_currently_selected, gpointer userdata)
884 MainView *mainview = (MainView *) userdata;
885 g_assert(mainview != NULL && mainview->data != NULL);
887 if (mainview->loading==FALSE)
889 #ifndef EXPANDING_ROWS
890 if (path_currently_selected)
891 return (FALSE);
892 #endif
894 #ifndef NEW_SEL_LOGIC
895 saveCurrentData(mainview);
896 #else
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);
905 #endif
907 return (TRUE);
910 gboolean newnodedlg_key_press_cb(GtkWidget * widget, GdkEventKey * event, GtkWidget * dlg)
912 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dlg), "sk");
914 switch (event->keyval)
916 case GDK_F7:
917 sketchwidget_redo(s);
918 return TRUE;
919 case GDK_F8:
920 sketchwidget_undo(s);
921 return TRUE;
923 return FALSE;
927 /* This struct will hold all our toggle buttons, so we can
928 * only allow one to be active at a time (i.e. radio buttons) */
929 typedef struct _newNodeToggleButtons newNodeToggleButtons;
930 struct _newNodeToggleButtons
932 GtkWidget *rbt; /* Text */
933 GtkWidget *rbs; /* Sketch */
934 GtkWidget *rbc; /* Checklist */
937 void show_sketch_widget(GtkWidget *widget, gpointer user_data)
939 GtkWidget *dialog = (GtkWidget*)user_data;
941 /* Show the sketch widget and hide the entry + draw button */
942 gtk_widget_show(gtk_object_get_data(GTK_OBJECT(dialog), "al"));
943 gtk_widget_hide(gtk_object_get_data(GTK_OBJECT(dialog), "draw_button"));
944 gtk_widget_hide(gtk_object_get_user_data(GTK_OBJECT(dialog)));
947 void new_node_dialog(nodeType typ, MainView * mainview)
949 GtkWidget *dialog, *entry, *but_ok, *vbox, *hbox, *al, *cb;
950 GtkWidget *rb1, *rb2, *rb3;
951 GtkWidget *hb;
952 gchar datetime_str[200];
953 time_t t_now;
954 struct tm *tm_now;
955 gboolean datetime_written = FALSE;
957 t_now = time(NULL);
958 tm_now = localtime(&t_now);
960 if (tm_now != NULL) {
961 if (strftime(datetime_str, sizeof(datetime_str), "%y-%m-%d %H:%M", tm_now) != 0) {
962 datetime_written = TRUE;
966 if (datetime_written == FALSE) {
967 /* Was not able to determine a datetime string - use default */
968 maepad_warning("Cannot determine current time");
969 strncpy(datetime_str, _("New memo"), sizeof(datetime_str));
970 datetime_str[sizeof(datetime_str)-1] = '\0';
973 newNodeToggleButtons *nntb = g_malloc(sizeof(newNodeToggleButtons));
975 dialog = gtk_dialog_new();
976 gtk_window_set_title(GTK_WINDOW(dialog), _("Create new memo"));
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), _("Create"), GTK_RESPONSE_OK);
1025 g_signal_connect(G_OBJECT(but_ok), "clicked", G_CALLBACK(callback_new_node_real), dialog);
1027 gtk_object_set_data(GTK_OBJECT(dialog), "m", mainview);
1029 hb = gtk_hbox_new(FALSE, 10);
1030 gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("Name:")), FALSE, FALSE, 0);
1031 entry = hildon_entry_new(HILDON_SIZE_AUTO);
1032 gtk_object_set_user_data(GTK_OBJECT(dialog), entry);
1033 gtk_entry_set_text(GTK_ENTRY(entry), datetime_str);
1034 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1035 gtk_box_pack_start(GTK_BOX(hb), entry, TRUE, TRUE, 0);
1037 /* Sketch widget, hidden by default */
1038 al = gtk_alignment_new(0.5, 0.5, 0, 0);
1039 SketchWidget *s = sketchwidget_new(SKETCHNODE_X, SKETCHNODE_Y, TRUE);
1040 gtk_object_set_data(GTK_OBJECT(dialog), "sk", s);
1041 gtk_object_set_data(GTK_OBJECT(dialog), "al", al);
1042 sketchwidget_set_brushsize(s, 2);
1043 sketchwidget_set_backstyle(s, SKETCHBACK_GRAPH);
1044 gtk_widget_set_size_request(sketchwidget_get_mainwidget(s), SKETCHNODE_X, SKETCHNODE_Y);
1045 gtk_container_add(GTK_CONTAINER(al), sketchwidget_get_mainwidget(s));
1046 gtk_box_pack_start(GTK_BOX(hb), al, FALSE, FALSE, 0);
1048 /*but_sketch = hildon_button_new_with_text(
1049 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
1050 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
1051 _("Use sketch label"), NULL);
1053 gtk_object_set_data(GTK_OBJECT(dialog), "draw_button", but_sketch);
1054 gtk_signal_connect(GTK_OBJECT(but_sketch), "clicked", G_CALLBACK(show_sketch_widget), dialog);
1055 gtk_box_pack_start(GTK_BOX(hb), but_sketch, FALSE, TRUE, 0);*/
1056 gtk_box_pack_start(GTK_BOX(vbox), hb, TRUE, FALSE, 0);
1058 cb = hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1059 gtk_button_set_label(GTK_BUTTON(cb), _("Create as child of selected memo"));
1060 hildon_check_button_set_active(HILDON_CHECK_BUTTON(cb), mainview->newnodedialog_createchild);
1061 gtk_box_pack_start(GTK_BOX(vbox), cb, FALSE, FALSE, 0);
1063 gtk_object_set_data(GTK_OBJECT(dialog), "cb", cb);
1065 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
1067 gtk_widget_grab_focus(entry);
1069 gtk_widget_show_all(dialog);
1071 /* Hide the sketch widget at first */
1072 gtk_widget_hide(al);
1073 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1076 void add_new_node(nodeData * node, MainView * mainview, gboolean ischild)
1078 GtkTreeIter parentiter, newiter;
1079 GtkTreeModel *model;
1080 void *ptr = NULL;
1082 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1084 if (gtk_tree_selection_get_selected(selection, &model, &parentiter))
1085 ptr = &parentiter;
1087 GtkTreePath *path = NULL;
1089 unsigned int parentnodeid = 0;
1091 if (ptr != NULL)
1093 path = gtk_tree_model_get_path(model, &parentiter);
1095 if (ischild == FALSE)
1097 gtk_tree_path_up(path);
1099 if (gtk_tree_path_get_depth(path) == 0)
1101 /* Selected node is a root node */
1102 ptr = NULL; /* New node can not have a Parent node */
1103 gtk_tree_path_down(path); /*restore path so expand() works */
1105 else if (gtk_tree_path_get_depth(path) > 0)
1107 /* Selected node is a child node */
1108 if (gtk_tree_model_get_iter(model, &parentiter, path))
1109 ptr = &parentiter;
1114 if (ptr != NULL)
1116 nodeData *nd;
1118 gtk_tree_model_get(model, ptr, NODE_DATA, &nd, -1);
1119 if (nd)
1120 parentnodeid = nd->sql3id;
1123 node->sql3id = 0;
1126 sqlite3_stmt *stmt = NULL;
1127 const char *dum;
1128 char tq[512];
1131 * FIXME: ord
1133 g_snprintf(tq, sizeof(tq), "INSERT INTO %s (parent, bodytype, name, nameblob, ord) VALUES (%d, %d, ?, ?, 0);", datatable_tmpname, parentnodeid, node->typ);
1134 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1136 if (rc)
1138 maepad_warning("Error inserting (1): %s", sqlite3_errmsg(mainview->db));
1139 break;
1141 if (node->name != NULL)
1142 sqlite3_bind_text(stmt, 1, node->name, strlen(node->name), SQLITE_TRANSIENT);
1143 else
1144 sqlite3_bind_text(stmt, 1, NULL, 0, SQLITE_TRANSIENT);
1146 if (node->namepix != NULL)
1148 gchar *namepixdata = NULL;
1149 gsize datalen = 0;
1151 GError *err = NULL;
1153 if (gdk_pixbuf_save_to_buffer(node->namepix, &namepixdata, &datalen, "png", &err, NULL) == FALSE)
1155 namepixdata = NULL;
1156 datalen = 0;
1157 maepad_warning("Error saving name: %s", err->message);
1158 g_error_free(err);
1160 sqlite3_bind_blob(stmt, 2, namepixdata, datalen, SQLITE_TRANSIENT);
1162 else
1163 sqlite3_bind_blob(stmt, 2, NULL, 0, SQLITE_TRANSIENT);
1165 rc = SQLITE_BUSY;
1166 while(rc == SQLITE_BUSY)
1168 rc = sqlite3_step(stmt);
1169 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1170 break;
1172 sqlite3_finalize(stmt);
1173 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
1175 maepad_warning("Error inserting (2): %s", sqlite3_errmsg(mainview->db));
1176 break;
1178 node->sql3id = sqlite3_last_insert_rowid(mainview->db);
1180 while(FALSE);
1182 if (node->sql3id == 0)
1184 if (node->name)
1185 g_free(node->name);
1186 if (node->namepix)
1187 g_object_unref(node->namepix);
1188 g_free(node);
1189 if (path)
1190 gtk_tree_path_free(path);
1191 show_banner(mainview, _("Error creating node"));
1192 return;
1195 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, ptr);
1197 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1199 if (path)
1201 mainview->loading=TRUE; /*only when we have a valid parent*/
1202 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);
1203 gtk_tree_path_free(path);
1206 gtk_tree_selection_select_iter(selection, &newiter);
1208 mainview->loading=FALSE;
1211 void callback_new_node_real(GtkAction * action, gpointer data)
1213 MainView *mainview;
1215 GtkWidget *dialog = data;
1216 GtkWidget *entry = gtk_object_get_user_data(GTK_OBJECT(dialog));
1218 mainview = gtk_object_get_data(GTK_OBJECT(dialog), "m");
1219 SketchWidget *s = gtk_object_get_data(GTK_OBJECT(dialog), "sk");
1220 GtkWidget *cb = gtk_object_get_data(GTK_OBJECT(dialog), "cb");
1221 newNodeToggleButtons *nntb = gtk_object_get_data(GTK_OBJECT(dialog), "nntb");
1223 nodeType typ = NODE_TEXT;
1224 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbs))) {
1225 typ = NODE_SKETCH;
1226 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nntb->rbc))) {
1227 typ = NODE_CHECKLIST;
1229 g_free(nntb);
1231 gchar *txt = NULL;
1233 /*if (GTK_WIDGET_VISIBLE(entry))
1235 txt = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1236 if (strcmp(txt, "") == 0)
1238 g_free(txt);
1239 return;
1242 else
1244 GtkWidget *sdr = sketchwidget_get_drawingarea(s);
1246 GdkPixmap *spix = sketchwidget_get_Pixmap(s);
1248 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(spix), NULL, 0, 0, 0, 0, sdr->allocation.width, sdr->allocation.height);
1249 g_object_unref(spix);
1250 double w, h;
1251 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf, SKETCHNODE_X, SKETCHNODE_Y, &w,
1252 &h, TRUE);
1253 if (pixbuf2==NULL) return;
1255 GdkPixbuf *pixbuf3 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, SKETCHNODE_RX,
1256 SKETCHNODE_RY);
1258 gdk_pixbuf_fill(pixbuf3, 0xffffffff);
1260 if (w <= SKETCHNODE_RX && h <= SKETCHNODE_RY)
1262 gdk_pixbuf_copy_area(pixbuf2, 0, 0, w, h, pixbuf3, 0, (SKETCHNODE_RY - h) / 2);
1264 else
1266 double neww, newh;
1268 if (w > h)
1270 neww = SKETCHNODE_RX;
1271 newh = (h / w) * SKETCHNODE_RX;
1273 else
1275 newh = SKETCHNODE_RY;
1276 neww = (w / h) * SKETCHNODE_RY;
1278 if (newh > SKETCHNODE_RY)
1279 newh = SKETCHNODE_RY;
1281 GdkPixbuf *tmpbuf = gdk_pixbuf_scale_simple(pixbuf2, neww, newh,
1282 GDK_INTERP_BILINEAR);
1284 gdk_pixbuf_copy_area(tmpbuf, 0, 0, neww, newh, pixbuf3, 0, (SKETCHNODE_RY - newh) / 2);
1286 gdk_pixbuf_unref(tmpbuf);
1289 pixbuf = pixbuf3;
1290 gdk_pixbuf_unref(pixbuf2);
1293 nodeData *node;
1295 node = g_malloc(sizeof(nodeData));
1296 node->typ = typ;
1297 node->name = txt;
1298 node->namepix = NULL;
1300 /*if (GTK_WIDGET_VISIBLE(entry))
1302 node->name = txt;
1304 else
1306 node->namepix = pixbuf;
1309 node->lastMod = 0;
1310 node->flags = 0;
1311 node->sql3id = 0;
1313 mainview->newnodedialog_createchild = hildon_check_button_get_active(HILDON_CHECK_BUTTON(cb));
1314 add_new_node(node, mainview, mainview->newnodedialog_createchild);
1316 sketchwidget_destroy(s);
1317 gtk_widget_destroy(dialog);
1318 mainview->file_edited = TRUE;
1322 * delete node
1324 void callback_file_delete_node(GtkAction * action, gpointer data)
1326 MainView *mainview = (MainView *) data;
1327 g_assert(mainview != NULL && mainview->data != NULL);
1329 if (getSelectedNode(mainview) == NULL) {
1330 show_banner(mainview, _("Select a node first"));
1331 return;
1334 if (show_confirmation(mainview, _("Delete selected memo?"))) {
1335 mainview->can_show_node_view = FALSE;
1336 callback_delete_node_real(mainview);
1337 gtk_widget_hide(GTK_WIDGET(mainview->data->node_view));
1342 * Callback for Rename Menuitem
1344 void callback_file_rename_node(GtkAction * action, gpointer data)
1346 MainView *mainview = (MainView*)data;
1347 g_assert(mainview != NULL && mainview->data != NULL);
1349 /* Get the selected node */
1350 nodeData *sel_node = getSelectedNode(mainview);
1351 if (sel_node == NULL) {
1352 /* Do nothing, if no node has been selected */
1353 show_banner(mainview, _("Select a node first"));
1354 return;
1357 if (sel_node->namepix != NULL) {
1358 /* the memo has a graphical label, cannot edit! */
1359 show_banner(mainview, _("Cannot rename memos with sketch name"));
1360 return;
1363 gchar* new_name = show_line_edit_dialog(mainview, _("Rename memo"), _("New name:"), _("Rename"), sel_node->name);
1365 /* Only rename node when user accepted the new name */
1366 if (new_name != NULL) {
1367 callback_rename_node_real(mainview, new_name);
1368 g_free(new_name);
1372 void callback_rename_node_real(MainView* mainview, gchar* new_name)
1374 GtkTreeIter iter;
1375 GtkTreeModel *model;
1376 nodeData *nd = NULL;
1378 /* Get the selected node */
1379 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1381 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1382 return;
1385 gtk_tree_model_get (model, &iter, NODE_DATA, &nd, -1);
1387 if (nd == NULL) {
1388 return;
1391 /* Update the database */
1392 sqlite3_stmt *stmt = NULL;
1394 char* sql = sqlite3_mprintf("UPDATE %s SET name='%q' WHERE nodeid=%d", datatable_tmpname, new_name, nd->sql3id);
1396 int rc = sqlite3_prepare(mainview->db, sql, strlen(sql), &stmt, NULL);
1397 if (rc == SQLITE_OK) {
1398 rc = SQLITE_BUSY;
1399 while (rc == SQLITE_BUSY) {
1400 rc = sqlite3_step(stmt);
1401 if (rc == SQLITE_DONE) {
1402 /* Update in the database was successful - now update the rest */
1404 /* Update the noteData */
1405 g_free(nd->name);
1406 nd->name = g_strdup(new_name);
1408 /* Update the window title of node_view */
1409 gtk_window_set_title(GTK_WINDOW(mainview->data->node_view), nd->name);
1411 /* Update the value in the tree store */
1412 gtk_tree_store_set (GTK_TREE_STORE(model), &iter, NODE_NAME, new_name, -1);
1414 break;
1415 } else if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) {
1416 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1417 break;
1420 sqlite3_finalize(stmt);
1421 } else {
1422 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1425 sqlite3_free(sql);
1427 mainview->file_edited = TRUE;
1430 void callback_file_export_node(GtkAction * action, gpointer data)
1432 MainView *mainview = (MainView *) data;
1433 g_assert(mainview != NULL && mainview->data != NULL);
1435 nodeData *nd=getSelectedNode(mainview);
1436 if (nd == NULL)
1438 show_banner(mainview, _("Select a memo first"));
1439 return;
1442 gchar *nodename=nd->name;
1443 if (nodename==NULL) nodename=_("saved memo");
1445 if (nd->typ == NODE_TEXT)
1448 GtkTextIter begin, end;
1449 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER(mainview->buffer), &begin, &end);
1450 gchar *text = gtk_text_buffer_get_slice(GTK_TEXT_BUFFER(mainview->buffer), &begin, &end, TRUE);
1452 GString *gstr=g_string_sized_new(4096);
1453 wp_text_buffer_save_document(mainview->buffer, (WPDocumentSaveCallback)(wp_savecallback), gstr);
1454 gint textlen=gstr->len;
1455 gchar *text=g_string_free(gstr, FALSE);
1457 if (text==NULL || !strcmp(text, ""))
1459 show_banner(mainview, _("Memo is empty"));
1461 else
1463 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "html");
1464 if (fn!=NULL)
1466 GnomeVFSResult vfs_result;
1467 GnomeVFSHandle *handle = NULL;
1468 GnomeVFSFileSize out_bytes;
1469 vfs_result = gnome_vfs_create(&handle, fn, GNOME_VFS_OPEN_WRITE, 0, 0600);
1470 if ( vfs_result != GNOME_VFS_OK ) {
1471 show_banner(mainview, _("Export failed"));
1473 else
1475 gnome_vfs_write(handle, text, textlen, &out_bytes);
1476 gnome_vfs_close(handle);
1477 if (out_bytes==strlen(text)) show_banner(mainview, _("Exported"));
1478 else show_banner(mainview, _("Export incomplete"));
1480 g_free(fn);
1483 g_free(text);
1485 else if (nd->typ == NODE_SKETCH)
1487 GdkPixmap *skpix = sketchwidget_get_Pixmap(mainview->sk);
1488 GtkWidget *skdr = sketchwidget_get_drawingarea(mainview->sk);
1489 GdkPixbuf *pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0, skdr->allocation.width, skdr->allocation.height);
1490 if (pixbuf==NULL)
1492 show_banner(mainview, _("Memo is empty"));
1494 else
1496 gchar *fn = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, nodename, "png");
1497 if (fn!=NULL)
1499 if (gdk_pixbuf_save(pixbuf, fn, "png", NULL, NULL)==FALSE)
1501 show_banner(mainview, _("Export failed"));
1503 else
1505 show_banner(mainview, _("Exported"));
1507 g_free(fn);
1510 g_object_unref(skpix);
1512 else if (nd->typ == NODE_CHECKLIST)
1514 show_banner(mainview, _("Export of checklists not possible yet"));
1519 * callback from menu item
1520 * move selected node down (switch node with next sibling), don't change level of node
1522 void callback_move_down_node(GtkAction * action, gpointer data)
1524 GtkTreeIter iter;
1525 GtkTreeModel *model;
1527 MainView *mainview = (MainView *) data;
1528 g_assert(mainview != NULL && mainview->data != NULL);
1530 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1531 gtk_tree_selection_get_selected(selection, &model, &iter);
1533 GtkTreeIter old_iter = iter;/*save pointer to old iter, we will need it during swap nodes*/
1535 if (gtk_tree_model_iter_next(model,&iter)==FALSE)/*get next node*/
1536 return;
1538 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1539 gtk_tree_store_swap(treeStore,&iter,&old_iter);
1541 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1545 * callback from menu item
1546 * move selected node down (switch node with prev sibling), don't change level of node
1548 void callback_move_up_node(GtkAction * action, gpointer data)
1550 GtkTreeIter iter;
1551 GtkTreeModel *model;
1553 MainView *mainview = (MainView *) data;
1554 g_assert(mainview != NULL && mainview->data != NULL);
1556 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1557 gtk_tree_selection_get_selected(selection, &model, &iter);
1559 GtkTreeIter old_iter=iter;/*save pointer to old iter, we will need it during swap nodes*/
1561 if (tree_model_iter_prev(model,&iter)==FALSE)/*get previous node*/
1562 return;
1564 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1565 gtk_tree_store_swap(treeStore,&old_iter,&iter);/*do move*/
1567 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1571 * callback from menu item
1572 * we change level of actual node with direction to top
1574 void callback_move_to_top_level_node(GtkAction * action, gpointer data)
1576 GtkTreeIter iter,new_parent;
1577 GtkTreeIter *p_new_parent;
1578 GtkTreeIter parent;
1579 GtkTreeModel *model;
1581 MainView *mainview = (MainView *) data;
1582 g_assert(mainview != NULL && mainview->data != NULL);
1584 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1585 gtk_tree_selection_get_selected(selection, &model, &iter);
1587 /*at first we need actual parent of selected node*/
1588 if (gtk_tree_model_iter_parent(model,&parent,&iter)==FALSE)
1590 /*if parent of selected node is ROOT we can't go higher*/
1591 return;
1593 /*we need also new parent, it's parent of actual parent*/
1594 if (gtk_tree_model_iter_parent(model,&new_parent,&parent)==FALSE)
1596 /*if our new parent is ROOT we got filled new_parent with invalid value,
1597 so we need set NULL value to p_new_parent (root item)*/
1598 p_new_parent=NULL;
1600 else
1602 p_new_parent=&new_parent;/*we only redirect pointer to treeiter*/
1605 saveCurrentData(mainview);/*we save changes in node befor move*/
1607 /*this move function provide move item with all his children, be careful iter value will change!*/
1608 if (move_node(mainview,p_new_parent,&iter,&parent)==TRUE){
1610 gint id_parent = get_node_id_on_tmp_db(model,p_new_parent);
1611 gint id_node = get_node_id_on_tmp_db(model,&iter);
1612 /*we need also update parent id of moved item*/
1613 char tq[512];
1614 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1615 exec_command_on_db(mainview,tq);
1617 /*select new created iter*/
1618 gtk_tree_selection_select_iter(selection,&iter);
1620 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1625 * callback from menu item
1626 * we change level of actual node with direction to bottom
1627 * previous node will be parent of our actual node
1629 void callback_move_to_bottom_level_node(GtkAction * action, gpointer data)
1631 GtkTreeIter iter;
1632 GtkTreeModel *model;
1634 MainView *mainview = (MainView *) data;
1635 g_assert(mainview != NULL && mainview->data != NULL);
1637 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1638 gtk_tree_selection_get_selected(selection, &model, &iter);
1640 GtkTreeIter move_iter=iter;/*save pointer to old iter*/
1642 /*we try to get previous node*/
1643 if (tree_model_iter_prev(model,&iter)==FALSE)
1644 return;/*if previous node on the same level doesn't exist we will exit*/
1646 saveCurrentData(mainview);/*we save changes in node befor move*/
1648 /*this move function provide move item with all his children, be careful move_iter value will change!*/
1649 if (move_node(mainview,&iter,&move_iter,NULL)==TRUE)
1651 gint id_parent = get_node_id_on_tmp_db(model,&iter);
1652 gint id_node = get_node_id_on_tmp_db(model,&move_iter);
1654 /*we need also update parent id of moved item*/
1655 char tq[512];
1656 g_snprintf (tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE nodeid=%d",datatable_tmpname,id_parent ,id_node);
1657 exec_command_on_db(mainview,tq);
1659 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1660 gtk_tree_view_expand_row(GTK_TREE_VIEW(mainview->treeview), path, FALSE);/*expand parent node*/
1661 gtk_tree_path_free(path);
1663 /*select new created iter*/
1664 gtk_tree_selection_select_iter(selection,&move_iter);
1666 mainview->file_edited = TRUE;/*we have made changes , if required show "save changes?" dialog in future*/
1671 * move item_to_move to new_parent with his children, this function is designed for change level of node
1672 * we copy item_to_move with his children to new position (after item_befor if is not NULL) and then we
1673 * destroy old node with his children, so ! item_to_move is set with new iter, be careful on this!
1675 gboolean move_node(MainView *mainview,GtkTreeIter *new_parent,GtkTreeIter *item_to_move,GtkTreeIter *item_befor)
1677 GtkTreeModel *model;
1679 model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
1680 GtkTreeStore *treeStore = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
1682 nodeData *node;
1683 gtk_tree_model_get(model, item_to_move, NODE_DATA, &node, -1);/*get data from actual iter*/
1684 if (node)
1686 GtkTreeIter new_iter;/*create new iter*/
1687 gtk_tree_store_append(treeStore,&new_iter,new_parent);/*append new iter to new parent*/
1689 if (item_befor!=NULL)
1690 gtk_tree_store_move_after(treeStore,&new_iter,item_befor);/*sometimes we need set position*/
1692 gtk_tree_store_set(treeStore, &new_iter, NODE_NAME, node->name,NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);/*set data from old iter*/
1694 GtkTreeIter child;
1695 while (gtk_tree_model_iter_children(model, &child, item_to_move)==TRUE)/*move all childrens while some exits*/
1697 if (move_node(mainview,&new_iter,&child,NULL)==FALSE)/*use recursion on children*/
1698 return FALSE;
1701 gtk_tree_store_set(treeStore, item_to_move, NODE_DATA, NULL, -1);
1702 gtk_tree_store_remove(treeStore, item_to_move);/*remove node, data need't remove, they are stored in new node*/
1704 /*we need return new value of moved item, so we need assign new_iter to item_to_move*/
1705 /*this code is ugly : new_iter to path and back to item_to_move*/
1706 GtkTreePath *path=gtk_tree_model_get_path(model,&new_iter);
1707 gtk_tree_model_get_iter(model,item_to_move,path);
1708 gtk_tree_path_free(path);
1710 else
1712 fprintf(stderr,"Get data node failed!\n");
1713 return FALSE;
1716 return TRUE;
1720 * simple execute of sql command which is stored in sql_string[]
1722 gboolean exec_command_on_db(MainView *mainview,char sql_string[])
1724 sqlite3_stmt *stmt = NULL;
1725 const char* dum;
1726 gboolean db_query_result = FALSE;
1728 int rc = sqlite3_prepare (mainview->db, sql_string, strlen(sql_string), &stmt, &dum);
1730 if (rc) {
1731 maepad_warning("Error preparing DB update query: %s", sqlite3_errmsg(mainview->db));
1732 return FALSE;
1735 rc = SQLITE_BUSY;
1736 while (rc == SQLITE_BUSY) {
1737 rc = sqlite3_step (stmt);
1738 if (rc == SQLITE_DONE) {
1739 db_query_result = TRUE;
1740 break;
1742 else if(rc == SQLITE_ERROR || rc== SQLITE_MISUSE) {
1743 maepad_warning("Error updating node: %s", sqlite3_errmsg(mainview->db));
1744 break;
1746 sqlite3_finalize(stmt);
1748 return TRUE;
1752 * 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)
1754 gboolean foreach_func_update_ord (GtkTreeModel *model,GtkTreePath *path,GtkTreeIter *iter, MainView *mainview)
1756 nodeData *node;
1757 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1758 /*we need index of node on actual level*/
1759 gint index=get_branch_node_index(path);
1761 /*prepare to execute update command,and exec it*/
1762 char sql_command[512];
1763 g_snprintf (sql_command, sizeof(sql_command), "UPDATE %s SET ord=\"%d\" WHERE nodeid=%d",datatable_tmpname, index, node->sql3id);
1764 exec_command_on_db(mainview,sql_command);
1766 /*we don't want break gtk_tree_model_foreach function,until we call this func on each node - so we return always FALSE*/
1767 return FALSE;
1771 * return id number of iter (id number which is used to identify in sql database of nodes)
1773 int get_node_id_on_tmp_db(GtkTreeModel *model,GtkTreeIter *iter)
1775 if (iter==NULL)
1776 return 0;/*we got ROOT parent here*/
1778 nodeData *node;
1779 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
1780 return node->sql3id;
1784 * get index of node in current branch
1786 gint get_branch_node_index(GtkTreePath *path)
1788 int depth=gtk_tree_path_get_depth(path);
1789 gint *indicies = gtk_tree_path_get_indices(path);
1791 return indicies[depth-1];
1795 * similiar with gtk_tree_model_iter_next (), but opposite
1797 gboolean tree_model_iter_prev(GtkTreeModel *tree_model,GtkTreeIter *iter)
1799 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
1801 if (path==NULL){
1802 fprintf(stderr,"Error: path is null\n");
1803 return FALSE;
1806 if (gtk_tree_path_prev(path)==FALSE)
1807 return FALSE;
1809 gtk_tree_model_get_iter(tree_model, iter,path);
1811 return TRUE;
1814 gboolean ref2iter(GtkTreeModel * model, GtkTreeRowReference * ref, GtkTreeIter * iter)
1816 gboolean res = FALSE;
1817 GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
1819 if (gtk_tree_model_get_iter(model, iter, path))
1821 res = TRUE;
1823 gtk_tree_path_free(path);
1824 return (res);
1827 GtkTreeRowReference *iter2ref(GtkTreeModel * model, GtkTreeIter * iter)
1829 GtkTreeRowReference *ref;
1831 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
1833 ref = gtk_tree_row_reference_new(model, path);
1834 gtk_tree_path_free(path);
1835 return (ref);
1838 void move_nodes_up(GtkTreeModel * model, GtkTreeRowReference * topnode, GtkTreeRowReference * newtop)
1840 GtkTreeIter topiter;
1842 if (ref2iter(model, topnode, &topiter) == FALSE)
1843 return;
1845 GtkTreeIter child;
1847 if (gtk_tree_model_iter_children(model, &child, &topiter))
1849 GtkTreeRowReference *ref;
1850 GList *rr_list = NULL, *node;
1854 ref = iter2ref(model, &child);
1855 rr_list = g_list_append(rr_list, ref);
1857 while(gtk_tree_model_iter_next(model, &child));
1860 * got a reflist for all children
1863 for(node = rr_list; node; node = node->next)
1865 ref = (GtkTreeRowReference *) (node->data);
1866 if (ref2iter(model, ref, &child))
1868 GtkTreeIter newtopiter, newiter;
1869 GtkTreeIter *newtopiterptr;
1871 if (ref2iter(model, newtop, &newtopiter))
1872 newtopiterptr = &newtopiter;
1873 else
1874 newtopiterptr = NULL;
1876 nodeData *node;
1878 gtk_tree_model_get(model, &child, NODE_DATA, &node, -1);
1880 gtk_tree_store_append(GTK_TREE_STORE(model), &newiter, newtopiterptr);
1881 gtk_tree_store_set(GTK_TREE_STORE(model), &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
1883 GtkTreeRowReference *newref = iter2ref(model, &newiter);
1885 move_nodes_up(model, ref, newref);
1886 gtk_tree_row_reference_free(newref);
1888 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
1890 gtk_tree_row_reference_free(ref);
1893 g_list_free(rr_list);
1898 void callback_delete_node_real(MainView* mainview)
1900 GtkTreeIter iter;
1901 GtkTreeModel *model;
1903 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
1905 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1906 return;
1908 nodeData *nd;
1910 gtk_tree_model_get(model, &iter, NODE_DATA, &nd, -1);
1911 if (!nd)
1912 return;
1914 mainview->file_edited = TRUE;
1916 unsigned int sql3id = nd->sql3id;
1918 if (nd->name)
1919 g_free(nd->name);
1922 * g_free(nd->data);
1923 * if (nd->pix) g_object_unref(nd->pix);
1925 g_free(nd);
1927 GtkTreeRowReference *upref = NULL, *ref = NULL;
1929 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1931 ref = gtk_tree_row_reference_new(model, path);
1932 if (gtk_tree_path_up(path))
1933 upref = gtk_tree_row_reference_new(model, path);
1934 gtk_tree_path_free(path);
1936 g_object_ref(model);
1937 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
1939 move_nodes_up(model, ref, upref);
1941 if (ref2iter(model, ref, &iter))
1943 char tq[512];
1945 g_snprintf(tq, sizeof(tq), "SELECT parent FROM %s WHERE nodeid=%d", datatable_tmpname, sql3id);
1946 sqlite3_stmt *stmt = NULL;
1947 const char *dum;
1948 int rc = sqlite3_prepare(mainview->db, tq, strlen(tq), &stmt, &dum);
1949 unsigned int sql3parentid = 0;
1951 if (rc)
1953 maepad_warning("Error finding children for delete: %s", sqlite3_errmsg(mainview->db));
1955 else
1957 rc = SQLITE_BUSY;
1958 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
1960 rc = sqlite3_step(stmt);
1961 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
1962 break;
1963 else if (rc == SQLITE_ROW)
1965 sql3parentid = sqlite3_column_int(stmt, 0);
1966 break;
1969 sqlite3_finalize(stmt);
1971 g_snprintf(tq, sizeof(tq), "UPDATE %s SET parent=%d WHERE parent=%d;", datatable_tmpname, sql3parentid, sql3id);
1972 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1973 maepad_warning("Error moving nodes up one level");
1974 } else
1976 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid=%d;", datatable_tmpname, sql3id);
1977 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1978 maepad_warning("Error deleting node");
1981 /* Delete all checklist items that do not have
1982 * a node anymore (= orphaned checklist items) */
1983 g_snprintf(tq, sizeof(tq), "DELETE FROM %s WHERE nodeid NOT IN (SELECT nodeid FROM %s);", checklisttable_tmpname, datatable_tmpname);
1984 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
1985 maepad_warning("Error deleting orphaned checklist items");
1989 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
1992 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
1993 g_object_unref(model);
1995 gtk_tree_row_reference_free(ref);
1996 gtk_tree_row_reference_free(upref);
1998 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
2002 void callback_edit_clear(GtkAction * action, gpointer data)
2004 MainView *mainview = (MainView *) data;
2005 g_assert(mainview != NULL && mainview->data != NULL);
2006 nodeData *nd = getSelectedNode(mainview);
2008 if (show_confirmation(mainview, _("Remove all contents of this memo?"))) {
2009 switch (nd->typ) {
2010 case NODE_TEXT:
2011 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", 0);
2012 break;
2013 case NODE_SKETCH:
2014 sketchwidget_clear(mainview->sk);
2015 break;
2016 case NODE_CHECKLIST:
2017 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview))));
2018 break;
2019 default:
2020 g_assert_not_reached();
2026 * cut
2028 void callback_edit_cut(GtkAction * action, gpointer data)
2030 MainView *mainview = (MainView *) data;
2031 g_assert(mainview != NULL && mainview->data != NULL);
2033 nodeData *nd = getSelectedNode(mainview);
2035 if (nd->typ == NODE_TEXT)
2036 gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, TRUE);
2037 else if (nd->typ == NODE_SKETCH)
2039 if (sketchwidget_cut(mainview->sk, mainview->clipboard)==FALSE)
2040 show_banner(mainview, _("Error cutting"));
2042 else if (nd->typ == NODE_CHECKLIST)
2043 show_banner(mainview, _("Unimplemented"));
2048 * copy
2050 void callback_edit_copy(GtkAction * action, gpointer data)
2052 MainView *mainview = (MainView *) data;
2053 g_assert(mainview != NULL && mainview->data != NULL);
2055 nodeData *nd = getSelectedNode(mainview);
2057 if (nd->typ == NODE_TEXT)
2058 gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard);
2059 else if (nd->typ == NODE_SKETCH)
2061 if (sketchwidget_copy(mainview->sk, mainview->clipboard)==FALSE)
2062 show_banner(mainview, _("Error copying"));
2064 else if (nd->typ == NODE_CHECKLIST)
2066 /* Copy all selected entries as multiline text (1 line per entry) */
2067 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2068 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2070 gint selected_rows = gtk_tree_selection_count_selected_rows(selection);
2071 GList* l = gtk_tree_selection_get_selected_rows(selection, NULL);
2073 GtkTreeIter iter;
2074 gchar *str_data;
2076 gchar **entries = g_malloc0(sizeof(gchar*)*selected_rows+1);
2077 gint entries_idx = 0;
2079 GList* cur = l;
2080 while(cur) {
2081 GtkTreePath *path = cur->data;
2083 if (gtk_tree_model_get_iter(model, &iter, path)) {
2084 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_TEXT, &(entries[entries_idx++]), -1);
2086 gtk_tree_path_free(path);
2088 cur = cur->next;
2091 g_list_free(l);
2092 str_data = g_strjoinv("\n", entries);
2093 g_strfreev(entries);
2094 gtk_clipboard_set_text(mainview->clipboard, str_data, -1);
2095 g_free(str_data);
2097 str_data = g_strdup_printf(_("Copied %d entries"), selected_rows);
2098 show_banner(mainview, str_data);
2099 g_free(str_data);
2105 * paste
2107 void callback_edit_paste(GtkAction * action, gpointer data)
2109 MainView *mainview = (MainView *) data;
2110 g_assert(mainview != NULL && mainview->data != NULL);
2112 nodeData *nd = getSelectedNode(mainview);
2114 if (nd->typ == NODE_TEXT)
2115 gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(mainview->buffer), mainview->clipboard, NULL, TRUE);
2116 else if (nd->typ == NODE_SKETCH)
2118 if (sketchwidget_paste(mainview->sk, mainview->clipboard)==FALSE)
2119 show_banner(mainview, _("Error pasting"));
2121 else if (nd->typ == NODE_CHECKLIST) {
2122 /* Paste string from clipboard as new item */
2123 callback_checklist_paste(mainview);
2126 mainview->file_edited = TRUE;
2129 gint cb_popup(GtkWidget * widget, GdkEvent * event)
2131 GtkMenu *menu;
2132 GdkEventButton *event_button;
2135 * The "widget" is the menu that was supplied when
2136 * * g_signal_connect_swapped() was called.
2138 menu = GTK_MENU(widget);
2139 event_button = (GdkEventButton *) event;
2140 if (event->type == GDK_BUTTON_PRESS && event_button->button == 3)
2142 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
2143 return TRUE;
2145 return FALSE;
2150 * on_node_menu_show(GtkWidget*, gpointer)
2152 * This is called when the longpress menu is shown in the main
2153 * window. In the Hildon UI mode that we are using, this does
2154 * not automatically select the touched node, so we need to set
2155 * the cursor here so that the functions in the menu operate on
2156 * the node that the user touched (i.e. the expected one).
2158 * The value of mainview->node_list_longpress_path has been set
2159 * by callback_treeview_button_press on the buttn press event.
2161 void
2162 on_node_menu_show(GtkWidget* nodemenu, gpointer user_data)
2164 MainView* mainview = (MainView*)user_data;
2166 if (mainview->node_list_longpress_path != NULL) {
2167 /* Set the cursor, but don't open the node view */
2168 mainview->can_show_node_view = FALSE;
2169 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->treeview),
2170 mainview->node_list_longpress_path, NULL, FALSE);
2172 /* Dispose the path (we don't need it anymore) */
2173 gtk_tree_path_free(mainview->node_list_longpress_path);
2174 mainview->node_list_longpress_path = NULL;
2179 * close
2181 gboolean closefile(MainView * mainview)
2183 saveCurrentData(mainview);
2185 if (mainview->file_edited)
2187 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));
2188 gint answer = gtk_dialog_run(GTK_DIALOG(hn));
2189 gtk_widget_destroy(GTK_WIDGET(hn));
2191 if (answer == CONFRESP_CANCEL)
2192 return (FALSE);
2193 else if (answer == CONFRESP_YES)
2195 if (mainview->file_name == NULL)
2197 mainview->file_name = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2199 write_buffer_to_file(mainview);
2203 if (mainview->db)
2204 sqlite3_close(mainview->db);
2205 mainview->db = NULL;
2206 return (TRUE);
2209 gboolean callback_file_close(GtkAction * action, gpointer data)
2212 MainView *mainview = (MainView *) data;
2213 g_assert(mainview != NULL && mainview->data != NULL);
2214 if (closefile(mainview) == FALSE)
2215 return(FALSE);
2217 gtk_main_quit();
2218 return(TRUE);
2221 void callback_file_new_node(GtkAction * action, gpointer data)
2223 MainView *mainview = (MainView *) data;
2224 g_assert(mainview != NULL && mainview->data != NULL);
2226 nodeType typ = NODE_SKETCH;
2228 nodeData *nd = getSelectedNode(mainview);
2230 if (nd != NULL)
2231 typ = nd->typ;
2233 new_node_dialog(typ, mainview);
2237 * new
2239 void callback_file_new(GtkAction * action, gpointer data)
2241 MainView *mainview = (MainView *) data;
2242 g_assert(mainview != NULL && mainview->data != NULL);
2244 gchar *filename = NULL;
2246 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "memos", "db");
2247 if (filename == NULL) {
2248 return;
2251 if (closefile(mainview) == FALSE) {
2252 return;
2255 new_file(mainview);
2259 busy_enter(mainview);
2261 int rc;
2263 rc = sqlite3_open(filename, &mainview->db);
2264 if (rc)
2266 show_banner(mainview, _("Cannot create database"));
2267 maepad_warning("Can't create database %s: %s", filename, sqlite3_errmsg(mainview->db));
2268 break;
2271 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
2273 char tq[512];
2275 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
2276 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
2278 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
2279 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2281 maepad_warning("Cannot create data table");
2282 show_banner(mainview, _("Error creating data table"));
2283 break;
2286 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
2287 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
2289 maepad_warning("Cannot create checklist table");
2290 show_banner(mainview, _("Error creating checklist table"));
2291 break;
2294 if (mainview->db)
2295 sqlite3_close(mainview->db);
2296 mainview->db = NULL;
2298 mainview->file_name = filename;
2299 mainview->file_edited = FALSE;
2300 read_file_to_buffer(mainview);
2302 /*add a starter memo*/
2303 nodeData *node;
2304 node = g_malloc(sizeof(nodeData));
2305 node->typ = NODE_SKETCH;
2306 node->name = _("My first memo");
2307 node->namepix = NULL;
2308 node->lastMod = 0;
2309 node->flags = 0;
2310 node->sql3id = 0;
2311 add_new_node(node, mainview, TRUE);
2312 /*gtk_paned_set_position(GTK_PANED(mainview->hpaned), 180);*/
2313 write_buffer_to_file(mainview);
2315 }while(FALSE);
2316 busy_reset(mainview);
2319 gboolean reset_ctree(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
2321 nodeData *node;
2323 gtk_tree_model_get(model, iter, NODE_DATA, &node, -1);
2324 if (node)
2326 if (node->name)
2327 g_free(node->name);
2328 if (node->namepix)
2329 g_object_unref(node->namepix);
2330 g_free(node);
2332 gtk_tree_store_set(GTK_TREE_STORE(model), iter, NODE_DATA, NULL, -1);
2334 return (FALSE);
2337 void new_file(MainView * mainview)
2339 busy_enter(mainview);
2341 * clear buffer, filename and free buffer text
2343 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(mainview->buffer), "", -1);
2344 mainview->file_name = NULL;
2345 mainview->file_edited = FALSE;
2346 mainview->newnodedialog_createchild = TRUE;
2348 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
2350 g_object_ref(model);
2351 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
2353 gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) reset_ctree, (gpointer) mainview);
2356 * crashing bastard
2357 * gtk_tree_store_clear(GTK_TREE_STORE(model));
2359 GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
2360 GtkTreeIter iter;
2362 if (gtk_tree_model_get_iter(model, &iter, path))
2366 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2368 while(gtk_tree_store_iter_is_valid(GTK_TREE_STORE(model), &iter));
2370 gtk_tree_path_free(path);
2372 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), model);
2373 g_object_unref(model);
2375 busy_leave(mainview);
2379 * open
2381 void callback_file_open(GtkAction * action, gpointer data)
2383 gchar *filename = NULL;
2384 MainView *mainview = (MainView *) data;
2385 g_assert(mainview != NULL && mainview->data != NULL);
2387 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
2388 if (filename == NULL) {
2389 return;
2392 if (closefile(mainview) == FALSE) {
2393 return;
2396 open_file(filename, mainview);
2397 g_free(filename);
2400 gboolean open_file(gchar * filename, MainView * mainview)
2402 gboolean ret=FALSE;
2404 /* Don't open nodes when opening a file */
2405 mainview->can_show_node_view = FALSE;
2407 busy_enter(mainview);
2409 while(filename != NULL)
2411 struct stat s;
2413 if (stat(filename, &s) == -1) break;
2415 mainview->file_name = g_strdup(filename);
2416 gboolean res = read_file_to_buffer(mainview);
2418 if (res == FALSE)
2420 g_free(mainview->file_name);
2421 mainview->file_name = NULL;
2422 break;
2424 mainview->file_edited = FALSE;
2425 ret=TRUE;
2426 break;
2429 busy_leave(mainview);
2430 return(ret);
2433 void callback_about_link(GtkAboutDialog *about, const gchar *link, gpointer data)
2435 MainView *mainview = (MainView *) data;
2436 g_assert(mainview != NULL && mainview->data != NULL);
2437 osso_rpc_run_with_defaults(mainview->data->osso, "osso_browser", OSSO_BROWSER_OPEN_NEW_WINDOW_REQ, NULL,
2438 DBUS_TYPE_STRING, link, DBUS_TYPE_INVALID);
2441 void callback_about(GtkAction * action, gpointer data)
2443 MainView* mainview = (MainView *)data;
2444 he_about_dialog_present(mainview_get_dialog_parent(mainview),
2445 NULL /* auto-detect app name */,
2446 "maepad",
2447 VERSION,
2448 _("A node-based memory pad for Maemo"),
2449 _("(c) 2010 Thomas Perl"),
2450 "http://thpinfo.com/2010/maepad/",
2451 "https://garage.maemo.org/tracker/?group_id=1291",
2452 "http://thpinfo.com/2010/maepad/donate");
2456 * save
2458 void callback_file_save(GtkAction * action, gpointer data)
2460 gchar *filename = NULL;
2461 MainView *mainview = (MainView *) data;
2462 g_assert(mainview != NULL && mainview->data != NULL);
2465 * check is we had a new file
2467 if (mainview->file_name != NULL)
2469 write_buffer_to_file(mainview);
2471 else
2473 filename = interface_file_chooser(mainview, GTK_FILE_CHOOSER_ACTION_SAVE, "maemopaddata", "db");
2475 * if we got a file name from chooser -> save file
2477 if (filename != NULL)
2479 mainview->file_name = filename;
2480 write_buffer_to_file(mainview);
2481 mainview->file_edited = FALSE;
2486 void callback_shapemenu(GtkAction * action, GtkWidget * wid)
2488 gint style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(wid)));
2489 MainView* mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2490 g_assert(mainview != NULL);
2492 if (style >= 0 && style < SKETCHSHAPE_COUNT) {
2493 /* We use the sketch widget's enum for available styles */
2494 sketchwidget_set_shape(mainview->sk, style);
2496 /* Draw the correct indicator for the current shape */
2497 GtkWidget* pix = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(wid), "i"));
2498 g_assert(pix != NULL);
2499 gtk_widget_show(pix);
2500 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->shape_tb), pix);
2501 } else {
2502 /* Fail. We shouldn't get here at all! */
2503 g_error("Invalid style ID from shape menu: %d", style);
2509 void callback_eraser(GtkAction * action, MainView * mainview)
2511 g_assert(mainview != NULL && mainview->data != NULL);
2513 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb))) {
2514 /* Eraser on: Set pen color to white */
2515 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };
2516 sketchwidget_set_brushcolor(mainview->sk, white);
2517 } else {
2518 /* Eraser off: Set default color again (or black) */
2519 GdkColor black = {0, 0, 0, 0};
2520 if (mainview->current_color == NULL) {
2521 mainview->current_color = gdk_color_copy(&black);
2523 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2527 void callback_menu(GtkAction * action, GtkWidget * menu)
2529 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
2532 void callback_brushsizetb(GtkAction * action, MainView *mainview)
2534 g_assert(mainview != NULL && mainview->data != NULL);
2535 callback_menu(NULL, mainview->brushsizemenu);
2538 void callback_brushsize(GtkAction * action, GtkWidget * wid)
2540 int bsize = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2541 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2543 g_assert(mainview != NULL && mainview->data != NULL);
2545 sketchwidget_set_brushsize(mainview->sk, bsize);
2547 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2549 gtk_widget_show(pix);
2550 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->brushsize_tb), pix);
2553 void callback_sketchlines(GtkAction * action, GtkWidget * wid)
2555 int style = (int)gtk_object_get_user_data(GTK_OBJECT(wid));
2556 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2558 g_assert(mainview != NULL);
2560 nodeData *nd = getSelectedNode(mainview);
2561 gboolean doit = FALSE;
2563 if (nd != NULL && nd->typ == NODE_SKETCH)
2565 nd->flags &= ~NODEFLAG_SKETCHLINES;
2566 nd->flags &= ~NODEFLAG_SKETCHGRAPH;
2567 /* sketchwidget_set_edited(mainview->sk, TRUE);*/ /*we call this on openfile, so this messes things up*/
2568 doit = TRUE;
2571 if (style == 0)
2573 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_NONE);
2575 else if (style == 1)
2577 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_LINES);
2578 if (doit == TRUE)
2579 nd->flags |= NODEFLAG_SKETCHLINES;
2581 else if (style == 2)
2583 sketchwidget_set_backstyle(mainview->sk, SKETCHBACK_GRAPH);
2584 if (doit == TRUE)
2585 nd->flags |= NODEFLAG_SKETCHGRAPH;
2588 GtkWidget *pix = gtk_object_get_data(GTK_OBJECT(wid), "i");
2590 gtk_widget_show(pix);
2591 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mainview->sketchlines_tb), pix);
2594 void callback_color(GtkAction* action, MainView* mainview)
2596 g_assert(mainview != NULL && mainview->data != NULL);
2598 nodeData *nd = getSelectedNode(mainview);
2599 if (nd == NULL) return;
2601 HeSimpleColorDialog* dialog = HE_SIMPLE_COLOR_DIALOG(he_simple_color_dialog_new());
2602 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
2604 if (mainview->current_color) {
2605 he_simple_color_dialog_set_color(dialog, mainview->current_color);
2608 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
2609 gtk_widget_destroy(GTK_WIDGET(dialog));
2610 return;
2613 gdk_color_free(mainview->current_color);
2614 mainview->current_color = he_simple_color_dialog_get_color(dialog);
2616 gtk_widget_destroy(GTK_WIDGET(dialog));
2618 switch (nd->typ) {
2619 case NODE_SKETCH:
2620 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->eraser_tb), FALSE);
2621 sketchwidget_set_brushcolor(mainview->sk, *(mainview->current_color));
2622 break;
2623 case NODE_CHECKLIST:
2624 { /* Put in a separate block to allow new local variables */
2625 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2626 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
2627 GList* selected = gtk_tree_selection_get_selected_rows(selection, NULL);
2629 gchar* color_string = g_strdup_printf("#%02x%02x%02x",
2630 mainview->current_color->red >> 8,
2631 mainview->current_color->green >> 8,
2632 mainview->current_color->blue >> 8);
2634 GList* cur = selected;
2635 while (cur != NULL) {
2636 GtkTreePath* path = cur->data;
2637 GtkTreeIter iter;
2638 if (gtk_tree_model_get_iter(model, &iter, path)) {
2639 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_COLOR, color_string, -1);
2641 gtk_tree_path_free(path);
2642 cur = cur->next;
2645 g_list_free(selected);
2646 g_free(color_string);
2648 break;
2649 default:
2650 g_assert_not_reached();
2654 void callback_color_invoke(GtkAction * action, gpointer data)
2656 MainView *mainview = (MainView *) data;
2657 g_assert(mainview != NULL && mainview->data != NULL);
2658 gtk_button_clicked(GTK_BUTTON(mainview->colorbutton_tb));
2663 void callback_pressure(GtkAction * action, MainView *mainview)
2665 g_assert(mainview != NULL && mainview->data != NULL);
2667 nodeData *nd = getSelectedNode(mainview);
2669 if (nd == NULL)
2670 return;
2671 if (nd->typ != NODE_SKETCH)
2672 return;
2674 /* pressure sensitivity disabled for now...
2675 mainview->sk->pressuresensitivity=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mainview->tools_pressure));*/
2679 void callback_wordwrap(GtkWidget* widget, gpointer user_data)
2681 MainView* mainview = (MainView*)user_data;
2682 nodeData* nd = getSelectedNode(mainview);
2683 GtkWrapMode wrap_mode;
2685 if (nd == NULL || nd->typ != NODE_TEXT) {
2686 return;
2689 if (hildon_check_button_get_active(HILDON_CHECK_BUTTON(mainview->menu_button_wordwrap))) {
2690 nd->flags |= NODEFLAG_WORDWRAP;
2691 wrap_mode = GTK_WRAP_WORD_CHAR;
2692 } else {
2693 nd->flags &= ~NODEFLAG_WORDWRAP;
2694 wrap_mode = GTK_WRAP_NONE;
2697 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mainview->textview), wrap_mode);
2701 void callback_font(GtkAction * action, gpointer data)
2703 MainView *mainview = (MainView *) data;
2704 g_assert(mainview != NULL && mainview->data != NULL);
2706 nodeData *nd = getSelectedNode(mainview);
2708 if (nd == NULL)
2709 return;
2710 if (nd->typ != NODE_TEXT)
2711 return;
2713 HildonFontSelectionDialog *dialog = HILDON_FONT_SELECTION_DIALOG(hildon_font_selection_dialog_new(NULL, NULL));
2715 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2716 /*gotsel=FALSE;*/
2718 WPTextBufferFormat fmt;
2719 wp_text_buffer_get_attributes(mainview->buffer, &fmt, gotsel);
2721 gint ri=0;
2722 if (fmt.text_position==TEXT_POSITION_SUPERSCRIPT) ri=1;
2723 else if (fmt.text_position==TEXT_POSITION_SUBSCRIPT) ri=-1;
2725 g_object_set(G_OBJECT(dialog),
2726 "family-set", fmt.cs.font,
2727 "family", wp_get_font_name(fmt.font),
2728 "size-set", fmt.cs.font_size,
2729 "size", wp_font_size[fmt.font_size],
2730 "color-set", fmt.cs.color,
2731 "color", &fmt.color,
2732 "bold-set", fmt.cs.bold,
2733 "bold", fmt.bold,
2734 "italic-set", fmt.cs.italic,
2735 "italic", fmt.italic,
2736 "underline-set", fmt.cs.underline,
2737 "underline", fmt.underline,
2738 "strikethrough-set", fmt.cs.strikethrough,
2739 "strikethrough", fmt.strikethrough,
2740 "position-set", fmt.cs.text_position,
2741 "position", ri,
2742 NULL);
2744 gtk_widget_show_all(GTK_WIDGET(dialog));
2745 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2747 gboolean bold, italic, underline, strikethrough;
2748 gchar *family = NULL;
2749 gint size, position;
2750 GdkColor *color=NULL;
2751 gboolean set_family, set_size, set_bold, set_italic, set_underline, set_strikethrough, set_color, set_position;
2753 g_object_get(G_OBJECT(dialog), "family", &family, "size", &size, "bold", &bold, "italic", &italic,
2754 "underline", &underline, "strikethrough", &strikethrough,
2755 "family-set", &set_family, "size-set", &set_size, "bold-set", &set_bold, "italic-set", &set_italic,
2756 "underline-set", &set_underline, "strikethrough-set", &set_strikethrough,
2757 "color", &color, "color-set", &set_color, "position", &position, "position-set", &set_position,
2758 NULL);
2760 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE);
2761 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;
2763 if (set_family) { fmt.font=wp_get_font_index(family, 1); fmt.cs.font=1; }
2764 if (set_size) { fmt.font_size=wp_get_font_size_index(size, 16); fmt.cs.font_size=1; }
2766 if (set_strikethrough)
2768 fmt.cs.strikethrough=1;
2769 fmt.strikethrough=strikethrough;
2772 if (set_color)
2775 GLIB WARNING ** GLib-GObject - IA__g_object_set_valist: object class `GtkTextTag' has no property named `'
2777 fmt.cs.color=1;
2778 fmt.color.pixel=color->pixel;
2779 fmt.color.red=color->red;
2780 fmt.color.green=color->green;
2781 fmt.color.blue=color->blue;
2784 if (set_position)
2786 if (position==1) ri=TEXT_POSITION_SUPERSCRIPT;
2787 else if (position==-1) ri=TEXT_POSITION_SUBSCRIPT;
2788 else ri=TEXT_POSITION_NORMAL;
2790 fmt.cs.text_position=1;
2791 fmt.text_position=ri;
2794 if (set_bold)
2796 fmt.cs.bold=1;
2797 fmt.bold=bold;
2799 if (set_italic)
2801 fmt.cs.italic=1;
2802 fmt.italic=italic;
2804 if (set_underline)
2806 fmt.cs.underline=1;
2807 fmt.underline=underline;
2810 wp_text_buffer_set_format(mainview->buffer, &fmt);
2813 gtk_widget_destroy(GTK_WIDGET(dialog));
2816 void callback_fontstyle(GtkAction * action, GtkWidget * wid)
2818 MainView *mainview = gtk_object_get_data(GTK_OBJECT(wid), "m");
2819 g_assert(mainview != NULL && mainview->data != NULL);
2821 nodeData *nd = getSelectedNode(mainview);
2823 if (nd == NULL)
2824 return;
2825 if (nd->typ == NODE_TEXT)
2827 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2829 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2830 wp_text_buffer_set_attribute(mainview->buffer, style, (gpointer)act);
2832 else if (nd->typ == NODE_CHECKLIST)
2834 gboolean act=gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(wid));
2835 gint style = (gint)gtk_object_get_data(GTK_OBJECT(wid), "s");
2836 if (style!=WPT_BOLD && style!=WPT_STRIKE && style!=WPT_LEFT) return;
2838 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
2839 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
2841 gint styletoset_weight=PANGO_WEIGHT_NORMAL;
2842 gboolean styletoset_strike=FALSE;
2843 gboolean checkit=FALSE;
2845 if (style==WPT_BOLD && act==TRUE) styletoset_weight=PANGO_WEIGHT_BOLD;
2846 else if (style==WPT_STRIKE && act==TRUE) styletoset_strike=TRUE;
2847 else if (style==WPT_LEFT && act==TRUE) checkit=TRUE;
2849 GList* cur=l;
2850 while(cur)
2852 GtkTreePath *path=cur->data;
2854 GtkTreeIter iter;
2855 if (gtk_tree_model_get_iter(model, &iter, path))
2857 if (style==WPT_BOLD) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_BOLD, styletoset_weight, -1);
2858 else if (style==WPT_STRIKE) gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_STRIKE, styletoset_strike, -1);
2859 else if (style==WPT_LEFT) {
2860 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_CHECKED, checkit, -1);
2861 if (checkit) {
2862 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, "widgets_tickmark_list", -1);
2863 } else {
2864 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_ICON_NAME, NULL, -1);
2868 gtk_tree_path_free(path);
2869 cur=cur->next;
2872 g_list_free(l);
2873 mainview->checklist_edited = TRUE;
2877 void
2878 callback_sharing(GtkWidget* widget, gpointer user_data)
2880 MainView* mainview = (MainView*)user_data;
2881 nodeData* nd = getSelectedNode(mainview);
2882 gchar* filename = g_strdup("/tmp/untitled.png");
2883 gchar* uri = NULL;
2885 if (nd == NULL || nd->typ != NODE_SKETCH) {
2886 show_banner(mainview, _("Only sketches can be shared"));
2887 return;
2890 if (nd->name != NULL) {
2891 g_free(filename);
2892 filename = g_strdup_printf("/tmp/%s.png", nd->name);
2895 busy_enter(mainview);
2896 GdkPixmap* skpix = sketchwidget_get_Pixmap(mainview->sk);
2897 GtkWidget* skdr = sketchwidget_get_drawingarea(mainview->sk);
2898 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL,
2899 GDK_DRAWABLE(skpix), NULL, 0, 0, 0, 0,
2900 skdr->allocation.width, skdr->allocation.height);
2902 if (pixbuf == NULL) {
2903 show_banner(mainview, _("Memo is empty"));
2904 goto cleanup;
2907 if (!gdk_pixbuf_save(pixbuf, filename, "png", NULL, NULL)) {
2908 show_banner(mainview, _("File export failed"));
2909 goto cleanup;
2912 uri = g_strdup_printf("file://%s", filename);
2914 sharing_dialog_with_file(mainview->data->osso,
2915 mainview_get_dialog_parent(mainview),
2916 uri);
2918 cleanup:
2919 g_object_unref(skpix);
2920 g_free(filename);
2921 g_free(uri);
2922 busy_leave(mainview);
2925 void callback_textbuffer_move(WPTextBuffer *textbuffer, MainView *mainview)
2927 g_assert(mainview != NULL && mainview->data != NULL);
2930 gboolean gotsel=wp_text_buffer_has_selection(mainview->buffer);
2932 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), gotsel);
2933 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), gotsel);
2934 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), gotsel);
2935 _toggle_tool_button_set_inconsistent(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), gotsel);
2937 WPTextBufferFormat fmt;
2938 wp_text_buffer_get_attributes(mainview->buffer, &fmt, FALSE/*gotsel*/);
2940 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
2941 g_signal_handlers_block_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
2942 g_signal_handlers_block_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
2943 g_signal_handlers_block_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
2945 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), fmt.bold);
2946 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->italic_tb), fmt.italic);
2947 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->underline_tb), fmt.underline);
2948 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bullet_tb), fmt.bullet);
2950 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
2951 g_signal_handlers_unblock_by_func(mainview->italic_tb, callback_fontstyle, mainview->italic_tb);
2952 g_signal_handlers_unblock_by_func(mainview->underline_tb, callback_fontstyle, mainview->underline_tb);
2953 g_signal_handlers_unblock_by_func(mainview->bullet_tb, callback_fontstyle, mainview->bullet_tb);
2956 gint wp_savecallback(const gchar *buffer, GString * gstr)
2958 gstr=g_string_append(gstr, buffer);
2959 return(0);
2962 void callback_undo(GtkAction * action, MainView * mainview)
2964 g_assert(mainview != NULL && mainview->data != NULL);
2966 nodeData *nd = getSelectedNode(mainview);
2968 if (nd == NULL) return;
2970 if (nd->typ == NODE_SKETCH) sketchwidget_undo(mainview->sk);
2971 else if (nd->typ == NODE_TEXT) wp_text_buffer_undo(mainview->buffer);
2974 void callback_redo(GtkAction * action, MainView * mainview)
2976 g_assert(mainview != NULL && mainview->data != NULL);
2978 nodeData *nd = getSelectedNode(mainview);
2980 if (nd == NULL) return;
2982 if (nd->typ == NODE_SKETCH) sketchwidget_redo(mainview->sk);
2983 else if (nd->typ == NODE_TEXT) wp_text_buffer_redo(mainview->buffer);
2986 void callback_undotoggle(gpointer widget, gboolean st, MainView * mainview)
2988 g_assert(mainview != NULL && mainview->data != NULL);
2990 gtk_widget_set_sensitive(GTK_WIDGET(mainview->undo_tb), st);
2993 void callback_redotoggle(gpointer widget, gboolean st, MainView * mainview)
2995 g_assert(mainview != NULL && mainview->data != NULL);
2997 gtk_widget_set_sensitive(GTK_WIDGET(mainview->redo_tb), st);
3000 gboolean close_cb(GtkWidget * widget, GdkEventAny * event, MainView * mainview)
3002 callback_file_close(NULL, mainview);
3003 return (TRUE);
3006 gboolean
3007 on_main_view_key_press(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
3009 /* Begin special code zone */
3010 #define ER "Port"
3011 #define EA "Nata"
3012 #define _E "man "
3013 #define GG "mode"
3014 #define ST "lie "
3015 MainView* main_view = (MainView*)user_data;
3016 gchar* u = NULL;
3017 guint32 v = event->time;
3018 gchar w = (gchar)event->keyval;
3019 static gchar y[] = {97,0x6d,0151,25<<2,0x61,0xd8>>1,0x61,0xF0&0x0F};
3020 static guint32 x, z;
3022 if (v > z + 3000) { z = 0; x &= 0xF0; }
3024 if ((!z || v < z + 3000) && (w + *(y+x) == w<<1)) {
3025 u = (gchar*)g_get_application_name();
3026 if (!(*(y+(++x)))) {
3027 show_banner(main_view, EA ST ER _E GG " activated");
3028 u = g_strdup_printf("%s%c%c%c", u+x-4, *u, u[1], u[x&~5]);
3029 gtk_window_set_title(GTK_WINDOW(main_view->data->main_view), u);
3030 g_free(u);
3032 z = v;
3033 return FALSE;
3035 #undef ER
3036 #undef EA
3037 #undef _E
3038 #undef GG
3039 #undef ST
3040 x &= ~x;
3041 /* End special code zone */
3043 return FALSE;
3046 gboolean
3047 on_checklist_longpress_timeout(gpointer user_data)
3049 MainView* mainview = (MainView*)user_data;
3050 callback_checklist_edit(NULL, mainview);
3051 mainview->checklist_longpress_source_id = 0;
3052 return FALSE;
3055 gboolean
3056 on_checklist_button_press(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3058 MainView* mainview = (MainView*)user_data;
3059 GtkTreePath* path;
3060 GtkTreeViewColumn* column;
3061 GtkTreeSelection* selection;
3063 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
3064 event->x,
3065 event->y,
3066 &path,
3067 &column,
3068 NULL,
3069 NULL)) {
3070 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
3072 if (gtk_tree_selection_path_is_selected(selection, path)) {
3073 if (column == mainview->checklist_column_check) {
3074 /* Check column touched - toggle checklist item */
3075 maepad_toggle_gtk_toggle_tool_button(mainview->check_tb);
3076 } else if (column == mainview->checklist_column_text) {
3077 mainview->checklist_longpress_source_id = g_timeout_add(
3078 CHECKLIST_LONGPRESS_EDIT_DELAY,
3079 on_checklist_longpress_timeout,
3080 mainview);
3082 return TRUE;
3085 gtk_tree_path_free(path);
3088 return FALSE;
3091 void
3092 checklist_abort_longpress(MainView* mainview)
3094 /* Abort the longpress action on the checklist */
3095 if (mainview->checklist_longpress_source_id != 0) {
3096 g_source_remove(mainview->checklist_longpress_source_id);
3097 mainview->checklist_longpress_source_id = 0;
3101 gboolean
3102 on_checklist_button_release(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
3104 MainView* mainview = (MainView*)user_data;
3105 checklist_abort_longpress(mainview);
3106 return FALSE;
3109 gboolean
3110 on_checklist_start_panning(HildonPannableArea* area, gpointer user_data)
3112 MainView* mainview = (MainView*)user_data;
3113 checklist_abort_longpress(mainview);
3114 return FALSE;
3117 void callback_fullscreen(GtkToolButton* tool_button, gpointer user_data)
3119 MainView* mainview = (MainView*)user_data;
3120 gtk_window_fullscreen(GTK_WINDOW(mainview->data->node_view));
3123 void
3124 callback_sketch_button_toggled(HildonCheckButton* button, gpointer user_data)
3126 MainView* mainview = (MainView*)user_data;
3127 gboolean active = hildon_check_button_get_active(button);
3129 if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_square)) {
3130 sketchwidget_set_shift(mainview->sk, active);
3131 } else if (GTK_WIDGET(button) == GTK_WIDGET(mainview->menu_button_filled)) {
3132 sketchwidget_set_fillmode(mainview->sk, active);
3136 void callback_buffer_modified(GtkAction * action, gpointer data)
3138 MainView *mainview = (MainView *) data;
3139 g_assert(mainview != NULL && mainview->data != NULL);
3141 mainview->file_edited = TRUE;
3144 GtkTreeRowReference *read_sqlite3_data(MainView * mainview, unsigned int parentid, GtkTreeRowReference * parenttree, unsigned int selected, GtkTreeStore * model)
3146 GtkTreeRowReference *resref = NULL;
3148 char q[256];
3150 g_snprintf(q, sizeof(q), "SELECT nodeid, bodytype, name, nameblob, lastmodified, flags FROM %s WHERE parent=%d ORDER BY ord", datatable_tmpname, parentid);
3152 sqlite3_stmt *stmt = NULL;
3153 const char *dum;
3154 int rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3156 if (rc)
3158 maepad_warning("Error reading SQLite3 data: %s", sqlite3_errmsg(mainview->db));
3159 return (NULL);
3162 rc = SQLITE_BUSY;
3163 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3165 rc = sqlite3_step(stmt);
3166 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3167 break;
3168 else if (rc == SQLITE_ROW)
3170 int nodeid = sqlite3_column_int(stmt, 0);
3171 int typ = sqlite3_column_int(stmt, 1);
3172 const unsigned char *name = sqlite3_column_text(stmt, 2);
3173 const unsigned char *nameblob = sqlite3_column_text(stmt, 3);
3174 int lastmod = sqlite3_column_int(stmt, 4);
3175 int flags = sqlite3_column_int(stmt, 5);
3177 if ((typ != NODE_TEXT && typ != NODE_SKETCH && typ != NODE_CHECKLIST) || (name == NULL && nameblob == NULL)) {
3178 maepad_warning("Unknown node type in database: %d (skipping)", typ);
3179 continue;
3182 nodeData *node = g_malloc(sizeof(nodeData));
3184 node->sql3id = nodeid;
3185 node->typ = typ;
3186 node->flags = flags;
3187 node->name = NULL;
3188 node->namepix = NULL;
3189 if (name != NULL) {
3190 node->name = g_strdup((char *)name);
3191 } else {
3192 node->name = g_strdup(_("Unnamed node"));
3194 /*if (nameblob != NULL)
3196 int blobsize = sqlite3_column_bytes(stmt, 3);
3198 GdkPixbufLoader *pl = gdk_pixbuf_loader_new_with_type("png", NULL);
3199 GError *err = NULL;
3201 gdk_pixbuf_loader_write(pl, (guchar *) nameblob, blobsize, &err);
3202 if (err != NULL)
3204 fprintf(stderr, "Error loading nodename! %s\n", err->message);
3205 g_error_free(err);
3206 err = NULL;
3208 gdk_pixbuf_loader_close(pl, NULL);
3209 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(pl);
3211 if (GDK_IS_PIXBUF(pixbuf))
3212 node->namepix = pixbuf;
3214 node->lastMod = lastmod;
3216 GtkTreeIter parentiter, newiter;
3217 void *par = NULL;
3219 if (parenttree != NULL)
3221 GtkTreePath *pa = gtk_tree_row_reference_get_path(parenttree);
3223 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parentiter, pa);
3224 gtk_tree_path_free(pa);
3225 par = &parentiter;
3228 gtk_tree_store_append(model, &newiter, par);
3229 gtk_tree_store_set(model, &newiter, NODE_NAME, node->name, NODE_PIXBUF, node->namepix, NODE_DATA, node, -1);
3231 GtkTreePath *pa = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &newiter);
3233 GtkTreeRowReference *newref = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), pa);
3235 if (selected == nodeid)
3236 resref = newref;
3238 gtk_tree_path_free(pa);
3239 GtkTreeRowReference *r = read_sqlite3_data(mainview, nodeid, newref, selected,
3240 model);
3242 if (resref != newref)
3243 gtk_tree_row_reference_free(newref);
3245 if (r != NULL)
3247 if (resref == NULL)
3248 resref = r;
3249 else
3250 gtk_tree_row_reference_free(r); /*safeguard */
3255 if (stmt)
3256 sqlite3_finalize(stmt);
3258 return (resref); /*ref to supposed-to-be-selected treeitem */
3262 * read file
3264 gboolean read_file_to_buffer(MainView * mainview)
3266 char tq[512];
3268 g_assert(mainview != NULL);
3269 gboolean res = FALSE;
3271 gchar *filename = mainview->file_name;
3273 new_file(mainview);
3274 mainview->file_name = filename;
3275 mainview->loading=TRUE;
3277 maepad_message("Reading database file: %s", filename);
3279 int rc;
3280 sqlite3_stmt *stmt = NULL;
3282 rc = sqlite3_open(filename, &mainview->db);
3285 if (rc)
3287 maepad_warning("Cannot open database %s: %s", filename, sqlite3_errmsg(mainview->db));
3288 break;
3291 sqlite3_exec(mainview->db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
3293 char *q = "SELECT skey, sval FROM settings";
3294 const char *dum;
3296 rc = sqlite3_prepare(mainview->db, q, strlen(q), &stmt, &dum);
3297 if (rc)
3299 maepad_warning("Error reading settings: %s", sqlite3_errmsg(mainview->db));
3300 break;
3303 unsigned int selectedCard = 0;
3304 unsigned int curDataVersion = 0;
3305 unsigned int curChecklistVersion = 0;
3307 rc = SQLITE_BUSY;
3308 while(rc == SQLITE_BUSY || rc == SQLITE_ROW)
3310 rc = sqlite3_step(stmt);
3311 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE || rc == SQLITE_DONE)
3312 break;
3313 else if (rc == SQLITE_ROW)
3315 const gchar* col_key = (const gchar*)sqlite3_column_text(stmt, 0);
3316 const gchar* col_val = (const gchar*)sqlite3_column_text(stmt, 1);
3317 if (!strcmp(col_key, "selectedNode"))
3319 gint tmp = atoi((char *)col_val);
3321 if (tmp > 0)
3322 selectedCard = tmp;
3324 if (!strcmp(col_key, "dataVersion"))
3326 gint tmp = atoi((char *)col_val);
3328 if (tmp > 0)
3329 curDataVersion = tmp;
3331 if (!strcmp(col_key, "checklistVersion"))
3333 gint tmp = atoi((char *)col_val);
3335 if (tmp > 0)
3336 curChecklistVersion = tmp;
3338 if (!strcmp(col_key, "newNodeDlgCreateChild"))
3340 gint tmp = atoi((char *)col_val);
3342 mainview->newnodedialog_createchild = TRUE;
3343 if (tmp == 0)
3344 mainview->newnodedialog_createchild = FALSE;
3346 if (!strcmp(col_key, "brushSize"))
3348 gint tmp = atoi((char *)col_val);
3349 if (tmp>0) sk_set_brushsize(mainview, tmp);
3351 if (!strcmp(col_key, "brushColor"))
3353 unsigned long tmp = atol((char *)col_val);
3354 GdkColor c2;
3356 c2.red = ((tmp & 0xFF0000) >> 16) << 8;
3357 c2.green = ((tmp & 0xFF00) >> 8) << 8;
3358 c2.blue = (tmp & 0xFF) << 8;
3359 sketchwidget_set_brushcolor(mainview->sk, c2);
3361 if (mainview->current_color != NULL) {
3362 gdk_color_free(mainview->current_color);
3364 mainview->current_color = gdk_color_copy(&c2);
3369 if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE)
3371 maepad_warning("Error reading data: %s", sqlite3_errmsg(mainview->db));
3372 break;
3375 if (stmt) {
3376 sqlite3_finalize(stmt);
3377 stmt = NULL;
3380 gboolean resback = FALSE;
3382 while(curDataVersion < datatableversion)
3384 if (curDataVersion == 0)
3386 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3387 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3389 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_name, datatable_backupname);
3390 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3391 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3392 break;
3394 resback = TRUE;
3396 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_name, datatable);
3397 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3398 maepad_warning("Error creating table: %s", datatable_name);
3399 break;
3401 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);
3402 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3403 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_backupname);
3404 break;
3407 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3408 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3410 curDataVersion = datatableversion;
3412 break;
3415 if (curDataVersion != datatableversion)
3417 maepad_warning("Data table version mismatch: %d <=> %d", curDataVersion, datatableversion);
3419 if (resback == TRUE)
3421 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_name);
3422 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3423 g_snprintf(tq, sizeof(tq), "ALTER TABLE %s RENAME TO %s", datatable_backupname, datatable_name);
3424 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3427 break;
3431 while(curChecklistVersion < checklisttableversion)
3433 if (curChecklistVersion == 0) /*no checklisttable at all*/
3435 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_name, checklisttable);
3436 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3437 maepad_warning("Error creating checklist table during schema upgrade");
3438 break;
3440 curChecklistVersion = checklisttableversion;
3442 break;
3446 GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview)));
3448 g_object_ref(model);
3449 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), NULL);
3453 char tq[512];
3455 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, datatable_tmpname, datatable);
3456 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3457 maepad_warning("Error creating temp table: %s", datatable_tmpname);
3458 break;
3460 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", datatable_tmpname, datatable_tmpname, dataindex);
3461 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3462 maepad_warning("Error creating temp index for %s", datatable_tmpname);
3463 break;
3465 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_tmpname, datatable_name);
3466 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3467 maepad_warning("Error copying data from %s to %s", datatable_name, datatable_tmpname);
3468 break;
3471 g_snprintf(tq, sizeof(tq), "CREATE%s TABLE %s%s", TEMPTABLE_KEYWORD, checklisttable_tmpname, checklisttable);
3472 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3473 maepad_warning("Error creating temp table: %s", checklisttable_tmpname);
3474 break;
3476 g_snprintf(tq, sizeof(tq), "CREATE INDEX %s_index ON %s %s", checklisttable_tmpname, checklisttable_tmpname, checklistindex);
3477 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3478 maepad_warning("Error creating temp index for %s", checklisttable_tmpname);
3479 break;
3481 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_tmpname, checklisttable_name);
3482 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3483 maepad_warning("Error copying data from %s to %s", checklisttable_name, checklisttable_tmpname);
3484 break;
3487 while(FALSE);
3489 GtkTreeRowReference *selectedRef = read_sqlite3_data(mainview, 0, NULL, selectedCard, model);
3491 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->treeview), GTK_TREE_MODEL(model));
3492 g_object_unref(model);
3493 gtk_tree_view_expand_all(GTK_TREE_VIEW(mainview->treeview));
3495 if (selectedRef != NULL)
3497 GtkTreeIter seliter;
3499 if (ref2iter(GTK_TREE_MODEL(model), selectedRef, &seliter) == TRUE)
3501 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->treeview));
3502 gtk_tree_selection_select_iter(selection, &seliter);
3505 gtk_tree_row_reference_free(selectedRef);
3507 res = TRUE;
3509 while(FALSE);
3511 if (stmt) {
3512 sqlite3_finalize(stmt);
3516 mainview->loading=FALSE;
3518 return (res);
3522 * write to file
3524 void write_buffer_to_file(MainView * mainview)
3526 maepad_message("Writing database to file: %s", mainview->file_name);
3527 saveCurrentData(mainview);
3529 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->treeview));
3530 /*update ord value in database for all nodes*/
3531 gtk_tree_model_foreach(GTK_TREE_MODEL(model),(GtkTreeModelForeachFunc) foreach_func_update_ord,mainview);
3533 busy_enter(mainview);
3535 char tq[512];
3537 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", misctable_name);
3538 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3540 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", misctable_name, misctable);
3541 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3543 gint nndcc = 1;
3545 if (mainview->newnodedialog_createchild == FALSE)
3546 nndcc = 0;
3547 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('newNodeDlgCreateChild', '%d');", misctable_name, nndcc);
3548 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3550 nodeData *node = getSelectedNode(mainview);
3552 if (node)
3554 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('selectedNode', '%d');", misctable_name, node->sql3id);
3555 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3558 guint bsize = sketchwidget_get_brushsize(mainview->sk);
3559 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushSize', '%d');", misctable_name, bsize);
3560 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3562 if (mainview->current_color == NULL) {
3563 GdkColor color = {0, 0, 0, 0};
3564 mainview->current_color = gdk_color_copy(&color);
3566 unsigned long bcol = ((mainview->current_color->red >> 8) << 16) |
3567 ((mainview->current_color->green >> 8) << 8) |
3568 ((mainview->current_color->blue) >> 8);
3570 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('brushColor', '%lu');", misctable_name, bcol);
3571 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3573 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('dataVersion', '%d');", misctable_name, datatableversion);
3574 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3576 g_snprintf(tq, sizeof(tq), "INSERT INTO %s VALUES('checklistVersion', '%d');", misctable_name, checklisttableversion);
3577 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3579 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3580 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3581 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", datatable_backupname, datatable);
3582 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3584 maepad_warning("Error creating backup table: %s", datatable_backupname);
3585 show_banner(mainview, _("Error creating backup table"));
3587 busy_leave(mainview);
3588 return;
3590 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_backupname, datatable_name);
3591 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3593 maepad_warning("Error backing up table %s to %s", datatable_name, datatable_backupname);
3594 show_banner(mainview, _("Error creating backup table"));
3596 busy_leave(mainview);
3597 return;
3599 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3600 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3602 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_tmpname);
3603 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3605 maepad_warning("Error saving table %s to %s", datatable_tmpname, datatable_name);
3606 show_banner(mainview, _("Error saving table"));
3608 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", datatable_name);
3609 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3611 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", datatable_name, datatable_backupname);
3612 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3613 maepad_warning("Error restoring backup. Data lost :(");
3616 busy_leave(mainview);
3617 return;
3620 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", datatable_backupname);
3621 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3623 /*checklist*/
3624 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3625 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3626 g_snprintf(tq, sizeof(tq), "CREATE TABLE %s%s", checklisttable_backupname, checklisttable);
3627 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3629 maepad_warning("Error creating backup table: %s", checklisttable_backupname);
3630 show_banner(mainview, _("Error creating checklist backup table"));
3632 busy_leave(mainview);
3633 return;
3636 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_backupname, checklisttable_name);
3637 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3639 maepad_warning("Error backing up table %s to %s", checklisttable_name, checklisttable_backupname);
3640 show_banner(mainview, _("Error creating checklist backup table"));
3642 busy_leave(mainview);
3643 return;
3645 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3646 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3648 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_tmpname);
3649 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0)
3651 maepad_warning("Error saving table %s to %s", checklisttable_tmpname, checklisttable_name);
3652 show_banner(mainview, _("Error saving checklist table"));
3654 g_snprintf(tq, sizeof(tq), "DELETE FROM %s", checklisttable_name);
3655 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3657 g_snprintf(tq, sizeof(tq), "INSERT INTO %s SELECT * FROM %s", checklisttable_name, checklisttable_backupname);
3658 if (sqlite3_exec(mainview->db, tq, NULL, NULL, NULL) != 0) {
3659 maepad_warning("Error restoring backup. Data lost :(");
3661 busy_leave(mainview);
3662 return;
3665 g_snprintf(tq, sizeof(tq), "DROP TABLE %s", checklisttable_backupname);
3666 sqlite3_exec(mainview->db, tq, NULL, NULL, NULL);
3668 mainview->file_edited = FALSE;
3669 busy_leave(mainview);
3670 show_banner(mainview, _("Changes saved"));
3673 void callback_checklist_change(GtkTreeSelection *selection, MainView *mainview)
3675 g_assert(mainview != NULL && mainview->data != NULL);
3677 g_signal_handlers_block_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3678 g_signal_handlers_block_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
3679 g_signal_handlers_block_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
3681 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), FALSE);
3682 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), FALSE);
3683 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), FALSE);
3685 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
3686 GList* l=gtk_tree_selection_get_selected_rows(selection, NULL);
3688 gboolean gotit=FALSE;
3690 GList* cur=l;
3691 while(cur)
3693 GtkTreePath *path=cur->data;
3695 if (!gotit)
3697 GtkTreeIter iter;
3698 if (gtk_tree_model_get_iter(model, &iter, path))
3700 gint styletoset_weight;
3701 gboolean styletoset_strike;
3702 gboolean ischecked;
3704 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHECKNODE_BOLD, &styletoset_weight, CHECKNODE_STRIKE, &styletoset_strike, CHECKNODE_CHECKED, &ischecked, -1);
3705 if (styletoset_weight==PANGO_WEIGHT_BOLD) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->bold_tb), TRUE);
3706 if (styletoset_strike==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->strikethru_tb), TRUE);
3707 if (ischecked==TRUE) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mainview->check_tb), TRUE);
3708 gotit=TRUE;
3711 gtk_tree_path_free(path);
3712 cur=cur->next;
3715 g_list_free(l);
3717 g_signal_handlers_unblock_by_func(mainview->bold_tb, callback_fontstyle, mainview->bold_tb);
3718 g_signal_handlers_unblock_by_func(mainview->strikethru_tb, callback_fontstyle, mainview->strikethru_tb);
3719 g_signal_handlers_unblock_by_func(mainview->check_tb, callback_fontstyle, mainview->check_tb);
3722 void callback_checklist_paste(MainView *mainview)
3724 g_assert(mainview != NULL && mainview->data != NULL);
3725 gchar **entries;
3726 gint length, i;
3728 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
3729 GtkTreeIter toplevel;
3730 gchar *pasted_text = gtk_clipboard_wait_for_text(mainview->clipboard);
3732 entries = g_strsplit(pasted_text, "\n", 0);
3733 length = g_strv_length(entries);
3735 for (i=0; i<length; i++) {
3736 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
3737 gtk_list_store_set(GTK_LIST_STORE(model), &toplevel, CHECKNODE_CHECKED, FALSE, CHECKNODE_TEXT, entries[i], -1);
3740 mainview->checklist_edited = TRUE;
3741 g_free(pasted_text);
3742 g_strfreev(entries);
3745 void callback_checklist_add(GtkAction *action, MainView *mainview)
3747 g_assert(mainview != NULL && mainview->data != NULL);
3749 gchar* text = show_line_edit_dialog(mainview, _("Add new checklist item"), _("Name:"), _("Add"), "");
3751 if (text != NULL) {
3752 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
3753 GtkTreeIter toplevel;
3754 gtk_list_store_append(GTK_LIST_STORE(model), &toplevel);
3756 gtk_list_store_set(GTK_LIST_STORE(model),
3757 &toplevel,
3758 CHECKNODE_CHECKED, FALSE,
3759 CHECKNODE_TEXT, text,
3760 -1);
3762 GtkTreePath *path = gtk_tree_model_get_path(model, &toplevel);
3763 if (path) {
3764 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mainview->listview), path, mainview->checklist_column_text, FALSE);
3765 gtk_tree_path_free(path);
3768 mainview->checklist_edited = TRUE;
3772 void callback_checklist_edit(GtkAction *action, MainView *mainview)
3774 g_assert(mainview != NULL && mainview->data != NULL);
3776 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview));
3778 if (gtk_tree_selection_count_selected_rows(selection) == 0) {
3779 show_banner(mainview, _("Select items first"));
3780 return;
3783 GtkTreeModel* model;
3784 GtkTreeIter iter;
3786 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
3787 gchar* old_text = NULL;
3788 gtk_tree_model_get(model, &iter, CHECKNODE_TEXT, &old_text, -1);
3790 gchar* new_text = show_line_edit_dialog(mainview, _("Edit checklist item"), _("New name:"), _("Save"), old_text);
3792 if (new_text != NULL) {
3793 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHECKNODE_TEXT, new_text, -1);
3794 g_free(new_text);
3797 g_free(old_text);
3800 mainview->checklist_edited = TRUE;
3803 void callback_checklist_delete(GtkAction *action, MainView *mainview)
3805 g_assert(mainview != NULL && mainview->data != NULL);
3807 if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)))==0) {
3808 show_banner(mainview, _("Select items first"));
3809 return;
3812 if (show_confirmation(mainview, _("Delete selected checklist item?"))) {
3813 callback_checklist_delete_real(mainview);
3817 void callback_checklist_delete_real(MainView* mainview)
3819 GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(mainview->listview));
3820 GList* l=gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(mainview->listview)), NULL);
3822 GList* rowrefs=NULL;
3823 GList* cur=l;
3824 while(cur)
3826 GtkTreePath *path=cur->data;
3828 GtkTreeIter iter;
3829 if (gtk_tree_model_get_iter(model, &iter, path))
3831 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, path);
3832 rowrefs=g_list_append(rowrefs, rowref);
3834 gtk_tree_path_free(path);
3835 cur=cur->next;
3837 g_list_free(l);
3839 g_object_ref(model);
3840 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), NULL);
3842 cur=rowrefs;
3843 while(cur)
3845 GtkTreeRowReference *rowref=cur->data;
3846 GtkTreePath *path= gtk_tree_row_reference_get_path(rowref);
3847 if (path)
3849 GtkTreeIter iter;
3850 if (gtk_tree_model_get_iter(model, &iter, path)) gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
3851 gtk_tree_path_free(path);
3853 gtk_tree_row_reference_free(rowref);
3854 cur=cur->next;
3856 g_list_free(rowrefs);
3858 gtk_tree_view_set_model(GTK_TREE_VIEW(mainview->listview), model);
3859 g_object_unref(model);
3860 mainview->checklist_edited = TRUE;
3863 /* Ask the user for confirmation of a specific action */
3864 gboolean
3865 show_confirmation(MainView* mainview, gchar* question)
3867 GtkDialog* dialog = GTK_DIALOG(hildon_note_new_confirmation(
3868 GTK_WINDOW(mainview->data->main_view), question));
3869 gtk_window_set_transient_for(GTK_WINDOW(dialog), mainview_get_dialog_parent(mainview));
3871 gint response = gtk_dialog_run(dialog);
3872 gtk_widget_destroy(GTK_WIDGET(dialog));
3874 return (response == GTK_RESPONSE_OK);
3877 /* Show a information banner to the user (non-modal) */
3878 void
3879 show_banner(MainView* mainview, const gchar* text)
3881 hildon_banner_show_information(GTK_WIDGET(mainview_get_dialog_parent(mainview)), NULL, text);
3884 /* Let the user enter or edit a line of text */
3885 gchar*
3886 show_line_edit_dialog(MainView* mainview, const gchar* title, const gchar* label_text, const gchar* action, const gchar* text)
3888 GtkWidget* edit_dialog;
3889 GtkWidget* label;
3890 GtkWidget* entry;
3891 GtkWidget* hbox;
3892 gchar* result = NULL;
3894 edit_dialog = GTK_WIDGET(gtk_dialog_new());
3895 gtk_window_set_title(GTK_WINDOW(edit_dialog), title);
3896 gtk_window_set_transient_for(GTK_WINDOW(edit_dialog), mainview_get_dialog_parent(mainview));
3898 label = GTK_WIDGET(gtk_label_new(label_text));
3900 entry = hildon_entry_new(HILDON_SIZE_AUTO);
3901 gtk_entry_set_text(GTK_ENTRY(entry), text);
3902 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
3903 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
3905 gtk_dialog_add_button(GTK_DIALOG(edit_dialog), action, GTK_RESPONSE_OK);
3906 gtk_dialog_set_default_response(GTK_DIALOG(edit_dialog), GTK_RESPONSE_OK);
3908 hbox = GTK_WIDGET(gtk_hbox_new(FALSE, 10));
3910 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(edit_dialog))), GTK_WIDGET(hbox));
3911 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
3912 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
3914 gtk_widget_show_all(GTK_WIDGET(hbox));
3916 while (TRUE) {
3917 if (gtk_dialog_run(GTK_DIALOG(edit_dialog)) == GTK_RESPONSE_OK) {
3918 result = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
3919 if (strcmp(result, "") != 0) {
3920 break;
3921 } else {
3922 show_banner(mainview, _("Please enter a non-empty text"));
3923 g_free(result);
3924 result = NULL;
3926 } else {
3927 result = NULL;
3928 break;
3932 gtk_widget_destroy(GTK_WIDGET(edit_dialog));
3933 return result;