1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		Chris Lahey <clahey@ximian.com>
17  *
18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19  *
20  */
21 
22 #include "evolution-config.h"
23 
24 #include "e-selection-model.h"
25 
26 #include <glib/gi18n.h>
27 #include <gdk/gdkkeysyms.h>
28 
29 #include "e-marshal.h"
30 
31 G_DEFINE_TYPE (
32 	ESelectionModel,
33 	e_selection_model,
34 	G_TYPE_OBJECT)
35 
36 enum {
37 	CURSOR_CHANGED,
38 	CURSOR_ACTIVATED,
39 	SELECTION_CHANGED,
40 	SELECTION_ROW_CHANGED,
41 	LAST_SIGNAL
42 };
43 
44 static guint signals[LAST_SIGNAL] = { 0, };
45 
46 enum {
47 	PROP_0,
48 	PROP_SORTER,
49 	PROP_SELECTION_MODE,
50 	PROP_CURSOR_MODE
51 };
52 
53 inline static void
add_sorter(ESelectionModel * model,ESorter * sorter)54 add_sorter (ESelectionModel *model,
55             ESorter *sorter)
56 {
57 	model->sorter = sorter;
58 	if (sorter) {
59 		g_object_ref (sorter);
60 	}
61 }
62 
63 inline static void
drop_sorter(ESelectionModel * model)64 drop_sorter (ESelectionModel *model)
65 {
66 	if (model->sorter) {
67 		g_object_unref (model->sorter);
68 	}
69 	model->sorter = NULL;
70 }
71 
72 static void
selection_model_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)73 selection_model_set_property (GObject *object,
74                               guint property_id,
75                               const GValue *value,
76                               GParamSpec *pspec)
77 {
78 	ESelectionModel *model = E_SELECTION_MODEL (object);
79 
80 	switch (property_id) {
81 		case PROP_SORTER:
82 			drop_sorter (model);
83 			add_sorter (
84 				model, g_value_get_object (value) ?
85 				E_SORTER (g_value_get_object (value)) : NULL);
86 			break;
87 
88 		case PROP_SELECTION_MODE:
89 			model->mode = g_value_get_int (value);
90 			if (model->mode == GTK_SELECTION_SINGLE) {
91 				gint cursor_row = e_selection_model_cursor_row (model);
92 				gint cursor_col = e_selection_model_cursor_col (model);
93 				e_selection_model_do_something (model, cursor_row, cursor_col, 0);
94 			}
95 			break;
96 
97 		case PROP_CURSOR_MODE:
98 			model->cursor_mode = g_value_get_int (value);
99 			break;
100 	}
101 }
102 
103 static void
selection_model_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)104 selection_model_get_property (GObject *object,
105                               guint property_id,
106                               GValue *value,
107                               GParamSpec *pspec)
108 {
109 	ESelectionModel *model = E_SELECTION_MODEL (object);
110 
111 	switch (property_id) {
112 		case PROP_SORTER:
113 			g_value_set_object (value, model->sorter);
114 			break;
115 
116 		case PROP_SELECTION_MODE:
117 			g_value_set_int (value, model->mode);
118 			break;
119 
120 		case PROP_CURSOR_MODE:
121 			g_value_set_int (value, model->cursor_mode);
122 			break;
123 	}
124 }
125 
126 static void
selection_model_dispose(GObject * object)127 selection_model_dispose (GObject *object)
128 {
129 	ESelectionModel *model;
130 
131 	model = E_SELECTION_MODEL (object);
132 
133 	drop_sorter (model);
134 
135 	/* Chain up to parent's dispose() method. */
136 	G_OBJECT_CLASS (e_selection_model_parent_class)->dispose (object);
137 }
138 
139 static void
e_selection_model_class_init(ESelectionModelClass * class)140 e_selection_model_class_init (ESelectionModelClass *class)
141 {
142 	GObjectClass *object_class;
143 
144 	object_class = G_OBJECT_CLASS (class);
145 	object_class->set_property = selection_model_set_property;
146 	object_class->get_property = selection_model_get_property;
147 	object_class->dispose = selection_model_dispose;
148 
149 	signals[CURSOR_CHANGED] = g_signal_new (
150 		"cursor_changed",
151 		G_OBJECT_CLASS_TYPE (object_class),
152 		G_SIGNAL_RUN_LAST,
153 		G_STRUCT_OFFSET (ESelectionModelClass, cursor_changed),
154 		NULL, NULL,
155 		e_marshal_VOID__INT_INT,
156 		G_TYPE_NONE, 2,
157 		G_TYPE_INT,
158 		G_TYPE_INT);
159 
160 	signals[CURSOR_ACTIVATED] = g_signal_new (
161 		"cursor_activated",
162 		G_OBJECT_CLASS_TYPE (object_class),
163 		G_SIGNAL_RUN_LAST,
164 		G_STRUCT_OFFSET (ESelectionModelClass, cursor_activated),
165 		NULL, NULL,
166 		e_marshal_VOID__INT_INT,
167 		G_TYPE_NONE, 2,
168 		G_TYPE_INT,
169 		G_TYPE_INT);
170 
171 	signals[SELECTION_CHANGED] = g_signal_new (
172 		"selection_changed",
173 		G_OBJECT_CLASS_TYPE (object_class),
174 		G_SIGNAL_RUN_LAST,
175 		G_STRUCT_OFFSET (ESelectionModelClass, selection_changed),
176 		NULL, NULL,
177 		g_cclosure_marshal_VOID__VOID,
178 		G_TYPE_NONE, 0);
179 
180 	signals[SELECTION_ROW_CHANGED] = g_signal_new (
181 		"selection_row_changed",
182 		G_OBJECT_CLASS_TYPE (object_class),
183 		G_SIGNAL_RUN_LAST,
184 		G_STRUCT_OFFSET (ESelectionModelClass, selection_row_changed),
185 		NULL, NULL,
186 		g_cclosure_marshal_VOID__INT,
187 		G_TYPE_NONE, 1,
188 		G_TYPE_INT);
189 
190 	g_object_class_install_property (
191 		object_class,
192 		PROP_SORTER,
193 		g_param_spec_object (
194 			"sorter",
195 			"Sorter",
196 			NULL,
197 			E_TYPE_SORTER,
198 			G_PARAM_READWRITE));
199 
200 	g_object_class_install_property (
201 		object_class,
202 		PROP_SELECTION_MODE,
203 		g_param_spec_int (
204 			"selection_mode",
205 			"Selection Mode",
206 			NULL,
207 			GTK_SELECTION_NONE,
208 			GTK_SELECTION_MULTIPLE,
209 			GTK_SELECTION_SINGLE,
210 			G_PARAM_READWRITE));
211 
212 	g_object_class_install_property (
213 		object_class,
214 		PROP_CURSOR_MODE,
215 		g_param_spec_int (
216 			"cursor_mode",
217 			"Cursor Mode",
218 			NULL,
219 			E_CURSOR_LINE,
220 			E_CURSOR_SPREADSHEET,
221 			E_CURSOR_LINE,
222 			G_PARAM_READWRITE));
223 }
224 
225 static void
e_selection_model_init(ESelectionModel * model)226 e_selection_model_init (ESelectionModel *model)
227 {
228 	model->mode = GTK_SELECTION_MULTIPLE;
229 	model->cursor_mode = E_CURSOR_SIMPLE;
230 	model->old_selection = -1;
231 }
232 
233 /**
234  * e_selection_model_is_row_selected
235  * @model: #ESelectionModel to check
236  * @n: The row to check
237  *
238  * This routine calculates whether the given row is selected.
239  *
240  * Returns: %TRUE if the given row is selected
241  */
242 gboolean
e_selection_model_is_row_selected(ESelectionModel * model,gint n)243 e_selection_model_is_row_selected (ESelectionModel *model,
244                                    gint n)
245 {
246 	ESelectionModelClass *class;
247 
248 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), FALSE);
249 
250 	class = E_SELECTION_MODEL_GET_CLASS (model);
251 	g_return_val_if_fail (class != NULL, FALSE);
252 	g_return_val_if_fail (class->is_row_selected != NULL, FALSE);
253 
254 	return class->is_row_selected (model, n);
255 }
256 
257 /**
258  * e_selection_model_foreach
259  * @model: #ESelectionModel to traverse
260  * @callback: The callback function to call back.
261  * @closure: The closure
262  *
263  * This routine calls the given callback function once for each
264  * selected row, passing closure as the closure.
265  */
266 void
e_selection_model_foreach(ESelectionModel * model,EForeachFunc callback,gpointer closure)267 e_selection_model_foreach (ESelectionModel *model,
268                            EForeachFunc callback,
269                            gpointer closure)
270 {
271 	ESelectionModelClass *class;
272 
273 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
274 	g_return_if_fail (callback != NULL);
275 
276 	class = E_SELECTION_MODEL_GET_CLASS (model);
277 	g_return_if_fail (class != NULL);
278 	g_return_if_fail (class->foreach != NULL);
279 
280 	class->foreach (model, callback, closure);
281 }
282 
283 /**
284  * e_selection_model_clear
285  * @model: #ESelectionModel to clear
286  *
287  * This routine clears the selection to no rows selected.
288  */
289 void
e_selection_model_clear(ESelectionModel * model)290 e_selection_model_clear (ESelectionModel *model)
291 {
292 	ESelectionModelClass *class;
293 
294 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
295 
296 	class = E_SELECTION_MODEL_GET_CLASS (model);
297 	g_return_if_fail (class != NULL);
298 	g_return_if_fail (class->clear != NULL);
299 
300 	class->clear (model);
301 }
302 
303 /**
304  * e_selection_model_selected_count
305  * @model: #ESelectionModel to count
306  *
307  * This routine calculates the number of rows selected.
308  *
309  * Returns: The number of rows selected in the given model.
310  */
311 gint
e_selection_model_selected_count(ESelectionModel * model)312 e_selection_model_selected_count (ESelectionModel *model)
313 {
314 	ESelectionModelClass *class;
315 
316 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), 0);
317 
318 	class = E_SELECTION_MODEL_GET_CLASS (model);
319 	g_return_val_if_fail (class != NULL, 0);
320 	g_return_val_if_fail (class->selected_count != NULL, 0);
321 
322 	return class->selected_count (model);
323 }
324 
325 /**
326  * e_selection_model_select_all
327  * @model: #ESelectionModel to select all
328  *
329  * This routine selects all the rows in the given
330  * #ESelectionModel.
331  */
332 void
e_selection_model_select_all(ESelectionModel * model)333 e_selection_model_select_all (ESelectionModel *model)
334 {
335 	ESelectionModelClass *class;
336 
337 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
338 
339 	class = E_SELECTION_MODEL_GET_CLASS (model);
340 	g_return_if_fail (class != NULL);
341 	g_return_if_fail (class->select_all != NULL);
342 
343 	class->select_all (model);
344 }
345 
346 gint
e_selection_model_row_count(ESelectionModel * model)347 e_selection_model_row_count (ESelectionModel *model)
348 {
349 	ESelectionModelClass *class;
350 
351 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), 0);
352 
353 	class = E_SELECTION_MODEL_GET_CLASS (model);
354 	g_return_val_if_fail (class != NULL, 0);
355 	g_return_val_if_fail (class->row_count != NULL, 0);
356 
357 	return class->row_count (model);
358 }
359 
360 void
e_selection_model_change_one_row(ESelectionModel * model,gint row,gboolean grow)361 e_selection_model_change_one_row (ESelectionModel *model,
362                                   gint row,
363                                   gboolean grow)
364 {
365 	ESelectionModelClass *class;
366 
367 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
368 
369 	class = E_SELECTION_MODEL_GET_CLASS (model);
370 	g_return_if_fail (class != NULL);
371 	g_return_if_fail (class->change_one_row != NULL);
372 
373 	return class->change_one_row (model, row, grow);
374 }
375 
376 void
e_selection_model_change_cursor(ESelectionModel * model,gint row,gint col)377 e_selection_model_change_cursor (ESelectionModel *model,
378                                  gint row,
379                                  gint col)
380 {
381 	ESelectionModelClass *class;
382 
383 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
384 
385 	class = E_SELECTION_MODEL_GET_CLASS (model);
386 	g_return_if_fail (class != NULL);
387 	g_return_if_fail (class->change_cursor != NULL);
388 
389 	class->change_cursor (model, row, col);
390 }
391 
392 gint
e_selection_model_cursor_row(ESelectionModel * model)393 e_selection_model_cursor_row (ESelectionModel *model)
394 {
395 	ESelectionModelClass *class;
396 
397 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), -1);
398 
399 	class = E_SELECTION_MODEL_GET_CLASS (model);
400 	g_return_val_if_fail (class != NULL, -1);
401 	g_return_val_if_fail (class->cursor_row != NULL, -1);
402 
403 	return class->cursor_row (model);
404 }
405 
406 gint
e_selection_model_cursor_col(ESelectionModel * model)407 e_selection_model_cursor_col (ESelectionModel *model)
408 {
409 	ESelectionModelClass *class;
410 
411 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), -1);
412 
413 	class = E_SELECTION_MODEL_GET_CLASS (model);
414 	g_return_val_if_fail (class != NULL, -1);
415 	g_return_val_if_fail (class->cursor_col != NULL, -1);
416 
417 	return class->cursor_col (model);
418 }
419 
420 void
e_selection_model_select_single_row(ESelectionModel * model,gint row)421 e_selection_model_select_single_row (ESelectionModel *model,
422                                      gint row)
423 {
424 	ESelectionModelClass *class;
425 
426 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
427 
428 	class = E_SELECTION_MODEL_GET_CLASS (model);
429 	g_return_if_fail (class != NULL);
430 	g_return_if_fail (class->select_single_row != NULL);
431 
432 	class->select_single_row (model, row);
433 }
434 
435 void
e_selection_model_toggle_single_row(ESelectionModel * model,gint row)436 e_selection_model_toggle_single_row (ESelectionModel *model,
437                                      gint row)
438 {
439 	ESelectionModelClass *class;
440 
441 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
442 
443 	class = E_SELECTION_MODEL_GET_CLASS (model);
444 	g_return_if_fail (class != NULL);
445 	g_return_if_fail (class->toggle_single_row != NULL);
446 
447 	class->toggle_single_row (model, row);
448 }
449 
450 void
e_selection_model_move_selection_end(ESelectionModel * model,gint row)451 e_selection_model_move_selection_end (ESelectionModel *model,
452                                       gint row)
453 {
454 	ESelectionModelClass *class;
455 
456 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
457 
458 	class = E_SELECTION_MODEL_GET_CLASS (model);
459 	g_return_if_fail (class != NULL);
460 	g_return_if_fail (class->move_selection_end != NULL);
461 
462 	class->move_selection_end (model, row);
463 }
464 
465 void
e_selection_model_set_selection_end(ESelectionModel * model,gint row)466 e_selection_model_set_selection_end (ESelectionModel *model,
467                                      gint row)
468 {
469 	ESelectionModelClass *class;
470 
471 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
472 
473 	class = E_SELECTION_MODEL_GET_CLASS (model);
474 	g_return_if_fail (class != NULL);
475 	g_return_if_fail (class->set_selection_end != NULL);
476 
477 	class->set_selection_end (model, row);
478 }
479 
480 /**
481  * e_selection_model_do_something
482  * @model: #ESelectionModel to do something to.
483  * @row: The row to do something in.
484  * @col: The col to do something in.
485  * @state: The state in which to do something.
486  *
487  * This routine does whatever is appropriate as if the user clicked
488  * the mouse in the given row and column.
489  */
490 void
e_selection_model_do_something(ESelectionModel * model,guint row,guint col,GdkModifierType state)491 e_selection_model_do_something (ESelectionModel *model,
492                                 guint row,
493                                 guint col,
494                                 GdkModifierType state)
495 {
496 	gint shift_p = state & GDK_SHIFT_MASK;
497 	gint ctrl_p = state & GDK_CONTROL_MASK;
498 	gint row_count;
499 
500 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
501 
502 	model->old_selection = -1;
503 
504 	if (row == -1 && col != -1)
505 		row = 0;
506 	if (col == -1 && row != -1)
507 		col = 0;
508 
509 	row_count = e_selection_model_row_count (model);
510 	if (row_count >= 0 && row < row_count) {
511 		switch (model->mode) {
512 		case GTK_SELECTION_SINGLE:
513 			e_selection_model_select_single_row (model, row);
514 			break;
515 		case GTK_SELECTION_BROWSE:
516 		case GTK_SELECTION_MULTIPLE:
517 			if (shift_p) {
518 				e_selection_model_set_selection_end (model, row);
519 			} else {
520 				if (ctrl_p) {
521 					e_selection_model_toggle_single_row (model, row);
522 				} else {
523 					e_selection_model_select_single_row (model, row);
524 				}
525 			}
526 			break;
527 		default:
528 			g_return_if_reached ();
529 			break;
530 		}
531 		e_selection_model_change_cursor (model, row, col);
532 		g_signal_emit (
533 			model,
534 			signals[CURSOR_CHANGED], 0,
535 			row, col);
536 		g_signal_emit (
537 			model,
538 			signals[CURSOR_ACTIVATED], 0,
539 			row, col);
540 	}
541 }
542 
543 /**
544  * e_selection_model_maybe_do_something
545  * @model: #ESelectionModel to do something to.
546  * @row: The row to do something in.
547  * @col: The col to do something in.
548  * @state: The state in which to do something.
549  *
550  * If this row is selected, this routine just moves the cursor row and
551  * column.  Otherwise, it does the same thing as
552  * e_selection_model_do_something().  This is for being used on
553  * right clicks and other events where if the user hit the selection,
554  * they don't want it to change.
555  */
556 gboolean
e_selection_model_maybe_do_something(ESelectionModel * model,guint row,guint col,GdkModifierType state)557 e_selection_model_maybe_do_something (ESelectionModel *model,
558                                       guint row,
559                                       guint col,
560                                       GdkModifierType state)
561 {
562 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), FALSE);
563 
564 	model->old_selection = -1;
565 
566 	if (e_selection_model_is_row_selected (model, row)) {
567 		e_selection_model_change_cursor (model, row, col);
568 		g_signal_emit (
569 			model,
570 			signals[CURSOR_CHANGED], 0,
571 			row, col);
572 		return FALSE;
573 	} else {
574 		e_selection_model_do_something (model, row, col, state);
575 		return TRUE;
576 	}
577 }
578 
579 void
e_selection_model_right_click_down(ESelectionModel * model,guint row,guint col,GdkModifierType state)580 e_selection_model_right_click_down (ESelectionModel *model,
581                                     guint row,
582                                     guint col,
583                                     GdkModifierType state)
584 {
585 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
586 
587 	if (model->mode == GTK_SELECTION_SINGLE) {
588 		model->old_selection =
589 			e_selection_model_cursor_row (model);
590 		e_selection_model_select_single_row (model, row);
591 	} else {
592 		e_selection_model_maybe_do_something (
593 			model, row, col, state);
594 	}
595 }
596 
597 void
e_selection_model_right_click_up(ESelectionModel * model)598 e_selection_model_right_click_up (ESelectionModel *model)
599 {
600 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
601 
602 	if (model->mode != GTK_SELECTION_SINGLE)
603 		return;
604 
605 	if (model->old_selection == -1)
606 		return;
607 
608 	e_selection_model_select_single_row (
609 		model, model->old_selection);
610 }
611 
612 void
e_selection_model_select_as_key_press(ESelectionModel * model,guint row,guint col,GdkModifierType state)613 e_selection_model_select_as_key_press (ESelectionModel *model,
614                                        guint row,
615                                        guint col,
616                                        GdkModifierType state)
617 {
618 	gint cursor_activated = TRUE;
619 
620 	gint shift_p = state & GDK_SHIFT_MASK;
621 	gint ctrl_p = state & GDK_CONTROL_MASK;
622 
623 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
624 
625 	model->old_selection = -1;
626 
627 	switch (model->mode) {
628 	case GTK_SELECTION_BROWSE:
629 	case GTK_SELECTION_MULTIPLE:
630 		if (shift_p) {
631 			e_selection_model_set_selection_end (model, row);
632 		} else if (!ctrl_p) {
633 			e_selection_model_select_single_row (model, row);
634 		} else
635 			cursor_activated = FALSE;
636 		break;
637 	case GTK_SELECTION_SINGLE:
638 		e_selection_model_select_single_row (model, row);
639 		break;
640 	default:
641 		g_return_if_reached ();
642 		break;
643 	}
644 	if (row != -1) {
645 		e_selection_model_change_cursor (model, row, col);
646 		g_signal_emit (
647 			model,
648 			signals[CURSOR_CHANGED], 0,
649 			row, col);
650 		if (cursor_activated)
651 			g_signal_emit (
652 				model,
653 				signals[CURSOR_ACTIVATED], 0,
654 				row, col);
655 	}
656 }
657 
658 static gint
move_selection(ESelectionModel * model,gboolean up,GdkModifierType state)659 move_selection (ESelectionModel *model,
660                 gboolean up,
661                 GdkModifierType state)
662 {
663 	gint row = e_selection_model_cursor_row (model);
664 	gint col = e_selection_model_cursor_col (model);
665 	gint row_count;
666 
667 	/* there is no selected row when row is -1 */
668 	if (row != -1 && model->sorter != NULL)
669 		row = e_sorter_model_to_sorted (model->sorter, row);
670 
671 	if (up)
672 		row--;
673 	else
674 		row++;
675 	if (row < 0)
676 		row = 0;
677 	row_count = e_selection_model_row_count (model);
678 	if (row >= row_count)
679 		row = row_count - 1;
680 	if (model->sorter != NULL)
681 		row = e_sorter_sorted_to_model (model->sorter, row);
682 
683 	e_selection_model_select_as_key_press (model, row, col, state);
684 	return TRUE;
685 }
686 
687 /**
688  * e_selection_model_key_press
689  * @model: #ESelectionModel to affect.
690  * @key: The event.
691  *
692  * This routine does whatever is appropriate as if the user pressed
693  * the given key.
694  *
695  * Returns: %TRUE if the #ESelectionModel used the key.
696  */
697 gboolean
e_selection_model_key_press(ESelectionModel * model,GdkEventKey * key)698 e_selection_model_key_press (ESelectionModel *model,
699                              GdkEventKey *key)
700 {
701 	g_return_val_if_fail (E_IS_SELECTION_MODEL (model), FALSE);
702 	g_return_val_if_fail (key != NULL, FALSE);
703 
704 	model->old_selection = -1;
705 
706 	switch (key->keyval) {
707 	case GDK_KEY_Up:
708 	case GDK_KEY_KP_Up:
709 		return move_selection (model, TRUE, key->state);
710 	case GDK_KEY_Down:
711 	case GDK_KEY_KP_Down:
712 		return move_selection (model, FALSE, key->state);
713 	case GDK_KEY_space:
714 	case GDK_KEY_KP_Space:
715 		if (model->mode != GTK_SELECTION_SINGLE) {
716 			gint row = e_selection_model_cursor_row (model);
717 			gint col = e_selection_model_cursor_col (model);
718 			if (row == -1)
719 				break;
720 
721 			e_selection_model_toggle_single_row (model, row);
722 			g_signal_emit (
723 				model,
724 				signals[CURSOR_ACTIVATED], 0,
725 				row, col);
726 			return TRUE;
727 		}
728 		break;
729 	case GDK_KEY_Return:
730 	case GDK_KEY_KP_Enter:
731 		if (model->mode != GTK_SELECTION_SINGLE) {
732 			gint row = e_selection_model_cursor_row (model);
733 			gint col = e_selection_model_cursor_col (model);
734 			e_selection_model_select_single_row (model, row);
735 			g_signal_emit (
736 				model,
737 				signals[CURSOR_ACTIVATED], 0,
738 				row, col);
739 			return TRUE;
740 		}
741 		break;
742 	case GDK_KEY_Home:
743 	case GDK_KEY_KP_Home:
744 		if (model->cursor_mode == E_CURSOR_LINE) {
745 			gint row = 0;
746 			gint cursor_col = e_selection_model_cursor_col (model);
747 
748 			if (model->sorter != NULL)
749 				row = e_sorter_sorted_to_model (
750 					model->sorter, row);
751 			e_selection_model_select_as_key_press (
752 				model, row, cursor_col, key->state);
753 			return TRUE;
754 		}
755 		break;
756 	case GDK_KEY_End:
757 	case GDK_KEY_KP_End:
758 		if (model->cursor_mode == E_CURSOR_LINE) {
759 			gint row = e_selection_model_row_count (model) - 1;
760 			gint cursor_col = e_selection_model_cursor_col (model);
761 
762 			if (model->sorter != NULL)
763 				row = e_sorter_sorted_to_model (
764 					model->sorter, row);
765 			e_selection_model_select_as_key_press (
766 				model, row, cursor_col, key->state);
767 			return TRUE;
768 		}
769 		break;
770 	}
771 	return FALSE;
772 }
773 
774 void
e_selection_model_cursor_changed(ESelectionModel * model,gint row,gint col)775 e_selection_model_cursor_changed (ESelectionModel *model,
776                                   gint row,
777                                   gint col)
778 {
779 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
780 
781 	g_signal_emit (model, signals[CURSOR_CHANGED], 0, row, col);
782 }
783 
784 void
e_selection_model_cursor_activated(ESelectionModel * model,gint row,gint col)785 e_selection_model_cursor_activated (ESelectionModel *model,
786                                     gint row,
787                                     gint col)
788 {
789 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
790 
791 	g_signal_emit (model, signals[CURSOR_ACTIVATED], 0, row, col);
792 }
793 
794 void
e_selection_model_selection_changed(ESelectionModel * model)795 e_selection_model_selection_changed (ESelectionModel *model)
796 {
797 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
798 
799 	g_signal_emit (model, signals[SELECTION_CHANGED], 0);
800 }
801 
802 void
e_selection_model_selection_row_changed(ESelectionModel * model,gint row)803 e_selection_model_selection_row_changed (ESelectionModel *model,
804                                          gint row)
805 {
806 	g_return_if_fail (E_IS_SELECTION_MODEL (model));
807 
808 	g_signal_emit (model, signals[SELECTION_ROW_CHANGED], 0, row);
809 }
810