3
* Copyright (C) Pierre-Yves Luyten 2012, 2013 <py@luyten.fr>
5
* bijiben is free software: you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the
7
* Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* bijiben is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
* See the GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include "bjb-controller.h"
22
#include "bjb-main-view.h"
23
#include "bjb-window-base.h"
24
#include "utils/bjb-icons-colors.h"
29
struct _BjbControllerPrivate
34
GtkTreeModel *completion;
37
* Currently Controller is window-wide, in order to live while
38
* going from main view to note view.
39
* But not app-wide : each win has its controller & needle.
41
* gd-main-view is setup by main-view to allow choosing pixbuf
42
* according to grid / list view mode */
46
GList *notes_to_show ;
59
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
61
/* Currently used by toolbars */
64
DISPLAY_NOTES_CHANGED, // either search or book change
65
BJB_CONTROLLER_SIGNALS
68
static guint bjb_controller_signals [BJB_CONTROLLER_SIGNALS] = { 0 };
70
#define BJB_CONTROLLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BJB_TYPE_CONTROLLER, BjbControllerPrivate))
72
G_DEFINE_TYPE (BjbController, bjb_controller, G_TYPE_OBJECT);
77
bjb_controller_init (BjbController *self)
79
BjbControllerPrivate *priv ;
81
GtkListStore *completion ;
83
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
85
BjbControllerPrivate);
88
/* Create the columns */
89
store = gtk_list_store_new (NUMBER_COLUMNS,
92
G_TYPE_STRING, // name
93
G_TYPE_STRING, // author
94
GDK_TYPE_PIXBUF, // icon then note
95
G_TYPE_INT64, // mtime
96
G_TYPE_BOOLEAN); // state
98
priv->model = GTK_TREE_MODEL(store) ;
99
priv->notes_to_show = NULL;
101
priv->connected = FALSE;
103
completion = gtk_list_store_new (1, G_TYPE_STRING);
104
priv->completion = GTK_TREE_MODEL (completion);
108
free_notes_store(BjbController *self)
110
GtkListStore *store ;
112
store = GTK_LIST_STORE (self->priv->model) ;
114
gtk_list_store_clear(store);
118
bjb_controller_finalize (GObject *object)
120
BjbController *self = BJB_CONTROLLER(object);
121
BjbControllerPrivate *priv = self->priv ;
123
free_notes_store (self);
124
g_object_unref (priv->model);
126
g_object_unref (priv->completion);
127
g_free (priv->needle);
128
g_list_free (priv->notes_to_show);
130
G_OBJECT_CLASS (bjb_controller_parent_class)->finalize (object);
134
bjb_controller_get_property (GObject *object,
139
BjbController *self = BJB_CONTROLLER (object);
144
g_value_set_object (value, self->priv->book);
147
g_value_set_string(value, self->priv->needle);
150
g_value_set_object(value, self->priv->model);
153
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
159
bjb_controller_set_property (GObject *object,
164
BjbController *self = BJB_CONTROLLER (object);
169
bjb_controller_set_book(self,g_value_get_object(value));
172
bjb_controller_set_needle(self,g_value_get_string(value));
175
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
181
bjb_controller_add_note (BjbController *self,
187
GdkPixbuf *pix = NULL;
190
g_return_if_fail (BIJI_IS_NOTE_OBJ (note));
191
store = GTK_LIST_STORE (self->priv->model);
194
gtk_list_store_insert (store, &iter, 0);
197
gtk_list_store_append (store, &iter);
199
/* Only append notes which are not templates. Currently useless */
200
if ( biji_note_obj_is_template (note) == FALSE)
203
/* First , if there is a gd main view , and if gd main view
204
* is a list, then load the 16x16 note pixbuf
205
* This is probably not correct but allows a nice list view */
208
if (gd_main_view_get_view_type (self->priv->cur) == GD_MAIN_VIEW_LIST)
209
pix = get_note_pixbuf();
212
/* If no gd-main-view or if not list view,
213
* load the icon for grid */
215
pix = biji_note_obj_get_icon (note);
217
/* Appart from pixbuf, both icon & list view types
218
* currently use the same model */
219
path = biji_note_obj_get_path (note);
221
gtk_list_store_set (store,
225
COL_NAME, biji_note_obj_get_title(note),
228
COL_MTIME, biji_note_obj_get_last_change_date_sec(note),
238
/* If the user searches for notes, is the note searched? */
240
bjb_controller_add_note_if_needed (BjbController *self,
244
gboolean need_to_add_note =FALSE;
245
gchar *title, *content;
246
GList *collections, *l;
247
BjbControllerPrivate *priv = self->priv;
250
if (!note || !BIJI_IS_NOTE_OBJ (note))
253
/* No search - we add the note */
254
if (!priv->needle || g_strcmp0 (priv->needle, "")==0)
256
need_to_add_note = TRUE;
259
/* a search.. we test...*/
263
title = biji_note_obj_get_title (note);
264
content = biji_note_get_raw_text (note);
266
/* matching title or content ... */
267
if (g_strrstr (title , priv->needle) != NULL ||
268
g_strrstr (content, priv->needle) != NULL )
269
need_to_add_note = TRUE;
271
/* last chance, matching collections... */
274
collections = biji_note_obj_get_collections (note);
276
for (l = collections; l != NULL; l=l->next)
278
if (g_strrstr (l->data, title))
280
need_to_add_note = TRUE;
285
g_list_free (collections);
289
if (need_to_add_note)
290
bjb_controller_add_note (self, note, prepend);
294
bjb_controller_update_view (BjbController *self)
298
/* Do not update if nothing to show */
299
if (!self->priv->cur)
302
notes = self->priv->notes_to_show ;
303
free_notes_store (self);
305
for (l = notes; l != NULL; l = l->next)
307
bjb_controller_add_note (self, l->data, FALSE);
312
most_recent_note_first (gconstpointer a, gconstpointer b)
314
BijiNoteObj *one = BIJI_NOTE_OBJ (a);
315
BijiNoteObj *other = BIJI_NOTE_OBJ (b);
317
glong result = biji_note_obj_get_last_change_date_sec (other);
318
return result - biji_note_obj_get_last_change_date_sec (one);
322
sort_notes( BjbController *self)
324
self->priv->notes_to_show = g_list_sort (self->priv->notes_to_show,
325
most_recent_note_first);
329
sort_and_update (BjbController *self)
332
bjb_controller_update_view (self);
334
g_signal_emit (G_OBJECT (self), bjb_controller_signals[DISPLAY_NOTES_CHANGED],0);
338
update_controller_callback (GObject *source_object,
343
BjbController *self = BJB_CONTROLLER (user_data);
345
result = biji_get_notes_with_strings_or_collection_finish (source_object, res, self->priv->book);
346
self->priv->notes_to_show = result;
347
sort_and_update (self);
351
bjb_controller_apply_needle (BjbController *self)
353
BjbControllerPrivate *priv = self->priv;
356
if (priv->notes_to_show)
357
g_clear_pointer (&priv->notes_to_show, g_list_free);
359
needle = priv->needle;
362
if (needle == NULL || g_strcmp0 (needle,"") == 0)
364
priv->notes_to_show = biji_note_book_get_notes (self->priv->book);
365
sort_and_update (self);
369
biji_get_notes_with_string_or_collection_async (needle, update_controller_callback, self);
373
on_needle_changed ( BjbController *self )
375
bjb_controller_apply_needle (self);
376
g_signal_emit (self, bjb_controller_signals[SEARCH_CHANGED], 0);
380
add_note_to_completion(BijiNoteObj *note , BjbController *self)
385
store = GTK_LIST_STORE(self->priv->completion);
388
gtk_list_store_append (store, &iter);
389
gtk_list_store_set (store,
392
biji_note_obj_get_title(note),
397
refresh_completion(BjbController *self)
399
GList *notes = biji_note_book_get_notes (self->priv->book);
400
gtk_list_store_clear(GTK_LIST_STORE(self->priv->completion));
404
g_list_foreach (notes, (GFunc)add_note_to_completion, self);
410
bjb_controller_get_iter_at_note (BjbController *self, BijiNoteObj *note, GtkTreeIter **iter)
412
BjbControllerPrivate *priv = self->priv;
413
gchar *needle = biji_note_obj_get_path (note);
414
gboolean retval = FALSE;
415
gboolean still = gtk_tree_model_get_iter_first (priv->model, *iter);
421
gtk_tree_model_get (priv->model, *iter, GD_MAIN_COLUMN_URI, ¬e_path,-1);
423
if (g_strcmp0 (note_path, needle)==0)
432
still = gtk_tree_model_iter_next (priv->model, *iter);
439
/* Depending on the change at data level,
440
* the view has to be totaly refreshed or just amended */
442
on_book_changed (BijiNoteBook *book,
443
BijiNoteBookChangeFlag flag,
447
BjbControllerPrivate *priv = self->priv;
448
BijiNoteObj *note = BIJI_NOTE_OBJ (note_obj);
450
GtkTreeIter *p_iter = &iter;
454
/* If this is a *new* note, per def prepend
455
* But do not add a new note to a search window */
456
case BIJI_BOOK_NOTE_ADDED:
457
bjb_controller_add_note_if_needed (self, note, TRUE);
458
priv->notes_to_show = g_list_prepend (priv->notes_to_show, note);
459
g_signal_emit (G_OBJECT (self), bjb_controller_signals[DISPLAY_NOTES_CHANGED],0);
462
/* If the note is *amended*, then per definition we prepend.
463
* but if we add other ordering this does not work */
464
case BIJI_BOOK_NOTE_AMENDED:
465
if (bjb_controller_get_iter_at_note (self, note, &p_iter))
467
gtk_list_store_remove (GTK_LIST_STORE (priv->model), p_iter);
468
bjb_controller_add_note_if_needed (self, note, TRUE);
472
/* If color changed we just amend the icon */
473
case BIJI_BOOK_NOTE_COLORED:
474
if (gd_main_view_get_view_type (priv->cur) == GD_MAIN_VIEW_ICON
475
&& bjb_controller_get_iter_at_note (self, note, &p_iter))
476
gtk_list_store_set (GTK_LIST_STORE (priv->model), p_iter,
477
COL_IMAGE, biji_note_obj_get_icon (note), -1);
480
case BIJI_BOOK_NOTE_TRASHED:
481
if (bjb_controller_get_iter_at_note (self, note, &p_iter))
482
gtk_list_store_remove (GTK_LIST_STORE (priv->model), p_iter);
484
priv->notes_to_show = g_list_remove (priv->notes_to_show, note);
485
g_signal_emit (G_OBJECT (self), bjb_controller_signals[DISPLAY_NOTES_CHANGED],0);
489
bjb_controller_apply_needle (self);
492
/* FIXME we refresh the whole completion model each time */
493
refresh_completion(self);
497
bjb_controller_connect (BjbController *self)
499
BjbControllerPrivate *priv = self->priv;
501
if (!priv->connected)
503
priv->book_change = g_signal_connect (self->priv->book, "changed",
504
G_CALLBACK(on_book_changed), self);
505
priv->connected = TRUE;
510
bjb_controller_disconnect (BjbController *self)
512
BjbControllerPrivate *priv = self->priv;
514
g_signal_handler_disconnect (priv->book, priv->book_change);
515
priv->book_change = 0;
519
bjb_controller_constructed (GObject *obj)
521
G_OBJECT_CLASS(bjb_controller_parent_class)->constructed(obj);
525
bjb_controller_class_init (BjbControllerClass *klass)
527
GObjectClass* object_class = G_OBJECT_CLASS (klass);
529
g_type_class_add_private (klass, sizeof (BjbControllerPrivate));
531
object_class->get_property = bjb_controller_get_property;
532
object_class->set_property = bjb_controller_set_property;
533
object_class->finalize = bjb_controller_finalize;
534
object_class->constructed = bjb_controller_constructed;
536
bjb_controller_signals[SEARCH_CHANGED] = g_signal_new ( "search-changed" ,
537
G_OBJECT_CLASS_TYPE (klass),
542
g_cclosure_marshal_VOID__VOID,
546
bjb_controller_signals[DISPLAY_NOTES_CHANGED] = g_signal_new ( "display-notes-changed" ,
547
G_OBJECT_CLASS_TYPE (klass),
552
g_cclosure_marshal_VOID__BOOLEAN,
556
properties[PROP_BOOK] = g_param_spec_object ("book",
562
G_PARAM_STATIC_STRINGS);
564
properties[PROP_NEEDLE] = g_param_spec_string ("needle",
566
"String to search notes",
570
G_PARAM_STATIC_STRINGS);
573
properties[PROP_MODEL] = g_param_spec_object ("model",
578
G_PARAM_STATIC_STRINGS);
580
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
585
bjb_controller_new (BijiNoteBook *book,
588
return g_object_new ( BJB_TYPE_CONTROLLER,
595
bjb_controller_set_book (BjbController *self, BijiNoteBook *book )
597
self->priv->book = book ;
599
/* Only update completion.
600
* Notes model is updated when needle changes */
601
refresh_completion(self);
605
bjb_controller_set_needle (BjbController *self, const gchar *needle )
607
if (self->priv->needle)
608
g_free (self->priv->needle);
610
self->priv->needle = g_strdup (needle);
611
on_needle_changed (self);
615
bjb_controller_get_needle (BjbController *self)
617
if (!self->priv->needle)
620
return self->priv->needle;
624
bjb_controller_get_model (BjbController *self)
626
return self->priv->model ;
630
bjb_controller_get_completion(BjbController *self)
632
return self->priv->completion ;
636
bjb_controller_set_main_view (BjbController *self, GdMainView *current)
638
/* Refresh the model */
639
self->priv->cur = current;
640
bjb_controller_update_view (self);
644
bjb_controller_shows_notes (BjbController *self)
646
if (self->priv->notes_to_show)