1 /*
2  * model: A simple and generic data model holding one value per row
3  *
4  * Copyright 2012-2020 Stephan Haller <nomad@froevel.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  *
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <libxfdashboard/model.h>
29 
30 #include <glib/gi18n-lib.h>
31 
32 
33 /* Define theses classes in GObject system */
34 struct _XfdashboardModelPrivate
35 {
36 	/* Instance related */
37 	GSequence					*data;
38 	GDestroyNotify				freeDataCallback;
39 
40 	XfdashboardModelSortFunc	sortCallback;
41 	gpointer					sortUserData;
42 	GDestroyNotify				sortUserDataDestroyCallback;
43 
44 	XfdashboardModelFilterFunc	filterCallback;
45 	gpointer					filterUserData;
46 	GDestroyNotify				filterUserDataDestroyCallback;
47 };
48 
49 G_DEFINE_TYPE_WITH_PRIVATE(XfdashboardModel,
50 							xfdashboard_model,
51 							G_TYPE_OBJECT);
52 
53 struct _XfdashboardModelIterPrivate
54 {
55 	/* Instance related */
56 	XfdashboardModel			*model;
57 	GSequenceIter				*iter;
58 };
59 
60 G_DEFINE_TYPE_WITH_PRIVATE(XfdashboardModelIter,
61 							xfdashboard_model_iter,
62 							G_TYPE_OBJECT);
63 
64 /* Properties */
65 enum
66 {
67 	PROP_0,
68 
69 	PROP_ROWS,
70 	PROP_SORT_SET,
71 	PROP_FILTER_SET,
72 	PROP_FREE_DATA_CALLBACK,
73 
74 	PROP_LAST
75 };
76 
77 static GParamSpec* XfdashboardModelProperties[PROP_LAST]={ 0, };
78 
79 /* Signals */
80 enum
81 {
82 	SIGNAL_ROW_ADDED,
83 	SIGNAL_ROW_REMOVED,
84 	SIGNAL_ROW_CHANGED,
85 	SIGNAL_SORT_CHANGED,
86 	SIGNAL_FILTER_CHANGED,
87 
88 	SIGNAL_LAST
89 };
90 
91 static guint XfdashboardModelSignals[SIGNAL_LAST]={ 0, };
92 
93 
94 /* IMPLEMENTATION: Private variables and methods */
95 
96 typedef struct _XfdashboardModelSortData			XfdashboardModelSortData;
97 struct _XfdashboardModelSortData
98 {
99 	XfdashboardModel			*model;
100 	XfdashboardModelIter		*leftIter;
101 	XfdashboardModelIter		*rightIter;
102 };
103 
104 /* Checks for valid iterator for model */
_xfdashboard_model_iter_is_valid(XfdashboardModelIter * self,gboolean inNeedsIter)105 static gboolean _xfdashboard_model_iter_is_valid(XfdashboardModelIter *self, gboolean inNeedsIter)
106 {
107 	XfdashboardModelIterPrivate		*priv;
108 
109 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL_ITER(self), FALSE);
110 
111 	priv=self->priv;
112 
113 	/* Check if model is set */
114 	if(!priv->model) return(FALSE);
115 
116 	/* Check if an iterator is set when an iterator is needed */
117 	if(inNeedsIter && !priv->iter) return(FALSE);
118 
119 	/* Check if an iterator is set and if it is then check if associated
120 	 * GSequence at iterator matches the one associated with the model.
121 	 * If an iterator is needed the check before ensures that in this check
122 	 * an iterator exists and the check will be performed.
123 	 */
124 	if(priv->iter)
125 	{
126 		if(g_sequence_iter_get_sequence(priv->iter)!=priv->model->priv->data) return(FALSE);
127 	}
128 
129 	/* If we get here all tests are passed successfully and iterator is valid */
130 	return(TRUE);
131 }
132 
133 /* Checks if requested row is valid in this model */
_xfdashboard_model_is_valid_row(XfdashboardModel * self,gint inRow)134 static gboolean _xfdashboard_model_is_valid_row(XfdashboardModel *self, gint inRow)
135 {
136 	XfdashboardModelPrivate			*priv;
137 
138 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
139 
140 	priv=self->priv;
141 
142 	/* Check if row is a positive number and smaller than the total numbers
143 	 * of rows in model's data.
144 	 */
145 	if(inRow<0 || inRow>=g_sequence_get_length(priv->data)) return(FALSE);
146 
147 	/* If we get here the requested row is within model's data and valid */
148 	return(TRUE);
149 }
150 
151 /* Internal callback function for sorting which creates iterators used for
152  * user supplied callback function.
153  */
_xfdashboard_model_sort_internal(GSequenceIter * inLeft,GSequenceIter * inRight,gpointer inUserData)154 static gint _xfdashboard_model_sort_internal(GSequenceIter *inLeft,
155 												GSequenceIter *inRight,
156 												gpointer inUserData)
157 {
158 	XfdashboardModelSortData		*sortData;
159 	XfdashboardModelPrivate			*priv;
160 	gint							result;
161 
162 	g_return_val_if_fail(inLeft, 0);
163 	g_return_val_if_fail(inRight, 0);
164 	g_return_val_if_fail(inUserData, 0);
165 
166 	sortData=(XfdashboardModelSortData*)inUserData;
167 	priv=sortData->model->priv;
168 
169 	/* Update iterators to pass to user supplied sort callback function */
170 	sortData->leftIter->priv->iter=inLeft;
171 	sortData->rightIter->priv->iter=inRight;
172 
173 	/* Call user supplied sort callback function and return its result */
174 	result=(priv->sortCallback)(sortData->leftIter,
175 								sortData->rightIter,
176 								priv->sortUserData);
177 
178 	/* Return result of user supplied sort callback function */
179 	return(result);
180 }
181 
182 /* IMPLEMENTATION: GObject */
183 
184 /* Dispose this object of type XfdashboardModel */
_xfdashboard_model_dispose(GObject * inObject)185 static void _xfdashboard_model_dispose(GObject *inObject)
186 {
187 	XfdashboardModel				*self=XFDASHBOARD_MODEL(inObject);
188 	XfdashboardModelPrivate			*priv=self->priv;
189 
190 	/* Release our allocated variables */
191 	if(priv->sortUserData &&
192 		priv->sortUserDataDestroyCallback)
193 	{
194 		(priv->sortUserDataDestroyCallback)(priv->sortUserData);
195 	}
196 	priv->sortUserDataDestroyCallback=NULL;
197 	priv->sortUserData=NULL;
198 	priv->sortCallback=NULL;
199 
200 	if(priv->filterUserData &&
201 		priv->filterUserDataDestroyCallback)
202 	{
203 		(priv->filterUserDataDestroyCallback)(priv->filterUserData);
204 	}
205 	priv->filterUserDataDestroyCallback=NULL;
206 	priv->filterUserData=NULL;
207 	priv->filterCallback=NULL;
208 
209 	if(priv->data)
210 	{
211 		g_sequence_free(priv->data);
212 		priv->data=NULL;
213 	}
214 	priv->freeDataCallback=NULL;
215 
216 	/* Call parent's class dispose method */
217 	G_OBJECT_CLASS(xfdashboard_model_parent_class)->dispose(inObject);
218 }
219 
220 /* Set/get properties of type XfdashboardModel */
_xfdashboard_model_set_property(GObject * inObject,guint inPropID,const GValue * inValue,GParamSpec * inSpec)221 static void _xfdashboard_model_set_property(GObject *inObject,
222 											guint inPropID,
223 											const GValue *inValue,
224 											GParamSpec *inSpec)
225 {
226 	XfdashboardModel				*self=XFDASHBOARD_MODEL(inObject);
227 
228 	switch(inPropID)
229 	{
230 		case PROP_FREE_DATA_CALLBACK:
231 			self->priv->freeDataCallback=g_value_get_pointer(inValue);
232 			break;
233 
234 		default:
235 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
236 			break;
237 	}
238 }
239 
_xfdashboard_model_get_property(GObject * inObject,guint inPropID,GValue * outValue,GParamSpec * inSpec)240 static void _xfdashboard_model_get_property(GObject *inObject,
241 											guint inPropID,
242 											GValue *outValue,
243 											GParamSpec *inSpec)
244 {
245 	XfdashboardModel				*self=XFDASHBOARD_MODEL(inObject);
246 
247 	switch(inPropID)
248 	{
249 		case PROP_ROWS:
250 			g_value_set_int(outValue, xfdashboard_model_get_rows_count(self));
251 			break;
252 
253 		case PROP_SORT_SET:
254 			g_value_set_boolean(outValue, xfdashboard_model_is_sorted(self));
255 			break;
256 
257 		case PROP_FILTER_SET:
258 			g_value_set_boolean(outValue, xfdashboard_model_is_filtered(self));
259 			break;
260 
261 		default:
262 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
263 			break;
264 	}
265 }
266 
267 /* Class initialization of type XfdashboardModel
268  * Override functions in parent classes and define properties
269  * and signals
270  */
xfdashboard_model_class_init(XfdashboardModelClass * klass)271 static void xfdashboard_model_class_init(XfdashboardModelClass *klass)
272 {
273 	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
274 
275 	/* Override functions */
276 	gobjectClass->dispose=_xfdashboard_model_dispose;
277 	gobjectClass->set_property=_xfdashboard_model_set_property;
278 	gobjectClass->get_property=_xfdashboard_model_get_property;
279 
280 	/* Define properties */
281 	XfdashboardModelProperties[PROP_ROWS]=
282 		g_param_spec_int("rows",
283 							"Rows",
284 							"The number of rows this model contains",
285 							0, G_MAXINT,
286 							0,
287 							G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
288 
289 	XfdashboardModelProperties[PROP_SORT_SET]=
290 		g_param_spec_boolean("sort-set",
291 								"Sort set",
292 								"Whether a sorting function is set or not",
293 								FALSE,
294 								G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
295 
296 	XfdashboardModelProperties[PROP_FILTER_SET]=
297 		g_param_spec_boolean("filter-set",
298 								"Filter set",
299 								"Whether a filter is set or not",
300 								FALSE,
301 								G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
302 
303 	XfdashboardModelProperties[PROP_FREE_DATA_CALLBACK]=
304 		g_param_spec_pointer("free-data-callback",
305 								"Free data callback",
306 								"Callback function to free data when removing or overwriting data in model",
307 								G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
308 
309 	g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardModelProperties);
310 
311 	/* Define signals */
312 	XfdashboardModelSignals[SIGNAL_ROW_ADDED]=
313 		g_signal_new("row-added",
314 						G_TYPE_FROM_CLASS(klass),
315 						G_SIGNAL_RUN_LAST,
316 						G_STRUCT_OFFSET(XfdashboardModelClass, row_added),
317 						NULL,
318 						NULL,
319 						g_cclosure_marshal_VOID__OBJECT,
320 						G_TYPE_NONE,
321 						1,
322 						XFDASHBOARD_TYPE_MODEL_ITER);
323 
324 	XfdashboardModelSignals[SIGNAL_ROW_REMOVED]=
325 		g_signal_new("row-removed",
326 						G_TYPE_FROM_CLASS(klass),
327 						G_SIGNAL_RUN_LAST,
328 						G_STRUCT_OFFSET(XfdashboardModelClass, row_removed),
329 						NULL,
330 						NULL,
331 						g_cclosure_marshal_VOID__OBJECT,
332 						G_TYPE_NONE,
333 						1,
334 						XFDASHBOARD_TYPE_MODEL_ITER);
335 
336 	XfdashboardModelSignals[SIGNAL_ROW_CHANGED]=
337 		g_signal_new("row-changed",
338 						G_TYPE_FROM_CLASS(klass),
339 						G_SIGNAL_RUN_LAST,
340 						G_STRUCT_OFFSET(XfdashboardModelClass, row_changed),
341 						NULL,
342 						NULL,
343 						g_cclosure_marshal_VOID__OBJECT,
344 						G_TYPE_NONE,
345 						1,
346 						XFDASHBOARD_TYPE_MODEL_ITER);
347 
348 	XfdashboardModelSignals[SIGNAL_SORT_CHANGED]=
349 		g_signal_new("sort-changed",
350 						G_TYPE_FROM_CLASS(klass),
351 						G_SIGNAL_RUN_LAST,
352 						G_STRUCT_OFFSET(XfdashboardModelClass, sort_changed),
353 						NULL,
354 						NULL,
355 						g_cclosure_marshal_VOID__VOID,
356 						G_TYPE_NONE,
357 						0);
358 
359 	XfdashboardModelSignals[SIGNAL_FILTER_CHANGED]=
360 		g_signal_new("filter-changed",
361 						G_TYPE_FROM_CLASS(klass),
362 						G_SIGNAL_RUN_LAST,
363 						G_STRUCT_OFFSET(XfdashboardModelClass, filter_changed),
364 						NULL,
365 						NULL,
366 						g_cclosure_marshal_VOID__VOID,
367 						G_TYPE_NONE,
368 						0);
369 }
370 
371 /* Object initialization of type XfdashboardModel
372  * Create private structure and set up default values
373  */
xfdashboard_model_init(XfdashboardModel * self)374 static void xfdashboard_model_init(XfdashboardModel *self)
375 {
376 	XfdashboardModelPrivate			*priv;
377 
378 	priv=self->priv=xfdashboard_model_get_instance_private(self);
379 
380 	/* Set up default values */
381 	priv->data=g_sequence_new(NULL);
382 	priv->freeDataCallback=NULL;
383 
384 	priv->sortCallback=NULL;
385 	priv->sortUserData=NULL;
386 	priv->sortUserDataDestroyCallback=NULL;
387 
388 	priv->filterCallback=NULL;
389 	priv->filterUserData=NULL;
390 	priv->filterUserDataDestroyCallback=NULL;
391 }
392 
393 /* Dispose this object of type XfdashboardModelIter */
_xfdashboard_model_iter_dispose(GObject * inObject)394 static void _xfdashboard_model_iter_dispose(GObject *inObject)
395 {
396 	XfdashboardModelIter			*self=XFDASHBOARD_MODEL_ITER(inObject);
397 	XfdashboardModelIterPrivate		*priv=self->priv;
398 
399 	/* Release our allocated variables */
400 	if(priv->model)
401 	{
402 		g_object_unref(priv->model);
403 		priv->model=NULL;
404 	}
405 
406 	priv->iter=NULL;
407 
408 	/* Call parent's class dispose method */
409 	G_OBJECT_CLASS(xfdashboard_model_iter_parent_class)->dispose(inObject);
410 }
411 
412 /* Class initialization of type XfdashboardModelIter
413  * Override functions in parent classes and define properties
414  * and signals
415  */
xfdashboard_model_iter_class_init(XfdashboardModelIterClass * klass)416 static void xfdashboard_model_iter_class_init(XfdashboardModelIterClass *klass)
417 {
418 	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
419 
420 	/* Override functions */
421 	gobjectClass->dispose=_xfdashboard_model_iter_dispose;
422 }
423 
424 /* Object initialization of type XfdashboardModelIter
425  * Create private structure and set up default values
426  */
xfdashboard_model_iter_init(XfdashboardModelIter * self)427 static void xfdashboard_model_iter_init(XfdashboardModelIter *self)
428 {
429 	XfdashboardModelIterPrivate		*priv;
430 
431 	priv=self->priv=xfdashboard_model_iter_get_instance_private(self);
432 
433 	/* Set up default values */
434 	priv->model=NULL;
435 	priv->iter=NULL;
436 }
437 
438 
439 /* IMPLEMENTATION: Public API of XfdashboardModel */
440 
441 /* Model creation functions */
xfdashboard_model_new(void)442 XfdashboardModel* xfdashboard_model_new(void)
443 {
444 	GObject		*model;
445 
446 	model=g_object_new(XFDASHBOARD_TYPE_MODEL, NULL);
447 	if(!model) return(NULL);
448 
449 	return(XFDASHBOARD_MODEL(model));
450 }
451 
452 /* Return number of rows in this model */
xfdashboard_model_get_rows_count(XfdashboardModel * self)453 gint xfdashboard_model_get_rows_count(XfdashboardModel *self)
454 {
455 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), 0);
456 
457 	return(g_sequence_get_length(self->priv->data));
458 }
459 
460 /* Get item at requested row of this model */
xfdashboard_model_get(XfdashboardModel * self,gint inRow)461 gpointer xfdashboard_model_get(XfdashboardModel *self, gint inRow)
462 {
463 	XfdashboardModelPrivate			*priv;
464 	GSequenceIter					*iter;
465 	gpointer						item;
466 
467 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), NULL);
468 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(self, inRow), NULL);
469 
470 	priv=self->priv;
471 	item=NULL;
472 
473 	/* Get iterator at requested row */
474 	iter=g_sequence_get_iter_at_pos(priv->data, inRow);
475 	if(iter)
476 	{
477 		/* Get item from iterator */
478 		item=g_sequence_get(iter);
479 	}
480 
481 	/* Return item found */
482 	return(item);
483 }
484 
485 /* Add a new item to end of model's data */
xfdashboard_model_append(XfdashboardModel * self,gpointer inData,XfdashboardModelIter ** outIter)486 gboolean xfdashboard_model_append(XfdashboardModel *self,
487 									gpointer inData,
488 									XfdashboardModelIter **outIter)
489 {
490 	XfdashboardModelPrivate			*priv;
491 	XfdashboardModelIter			*iter;
492 	GSequenceIter					*seqIter;
493 
494 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
495 	g_return_val_if_fail(outIter==NULL || *outIter==NULL, FALSE);
496 
497 	priv=self->priv;
498 
499 	/* Append data to model's data */
500 	seqIter=g_sequence_append(priv->data, inData);
501 
502 	/* Create iterator for returned sequence iterator */
503 	iter=xfdashboard_model_iter_new(self);
504 	iter->priv->iter=seqIter;
505 
506 	/* Emit signal */
507 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_ADDED], 0, iter);
508 
509 	/* Store iterator if callee requested it */
510 	if(outIter) *outIter=XFDASHBOARD_MODEL_ITER(g_object_ref(iter));
511 
512 	/* Release allocated resources */
513 	if(iter) g_object_unref(iter);
514 
515 	/* Return TRUE for success */
516 	return(TRUE);
517 }
518 
519 /* Add a new item to begin of model's data */
xfdashboard_model_prepend(XfdashboardModel * self,gpointer inData,XfdashboardModelIter ** outIter)520 gboolean xfdashboard_model_prepend(XfdashboardModel *self,
521 									gpointer inData,
522 									XfdashboardModelIter **outIter)
523 {
524 	XfdashboardModelPrivate			*priv;
525 	XfdashboardModelIter			*iter;
526 	GSequenceIter					*seqIter;
527 
528 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
529 	g_return_val_if_fail(outIter==NULL || *outIter==NULL, FALSE);
530 
531 	priv=self->priv;
532 
533 	/* Append data to model's data */
534 	seqIter=g_sequence_prepend(priv->data, inData);
535 
536 	/* Create iterator for returned sequence iterator */
537 	iter=xfdashboard_model_iter_new(self);
538 	iter->priv->iter=seqIter;
539 
540 	/* Emit signal */
541 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_ADDED], 0, iter);
542 
543 	/* Store iterator if callee requested it */
544 	if(outIter) *outIter=XFDASHBOARD_MODEL_ITER(g_object_ref(iter));
545 
546 	/* Release allocated resources */
547 	if(iter) g_object_unref(iter);
548 
549 	/* Return TRUE for success */
550 	return(TRUE);
551 }
552 
553 /* Add a new item at requested row (i.e. before the item at requested row)
554  * at model's data.
555  */
xfdashboard_model_insert(XfdashboardModel * self,gint inRow,gpointer inData,XfdashboardModelIter ** outIter)556 gboolean xfdashboard_model_insert(XfdashboardModel *self,
557 									gint inRow,
558 									gpointer inData,
559 									XfdashboardModelIter **outIter)
560 {
561 	XfdashboardModelPrivate			*priv;
562 	XfdashboardModelIter			*iter;
563 	GSequenceIter					*seqIter;
564 	GSequenceIter					*insertIter;
565 
566 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
567 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(self, inRow), FALSE);
568 	g_return_val_if_fail(outIter==NULL || *outIter==NULL, FALSE);
569 
570 	priv=self->priv;
571 
572 	/* Create sequence iterator where to insert new data at */
573 	insertIter=g_sequence_get_iter_at_pos(priv->data, inRow);
574 
575 	/* Insert data at "insert iterator" at model's data */
576 	seqIter=g_sequence_insert_before(insertIter, inData);
577 
578 	/* Create iterator for returned sequence iterator */
579 	iter=xfdashboard_model_iter_new(self);
580 	iter->priv->iter=seqIter;
581 
582 	/* Emit signal */
583 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_ADDED], 0, iter);
584 
585 	/* Store iterator if callee requested it */
586 	if(outIter) *outIter=XFDASHBOARD_MODEL_ITER(g_object_ref(iter));
587 
588 	/* Release allocated resources */
589 	if(iter) g_object_unref(iter);
590 
591 	/* Return TRUE for success */
592 	return(TRUE);
593 }
594 
595 /* Set or replace data at iterator */
xfdashboard_model_set(XfdashboardModel * self,gint inRow,gpointer inData,XfdashboardModelIter ** outIter)596 gboolean xfdashboard_model_set(XfdashboardModel *self,
597 								gint inRow,
598 								gpointer inData,
599 								XfdashboardModelIter **outIter)
600 {
601 	XfdashboardModelPrivate			*priv;
602 	XfdashboardModelIter			*iter;
603 	GSequenceIter					*seqIter;
604 
605 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
606 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(self, inRow), FALSE);
607 
608 	priv=self->priv;
609 
610 	/* Create sequence iterator to row which is set */
611 	seqIter=g_sequence_get_iter_at_pos(priv->data, inRow);
612 
613 	/* If a function is provided to free data on removal then call it now */
614 	if(priv->freeDataCallback)
615 	{
616 		gpointer					oldData;
617 
618 		/* Get data to remove */
619 		oldData=g_sequence_get(seqIter);
620 
621 		/* Call function to free data */
622 		(priv->freeDataCallback)(oldData);
623 	}
624 
625 	/* Set new data at iterator */
626 	g_sequence_set(seqIter, inData);
627 
628 	/* Create iterator for returned sequence iterator */
629 	iter=xfdashboard_model_iter_new(self);
630 	iter->priv->iter=seqIter;
631 
632 	/* Emit signal */
633 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_CHANGED], 0, iter);
634 
635 	/* Store iterator if callee requested it */
636 	if(outIter) *outIter=XFDASHBOARD_MODEL_ITER(g_object_ref(iter));
637 
638 	/* Release allocated resources */
639 	if(iter) g_object_unref(iter);
640 
641 	/* Return TRUE for success */
642 	return(TRUE);
643 }
644 
645 /* Remove data at requested row from model's data */
xfdashboard_model_remove(XfdashboardModel * self,gint inRow)646 gboolean xfdashboard_model_remove(XfdashboardModel *self, gint inRow)
647 {
648 	XfdashboardModelPrivate			*priv;
649 	XfdashboardModelIter			*iter;
650 	GSequenceIter					*seqIter;
651 
652 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
653 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(self, inRow), FALSE);
654 
655 	priv=self->priv;
656 
657 	/* Create sequence iterator to row which is to remove */
658 	seqIter=g_sequence_get_iter_at_pos(priv->data, inRow);
659 
660 	/* Create iterator for returned sequence iterator */
661 	iter=xfdashboard_model_iter_new(self);
662 	iter->priv->iter=seqIter;
663 
664 	/* Emit signal before removal to give signal handlers a changed
665 	 * to access the data at iterator a last time.
666 	 */
667 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_REMOVED], 0, iter);
668 
669 	/* If a function is provided to free data on removal then call it now */
670 	if(priv->freeDataCallback)
671 	{
672 		gpointer					oldData;
673 
674 		/* Get data to remove */
675 		oldData=g_sequence_get(seqIter);
676 
677 		/* Call function to free data */
678 		(priv->freeDataCallback)(oldData);
679 	}
680 
681 	/* Remove data from model's data */
682 	g_sequence_remove(seqIter);
683 
684 	/* Release allocated resources */
685 	if(iter) g_object_unref(iter);
686 
687 	/* Return TRUE for success */
688 	return(TRUE);
689 }
690 
691 /* Remove all data from model's data */
xfdashboard_model_remove_all(XfdashboardModel * self)692 void xfdashboard_model_remove_all(XfdashboardModel *self)
693 {
694 	XfdashboardModelPrivate			*priv;
695 	XfdashboardModelIter			*iter;
696 
697 	g_return_if_fail(XFDASHBOARD_IS_MODEL(self));
698 
699 	priv=self->priv;
700 
701 	/* Create iterator used to iterate through all items in model's data
702 	 * and it is used when emitting signal.
703 	 */
704 	iter=xfdashboard_model_iter_new(self);
705 	iter->priv->iter=g_sequence_get_begin_iter(priv->data);
706 
707 	/* Iterate through all items in model's data, emit signal for each item
708 	 * being remove and remove them finally. If model provides a function to
709 	 * free data call it with the item to remove.
710 	 */
711 	while(!g_sequence_iter_is_end(iter->priv->iter))
712 	{
713 		/* Emit signal before removal to give signal handlers a changed
714 		 * to access the data at iterator a last time.
715 		 */
716 		g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_REMOVED], 0, iter);
717 
718 		/* If a function is provided to free data on removal then call it now */
719 		if(priv->freeDataCallback)
720 		{
721 			gpointer					oldData;
722 
723 			/* Get data to remove */
724 			oldData=g_sequence_get(iter->priv->iter);
725 
726 			/* Call function to free data */
727 			(priv->freeDataCallback)(oldData);
728 		}
729 
730 		/* Remove data from model's data */
731 		g_sequence_remove(iter->priv->iter);
732 
733 		/* Move iterator to next item in model's data */
734 		iter->priv->iter=g_sequence_iter_next(iter->priv->iter);
735 	}
736 
737 	/* Release allocated resources */
738 	if(iter) g_object_unref(iter);
739 }
740 
741 /* Iterate through all items in model's data and call user supplied callback
742  * function for each item.
743  */
xfdashboard_model_foreach(XfdashboardModel * self,XfdashboardModelForeachFunc inForeachCallback,gpointer inUserData)744 void xfdashboard_model_foreach(XfdashboardModel *self,
745 								XfdashboardModelForeachFunc inForeachCallback,
746 								gpointer inUserData)
747 {
748 	XfdashboardModelIter			*iter;
749 	gpointer						item;
750 
751 	g_return_if_fail(XFDASHBOARD_IS_MODEL(self));
752 	g_return_if_fail(inForeachCallback);
753 
754 	/* Iterate through all items in model's data */
755 	/* Call user supplied callback function */
756 	iter=xfdashboard_model_iter_new(self);
757 	while(xfdashboard_model_iter_next(iter))
758 	{
759 		/* Get item at position the iterator points to */
760 		item=xfdashboard_model_iter_get(iter);
761 
762 		/* Call user supplied callback function */
763 		(inForeachCallback)(iter, item, inUserData);
764 	}
765 
766 	/* Release allocated resources */
767 	if(iter) g_object_unref(iter);
768 }
769 
770 /* Model sort functions */
xfdashboard_model_is_sorted(XfdashboardModel * self)771 gboolean xfdashboard_model_is_sorted(XfdashboardModel *self)
772 {
773 	XfdashboardModelPrivate			*priv;
774 
775 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
776 
777 	priv=self->priv;
778 
779 	/* If a sort function is set then return TRUE ... */
780 	if(priv->sortCallback) return(TRUE);
781 
782 	/* ... otherwise FALSE */
783 	return(FALSE);
784 }
785 
786 /* Set sorting function */
xfdashboard_model_set_sort(XfdashboardModel * self,XfdashboardModelSortFunc inSortCallback,gpointer inUserData,GDestroyNotify inUserDataDestroyCallback)787 void xfdashboard_model_set_sort(XfdashboardModel *self,
788 								XfdashboardModelSortFunc inSortCallback,
789 								gpointer inUserData,
790 								GDestroyNotify inUserDataDestroyCallback)
791 {
792 	XfdashboardModelPrivate			*priv;
793 
794 	g_return_if_fail(XFDASHBOARD_IS_MODEL(self));
795 
796 	priv=self->priv;
797 
798 	/* Set value if changed */
799 	if(priv->sortCallback!=inSortCallback ||
800 		priv->sortUserData!=inUserData ||
801 		priv->sortUserDataDestroyCallback!=inUserDataDestroyCallback)
802 	{
803 		gboolean				oldSortIsSet;
804 		gboolean				newSortIsSet;
805 
806 		/* Get old "sort-set" value. It is used later to determine if this
807 		 * property has changed also.
808 		 */
809 		oldSortIsSet=xfdashboard_model_is_sorted(self);
810 
811 		/* Release old values */
812 		if(priv->sortUserData &&
813 			priv->sortUserDataDestroyCallback)
814 		{
815 			(priv->sortUserDataDestroyCallback)(priv->sortUserData);
816 		}
817 		priv->sortUserDataDestroyCallback=NULL;
818 		priv->sortUserData=NULL;
819 		priv->sortCallback=NULL;
820 
821 		/* Set value */
822 		priv->sortCallback=inSortCallback;
823 		priv->sortUserData=inUserData;
824 		priv->sortUserDataDestroyCallback=inUserDataDestroyCallback;
825 
826 		/* Get new "sort-set" value to determine if this property has
827 		 * changed also.
828 		 */
829 		newSortIsSet=xfdashboard_model_is_sorted(self);
830 
831 		/* Sort model if sort function is set */
832 		if(newSortIsSet) xfdashboard_model_resort(self);
833 
834 		/* Notify about change of 'sort-set' if changed and after model
835 		 * was sorted.
836 		 */
837 		if(oldSortIsSet!=newSortIsSet)
838 		{
839 			g_object_notify_by_pspec(G_OBJECT(self), XfdashboardModelProperties[PROP_SORT_SET]);
840 		}
841 
842 		/* Emit signal that sorting has changed */
843 		g_signal_emit(self, XfdashboardModelSignals[SIGNAL_SORT_CHANGED], 0);
844 	}
845 }
846 
847 /* Resort this model's data with sorting function set */
xfdashboard_model_resort(XfdashboardModel * self)848 void xfdashboard_model_resort(XfdashboardModel *self)
849 {
850 	XfdashboardModelPrivate			*priv;
851 	XfdashboardModelSortData		sortData;
852 
853 	g_return_if_fail(XFDASHBOARD_IS_MODEL(self));
854 
855 	priv=self->priv;
856 
857 	/* If no sort function is set return immediately because this model
858 	 * cannot be sorted without a sort function.
859 	 */
860 	if(!priv->sortCallback) return;
861 
862 	/* Set up sort data which wraps all needed information into a structure.
863 	 * The interators are pre-initialized and updated in internal sort function
864 	 * which is passed to GSequence's sort function. This internal callback
865 	 * only updates the existing iterators to reduce creation and destructions
866 	 * of these iterator. This can be done because the model does not change
867 	 * while sorting.
868 	 */
869 	sortData.model=XFDASHBOARD_MODEL(g_object_ref(self));
870 	sortData.leftIter=xfdashboard_model_iter_new(self);
871 	sortData.rightIter=xfdashboard_model_iter_new(self);
872 
873 	/* Sort this model again by using internal sorting function which
874 	 * calls user's sort function with adjusted parameters.
875 	 */
876 	g_sequence_sort_iter(priv->data, _xfdashboard_model_sort_internal, &sortData);
877 
878 	/* Release allocated resources */
879 	if(sortData.model) g_object_unref(sortData.model);
880 	if(sortData.leftIter) g_object_unref(sortData.leftIter);
881 	if(sortData.rightIter) g_object_unref(sortData.rightIter);
882 }
883 
884 /* Model filter functions */
xfdashboard_model_is_filtered(XfdashboardModel * self)885 gboolean xfdashboard_model_is_filtered(XfdashboardModel *self)
886 {
887 	XfdashboardModelPrivate			*priv;
888 
889 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
890 
891 	priv=self->priv;
892 
893 	/* If a filter function is set then return TRUE ... */
894 	if(priv->filterCallback) return(TRUE);
895 
896 	/* ... otherwise FALSE */
897 	return(FALSE);
898 }
899 
900 /* Set filter function */
xfdashboard_model_set_filter(XfdashboardModel * self,XfdashboardModelFilterFunc inFilterCallback,gpointer inUserData,GDestroyNotify inUserDataDestroyCallback)901 void xfdashboard_model_set_filter(XfdashboardModel *self,
902 									XfdashboardModelFilterFunc inFilterCallback,
903 									gpointer inUserData,
904 									GDestroyNotify inUserDataDestroyCallback)
905 {
906 	XfdashboardModelPrivate			*priv;
907 
908 	g_return_if_fail(XFDASHBOARD_IS_MODEL(self));
909 
910 	priv=self->priv;
911 
912 	/* Set value if changed */
913 	if(priv->filterCallback!=inFilterCallback ||
914 		priv->filterUserData!=inUserData ||
915 		priv->filterUserDataDestroyCallback!=inUserDataDestroyCallback)
916 	{
917 		gboolean				oldFilterIsSet;
918 		gboolean				newFilterIsSet;
919 
920 		/* Get old "filter-set" value. It is used later to determine if this
921 		 * property has changed also.
922 		 */
923 		oldFilterIsSet=xfdashboard_model_is_filtered(self);
924 
925 		/* Release old values */
926 		if(priv->filterUserData &&
927 			priv->filterUserDataDestroyCallback)
928 		{
929 			(priv->filterUserDataDestroyCallback)(priv->filterUserData);
930 		}
931 		priv->filterUserDataDestroyCallback=NULL;
932 		priv->filterUserData=NULL;
933 		priv->filterCallback=NULL;
934 
935 		/* Set value */
936 		priv->filterCallback=inFilterCallback;
937 		priv->filterUserData=inUserData;
938 		priv->filterUserDataDestroyCallback=inUserDataDestroyCallback;
939 
940 		/* Get new "sort-set" value to determine if this property has
941 		 * changed also.
942 		 */
943 		newFilterIsSet=xfdashboard_model_is_filtered(self);
944 
945 		/* Notify about change of 'sort-set' if changed and after model
946 		 * was sorted.
947 		 */
948 		if(oldFilterIsSet!=newFilterIsSet)
949 		{
950 			g_object_notify_by_pspec(G_OBJECT(self), XfdashboardModelProperties[PROP_FILTER_SET]);
951 		}
952 
953 		/* Emit signal that filter has changed */
954 		g_signal_emit(self, XfdashboardModelSignals[SIGNAL_FILTER_CHANGED], 0);
955 	}
956 }
957 
958 /* Check if requested row is filtered */
xfdashboard_model_filter_row(XfdashboardModel * self,gint inRow)959 gboolean xfdashboard_model_filter_row(XfdashboardModel *self, gint inRow)
960 {
961 	XfdashboardModelPrivate			*priv;
962 	XfdashboardModelIter			*iter;
963 	gboolean						isVisible;
964 
965 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(self), FALSE);
966 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(self, inRow), FALSE);
967 
968 	priv=self->priv;
969 	isVisible=TRUE;
970 
971 	/* Call user supplied filter callback function to determine if this
972 	 * row should be filtered or not but only if filter function is set.
973 	 */
974 	if(priv->filterCallback)
975 	{
976 		/* Create iterator */
977 		iter=xfdashboard_model_iter_new_for_row(self, inRow);
978 
979 		/* Determine if row is filtered */
980 		isVisible=(priv->filterCallback)(iter, priv->filterUserData);
981 
982 		/* Release allocated resources */
983 		if(iter) g_object_unref(iter);
984 	}
985 
986 	/* Return filter status */
987 	return(isVisible);
988 }
989 
990 /* Create iterator for model */
xfdashboard_model_iter_new(XfdashboardModel * inModel)991 XfdashboardModelIter* xfdashboard_model_iter_new(XfdashboardModel *inModel)
992 {
993 	XfdashboardModelIter			*iter;
994 
995 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(inModel), NULL);
996 
997 	/* Create iterator */
998 	iter=XFDASHBOARD_MODEL_ITER(g_object_new(XFDASHBOARD_TYPE_MODEL_ITER, NULL));
999 
1000 	/* Set up iterator */
1001 	iter->priv->model=XFDASHBOARD_MODEL(g_object_ref(inModel));
1002 	iter->priv->iter=NULL;
1003 
1004 	/* Return newly created iterator */
1005 	return(iter);
1006 }
1007 
1008 /* Create iterator for model at requested row */
xfdashboard_model_iter_new_for_row(XfdashboardModel * inModel,gint inRow)1009 XfdashboardModelIter* xfdashboard_model_iter_new_for_row(XfdashboardModel *inModel, gint inRow)
1010 {
1011 	XfdashboardModelIter			*iter;
1012 	XfdashboardModelPrivate			*modelPriv;
1013 
1014 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL(inModel), NULL);
1015 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(inModel, inRow), NULL);
1016 
1017 	modelPriv=inModel->priv;
1018 
1019 	/* Create iterator */
1020 	iter=XFDASHBOARD_MODEL_ITER(g_object_new(XFDASHBOARD_TYPE_MODEL_ITER, NULL));
1021 
1022 	/* Set up iterator */
1023 	iter->priv->model=XFDASHBOARD_MODEL(g_object_ref(inModel));
1024 	iter->priv->iter=g_sequence_get_iter_at_pos(modelPriv->data, inRow);
1025 
1026 	/* Return newly created iterator */
1027 	return(iter);
1028 }
1029 
1030 /* Create copy of an iterator */
xfdashboard_model_iter_copy(XfdashboardModelIter * self)1031 XfdashboardModelIter* xfdashboard_model_iter_copy(XfdashboardModelIter *self)
1032 {
1033 	XfdashboardModelIterPrivate		*priv;
1034 	XfdashboardModelIter			*copyIter;
1035 
1036 	g_return_val_if_fail(XFDASHBOARD_IS_MODEL_ITER(self), NULL);
1037 
1038 	priv=self->priv;
1039 
1040 	/* Create iterator */
1041 	copyIter=XFDASHBOARD_MODEL_ITER(g_object_new(XFDASHBOARD_TYPE_MODEL_ITER, NULL));
1042 
1043 	/* Set up iterator to be a copy of given iterator */
1044 	copyIter->priv->model=XFDASHBOARD_MODEL(g_object_ref(priv->model));
1045 	copyIter->priv->iter=priv->iter;
1046 
1047 	/* Return copy of iterator */
1048 	return(copyIter);
1049 }
1050 
1051 /* Move iterator to next item in model's data */
xfdashboard_model_iter_next(XfdashboardModelIter * self)1052 gboolean xfdashboard_model_iter_next(XfdashboardModelIter *self)
1053 {
1054 	XfdashboardModelIterPrivate		*priv;
1055 	XfdashboardModelPrivate			*modelPriv;
1056 	GSequenceIter					*newIter;
1057 
1058 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, FALSE), FALSE);
1059 
1060 	priv=self->priv;
1061 	modelPriv=priv->model->priv;
1062 
1063 	/* If no iterator was initialized then create an iterator pointing
1064 	 * to begin of model's data ...
1065 	 */
1066 	if(!priv->iter)
1067 	{
1068 		/* Get and set iterator pointing to begin of model's data */
1069 		newIter=g_sequence_get_begin_iter(modelPriv->data);
1070 	}
1071 		/* ... otherwise move iterator to next item in model's data */
1072 		else
1073 		{
1074 			/* Move iterator to next item in model's data */
1075 			newIter=g_sequence_iter_next(priv->iter);
1076 		}
1077 
1078 	/* If iterator is invalid or end of model's data is reached
1079 	 * return FALSE here.
1080 	 */
1081 	if(!newIter ||
1082 		g_sequence_iter_is_end(newIter))
1083 	{
1084 		return(FALSE);
1085 	}
1086 
1087 	/* New iterator is valid so set it */
1088 	priv->iter=newIter;
1089 
1090 	/* If we get here then all went well and we can return TRUE */
1091 	return(TRUE);
1092 }
1093 
1094 /* Move iterator to previous item in model's data */
xfdashboard_model_iter_prev(XfdashboardModelIter * self)1095 gboolean xfdashboard_model_iter_prev(XfdashboardModelIter *self)
1096 {
1097 	XfdashboardModelIterPrivate		*priv;
1098 	XfdashboardModelPrivate			*modelPriv;
1099 	GSequenceIter					*newIter;
1100 
1101 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, FALSE), FALSE);
1102 
1103 	priv=self->priv;
1104 	modelPriv=priv->model->priv;
1105 
1106 	/* If no iterator was initialized then create an iterator pointing
1107 	 * to end of model's data ...
1108 	 */
1109 	if(!priv->iter)
1110 	{
1111 		/* Get and set iterator pointing to end of model's data */
1112 		newIter=g_sequence_get_end_iter(modelPriv->data);
1113 	}
1114 		/* ... otherwise move iterator to previous item in model's data */
1115 		else
1116 		{
1117 			/* Move iterator to next item in model's data */
1118 			newIter=g_sequence_iter_prev(priv->iter);
1119 		}
1120 
1121 	/* If iterator is invalid or begin of model's data is reached
1122 	 * return FALSE here.
1123 	 */
1124 	if(!newIter ||
1125 		g_sequence_iter_is_begin(newIter))
1126 	{
1127 		return(FALSE);
1128 	}
1129 
1130 	/* New iterator is valid so set it */
1131 	priv->iter=newIter;
1132 
1133 	/* If we get here then all went well and we can return TRUE */
1134 	return(TRUE);
1135 }
1136 
1137 /* Move iterator to requested row in model's data */
xfdashboard_model_iter_move_to_row(XfdashboardModelIter * self,gint inRow)1138 gboolean xfdashboard_model_iter_move_to_row(XfdashboardModelIter *self, gint inRow)
1139 {
1140 	XfdashboardModelIterPrivate		*priv;
1141 	XfdashboardModelPrivate			*modelPriv;
1142 
1143 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, FALSE), FALSE);
1144 
1145 	priv=self->priv;
1146 	modelPriv=priv->model->priv;
1147 
1148 	/* Check that requested row is within range */
1149 	g_return_val_if_fail(_xfdashboard_model_is_valid_row(priv->model, inRow), FALSE);
1150 
1151 	/* Move iterator to requested row */
1152 	priv->iter=g_sequence_get_iter_at_pos(modelPriv->data, inRow);
1153 
1154 	/* If we get here then all went well and we can return TRUE */
1155 	return(TRUE);
1156 }
1157 
1158 /* Get model to which this iterator belongs to */
xfdashboard_model_iter_get_model(XfdashboardModelIter * self)1159 XfdashboardModel* xfdashboard_model_iter_get_model(XfdashboardModelIter *self)
1160 {
1161 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, FALSE), FALSE);
1162 
1163 	return(self->priv->model);
1164 }
1165 
1166 /* Get row at model's data this iterator points to currently */
xfdashboard_model_iter_get_row(XfdashboardModelIter * self)1167 guint xfdashboard_model_iter_get_row(XfdashboardModelIter *self)
1168 {
1169 	XfdashboardModelIterPrivate		*priv;
1170 	gint							position;
1171 
1172 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, TRUE), 0);
1173 
1174 	priv=self->priv;
1175 
1176 	/* Get position from iterator */
1177 	position=g_sequence_iter_get_position(priv->iter);
1178 	if(position<0) position=0;
1179 
1180 	/* Return position (maybe corrected for unsigned integer) */
1181 	return((guint)position);
1182 }
1183 
1184 /* Get item at position and model of this iterator */
xfdashboard_model_iter_get(XfdashboardModelIter * self)1185 gpointer xfdashboard_model_iter_get(XfdashboardModelIter *self)
1186 {
1187 	XfdashboardModelIterPrivate		*priv;
1188 
1189 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, TRUE), NULL);
1190 
1191 	priv=self->priv;
1192 
1193 	/* Get item of model this iterator belongs to */
1194 	return(g_sequence_get(priv->iter));
1195 }
1196 
1197 /* Set or replace data at iterator */
xfdashboard_model_iter_set(XfdashboardModelIter * self,gpointer inData)1198 gboolean xfdashboard_model_iter_set(XfdashboardModelIter *self, gpointer inData)
1199 {
1200 	XfdashboardModelIterPrivate		*priv;
1201 	XfdashboardModelPrivate			*modelPriv;
1202 
1203 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, TRUE), FALSE);
1204 
1205 	priv=self->priv;
1206 	modelPriv=priv->model->priv;
1207 
1208 	/* If a function at model is provided to free data on removal
1209 	 * then call it now.
1210 	 */
1211 	if(modelPriv->freeDataCallback)
1212 	{
1213 		gpointer					oldData;
1214 
1215 		/* Get data to remove */
1216 		oldData=g_sequence_get(priv->iter);
1217 
1218 		/* Call function to free data */
1219 		(modelPriv->freeDataCallback)(oldData);
1220 	}
1221 
1222 	/* Set new data at iterator */
1223 	g_sequence_set(priv->iter, inData);
1224 
1225 	/* Emit signal */
1226 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_CHANGED], 0, self);
1227 
1228 	/* Return TRUE for success */
1229 	return(TRUE);
1230 }
1231 
1232 /* Remove data at iterator */
xfdashboard_model_iter_remove(XfdashboardModelIter * self)1233 gboolean xfdashboard_model_iter_remove(XfdashboardModelIter *self)
1234 {
1235 	XfdashboardModelIterPrivate		*priv;
1236 	XfdashboardModelPrivate			*modelPriv;
1237 
1238 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, TRUE), FALSE);
1239 
1240 	priv=self->priv;
1241 	modelPriv=priv->model->priv;
1242 
1243 	/* Emit signal before removal to give signal handlers a changed
1244 	 * to access the data at iterator a last time.
1245 	 */
1246 	g_signal_emit(self, XfdashboardModelSignals[SIGNAL_ROW_REMOVED], 0, self);
1247 
1248 	/* If a function at model is provided to free data on removal
1249 	 * then call it now.
1250 	 */
1251 	if(modelPriv->freeDataCallback)
1252 	{
1253 		gpointer					oldData;
1254 
1255 		/* Get data to remove */
1256 		oldData=g_sequence_get(priv->iter);
1257 
1258 		/* Call function to free data */
1259 		(modelPriv->freeDataCallback)(oldData);
1260 	}
1261 
1262 	/* Remove data from model's data */
1263 	g_sequence_remove(priv->iter);
1264 
1265 	/* Return TRUE for success */
1266 	return(TRUE);
1267 }
1268 
1269 /* Check if row is filtered to which this iterator is pointing to */
xfdashboard_model_iter_filter(XfdashboardModelIter * self)1270 gboolean xfdashboard_model_iter_filter(XfdashboardModelIter *self)
1271 {
1272 	XfdashboardModelIterPrivate		*priv;
1273 	XfdashboardModelPrivate			*modelPriv;
1274 	gboolean						isVisible;
1275 
1276 	g_return_val_if_fail(_xfdashboard_model_iter_is_valid(self, TRUE), FALSE);
1277 
1278 	priv=self->priv;
1279 	modelPriv=priv->model->priv;
1280 	isVisible=TRUE;
1281 
1282 	/* Call user supplied filter callback function to determine if this
1283 	 * row should be filtered or not but only if filter function is set.
1284 	 */
1285 	if(modelPriv->filterCallback)
1286 	{
1287 		/* Determine if row is filtered */
1288 		isVisible=(modelPriv->filterCallback)(self, modelPriv->filterUserData);
1289 	}
1290 
1291 	/* Return filter status */
1292 	return(isVisible);
1293 }
1294