1 /* abstract base class for items which can form a row in a tally
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 /*
31 #define DEBUG
32 #define DEBUG_VIEWCHILD
33 */
34
35 /* Time each refresh
36 #define DEBUG_TIME
37 */
38
39 #include "ip.h"
40
41 static vObjectClass *parent_class = NULL;
42
43 static GSList *view_scannable = NULL;
44
45 static GSList *view_resettable = NULL;
46
47 void
view_scannable_register(View * view)48 view_scannable_register( View *view )
49 {
50 /* Must have a scan method.
51 */
52 g_assert( VIEW_GET_CLASS( view )->scan );
53
54 if( !view->scannable ) {
55 view_scannable = g_slist_prepend( view_scannable, view );
56 view->scannable = TRUE;
57 }
58 }
59
60 void
view_scannable_unregister(View * view)61 view_scannable_unregister( View *view )
62 {
63 if( view->scannable ) {
64 view_scannable = g_slist_remove( view_scannable, view );
65 view->scannable = FALSE;
66 }
67 }
68
69 gboolean
view_scan_all(void)70 view_scan_all( void )
71 {
72 if( slist_map( view_scannable, (SListMapFn) view_scan, NULL ) )
73 return( FALSE );
74
75 view_reset_all();
76
77 return( TRUE );
78 }
79
80 void
view_resettable_register(View * view)81 view_resettable_register( View *view )
82 {
83 /* Must have a reset method.
84 */
85 g_assert( VIEW_GET_CLASS( view )->reset );
86
87 if( !view->resettable ) {
88 view_resettable = g_slist_prepend( view_resettable, view );
89 view->resettable = TRUE;
90 }
91 }
92
93 void
view_resettable_unregister(View * view)94 view_resettable_unregister( View *view )
95 {
96 if( view->resettable ) {
97 view_resettable = g_slist_remove( view_resettable, view );
98 view->resettable = FALSE;
99 }
100 }
101
102 void
view_reset_all(void)103 view_reset_all( void )
104 {
105 (void) slist_map( view_resettable, (SListMapFn) view_reset, NULL );
106 }
107
108 /* Should a viewchild be displayed? If model->display is true, also give the
109 * enclosing view a chance to filter.
110 */
111 static gboolean
view_viewchild_display(ViewChild * viewchild)112 view_viewchild_display( ViewChild *viewchild )
113 {
114 View *parent_view = viewchild->parent_view;
115 Model *child_model = viewchild->child_model;
116 ViewClass *parent_view_class = VIEW_GET_CLASS( parent_view );
117
118 if( child_model->display && parent_view_class->display )
119 return( parent_view_class->display( parent_view,
120 child_model ) );
121
122 return( child_model->display );
123 }
124
125 /* One of the children of the model we watch has changed ... create or destroy
126 * the child view as required.
127 */
128 static void
view_viewchild_changed(Model * model,ViewChild * viewchild)129 view_viewchild_changed( Model *model, ViewChild *viewchild )
130 {
131 gboolean display = view_viewchild_display( viewchild );
132 View *child = viewchild->child_view;
133
134 if( !display && child ) {
135 #ifdef DEBUG_VIEWCHILD
136 printf( "view_viewchild_changed: %s \"%s\", removing view\n",
137 G_OBJECT_TYPE_NAME( model ),
138 NN( IOBJECT( model )->name ) );
139
140 printf( "view_viewchild_changed: %s\n",
141 G_OBJECT_TYPE_NAME( child ) );
142 #endif /*DEBUG_VIEWCHILD*/
143
144 DESTROY_GTK( child );
145 }
146 else if( display && !child ) {
147 #ifdef DEBUG_VIEWCHILD
148 printf( "view_viewchild_changed: %s \"%s\", adding view\n",
149 G_OBJECT_TYPE_NAME( model ),
150 NN( IOBJECT( model )->name ) );
151 #endif /*DEBUG_VIEWCHILD*/
152
153 model_view_new( model, viewchild->parent_view );
154 }
155 }
156
157 static ViewChild *
view_viewchild_new(View * parent_view,Model * child_model)158 view_viewchild_new( View *parent_view, Model *child_model )
159 {
160 ViewChild *viewchild;
161
162 #ifdef DEBUG_VIEWCHILD
163 printf( "view_viewchild_new: view \"%s\" watching %s \"%s\"\n",
164 G_OBJECT_TYPE_NAME( parent_view ),
165 G_OBJECT_TYPE_NAME( child_model ),
166 NN( IOBJECT( child_model )->name ) );
167 #endif /*DEBUG_VIEWCHILD*/
168
169 if( !(viewchild = INEW( NULL, ViewChild )) )
170 return( NULL );
171
172 viewchild->parent_view = parent_view;
173 viewchild->child_model = child_model;
174 viewchild->child_model_changed_sid =
175 g_signal_connect( child_model, "changed",
176 G_CALLBACK( view_viewchild_changed ), viewchild );
177 viewchild->child_view = NULL;
178
179 parent_view->managed =
180 g_slist_append( parent_view->managed, viewchild );
181
182 return( viewchild );
183 }
184
185 static void *
view_viewchild_destroy(ViewChild * viewchild)186 view_viewchild_destroy( ViewChild *viewchild )
187 {
188 View *parent_view = viewchild->parent_view;
189 View *child_view = viewchild->child_view;
190
191 #ifdef DEBUG_VIEWCHILD
192 printf( "view_viewchild_destroy: view %s watching model %s\n",
193 G_OBJECT_TYPE_NAME( viewchild->parent_view ),
194 G_OBJECT_TYPE_NAME( viewchild->child_model ) );
195 #endif /*DEBUG_VIEWCHILD*/
196
197 if( child_view ) {
198 g_assert( child_view->parent == parent_view );
199 child_view->parent = NULL;
200 }
201 FREESID( viewchild->child_model_changed_sid, viewchild->child_model );
202 parent_view->managed =
203 g_slist_remove( parent_view->managed, viewchild );
204
205 im_free( viewchild );
206
207 return( NULL );
208 }
209
210 static void *
view_viewchild_test_child_model(ViewChild * viewchild,Model * child_model)211 view_viewchild_test_child_model( ViewChild *viewchild, Model *child_model )
212 {
213 #ifdef DEBUG
214 printf( "view_viewchild_test_child_model: model %s \"%s\"\n",
215 G_OBJECT_TYPE_NAME( child_model ),
216 NN( IOBJECT( child_model )->name ) );
217 #endif /*DEBUG*/
218
219 if( viewchild->child_model == child_model )
220 return( viewchild );
221
222 return( NULL );
223 }
224
225 /* Do we have a model?
226 */
227 gboolean
view_hasmodel(View * view)228 view_hasmodel( View *view )
229 {
230 return( VOBJECT( view )->iobject != NULL );
231 }
232
233 void *
view_model_test(View * view,Model * model)234 view_model_test( View *view, Model *model )
235 {
236 if( VOBJECT( view )->iobject == IOBJECT( model ) )
237 return( view );
238
239 return( NULL );
240 }
241
242 /* Link to enclosing model and view.
243 */
244 void
view_link(View * view,Model * model,View * parent)245 view_link( View *view, Model *model, View *parent )
246 {
247 VIEW_GET_CLASS( view )->link( view, model, parent );
248 }
249
250 /* Add a child.
251 */
252 void
view_child_add(View * parent,View * child)253 view_child_add( View *parent, View *child )
254 {
255 VIEW_GET_CLASS( parent )->child_add( parent, child );
256 }
257
258 /* Remove a child.
259 */
260 void
view_child_remove(View * child)261 view_child_remove( View *child )
262 {
263 View *parent = child->parent;
264
265 VIEW_GET_CLASS( parent )->child_remove( parent, child );
266 }
267
268 /* Child needs repositioning.
269 */
270 void
view_child_position(View * child)271 view_child_position( View *child )
272 {
273 View *parent = child->parent;
274
275 VIEW_GET_CLASS( parent )->child_position( parent, child );
276 }
277
278 /* Pop child to front of stacking order.
279 */
280 void
view_child_front(View * child)281 view_child_front( View *child )
282 {
283 View *parent = child->parent;
284
285 if( parent )
286 VIEW_GET_CLASS( parent )->child_front( parent, child );
287 }
288
289 /* Break link to model.
290 */
291 void
view_unlink(View * view)292 view_unlink( View *view )
293 {
294 g_assert( view != NULL );
295 g_assert( VOBJECT( view )->iobject != NULL );
296 g_assert( IS_VIEW( view ) && IS_MODEL( VOBJECT( view )->iobject ) );
297
298 FREESID( view->pos_changed_sid, VOBJECT( view )->iobject );
299 FREESID( view->scrollto_sid, VOBJECT( view )->iobject );
300 FREESID( view->layout_sid, VOBJECT( view )->iobject );
301 FREESID( view->reset_sid, VOBJECT( view )->iobject );
302 FREESID( view->front_sid, VOBJECT( view )->iobject );
303 FREESID( view->child_add_sid, VOBJECT( view )->iobject );
304 FREESID( view->child_remove_sid, VOBJECT( view )->iobject );
305 FREESID( view->child_detach_sid, VOBJECT( view )->iobject );
306 FREESID( view->child_attach_sid, VOBJECT( view )->iobject );
307 }
308
309 static void
view_destroy(GtkObject * object)310 view_destroy( GtkObject *object )
311 {
312 View *view;
313
314 g_return_if_fail( object != NULL );
315 g_return_if_fail( IS_VIEW( object ) );
316
317 view = VIEW( object );
318
319 #ifdef DEBUG
320 printf( "view_destroy: \"%s\"\n", G_OBJECT_TYPE_NAME( object ) );
321 #endif /*DEBUG*/
322
323 /* We're probably changing the size of our enclosing column.
324 */
325 view_resize( view );
326
327 if( view->scannable )
328 view_scannable_unregister( view );
329 if( view->resettable )
330 view_resettable_unregister( view );
331
332 if( VOBJECT( view )->iobject )
333 view_unlink( view );
334
335 if( view->parent )
336 view_child_remove( view );
337
338 slist_map( view->managed,
339 (SListMapFn) view_viewchild_destroy, NULL );
340
341 GTK_OBJECT_CLASS( parent_class )->destroy( object );
342 }
343
344 static void
view_finalize(GObject * gobject)345 view_finalize( GObject *gobject )
346 {
347 #ifdef DEBUG
348 printf( "view_finalize: \"%s\"\n", G_OBJECT_TYPE_NAME( gobject ) );
349 #endif /*DEBUG*/
350
351 G_OBJECT_CLASS( parent_class )->finalize( gobject );
352 }
353
354 /* Called for model pos_changed signal ... queue a refresh.
355 */
356 static void
view_model_pos_changed(Model * model,View * view)357 view_model_pos_changed( Model *model, View *view )
358 {
359 g_assert( IS_MODEL( model ) );
360 g_assert( IS_VIEW( view ) );
361
362 #ifdef DEBUG
363 printf( "view_model_pos_changed: %s %s \"%s\"\n",
364 G_OBJECT_TYPE_NAME( view ),
365 G_OBJECT_TYPE_NAME( model ),
366 NN( IOBJECT( model )->name ) );
367 #endif /*DEBUG*/
368
369 vobject_refresh_queue( VOBJECT( view ) );
370 }
371
372 /* Called for model scrollto signal ... try scrolling.
373 */
374 static void
view_model_scrollto(Model * model,ModelScrollPosition position,View * view)375 view_model_scrollto( Model *model, ModelScrollPosition position, View *view )
376 {
377 g_assert( IS_MODEL( model ) );
378 g_assert( IS_VIEW( view ) );
379
380 #ifdef DEBUG
381 printf( "view_model_scrollto: %s\n", IOBJECT( model )->name );
382 #endif /*DEBUG*/
383
384 view_scrollto( view, position );
385 }
386
387 /* Called for model layout signal ... try to lay out children.
388 */
389 static void
view_model_layout(Model * model,View * view)390 view_model_layout( Model *model, View *view )
391 {
392 g_assert( IS_MODEL( model ) );
393 g_assert( IS_VIEW( view ) );
394
395 #ifdef DEBUG
396 printf( "view_model_layout: %s\n", IOBJECT( model )->name );
397 #endif /*DEBUG*/
398
399 view_layout( view );
400 }
401
402 /* Called for model reset signal ... try resetting.
403 */
404 static void
view_model_reset(Model * model,View * view)405 view_model_reset( Model *model, View *view )
406 {
407 g_assert( IS_MODEL( model ) );
408 g_assert( IS_VIEW( view ) );
409
410 #ifdef DEBUG
411 printf( "view_model_reset: %s\n", IOBJECT( model )->name );
412 #endif /*DEBUG*/
413
414 view_reset( view );
415 }
416
417 /* Called for model front signal ... bring view to front.
418 */
419 static void
view_model_front(Model * model,View * view)420 view_model_front( Model *model, View *view )
421 {
422 g_assert( IS_MODEL( model ) );
423 g_assert( IS_VIEW( view ) );
424
425 #ifdef DEBUG
426 printf( "view_model_front: model %s \"%s\"\n",
427 G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) );
428 printf( "\tview %s\n", G_OBJECT_TYPE_NAME( view ) );
429 #endif /*DEBUG*/
430
431 view_child_front( view );
432 }
433
434 /* Called for model child_add signal ... start watching that child.
435 */
436 static void
view_model_child_add(Model * parent,Model * child,int pos,View * parent_view)437 view_model_child_add( Model *parent, Model *child, int pos, View *parent_view )
438 {
439 ViewChild *viewchild;
440
441 #ifdef DEBUG
442 printf( "view_model_child_add: parent %s \"%s\"\n",
443 G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) );
444 #endif /*DEBUG*/
445
446 g_assert( IS_MODEL( parent ) );
447 g_assert( IS_MODEL( child ) );
448 g_assert( IS_VIEW( parent_view ) );
449
450 #ifdef DEBUG
451 viewchild = slist_map( parent_view->managed,
452 (SListMapFn) view_viewchild_test_child_model, child );
453 g_assert( !viewchild );
454 #endif /*DEBUG*/
455
456 viewchild = view_viewchild_new( parent_view, child );
457 view_viewchild_changed( child, viewchild );
458 }
459
460 /* Called for model child_remove signal ... stop watching that child. child
461 * may have been finalized already.
462 */
463 static void
view_model_child_remove(iContainer * parent,iContainer * child,View * parent_view)464 view_model_child_remove( iContainer *parent, iContainer *child,
465 View *parent_view )
466 {
467 ViewChild *viewchild;
468
469 #ifdef DEBUG
470 {
471 printf( "view_model_child_remove: child %s \"%s\"; "
472 "parent %s \"%s\"\n",
473 G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ),
474 G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) );
475
476 printf( "view_model_child_remove: parent_view = view of %s \"%s\"\n",
477 G_OBJECT_TYPE_NAME( VOBJECT( parent_view )->iobject ),
478 NN( IOBJECT( VOBJECT( parent_view )->iobject )->name ) );
479 }
480 #endif /*DEBUG*/
481
482 viewchild = slist_map( parent_view->managed,
483 (SListMapFn) view_viewchild_test_child_model, child );
484
485 g_assert( viewchild );
486
487 (void) view_viewchild_destroy( viewchild );
488 }
489
490 /* Called for model parent_detach signal ... remove the viewchild for this
491 * child. child_attach will build a new one.
492 */
493 static void
view_model_child_detach(iContainer * old_parent,iContainer * child,View * old_parent_view)494 view_model_child_detach( iContainer *old_parent, iContainer *child,
495 View *old_parent_view )
496 {
497 ViewChild *viewchild;
498
499 #ifdef DEBUG
500 {
501 printf( "view_model_child_detach: child %s \"%s\"; "
502 "old_parent %s \"%s\"\n",
503 G_OBJECT_TYPE_NAME( child ),
504 NN( IOBJECT( child )->name ),
505 G_OBJECT_TYPE_NAME( old_parent ),
506 NN( IOBJECT( old_parent )->name ) );
507
508 printf( "view_model_child_detach: old_parent_view = "
509 "view of %s \"%s\"\n",
510 G_OBJECT_TYPE_NAME( VOBJECT( old_parent_view )->iobject ),
511 NN( IOBJECT( VOBJECT( old_parent_view )->iobject )->name ) );
512 }
513 #endif /*DEBUG*/
514
515 viewchild = slist_map( old_parent_view->managed,
516 (SListMapFn) view_viewchild_test_child_model, child );
517
518 g_assert( viewchild );
519 g_assert( !child->temp_view );
520
521 child->temp_view = viewchild->child_view;
522
523 (void) view_viewchild_destroy( viewchild );
524 }
525
526 /* Called for model child_attach signal ... make a new viewchild on the new
527 * parent view.
528 */
529 static void
view_model_child_attach(iContainer * new_parent,iContainer * child,int pos,View * new_parent_view)530 view_model_child_attach( iContainer *new_parent, iContainer *child, int pos,
531 View *new_parent_view )
532 {
533 ViewChild *viewchild;
534
535 g_assert( !slist_map( new_parent_view->managed,
536 (SListMapFn) view_viewchild_test_child_model, child ) );
537
538 viewchild = view_viewchild_new( new_parent_view, MODEL( child ) );
539
540 g_assert( child->temp_view && IS_VIEW( child->temp_view ) );
541 viewchild->child_view = child->temp_view;
542 child->temp_view = NULL;
543
544 viewchild->child_view->parent = new_parent_view;
545 }
546
547 static void *
view_real_link_sub(Model * child_model,View * parent_view)548 view_real_link_sub( Model *child_model, View *parent_view )
549 {
550 ViewChild *viewchild;
551
552 viewchild = view_viewchild_new( parent_view, child_model );
553 view_viewchild_changed( child_model, viewchild );
554
555 return( NULL );
556 }
557
558 /* Link to model and to enclosing view.
559 */
560 static void
view_real_link(View * view,Model * model,View * parent_view)561 view_real_link( View *view, Model *model, View *parent_view )
562 {
563 g_assert( view != NULL );
564 g_assert( IS_VIEW( view ) && IS_MODEL( model ) );
565 g_assert( !VOBJECT( view )->iobject );
566
567 #ifdef DEBUG
568 printf( "view_real_link: linking %s to model %s \"%s\"\n",
569 G_OBJECT_TYPE_NAME( view ),
570 G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) );
571 #endif /*DEBUG*/
572
573 vobject_link( VOBJECT( view ), IOBJECT( model ) );
574 if( parent_view )
575 view_child_add( parent_view, view );
576
577 view->pos_changed_sid = g_signal_connect( model, "pos_changed",
578 G_CALLBACK( view_model_pos_changed ), view );
579 view->scrollto_sid = g_signal_connect( model, "scrollto",
580 G_CALLBACK( view_model_scrollto ), view );
581 view->layout_sid = g_signal_connect( model, "layout",
582 G_CALLBACK( view_model_layout ), view );
583 view->reset_sid = g_signal_connect( model, "reset",
584 G_CALLBACK( view_model_reset ), view );
585 view->front_sid = g_signal_connect( model, "front",
586 G_CALLBACK( view_model_front ), view );
587 view->child_add_sid = g_signal_connect( model, "child_add",
588 G_CALLBACK( view_model_child_add ), view );
589 view->child_remove_sid = g_signal_connect( model, "child_remove",
590 G_CALLBACK( view_model_child_remove ), view );
591 view->child_detach_sid = g_signal_connect( model, "child_detach",
592 G_CALLBACK( view_model_child_detach ), view );
593 view->child_attach_sid = g_signal_connect( model, "child_attach",
594 G_CALLBACK( view_model_child_attach ), view );
595
596 icontainer_map( ICONTAINER( model ),
597 (icontainer_map_fn) view_real_link_sub, view, NULL );
598
599 gtk_widget_show( GTK_WIDGET( view ) );
600 }
601
602 static void
view_real_child_add(View * parent,View * child)603 view_real_child_add( View *parent, View *child )
604 {
605 ViewChild *viewchild;
606
607 g_assert( IS_VIEW( parent ) && IS_VIEW( child ) );
608 g_assert( child->parent == NULL );
609
610 #ifdef DEBUG
611 printf( "view_real_child_add: parent %p %s, child %p %s\n",
612 parent,
613 G_OBJECT_TYPE_NAME( parent ),
614 child,
615 G_OBJECT_TYPE_NAME( child ) );
616 #endif /*DEBUG*/
617
618 viewchild = slist_map( parent->managed,
619 (SListMapFn) view_viewchild_test_child_model,
620 VOBJECT( child)->iobject );
621
622 g_assert( viewchild );
623 g_assert( viewchild->child_view == NULL );
624
625 /* Not all views are true widgets (ie. get _ref()'s and _sink()'d by a
626 * parent in gtk_container()). Ref and sink ourselves to ensure that
627 * even these odd views get unfloated. See also
628 * view_real_child_remove(). Affects the tool/toolkit views, and
629 * rowview at least.
630 */
631 child->parent = parent;
632 viewchild->child_view = child;
633 g_object_ref( GTK_OBJECT( child ) );
634 gtk_object_sink( GTK_OBJECT( child ) );
635 }
636
637 static void
view_real_child_remove(View * parent,View * child)638 view_real_child_remove( View *parent, View *child )
639 {
640 ViewChild *viewchild;
641
642 #ifdef DEBUG
643 printf( "view_real_child_remove: parent %s, child %s\n",
644 G_OBJECT_TYPE_NAME( parent ), G_OBJECT_TYPE_NAME( child ) );
645 #endif /*DEBUG*/
646
647 viewchild = slist_map( parent->managed,
648 (SListMapFn) view_viewchild_test_child_model,
649 VOBJECT( child )->iobject );
650
651 /* Can have floating views which are not part of the viewchild system.
652 */
653 if( viewchild &&
654 viewchild->child_view == child ) {
655 viewchild->child_view = NULL;
656 g_object_unref( G_OBJECT( child ) );
657 }
658
659 child->parent = NULL;
660 }
661
662 static void
view_real_child_position(View * parent,View * child)663 view_real_child_position( View *parent, View *child )
664 {
665 }
666
667 static void
view_real_child_front(View * parent,View * child)668 view_real_child_front( View *parent, View *child )
669 {
670 }
671
672 static void
view_real_reset(View * view)673 view_real_reset( View *view )
674 {
675 view_resettable_unregister( view );
676 }
677
678 static void *
view_real_scan(View * view)679 view_real_scan( View *view )
680 {
681 Model *model = MODEL( VOBJECT( view )->iobject );
682 Heapmodel *heapmodel;
683
684 view_scannable_unregister( view );
685
686 /* If we've changed something in this model, mark it for recomp.
687 */
688 if( model && IS_HEAPMODEL( model ) &&
689 (heapmodel = HEAPMODEL( model ))->modified &&
690 heapmodel->row ) {
691 Expr *expr = heapmodel->row->expr;
692
693 if( expr )
694 (void) expr_dirty( expr, link_serial_new() );
695 }
696
697 return( NULL );
698 }
699
700 static void
view_class_init(ViewClass * class)701 view_class_init( ViewClass *class )
702 {
703 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
704 GtkObjectClass *object_class = (GtkObjectClass*) class;
705
706 parent_class = g_type_class_peek_parent( class );
707
708 gobject_class->finalize = view_finalize;
709
710 object_class->destroy = view_destroy;
711
712 /* Create signals.
713 */
714
715 /* Init default methods.
716 */
717 class->link = view_real_link;
718 class->child_add = view_real_child_add;
719 class->child_remove = view_real_child_remove;
720 class->child_position = view_real_child_position;
721 class->child_front = view_real_child_front;
722 class->display = NULL;
723
724 class->reset = view_real_reset;
725 class->scan = view_real_scan;
726 class->scrollto = NULL;
727 class->layout = NULL;
728 }
729
730 static void
view_init(View * view)731 view_init( View *view )
732 {
733 /* Init our instance fields.
734 */
735 view->pos_changed_sid = 0;
736 view->scrollto_sid = 0;
737 view->layout_sid = 0;
738 view->reset_sid = 0;
739 view->front_sid = 0;
740 view->child_add_sid = 0;
741 view->child_remove_sid = 0;
742 view->child_detach_sid = 0;
743 view->child_attach_sid = 0;
744
745 view->parent = NULL;
746
747 view->scannable = FALSE;
748 view->resettable = FALSE;
749 }
750
751 GtkType
view_get_type(void)752 view_get_type( void )
753 {
754 static GtkType view_type = 0;
755
756 if( !view_type ) {
757 static const GtkTypeInfo view_info = {
758 "View",
759 sizeof( View ),
760 sizeof( ViewClass ),
761 (GtkClassInitFunc) view_class_init,
762 (GtkObjectInitFunc) view_init,
763 /* reserved_1 */ NULL,
764 /* reserved_2 */ NULL,
765 (GtkClassInitFunc) NULL,
766 };
767
768 view_type = gtk_type_unique( TYPE_VOBJECT, &view_info );
769 }
770
771 return( view_type );
772 }
773
774 /* Trigger the reset method for a view.
775 */
776 void *
view_reset(View * view)777 view_reset( View *view )
778 {
779 ViewClass *view_class = VIEW_GET_CLASS( view );
780
781 if( view_class->reset )
782 view_class->reset( view );
783
784 return( NULL );
785 }
786
787 /* Trigger the scan method for a view.
788 */
789 void *
view_scan(View * view)790 view_scan( View *view )
791 {
792 ViewClass *view_class = VIEW_GET_CLASS( view );
793
794 if( view_class->scan )
795 return( view_class->scan( view ) );
796
797 return( NULL );
798 }
799
800 /* Trigger the scrollto method for a view.
801 */
802 void *
view_scrollto(View * view,ModelScrollPosition position)803 view_scrollto( View *view, ModelScrollPosition position )
804 {
805 ViewClass *view_class = VIEW_GET_CLASS( view );
806
807 if( view_class->scrollto )
808 view_class->scrollto( view, position );
809
810 return( NULL );
811 }
812
813 /* Trigger the layout method for a view.
814 */
815 void *
view_layout(View * view)816 view_layout( View *view )
817 {
818 ViewClass *view_class = VIEW_GET_CLASS( view );
819
820 if( view_class->layout )
821 view_class->layout( view );
822
823 return( NULL );
824 }
825
826 static void *
view_map_sub(ViewChild * viewchild,view_map_fn fn,void * a,void * b)827 view_map_sub( ViewChild *viewchild, view_map_fn fn, void *a, void *b )
828 {
829 if( viewchild->child_view )
830 return( fn( viewchild->child_view, a, b ) );
831
832 return( NULL );
833 }
834
835 /* Map over a view's children.
836 */
837 void *
view_map(View * view,view_map_fn fn,void * a,void * b)838 view_map( View *view, view_map_fn fn, void *a, void *b )
839 {
840 return( slist_map3( view->managed,
841 (SListMap3Fn) view_map_sub, (void *) fn, a, b ) );
842 }
843
844 /* Apply a function to view, and to all it's children.
845 */
846 void *
view_map_all(View * view,view_map_fn fn,void * a)847 view_map_all( View *view, view_map_fn fn, void *a )
848 {
849 View *result;
850
851 if( (result = fn( view, a, NULL )) )
852 return( result );
853
854 return( view_map( view,
855 (view_map_fn) view_map_all, (void *) fn, a ) );
856 }
857
858 void
view_save_as_cb(GtkWidget * menu,GtkWidget * host,View * view)859 view_save_as_cb( GtkWidget *menu, GtkWidget *host, View *view )
860 {
861 Model *model = MODEL( VOBJECT( view )->iobject );
862
863 if( IS_FILEMODEL( model ) ) {
864 iWindow *iwnd = IWINDOW( view_get_toplevel( view ) );
865
866 filemodel_inter_saveas( iwnd, FILEMODEL( model ) );
867 }
868 }
869
870 void
view_save_cb(GtkWidget * menu,GtkWidget * host,View * view)871 view_save_cb( GtkWidget *menu, GtkWidget *host, View *view )
872 {
873 Model *model = MODEL( VOBJECT( view )->iobject );
874
875 if( IS_FILEMODEL( model ) ) {
876 iWindow *iwnd = IWINDOW( view_get_toplevel( view ) );
877
878 filemodel_inter_save( iwnd, FILEMODEL( model ) );
879 }
880 }
881
882 void
view_close_cb(GtkWidget * menu,GtkWidget * host,View * view)883 view_close_cb( GtkWidget *menu, GtkWidget *host, View *view )
884 {
885 Model *model = MODEL( VOBJECT( view )->iobject );
886
887 if( IS_FILEMODEL( model ) ) {
888 iWindow *iwnd = IWINDOW( view_get_toplevel( view ) );
889
890 filemodel_inter_savenclose( iwnd, FILEMODEL( model ) );
891 }
892 }
893
894 /* Callback for "activate" on a view.
895 */
896 void
view_activate_cb(View * view)897 view_activate_cb( View *view )
898 {
899 view_scannable_register( view );
900 symbol_recalculate_all();
901 }
902
903 /* Callback for "changed" on a view.
904 */
905 void
view_changed_cb(View * view)906 view_changed_cb( View *view )
907 {
908 /* Make sure it's on the scannable list.
909 */
910 view_scannable_register( view );
911 }
912
913 void
view_not_implemented_cb(GtkWidget * menu,GtkWidget * host,View * view)914 view_not_implemented_cb( GtkWidget *menu, GtkWidget *host, View *view )
915 {
916 error_top( _( "Not implemented." ) );
917 iwindow_alert( GTK_WIDGET( view ), GTK_MESSAGE_ERROR );
918 }
919
920 GtkWidget *
view_get_toplevel(View * view)921 view_get_toplevel( View *view )
922 {
923 while( IS_VIEW( view ) && view->parent )
924 view = view->parent;
925
926 return( gtk_widget_get_toplevel( GTK_WIDGET( view ) ) );
927 }
928
929 Columnview *
view_get_columnview(View * child)930 view_get_columnview( View *child )
931 {
932 View *view;
933
934 for( view = child; view && !IS_COLUMNVIEW( view ); view = view->parent )
935 ;
936
937 if( !view )
938 return( NULL );
939
940 return( COLUMNVIEW( view ) );
941 }
942
943 /* A view has changed size ... rethink the enclosing column geo. Helps table
944 * to not break.
945 */
946 void *
view_resize(View * view)947 view_resize( View *view )
948 {
949 Columnview *cview = view_get_columnview( view );
950
951 if( cview )
952 gtk_widget_queue_resize( GTK_WIDGET( cview ) );
953
954 return( NULL );
955 }
956