1 /*
2  * gal-view-etable.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "gal-view-etable.h"
19 
20 #define GAL_VIEW_ETABLE_GET_PRIVATE(obj) \
21 	(G_TYPE_INSTANCE_GET_PRIVATE \
22 	((obj), GAL_TYPE_VIEW_ETABLE, GalViewEtablePrivate))
23 
24 struct _GalViewEtablePrivate {
25 	gchar *state_filename;
26 
27 	ETable *table;
28 	guint table_state_changed_id;
29 
30 	ETree *tree;
31 	guint tree_state_changed_id;
32 };
33 
G_DEFINE_TYPE(GalViewEtable,gal_view_etable,GAL_TYPE_VIEW)34 G_DEFINE_TYPE (GalViewEtable, gal_view_etable, GAL_TYPE_VIEW)
35 
36 static void
37 detach_table (GalViewEtable *view)
38 {
39 	if (view->priv->table_state_changed_id > 0) {
40 		g_signal_handler_disconnect (
41 			view->priv->table,
42 			view->priv->table_state_changed_id);
43 		view->priv->table_state_changed_id = 0;
44 	}
45 
46 	g_clear_object (&view->priv->table);
47 }
48 
49 static void
detach_tree(GalViewEtable * view)50 detach_tree (GalViewEtable *view)
51 {
52 	if (view->priv->tree_state_changed_id > 0) {
53 		g_signal_handler_disconnect (
54 			view->priv->tree,
55 			view->priv->tree_state_changed_id);
56 		view->priv->tree_state_changed_id = 0;
57 	}
58 
59 	g_clear_object (&view->priv->tree);
60 }
61 
62 static void
gal_view_etable_load(GalView * view,const gchar * filename)63 gal_view_etable_load (GalView *view,
64                       const gchar *filename)
65 {
66 	GalViewEtable *view_etable;
67 
68 	view_etable = GAL_VIEW_ETABLE (view);
69 
70 	/* Just note the filename.  We'll do the actual load
71 	 * when an ETable or ETree gets attached since we need
72 	 * its ETableSpecification to create an ETableState. */
73 	g_free (view_etable->priv->state_filename);
74 	view_etable->priv->state_filename = g_strdup (filename);
75 }
76 
77 static void
gal_view_etable_save(GalView * view,const gchar * filename)78 gal_view_etable_save (GalView *view,
79                       const gchar *filename)
80 {
81 	GalViewEtable *view_etable;
82 
83 	view_etable = GAL_VIEW_ETABLE (view);
84 
85 	if (view_etable->priv->table != NULL) {
86 		ETableState *state;
87 
88 		state = e_table_get_state_object (view_etable->priv->table);
89 		e_table_state_save_to_file (state, filename);
90 		g_object_unref (state);
91 	}
92 
93 	if (view_etable->priv->tree != NULL) {
94 		ETableState *state;
95 
96 		state = e_tree_get_state_object (view_etable->priv->tree);
97 		e_table_state_save_to_file (state, filename);
98 		g_object_unref (state);
99 	}
100 
101 	/* Remember the filename, it may eventually change */
102 	gal_view_etable_load (view, filename);
103 }
104 
105 static GalView *
gal_view_etable_clone(GalView * view)106 gal_view_etable_clone (GalView *view)
107 {
108 	GalViewEtable *gve;
109 	GalView *clone;
110 
111 	/* Chain up to parent's clone() method. */
112 	clone = GAL_VIEW_CLASS (gal_view_etable_parent_class)->clone (view);
113 
114 	gve = GAL_VIEW_ETABLE (view);
115 
116 	/* do this before setting state_filename, to not overwrite current
117 	 * state changes in the 'attach' function */
118 	if (gve->priv->table)
119 		gal_view_etable_attach_table (GAL_VIEW_ETABLE (clone), gve->priv->table);
120 	else if (gve->priv->tree)
121 		gal_view_etable_attach_tree (GAL_VIEW_ETABLE (clone), gve->priv->tree);
122 
123 	GAL_VIEW_ETABLE (clone)->priv->state_filename =
124 		g_strdup (gve->priv->state_filename);
125 
126 	return clone;
127 }
128 
129 static void
gal_view_etable_dispose(GObject * object)130 gal_view_etable_dispose (GObject *object)
131 {
132 	GalViewEtable *view = GAL_VIEW_ETABLE (object);
133 
134 	gal_view_etable_detach (view);
135 
136 	/* Chain up to parent's dispose() method. */
137 	G_OBJECT_CLASS (gal_view_etable_parent_class)->dispose (object);
138 }
139 
140 static void
gal_view_etable_finalize(GObject * object)141 gal_view_etable_finalize (GObject *object)
142 {
143 	GalViewEtable *view = GAL_VIEW_ETABLE (object);
144 
145 	g_free (view->priv->state_filename);
146 
147 	/* Chain up to parent's finalize() method. */
148 	G_OBJECT_CLASS (gal_view_etable_parent_class)->finalize (object);
149 }
150 
151 static void
gal_view_etable_class_init(GalViewEtableClass * class)152 gal_view_etable_class_init (GalViewEtableClass *class)
153 {
154 	GObjectClass *object_class;
155 	GalViewClass *gal_view_class;
156 
157 	g_type_class_add_private (class, sizeof (GalViewEtablePrivate));
158 
159 	object_class = G_OBJECT_CLASS (class);
160 	object_class->dispose = gal_view_etable_dispose;
161 	object_class->finalize = gal_view_etable_finalize;
162 
163 	gal_view_class = GAL_VIEW_CLASS (class);
164 	gal_view_class->type_code = "etable";
165 	gal_view_class->load = gal_view_etable_load;
166 	gal_view_class->save = gal_view_etable_save;
167 	gal_view_class->clone = gal_view_etable_clone;
168 }
169 
170 static void
gal_view_etable_init(GalViewEtable * view)171 gal_view_etable_init (GalViewEtable *view)
172 {
173 	view->priv = GAL_VIEW_ETABLE_GET_PRIVATE (view);
174 }
175 
176 /**
177  * gal_view_etable_new
178  * @title: The name of the new view.
179  *
180  * Returns a new GalViewEtable.  This is primarily for use by
181  * GalViewFactoryEtable.
182  *
183  * Returns: The new GalViewEtable.
184  */
185 GalView *
gal_view_etable_new(const gchar * title)186 gal_view_etable_new (const gchar *title)
187 {
188 	return g_object_new (GAL_TYPE_VIEW_ETABLE, "title", title, NULL);
189 }
190 
191 static void
table_state_changed(ETable * table,GalView * view)192 table_state_changed (ETable *table,
193                      GalView *view)
194 {
195 	gal_view_changed (view);
196 }
197 
198 static void
tree_state_changed(ETree * tree,GalView * view)199 tree_state_changed (ETree *tree,
200                     GalView *view)
201 {
202 	gal_view_changed (view);
203 }
204 
205 void
gal_view_etable_attach_table(GalViewEtable * view,ETable * table)206 gal_view_etable_attach_table (GalViewEtable *view,
207                               ETable *table)
208 {
209 	g_return_if_fail (GAL_IS_VIEW_ETABLE (view));
210 	g_return_if_fail (E_IS_TABLE (table));
211 
212 	gal_view_etable_detach (view);
213 
214 	/* Load the state file now. */
215 	if (view->priv->state_filename != NULL) {
216 		ETableSpecification *specification;
217 		ETableState *state;
218 
219 		specification = table->spec;
220 		state = e_table_state_new (specification);
221 		e_table_state_load_from_file (
222 			state, view->priv->state_filename);
223 
224 		e_table_set_state_object (table, state);
225 
226 		g_object_unref (state);
227 	}
228 
229 	view->priv->table = g_object_ref (table);
230 
231 	view->priv->table_state_changed_id = g_signal_connect (
232 		view->priv->table, "state_change",
233 		G_CALLBACK (table_state_changed), view);
234 }
235 
236 void
gal_view_etable_attach_tree(GalViewEtable * view,ETree * tree)237 gal_view_etable_attach_tree (GalViewEtable *view,
238                              ETree *tree)
239 {
240 	g_return_if_fail (GAL_IS_VIEW_ETABLE (view));
241 	g_return_if_fail (E_IS_TREE (tree));
242 
243 	gal_view_etable_detach (view);
244 
245 	/* Load the state file now. */
246 	if (view->priv->state_filename != NULL) {
247 		ETableSpecification *specification;
248 		ETableState *state;
249 
250 		specification = e_tree_get_spec (tree);
251 		state = e_table_state_new (specification);
252 		e_table_state_load_from_file (
253 			state, view->priv->state_filename);
254 
255 		e_tree_set_state_object (tree, state);
256 
257 		g_object_unref (state);
258 	}
259 
260 	view->priv->tree = g_object_ref (tree);
261 
262 	view->priv->tree_state_changed_id = g_signal_connect (
263 		view->priv->tree, "state_change",
264 		G_CALLBACK (tree_state_changed), view);
265 }
266 
267 void
gal_view_etable_detach(GalViewEtable * view)268 gal_view_etable_detach (GalViewEtable *view)
269 {
270 	g_return_if_fail (GAL_IS_VIEW_ETABLE (view));
271 
272 	if (view->priv->table != NULL)
273 		detach_table (view);
274 	if (view->priv->tree != NULL)
275 		detach_tree (view);
276 }
277 
278 ETable *
gal_view_etable_get_table(GalViewEtable * view)279 gal_view_etable_get_table (GalViewEtable *view)
280 {
281 	g_return_val_if_fail (GAL_IS_VIEW_ETABLE (view), NULL);
282 
283 	return view->priv->table;
284 }
285 
286 ETree *
gal_view_etable_get_tree(GalViewEtable * view)287 gal_view_etable_get_tree (GalViewEtable *view)
288 {
289 	g_return_val_if_fail (GAL_IS_VIEW_ETABLE (view), NULL);
290 
291 	return view->priv->tree;
292 }
293