1 /*
2  * gnm-sheet-sel.c: A selector for sheets.
3  *
4  * Copyright (c) 2018 Morten Welinder
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  **/
19 
20 #include <gnumeric-config.h>
21 #include <widgets/gnm-sheet-sel.h>
22 #include <gnm-i18n.h>
23 #include <sheet.h>
24 #include <workbook.h>
25 #include <application.h>
26 
27 #define SHEET_KEY "__sheet"
28 
29 struct GnmSheetSel_ {
30 	GOOptionMenu parent;
31 
32 	Sheet *sheet;
33 };
34 
35 typedef struct {
36 	GOOptionMenuClass parent_klass;
37 } GnmSheetSelClass;
38 
39 enum {
40 	PROP_0,
41 	PROP_SHEET
42 };
43 
44 static GOOptionMenuClass *gnm_sheet_sel_parent_class;
45 
46 /**
47  * gnm_sheet_sel_set_sheet:
48  * @ss: #GnmSheetSel
49  * @sheet: (transfer none): #Sheet
50  */
51 void
gnm_sheet_sel_set_sheet(GnmSheetSel * ss,Sheet * sheet)52 gnm_sheet_sel_set_sheet (GnmSheetSel *ss, Sheet *sheet)
53 {
54 	GtkWidget *menu;
55 
56 	g_return_if_fail (GNM_IS_SHEET_SEL (ss));
57 
58 	if (sheet == ss->sheet)
59 		return;
60 
61 	menu = go_option_menu_get_menu (&ss->parent);
62 	if (menu) {
63 		GList *children =
64 			gtk_container_get_children (GTK_CONTAINER (menu));
65 		GList *l;
66 
67 		for (l = children; l; l = l->next) {
68 			GtkMenuItem *item = l->data;
69 			Sheet *this_sheet =
70 				g_object_get_data (G_OBJECT (item), SHEET_KEY);
71 			if (this_sheet == sheet) {
72 				go_option_menu_select_item (&ss->parent, item);
73 				break;
74 			}
75 		}
76 		g_list_free (children);
77 	}
78 
79 	ss->sheet = sheet;
80 
81 	g_object_notify (G_OBJECT (ss), "sheet");
82 }
83 
84 /**
85  * gnm_sheet_sel_get_sheet:
86  * @ss: #GnmSheetSel
87  *
88  * Returns: (transfer none): Selected #Sheet
89  */
90 Sheet *
gnm_sheet_sel_get_sheet(GnmSheetSel * ss)91 gnm_sheet_sel_get_sheet (GnmSheetSel *ss)
92 {
93 	g_return_val_if_fail (GNM_IS_SHEET_SEL (ss), NULL);
94 	return ss->sheet;
95 }
96 
97 static void
cb_changed(GOOptionMenu * om,GnmSheetSel * ss)98 cb_changed (GOOptionMenu *om, GnmSheetSel *ss)
99 {
100 	GtkWidget *item = go_option_menu_get_history (om);
101 	Sheet *sheet = g_object_get_data (G_OBJECT (item), SHEET_KEY);
102 	gnm_sheet_sel_set_sheet (ss, sheet);
103 }
104 
105 static void
gnm_sheet_sel_init(GnmSheetSel * ss)106 gnm_sheet_sel_init (GnmSheetSel *ss)
107 {
108 	g_signal_connect (G_OBJECT (&ss->parent), "changed",
109                           G_CALLBACK (cb_changed), ss);
110 }
111 
112 static void
gnm_sheet_sel_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)113 gnm_sheet_sel_set_property (GObject *object, guint property_id,
114 			    const GValue *value, GParamSpec *pspec)
115 {
116 	GnmSheetSel *ss = (GnmSheetSel *)object;
117 
118 	switch (property_id) {
119 	case PROP_SHEET:
120 		gnm_sheet_sel_set_sheet (ss, g_value_get_object (value));
121 		break;
122 	default:
123 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124 		break;
125 	}
126 }
127 
128 static void
gnm_sheet_sel_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)129 gnm_sheet_sel_get_property (GObject *object, guint property_id,
130 			    GValue *value, GParamSpec *pspec)
131 {
132 	GnmSheetSel *ss = (GnmSheetSel *)object;
133 
134 	switch (property_id) {
135 	case PROP_SHEET:
136 		g_value_set_object (value, ss->sheet);
137 		break;
138 	default:
139 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
140 		break;
141 	}
142 }
143 
144 static void
gnm_sheet_sel_class_init(GObjectClass * klass)145 gnm_sheet_sel_class_init (GObjectClass *klass)
146 {
147 	gnm_sheet_sel_parent_class = g_type_class_peek (GO_TYPE_OPTION_MENU);
148 
149 	klass->set_property	= gnm_sheet_sel_set_property;
150 	klass->get_property	= gnm_sheet_sel_get_property;
151 
152 	g_object_class_install_property
153 		(klass, PROP_SHEET,
154 		 g_param_spec_object ("sheet",
155 				      P_("Sheet"),
156 				      P_("The current sheet"),
157 				      GNM_SHEET_TYPE,
158 				      GSF_PARAM_STATIC | G_PARAM_READWRITE));
159 }
160 
161 
GSF_CLASS(GnmSheetSel,gnm_sheet_sel,gnm_sheet_sel_class_init,gnm_sheet_sel_init,GO_TYPE_OPTION_MENU)162 GSF_CLASS (GnmSheetSel, gnm_sheet_sel,
163 	   gnm_sheet_sel_class_init, gnm_sheet_sel_init,
164 	   GO_TYPE_OPTION_MENU)
165 
166 GtkWidget *
167 gnm_sheet_sel_new (void)
168 {
169 	return g_object_new (GNM_TYPE_SHEET_SEL, NULL);
170 }
171 
172 /**
173  * gnm_sheet_sel_set_sheets:
174  * @ss: #GnmSheetSel
175  * @sheets: (element-type Sheet) (transfer none): sheets
176  */
177 void
gnm_sheet_sel_set_sheets(GnmSheetSel * ss,GPtrArray * sheets)178 gnm_sheet_sel_set_sheets (GnmSheetSel *ss, GPtrArray *sheets)
179 {
180 	GtkMenu *menu;
181 	unsigned ui;
182 
183 	g_return_if_fail (GNM_IS_SHEET_SEL (ss));
184 
185         menu = GTK_MENU (gtk_menu_new ());
186 
187 	for (ui = 0; ui < sheets->len; ui++) {
188 		Sheet *sheet = g_ptr_array_index (sheets, ui);
189 		GtkWidget *item =
190 			gtk_check_menu_item_new_with_label
191 			(sheet->name_unquoted);
192 		gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), TRUE);
193 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE);
194 		g_object_set_data (G_OBJECT (item), SHEET_KEY, sheet);
195 		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
196 	}
197 
198 	gtk_widget_show_all (GTK_WIDGET (menu));
199 	go_option_menu_set_menu (&ss->parent, GTK_WIDGET (menu));
200 
201 	if (sheets->len > 0)
202 		gnm_sheet_sel_set_sheet (ss, g_ptr_array_index (sheets, 0));
203 }
204 
205 static void
cb_wb_changed(GnmWorkbookSel * wbs,G_GNUC_UNUSED GParamSpec * pspec,GnmSheetSel * ss)206 cb_wb_changed (GnmWorkbookSel *wbs,
207 	       G_GNUC_UNUSED GParamSpec *pspec,
208 	       GnmSheetSel *ss)
209 {
210 	Workbook *wb = gnm_workbook_sel_get_workbook (wbs);
211 	GPtrArray *sheets = wb ? workbook_sheets (wb) : NULL;
212 	// FIXME: sort?
213 	gnm_sheet_sel_set_sheets (ss, sheets);
214 	g_ptr_array_unref (sheets);
215 }
216 
217 void
gnm_sheet_sel_link(GnmSheetSel * ss,GnmWorkbookSel * wbs)218 gnm_sheet_sel_link (GnmSheetSel *ss, GnmWorkbookSel *wbs)
219 {
220 	g_return_if_fail (GNM_IS_SHEET_SEL (ss));
221 	g_return_if_fail (GNM_IS_WORKBOOK_SEL (wbs));
222 
223 	g_signal_connect_object
224 		(wbs,
225 		 "notify::workbook", G_CALLBACK (cb_wb_changed),
226 		 ss, 0);
227 	cb_wb_changed (wbs, NULL, ss);
228 }
229