1 /* Fo
2  * fo-keep.c: Keep datatype
3  *
4  * Copyright (C) 2001 Sun Microsystems
5  * Copyright (C) 2007-2010 Menteith Consulting Ltd
6  *
7  * See COPYING for the status of this software.
8  */
9 
10 #include "fo-utils.h"
11 #include "fo-datatype.h"
12 #include "fo-datatype-private.h"
13 #include "fo-keep.h"
14 #include "fo-enum.h"
15 #include "fo-length.h"
16 #include "fo-integer.h"
17 #include "fo-percentage.h"
18 #include "fo-boolean.h"
19 
20 enum {
21   PROP_0,
22   PROP_WITHIN_LINE,
23   PROP_WITHIN_COLUMN,
24   PROP_WITHIN_PAGE
25 };
26 
27 struct _FoKeep
28 {
29   FoDatatype parent_instance;
30 
31   FoDatatype *within_line;
32   FoDatatype *within_column;
33   FoDatatype *within_page;
34 };
35 
36 struct _FoKeepClass
37 {
38   FoDatatypeClass parent_class;
39 
40 };
41 
42 static void _init         (FoKeep      *keep);
43 static void _class_init   (FoKeepClass *klass);
44 static void _set_property (GObject       *object,
45 			   guint          prop_id,
46 			   const GValue  *value,
47 			   GParamSpec    *pspec);
48 static void _get_property (GObject       *object,
49 			   guint          prop_id,
50 			   GValue        *value,
51 			   GParamSpec    *pspec);
52 static void _dispose      (GObject       *object);
53 
54 static gchar*       _sprintf           (FoObject   *object);
55 static FoDatatype * _copy              (FoDatatype *datatype);
56 static void         _set_within_line   (FoDatatype *keep,
57 					FoDatatype *new_within_line);
58 static void         _set_within_column (FoDatatype *keep,
59 					FoDatatype *new_within_column);
60 static void         _set_within_page   (FoDatatype *keep,
61 					FoDatatype *new_within_page);
62 
63 static gpointer parent_class;
64 
65 /**
66  * fo_keep_get_type:
67  *
68  * Register the #FoKeep object type.
69  *
70  * Return value: GType value of the #FoKeep object type.
71  **/
72 GType
fo_keep_get_type(void)73 fo_keep_get_type (void)
74 {
75   static GType object_type = 0;
76 
77   if (!object_type)
78     {
79       static const GTypeInfo object_info =
80       {
81         sizeof (FoKeepClass),
82 	NULL,		/* base_init */
83 	NULL,		/* base_finalize */
84         (GClassInitFunc) _class_init,
85         NULL,           /* class_finalize */
86         NULL,           /* class_data */
87         sizeof (FoKeep),
88         0,              /* n_preallocs */
89         (GInstanceInitFunc) _init,
90 	NULL		/* value_table */
91       };
92 
93       object_type = g_type_register_static (FO_TYPE_DATATYPE,
94                                             "FoKeep",
95                                             &object_info, 0);
96     }
97 
98   return object_type;
99 }
100 
101 /**
102  * _init:
103  * @keep: #FoKeep object to initialise
104  *
105  * Implements GInstanceInitFunc for #FoKeep
106  **/
107 void
_init(FoKeep * keep)108 _init (FoKeep *keep)
109 {
110   keep->within_page =
111     g_object_ref (fo_enum_factory_get_enum_by_value (FO_ENUM_ENUM_AUTO));
112   keep->within_column =
113     g_object_ref (fo_enum_factory_get_enum_by_value (FO_ENUM_ENUM_AUTO));
114   keep->within_line =
115     g_object_ref (fo_enum_factory_get_enum_by_value (FO_ENUM_ENUM_AUTO));
116 }
117 
118 /**
119  * _class_init:
120  * @klass: FoKeepClass object to initialise
121  *
122  * Implements GClassInitFunc for FoKeepClass
123  **/
124 void
_class_init(FoKeepClass * klass)125 _class_init (FoKeepClass *klass)
126 {
127   GObjectClass *object_class = G_OBJECT_CLASS (klass);
128 
129   parent_class = g_type_class_peek_parent (klass);
130 
131   object_class->dispose = _dispose;
132 
133   object_class->set_property = _set_property;
134   object_class->get_property = _get_property;
135 
136   FO_DATATYPE_CLASS (klass)->copy = _copy;
137   FO_OBJECT_CLASS (klass)->print_sprintf = _sprintf;
138 
139   g_object_class_install_property (object_class,
140                                    PROP_WITHIN_LINE,
141                                    g_param_spec_object ("within-line",
142 							_("Within Line"),
143 							_("Keep within line value"),
144 							FO_TYPE_DATATYPE,
145 							G_PARAM_READWRITE |
146 							G_PARAM_CONSTRUCT_ONLY));
147 
148   g_object_class_install_property (object_class,
149                                    PROP_WITHIN_COLUMN,
150                                    g_param_spec_object ("within-column",
151 							_("Within Column"),
152 							_("Keep within column value"),
153 							FO_TYPE_DATATYPE,
154 							G_PARAM_READWRITE |
155 							G_PARAM_CONSTRUCT_ONLY));
156 
157   g_object_class_install_property (object_class,
158                                    PROP_WITHIN_PAGE,
159                                    g_param_spec_object ("within-page",
160 							_("Within Page"),
161 							_("Keep within page value"),
162 							FO_TYPE_DATATYPE,
163 							G_PARAM_READWRITE |
164 							G_PARAM_CONSTRUCT_ONLY));
165 
166 
167 }
168 
169 /**
170  * _dispose:
171  * @object: FoKeep object to dispose
172  *
173  * Implements GObjectDisposeFunc for FoKeep
174  **/
175 void
_dispose(GObject * object)176 _dispose (GObject *object)
177 {
178   FoKeep *keep = FO_KEEP (object);
179 
180   if (keep->within_page != NULL)
181     {
182       g_object_unref (keep->within_page);
183       keep->within_page = NULL;
184     }
185 
186   if (keep->within_column != NULL)
187     {
188       g_object_unref (keep->within_column);
189       keep->within_column = NULL;
190     }
191 
192   if (keep->within_line != NULL)
193     {
194       g_object_unref (keep->within_line);
195       keep->within_line = NULL;
196     }
197 
198   G_OBJECT_CLASS (parent_class)->dispose (object);
199 }
200 
201 
202 /**
203  * _get_property:
204  * @object:  GObject whose property will be retreived
205  * @prop_id: Property ID assigned when property registered
206  * @value:   GValue to set with property value
207  * @pspec:   Parameter specification for this property type
208  *
209  * Implements #GObjectGetPropertyFunc for FoKeep
210  **/
211 void
_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)212 _get_property (GObject         *object,
213 	       guint            prop_id,
214 	       GValue          *value,
215 	       GParamSpec      *pspec)
216 {
217   FoDatatype *keep;
218 
219   keep = FO_DATATYPE (object);
220 
221   switch (prop_id)
222     {
223     case PROP_WITHIN_LINE:
224       g_value_set_object (value, fo_keep_get_within_line (keep));
225       break;
226     case PROP_WITHIN_COLUMN:
227       g_value_set_object (value, fo_keep_get_within_column (keep));
228       break;
229     case PROP_WITHIN_PAGE:
230       g_value_set_object (value, fo_keep_get_within_page (keep));
231       break;
232     default:
233       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
234       break;
235     }
236 }
237 
238 /**
239  * _set_property:
240  * @object:  GObject whose property will be set
241  * @prop_id: Property ID assigned when property registered
242  * @value:   New value for property
243  * @pspec:   Parameter specification for this property type
244  *
245  * Implements #GObjectSetPropertyFunc for FoKeep
246  **/
247 void
_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)248 _set_property (GObject         *object,
249 	       guint            prop_id,
250 	       const GValue    *value,
251 	       GParamSpec      *pspec)
252 {
253   FoDatatype *keep;
254 
255   keep = FO_DATATYPE (object);
256 
257   switch (prop_id)
258     {
259     case PROP_WITHIN_LINE:
260       _set_within_line (keep, g_value_get_object (value));
261       break;
262     case PROP_WITHIN_COLUMN:
263       _set_within_column (keep, g_value_get_object (value));
264       break;
265     case PROP_WITHIN_PAGE:
266       _set_within_page (keep, g_value_get_object (value));
267       break;
268     default:
269       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270       break;
271     }
272 }
273 
274 /**
275  * fo_keep_new:
276  *
277  * Creates a new #FoKeep initialized to default value.
278  *
279  * Return value: the new #FoKeep
280  **/
281 FoDatatype *
fo_keep_new(void)282 fo_keep_new (void)
283 {
284   return FO_DATATYPE (g_object_new (fo_keep_get_type (),
285 				    NULL));
286 }
287 
288 /**
289  * fo_keep_new_with_value:
290  * @value: Keep of the new #FoKeep
291  *
292  * Creates a new #FoKeep set to @value
293  *
294  * Return value: The new #FoKeep
295  **/
296 FoDatatype *
fo_keep_new_with_value(FoDatatype * value)297 fo_keep_new_with_value (FoDatatype *value)
298 {
299   FoDatatype *keep = fo_keep_new ();
300 
301   _set_within_page (keep, value);
302   _set_within_column (keep, value);
303   _set_within_line (keep, value);
304 
305   return keep;
306 }
307 
308 /**
309  * fo_keep_get_keep_auto:
310  *
311  * Creates a new #FoKeep set to .within-line="auto",
312  * .within-column="auto", and .within-page="auto".
313  *
314  * Return value: The new #FoKeep
315  **/
316 FoDatatype*
fo_keep_get_keep_auto(void)317 fo_keep_get_keep_auto (void)
318 {
319   static FoDatatype *keep = NULL;
320 
321   if (keep == NULL)
322     {
323       keep = fo_keep_new ();
324     }
325 
326   return keep;
327 }
328 
329 /**
330  * fo_keep_get_keep_always:
331  *
332  * Creates a new #FoKeep set to .within-line="always",
333  * .within-column="always", and .within-page="always".
334  *
335  * Return value: The new #FoKeep
336  **/
337 FoDatatype *
fo_keep_get_keep_always(void)338 fo_keep_get_keep_always (void)
339 {
340   static FoDatatype *keep = NULL;
341 
342   if (keep == NULL)
343     {
344       keep =
345 	fo_keep_new_with_value (fo_enum_factory_get_enum_by_value (FO_ENUM_ENUM_ALWAYS));
346     }
347 
348   return keep;
349 }
350 
351 /**
352  * fo_keep_get_within_page:
353  * @datatype: #FoKeep
354  *
355  * Gets the .within-page component value of @datatype
356  *
357  * Return value: The .within-page value of @datatype
358  **/
359 FoDatatype *
fo_keep_get_within_page(FoDatatype * datatype)360 fo_keep_get_within_page (FoDatatype *datatype)
361 {
362   g_return_val_if_fail (datatype != NULL, NULL);
363   g_return_val_if_fail (FO_IS_KEEP (datatype), 0);
364 
365   return FO_KEEP (datatype)->within_page;
366 }
367 
368 /**
369  * _set_within_page:
370  * @datatype:     #FoKeep
371  * @new_within_page:  New .within-page value
372  *
373  * Sets the .within-page component of @datatype
374  **/
375 static void
_set_within_page(FoDatatype * datatype,FoDatatype * new_within_page)376 _set_within_page (FoDatatype *datatype,
377 		  FoDatatype *new_within_page)
378 {
379   FoKeep *keep = (FoKeep *) datatype;
380 
381   g_return_if_fail (keep != NULL);
382   g_return_if_fail (FO_IS_KEEP (keep));
383   g_return_if_fail ((new_within_page == NULL) ||
384 		    FO_IS_DATATYPE (new_within_page));
385 
386   if (new_within_page != NULL)
387     {
388       g_object_ref (new_within_page);
389     }
390   if (keep->within_page != NULL)
391     {
392       g_object_unref (keep->within_page);
393     }
394 
395   keep->within_page = new_within_page;
396   /*g_object_notify(G_OBJECT(keep), "within-page");*/
397 }
398 
399 /**
400  * fo_keep_get_within_column:
401  * @datatype: #FoKeep
402  *
403  * Gets the .within-column component value of @datatype
404  *
405  * Return value: The .within-column value of @datatype
406  **/
407 FoDatatype *
fo_keep_get_within_column(FoDatatype * datatype)408 fo_keep_get_within_column (FoDatatype *datatype)
409 {
410   g_return_val_if_fail (datatype != NULL, NULL);
411   g_return_val_if_fail (FO_IS_KEEP (datatype), 0);
412 
413   return FO_KEEP (datatype)->within_column;
414 }
415 
416 /**
417  * _set_within_column:
418  * @datatype:     #FoKeep
419  * @new_within_column:  New .within-column value
420  *
421  * Sets the .within-column component of @datatype
422  **/
423 static void
_set_within_column(FoDatatype * datatype,FoDatatype * new_within_column)424 _set_within_column (FoDatatype *datatype,
425 		    FoDatatype *new_within_column)
426 {
427   FoKeep *keep = (FoKeep *) datatype;
428 
429   g_return_if_fail (keep != NULL);
430   g_return_if_fail (FO_IS_KEEP (keep));
431   g_return_if_fail ((new_within_column == NULL) ||
432 		    FO_IS_DATATYPE (new_within_column));
433 
434   if (new_within_column != NULL)
435     {
436       g_object_ref (new_within_column);
437     }
438 
439   if (keep->within_column != NULL)
440     {
441       g_object_unref (keep->within_column);
442     }
443 
444   keep->within_column = new_within_column;
445   /*g_object_notify(G_OBJECT(keep), "within-column");*/
446 }
447 
448 /**
449  * fo_keep_get_within_line:
450  * @datatype: #FoKeep
451  *
452  * Gets the .within-line component value of @datatype
453  *
454  * Return value: The .within-line value of @datatype
455  **/
456 FoDatatype *
fo_keep_get_within_line(FoDatatype * datatype)457 fo_keep_get_within_line (FoDatatype *datatype)
458 {
459   g_return_val_if_fail (datatype != NULL, NULL);
460   g_return_val_if_fail (FO_IS_KEEP (datatype), 0);
461 
462   return FO_KEEP (datatype)->within_line;
463 }
464 
465 /**
466  * _set_within_line:
467  * @datatype:     #FoKeep
468  * @new_within_line:  New .within-line value
469  *
470  * Sets the .within-line component of @datatype
471  **/
472 static void
_set_within_line(FoDatatype * datatype,FoDatatype * new_within_line)473 _set_within_line (FoDatatype *datatype,
474 		  FoDatatype *new_within_line)
475 {
476   FoKeep *keep = (FoKeep *) datatype;
477 
478   g_return_if_fail (keep != NULL);
479   g_return_if_fail (FO_IS_KEEP (keep));
480   g_return_if_fail ((new_within_line == NULL) ||
481 		    FO_IS_DATATYPE (new_within_line));
482 
483   if (new_within_line != NULL)
484     {
485       g_object_ref (new_within_line);
486     }
487 
488   if (keep->within_line != NULL)
489     {
490       g_object_unref (keep->within_line);
491     }
492 
493   keep->within_line = new_within_line;
494   /*g_object_notify(G_OBJECT(keep), "within-line");*/
495 }
496 
497 /**
498  * _sprintf:
499  * @object:
500  *
501  *
502  *
503  * Returns:
504  **/
505 static gchar*
_sprintf(FoObject * object)506 _sprintf (FoObject *object)
507 {
508   g_return_val_if_fail (object != NULL, NULL);
509   g_return_val_if_fail (FO_IS_KEEP (object), NULL);
510 
511   gchar *within_page = fo_object_sprintf (FO_KEEP (object)->within_page);
512   gchar *within_column = fo_object_sprintf (FO_KEEP (object)->within_column);
513   gchar *within_line = fo_object_sprintf (FO_KEEP (object)->within_line);
514 
515   gchar *string = g_strdup_printf ("page: %s; column: %s; line: %s",
516 				   within_page,
517 				   within_column,
518 				   within_line);
519 
520   g_free (within_line);
521   g_free (within_column);
522   g_free (within_page);
523 
524   return string;
525 }
526 
527 /**
528  * _copy:
529  * @datatype: Source #FoKeep
530  *
531  * Creates a copy of @datatype
532  *
533  * Return value: Copy of @datatype
534  **/
535 static FoDatatype *
_copy(FoDatatype * datatype)536 _copy (FoDatatype *datatype)
537 {
538   FoDatatype* keep;
539 
540   g_return_val_if_fail (datatype != NULL, NULL);
541   g_return_val_if_fail (FO_IS_KEEP (datatype), NULL);
542 
543   keep = fo_keep_new ();
544   FO_KEEP (keep)->within_page =
545     FO_KEEP (datatype)->within_page;
546   FO_KEEP (keep)->within_column =
547     FO_KEEP (datatype)->within_column;
548   FO_KEEP (keep)->within_line =
549     FO_KEEP (datatype)->within_line;
550 
551   return (keep);
552 }
553 
554 /**
555  * fo_keep_resolve:
556  * @shortform:       Single-value short form of the keep, or
557  *                     NULL
558  * @within_line:     .within-line component of the keep, or NULL
559  * @within_column:   .within-column component of the keep, or NULL
560  * @within_page:     .within-page component of the keep, or NULL
561  * @error:           GError used for reporting errors
562  *
563  * Resolve the shortform and components of the keep in
564  * accordance with Section 5.11, Datatypes, of the XSL 1.0
565  * Recommendation.
566  *
567  * Does not change the ref-count of any FoDatatype arguments.
568  *
569  * Return value: Compound keep datatype, or NULL if an error
570  *               occurred
571  **/
572 FoDatatype *
fo_keep_resolve(FoDatatype * shortform,FoDatatype * within_line,FoDatatype * within_column,FoDatatype * within_page,GError ** error G_GNUC_UNUSED)573 fo_keep_resolve (FoDatatype *shortform,
574 		 FoDatatype *within_line,
575 		 FoDatatype *within_column,
576 		 FoDatatype *within_page,
577 		 GError **error G_GNUC_UNUSED)
578 {
579   FoDatatype *use_keep;
580 
581   g_return_val_if_fail (shortform == NULL ||
582 			FO_IS_KEEP (shortform),
583 			NULL);
584   g_return_val_if_fail (within_line == NULL ||
585 			FO_IS_INTEGER (within_line) ||
586 			(FO_IS_ENUM (within_line) &&
587 			 ((fo_enum_get_value (within_line) ==
588 			   FO_ENUM_ENUM_AUTO) ||
589 			  (fo_enum_get_value (within_line) ==
590 			   FO_ENUM_ENUM_ALWAYS))),
591 			NULL);
592   g_return_val_if_fail (within_column == NULL ||
593 			FO_IS_INTEGER (within_column) ||
594 			(FO_IS_ENUM (within_column) &&
595 			 ((fo_enum_get_value (within_column) ==
596 			   FO_ENUM_ENUM_AUTO) ||
597 			  (fo_enum_get_value (within_column) ==
598 			   FO_ENUM_ENUM_ALWAYS))),
599 			NULL);
600   g_return_val_if_fail (within_page == NULL ||
601 			FO_IS_INTEGER (within_page) ||
602 			(FO_IS_ENUM (within_page) &&
603 			 ((fo_enum_get_value (within_page) ==
604 			   FO_ENUM_ENUM_AUTO) ||
605 			  (fo_enum_get_value (within_page) ==
606 			   FO_ENUM_ENUM_ALWAYS))),
607 			NULL);
608 
609   if (FO_IS_KEEP (shortform) &&
610       within_line == NULL &&
611       within_column == NULL &&
612       within_page == NULL)
613     {
614       use_keep = shortform;
615     }
616   else
617     {
618       if (shortform == NULL)
619 	{
620 	  use_keep = fo_keep_new ();
621 	}
622       else
623 	{
624 	  use_keep = _copy (shortform);
625 	}
626 
627       if (within_line != NULL)
628 	{
629 	  _set_within_line (use_keep,
630 			    within_line);
631 	}
632 
633       if (within_column != NULL)
634 	{
635 	  _set_within_column (use_keep,
636 			      within_column);
637 	}
638 
639       if (within_page != NULL)
640 	{
641 	  _set_within_page (use_keep,
642 			    within_page);
643 	}
644     }
645 
646   return use_keep;
647 }
648