1 /*
2  * This file is part of GNOME LaTeX.
3  *
4  * Copyright (C) 2015 - Sébastien Wilmet <swilmet@gnome.org>
5  *
6  * GNOME LaTeX 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GNOME LaTeX 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 GNOME LaTeX.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "latexila-templates-dialogs.h"
21 #include <glib/gi18n.h>
22 #include "latexila-templates-common.h"
23 #include "latexila-templates-default.h"
24 #include "latexila-templates-personal.h"
25 #include "latexila-utils.h"
26 
27 static void
init_open_dialog(GtkDialog * dialog,GtkTreeView * default_view,GtkTreeView * personal_view)28 init_open_dialog (GtkDialog   *dialog,
29 		  GtkTreeView *default_view,
30 		  GtkTreeView *personal_view)
31 {
32 	GtkContainer *hgrid;
33 	GtkWidget *scrolled_window;
34 	GtkWidget *component;
35 	GtkWidget *content_area;
36 
37 	hgrid = GTK_CONTAINER (gtk_grid_new ());
38 	gtk_orientable_set_orientation (GTK_ORIENTABLE (hgrid), GTK_ORIENTATION_HORIZONTAL);
39 	gtk_grid_set_column_spacing (GTK_GRID (hgrid), 10);
40 
41 	/* Default templates */
42 
43 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
44 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
45 	gtk_widget_set_size_request (scrolled_window, 250, 200);
46 
47 	gtk_container_add (GTK_CONTAINER (scrolled_window),
48 			   GTK_WIDGET (default_view));
49 
50 	component = latexila_utils_get_dialog_component (_ ("Default Templates"), scrolled_window);
51 	gtk_container_add (hgrid, component);
52 
53 	/* Personal templates */
54 
55 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
56 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
57 	gtk_widget_set_size_request (scrolled_window, 250, 200);
58 
59 	gtk_container_add (GTK_CONTAINER (scrolled_window),
60 			   GTK_WIDGET (personal_view));
61 
62 	component = latexila_utils_get_dialog_component (_ ("Personal Templates"), scrolled_window);
63 	gtk_container_add (hgrid, component);
64 
65 	content_area = gtk_dialog_get_content_area (dialog);
66 	gtk_box_pack_start (GTK_BOX (content_area), GTK_WIDGET (hgrid), TRUE, TRUE, 0);
67 	gtk_widget_show_all (content_area);
68 }
69 
70 static void
selection_changed_cb(GtkTreeSelection * selection,GtkTreeSelection * other_selection)71 selection_changed_cb (GtkTreeSelection *selection,
72 		      GtkTreeSelection *other_selection)
73 {
74 	/* Only one item of the two lists can be selected at once. */
75 
76 	/* We unselect all the items of the other list only if the current list have
77 	 * an item selected, because when we unselect all the items the "changed"
78 	 * signal is emitted for the other list, so for the other list this function
79 	 * is also called but no item is selected so nothing is done and the item
80 	 * selected by the user is kept selected.
81 	 */
82 
83 	if (gtk_tree_selection_count_selected_rows (selection) > 0)
84 	{
85 		gtk_tree_selection_unselect_all (other_selection);
86 	}
87 }
88 
89 static void
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,GtkDialog * dialog)90 row_activated_cb (GtkTreeView       *tree_view,
91 		  GtkTreePath       *path,
92 		  GtkTreeViewColumn *column,
93 		  GtkDialog         *dialog)
94 {
95 	gtk_dialog_response (dialog, GTK_RESPONSE_OK);
96 }
97 
98 /**
99  * latexila_templates_dialogs_open:
100  * @parent_window: transient parent window of the dialog.
101  *
102  * Runs a #GtkDialog to create a new document from a template. Only the
103  * template's contents is returned.
104  *
105  * Returns: the template contents, or %NULL if no templates must be opened.
106  */
107 gchar *
latexila_templates_dialogs_open(GtkWindow * parent_window)108 latexila_templates_dialogs_open (GtkWindow *parent_window)
109 {
110 	GtkDialog *dialog;
111 	LatexilaTemplatesDefault *default_store;
112 	LatexilaTemplatesPersonal *personal_store;
113 	GtkTreeView *default_view;
114 	GtkTreeView *personal_view;
115 	GtkTreeSelection *default_selection;
116 	GtkTreeSelection *personal_selection;
117 	gint response;
118 	gchar *contents = NULL;
119 
120 	g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL);
121 
122 	dialog = g_object_new (GTK_TYPE_DIALOG,
123 			       "use-header-bar", TRUE,
124 			       "title", _ ("New File…"),
125 			       "destroy-with-parent", TRUE,
126 			       "transient-for", parent_window,
127 			       NULL);
128 
129 	gtk_dialog_add_buttons (dialog,
130 				_ ("_Cancel"), GTK_RESPONSE_CANCEL,
131 				_ ("_New"), GTK_RESPONSE_OK,
132 				NULL);
133 
134 	gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
135 
136 	default_store = latexila_templates_default_get_instance ();
137 	personal_store = latexila_templates_personal_get_instance ();
138 
139 	default_view = latexila_templates_get_view (GTK_LIST_STORE (default_store));
140 	personal_view = latexila_templates_get_view (GTK_LIST_STORE (personal_store));
141 
142 	init_open_dialog (dialog, default_view, personal_view);
143 
144 	/* Selection: at most one selected template in both GtkTreeViews. */
145 	default_selection = gtk_tree_view_get_selection (default_view);
146 	personal_selection = gtk_tree_view_get_selection (personal_view);
147 
148 	g_signal_connect_object (default_selection,
149 				 "changed",
150 				 G_CALLBACK (selection_changed_cb),
151 				 personal_selection,
152 				 0);
153 
154 	g_signal_connect_object (personal_selection,
155 				 "changed",
156 				 G_CALLBACK (selection_changed_cb),
157 				 default_selection,
158 				 0);
159 
160 	/* Double-click */
161 	g_signal_connect (default_view,
162 			  "row-activated",
163 			  G_CALLBACK (row_activated_cb),
164 			  dialog);
165 
166 	g_signal_connect (personal_view,
167 			  "row-activated",
168 			  G_CALLBACK (row_activated_cb),
169 			  dialog);
170 
171 	response = gtk_dialog_run (dialog);
172 
173 	if (response == GTK_RESPONSE_OK)
174 	{
175 		GList *selected_rows = NULL;
176 		GtkTreePath *path;
177 
178 		if (gtk_tree_selection_count_selected_rows (default_selection) > 0)
179 		{
180 			selected_rows = gtk_tree_selection_get_selected_rows (default_selection, NULL);
181 			g_assert (g_list_length (selected_rows) == 1);
182 
183 			path = selected_rows->data;
184 			contents = latexila_templates_default_get_contents (default_store, path);
185 		}
186 		else if (gtk_tree_selection_count_selected_rows (personal_selection) > 0)
187 		{
188 			selected_rows = gtk_tree_selection_get_selected_rows (personal_selection, NULL);
189 			g_assert (g_list_length (selected_rows) == 1);
190 
191 			path = selected_rows->data;
192 			contents = latexila_templates_personal_get_contents (personal_store, path);
193 		}
194 		/* No templates selected. */
195 		else
196 		{
197 			contents = g_strdup ("");
198 		}
199 
200 		g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
201 	}
202 
203 	gtk_widget_destroy (GTK_WIDGET (dialog));
204 	return contents;
205 }
206 
207 /**
208  * latexila_templates_dialogs_create_template:
209  * @parent_window: transient parent window of the dialog.
210  * @template_contents: the template's contents.
211  *
212  * Runs a #GtkDialog to create a new template. The template's contents is given.
213  * The #GtkDialog asks the template's name and icon.
214  */
215 void
latexila_templates_dialogs_create_template(GtkWindow * parent_window,const gchar * template_contents)216 latexila_templates_dialogs_create_template (GtkWindow   *parent_window,
217 					    const gchar *template_contents)
218 {
219 	GtkDialog *dialog;
220 	GtkBox *content_area;
221 	GtkEntry *entry;
222 	GtkWidget *component;
223 	LatexilaTemplatesDefault *default_store;
224 	GtkTreeView *default_view;
225 	GtkWidget *scrolled_window;
226 
227 	g_return_if_fail (GTK_IS_WINDOW (parent_window));
228 	g_return_if_fail (template_contents != NULL);
229 
230 	dialog = g_object_new (GTK_TYPE_DIALOG,
231 			       "use-header-bar", TRUE,
232 			       "title", _ ("New Template…"),
233 			       "destroy-with-parent", TRUE,
234 			       "transient-for", parent_window,
235 			       NULL);
236 
237 	gtk_dialog_add_buttons (dialog,
238 				_ ("_Cancel"), GTK_RESPONSE_CANCEL,
239 				_ ("Crea_te"), GTK_RESPONSE_OK,
240 				NULL);
241 
242 	gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
243 
244 	content_area = GTK_BOX (gtk_dialog_get_content_area (dialog));
245 
246 	/* Name */
247 	entry = GTK_ENTRY (gtk_entry_new ());
248 	gtk_widget_set_hexpand (GTK_WIDGET (entry), TRUE);
249 	component = latexila_utils_get_dialog_component (_ ("Name of the new template"),
250 							 GTK_WIDGET (entry));
251 	gtk_box_pack_start (content_area, component, FALSE, TRUE, 0);
252 
253 	/* Icon.
254 	 * Take the default store because it contains all the icons.
255 	 */
256 	default_store = latexila_templates_default_get_instance ();
257 	default_view = latexila_templates_get_view (GTK_LIST_STORE (default_store));
258 
259 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
260 	gtk_widget_set_size_request (scrolled_window, 400, 200);
261 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
262 					     GTK_SHADOW_IN);
263 
264 	gtk_container_add (GTK_CONTAINER (scrolled_window),
265 			   GTK_WIDGET (default_view));
266 
267 	component = latexila_utils_get_dialog_component (_ ("Choose an icon"), scrolled_window);
268 	gtk_box_pack_start (content_area, component, TRUE, TRUE, 0);
269 
270 	gtk_widget_show_all (GTK_WIDGET (content_area));
271 
272 	while (gtk_dialog_run (dialog) == GTK_RESPONSE_OK)
273 	{
274 		GtkTreeSelection *selection;
275 		GList *selected_rows;
276 		GtkTreePath *path;
277 		GtkTreeIter iter;
278 		gchar *config_icon_name = NULL;
279 		const gchar *name = NULL;
280 		LatexilaTemplatesPersonal *personal_store;
281 		GError *error = NULL;
282 
283 		/* If no name specified. */
284 		if (gtk_entry_get_text_length (entry) == 0)
285 		{
286 			continue;
287 		}
288 
289 		selection = gtk_tree_view_get_selection (default_view);
290 
291 		/* If no icons selected. */
292 		if (gtk_tree_selection_count_selected_rows (selection) == 0)
293 		{
294 			continue;
295 		}
296 
297 		/* Get config icon name. */
298 		selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
299 		g_assert (g_list_length (selected_rows) == 1);
300 
301 		path = selected_rows->data;
302 
303 		if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (default_store), &iter, path))
304 		{
305 			g_warning ("Create template dialog: invalid path");
306 			break;
307 		}
308 
309 		gtk_tree_model_get (GTK_TREE_MODEL (default_store), &iter,
310 				    LATEXILA_TEMPLATES_COLUMN_CONFIG_ICON_NAME, &config_icon_name,
311 				    -1);
312 
313 		name = gtk_entry_get_text (entry);
314 
315 		personal_store = latexila_templates_personal_get_instance ();
316 
317 		latexila_templates_personal_create (personal_store,
318 						    name,
319 						    config_icon_name,
320 						    template_contents,
321 						    &error);
322 
323 		g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
324 		g_free (config_icon_name);
325 
326 		if (error != NULL)
327 		{
328 			GtkWidget *error_dialog;
329 
330 			error_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
331 							       GTK_DIALOG_MODAL |
332 							       GTK_DIALOG_DESTROY_WITH_PARENT |
333 							       GTK_DIALOG_USE_HEADER_BAR,
334 							       GTK_MESSAGE_ERROR,
335 							       GTK_BUTTONS_OK,
336 							       "%s", _ ("Impossible to create the personal template."));
337 
338 			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog),
339 								  "%s", error->message);
340 
341 			gtk_dialog_run (GTK_DIALOG (error_dialog));
342 			gtk_widget_destroy (error_dialog);
343 
344 			g_error_free (error);
345 			continue;
346 		}
347 
348 		break;
349 	}
350 
351 	gtk_widget_destroy (GTK_WIDGET (dialog));
352 }
353