1 /**
2 * @file gui-main.c
3 * @brief
4 *
5 * Copyright (C) 2009 Gummi Developers
6 * All Rights reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following
15 * conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30 #include "gui-main.h"
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36
37 #ifndef WIN32
38 # include <unistd.h>
39 #endif
40
41 #include <glib.h>
42 #include <gdk-pixbuf/gdk-pixbuf.h>
43
44 #include "biblio.h"
45 #include "configfile.h"
46 #include "constants.h"
47 #include "editor.h"
48 #include "environment.h"
49 #include "importer.h"
50 #include "utils.h"
51 #include "template.h"
52
53 #include "compile/rubber.h"
54 #include "compile/latexmk.h"
55 #include "compile/texlive.h"
56
57
58 extern Gummi* gummi;
59 extern GummiGui* gui;
60
61 /* Many of the functions in this file are based on the excellent GTK+
62 * tutorials written by Micah Carrick that can be found on:
63 * http://www.micahcarrick.com/gtk-glade-tutorial-part-3.html */
64
65
66 /* These widgets are (de)sensitised using the gui_set_hastabs_sensitive
67 * function for when we switch from 0 to 1 tabs and vice versa */
68 const gchar* insens_widgets_str[] = {
69 "box_rightpane", "tool_save", "tool_bold", "tool_italic", "tool_unline",
70 "tool_left", "tool_center", "tool_right", "box_importers",
71 "menu_save", "menu_saveas", "menu_close", "menu_export",
72 "menu_undo", "menu_redo", "menu_cut", "menu_copy", "menu_paste",
73 "menu_delete", "menu_selectall", "menu_preferences", "menu_find",
74 "menu_prev", "menu_next", "menu_pdfcompile", "menu_compileopts",
75 "menu_runmakeindex", "menu_runbibtex", "menu_docstat", "menu_spelling",
76 "menu_snippets", "menu_edit", "menu_document", "menu_search",
77 "menu_cleanup", "menu_page_layout"
78 };
79
80
gui_init(GtkBuilder * builder)81 GummiGui* gui_init (GtkBuilder* builder) {
82 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
83
84 GtkWidget* hpaned;
85 gint i = 0, wx = 0, wy = 0, width = 0, height = 0;
86
87 GummiGui* g = g_new0 (GummiGui, 1);
88
89 g->builder = builder;
90
91 g->mainwindow =
92 GTK_WINDOW (gtk_builder_get_object (builder, "mainwindow"));
93 g->toolbar =
94 GTK_WIDGET (gtk_builder_get_object (builder, "maintoolbar"));
95 g->statusbar =
96 GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar"));
97 g->rightpane =
98 GTK_BOX (gtk_builder_get_object (builder, "box_rightpane"));
99 g->errorview =
100 GTK_TEXT_VIEW (gtk_builder_get_object (builder, "errorview"));
101 g->errorbuff =
102 gtk_text_view_get_buffer (GTK_TEXT_VIEW (g->errorview));
103 g->menu_spelling =
104 GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menu_spelling"));
105 g->menu_snippets =
106 GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menu_snippets"));
107 g->menu_toolbar =
108 GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menu_toolbar"));
109 g->menu_statusbar =
110 GTK_CHECK_MENU_ITEM(gtk_builder_get_object (builder, "menu_statusbar"));
111 g->statusid =
112 gtk_statusbar_get_context_id (GTK_STATUSBAR (g->statusbar), "Gummi");
113 g->recent[0] =
114 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_recent1"));
115 g->recent[1] =
116 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_recent2"));
117 g->recent[2] =
118 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_recent3"));
119 g->recent[3] =
120 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_recent4"));
121 g->recent[4] =
122 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_recent5"));
123
124 g->docstatswindow =
125 GTK_WIDGET (gtk_builder_get_object (builder, "docstatswindow"));
126
127 g->menu_runbibtex =
128 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_runbibtex"));
129 g->menu_runmakeindex =
130 GTK_MENU_ITEM (gtk_builder_get_object (builder, "menu_runmakeindex"));
131 g->bibcompile =
132 GTK_WIDGET (gtk_builder_get_object (builder, "bibcompile"));
133
134 g->insens_widget_size = sizeof(insens_widgets_str) / sizeof(gchar*);
135 g->insens_widgets = g_new0(GtkWidget*, g->insens_widget_size);
136
137 for (i = 0; i < g->insens_widget_size; ++i)
138 g->insens_widgets[i] =
139 GTK_WIDGET(gtk_builder_get_object (builder, insens_widgets_str[i]));
140
141 g->menugui = menugui_init (builder);
142 g->importgui = importgui_init (builder);
143 g->previewgui = previewgui_init (builder);
144 g->searchgui = searchgui_init (builder);
145 g->prefsgui = prefsgui_init (g->mainwindow);
146 g->snippetsgui = snippetsgui_init (g->mainwindow);
147 g->tabmanagergui = tabmanagergui_init (builder);
148 g->infoscreengui = infoscreengui_init (builder);
149 g->projectgui = projectgui_init (builder);
150
151 gchar* icon_file = g_build_filename (GUMMI_DATA, "icons", "icon.png", NULL);
152 gtk_window_set_icon_from_file (g->mainwindow, icon_file, NULL);
153 g_free (icon_file);
154
155 // set main window size and positioning:
156 if (config_get_boolean ("Interface", "mainwindow_max")) {
157 gtk_window_maximize (g->mainwindow);
158 }
159 else {
160 gtk_window_resize (g->mainwindow,
161 config_get_integer ("Interface", "mainwindow_w"),
162 config_get_integer ("Interface", "mainwindow_h"));
163
164 wx = config_get_integer ("Interface", "mainwindow_x");
165 wy = config_get_integer ("Interface", "mainwindow_y");
166 if (wx && wy) {
167 gtk_window_move (g->mainwindow, wx, wy);
168 }
169 else {
170 gtk_window_set_position (g->mainwindow, GTK_WIN_POS_CENTER);
171 }
172 }
173
174 // use new css styling for errorview pane:
175 gtk_widget_set_name (GTK_WIDGET (g->errorview), "errorview");
176
177 GtkCssProvider *provider = gtk_css_provider_new ();
178 GError* error = NULL;
179
180 const gchar* css_data =
181 "#errorview {\n"
182 " font: 12px 'Monospace';\n"
183 "}\n";
184
185 gtk_css_provider_load_from_data (provider, css_data, -1, &error);
186 if (error == NULL) {
187 GtkStyleContext *context;
188 context = gtk_widget_get_style_context (GTK_WIDGET (g->errorview));
189
190 gtk_style_context_add_provider (context,
191 GTK_STYLE_PROVIDER (provider),
192 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
193 }
194 else {
195 slog (L_ERROR, "%s\n", error->message);
196 }
197 g_object_unref (provider);
198
199 gtk_window_get_size (g->mainwindow, &width, &height);
200
201 hpaned= GTK_WIDGET (gtk_builder_get_object (builder, "hpaned"));
202 gtk_paned_set_position (GTK_PANED (hpaned), (width/2));
203
204 if (config_get_boolean ("Editor", "spelling"))
205 gtk_check_menu_item_set_active (g->menu_spelling, TRUE);
206
207 if (config_get_boolean ("Interface", "snippets")) {
208 gtk_check_menu_item_set_active (g->menu_snippets, TRUE);
209 gtk_widget_show (GTK_WIDGET (g->menu_snippets));
210 }
211 if (config_get_boolean ("Interface", "toolbar")) {
212 gtk_check_menu_item_set_active (g->menu_toolbar, TRUE);
213 gtk_widget_show (g->toolbar);
214 } else {
215 config_set_boolean ("Interface", "toolbar", FALSE);
216 gtk_check_menu_item_set_active (g->menu_toolbar, FALSE);
217 gtk_widget_hide (g->toolbar);
218 }
219
220 if (config_get_boolean ("Interface", "statusbar")) {
221 gtk_check_menu_item_set_active (g->menu_statusbar, TRUE);
222 gtk_widget_show (GTK_WIDGET (g->statusbar));
223 } else {
224 config_set_boolean ("Interface", "statusbar", FALSE);
225 gtk_check_menu_item_set_active (g->menu_statusbar, FALSE);
226 gtk_widget_hide (GTK_WIDGET (g->statusbar));
227 }
228
229 g->menu_autosync =
230 GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menu_autosync"));
231
232 if (latex_can_synctex() && config_get_boolean ("Compile", "synctex")) {
233 gtk_widget_set_sensitive (GTK_WIDGET (g->menu_autosync), TRUE);
234 gboolean async = latex_use_synctex();
235 gtk_check_menu_item_set_active (g->menu_autosync, (async? TRUE: FALSE));
236 }
237
238 g->recent_list[0] = g_strdup (config_get_string ("Misc", "recent1"));
239 g->recent_list[1] = g_strdup (config_get_string ("Misc", "recent2"));
240 g->recent_list[2] = g_strdup (config_get_string ("Misc", "recent3"));
241 g->recent_list[3] = g_strdup (config_get_string ("Misc", "recent4"));
242 g->recent_list[4] = g_strdup (config_get_string ("Misc", "recent5"));
243
244 display_recent_files (g);
245
246 return g;
247 }
248
gui_main(GtkBuilder * builder)249 void gui_main (GtkBuilder* builder) {
250 gtk_builder_connect_signals (builder, NULL);
251 gtk_widget_show_all (GTK_WIDGET (gui->mainwindow));
252
253 gtk_main ();
254 }
255
256
257
258 G_MODULE_EXPORT
on_menu_autosync_toggled(GtkCheckMenuItem * menu_autosync,void * user)259 void on_menu_autosync_toggled (GtkCheckMenuItem *menu_autosync, void* user) {
260 if (gtk_check_menu_item_get_active(menu_autosync)) {
261 config_set_boolean ("Preview", "autosync", TRUE);
262 } else {
263 config_set_boolean ("Preview", "autosync", FALSE);
264 }
265 }
266
267 G_MODULE_EXPORT
on_tab_notebook_switch_page(GtkNotebook * notebook,GtkWidget * nbpage,int pagenr,void * data)268 void on_tab_notebook_switch_page (GtkNotebook *notebook, GtkWidget *nbpage, int pagenr, void *data) {
269 slog (L_DEBUG, "Switched to environment at page %d\n", pagenr);
270 /* Kill typesetter command */
271 motion_kill_typesetter(gummi->motion);
272
273 /* set the active tab/editor pointers */
274 tabmanager_set_active_tab (pagenr);
275
276 /* update the title of the mainwindow */
277 gui_set_filename_display (g_active_tab, TRUE, FALSE);
278
279 /* clear the build log output window */
280 gui_buildlog_set_text ("");
281
282 previewgui_reset (gui->previewgui);
283 }
284
285 G_MODULE_EXPORT
on_right_notebook_switch_page(GtkNotebook * notebook,GtkWidget * nbpage,int page,void * data)286 void on_right_notebook_switch_page(GtkNotebook *notebook, GtkWidget *nbpage,
287 int page, void *data) {
288 if (page == 2) {
289 if (gummi_project_active ()) {
290 //projectgui_enable (gummi->project, gui->projectgui);
291 }
292 else {
293 //projectgui_disable (gummi->project, gui->projectgui);
294 }
295 }
296 }
297
gui_set_filename_display(GuTabContext * tc,gboolean title,gboolean label)298 void gui_set_filename_display (GuTabContext* tc, gboolean title, gboolean label) {
299 gchar* filetext = tabmanager_get_tabname (tc);
300
301 if (label) tabmanagergui_update_label (tc->page, filetext);
302 if (title) gui_set_window_title (tc->editor->filename, filetext);
303 }
304
gui_set_window_title(const gchar * filename,const gchar * text)305 void gui_set_window_title (const gchar* filename, const gchar* text) {
306 gchar* dirname;
307 gchar* title;
308
309 if (filename != NULL) {
310 dirname = g_strdup_printf("(%s)", g_path_get_dirname (filename));
311 title = g_strdup_printf ("%s %s - %s", text, dirname,
312 C_PACKAGE_NAME);
313 }
314 else {
315 title = g_strdup_printf ("%s - %s", text, C_PACKAGE_NAME);
316 }
317 gtk_window_set_title (gui->mainwindow, title);
318 g_free (title);
319 }
320
on_recovery_infobar_response(GtkInfoBar * bar,gint res,gpointer filename)321 void on_recovery_infobar_response (GtkInfoBar* bar, gint res, gpointer filename) {
322 gchar* prev_workfile = iofunctions_get_swapfile (filename);
323
324 if (res == GTK_RESPONSE_YES) {
325 tabmanager_set_content (A_LOAD_OPT, filename, prev_workfile);
326 }
327 else { // NO
328 tabmanager_set_content (A_LOAD, filename, NULL);
329 }
330 gui_recovery_mode_disable (bar);
331 }
332
gui_recovery_mode_enable(GuTabContext * tab,const gchar * filename)333 void gui_recovery_mode_enable (GuTabContext* tab, const gchar* filename) {
334 gchar* prev_workfile = iofunctions_get_swapfile (filename);
335
336 slog (L_WARNING, "Swap file `%s' found.\n", prev_workfile);
337 gchar* msg = g_strdup_printf (_("Swap file exists for %s, "
338 "do you want to recover from it?"), filename);
339 gtk_label_set_text (GTK_LABEL (tab->page->barlabel), msg);
340 g_free (msg);
341
342 gchar* data = g_strconcat (filename, NULL);
343 tab->page->infosignal =
344 g_signal_connect (g_active_tab->page->infobar, "response",
345 G_CALLBACK (on_recovery_infobar_response), (gpointer)data);
346
347 gtk_widget_set_sensitive (GTK_WIDGET (tab->editor->view), FALSE);
348 gtk_widget_show (tab->page->infobar);
349 }
350
gui_recovery_mode_disable(GtkInfoBar * infobar)351 void gui_recovery_mode_disable (GtkInfoBar *infobar) {
352 gint id = g_active_tab->page->infosignal;
353 g_signal_handler_disconnect (infobar, id);
354
355 gtk_widget_hide (GTK_WIDGET(infobar));
356 gtk_widget_set_sensitive (GTK_WIDGET (g_active_editor->view), TRUE);
357 }
358
gui_open_file(const gchar * filename)359 void gui_open_file (const gchar* filename) {
360 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
361 slog(L_G_ERROR, "Failed to open file '%s': No such file or "
362 "directory\n", filename);
363 return;
364 }
365
366 tabmanager_create_tab (A_LOAD, filename, NULL);
367 if (!gtk_widget_get_sensitive (GTK_WIDGET (gui->rightpane))) {
368 gui_set_hastabs_sensitive (TRUE);
369 }
370 }
371
gui_save_file(GuTabContext * tab,gboolean saveas)372 void gui_save_file (GuTabContext* tab, gboolean saveas) {
373 gboolean new = FALSE;
374 gchar* filename = NULL;
375 gchar* pdfname = NULL;
376 gchar* prev = NULL;
377 gint ret = 0;
378
379 if (saveas || !(filename = tab->editor->filename)) {
380 if ((filename = get_save_filename (TYPE_LATEX))) {
381 new = TRUE;
382 if (!STR_EQU (filename + strlen (filename) -4, ".tex")) {
383 prev = filename;
384 filename = g_strdup_printf ("%s.tex", filename);
385 g_free (prev);
386 }
387 if (utils_path_exists (filename)) {
388 ret = utils_yes_no_dialog (
389 _("The file already exists. Overwrite?"));
390 if (GTK_RESPONSE_YES != ret) goto cleanup;
391 }
392 } else goto cleanup;
393 }
394
395 gchar *text;
396 GtkWidget* focus = NULL;
397
398 // check whether the file has been changed by (some) external program
399 double lastmod;
400 struct stat attr;
401 stat(filename, &attr);
402 lastmod = difftime (tab->editor->last_modtime, attr.st_mtime);
403
404 if (lastmod != 0.0 && tab->editor->last_modtime != 0.0 ) {
405 // ask the user whether he want to save or reload
406 ret = utils_save_reload_dialog (
407 _("The content of the file has been changed externally. "
408 "Saving will remove any external modifications."));
409 if (ret == GTK_RESPONSE_YES) {
410 tabmanager_set_content (A_LOAD, filename, NULL);
411 // resets modtime
412 stat(filename, &attr);
413 tab->editor->last_modtime = attr.st_mtime;
414 goto cleanup;
415 } else if (ret != GTK_RESPONSE_NO) {
416 // cancel means: do nothing
417 goto cleanup;
418 }
419 }
420
421 focus = gtk_window_get_focus (gummi_get_gui ()->mainwindow);
422 text = editor_grab_buffer (tab->editor);
423 gtk_widget_grab_focus (focus);
424
425 iofunctions_save_file (gummi->io, filename, text);
426
427 if (config_get_boolean ("File", "autoexport")) {
428 pdfname = g_strdup (filename);
429 pdfname[strlen (pdfname) -4] = 0;
430 latex_export_pdffile (gummi->latex, tab->editor, pdfname, FALSE);
431 }
432 if (new) tabmanager_update_tab (filename);
433 gui_set_filename_display (tab, TRUE, TRUE);
434 gtk_widget_grab_focus (GTK_WIDGET (tab->editor->view));
435
436 // Resets modtime
437 stat(filename, &attr);
438 tab->editor->last_modtime = attr.st_mtime;
439
440 cleanup:
441 if (new) g_free (filename);
442 g_free (pdfname);
443 }
444
gui_set_hastabs_sensitive(gboolean enable)445 void gui_set_hastabs_sensitive (gboolean enable) {
446 gint i = 0;
447 for (i = 0; i < gui->insens_widget_size; ++i) {
448 gtk_widget_set_sensitive (gui->insens_widgets[i], enable);
449 }
450 }
451
452 G_MODULE_EXPORT
on_menu_bibupdate_activate(GtkWidget * widget,void * user)453 void on_menu_bibupdate_activate (GtkWidget *widget, void * user) {
454 biblio_compile_bibliography (gummi->biblio, g_active_editor);
455 }
456
457 G_MODULE_EXPORT
on_docstats_close_clicked(GtkWidget * widget,void * user)458 gboolean on_docstats_close_clicked (GtkWidget* widget, void* user) {
459 gtk_widget_hide (GTK_WIDGET (gui->docstatswindow));
460 return TRUE;
461 }
462
463 G_MODULE_EXPORT
on_tool_textstyle_bold_activate(GtkWidget * widget,void * user)464 void on_tool_textstyle_bold_activate (GtkWidget* widget, void* user) {
465 editor_set_selection_textstyle (g_active_editor, "tool_bold");
466 }
467
468 G_MODULE_EXPORT
on_tool_textstyle_italic_activate(GtkWidget * widget,void * user)469 void on_tool_textstyle_italic_activate (GtkWidget* widget, void* user) {
470 editor_set_selection_textstyle (g_active_editor, "tool_italic");
471 }
472
473 G_MODULE_EXPORT
on_tool_textstyle_underline_activate(GtkWidget * widget,void * user)474 void on_tool_textstyle_underline_activate (GtkWidget* widget, void* user) {
475 editor_set_selection_textstyle (g_active_editor, "tool_unline");
476 }
477
478 G_MODULE_EXPORT
on_tool_textstyle_left_activate(GtkWidget * widget,void * user)479 void on_tool_textstyle_left_activate (GtkWidget* widget, void* user) {
480 editor_set_selection_textstyle (g_active_editor, "tool_left");
481 }
482
483 G_MODULE_EXPORT
on_tool_textstyle_center_activate(GtkWidget * widget,void * user)484 void on_tool_textstyle_center_activate (GtkWidget* widget, void* user) {
485 editor_set_selection_textstyle (g_active_editor, "tool_center");
486 }
487
488 G_MODULE_EXPORT
on_tool_textstyle_right_activate(GtkWidget * widget,void * user)489 void on_tool_textstyle_right_activate (GtkWidget* widget, void* user) {
490 editor_set_selection_textstyle (g_active_editor, "tool_right");
491 }
492
493 G_MODULE_EXPORT
on_button_template_add_clicked(GtkWidget * widget,void * user)494 void on_button_template_add_clicked (GtkWidget* widget, void* user) {
495 template_add_new_entry (gummi->templ);
496 }
497
498 G_MODULE_EXPORT
on_button_template_remove_clicked(GtkWidget * widget,void * user)499 void on_button_template_remove_clicked (GtkWidget* widget, void* user) {
500 template_remove_entry (gummi->templ);
501 }
502
503 G_MODULE_EXPORT
on_button_template_open_clicked(GtkWidget * widget,void * user)504 void on_button_template_open_clicked (GtkWidget* widget, void* user) {
505 gchar* status = NULL;
506 gchar* templ_name = template_get_selected_path (gummi->templ);
507
508 if (templ_name) {
509 /* add Loading message to status bar */
510 status = g_strdup_printf (_("Loading template ..."));
511 statusbar_set_message (status);
512 g_free (status);
513
514 tabmanager_create_tab (A_LOAD_OPT, NULL, templ_name);
515 gtk_widget_hide (GTK_WIDGET (gummi->templ->templatewindow));
516 }
517 g_free(templ_name);
518
519 if (!gtk_widget_get_sensitive (GTK_WIDGET (gui->rightpane)))
520 gui_set_hastabs_sensitive (TRUE);
521 }
522
523 G_MODULE_EXPORT
on_button_template_close_clicked(GtkWidget * widget,void * user)524 void on_button_template_close_clicked (GtkWidget* widget, void* user) {
525 gtk_widget_set_sensitive (GTK_WIDGET (gummi->templ->template_add), TRUE);
526 gtk_widget_set_sensitive (GTK_WIDGET (gummi->templ->template_remove), TRUE);
527 gtk_widget_set_sensitive (GTK_WIDGET (gummi->templ->template_open), TRUE);
528 gtk_widget_hide (GTK_WIDGET (gummi->templ->templatewindow));
529 }
530
531 G_MODULE_EXPORT
on_template_rowitem_edited(GtkWidget * widget,gchar * path,gchar * filenm,void * user)532 void on_template_rowitem_edited (GtkWidget* widget, gchar *path, gchar* filenm,
533 void* user) {
534 GtkTreeIter iter;
535 GtkTreeModel* model = NULL;
536 GtkTreeSelection* selection = NULL;
537 gchar* text = NULL;
538
539 gchar* filepath = g_build_filename (C_GUMMI_TEMPLATEDIR, filenm, NULL);
540
541 model = gtk_tree_view_get_model (gummi->templ->templateview);
542 selection = gtk_tree_view_get_selection (gummi->templ->templateview);
543
544 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
545 gtk_list_store_set (gummi->templ->list_templates, &iter, 0, filenm, 1,
546 filepath, -1);
547 text = editor_grab_buffer (g_active_editor);
548 template_create_file (gummi->templ, filenm, text);
549 }
550 g_free (text);
551 g_free (filepath);
552 }
553
554 G_MODULE_EXPORT
on_template_cursor_changed(GtkTreeView * tree,gpointer data)555 void on_template_cursor_changed (GtkTreeView *tree, gpointer data) {
556 if (!gtk_tree_view_get_selection (tree) == 0) {
557 gtk_widget_set_sensitive (gummi->templ->template_open, TRUE);
558 }
559 }
560
561
562 G_MODULE_EXPORT
on_bibcolumn_clicked(GtkWidget * widget,void * user)563 void on_bibcolumn_clicked (GtkWidget* widget, void* user) {
564 gint id = gtk_tree_view_column_get_sort_column_id
565 (GTK_TREE_VIEW_COLUMN (widget));
566 gtk_tree_view_column_set_sort_column_id
567 (GTK_TREE_VIEW_COLUMN (widget), id);
568 }
569
570 G_MODULE_EXPORT
on_button_biblio_compile_clicked(GtkWidget * widget,void * user)571 void on_button_biblio_compile_clicked (GtkWidget* widget, void* user) {
572 gummi->biblio->progressval = 0.0;
573
574 gtk_widget_set_sensitive (widget, FALSE);
575 g_timeout_add (10, on_bibprogressbar_update, widget);
576
577 if (biblio_compile_bibliography (gummi->biblio, g_active_editor)) {
578 statusbar_set_message (_("Compiling bibliography file.."));
579 // NOTE gtk3s bar doesn't place text inside the widget anymore :/
580 //gtk_progress_bar_set_text (gummi->biblio->progressbar,
581 // _("Bibliography compiled without errors"));
582 motion_force_compile (gummi->motion);
583 } else {
584 statusbar_set_message
585 (_("Error compiling bibliography file or none detected.."));
586 // NOTE gtk3s bar doesn't place text inside the widget anymore :/
587 //gtk_progress_bar_set_text (gummi->biblio->progressbar,
588 // _("Error compiling bibliography file"));
589 }
590 }
591
592 G_MODULE_EXPORT
on_button_biblio_detect_clicked(GtkWidget * widget,void * user)593 void on_button_biblio_detect_clicked (GtkWidget* widget, void* user) {
594 gchar* text = 0;
595 gchar* str = 0;
596 gchar* basename = 0;
597 GError* err = NULL;
598 gint number = 0;
599
600 gummi->biblio->progressval = 0.0;
601 g_timeout_add (2, on_bibprogressbar_update, widget);
602 gtk_list_store_clear (gummi->biblio->list_biblios);
603
604 if (biblio_detect_bibliography (g_active_editor)) {
605 editor_insert_bib (g_active_editor, g_active_editor->bibfile);
606 if (!g_file_get_contents(g_active_editor->bibfile, &text, NULL, &err)) {
607 slog (L_G_ERROR, "g_file_get_contents (): %s\n", err->message);
608 g_error_free (err);
609 return;
610 }
611
612 gtk_widget_set_sensitive
613 (GTK_WIDGET(gummi->biblio->list_filter), TRUE);
614
615 number = biblio_parse_entries (gummi->biblio, text);
616 basename = g_path_get_basename (g_active_editor->bibfile);
617 gtk_label_set_text (gummi->biblio->filenm_label, basename);
618 str = g_strdup_printf ("%d", number);
619 gtk_label_set_text (gummi->biblio->refnr_label, str);
620 g_free (str);
621 // NOTE gtk3s bar doesn't place text inside the widget anymore :/
622 //gtk_progress_bar_set_text (gummi->biblio->progressbar, str);
623 g_free (basename);
624 }
625 else {
626 gtk_widget_set_sensitive
627 (GTK_WIDGET(gummi->biblio->list_filter), FALSE);
628 statusbar_set_message
629 (_("No bibliography file detected in document.."));
630 // NOTE gtk3s bar doesn't place text inside the widget anymore :/
631 //gtk_progress_bar_set_text (gummi->biblio->progressbar,
632 // _("no bibliography file detected"));
633 gtk_label_set_text (gummi->biblio->filenm_label, _("none"));
634 gtk_label_set_text (gummi->biblio->refnr_label, _("N/A"));
635 }
636 }
637
638 G_MODULE_EXPORT
on_bibreference_clicked(GtkTreeView * view,GtkTreePath * Path,GtkTreeViewColumn * column,void * user)639 void on_bibreference_clicked (GtkTreeView* view, GtkTreePath* Path,
640 GtkTreeViewColumn* column, void* user) {
641 GtkTreeIter iter;
642 gchar* value;
643 gchar* out;
644 GtkTreeModel* model = GTK_TREE_MODEL (gummi->biblio->list_biblios);
645 GtkTreeSelection* selection = gtk_tree_view_get_selection (view);
646
647 gtk_tree_selection_get_selected (selection, &model, &iter);
648 gtk_tree_model_get (model, &iter, 0, &value, -1);
649 out = g_strdup_printf ("\\cite{%s}", value);
650 gtk_text_buffer_insert_at_cursor (g_e_buffer, out, strlen (out));
651 g_free (out);
652 }
653
visible_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)654 static gboolean visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
655 gboolean row_visible = FALSE;
656 gchar* title;
657 gchar* author;
658 gchar* year;
659
660 /* make all entries visible again when filter buffer is empty */
661 if (strlen(data) == 0) return TRUE;
662
663 gtk_tree_model_get (model, iter, 1, &title, 2, &author, 3, &year, -1);
664 if (utils_subinstr (data, title , TRUE)) row_visible = TRUE;
665 if (utils_subinstr (data, author , TRUE)) row_visible = TRUE;
666 if (utils_subinstr (data, year , TRUE)) row_visible = TRUE;
667
668 g_free(title);
669 g_free(author);
670 g_free(year);
671
672 return row_visible;
673 }
674
675 G_MODULE_EXPORT
on_biblio_filter_changed(GtkWidget * widget,void * user)676 void on_biblio_filter_changed (GtkWidget* widget, void* user) {
677 GtkTreeModel *filter;
678
679 const gchar *entry = gtk_entry_get_text(GTK_ENTRY(widget));
680 filter = gtk_tree_model_filter_new (
681 GTK_TREE_MODEL(gummi->biblio->list_biblios),NULL);
682 gtk_tree_model_filter_set_visible_func(
683 GTK_TREE_MODEL_FILTER(filter), visible_func, (gpointer)entry, NULL);
684 gtk_tree_view_set_model (
685 GTK_TREE_VIEW( gummi->biblio->biblio_treeview ),filter);
686 g_object_unref (G_OBJECT(filter));
687 }
688
typesetter_setup(void)689 void typesetter_setup (void) {
690 // change the pref gui options on changing typesetter:
691 gboolean status = texlive_active();
692 gtk_widget_set_sensitive (GTK_WIDGET (gui->menu_runbibtex), status);
693 gtk_widget_set_sensitive (GTK_WIDGET (gui->menu_runmakeindex), status);
694 gtk_widget_set_sensitive (GTK_WIDGET (gui->prefsgui->opt_shellescape),
695 status);
696
697 if (config_get_boolean ("Compile", "synctex")) {
698 gtk_toggle_button_set_active (gui->prefsgui->opt_synctex, TRUE);
699 }
700 else {
701 gtk_toggle_button_set_active (gui->prefsgui->opt_synctex, FALSE);
702 }
703 gtk_widget_set_sensitive (GTK_WIDGET (gui->prefsgui->opt_synctex), TRUE);
704
705 slog (L_INFO, "Typesetter %s configured\n",
706 config_get_string ("Compile", "typesetter"));
707 }
708
on_bibprogressbar_update(void * data)709 gboolean on_bibprogressbar_update (void* data) {
710 gummi->biblio->progressval += 0.01;
711
712 gtk_progress_bar_set_fraction(gummi->biblio->progressbar,
713 gummi->biblio->progressval);
714
715 if (gummi->biblio->progressval >= 1) {
716 gtk_widget_set_sensitive (data, TRUE);
717 return FALSE;
718 }
719 return TRUE;
720 }
721
check_for_save(GuEditor * editor)722 gint check_for_save (GuEditor* editor) {
723 GtkWidget* dialog;
724 gint ret = 0;
725
726 if (editor && editor_buffer_changed (editor)){
727 dialog = gtk_message_dialog_new (gui->mainwindow,
728 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
729 GTK_MESSAGE_QUESTION,
730 GTK_BUTTONS_NONE,
731 _("This document has unsaved changes"));
732
733 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
734 _("Do you want to save the changes to %s before closing?"),
735 editor->filename != NULL ? g_path_get_basename (editor->filename) : _("this document"));
736
737 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
738 _("_Close without Saving"), GTK_RESPONSE_NO,
739 _("_Cancel"), GTK_RESPONSE_CANCEL,
740 _("_Save As"), GTK_RESPONSE_YES,
741 NULL);
742
743 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
744
745 ret = gtk_dialog_run (GTK_DIALOG (dialog));
746 gtk_widget_destroy (dialog);
747 }
748 return ret;
749 }
750
get_open_filename(GuFilterType type)751 gchar* get_open_filename (GuFilterType type) {
752 GtkFileChooser* chooser = NULL;
753 gchar* active_cwd = NULL;
754 gchar* filename = NULL;
755
756
757 /* check if both active_editor and filename are defined. when zero tabs
758 * are open, the g_active_editor object is destroyed causing a segfault
759 * on the (filename != null) check. */
760 if (g_active_editor != NULL && g_active_editor->filename != NULL) {
761 active_cwd = g_path_get_dirname(g_active_editor->filename);
762 }
763
764 const gchar* chooser_title[] = {
765 _("Open LaTeX document"),
766 "shouldn't happen",
767 "shouldn't happen",
768 _("Select an image to insert"),
769 _("Select bibliography file"),
770 _("Select project file")
771 };
772
773 chooser = GTK_FILE_CHOOSER (gtk_file_chooser_dialog_new (
774 chooser_title[type],
775 gui->mainwindow,
776 GTK_FILE_CHOOSER_ACTION_OPEN,
777 _("_Cancel"), GTK_RESPONSE_CANCEL,
778 _("_Open"), GTK_RESPONSE_OK,
779 NULL));
780
781 file_dialog_set_filter (chooser, type);
782 if (active_cwd)
783 gtk_file_chooser_set_current_folder (chooser, active_cwd);
784 else
785 gtk_file_chooser_set_current_folder (chooser, g_get_home_dir ());
786
787 if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK)
788 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
789
790 if (filename) {
791 g_free (active_cwd);
792 }
793
794 gtk_widget_destroy (GTK_WIDGET (chooser));
795 return filename;
796 }
797
get_save_filename(GuFilterType type)798 gchar* get_save_filename (GuFilterType type) {
799 GtkFileChooser* chooser = NULL;
800 gchar* filename = NULL;
801
802 const gchar* chooser_title[] = {
803 _("Save LaTeX document"),
804 _("Save as LaTeX document"),
805 _("Export to PDF"),
806 "shouldn't happen",
807 "shouldn't happen",
808 _("Create project")
809 };
810
811 chooser = GTK_FILE_CHOOSER (gtk_file_chooser_dialog_new (
812 chooser_title[type],
813 gui->mainwindow,
814 GTK_FILE_CHOOSER_ACTION_SAVE,
815 _("_Cancel"), GTK_RESPONSE_CANCEL,
816 _("_Save"), GTK_RESPONSE_OK,
817 NULL));
818
819 file_dialog_set_filter (chooser, type);
820 gtk_file_chooser_set_current_folder (chooser, g_get_home_dir ());
821
822 if (g_active_editor->filename) {
823 gchar* dirname = g_path_get_dirname (g_active_editor->filename);
824 gchar* basename = g_path_get_basename (g_active_editor->filename);
825
826 gtk_file_chooser_set_current_folder (chooser, dirname);
827
828 if (TYPE_PDF == type) {
829 basename[strlen (basename) -4] = 0;
830 gchar* path = g_strdup_printf ("%s.pdf", basename);
831 gtk_file_chooser_set_current_name (chooser, path);
832 g_free (path);
833 } else if (TYPE_LATEX_SAVEAS == type)
834 gtk_file_chooser_set_current_name (chooser, basename);
835
836 g_free (dirname);
837 g_free (basename);
838 }
839 else {
840 gchar *unsaved = g_strdup_printf (_("Unsaved Document"));
841 if (type == TYPE_PDF)
842 unsaved = g_strconcat (unsaved, ".pdf", NULL);
843 if (type == TYPE_LATEX)
844 unsaved = g_strconcat (unsaved, ".tex", NULL);
845 gtk_file_chooser_set_current_name (chooser, unsaved);
846 }
847
848 if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK)
849 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
850
851 gtk_widget_destroy (GTK_WIDGET (chooser));
852 return filename;
853 }
854
file_dialog_set_filter(GtkFileChooser * dialog,GuFilterType type)855 void file_dialog_set_filter (GtkFileChooser* dialog, GuFilterType type) {
856 GtkFileFilter* filter = gtk_file_filter_new ();
857
858 switch (type) {
859 case TYPE_LATEX:
860 case TYPE_LATEX_SAVEAS:
861 gtk_file_filter_set_name (filter, _("LaTeX files"));
862 gtk_file_filter_add_pattern (filter, "*.tex");
863 gtk_file_chooser_add_filter (dialog, filter);
864 gtk_file_chooser_set_filter (dialog, filter);
865 break;
866
867 case TYPE_PDF:
868 gtk_file_filter_set_name (filter, _(("PDF files")));
869 gtk_file_filter_add_pattern (filter, "*.pdf");
870 gtk_file_chooser_add_filter (dialog, filter);
871 gtk_file_chooser_set_filter (dialog, filter);
872 break;
873
874 case TYPE_IMAGE:
875 /* Only \insertgraphics uses this section now. Make sure
876 * the patterns & mimes are correct before assigning it
877 * for other functions */
878 gtk_file_filter_set_name (filter, _("Supported Image files"));
879
880 /* Pdflatex supports different formats than pure latex */
881 if (latex_method_active ("texpdf")) {
882 gtk_file_filter_add_pattern (filter, "*.jpg");
883 gtk_file_filter_add_pattern (filter, "*.jpeg");
884 gtk_file_filter_add_pattern (filter, "*.png");
885 gtk_file_filter_add_pattern (filter, "*.pdf");
886 }
887 gtk_file_filter_add_pattern (filter, "*.eps");
888 gtk_file_chooser_add_filter (dialog, filter);
889 gtk_file_chooser_set_filter (dialog, filter);
890 break;
891
892 case TYPE_BIBLIO:
893 gtk_file_filter_set_name (filter, _("Bibtex files"));
894 gtk_file_filter_add_pattern (filter, "*.bib");
895 gtk_file_chooser_add_filter (dialog, filter);
896 gtk_file_chooser_set_filter (dialog, filter);
897 break;
898 case TYPE_PROJECT:
899 gtk_file_filter_set_name (filter, _("Gummi project files"));
900 gtk_file_filter_add_pattern (filter, "*.gummi");
901 gtk_file_chooser_add_filter (dialog, filter);
902 gtk_file_chooser_set_filter (dialog, filter);
903 break;
904 }
905 }
906
add_to_recent_list(const gchar * filename)907 void add_to_recent_list (const gchar* filename) {
908 if (!filename) return;
909 gint i = 0;
910 /* check if it already exists */
911 for (i = 0; i < 5; ++i)
912 if (STR_EQU (filename, gui->recent_list[i]))
913 return;
914
915 /* add to recent list */
916 g_free (gui->recent_list[RECENT_FILES_NUM -1]);
917 for (i = RECENT_FILES_NUM -2; i >= 0; --i)
918 gui->recent_list[i + 1] = gui->recent_list[i];
919 gui->recent_list[0] = g_strdup (filename);
920 display_recent_files (gui);
921 }
922
display_recent_files(GummiGui * gui)923 void display_recent_files (GummiGui* gui) {
924 gchar* tstr = 0;
925 gchar* basename = 0;
926 gint i = 0, count = 0;
927
928 for (i = 0; i < 5; ++i)
929 gtk_widget_hide (GTK_WIDGET (gui->recent[i]));
930
931 for (i = 0; i < RECENT_FILES_NUM; ++i) {
932 if (!STR_EQU (gui->recent_list[i], "__NULL__")) {
933 basename = g_path_get_basename (gui->recent_list[i]);
934 tstr = g_strdup_printf ("%d. %s", count + 1, basename);
935 gtk_menu_item_set_label (gui->recent[i], tstr);
936 gtk_widget_set_tooltip_text (GTK_WIDGET (gui->recent[i]),
937 gui->recent_list[i]);
938 gtk_widget_show (GTK_WIDGET (gui->recent[i]));
939 g_free (tstr);
940 g_free (basename);
941 ++count;
942 }
943 }
944 // update recent files
945 for (i = 0; i < RECENT_FILES_NUM; ++i) {
946 tstr = g_strdup_printf ("recent%d", i + 1);
947 config_set_string ("Misc", tstr, gui->recent_list[i]);
948 g_free (tstr);
949 }
950 }
951
gui_buildlog_set_text(const gchar * message)952 void gui_buildlog_set_text (const gchar *message) {
953 if (message) {
954 GtkTextIter iter;
955 GtkTextMark *mark;
956
957 gtk_text_buffer_set_text (gui->errorbuff, message, -1);
958 gtk_text_buffer_get_end_iter (gui->errorbuff, &iter);
959
960 // scrolling to the end used to cause bug #252 but seems ok now:
961 mark = gtk_text_buffer_create_mark(gui->errorbuff, NULL, &iter, FALSE);
962 gtk_text_view_scroll_to_mark (gui->errorview, mark, 0.25, FALSE, 0, 0);
963 }
964 }
965
statusbar_set_message(const gchar * message)966 void statusbar_set_message (const gchar *message) {
967 gtk_statusbar_push (GTK_STATUSBAR (gui->statusbar), gui->statusid, message);
968 g_timeout_add_seconds (4, statusbar_del_message, NULL);
969 }
970
statusbar_del_message(void * user)971 gboolean statusbar_del_message (void* user) {
972 gtk_statusbar_pop (GTK_STATUSBAR (gui->statusbar), gui->statusid);
973 return FALSE;
974 }
975
976 /**
977 * @brief "changed" signal callback for editor->buffer
978 * Automatically check whether to start timer if buffer changed.
979 * Also set_modified for buffer
980 */
check_preview_timer(void)981 void check_preview_timer (void) {
982 g_return_if_fail (g_active_tab != NULL);
983
984 gtk_text_buffer_set_modified (g_e_buffer, TRUE);
985 gummi->latex->modified_since_compile = TRUE;
986
987 gui_set_filename_display (g_active_tab, TRUE, TRUE);
988
989 motion_start_timer (gummi->motion);
990 }
991