1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * dialog-doc-metadata.c: Edit document metadata
5 * Copyright (C) 2005 Jody Goldberg (jody@gnome.org)
6 * Copyright (C) 2011 Andreas J. Guelzow (aguelzow@pyrshep.ca)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 #include <gnumeric-config.h>
29 #include <workbook-control.h>
31 #include <workbook-view.h>
32 #include <workbook-priv.h>
34 #include <parse-util.h>
38 #include <number-match.h>
39 #include <dead-kittens.h>
41 #include <gsf/gsf-doc-meta-data.h>
42 #include <gsf/gsf-meta-names.h>
43 #include <gsf/gsf-timestamp.h>
44 #include <gsf/gsf-docprop-vector.h>
46 #include <goffice/goffice.h>
50 #include <glib-object.h>
51 #include <glib/gi18n-lib.h>
52 #include <glib/gprintf.h>
57 #define DOC_METADATA_KEY "dialog-doc-metadata"
70 /*pointer to the document metadata*/
71 GsfDocMetaData
*metadata
;
73 gboolean permissions_changed
;
74 GOFilePermissions
*file_permissions
;
84 GtkNotebook
*notebook
;
85 GtkButton
*help_button
;
86 GtkButton
*close_button
;
88 /* File Information Page */
97 GtkCheckButton
*owner_read
;
98 GtkCheckButton
*owner_write
;
100 GtkCheckButton
*group_read
;
101 GtkCheckButton
*group_write
;
103 GtkCheckButton
*others_read
;
104 GtkCheckButton
*others_write
;
106 /* Description Page */
114 GtkTextView
*comments
;
116 /* Properties Page */
117 GtkTreeView
*properties
;
118 GtkTreeStore
*properties_store
;
122 GtkComboBox
*ppt_type
;
123 GtkListStore
*type_store
;
124 GtkTreeModelFilter
*type_store_filter
;
126 GtkButton
*add_button
;
127 GtkButton
*remove_button
;
129 GtkLabel
*instruction
;
133 GtkTreeView
*key_tree_view
;
134 GtkListStore
*key_store
;
135 GtkButton
*key_add_button
;
136 GtkButton
*key_remove_button
;
138 /* Statistics Page */
143 /* Calculation Page */
144 GtkCheckButton
*recalc_auto
;
145 GtkCheckButton
*recalc_manual
;
146 GtkCheckButton
*recalc_iteration
;
147 GtkEntry
*recalc_max
;
148 GtkEntry
*recalc_tolerance
;
149 GtkWidget
*recalc_iteration_grid
;
153 #define trim_string(s_) g_strstrip (g_strdup ((s_)))
155 static gchar
*dialog_doc_metadata_get_prop_val (DialogDocMetaData
*state
, char const *prop_name
,
158 static gboolean
cb_dialog_doc_metadata_ppt_changed (G_GNUC_UNUSED GtkEntry
*entry
,
159 G_GNUC_UNUSED GdkEventFocus
*event
,
160 DialogDocMetaData
*state
);
164 dialog_doc_metadata_get_value_type_from_name (gchar
const *name
, GType def
)
166 /* shared by all instances and never freed */
167 static GHashTable
*dialog_doc_metadata_name_to_type
= NULL
;
170 if (NULL
== dialog_doc_metadata_name_to_type
) {
175 {GSF_META_NAME_GENERATOR
, G_TYPE_STRING
},
176 {GSF_META_NAME_INITIAL_CREATOR
, G_TYPE_STRING
},
177 {GSF_META_NAME_CREATOR
, G_TYPE_STRING
},
178 {GSF_META_NAME_TITLE
, G_TYPE_STRING
},
179 {GSF_META_NAME_SUBJECT
, G_TYPE_STRING
},
180 {GSF_META_NAME_MANAGER
, G_TYPE_STRING
},
181 {GSF_META_NAME_COMPANY
, G_TYPE_STRING
},
182 {GSF_META_NAME_CATEGORY
, G_TYPE_STRING
},
183 {GSF_META_NAME_DESCRIPTION
, G_TYPE_STRING
},
184 {GSF_META_NAME_LAST_SAVED_BY
, G_TYPE_STRING
},
185 {GSF_META_NAME_TEMPLATE
, G_TYPE_STRING
},
186 {GSF_META_NAME_EDITING_DURATION
, G_TYPE_STRING
}, /* special */
187 {GSF_META_NAME_SPREADSHEET_COUNT
, G_TYPE_INT
},
188 {GSF_META_NAME_TABLE_COUNT
, G_TYPE_INT
},
189 {GSF_META_NAME_CELL_COUNT
, G_TYPE_INT
},
190 {GSF_META_NAME_CHARACTER_COUNT
, G_TYPE_INT
},
191 {GSF_META_NAME_BYTE_COUNT
, G_TYPE_INT
},
192 {GSF_META_NAME_SECURITY
, G_TYPE_INT
},
193 {GSF_META_NAME_HIDDEN_SLIDE_COUNT
, G_TYPE_INT
},
194 {GSF_META_NAME_LINE_COUNT
, G_TYPE_INT
},
195 {GSF_META_NAME_SLIDE_COUNT
, G_TYPE_INT
},
196 {GSF_META_NAME_WORD_COUNT
, G_TYPE_INT
},
197 {GSF_META_NAME_MM_CLIP_COUNT
, G_TYPE_INT
},
198 {GSF_META_NAME_NOTE_COUNT
, G_TYPE_INT
},
199 {GSF_META_NAME_PARAGRAPH_COUNT
, G_TYPE_INT
},
200 {GSF_META_NAME_PAGE_COUNT
, G_TYPE_INT
},
201 {GSF_META_NAME_CODEPAGE
, G_TYPE_INT
},
202 {GSF_META_NAME_LOCALE_SYSTEM_DEFAULT
,G_TYPE_INT
},
203 {GSF_META_NAME_OBJECT_COUNT
, G_TYPE_INT
},
204 {"xlsx:HyperlinksChanged", G_TYPE_BOOLEAN
},
205 {GSF_META_NAME_LINKS_DIRTY
, G_TYPE_BOOLEAN
},
206 {"xlsx:SharedDoc", G_TYPE_BOOLEAN
},
207 {GSF_META_NAME_SCALE
, G_TYPE_BOOLEAN
}
209 static char const *map_vector
[] =
210 {GSF_META_NAME_KEYWORDS
,
211 GSF_META_NAME_DOCUMENT_PARTS
,
212 GSF_META_NAME_HEADING_PAIRS
};
213 static char const *map_timestamps
[] =
214 {GSF_META_NAME_DATE_CREATED
,
215 GSF_META_NAME_DATE_MODIFIED
};
217 /*Missing:GSF_META_NAME_THUMBNAIL */
219 int i
= G_N_ELEMENTS (map
);
220 dialog_doc_metadata_name_to_type
= g_hash_table_new (g_str_hash
, g_str_equal
);
222 g_hash_table_insert (dialog_doc_metadata_name_to_type
,
223 (gpointer
)map
[i
].name
,
224 GINT_TO_POINTER (map
[i
].type
));
226 i
= G_N_ELEMENTS (map_vector
);
228 g_hash_table_insert (dialog_doc_metadata_name_to_type
,
229 (gpointer
)map_vector
[i
],
230 GINT_TO_POINTER (GSF_DOCPROP_VECTOR_TYPE
));
232 i
= G_N_ELEMENTS (map_timestamps
);
234 g_hash_table_insert (dialog_doc_metadata_name_to_type
,
235 (gpointer
)map_timestamps
[i
],
236 GINT_TO_POINTER (GSF_TIMESTAMP_TYPE
));
240 res
= g_hash_table_lookup (dialog_doc_metadata_name_to_type
, name
);
243 return GPOINTER_TO_INT (res
);
249 dialog_doc_metadata_get_value_type (GValue
*value
)
251 GType val_type
= G_VALUE_TYPE (value
);
260 /* Just leave it as is */
264 /* Check if it is a GsfDocPropVector or GsfTimeStamp */
266 if (VAL_IS_GSF_TIMESTAMP (value
))
267 val_type
= GSF_TIMESTAMP_TYPE
;
268 else if (VAL_IS_GSF_DOCPROP_VECTOR (value
))
269 val_type
= GSF_DOCPROP_VECTOR_TYPE
;
271 g_printerr ("GType %s (%i) not handled in metadata dialog.\n",
272 g_type_name (val_type
), (int) val_type
);
273 val_type
= G_TYPE_INVALID
;
283 /******************************************************************************
284 * G_VALUE TRANSFORM FUNCTIONS
285 ******************************************************************************/
288 * G_TYPE_STRING TO OTHER
292 dialog_doc_metadata_transform_str_to_timestamp (const GValue
*string_value
,
293 GValue
*timestamp_value
)
300 GnmValue
*conversion
;
303 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
304 g_return_if_fail (VAL_IS_GSF_TIMESTAMP (timestamp_value
));
306 fmt
= go_format_new_from_XL ("yyyy-mm-dd hh:mm:ss");
307 str
= g_value_get_string (string_value
);
308 conversion
= format_match_number (str
, fmt
, NULL
);
309 go_format_unref (fmt
);
311 serial
= value_get_as_float (conversion
);
312 value_release (conversion
);
314 /* Convert from Gnumeric time to unix time */
315 int_serial
= (int)serial
;
316 s
= go_date_serial_to_timet (int_serial
, NULL
);
318 if (gnm_abs (serial
- int_serial
) >= 1.0 || s
== (time_t)-1) {
321 s
+= (gnm_fake_round (3600 * 24 * (serial
- int_serial
)));
326 gt
= gsf_timestamp_new ();
327 gsf_timestamp_set_time (gt
, s
);
328 gsf_timestamp_to_value (gt
, timestamp_value
);
332 dialog_doc_metadata_transform_str_to_float (const GValue
*string_value
,
337 GnmValue
*conversion
;
339 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
340 g_return_if_fail (G_VALUE_HOLDS_FLOAT (float_value
));
342 str
= g_value_get_string (string_value
);
343 conversion
= format_match_number (str
, NULL
, NULL
);
345 x
= value_get_as_float (conversion
);
346 value_release (conversion
);
350 g_value_set_float (float_value
, x
);
354 dialog_doc_metadata_transform_str_to_boolean (const GValue
*string_value
,
359 GnmValue
*conversion
;
361 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
362 g_return_if_fail (G_VALUE_HOLDS_BOOLEAN (b_value
));
364 str
= g_value_get_string (string_value
);
365 conversion
= format_match_number (str
, NULL
, NULL
);
367 x
= value_get_as_bool (conversion
, &err
);
368 value_release (conversion
);
374 g_value_set_boolean (b_value
, x
);
378 dialog_doc_metadata_transform_str_to_docprop_vect (const GValue
*string_value
,
379 GValue
*docprop_value
)
382 GsfDocPropVector
*gdpv
;
385 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
386 g_return_if_fail (VAL_IS_GSF_DOCPROP_VECTOR (docprop_value
));
388 gdpv
= gsf_docprop_vector_new ();
389 str
= g_value_get_string (string_value
);
391 while (*str
== ' ') {str
++;}
393 while (*str
== '"') {
396 while (*s
!= '"' && *s
!= '\0') {
397 if (*(s
++) == '\\') {
406 key
= g_strndup (str
, s
- str
);
407 value
= g_new0 (GValue
, 1);
408 g_value_take_string (g_value_init (value
, G_TYPE_STRING
),
409 g_strcompress (key
));
410 gsf_docprop_vector_append (gdpv
, value
);
413 while (*str
== ' ') {str
++;}
417 while (*str
== ' ') {str
++;}
420 g_value_set_object (docprop_value
, gdpv
);
421 g_object_unref (gdpv
);
429 char const *format
= "%c";
434 len
= strftime (buffer
, sizeof (buffer
), format
, localtime (&t
));
438 return g_locale_to_utf8 (buffer
, len
, NULL
, NULL
, NULL
);
442 time2str_go (time_t t
)
444 /* We need to create a format that is also parsable */
452 t_gnm
= go_date_timet_to_serial_raw (t
, NULL
);
454 fmt
= go_format_new_from_XL ("yyyy-mm-dd hh:mm:ss");
455 str
= go_format_value (fmt
, t_gnm
);
456 go_format_unref (fmt
);
461 * OTHER TO G_TYPE_STRING
464 dialog_doc_metadata_transform_timestamp_to_str (const GValue
*timestamp_value
,
465 GValue
*string_value
)
467 GsfTimestamp
const *timestamp
= NULL
;
469 g_return_if_fail (VAL_IS_GSF_TIMESTAMP (timestamp_value
));
470 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
472 timestamp
= g_value_get_boxed (timestamp_value
);
473 if (timestamp
!= NULL
)
474 g_value_take_string (string_value
,
475 time2str_go (timestamp
->timet
));
479 dialog_doc_metadata_transform_float_to_str (const GValue
*float_value
,
480 GValue
*string_value
)
486 g_return_if_fail (G_VALUE_HOLDS_FLOAT (float_value
));
487 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
489 x
= g_value_get_float (float_value
);
491 fmt
= go_format_general ();
492 str
= go_format_value (fmt
, x
);
493 g_value_take_string (string_value
, str
);
497 dialog_doc_metadata_transform_boolean_to_str (const GValue
*b_value
,
498 GValue
*string_value
)
502 g_return_if_fail (G_VALUE_HOLDS_BOOLEAN (b_value
));
503 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
505 x
= g_value_get_boolean (b_value
);
507 g_value_set_static_string (string_value
, x
? _("TRUE") : _("FALSE"));
511 gnm_docprop_vector_as_string (GsfDocPropVector
*vector
)
517 GValue vl
= G_VALUE_INIT
;
519 g_return_val_if_fail (vector
!= NULL
, NULL
);
521 g_value_set_object (g_value_init (&vl
, GSF_DOCPROP_VECTOR_TYPE
), vector
);
522 gva
= gsf_value_get_docprop_varray (&vl
);
524 g_return_val_if_fail (gva
!= NULL
, NULL
);
526 num_values
= gva
->n_values
;
527 rstring
= g_string_sized_new (num_values
* 8);
529 for (i
= 0; i
< num_values
; i
++) {
533 v
= g_value_array_get_nth (gva
, i
);
535 if (G_VALUE_TYPE(v
) == G_TYPE_STRING
)
536 str
= g_strescape (g_value_get_string (v
), "");
538 char *b_str
= g_strdup_value_contents (v
);
539 str
= g_strescape (b_str
, "");
542 g_string_append_c (rstring
, '"');
543 g_string_append (rstring
, str
);
544 g_string_append (rstring
, "\", ");
547 if (rstring
->len
> 0)
548 g_string_truncate (rstring
, rstring
->len
- 2);
552 return g_string_free (rstring
, FALSE
);
556 dialog_doc_metadata_transform_docprop_vect_to_str (const GValue
*docprop_value
,
557 GValue
*string_value
)
559 GsfDocPropVector
* docprop_vector
= NULL
;
561 g_return_if_fail (VAL_IS_GSF_DOCPROP_VECTOR (docprop_value
));
562 g_return_if_fail (G_VALUE_HOLDS_STRING (string_value
));
564 docprop_vector
= gsf_value_get_docprop_vector (docprop_value
);
566 if (docprop_vector
!= NULL
)
567 g_value_set_string (string_value
,
568 gnm_docprop_vector_as_string (docprop_vector
));
571 /******************************************************************************
572 * FUNCTIONS RELATED TO 'FILE' PAGE
573 ******************************************************************************/
576 cb_dialog_doc_metadata_change_permission (GtkCheckButton
*bt
,
577 DialogDocMetaData
*state
)
579 g_return_if_fail (state
->file_permissions
!= NULL
);
581 /* Check which button was toggled */
582 if (bt
== state
->owner_read
)
583 state
->file_permissions
->owner_read
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
584 else if (bt
== state
->owner_write
)
585 state
->file_permissions
->owner_write
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
586 else if (bt
== state
->group_read
)
587 state
->file_permissions
->group_read
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
588 else if (bt
== state
->group_write
)
589 state
->file_permissions
->group_write
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
590 else if (bt
== state
->others_read
)
591 state
->file_permissions
->others_read
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
592 else if (bt
== state
->others_write
)
593 state
->file_permissions
->others_write
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bt
));
597 state
->permissions_changed
= TRUE
;
601 dialog_doc_metadata_set_up_permissions (DialogDocMetaData
*state
)
603 g_return_if_fail (state
->metadata
!= NULL
);
605 state
->file_permissions
= go_get_file_permissions (
606 go_doc_get_uri (state
->doc
));
608 if (state
->file_permissions
!= NULL
) {
609 /* Set Check buttons */
612 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->owner_read
),
613 state
->file_permissions
->owner_read
);
615 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->owner_write
),
616 state
->file_permissions
->owner_write
);
619 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->group_read
),
620 state
->file_permissions
->group_read
);
622 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->group_write
),
623 state
->file_permissions
->group_write
);
626 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->others_read
),
627 state
->file_permissions
->others_read
);
629 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->others_write
),
630 state
->file_permissions
->others_write
);
633 /* At this moment we don't let user change file permissions */
634 gtk_widget_set_sensitive (GTK_WIDGET (state
->owner_read
), FALSE
);
635 gtk_widget_set_sensitive (GTK_WIDGET (state
->owner_write
), FALSE
);
636 gtk_widget_set_sensitive (GTK_WIDGET (state
->group_read
), FALSE
);
637 gtk_widget_set_sensitive (GTK_WIDGET (state
->group_write
), FALSE
);
638 gtk_widget_set_sensitive (GTK_WIDGET (state
->others_read
), FALSE
);
639 gtk_widget_set_sensitive (GTK_WIDGET (state
->others_write
), FALSE
);
642 /* @auto_fill : if TRUE and the text is NULL, try to set the label text with an automatic value. */
644 dialog_doc_metadata_set_label (DialogDocMetaData
*state
,
649 Workbook
*wb
= state
->wb
;
650 gchar
*str_value
= NULL
;
652 g_return_if_fail (label
!= NULL
);
655 str_value
= g_strdup (text
);
657 if (str_value
== NULL
&& auto_fill
== TRUE
) {
659 if (label
== state
->file_name
) {
660 str_value
= go_basename_from_uri (go_doc_get_uri (state
->doc
));
664 else if (label
== state
->location
) {
665 str_value
= go_dirname_from_uri (go_doc_get_uri (state
->doc
), TRUE
);
669 else if (label
== state
->created
) {
670 /* Nothing to do ATM */
674 else if (label
== state
->modified
) {
675 str_value
= time2str (go_file_get_date_modified (go_doc_get_uri (state
->doc
)));
679 else if (label
== state
->accessed
) {
680 str_value
= time2str (go_file_get_date_accessed (go_doc_get_uri (state
->doc
)));
684 else if (label
== state
->owner
) {
685 str_value
= go_file_get_owner_name (go_doc_get_uri (state
->doc
));
689 else if (label
== state
->group
) {
690 str_value
= go_file_get_group_name (go_doc_get_uri (state
->doc
));
693 /* Number of Sheets */
694 else if (label
== state
->sheets
) {
695 str_value
= g_strdup_printf ("%d", workbook_sheet_count (wb
));
698 /* Number of cells */
699 else if (label
== state
->cells
) {
700 /* Nothing to do ATM */
703 /* Number of pages */
704 else if (label
== state
->pages
) {
705 /* Nothing to do ATM */
709 if (str_value
!= NULL
) {
710 gtk_label_set_text (label
, str_value
);
713 gtk_label_set_text (label
, _("Unknown"));
717 dialog_doc_metadata_init_file_page (DialogDocMetaData
*state
)
719 g_return_if_fail (state
->metadata
!= NULL
);
721 /* Set up the labels */
722 dialog_doc_metadata_set_label (state
, state
->file_name
, NULL
, TRUE
);
723 dialog_doc_metadata_set_label (state
, state
->location
, NULL
, TRUE
);
724 dialog_doc_metadata_set_label (state
, state
->created
, NULL
, TRUE
);
725 dialog_doc_metadata_set_label (state
, state
->modified
, NULL
, TRUE
);
726 dialog_doc_metadata_set_label (state
, state
->accessed
, NULL
, TRUE
);
727 dialog_doc_metadata_set_label (state
, state
->owner
, NULL
, TRUE
);
728 dialog_doc_metadata_set_label (state
, state
->group
, NULL
, TRUE
);
730 /* Set up check buttons */
731 state
->permissions_changed
= FALSE
;
732 dialog_doc_metadata_set_up_permissions (state
);
737 g_signal_connect (G_OBJECT (state
->owner_read
),
739 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
742 g_signal_connect (G_OBJECT (state
->owner_write
),
744 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
748 g_signal_connect (G_OBJECT (state
->group_read
),
750 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
753 g_signal_connect (G_OBJECT (state
->group_write
),
755 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
759 g_signal_connect (G_OBJECT (state
->others_read
),
761 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
764 g_signal_connect (G_OBJECT (state
->others_write
),
766 G_CALLBACK (cb_dialog_doc_metadata_change_permission
),
771 /******************************************************************************
772 * FUNCTIONS RELATED TO 'DESCRIPTION' PAGE
773 ******************************************************************************/
775 /* @activate_property : if TRUE, sets the tree view row which was added active. */
777 dialog_doc_metadata_add_prop (DialogDocMetaData
*state
,
783 gboolean editable
= (val_type
!= G_TYPE_INVALID
)
784 && (val_type
!= GSF_DOCPROP_VECTOR_TYPE
);
791 /* Append new values in tree view */
792 gtk_tree_store_insert_with_values (state
->properties_store
, NULL
, NULL
, G_MAXINT
,
802 dialog_doc_metadata_get_gsf_prop_val_type (DialogDocMetaData
*state
,
805 GsfDocProp
*prop
= NULL
;
806 GValue
*value
= NULL
;
808 g_return_val_if_fail (state
->metadata
!= NULL
, G_TYPE_INVALID
);
810 /* First we try the clean way */
811 prop
= gsf_doc_meta_data_lookup (state
->metadata
, name
);
814 value
= (GValue
*) gsf_doc_prop_get_val (prop
);
817 return dialog_doc_metadata_get_value_type (value
);
819 return dialog_doc_metadata_get_value_type_from_name (name
, G_TYPE_STRING
);
823 dialog_doc_metadata_set_gsf_prop_val (DialogDocMetaData
*state
,
825 const gchar
*str_val
)
827 GType t
= G_VALUE_TYPE (prop_value
);
829 /* The preinstalled transform functions do not handle simple transformations */
830 /* such as from string to double, so we do that ourselves */
833 g_value_set_string (prop_value
, g_strdup (str_val
));
838 GnmValue
*val
= NULL
;
839 GnmExprTop
const *texpr
= NULL
;
840 parse_pos_init_sheet (&pos
, workbook_sheet_by_index (state
->wb
, 0));
841 parse_text_value_or_expr (&pos
, str_val
,
844 gnm_float fl
= value_get_as_float (val
);
846 if (t
== G_TYPE_DOUBLE
)
847 g_value_set_double (prop_value
, fl
);
849 g_value_set_float (prop_value
, fl
);
852 gnm_expr_top_unref (texpr
);
856 if (g_value_type_transformable (t
, G_TYPE_STRING
)) {
857 GValue string_value
= G_VALUE_INIT
;
858 g_value_init (&string_value
, G_TYPE_STRING
);
859 g_value_set_string (&string_value
, g_strdup (str_val
));
860 g_value_transform (&string_value
, prop_value
);
861 g_value_unset (&string_value
);
863 g_printerr (_("Transform function of G_TYPE_STRING to %s is required!\n"),
870 * dialog_doc_metadata_set_gsf_prop
872 * @state: dialog main struct
873 * @name: property name
874 * @value: property value
875 * @lnk: property linked to
877 * Sets a new value to the property in the GsfDocMetaData struct
881 dialog_doc_metadata_set_gsf_prop (DialogDocMetaData
*state
,
887 GsfDocProp
*existing_prop
= NULL
;
888 GsfDocProp
*doc_prop
;
889 GValue
*existing_value
= NULL
;
890 char const *existing_link
= NULL
;
893 existing_prop
= gsf_doc_meta_data_lookup (state
->metadata
, name
);
894 if (existing_prop
!= NULL
) {
895 existing_value
= (GValue
*) gsf_doc_prop_get_val (existing_prop
);
896 existing_link
= gsf_doc_prop_get_link (existing_prop
);
899 if (lnk
!= NULL
&& *lnk
== 0)
901 if (value
!= NULL
&& *value
== 0)
903 if ((value
== NULL
) && (lnk
== NULL
)) {
904 if ((existing_prop
== NULL
) ||
905 ((existing_value
== NULL
) && (existing_link
== NULL
)))
906 return G_TYPE_INVALID
;
908 cmd_change_meta_data (GNM_WBC (state
->wbcg
), NULL
,
909 g_slist_prepend (NULL
, g_strdup (name
)));
910 return G_TYPE_INVALID
;
914 if (existing_prop
!= NULL
) {
915 gboolean link_changed
;
916 gboolean value_changed
= TRUE
;
918 if (existing_link
!= NULL
&& *existing_link
== 0)
919 existing_link
= NULL
;
920 if (lnk
== existing_link
)
921 link_changed
= FALSE
;
922 else if (lnk
== NULL
|| existing_link
== NULL
)
925 link_changed
= (0 != strcmp (lnk
, existing_link
));
927 if (existing_value
== NULL
)
928 value_changed
= (value
!= NULL
);
929 else if (G_VALUE_HOLDS_STRING (existing_value
) && (type
== 0 || type
== G_TYPE_STRING
)) {
930 char const * existing_val_str
= g_value_get_string (existing_value
);
931 if (existing_val_str
!= NULL
&& *existing_val_str
== 0)
932 existing_val_str
= NULL
;
933 if (value
== existing_val_str
)
934 value_changed
= FALSE
;
935 else if (value
== NULL
|| existing_val_str
== NULL
)
936 value_changed
= TRUE
;
938 value_changed
= (0 != strcmp (value
, existing_val_str
));
939 if (!link_changed
&& !value_changed
)
940 return G_TYPE_STRING
;
945 /* Create a new GsfDocProp */
946 doc_prop
= gsf_doc_prop_new (g_strdup (name
));
949 val_type
= dialog_doc_metadata_get_gsf_prop_val_type (state
, name
);
953 if (val_type
!= G_TYPE_INVALID
) {
954 GValue
*doc_prop_value
;
956 /* Create a new Value */
957 doc_prop_value
= g_new0 (GValue
, 1);
959 g_value_init (doc_prop_value
, val_type
);
960 dialog_doc_metadata_set_gsf_prop_val (state
, doc_prop_value
, value
);
961 gsf_doc_prop_set_val (doc_prop
, doc_prop_value
);
965 gsf_doc_prop_set_link (doc_prop
, g_strdup (lnk
));
967 cmd_change_meta_data (GNM_WBC (state
->wbcg
),
968 g_slist_prepend (NULL
, doc_prop
), NULL
);
974 * dialog_doc_metadata_set_prop
976 * @state: dialog main struct
977 * @prop_name: property name
978 * @prop_value: property value
980 * Tries to update the property value in all the dialog and in the GsfDocMetaData
981 * struct. If the property was not found, creates a new one.
985 dialog_doc_metadata_set_prop (DialogDocMetaData
*state
,
986 const gchar
*prop_name
,
987 const gchar
*prop_value
,
988 const gchar
*link_value
,
991 GtkTreeIter tree_iter
;
996 GsfDocProp
*updated_prop
;
997 gchar
*new_prop_value
= NULL
;
999 g_return_if_fail (state
->metadata
!= NULL
);
1001 val_type
= dialog_doc_metadata_set_gsf_prop (state
, prop_name
, prop_value
,
1004 /* Due to changes in type, prop_value may have changed */
1005 updated_prop
= gsf_doc_meta_data_lookup (state
->metadata
, prop_name
);
1006 if (updated_prop
!= NULL
) {
1007 GValue
*new_value
= (GValue
*) gsf_doc_prop_get_val (updated_prop
);
1008 if (new_value
!= NULL
)
1009 new_prop_value
= dialog_doc_metadata_get_prop_val (state
, prop_name
, new_value
);
1010 if (new_prop_value
== NULL
)
1011 new_prop_value
= g_strdup ("");
1016 /* Search tree view for property */
1017 value
= g_new0 (GValue
, 1);
1019 ret
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL (state
->properties_store
),
1022 while (ret
== TRUE
) {
1024 gtk_tree_model_get_value (GTK_TREE_MODEL (state
->properties_store
),
1029 if (strcmp (prop_name
, g_value_get_string (value
)) == 0) {
1030 if (updated_prop
!= NULL
) {
1032 gtk_tree_store_set (state
->properties_store
,
1037 if (link_value
!= NULL
)
1038 gtk_tree_store_set (state
->properties_store
,
1044 gtk_tree_store_remove (state
->properties_store
,
1047 g_value_unset (value
);
1053 g_value_unset (value
);
1054 ret
= gtk_tree_model_iter_next (GTK_TREE_MODEL (state
->properties_store
),
1058 if (val_type
!= G_TYPE_INVALID
&& found
== FALSE
)
1059 dialog_doc_metadata_add_prop (state
, prop_name
, new_prop_value
, "", val_type
);
1063 g_free (new_prop_value
);
1067 * CALLBACKS for 'Description' page entries
1070 cb_dialog_doc_metadata_title_changed (GtkEntry
*entry
,
1071 G_GNUC_UNUSED GdkEventFocus
*event
,
1072 DialogDocMetaData
*state
)
1074 dialog_doc_metadata_set_prop (state
,
1075 GSF_META_NAME_TITLE
,
1076 gtk_entry_get_text (entry
),
1077 NULL
, G_TYPE_STRING
);
1082 cb_dialog_doc_metadata_subject_changed (GtkEntry
*entry
,
1083 G_GNUC_UNUSED GdkEventFocus
*event
,
1084 DialogDocMetaData
*state
)
1086 dialog_doc_metadata_set_prop (state
,
1087 GSF_META_NAME_SUBJECT
,
1088 gtk_entry_get_text (entry
),
1089 NULL
, G_TYPE_STRING
);
1094 cb_dialog_doc_metadata_author_changed (GtkEntry
*entry
,
1095 G_GNUC_UNUSED GdkEventFocus
*event
,
1096 DialogDocMetaData
*state
)
1098 dialog_doc_metadata_set_prop (state
,
1099 GSF_META_NAME_INITIAL_CREATOR
,
1100 gtk_entry_get_text (entry
),
1101 NULL
, G_TYPE_STRING
);
1106 cb_dialog_doc_metadata_manager_changed (GtkEntry
*entry
,
1107 G_GNUC_UNUSED GdkEventFocus
*event
,
1108 DialogDocMetaData
*state
)
1110 dialog_doc_metadata_set_prop (state
,
1111 GSF_META_NAME_MANAGER
,
1112 gtk_entry_get_text (entry
),
1113 NULL
, G_TYPE_STRING
);
1118 cb_dialog_doc_metadata_company_changed (GtkEntry
*entry
,
1119 G_GNUC_UNUSED GdkEventFocus
*event
,
1120 DialogDocMetaData
*state
)
1122 dialog_doc_metadata_set_prop (state
,
1123 GSF_META_NAME_COMPANY
,
1124 gtk_entry_get_text (entry
),
1125 NULL
, G_TYPE_STRING
);
1130 cb_dialog_doc_metadata_category_changed (GtkEntry
*entry
,
1131 G_GNUC_UNUSED GdkEventFocus
*event
,
1132 DialogDocMetaData
*state
)
1134 dialog_doc_metadata_set_prop (state
,
1135 GSF_META_NAME_CATEGORY
,
1136 gtk_entry_get_text (entry
),
1137 NULL
, G_TYPE_STRING
);
1142 cb_dialog_doc_metadata_comments_changed (GtkTextView
*view
,
1143 G_GNUC_UNUSED GdkEventFocus
*event
,
1144 DialogDocMetaData
*state
)
1146 GtkTextIter start_iter
;
1147 GtkTextIter end_iter
;
1149 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer (view
);
1151 gtk_text_buffer_get_start_iter (buffer
, &start_iter
);
1152 gtk_text_buffer_get_end_iter (buffer
, &end_iter
);
1154 text
= gtk_text_buffer_get_text (buffer
, &start_iter
, &end_iter
, TRUE
);
1156 dialog_doc_metadata_set_prop (state
,
1157 GSF_META_NAME_DESCRIPTION
,
1159 NULL
, G_TYPE_STRING
);
1164 * dialog_doc_metadata_init_description_page
1166 * @state: dialog main struct
1168 * Initializes the widgets and signals for the 'Description' page.
1172 dialog_doc_metadata_init_description_page (DialogDocMetaData
*state
)
1174 g_return_if_fail (state
->metadata
!= NULL
);
1176 /* At this point, the entry values were already filled */
1178 /* Set up the signals */
1179 g_signal_connect (G_OBJECT (state
->title
),
1181 G_CALLBACK (cb_dialog_doc_metadata_title_changed
),
1184 g_signal_connect (G_OBJECT (state
->subject
),
1186 G_CALLBACK (cb_dialog_doc_metadata_subject_changed
),
1189 g_signal_connect (G_OBJECT (state
->author
),
1191 G_CALLBACK (cb_dialog_doc_metadata_author_changed
),
1194 g_signal_connect (G_OBJECT (state
->manager
),
1196 G_CALLBACK (cb_dialog_doc_metadata_manager_changed
),
1199 g_signal_connect (G_OBJECT (state
->company
),
1201 G_CALLBACK (cb_dialog_doc_metadata_company_changed
),
1204 g_signal_connect (G_OBJECT (state
->category
),
1206 G_CALLBACK (cb_dialog_doc_metadata_category_changed
),
1209 g_signal_connect (G_OBJECT (state
->comments
),
1211 G_CALLBACK (cb_dialog_doc_metadata_comments_changed
),
1215 /******************************************************************************
1216 * FUNCTIONS RELATED TO 'KEYWORDS' PAGE
1217 ******************************************************************************/
1220 dialog_doc_metadata_update_keywords_changed (DialogDocMetaData
*state
)
1222 GValue val
= G_VALUE_INIT
;
1224 GsfDocPropVector
*vector
= gsf_docprop_vector_new ();
1226 g_value_init (&val
, GSF_DOCPROP_VECTOR_TYPE
);
1228 if (gtk_tree_model_get_iter_first
1229 (GTK_TREE_MODEL (state
->key_store
), &iter
)) {
1231 GValue
*value
= g_new0 (GValue
, 1);
1232 gtk_tree_model_get_value
1233 (GTK_TREE_MODEL (state
->key_store
), &iter
,
1235 gsf_docprop_vector_append (vector
, value
);
1236 g_value_unset (value
);
1238 } while (gtk_tree_model_iter_next
1239 (GTK_TREE_MODEL (state
->key_store
), &iter
));
1241 g_value_set_object (&val
, vector
);
1242 g_object_unref (vector
);
1244 dialog_doc_metadata_set_prop
1245 (state
, GSF_META_NAME_KEYWORDS
,
1246 dialog_doc_metadata_get_prop_val (state
, GSF_META_NAME_KEYWORDS
, &val
),
1247 NULL
, GSF_DOCPROP_VECTOR_TYPE
);
1249 g_value_unset (&val
);
1253 cb_dialog_doc_metadata_keywords_sel_changed (GtkTreeSelection
*treeselection
,
1254 DialogDocMetaData
*state
)
1256 gtk_widget_set_sensitive
1257 (GTK_WIDGET (state
->key_remove_button
),
1258 gtk_tree_selection_get_selected (treeselection
, NULL
, NULL
));
1262 dialog_doc_metadata_update_keyword_list (DialogDocMetaData
*state
, GsfDocProp
*prop
)
1265 GtkTreeSelection
*sel
;
1267 gtk_list_store_clear (state
->key_store
);
1271 array
= gsf_value_get_docprop_varray (gsf_doc_prop_get_val (prop
));
1272 if (array
!= NULL
) {
1273 for (i
= 0; i
< array
->n_values
; i
++) {
1274 GValue
*val
= g_value_array_get_nth (array
, i
);
1275 gtk_list_store_insert_with_values
1276 (state
->key_store
, NULL
, G_MAXINT
,
1277 0, g_value_get_string (val
), -1);
1282 sel
= gtk_tree_view_get_selection (state
->key_tree_view
);
1283 cb_dialog_doc_metadata_keywords_sel_changed (sel
, state
);
1287 cb_dialog_doc_metadata_keywords_add_clicked (G_GNUC_UNUSED GtkWidget
*w
,
1288 DialogDocMetaData
*state
)
1290 gtk_list_store_insert_with_values (state
->key_store
, NULL
, G_MAXINT
,
1292 dialog_doc_metadata_update_keywords_changed (state
);
1296 cb_dialog_doc_metadata_keywords_remove_clicked (G_GNUC_UNUSED GtkWidget
*w
,
1297 DialogDocMetaData
*state
)
1300 GtkTreeSelection
*sel
= gtk_tree_view_get_selection (state
->key_tree_view
);
1302 if (gtk_tree_selection_get_selected (sel
, NULL
, &iter
)) {
1303 gtk_list_store_remove (state
->key_store
, &iter
);
1304 dialog_doc_metadata_update_keywords_changed (state
);
1309 cb_dialog_doc_metadata_keyword_edited (G_GNUC_UNUSED GtkCellRendererText
*renderer
,
1312 DialogDocMetaData
*state
)
1315 if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (state
->key_store
), &iter
, path
)) {
1316 gtk_list_store_set (state
->key_store
, &iter
, 0, new_text
, -1);
1317 dialog_doc_metadata_update_keywords_changed (state
);
1323 * dialog_doc_metadata_init_keywords_page
1325 * @state: dialog main struct
1327 * Initializes the widgets and signals for the 'Description' page.
1331 dialog_doc_metadata_init_keywords_page (DialogDocMetaData
*state
)
1333 GtkTreeViewColumn
*column
;
1334 GtkCellRenderer
*renderer
;
1335 GtkTreeSelection
*sel
;
1337 g_return_if_fail (state
->metadata
!= NULL
);
1339 renderer
= gtk_cell_renderer_text_new ();
1340 g_object_set (G_OBJECT (renderer
), "editable", TRUE
, NULL
);
1341 column
= gtk_tree_view_column_new_with_attributes (_("Keywords"),
1345 gtk_tree_view_insert_column (state
->key_tree_view
, column
, -1);
1347 gtk_widget_set_sensitive (GTK_WIDGET (state
->key_add_button
), TRUE
);
1348 gtk_widget_set_sensitive (GTK_WIDGET (state
->key_remove_button
), FALSE
);
1350 sel
= gtk_tree_view_get_selection (state
->key_tree_view
);
1351 g_signal_connect (G_OBJECT (sel
),
1353 G_CALLBACK (cb_dialog_doc_metadata_keywords_sel_changed
),
1356 g_signal_connect (G_OBJECT (state
->key_add_button
),
1358 G_CALLBACK (cb_dialog_doc_metadata_keywords_add_clicked
),
1360 g_signal_connect (G_OBJECT (state
->key_remove_button
),
1362 G_CALLBACK (cb_dialog_doc_metadata_keywords_remove_clicked
),
1364 g_signal_connect (G_OBJECT (renderer
),
1366 G_CALLBACK (cb_dialog_doc_metadata_keyword_edited
),
1369 cb_dialog_doc_metadata_keywords_sel_changed (sel
, state
);
1372 /******************************************************************************
1373 * FUNCTIONS RELATED TO 'PROPERTIES' PAGE
1374 ******************************************************************************/
1377 cb_dialog_doc_metadata_value_edited (G_GNUC_UNUSED GtkCellRendererText
*renderer
,
1380 DialogDocMetaData
*state
)
1383 if (gtk_tree_model_get_iter_from_string
1384 (GTK_TREE_MODEL (state
->properties_store
), &iter
, path
)) {
1389 gtk_tree_model_get (GTK_TREE_MODEL (state
->properties_store
),
1395 dialog_doc_metadata_set_prop (state
, prop_name
, new_text
, link_value
, type
);
1397 g_free (link_value
);
1402 * cb_dialog_doc_metadata_add_clicked
1405 * @state: dialog main struct
1407 * Adds a new "empty" property to the tree view.
1411 cb_dialog_doc_metadata_add_clicked (G_GNUC_UNUSED GtkWidget
*w
,
1412 DialogDocMetaData
*state
)
1414 const gchar
*name
= gtk_entry_get_text (state
->ppt_name
);
1415 const gchar
*value
= gtk_entry_get_text (state
->ppt_value
);
1416 gchar
*name_trimmed
= trim_string (name
);
1418 GtkTreeIter filter_iter
;
1420 if (gtk_combo_box_get_active_iter (state
->ppt_type
, &filter_iter
)) {
1421 GtkTreeIter child_iter
;
1422 gtk_tree_model_filter_convert_iter_to_child_iter
1423 (state
->type_store_filter
, &child_iter
, &filter_iter
);
1424 gtk_tree_model_get (GTK_TREE_MODEL (state
->type_store
), &child_iter
,
1427 t
= dialog_doc_metadata_get_value_type_from_name (name_trimmed
, G_TYPE_STRING
);
1428 dialog_doc_metadata_set_prop (state
, name_trimmed
, value
, NULL
, t
);
1430 g_free (name_trimmed
);
1432 cb_dialog_doc_metadata_ppt_changed (NULL
, NULL
, state
);
1433 gtk_label_set_text (state
->warning
, "");
1437 * dialog_doc_metadata_update_prop
1439 * @state: dialog main struct
1440 * @prop_name: property name
1441 * @prop_value: property value
1443 * Updates a label or a entry text with the new value.
1448 dialog_doc_metadata_update_prop (DialogDocMetaData
*state
,
1449 const gchar
*prop_name
,
1450 const gchar
*prop_value
,
1454 if (strcmp (prop_name
, GSF_META_NAME_DATE_CREATED
) == 0) {
1455 dialog_doc_metadata_set_label (state
,
1460 else if (strcmp (prop_name
, GSF_META_NAME_DATE_MODIFIED
) == 0) {
1461 dialog_doc_metadata_set_label (state
,
1466 else if (strcmp (prop_name
, GSF_META_NAME_SPREADSHEET_COUNT
) == 0) {
1467 dialog_doc_metadata_set_label (state
,
1472 else if (strcmp (prop_name
, GSF_META_NAME_CELL_COUNT
) == 0) {
1473 dialog_doc_metadata_set_label (state
,
1478 else if (strcmp (prop_name
, GSF_META_NAME_PAGE_COUNT
) == 0) {
1479 dialog_doc_metadata_set_label (state
,
1486 if (prop_value
== NULL
)
1489 if (strcmp (prop_name
, GSF_META_NAME_TITLE
) == 0) {
1490 gtk_entry_set_text (state
->title
, prop_value
);
1493 else if (strcmp (prop_name
, GSF_META_NAME_SUBJECT
) == 0) {
1494 gtk_entry_set_text (state
->subject
, prop_value
);
1497 else if (strcmp (prop_name
, GSF_META_NAME_INITIAL_CREATOR
) == 0) {
1498 gtk_entry_set_text (state
->author
, prop_value
);
1501 else if (strcmp (prop_name
, GSF_META_NAME_MANAGER
) == 0) {
1502 gtk_entry_set_text (state
->manager
, prop_value
);
1505 else if (strcmp (prop_name
, GSF_META_NAME_COMPANY
) == 0) {
1506 gtk_entry_set_text (state
->company
, prop_value
);
1509 else if (strcmp (prop_name
, GSF_META_NAME_CATEGORY
) == 0) {
1510 gtk_entry_set_text (state
->category
, prop_value
);
1513 else if (strcmp (prop_name
, GSF_META_NAME_KEYWORDS
) == 0) {
1514 dialog_doc_metadata_update_keyword_list (state
, prop
);
1517 else if (strcmp (prop_name
, GSF_META_NAME_DESCRIPTION
) == 0) {
1518 gtk_text_buffer_set_text (gtk_text_view_get_buffer (state
->comments
),
1525 * cb_dialog_doc_metadata_remove_clicked
1527 * @remove_bt: widget
1528 * @state: dialog main struct
1530 * Removes a property from the tree view and updates all the dialog and
1531 * the GsfDocMetaData struct.
1535 cb_dialog_doc_metadata_remove_clicked (GtkWidget
*remove_bt
,
1536 DialogDocMetaData
*state
)
1538 GtkTreeIter tree_iter
;
1540 GtkTreeSelection
*sel
= gtk_tree_view_get_selection (state
->properties
);
1542 g_return_if_fail (state
->metadata
!= NULL
);
1544 if (gtk_tree_selection_get_selected (sel
, NULL
, &tree_iter
)) {
1546 /* Get the property name */
1547 prop_name
= g_new0 (GValue
, 1);
1548 gtk_tree_model_get_value (GTK_TREE_MODEL (state
->properties_store
),
1553 /* Update other pages */
1554 dialog_doc_metadata_update_prop (state
,
1555 g_value_get_string (prop_name
),
1558 /* Remove property from GsfMetadata */
1559 cmd_change_meta_data (GNM_WBC (state
->wbcg
), NULL
,
1560 g_slist_prepend (NULL
, g_value_dup_string (prop_name
)));
1562 /* Remove from Tree View */
1563 gtk_tree_store_remove (state
->properties_store
,
1567 g_value_unset (prop_name
);
1571 /* Set remove button insensitive */
1572 gtk_widget_set_sensitive (remove_bt
, FALSE
);
1577 * cb_dialog_doc_metadata_tree_prop_selected
1579 * @combo_box: widget
1580 * @state: dialog main struct
1582 * Update the highlited item in the 'Properties' page combo box.
1586 cb_dialog_doc_metadata_tree_prop_selected (GtkTreeSelection
*selection
,
1587 DialogDocMetaData
*state
)
1591 gchar
const *text
= "";
1593 g_return_if_fail (state
->metadata
!= NULL
);
1595 selected
= gtk_tree_selection_get_selected (selection
, NULL
, &iter
);
1597 /* Set remove button sensitive */
1598 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove_button
), selected
);
1601 GType val_type
= G_TYPE_INVALID
;
1602 gchar
*prop_name
= NULL
;
1603 gtk_tree_model_get (GTK_TREE_MODEL (state
->properties_store
),
1610 text
= _("Edit string value directly in above listing.");
1613 text
= _("Edit positive integer value directly in above listing.");
1616 text
= _("Edit integer value directly in above listing.");
1620 text
= _("Edit decimal number value directly in above listing.");
1622 case G_TYPE_BOOLEAN
:
1623 text
= _("Edit TRUE/FALSE value directly in above listing.");
1626 if (val_type
== GSF_DOCPROP_VECTOR_TYPE
) {
1627 if (0 == strcmp (prop_name
, "dc:keywords"))
1628 text
= _("To edit, use the keywords tab.");
1630 text
= _("This property value cannot be edited.");
1631 } else if (val_type
== GSF_TIMESTAMP_TYPE
)
1632 text
= _("Edit timestamp directly in above listing.");
1638 gtk_label_set_text (state
->instruction
, text
);
1642 * dialog_doc_metadata_get_prop_val
1644 * @prop_name: property name
1645 * @prop_value: property value
1647 * Retrieves an arbitrary property value always as string.
1651 dialog_doc_metadata_get_prop_val (G_GNUC_UNUSED DialogDocMetaData
*state
,
1652 char const *prop_name
,
1655 GValue str_value
= G_VALUE_INIT
;
1656 gboolean ret
= FALSE
;
1658 g_return_val_if_fail (prop_value
!= NULL
, NULL
);
1660 g_value_init (&str_value
, G_TYPE_STRING
);
1662 ret
= g_value_transform (prop_value
, &str_value
);
1665 g_warning ("Metadata tag '%s' holds unrecognized value type.", prop_name
);
1669 return g_value_dup_string (&str_value
);
1673 * dialog_doc_metadata_populate_tree_view
1675 * @name: property name
1676 * @prop: property stored in GsfDocMetaData
1677 * @state: dialog main struct
1679 * Populates the tree view in 'Properties' page.
1683 dialog_doc_metadata_populate_tree_view (gchar
*name
,
1685 DialogDocMetaData
*state
)
1691 g_return_if_fail (state
->metadata
!= NULL
);
1693 value
= (GValue
*) gsf_doc_prop_get_val (prop
);
1694 /* Get the prop value as string */
1695 str_value
= dialog_doc_metadata_get_prop_val (state
, name
, value
);
1697 link_value
= (char *) gsf_doc_prop_get_link (prop
);
1699 dialog_doc_metadata_add_prop
1701 gsf_doc_prop_get_name (prop
),
1702 str_value
== NULL
? "" : str_value
,
1703 link_value
== NULL
? "" : link_value
,
1704 dialog_doc_metadata_get_value_type (value
));
1706 dialog_doc_metadata_update_prop (state
, gsf_doc_prop_get_name (prop
), str_value
, prop
);
1712 dialog_doc_metadata_show_all_types (GtkTreeModel
*model
,
1713 G_GNUC_UNUSED GtkTreePath
*path
,
1715 G_GNUC_UNUSED gpointer data
)
1717 gtk_list_store_set (GTK_LIST_STORE (model
), iter
, 2, TRUE
, -1);
1722 dialog_doc_metadata_show_this_type (GtkTreeModel
*model
,
1723 G_GNUC_UNUSED GtkTreePath
*path
,
1727 GType t
, type
= GPOINTER_TO_INT (data
);
1729 gtk_tree_model_get (model
, iter
, 1, &t
, -1);
1730 gtk_list_store_set (GTK_LIST_STORE (model
), iter
, 2, t
== type
, -1);
1735 cb_dialog_doc_metadata_ppt_changed (G_GNUC_UNUSED GtkEntry
*entry
,
1736 G_GNUC_UNUSED GdkEventFocus
*event
,
1737 DialogDocMetaData
*state
)
1741 gchar
*name_trimmed
;
1742 gboolean enable
= FALSE
;
1744 GsfDocProp
*prop
= NULL
;
1747 name
= gtk_entry_get_text (state
->ppt_name
);
1748 value
= gtk_entry_get_text (state
->ppt_value
);
1749 name_trimmed
= trim_string (name
);
1751 enable
= strlen (name_trimmed
) > 0 && strlen (value
) > 0;
1754 enable
= gtk_combo_box_get_active_iter (state
->ppt_type
, &iter
);
1757 prop
= gsf_doc_meta_data_lookup (state
->metadata
, name_trimmed
);
1759 str
= g_strdup_printf
1760 (_("A document property with the name \'%s\' already exists."),
1765 g_free (name_trimmed
);
1766 gtk_widget_set_sensitive (GTK_WIDGET (state
->add_button
), enable
);
1767 gtk_label_set_text (state
->warning
, str
? str
: "");
1773 cb_dialog_doc_metadata_ppt_type_changed (G_GNUC_UNUSED GtkComboBox
*widget
,
1774 DialogDocMetaData
*state
)
1776 cb_dialog_doc_metadata_ppt_changed (NULL
, NULL
, state
);
1780 cb_dialog_doc_metadata_ppt_name_changed (G_GNUC_UNUSED GtkEntry
*entry
,
1781 G_GNUC_UNUSED GdkEventFocus
*event
,
1782 DialogDocMetaData
*state
)
1785 gchar
*name_trimmed
;
1786 gboolean enable
= FALSE
;
1790 name
= gtk_entry_get_text (state
->ppt_name
);
1791 name_trimmed
= trim_string (name
);
1793 enable
= strlen (name_trimmed
) > 0;
1796 GType t
= dialog_doc_metadata_get_value_type_from_name (name_trimmed
, G_TYPE_INVALID
);
1798 if (t
== GSF_DOCPROP_VECTOR_TYPE
) {
1799 str
= g_strdup_printf
1800 (_("Use the keywords tab to create this property."));
1804 if (t
== G_TYPE_INVALID
) {
1805 g_signal_handlers_block_by_func(G_OBJECT (state
->ppt_type
),
1806 cb_dialog_doc_metadata_ppt_type_changed
,
1808 gtk_tree_model_foreach (GTK_TREE_MODEL (state
->type_store
),
1809 dialog_doc_metadata_show_all_types
, NULL
);
1810 gtk_tree_model_filter_refilter (state
->type_store_filter
);
1811 g_signal_handlers_unblock_by_func(G_OBJECT (state
->ppt_type
),
1812 cb_dialog_doc_metadata_ppt_type_changed
,
1815 gtk_combo_box_set_active_iter (state
->ppt_type
, NULL
);
1816 g_signal_handlers_block_by_func(G_OBJECT (state
->ppt_type
),
1817 cb_dialog_doc_metadata_ppt_type_changed
,
1819 gtk_tree_model_foreach (GTK_TREE_MODEL (state
->type_store
),
1820 dialog_doc_metadata_show_this_type
,
1821 GINT_TO_POINTER (t
));
1822 gtk_tree_model_filter_refilter (state
->type_store_filter
);
1823 g_signal_handlers_unblock_by_func(G_OBJECT (state
->ppt_type
),
1824 cb_dialog_doc_metadata_ppt_type_changed
,
1826 if (gtk_tree_model_get_iter_first
1827 (GTK_TREE_MODEL (state
->type_store_filter
), &iter
))
1828 gtk_combo_box_set_active_iter (state
->ppt_type
, &iter
);
1831 g_free (name_trimmed
);
1834 return cb_dialog_doc_metadata_ppt_changed (NULL
, NULL
, state
);
1836 gtk_widget_set_sensitive (GTK_WIDGET (state
->add_button
), FALSE
);
1837 gtk_label_set_text (state
->warning
, str
? str
: "");
1847 * dialog_doc_metadata_init_properties_page
1849 * @state: dialog main struct
1851 * Initializes the widgets and signals for the 'Properties' page.
1855 dialog_doc_metadata_init_properties_page (DialogDocMetaData
*state
)
1857 GtkTreeSelection
*sel
;
1858 GtkCellRenderer
*cell
;
1862 char const *type_name
;
1865 {N_("String"), G_TYPE_STRING
},
1866 {N_("Integer"), G_TYPE_INT
},
1867 {N_("Decimal Number"), G_TYPE_FLOAT
},
1868 {N_("TRUE/FALSE"), G_TYPE_BOOLEAN
}
1871 g_return_if_fail (state
->metadata
!= NULL
);
1872 g_return_if_fail (state
->properties
!= NULL
);
1874 /* Set Remove and Apply buttons insensitive */
1875 gtk_widget_set_sensitive (GTK_WIDGET (state
->add_button
), FALSE
);
1876 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove_button
), FALSE
);
1878 /* Intialize Combo Box */
1879 /* gtk_combo_box_set_id_column (state->ppt_type, 0); */
1880 cell
= gtk_cell_renderer_text_new();
1881 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(state
->ppt_type
), cell
, TRUE
);
1882 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(state
->ppt_type
), cell
, "text", 0, NULL
);
1884 for (i
= 0; i
< G_N_ELEMENTS (ppt_types
); i
++)
1885 gtk_list_store_insert_with_values (state
->type_store
, NULL
, G_MAXINT
,
1886 0, _(ppt_types
[i
].type_name
),
1887 1, ppt_types
[i
].type
,
1890 gtk_list_store_insert_with_values (state
->type_store
, NULL
, G_MAXINT
,
1891 0, _("Date & Time"),
1892 1, GSF_TIMESTAMP_TYPE
,
1895 gtk_tree_model_filter_set_visible_column (state
->type_store_filter
, 2);
1896 gtk_tree_model_filter_refilter (state
->type_store_filter
);
1898 /* Populate Treeview */
1899 state
->properties_store
= gtk_tree_store_new (5,
1906 gtk_tree_view_set_model (state
->properties
,
1907 GTK_TREE_MODEL (state
->properties_store
));
1908 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (state
->properties_store
),
1909 0, GTK_SORT_ASCENDING
);
1910 g_object_unref (state
->properties_store
);
1912 /* Append Columns */
1913 gtk_tree_view_insert_column_with_attributes (state
->properties
,
1915 gtk_cell_renderer_text_new(),
1919 cell
= gtk_cell_renderer_text_new();
1920 gtk_tree_view_insert_column_with_attributes (state
->properties
,
1926 g_signal_connect (G_OBJECT (cell
),
1928 G_CALLBACK (cb_dialog_doc_metadata_value_edited
),
1931 gtk_tree_view_insert_column_with_attributes (state
->properties
,
1933 gtk_cell_renderer_text_new(),
1937 /* Read all metadata */
1938 gsf_doc_meta_data_foreach (state
->metadata
,
1939 (GHFunc
) dialog_doc_metadata_populate_tree_view
,
1942 /* Set up signals */
1944 sel
= gtk_tree_view_get_selection (state
->properties
);
1945 g_signal_connect (G_OBJECT (sel
),
1947 G_CALLBACK (cb_dialog_doc_metadata_tree_prop_selected
),
1951 g_signal_connect (G_OBJECT (state
->ppt_name
),
1953 G_CALLBACK (cb_dialog_doc_metadata_ppt_name_changed
),
1955 g_signal_connect (G_OBJECT (state
->ppt_value
),
1957 G_CALLBACK (cb_dialog_doc_metadata_ppt_changed
),
1960 g_signal_connect (G_OBJECT (state
->ppt_type
),
1962 G_CALLBACK (cb_dialog_doc_metadata_ppt_type_changed
),
1965 /* 'Add', 'Remove' and 'Apply' Button Signals */
1966 g_signal_connect (G_OBJECT (state
->add_button
),
1968 G_CALLBACK (cb_dialog_doc_metadata_add_clicked
),
1971 g_signal_connect (G_OBJECT (state
->remove_button
),
1973 G_CALLBACK (cb_dialog_doc_metadata_remove_clicked
),
1976 cb_dialog_doc_metadata_tree_prop_selected (sel
, state
);
1977 gtk_combo_box_set_active (state
->ppt_type
, 0);
1980 /******************************************************************************
1981 * FUNCTIONS RELATED TO 'STATISTICS' PAGE
1982 ******************************************************************************/
1985 * dialog_doc_metadata_init_statistics_page
1987 * @state: dialog main struct
1989 * Initializes the widgets and signals for the 'Statistics' page.
1993 dialog_doc_metadata_init_statistics_page (DialogDocMetaData
*state
)
1995 g_return_if_fail (state
->metadata
!= NULL
);
1997 /* Set up the labels */
1998 dialog_doc_metadata_set_label (state
, state
->sheets
, NULL
, TRUE
);
1999 dialog_doc_metadata_set_label (state
, state
->cells
, NULL
, TRUE
);
2000 dialog_doc_metadata_set_label (state
, state
->pages
, NULL
, TRUE
);
2003 /******************************************************************************
2004 * FUNCTIONS RELATED TO 'CALCULATIONS' PAGE
2005 ******************************************************************************/
2008 cb_dialog_doc_metadata_recalc_max_changed (GtkEntry
*entry
,
2009 G_GNUC_UNUSED GdkEventFocus
*event
,
2010 DialogDocMetaData
*state
)
2013 if (!entry_to_int (entry
, &val
, TRUE
))
2014 /* FIXME: make undoable */
2015 workbook_iteration_max_number (state
->wb
, val
);
2020 cb_dialog_doc_metadata_recalc_tolerance_changed (GtkEntry
*entry
,
2021 G_GNUC_UNUSED GdkEventFocus
*event
,
2022 DialogDocMetaData
*state
)
2025 if (!entry_to_float (entry
, &val
, TRUE
))
2026 /* FIXME: make undoable */
2027 workbook_iteration_tolerance (state
->wb
, val
);
2032 cb_dialog_doc_metadata_recalc_auto_changed (GtkWidget
*widget
, DialogDocMetaData
*state
)
2034 /* FIXME: make undoable */
2035 workbook_set_recalcmode (state
->wb
, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget
)));
2039 cb_dialog_doc_metadata_recalc_iteration_changed (G_GNUC_UNUSED GtkWidget
*widget
, DialogDocMetaData
*state
)
2041 /* FIXME: make undoable */
2042 workbook_iteration_enabled (state
->wb
, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget
)));
2043 gtk_widget_set_sensitive (state
->recalc_iteration_grid
, state
->wb
->iteration
.enabled
);
2047 * dialog_doc_metadata_init_calculations_page
2049 * @state: dialog main struct
2051 * Initializes the widgets and signals for the 'Calculations' page.
2055 dialog_doc_metadata_init_calculations_page (DialogDocMetaData
*state
)
2059 gtk_toggle_button_set_active
2060 (GTK_TOGGLE_BUTTON ( workbook_get_recalcmode (state
->wb
) ? state
->recalc_auto
: state
->recalc_manual
),
2062 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state
->recalc_iteration
),
2063 state
->wb
->iteration
.enabled
);
2064 gtk_widget_set_sensitive (state
->recalc_iteration_grid
, state
->wb
->iteration
.enabled
);
2066 buf
= g_strdup_printf ("%d", state
->wb
->iteration
.max_number
);
2067 gtk_entry_set_text (state
->recalc_max
, buf
);
2069 buf
= g_strdup_printf ("%g", state
->wb
->iteration
.tolerance
);
2070 gtk_entry_set_text (state
->recalc_tolerance
, buf
);
2073 g_signal_connect (G_OBJECT (state
->recalc_auto
),
2075 G_CALLBACK (cb_dialog_doc_metadata_recalc_auto_changed
), state
);
2076 g_signal_connect (G_OBJECT (state
->recalc_iteration
),
2078 G_CALLBACK (cb_dialog_doc_metadata_recalc_iteration_changed
), state
);
2079 g_signal_connect (G_OBJECT (state
->recalc_max
),
2081 G_CALLBACK (cb_dialog_doc_metadata_recalc_max_changed
),
2083 g_signal_connect (G_OBJECT (state
->recalc_tolerance
),
2085 G_CALLBACK (cb_dialog_doc_metadata_recalc_tolerance_changed
),
2090 /******************************************************************************
2091 * DIALOG INITIALIZE/FINALIZE FUNCTIONS
2092 ******************************************************************************/
2095 * dialog_doc_metadata_set_file_permissions
2097 * @state: dialog main struct
2099 * Writes the new file permissions if there were any changes.
2103 dialog_doc_metadata_set_file_permissions (DialogDocMetaData
*state
)
2105 if (state
->file_permissions
!= NULL
&&
2106 state
->permissions_changed
== TRUE
)
2107 go_set_file_permissions (go_doc_get_uri (state
->doc
),
2108 state
->file_permissions
);
2112 dialog_doc_metadata_free (DialogDocMetaData
*state
)
2114 WorkbookControl
*wbc
= GNM_WBC (state
->wbcg
);
2116 wb_view_selection_desc (wb_control_view (wbc
), TRUE
, wbc
);
2118 if (state
->gui
!= NULL
) {
2119 dialog_doc_metadata_set_file_permissions (state
);
2121 g_object_unref (state
->gui
);
2125 g_free (state
->file_permissions
);
2126 state
->file_permissions
= NULL
;
2128 wbcg_edit_finish (state
->wbcg
, WBC_EDIT_REJECT
, NULL
);
2130 state
->dialog
= NULL
;
2136 dialog_doc_metadata_init_widgets (DialogDocMetaData
*state
)
2138 state
->dialog
= go_gtk_builder_get_widget (state
->gui
, "GOMetadataDialog");
2140 state
->notebook
= GTK_NOTEBOOK (go_gtk_builder_get_widget (state
->gui
, "notebook"));
2141 state
->help_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "help_button"));
2142 state
->close_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "close_button"));
2144 /* File Information Page */
2145 state
->file_name
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "file_name"));
2146 state
->location
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "location"));
2147 state
->created
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "created"));
2148 state
->modified
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "modified"));
2149 state
->accessed
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "accessed"));
2150 state
->owner
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "owner"));
2151 state
->group
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "group"));
2153 state
->owner_read
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "owner_read"));
2154 state
->owner_write
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "owner_write"));
2156 state
->group_read
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "group_read"));
2157 state
->group_write
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "group_write"));
2159 state
->others_read
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "others_read"));
2160 state
->others_write
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "others_write"));
2162 /* Description Page */
2163 state
->title
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "title"));
2164 state
->subject
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "subject"));
2165 state
->author
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "author"));
2166 state
->manager
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "manager"));
2167 state
->company
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "company"));
2168 state
->category
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "category"));
2170 state
->comments
= GTK_TEXT_VIEW (go_gtk_builder_get_widget (state
->gui
, "comments"));
2172 /* Properties Page */
2173 state
->properties
= GTK_TREE_VIEW (go_gtk_builder_get_widget (state
->gui
, "properties"));
2175 state
->ppt_name
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "property-name"));
2176 state
->ppt_value
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "property-value"));
2177 state
->ppt_type
= GTK_COMBO_BOX (go_gtk_builder_get_widget (state
->gui
, "type-combo"));
2178 state
->type_store
= GTK_LIST_STORE (gtk_builder_get_object (state
->gui
, "typestore"));
2179 state
->type_store_filter
= GTK_TREE_MODEL_FILTER (gtk_combo_box_get_model (state
->ppt_type
));
2181 state
->add_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "add_button"));
2182 state
->remove_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "remove_button"));
2183 state
->instruction
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "instruction-label"));
2184 state
->warning
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "warning"));
2187 state
->key_tree_view
= GTK_TREE_VIEW (go_gtk_builder_get_widget (state
->gui
, "keyview"));
2188 state
->key_store
= GTK_LIST_STORE (gtk_tree_view_get_model (state
->key_tree_view
));
2189 state
->key_add_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "key-add-button"));
2190 state
->key_remove_button
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "key-remove-button"));
2192 /* Statistics Page */
2193 state
->sheets
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "sheets"));
2194 state
->cells
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "cells"));
2195 state
->pages
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "pages"));
2197 /* Calculations Page */
2198 state
->recalc_auto
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "recalc_auto"));
2199 state
->recalc_manual
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "recalc_manual"));
2200 state
->recalc_iteration
= GTK_CHECK_BUTTON (go_gtk_builder_get_widget (state
->gui
, "iteration_enabled"));
2201 state
->recalc_max
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "max_iterations"));
2202 state
->recalc_tolerance
= GTK_ENTRY (go_gtk_builder_get_widget (state
->gui
, "iteration_tolerance"));
2203 state
->recalc_iteration_grid
= go_gtk_builder_get_widget (state
->gui
, "iteration-grid");
2207 dialog_doc_meta_data_add_item (DialogDocMetaData
*state
, char const *page_name
,
2208 char const *icon_name
,
2209 int page
, char const* parent_path
)
2211 GtkTreeIter iter
, parent
;
2212 GdkPixbuf
* icon
= NULL
;
2214 if (icon_name
!= NULL
)
2215 icon
= gtk_widget_render_icon_pixbuf (state
->dialog
, icon_name
,
2216 GTK_ICON_SIZE_MENU
);
2217 if ((parent_path
!= NULL
) && gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (state
->store
),
2218 &parent
, parent_path
))
2219 gtk_tree_store_append (state
->store
, &iter
, &parent
);
2221 gtk_tree_store_append (state
->store
, &iter
, NULL
);
2223 gtk_tree_store_set (state
->store
, &iter
,
2225 ITEM_NAME
, _(page_name
),
2229 g_object_unref (icon
);
2233 char const *page_name
;
2234 char const *icon_name
;
2235 char const *parent_path
;
2237 void (*page_initializer
) (DialogDocMetaData
*state
);
2240 static page_info_t
const page_info
[] = {
2241 /* IMPORTANT: OBEY THE ORDER 0 - 3 - 2 - 1 */
2242 {N_("File"), GTK_STOCK_FILE
, NULL
, 0, &dialog_doc_metadata_init_file_page
},
2243 {N_("Statistics"), "gnumeric-graphguru", NULL
, 3 ,&dialog_doc_metadata_init_statistics_page
},
2244 {N_("Properties"), GTK_STOCK_PROPERTIES
, NULL
, 2, &dialog_doc_metadata_init_properties_page
},
2245 {N_("Description"), GTK_STOCK_ABOUT
, NULL
, 1, &dialog_doc_metadata_init_description_page
},
2246 {N_("Keywords"), GTK_STOCK_INDEX
, NULL
, 5, &dialog_doc_metadata_init_keywords_page
},
2247 {N_("Calculation"), GTK_STOCK_EXECUTE
, NULL
, 4, &dialog_doc_metadata_init_calculations_page
},
2248 {NULL
, NULL
, NULL
, -1, NULL
},
2257 dialog_doc_metadata_select_page_search (GtkTreeModel
*model
,
2263 gtk_tree_model_get (model
, iter
, PAGE_NUMBER
, &page
, -1);
2264 if (page
== pst
->page
) {
2265 pst
->path
= gtk_tree_path_copy (path
);
2272 dialog_doc_metadata_select_page (DialogDocMetaData
*state
, int page
)
2274 page_search_t pst
= {page
, NULL
};
2277 gtk_tree_model_foreach (GTK_TREE_MODEL (state
->store
),
2278 (GtkTreeModelForeachFunc
) dialog_doc_metadata_select_page_search
,
2281 if (pst
.path
== NULL
)
2282 pst
.path
= gtk_tree_path_new_from_string ("0");
2284 if (pst
.path
!= NULL
) {
2285 gtk_tree_view_set_cursor (state
->view
, pst
.path
, NULL
, FALSE
);
2286 gtk_tree_view_expand_row (state
->view
, pst
.path
, TRUE
);
2287 gtk_tree_path_free (pst
.path
);
2292 cb_dialog_doc_metadata_selection_changed (GtkTreeSelection
*selection
,
2293 DialogDocMetaData
*state
)
2298 if (gtk_tree_selection_get_selected (selection
, NULL
, &iter
)) {
2299 gtk_tree_model_get (GTK_TREE_MODEL (state
->store
), &iter
,
2302 gtk_notebook_set_current_page (state
->notebook
, page
);
2304 dialog_doc_metadata_select_page (state
, 0);
2309 dialog_doc_metadata_init (DialogDocMetaData
*state
,
2312 GtkTreeViewColumn
*column
;
2313 GtkTreeSelection
*selection
;
2317 state
->wb
= wb_control_get_workbook (GNM_WBC(wbcg
));
2318 state
->doc
= GO_DOC (state
->wb
);
2319 state
->metadata
= go_doc_get_meta_data (wb_control_get_doc (GNM_WBC (state
->wbcg
)));
2321 g_return_val_if_fail (state
->metadata
!= NULL
, TRUE
);
2323 state
->gui
= gnm_gtk_builder_load ("res:ui/doc-meta-data.ui", NULL
,
2324 GO_CMD_CONTEXT (wbcg
));
2326 if (state
->gui
== NULL
)
2329 dialog_doc_metadata_init_widgets (state
);
2331 state
->view
= GTK_TREE_VIEW(go_gtk_builder_get_widget (state
->gui
, "itemlist"));
2332 state
->store
= gtk_tree_store_new (NUM_COLUMNS
,
2336 gtk_tree_view_set_model (state
->view
, GTK_TREE_MODEL(state
->store
));
2337 g_object_unref (state
->store
);
2338 selection
= gtk_tree_view_get_selection (state
->view
);
2339 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_BROWSE
);
2340 column
= gtk_tree_view_column_new_with_attributes ("",
2341 gtk_cell_renderer_pixbuf_new (),
2342 "pixbuf", ITEM_ICON
,
2344 gtk_tree_view_append_column (state
->view
, column
);
2345 column
= gtk_tree_view_column_new_with_attributes ("",
2346 gtk_cell_renderer_text_new (),
2349 gtk_tree_view_append_column (state
->view
, column
);
2350 gtk_tree_view_set_expander_column (state
->view
, column
);
2352 g_signal_connect (selection
,
2354 G_CALLBACK (cb_dialog_doc_metadata_selection_changed
), state
);
2357 /* Register g_value_transform functions */
2358 g_value_register_transform_func (G_TYPE_STRING
,
2360 dialog_doc_metadata_transform_str_to_timestamp
);
2362 g_value_register_transform_func (G_TYPE_STRING
,
2364 dialog_doc_metadata_transform_str_to_float
);
2366 g_value_register_transform_func (G_TYPE_STRING
,
2367 GSF_DOCPROP_VECTOR_TYPE
,
2368 dialog_doc_metadata_transform_str_to_docprop_vect
);
2370 g_value_register_transform_func (G_TYPE_STRING
,
2372 dialog_doc_metadata_transform_str_to_boolean
);
2374 g_value_register_transform_func (GSF_TIMESTAMP_TYPE
,
2376 dialog_doc_metadata_transform_timestamp_to_str
);
2378 g_value_register_transform_func (GSF_DOCPROP_VECTOR_TYPE
,
2380 dialog_doc_metadata_transform_docprop_vect_to_str
);
2382 g_value_register_transform_func (G_TYPE_FLOAT
,
2384 dialog_doc_metadata_transform_float_to_str
);
2386 g_value_register_transform_func (G_TYPE_BOOLEAN
,
2388 dialog_doc_metadata_transform_boolean_to_str
);
2390 for (i
= 0; page_info
[i
].page
> -1; i
++) {
2391 const page_info_t
*this_page
= &page_info
[i
];
2392 this_page
->page_initializer (state
);
2393 dialog_doc_meta_data_add_item (state
, this_page
->page_name
, this_page
->icon_name
,
2394 this_page
->page
, this_page
->parent_path
);
2397 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (state
->store
), ITEM_NAME
, GTK_SORT_ASCENDING
);
2399 /* A candidate for merging into attach guru */
2400 gnm_keyed_dialog (state
->wbcg
,
2401 GTK_WINDOW (state
->dialog
),
2405 go_gtk_nonmodal_dialog (wbcg_toplevel (state
->wbcg
),
2406 GTK_WINDOW (state
->dialog
));
2408 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
2409 g_object_set_data_full (G_OBJECT (state
->dialog
), "state",
2410 state
, (GDestroyNotify
) dialog_doc_metadata_free
);
2412 /* Help and Close buttons */
2413 gnm_init_help_button (GTK_WIDGET (state
->help_button
),
2414 GNUMERIC_HELP_LINK_METADATA
);
2416 g_signal_connect_swapped (G_OBJECT (state
->close_button
),
2418 G_CALLBACK (gtk_widget_destroy
),
2421 gtk_widget_show_all (GTK_WIDGET (state
->dialog
));
2426 /******************************************************************************
2427 * EXPORTED FUNCTIONS
2428 ******************************************************************************/
2431 * dialog_doc_metadata_new
2435 * Creates a new instance of the dialog.
2439 dialog_doc_metadata_new (WBCGtk
*wbcg
, int page
)
2441 DialogDocMetaData
*state
;
2443 g_return_if_fail (wbcg
!= NULL
);
2445 /* Only one guru per workbook. */
2446 if (wbc_gtk_get_guru (wbcg
))
2449 /* Only pop up one copy per workbook */
2450 if (gnm_dialog_raise_if_exists (wbcg
, DOC_METADATA_KEY
))
2453 state
= g_new0 (DialogDocMetaData
, 1);
2455 if (dialog_doc_metadata_init (state
, wbcg
)) {
2456 go_gtk_notice_dialog (wbcg_toplevel (wbcg
),
2458 _("Could not create the Properties dialog."));
2464 dialog_doc_metadata_select_page (state
, page
);