2 * dialogs.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 * File related dialogs, miscellaneous dialogs, font dialog.
30 #include <gdk/gdkkeysyms.h>
33 #ifdef HAVE_SYS_TIME_H
34 # include <sys/time.h>
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
42 /* gstdio.h also includes sys/stat.h */
43 #include <glib/gstdio.h>
47 #include "callbacks.h"
49 #include "filetypes.h"
51 #include "sciwrappers.h"
55 #include "keybindings.h"
56 #include "encodings.h"
64 GEANY_RESPONSE_RENAME
,
69 static gboolean
handle_save_as(const gchar
*utf8_filename
, gboolean open_new_tab
,
70 gboolean rename_file
);
73 static GtkWidget
*add_file_open_extra_widget(void);
77 on_file_open_dialog_response (GtkDialog
*dialog
,
81 gtk_widget_hide(ui_widgets
.open_filesel
);
83 if (response
== GTK_RESPONSE_ACCEPT
|| response
== GEANY_RESPONSE_VIEW
)
86 gint filetype_idx
= gtk_combo_box_get_active(GTK_COMBO_BOX(
87 ui_lookup_widget(GTK_WIDGET(dialog
), "filetype_combo")));
88 gint encoding_idx
= gtk_combo_box_get_active(GTK_COMBO_BOX(
89 ui_lookup_widget(GTK_WIDGET(dialog
), "encoding_combo")));
90 GeanyFiletype
*ft
= NULL
;
91 const gchar
*charset
= NULL
;
92 gboolean ro
= (response
== GEANY_RESPONSE_VIEW
); /* View clicked */
94 /* ignore detect from file item */
96 ft
= g_slist_nth_data(filetypes_by_title
, filetype_idx
);
97 if (encoding_idx
>= 0 && encoding_idx
< GEANY_ENCODINGS_MAX
)
98 charset
= encodings
[encoding_idx
].charset
;
100 filelist
= gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
));
101 if (filelist
!= NULL
)
103 document_open_files(filelist
, ro
, ft
, charset
);
104 g_slist_foreach(filelist
, (GFunc
) g_free
, NULL
); /* free filenames */
106 g_slist_free(filelist
);
108 if (app
->project
&& NZV(app
->project
->base_path
))
109 gtk_file_chooser_remove_shortcut_folder(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
110 app
->project
->base_path
, NULL
);
114 static void on_file_open_notify(GObject
*filechooser
, GParamSpec
*pspec
, gpointer data
)
118 value
= g_new0(GValue
, 1);
119 g_value_init(value
, pspec
->value_type
);
120 g_object_get_property(filechooser
, pspec
->name
, value
);
122 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
123 ui_lookup_widget(GTK_WIDGET(filechooser
), "check_hidden")), g_value_get_boolean(value
));
128 on_file_open_check_hidden_toggled(GtkToggleButton
*togglebutton
, gpointer user_data
)
130 gboolean is_on
= gtk_toggle_button_get_active(togglebutton
);
132 gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
), is_on
);
136 static void create_open_file_dialog(void)
138 GtkWidget
*filetype_combo
, *encoding_combo
;
141 gchar
*encoding_string
;
144 ui_widgets
.open_filesel
= gtk_file_chooser_dialog_new(_("Open File"), GTK_WINDOW(main_widgets
.window
),
145 GTK_FILE_CHOOSER_ACTION_OPEN
, NULL
, NULL
);
146 gtk_widget_set_name(ui_widgets
.open_filesel
, "GeanyDialog");
148 viewbtn
= gtk_dialog_add_button(GTK_DIALOG(ui_widgets
.open_filesel
), _("_View"),
149 GEANY_RESPONSE_VIEW
);
150 ui_widget_set_tooltip_text(viewbtn
,
151 _("Opens the file in read-only mode. If you choose more than one file to open, all files will be opened read-only."));
153 gtk_dialog_add_buttons(GTK_DIALOG(ui_widgets
.open_filesel
),
154 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
155 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
, NULL
);
156 gtk_dialog_set_default_response(GTK_DIALOG(ui_widgets
.open_filesel
), GTK_RESPONSE_ACCEPT
);
158 gtk_widget_set_size_request(ui_widgets
.open_filesel
, -1, 460);
159 gtk_window_set_modal(GTK_WINDOW(ui_widgets
.open_filesel
), TRUE
);
160 gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets
.open_filesel
), TRUE
);
161 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets
.open_filesel
), FALSE
);
162 gtk_window_set_type_hint(GTK_WINDOW(ui_widgets
.open_filesel
), GDK_WINDOW_TYPE_HINT_DIALOG
);
163 gtk_window_set_transient_for(GTK_WINDOW(ui_widgets
.open_filesel
), GTK_WINDOW(main_widgets
.window
));
164 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
), TRUE
);
165 if (gtk_check_version(2, 14, 0) == NULL
)
166 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
), FALSE
);
168 /* add checkboxes and filename entry */
169 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
170 add_file_open_extra_widget());
171 filetype_combo
= ui_lookup_widget(ui_widgets
.open_filesel
, "filetype_combo");
173 gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo
), _("Detect by file extension"));
174 /* add FileFilters(start with "All Files") */
175 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
176 filetypes_create_file_filter(filetypes
[GEANY_FILETYPES_NONE
]));
177 /* now create meta filter "All Source" */
178 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
179 filetypes_create_file_filter_all_source());
180 foreach_slist(node
, filetypes_by_title
)
182 GeanyFiletype
*ft
= node
->data
;
184 if (G_UNLIKELY(ft
->id
== GEANY_FILETYPES_NONE
))
186 gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo
), ft
->title
);
187 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
188 filetypes_create_file_filter(ft
));
190 gtk_combo_box_set_active(GTK_COMBO_BOX(filetype_combo
), 0);
192 /* fill encoding combo box */
193 encoding_combo
= ui_lookup_widget(ui_widgets
.open_filesel
, "encoding_combo");
194 for (i
= 0; i
< GEANY_ENCODINGS_MAX
; i
++)
196 encoding_string
= encodings_to_string(&encodings
[i
]);
197 gtk_combo_box_append_text(GTK_COMBO_BOX(encoding_combo
), encoding_string
);
198 g_free(encoding_string
);
200 gtk_combo_box_append_text(GTK_COMBO_BOX(encoding_combo
), _("Detect from file"));
201 gtk_combo_box_set_active(GTK_COMBO_BOX(encoding_combo
), GEANY_ENCODINGS_MAX
);
203 g_signal_connect(ui_widgets
.open_filesel
, "notify::show-hidden",
204 G_CALLBACK(on_file_open_notify
), NULL
);
205 g_signal_connect(ui_widgets
.open_filesel
, "delete-event",
206 G_CALLBACK(gtk_widget_hide_on_delete
), NULL
);
207 g_signal_connect(ui_widgets
.open_filesel
, "response",
208 G_CALLBACK(on_file_open_dialog_response
), NULL
);
212 /* This shows the file selection dialog to open a file. */
213 void dialogs_show_open_file()
217 /* set dialog directory to the current file's directory, if present */
218 initdir
= utils_get_current_file_dir_utf8();
220 /* use project or default startup directory (if set) if no files are open */
221 /** TODO should it only be used when initally open the dialog and not on every show? */
223 initdir
= g_strdup(utils_get_default_dir_utf8());
225 setptr(initdir
, utils_get_locale_from_utf8(initdir
));
228 if (interface_prefs
.use_native_windows_dialogs
)
229 win32_show_document_open_dialog(GTK_WINDOW(main_widgets
.window
), _("Open File"), initdir
);
233 /* We use the same file selection widget each time, so first of all we create it
234 * if it hasn't already been created. */
235 if (ui_widgets
.open_filesel
== NULL
)
236 create_open_file_dialog();
240 if (g_path_is_absolute(initdir
))
241 gtk_file_chooser_set_current_folder(
242 GTK_FILE_CHOOSER(ui_widgets
.open_filesel
), initdir
);
245 if (app
->project
&& NZV(app
->project
->base_path
))
246 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
),
247 app
->project
->base_path
, NULL
);
249 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(ui_widgets
.open_filesel
));
250 gtk_window_present(GTK_WINDOW(ui_widgets
.open_filesel
));
256 static GtkWidget
*add_file_open_extra_widget()
258 GtkWidget
*expander
, *vbox
, *table
, *check_hidden
;
259 GtkWidget
*filetype_ebox
, *filetype_label
, *filetype_combo
;
260 GtkWidget
*encoding_ebox
, *encoding_label
, *encoding_combo
;
262 expander
= gtk_expander_new_with_mnemonic(_("_More Options"));
263 vbox
= gtk_vbox_new(FALSE
, 6);
264 gtk_container_add(GTK_CONTAINER(expander
), vbox
);
266 table
= gtk_table_new(2, 4, FALSE
);
268 /* line 1 with checkbox and encoding combo */
269 check_hidden
= gtk_check_button_new_with_mnemonic(_("Show _hidden files"));
270 gtk_widget_show(check_hidden
);
271 gtk_table_attach(GTK_TABLE(table
), check_hidden
, 0, 1, 0, 1,
272 (GtkAttachOptions
) (GTK_FILL
| GTK_EXPAND
),
273 (GtkAttachOptions
) (0), 0, 5);
276 gtk_table_attach(GTK_TABLE(table
), gtk_label_new(""), 1, 2, 0, 1,
277 (GtkAttachOptions
) (GTK_FILL
),
278 (GtkAttachOptions
) (0), 5, 5);
280 encoding_label
= gtk_label_new(_("Set encoding:"));
281 gtk_misc_set_alignment(GTK_MISC(encoding_label
), 1, 0);
282 gtk_table_attach(GTK_TABLE(table
), encoding_label
, 2, 3, 0, 1,
283 (GtkAttachOptions
) (GTK_FILL
),
284 (GtkAttachOptions
) (0), 4, 5);
285 /* the ebox is for the tooltip, because gtk_combo_box can't show tooltips */
286 encoding_ebox
= gtk_event_box_new();
287 encoding_combo
= gtk_combo_box_new_text();
288 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(encoding_combo
), 3);
289 ui_widget_set_tooltip_text(encoding_ebox
,
290 _("Explicitly defines an encoding for the file, if it would not be detected. This is useful when you know that the encoding of a file cannot be detected correctly by Geany.\nNote if you choose multiple files, they will all be opened with the chosen encoding."));
291 gtk_container_add(GTK_CONTAINER(encoding_ebox
), encoding_combo
);
292 gtk_table_attach(GTK_TABLE(table
), encoding_ebox
, 3, 4, 0, 1,
293 (GtkAttachOptions
) (GTK_FILL
),
294 (GtkAttachOptions
) (0), 0, 5);
296 /* line 2 with filetype combo */
297 filetype_label
= gtk_label_new(_("Set filetype:"));
298 gtk_misc_set_alignment(GTK_MISC(filetype_label
), 1, 0);
299 gtk_table_attach(GTK_TABLE(table
), filetype_label
, 2, 3, 1, 2,
300 (GtkAttachOptions
) (GTK_FILL
),
301 (GtkAttachOptions
) (0), 4, 5);
302 /* the ebox is for the tooltip, because gtk_combo_box can't show tooltips */
303 filetype_ebox
= gtk_event_box_new();
304 filetype_combo
= gtk_combo_box_new_text();
305 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(filetype_combo
), 2);
306 ui_widget_set_tooltip_text(filetype_ebox
,
307 _("Explicitly defines a filetype for the file, if it would not be detected by filename extension.\nNote if you choose multiple files, they will all be opened with the chosen filetype."));
308 gtk_container_add(GTK_CONTAINER(filetype_ebox
), filetype_combo
);
309 gtk_table_attach(GTK_TABLE(table
), filetype_ebox
, 3, 4, 1, 2,
310 (GtkAttachOptions
) (GTK_FILL
),
311 (GtkAttachOptions
) (0), 0, 5);
313 gtk_box_pack_start(GTK_BOX(vbox
), table
, FALSE
, FALSE
, 0);
314 gtk_widget_show_all(vbox
);
316 g_signal_connect(check_hidden
, "toggled",
317 G_CALLBACK(on_file_open_check_hidden_toggled
), NULL
);
319 g_object_set_data_full(G_OBJECT(ui_widgets
.open_filesel
), "check_hidden",
320 g_object_ref(check_hidden
), (GDestroyNotify
)g_object_unref
);
321 g_object_set_data_full(G_OBJECT(ui_widgets
.open_filesel
), "filetype_combo",
322 g_object_ref(filetype_combo
), (GDestroyNotify
)g_object_unref
);
323 g_object_set_data_full(G_OBJECT(ui_widgets
.open_filesel
), "encoding_combo",
324 g_object_ref(encoding_combo
), (GDestroyNotify
)g_object_unref
);
330 static void on_save_as_new_tab_toggled(GtkToggleButton
*togglebutton
, gpointer user_data
)
332 gtk_widget_set_sensitive(GTK_WIDGET(user_data
),
333 ! gtk_toggle_button_get_active(togglebutton
));
337 static gboolean
handle_save_as(const gchar
*utf8_filename
, gboolean open_new_tab
, gboolean rename_file
)
339 GeanyDocument
*doc
= document_get_current();
340 gboolean success
= FALSE
;
342 g_return_val_if_fail(NZV(utf8_filename
), FALSE
);
345 { /* "open" the saved file in a new tab and switch to it */
346 doc
= document_clone(doc
, utf8_filename
);
347 success
= document_save_file_as(doc
, NULL
);
351 if (doc
->file_name
!= NULL
)
355 document_rename_file(doc
, utf8_filename
);
357 /* create a new tm_source_file object otherwise tagmanager won't work correctly */
358 tm_workspace_remove_object(doc
->tm_file
, TRUE
, TRUE
);
361 success
= document_save_file_as(doc
, utf8_filename
);
363 build_menu_update(doc
);
370 on_file_save_dialog_response (GtkDialog
*dialog
,
374 gboolean rename_file
= FALSE
;
375 gboolean success
= FALSE
;
376 gchar
*new_filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
));
380 case GEANY_RESPONSE_RENAME
:
381 /* rename doesn't check for empty filename or overwriting */
382 if (! NZV(new_filename
))
387 if (g_file_test(new_filename
, G_FILE_TEST_EXISTS
) &&
388 !dialogs_show_question_full(NULL
, NULL
, NULL
,
390 _("Filename already exists!")))
394 case GTK_RESPONSE_ACCEPT
:
396 gboolean open_new_tab
= gtk_toggle_button_get_active(
397 GTK_TOGGLE_BUTTON(ui_lookup_widget(ui_widgets
.save_filesel
, "check_open_new_tab")));
398 gchar
*utf8_filename
;
400 utf8_filename
= utils_get_utf8_from_locale(new_filename
);
401 success
= handle_save_as(utf8_filename
, open_new_tab
, rename_file
);
403 g_free(utf8_filename
);
406 case GTK_RESPONSE_CANCEL
:
410 g_free(new_filename
);
413 gtk_widget_hide(ui_widgets
.save_filesel
);
417 static void create_save_file_dialog(void)
419 GtkWidget
*vbox
, *check_open_new_tab
, *rename_btn
;
420 const gchar
*initdir
;
422 ui_widgets
.save_filesel
= gtk_file_chooser_dialog_new(_("Save File"), GTK_WINDOW(main_widgets
.window
),
423 GTK_FILE_CHOOSER_ACTION_SAVE
, NULL
, NULL
);
424 gtk_window_set_modal(GTK_WINDOW(ui_widgets
.save_filesel
), TRUE
);
425 gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets
.save_filesel
), TRUE
);
426 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets
.save_filesel
), FALSE
);
427 gtk_window_set_type_hint(GTK_WINDOW(ui_widgets
.save_filesel
), GDK_WINDOW_TYPE_HINT_DIALOG
);
428 gtk_widget_set_name(ui_widgets
.save_filesel
, "GeanyDialog");
430 rename_btn
= gtk_dialog_add_button(GTK_DIALOG(ui_widgets
.save_filesel
), _("R_ename"),
431 GEANY_RESPONSE_RENAME
);
432 ui_widget_set_tooltip_text(rename_btn
, _("Save the file and rename it"));
434 gtk_dialog_add_buttons(GTK_DIALOG(ui_widgets
.save_filesel
),
435 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
436 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
, NULL
);
437 gtk_dialog_set_default_response(GTK_DIALOG(ui_widgets
.save_filesel
), GTK_RESPONSE_ACCEPT
);
439 vbox
= gtk_vbox_new(FALSE
, 0);
440 check_open_new_tab
= gtk_check_button_new_with_mnemonic(_("_Open file in a new tab"));
441 ui_widget_set_tooltip_text(check_open_new_tab
,
442 _("Keep the current unsaved document open"
443 " and open the newly saved file in a new tab"));
444 gtk_box_pack_start(GTK_BOX(vbox
), check_open_new_tab
, FALSE
, FALSE
, 0);
445 gtk_widget_show_all(vbox
);
446 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
), vbox
);
447 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
), TRUE
);
448 if (gtk_check_version(2, 14, 0) == NULL
)
449 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
), FALSE
);
451 /* set the folder by default to the project base dir or the global pref for opening files */
452 initdir
= utils_get_default_dir_utf8();
455 gchar
*linitdir
= utils_get_locale_from_utf8(initdir
);
456 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
), linitdir
);
460 g_signal_connect(check_open_new_tab
, "toggled",
461 G_CALLBACK(on_save_as_new_tab_toggled
), rename_btn
);
463 g_object_set_data_full(G_OBJECT(ui_widgets
.save_filesel
), "check_open_new_tab",
464 g_object_ref(check_open_new_tab
), (GDestroyNotify
)g_object_unref
);
466 g_signal_connect(ui_widgets
.save_filesel
, "delete-event",
467 G_CALLBACK(gtk_widget_hide_on_delete
), NULL
);
468 g_signal_connect(ui_widgets
.save_filesel
, "response",
469 G_CALLBACK(on_file_save_dialog_response
), NULL
);
471 gtk_window_set_transient_for(GTK_WINDOW(ui_widgets
.save_filesel
), GTK_WINDOW(main_widgets
.window
));
475 static gboolean
gtk_show_save_as(void)
477 GeanyDocument
*doc
= document_get_current();
480 g_return_val_if_fail(doc
!= NULL
, FALSE
);
482 if (G_UNLIKELY(ui_widgets
.save_filesel
== NULL
))
483 create_save_file_dialog();
485 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
));
487 if (doc
->file_name
!= NULL
)
489 if (g_path_is_absolute(doc
->file_name
))
491 gchar
*locale_filename
= utils_get_locale_from_utf8(doc
->file_name
);
492 gchar
*locale_basename
= g_path_get_basename(locale_filename
);
493 gchar
*locale_dirname
= g_path_get_dirname(locale_filename
);
495 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
),
497 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
),
500 g_free(locale_filename
);
501 g_free(locale_basename
);
502 g_free(locale_dirname
);
505 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
),
512 if (doc
->file_type
!= NULL
&& doc
->file_type
->extension
!= NULL
)
513 fname
= g_strconcat(GEANY_STRING_UNTITLED
, ".",
514 doc
->file_type
->extension
, NULL
);
516 fname
= g_strdup(GEANY_STRING_UNTITLED
);
518 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
), fname
);
523 if (app
->project
&& NZV(app
->project
->base_path
))
524 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
),
525 app
->project
->base_path
, NULL
);
527 /* Run the dialog synchronously, pausing this function call */
528 resp
= gtk_dialog_run(GTK_DIALOG(ui_widgets
.save_filesel
));
530 if (app
->project
&& NZV(app
->project
->base_path
))
531 gtk_file_chooser_remove_shortcut_folder(GTK_FILE_CHOOSER(ui_widgets
.save_filesel
),
532 app
->project
->base_path
, NULL
);
534 return (resp
== GTK_RESPONSE_ACCEPT
);
539 * Shows the Save As dialog for the current notebook page.
541 * @return @c TRUE if the file was saved, otherwise @c FALSE.
543 gboolean
dialogs_show_save_as()
545 gboolean result
= FALSE
;
548 if (interface_prefs
.use_native_windows_dialogs
)
550 GeanyDocument
*doc
= document_get_current();
551 gchar
*utf8_name
= win32_show_document_save_as_dialog(GTK_WINDOW(main_widgets
.window
),
552 _("Save File"), DOC_FILENAME(doc
));
553 if (utf8_name
!= NULL
)
554 result
= handle_save_as(utf8_name
, FALSE
, FALSE
);
558 result
= gtk_show_save_as();
564 static void show_msgbox_dialog(GtkWidget
*dialog
, GtkMessageType type
, GtkWindow
*parent
)
569 case GTK_MESSAGE_ERROR
:
572 case GTK_MESSAGE_QUESTION
:
573 title
= _("Question");
575 case GTK_MESSAGE_WARNING
:
576 title
= _("Warning");
579 title
= _("Information");
582 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
583 if (parent
== NULL
|| GTK_IS_DIALOG(parent
))
585 GdkPixbuf
*pb
= ui_new_pixbuf_from_inline(GEANY_IMAGE_LOGO
);
586 gtk_window_set_icon(GTK_WINDOW(dialog
), pb
);
589 gtk_widget_set_name(dialog
, "GeanyDialog");
591 gtk_dialog_run(GTK_DIALOG(dialog
));
592 gtk_widget_destroy(dialog
);
598 * Shows a message box of the type @a type with @a text.
599 * On Unix-like systems a GTK message dialog box is shown, on Win32 systems a native Windows
600 * message dialog box is shown.
602 * @param type A @c GtkMessageType, e.g. @c GTK_MESSAGE_INFO, @c GTK_MESSAGE_WARNING,
603 * @c GTK_MESSAGE_QUESTION, @c GTK_MESSAGE_ERROR.
604 * @param text Printf()-style format string.
605 * @param ... Arguments for the @a text format string.
607 void dialogs_show_msgbox(GtkMessageType type
, const gchar
*text
, ...)
614 GtkWindow
*parent
= (main_status
.main_window_realized
) ? GTK_WINDOW(main_widgets
.window
) : NULL
;
616 va_start(args
, text
);
617 string
= g_strdup_vprintf(text
, args
);
621 win32_message_dialog(GTK_WIDGET(parent
), type
, string
);
623 dialog
= gtk_message_dialog_new(parent
, GTK_DIALOG_DESTROY_WITH_PARENT
,
624 type
, GTK_BUTTONS_OK
, "%s", string
);
625 show_msgbox_dialog(dialog
, type
, parent
);
631 void dialogs_show_msgbox_with_secondary(GtkMessageType type
, const gchar
*text
, const gchar
*secondary
)
633 GtkWindow
*parent
= (main_status
.main_window_realized
) ? GTK_WINDOW(main_widgets
.window
) : NULL
;
635 /* put the two strings together because Windows message boxes don't support secondary texts */
636 gchar
*string
= g_strconcat(text
, "\n", secondary
, NULL
);
637 win32_message_dialog(GTK_WIDGET(parent
), type
, string
);
641 dialog
= gtk_message_dialog_new(parent
, GTK_DIALOG_DESTROY_WITH_PARENT
,
642 type
, GTK_BUTTONS_OK
, "%s", text
);
643 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
), "%s", secondary
);
644 show_msgbox_dialog(dialog
, type
, parent
);
650 static gint
run_unsaved_dialog(const gchar
*msg
, const gchar
*msg2
)
652 GtkWidget
*dialog
, *button
;
655 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_widgets
.window
), GTK_DIALOG_DESTROY_WITH_PARENT
,
656 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
, "%s", msg
);
657 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
), "%s", msg2
);
658 gtk_dialog_add_button(GTK_DIALOG(dialog
), GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
);
660 button
= ui_button_new_with_image(GTK_STOCK_CLEAR
, _("_Don't save"));
661 gtk_dialog_add_action_widget(GTK_DIALOG(dialog
), button
, GTK_RESPONSE_NO
);
662 gtk_widget_show(button
);
664 gtk_dialog_add_button(GTK_DIALOG(dialog
), GTK_STOCK_SAVE
, GTK_RESPONSE_YES
);
666 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_YES
);
667 ret
= gtk_dialog_run(GTK_DIALOG(dialog
));
669 gtk_widget_destroy(dialog
);
676 gboolean
dialogs_show_unsaved_file(GeanyDocument
*doc
)
678 gchar
*msg
, *short_fn
= NULL
;
681 gboolean old_quitting_state
= main_status
.quitting
;
683 /* display the file tab to remind the user of the document */
684 main_status
.quitting
= FALSE
;
685 gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets
.notebook
),
686 document_get_notebook_page(doc
));
687 main_status
.quitting
= old_quitting_state
;
689 short_fn
= document_get_basename_for_display(doc
, -1);
691 msg
= g_strdup_printf(_("The file '%s' is not saved."),
692 (short_fn
!= NULL
) ? short_fn
: GEANY_STRING_UNTITLED
);
693 msg2
= _("Do you want to save it before closing?");
697 setptr(msg
, g_strconcat(msg
, "\n", msg2
, NULL
));
698 ret
= win32_message_dialog_unsaved(msg
);
700 ret
= run_unsaved_dialog(msg
, msg2
);
706 case GTK_RESPONSE_YES
:
708 if (document_need_save_as(doc
))
710 ret
= dialogs_show_save_as();
713 /* document_save_file() returns the status if the file could be saved */
714 ret
= document_save_file(doc
, FALSE
);
717 case GTK_RESPONSE_NO
: ret
= TRUE
; break;
718 case GTK_RESPONSE_CANCEL
: /* fall through to default and leave the function */
719 default: ret
= FALSE
; break;
722 return (gboolean
) ret
;
728 on_font_apply_button_clicked (GtkButton
*button
,
733 fontname
= gtk_font_selection_dialog_get_font_name(
734 GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
));
735 ui_set_editor_font(fontname
);
741 on_font_ok_button_clicked (GtkButton
*button
,
744 /* We do the same thing as apply, but we close the dialog after. */
745 on_font_apply_button_clicked(button
, NULL
);
746 gtk_widget_hide(ui_widgets
.open_fontsel
);
751 on_font_cancel_button_clicked (GtkButton
*button
,
754 gtk_widget_hide(ui_widgets
.open_fontsel
);
759 /* This shows the font selection dialog to choose a font. */
760 void dialogs_show_open_font()
763 win32_show_font_dialog();
766 if (ui_widgets
.open_fontsel
== NULL
)
768 ui_widgets
.open_fontsel
= gtk_font_selection_dialog_new(_("Choose font"));;
769 gtk_container_set_border_width(GTK_CONTAINER(ui_widgets
.open_fontsel
), 4);
770 gtk_window_set_modal(GTK_WINDOW(ui_widgets
.open_fontsel
), TRUE
);
771 gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets
.open_fontsel
), TRUE
);
772 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets
.open_fontsel
), TRUE
);
773 gtk_window_set_type_hint(GTK_WINDOW(ui_widgets
.open_fontsel
), GDK_WINDOW_TYPE_HINT_DIALOG
);
774 gtk_widget_set_name(ui_widgets
.open_fontsel
, "GeanyDialog");
776 gtk_widget_show(GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
)->apply_button
);
778 g_signal_connect(ui_widgets
.open_fontsel
,
779 "delete-event", G_CALLBACK(gtk_widget_hide_on_delete
), NULL
);
780 g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
)->ok_button
,
781 "clicked", G_CALLBACK(on_font_ok_button_clicked
), NULL
);
782 g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
)->cancel_button
,
783 "clicked", G_CALLBACK(on_font_cancel_button_clicked
), NULL
);
784 g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
)->apply_button
,
785 "clicked", G_CALLBACK(on_font_apply_button_clicked
), NULL
);
787 gtk_font_selection_dialog_set_font_name(
788 GTK_FONT_SELECTION_DIALOG(ui_widgets
.open_fontsel
), interface_prefs
.editor_font
);
789 gtk_window_set_transient_for(GTK_WINDOW(ui_widgets
.open_fontsel
), GTK_WINDOW(main_widgets
.window
));
791 /* We make sure the dialog is visible. */
792 gtk_window_present(GTK_WINDOW(ui_widgets
.open_fontsel
));
798 on_input_dialog_show(GtkDialog
*dialog
, GtkWidget
*entry
)
800 gtk_widget_grab_focus(entry
);
805 on_input_entry_activate(GtkEntry
*entry
, GtkDialog
*dialog
)
807 gtk_dialog_response(dialog
, GTK_RESPONSE_ACCEPT
);
812 on_input_numeric_activate(GtkEntry
*entry
, GtkDialog
*dialog
)
814 gtk_dialog_response(dialog
, GTK_RESPONSE_ACCEPT
);
819 on_input_dialog_response(GtkDialog
*dialog
,
823 gboolean persistent
= (gboolean
) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog
), "has_combo"));
825 if (response
== GTK_RESPONSE_ACCEPT
)
827 const gchar
*str
= gtk_entry_get_text(GTK_ENTRY(entry
));
828 GeanyInputCallback input_cb
=
829 (GeanyInputCallback
) g_object_get_data(G_OBJECT(dialog
), "input_cb");
833 GtkWidget
*combo
= (GtkWidget
*) g_object_get_data(G_OBJECT(dialog
), "combo");
834 ui_combo_box_add_to_history(GTK_COMBO_BOX(combo
), str
);
838 gtk_widget_hide(GTK_WIDGET(dialog
));
842 static void add_input_widgets(GtkWidget
*dialog
, GtkWidget
*vbox
,
843 const gchar
*label_text
, const gchar
*default_text
, gboolean persistent
,
844 GCallback insert_text_cb
)
850 GtkWidget
*label
= gtk_label_new(label_text
);
851 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
852 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
853 gtk_container_add(GTK_CONTAINER(vbox
), label
);
856 if (persistent
) /* remember previous entry text in a combo box */
858 GtkWidget
*combo
= gtk_combo_box_entry_new_text();
860 entry
= GTK_BIN(combo
)->child
;
861 ui_entry_add_clear_icon(GTK_ENTRY(entry
));
862 g_object_set_data(G_OBJECT(dialog
), "combo", combo
);
863 gtk_container_add(GTK_CONTAINER(vbox
), combo
);
867 entry
= gtk_entry_new();
868 ui_entry_add_clear_icon(GTK_ENTRY(entry
));
869 gtk_container_add(GTK_CONTAINER(vbox
), entry
);
872 if (default_text
!= NULL
)
874 gtk_entry_set_text(GTK_ENTRY(entry
), default_text
);
876 gtk_entry_set_max_length(GTK_ENTRY(entry
), 255);
877 gtk_entry_set_width_chars(GTK_ENTRY(entry
), 30);
879 if (insert_text_cb
!= NULL
)
880 g_signal_connect(entry
, "insert-text", insert_text_cb
, NULL
);
881 g_signal_connect(entry
, "activate", G_CALLBACK(on_input_entry_activate
), dialog
);
882 g_signal_connect(dialog
, "show", G_CALLBACK(on_input_dialog_show
), entry
);
883 g_signal_connect(dialog
, "response", G_CALLBACK(on_input_dialog_response
), entry
);
887 /* Create and display an input dialog.
888 * persistent: whether to remember previous entry text in a combo box;
889 * in this case the dialog returned is not destroyed on a response,
890 * and can be reshown.
891 * Returns: the dialog widget. */
893 dialogs_show_input_full(const gchar
*title
, const gchar
*label_text
, const gchar
*default_text
,
894 gboolean persistent
, GeanyInputCallback input_cb
, GCallback insert_text_cb
)
896 GtkWidget
*dialog
, *vbox
;
898 dialog
= gtk_dialog_new_with_buttons(title
, GTK_WINDOW(main_widgets
.window
),
899 GTK_DIALOG_DESTROY_WITH_PARENT
, GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
900 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
, NULL
);
901 vbox
= ui_dialog_vbox_new(GTK_DIALOG(dialog
));
902 gtk_widget_set_name(dialog
, "GeanyDialog");
903 gtk_box_set_spacing(GTK_BOX(vbox
), 6);
905 g_object_set_data(G_OBJECT(dialog
), "has_combo", GINT_TO_POINTER(persistent
));
906 g_object_set_data(G_OBJECT(dialog
), "input_cb", (gpointer
) input_cb
);
908 add_input_widgets(dialog
, vbox
, label_text
, default_text
, persistent
, insert_text_cb
);
912 /* override default handler */
913 g_signal_connect(dialog
, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete
), NULL
);
914 gtk_widget_show_all(dialog
);
917 gtk_widget_show_all(dialog
);
918 gtk_dialog_run(GTK_DIALOG(dialog
));
919 gtk_widget_destroy(dialog
);
924 /* Remember previous entry text in a combo box.
925 * Returns: the dialog widget. */
927 dialogs_show_input_persistent(const gchar
*title
, const gchar
*label_text
, const gchar
*default_text
,
928 GeanyInputCallback input_cb
)
930 return dialogs_show_input_full(title
, label_text
, default_text
, TRUE
, input_cb
, NULL
);
934 /* ugly hack - user_data not supported for callback */
935 static gchar
*dialog_input
= NULL
;
937 static void on_dialog_input(const gchar
*str
)
939 dialog_input
= g_strdup(str
);
943 /* Returns: newly allocated string - a copy of either the entry text or default_text. */
944 gchar
*dialogs_show_input(const gchar
*title
, const gchar
*label_text
,
945 const gchar
*default_text
)
948 dialogs_show_input_full(title
, label_text
, default_text
, FALSE
, on_dialog_input
, NULL
);
949 return NVL(dialog_input
, g_strdup(default_text
));
953 /* Returns: newly allocated copy of the entry text or NULL on cancel.
954 * Specialised variant for Goto Line dialog. */
955 gchar
*dialogs_show_input_goto_line(const gchar
*title
, const gchar
*label_text
,
956 const gchar
*default_text
)
959 dialogs_show_input_full(
960 title
, label_text
, default_text
, FALSE
, on_dialog_input
,
961 G_CALLBACK(ui_editable_insert_text_callback
));
967 * Shows an input box to enter a numerical value using a GtkSpinButton.
968 * If the dialog is aborted, @a value remains untouched.
970 * @param title The dialog title.
971 * @param label_text The shown dialog label.
972 * @param value The default value for the spin button and the return location of the entered value.
974 * @param min Minimum allowable value (see documentation for @c gtk_spin_button_new_with_range()).
975 * @param max Maximum allowable value (see documentation for @c gtk_spin_button_new_with_range()).
976 * @param step Increment added or subtracted by spinning the widget
977 * (see documentation for @c gtk_spin_button_new_with_range()).
979 * @return @c TRUE if a value was entered and the dialog closed with 'OK'. @c FALSE otherwise.
983 gboolean
dialogs_show_input_numeric(const gchar
*title
, const gchar
*label_text
,
984 gdouble
*value
, gdouble min
, gdouble max
, gdouble step
)
986 GtkWidget
*dialog
, *label
, *spin
, *vbox
;
987 gboolean res
= FALSE
;
989 g_return_val_if_fail(title
!= NULL
, FALSE
);
990 g_return_val_if_fail(label_text
!= NULL
, FALSE
);
991 g_return_val_if_fail(value
!= NULL
, FALSE
);
993 dialog
= gtk_dialog_new_with_buttons(title
, GTK_WINDOW(main_widgets
.window
),
994 GTK_DIALOG_DESTROY_WITH_PARENT
,
995 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
996 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
, NULL
);
997 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_CANCEL
);
998 vbox
= ui_dialog_vbox_new(GTK_DIALOG(dialog
));
999 gtk_widget_set_name(dialog
, "GeanyDialog");
1001 label
= gtk_label_new(label_text
);
1002 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
1004 spin
= gtk_spin_button_new_with_range(min
, max
, step
);
1005 ui_entry_add_clear_icon(GTK_ENTRY(spin
));
1006 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin
), *value
);
1007 g_signal_connect(spin
, "activate", G_CALLBACK(on_input_numeric_activate
), dialog
);
1009 gtk_container_add(GTK_CONTAINER(vbox
), label
);
1010 gtk_container_add(GTK_CONTAINER(vbox
), spin
);
1011 gtk_widget_show_all(vbox
);
1013 if (gtk_dialog_run(GTK_DIALOG(dialog
)) == GTK_RESPONSE_ACCEPT
)
1015 *value
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin
));
1018 gtk_widget_destroy(dialog
);
1024 void dialogs_show_file_properties(GeanyDocument
*doc
)
1026 GtkWidget
*dialog
, *label
, *table
, *hbox
, *image
, *perm_table
, *check
, *vbox
;
1027 gchar
*file_size
, *title
, *base_name
, *time_changed
, *time_modified
, *time_accessed
, *enctext
;
1029 #ifdef HAVE_SYS_TYPES_H
1033 gchar
*locale_filename
;
1039 /* define this ones, to avoid later trouble */
1054 if (doc
== NULL
|| doc
->file_name
== NULL
)
1056 dialogs_show_msgbox(GTK_MESSAGE_ERROR
,
1057 _("An error occurred or file information could not be retrieved (e.g. from a new file)."));
1062 #ifdef HAVE_SYS_TYPES_H
1063 locale_filename
= utils_get_locale_from_utf8(doc
->file_name
);
1064 if (g_stat(locale_filename
, &st
) == 0)
1066 /* first copy the returned string and the trim it, to not modify the static glibc string
1067 * g_strchomp() is used to remove trailing EOL chars, which are there for whatever reason */
1068 time_changed
= g_strchomp(g_strdup(ctime(&st
.st_ctime
)));
1069 time_modified
= g_strchomp(g_strdup(ctime(&st
.st_mtime
)));
1070 time_accessed
= g_strchomp(g_strdup(ctime(&st
.st_atime
)));
1071 filesize
= st
.st_size
;
1076 time_changed
= g_strdup(_("unknown"));
1077 time_modified
= g_strdup(_("unknown"));
1078 time_accessed
= g_strdup(_("unknown"));
1079 filesize
= (off_t
) 0;
1082 g_free(locale_filename
);
1084 time_changed
= g_strdup(_("unknown"));
1085 time_modified
= g_strdup(_("unknown"));
1086 time_accessed
= g_strdup(_("unknown"));
1089 base_name
= g_path_get_basename(doc
->file_name
);
1090 short_name
= utils_str_middle_truncate(base_name
, 30);
1091 title
= g_strconcat(short_name
, " ", _("Properties"), NULL
);
1092 dialog
= gtk_dialog_new_with_buttons(title
, GTK_WINDOW(main_widgets
.window
),
1093 GTK_DIALOG_DESTROY_WITH_PARENT
,
1094 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
, NULL
);
1097 gtk_widget_set_name(dialog
, "GeanyDialog");
1098 vbox
= ui_dialog_vbox_new(GTK_DIALOG(dialog
));
1100 g_signal_connect(dialog
, "response", G_CALLBACK(gtk_widget_destroy
), NULL
);
1101 g_signal_connect(dialog
, "delete-event", G_CALLBACK(gtk_widget_destroy
), NULL
);
1103 gtk_window_set_default_size(GTK_WINDOW(dialog
), 300, -1);
1105 label
= ui_label_new_bold(base_name
);
1106 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1107 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
1108 image
= gtk_image_new_from_stock("gtk-file", GTK_ICON_SIZE_BUTTON
);
1109 gtk_misc_set_alignment(GTK_MISC(image
), 1.0, 0.5);
1110 hbox
= gtk_hbox_new(FALSE
, 6);
1111 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1112 gtk_container_add(GTK_CONTAINER(hbox
), image
);
1113 gtk_container_add(GTK_CONTAINER(hbox
), label
);
1114 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
1116 table
= gtk_table_new(8, 2, FALSE
);
1117 gtk_table_set_row_spacings(GTK_TABLE(table
), 10);
1118 gtk_table_set_col_spacings(GTK_TABLE(table
), 10);
1120 label
= gtk_label_new(_("<b>Type:</b>"));
1121 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 0, 1,
1122 (GtkAttachOptions
) (GTK_FILL
),
1123 (GtkAttachOptions
) (0), 0, 0);
1124 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1125 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1127 label
= gtk_label_new(doc
->file_type
->title
);
1128 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1129 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 0, 1,
1130 (GtkAttachOptions
) (GTK_FILL
),
1131 (GtkAttachOptions
) (0), 0, 0);
1132 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1134 label
= gtk_label_new(_("<b>Size:</b>"));
1135 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 1, 2,
1136 (GtkAttachOptions
) (GTK_FILL
),
1137 (GtkAttachOptions
) (0), 0, 0);
1138 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1139 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1141 file_size
= utils_make_human_readable_str(filesize
, 1, 0);
1142 label
= gtk_label_new(file_size
);
1143 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1144 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 1, 2,
1145 (GtkAttachOptions
) (GTK_FILL
),
1146 (GtkAttachOptions
) (0), 0, 0);
1148 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1150 label
= gtk_label_new(_("<b>Location:</b>"));
1151 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 2, 3,
1152 (GtkAttachOptions
) (GTK_FILL
),
1153 (GtkAttachOptions
) (0), 0, 0);
1154 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1155 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1157 label
= gtk_label_new(doc
->file_name
);
1158 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1159 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 2, 3,
1160 (GtkAttachOptions
) (GTK_FILL
),
1161 (GtkAttachOptions
) (0), 0, 0);
1162 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0);
1164 label
= gtk_label_new(_("<b>Read-only:</b>"));
1165 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 3, 4,
1166 (GtkAttachOptions
) (GTK_FILL
),
1167 (GtkAttachOptions
) (0), 0, 0);
1168 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1169 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1171 check
= gtk_check_button_new_with_label(_("(only inside Geany)"));
1172 gtk_widget_set_sensitive(check
, FALSE
);
1173 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1174 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), doc
->readonly
);
1175 gtk_table_attach(GTK_TABLE(table
), check
, 1, 2, 3, 4,
1176 (GtkAttachOptions
) (GTK_FILL
),
1177 (GtkAttachOptions
) (0), 0, 0);
1178 gtk_button_set_alignment(GTK_BUTTON(check
), 0.0, 0);
1180 label
= gtk_label_new(_("<b>Encoding:</b>"));
1181 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 4, 5,
1182 (GtkAttachOptions
) (GTK_FILL
),
1183 (GtkAttachOptions
) (0), 0, 0);
1184 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1185 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1187 enctext
= g_strdup_printf("%s %s",
1189 (encodings_is_unicode_charset(doc
->encoding
)) ?
1190 ((doc
->has_bom
) ? _("(with BOM)") : _("(without BOM)")) : "");
1192 label
= gtk_label_new(enctext
);
1193 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1196 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 4, 5,
1197 (GtkAttachOptions
) (GTK_FILL
),
1198 (GtkAttachOptions
) (0), 0, 0);
1199 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0);
1201 label
= gtk_label_new(_("<b>Modified:</b>"));
1202 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 5, 6,
1203 (GtkAttachOptions
) (GTK_FILL
),
1204 (GtkAttachOptions
) (0), 0, 0);
1205 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1206 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1208 label
= gtk_label_new(time_modified
);
1209 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1210 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 5, 6,
1211 (GtkAttachOptions
) (GTK_FILL
),
1212 (GtkAttachOptions
) (0), 0, 0);
1213 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1215 label
= gtk_label_new(_("<b>Changed:</b>"));
1216 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 6, 7,
1217 (GtkAttachOptions
) (GTK_FILL
),
1218 (GtkAttachOptions
) (0), 0, 0);
1219 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1220 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1222 label
= gtk_label_new(time_changed
);
1223 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1224 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 6, 7,
1225 (GtkAttachOptions
) (GTK_FILL
),
1226 (GtkAttachOptions
) (0), 0, 0);
1227 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1229 label
= gtk_label_new(_("<b>Accessed:</b>"));
1230 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 7, 8,
1231 (GtkAttachOptions
) (GTK_FILL
),
1232 (GtkAttachOptions
) (0), 0, 0);
1233 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1234 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0);
1236 label
= gtk_label_new(time_accessed
);
1237 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
1238 gtk_table_attach(GTK_TABLE(table
), label
, 1, 2, 7, 8,
1239 (GtkAttachOptions
) (GTK_FILL
),
1240 (GtkAttachOptions
) (0), 0, 0);
1241 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1244 gtk_container_add(GTK_CONTAINER(vbox
), table
);
1246 /* create table with the permissions */
1247 perm_table
= gtk_table_new(5, 4, TRUE
);
1248 gtk_table_set_row_spacings(GTK_TABLE(perm_table
), 5);
1249 gtk_table_set_col_spacings(GTK_TABLE(perm_table
), 5);
1251 label
= gtk_label_new(_("<b>Permissions:</b>"));
1252 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1253 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
1254 gtk_table_attach(GTK_TABLE(perm_table
), label
, 0, 4, 0, 1,
1255 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1256 (GtkAttachOptions
) (0), 0, 0);
1259 label
= gtk_label_new(_("Read:"));
1260 gtk_table_attach(GTK_TABLE(perm_table
), label
, 1, 2, 1, 2,
1261 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1262 (GtkAttachOptions
) (0), 0, 0);
1263 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1264 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0);
1266 label
= gtk_label_new(_("Write:"));
1267 gtk_table_attach(GTK_TABLE(perm_table
), label
, 2, 3, 1, 2,
1268 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1269 (GtkAttachOptions
) (0), 0, 0);
1270 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1271 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0);
1273 label
= gtk_label_new(_("Execute:"));
1274 gtk_table_attach(GTK_TABLE(perm_table
), label
, 3, 4, 1, 2,
1275 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1276 (GtkAttachOptions
) (0), 0, 0);
1277 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1278 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0);
1281 label
= gtk_label_new(_("Owner:"));
1282 gtk_table_attach(GTK_TABLE(perm_table
), label
, 0, 1, 2, 3,
1283 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1284 (GtkAttachOptions
) (0), 0, 0);
1285 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1286 gtk_misc_set_alignment(GTK_MISC(label
), 0.5, 0);
1288 check
= gtk_check_button_new();
1289 gtk_widget_set_sensitive(check
, FALSE
);
1290 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1291 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IRUSR
);
1292 gtk_table_attach(GTK_TABLE(perm_table
), check
, 1, 2, 2, 3,
1293 (GtkAttachOptions
) (GTK_EXPAND
| GTK_EXPAND
| GTK_FILL
),
1294 (GtkAttachOptions
) (0), 0, 0);
1295 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1297 check
= gtk_check_button_new();
1298 gtk_widget_set_sensitive(check
, FALSE
);
1299 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1300 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IWUSR
);
1301 gtk_table_attach(GTK_TABLE(perm_table
), check
, 2, 3, 2, 3,
1302 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1303 (GtkAttachOptions
) (0), 0, 0);
1304 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1306 check
= gtk_check_button_new();
1307 gtk_widget_set_sensitive(check
, FALSE
);
1308 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1309 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IXUSR
);
1310 gtk_table_attach(GTK_TABLE(perm_table
), check
, 3, 4, 2, 3,
1311 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1312 (GtkAttachOptions
) (0), 0, 0);
1313 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1317 label
= gtk_label_new(_("Group:"));
1318 gtk_table_attach(GTK_TABLE(perm_table
), label
, 0, 1, 3, 4,
1319 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1320 (GtkAttachOptions
) (0), 0, 0);
1321 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1322 gtk_misc_set_alignment(GTK_MISC(label
), 0.5, 0);
1324 check
= gtk_check_button_new();
1325 gtk_widget_set_sensitive(check
, FALSE
);
1326 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1327 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IRGRP
);
1328 gtk_table_attach(GTK_TABLE(perm_table
), check
, 1, 2, 3, 4,
1329 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1330 (GtkAttachOptions
) (0), 0, 0);
1331 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1333 check
= gtk_check_button_new();
1334 gtk_widget_set_sensitive(check
, FALSE
);
1335 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1336 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IWGRP
);
1337 gtk_table_attach(GTK_TABLE(perm_table
), check
, 2, 3, 3, 4,
1338 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1339 (GtkAttachOptions
) (0), 0, 0);
1340 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1342 check
= gtk_check_button_new();
1343 gtk_widget_set_sensitive(check
, FALSE
);
1344 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1345 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IXGRP
);
1346 gtk_table_attach(GTK_TABLE(perm_table
), check
, 3, 4, 3, 4,
1347 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1348 (GtkAttachOptions
) (0), 0, 0);
1349 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1353 label
= gtk_label_new(_("Other:"));
1354 gtk_table_attach(GTK_TABLE(perm_table
), label
, 0, 1, 4, 5,
1355 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1356 (GtkAttachOptions
) (0), 0, 0);
1357 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1358 gtk_misc_set_alignment(GTK_MISC(label
), 0.5, 0);
1360 check
= gtk_check_button_new();
1361 gtk_widget_set_sensitive(check
, FALSE
);
1362 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1363 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IROTH
);
1364 gtk_table_attach(GTK_TABLE(perm_table
), check
, 1, 2, 4, 5,
1365 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1366 (GtkAttachOptions
) (0), 0, 0);
1367 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1369 check
= gtk_check_button_new();
1370 gtk_widget_set_sensitive(check
, FALSE
);
1371 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1372 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IWOTH
);
1373 gtk_table_attach(GTK_TABLE(perm_table
), check
, 2, 3, 4, 5,
1374 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1375 (GtkAttachOptions
) (0), 0, 0);
1376 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1378 check
= gtk_check_button_new();
1379 gtk_widget_set_sensitive(check
, FALSE
);
1380 gtk_button_set_focus_on_click(GTK_BUTTON(check
), FALSE
);
1381 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), mode
& S_IXOTH
);
1382 gtk_table_attach(GTK_TABLE(perm_table
), check
, 3, 4, 4, 5,
1383 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1384 (GtkAttachOptions
) (0), 0, 0);
1385 gtk_button_set_alignment(GTK_BUTTON(check
), 0.5, 0);
1387 gtk_container_add(GTK_CONTAINER(vbox
), perm_table
);
1390 g_free(time_changed
);
1391 g_free(time_modified
);
1392 g_free(time_accessed
);
1394 gtk_widget_show_all(dialog
);
1398 /* extra_text can be NULL; otherwise it is displayed below main_text.
1399 * if parent is NULL, main_widgets.window will be used
1400 * btn_1, btn_2, btn_3 can be NULL.
1401 * returns response_1, response_2 or response_3 */
1402 static gint
show_prompt(GtkWidget
*parent
,
1403 const gchar
*btn_1
, GtkResponseType response_1
,
1404 const gchar
*btn_2
, GtkResponseType response_2
,
1405 const gchar
*btn_3
, GtkResponseType response_3
,
1406 const gchar
*question_text
, const gchar
*extra_text
)
1408 gboolean ret
= FALSE
;
1414 btn_2
= GTK_STOCK_NO
;
1415 response_2
= GTK_RESPONSE_NO
;
1419 btn_3
= GTK_STOCK_YES
;
1420 response_3
= GTK_RESPONSE_YES
;
1424 /* our native dialog code doesn't support custom buttons */
1425 if (btn_3
== GTK_STOCK_YES
&& btn_2
== GTK_STOCK_NO
&& btn_1
== NULL
)
1427 gchar
*string
= (extra_text
== NULL
) ? g_strdup(question_text
) :
1428 g_strconcat(question_text
, "\n\n", extra_text
, NULL
);
1430 ret
= win32_message_dialog(parent
, GTK_MESSAGE_QUESTION
, string
);
1431 ret
= ret
? response_3
: response_2
;
1436 if (parent
== NULL
&& main_status
.main_window_realized
)
1437 parent
= main_widgets
.window
;
1439 dialog
= gtk_message_dialog_new(GTK_WINDOW(parent
),
1440 GTK_DIALOG_DESTROY_WITH_PARENT
, GTK_MESSAGE_QUESTION
,
1441 GTK_BUTTONS_NONE
, "%s", question_text
);
1442 gtk_widget_set_name(dialog
, "GeanyDialog");
1443 gtk_window_set_title(GTK_WINDOW(dialog
), _("Question"));
1444 if (parent
== NULL
|| GTK_IS_DIALOG(parent
))
1446 GdkPixbuf
*pb
= ui_new_pixbuf_from_inline(GEANY_IMAGE_LOGO
);
1447 gtk_window_set_icon(GTK_WINDOW(dialog
), pb
);
1451 /* question_text will be in bold if optional extra_text used */
1452 if (extra_text
!= NULL
)
1453 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
),
1457 gtk_dialog_add_button(GTK_DIALOG(dialog
), btn_1
, response_1
);
1459 /* For a cancel button, use cancel response so user can press escape to cancel */
1460 btn
= gtk_dialog_add_button(GTK_DIALOG(dialog
), btn_2
,
1461 utils_str_equal(btn_2
, GTK_STOCK_CANCEL
) ? GTK_RESPONSE_CANCEL
: response_2
);
1462 /* we don't want a default, but we need to override the apply button as default */
1463 gtk_widget_grab_default(btn
);
1464 gtk_dialog_add_button(GTK_DIALOG(dialog
), btn_3
, response_3
);
1466 ret
= gtk_dialog_run(GTK_DIALOG(dialog
));
1467 gtk_widget_destroy(dialog
);
1469 if (ret
== GTK_RESPONSE_CANCEL
)
1476 * Shows a question message box with @a text and Yes/No buttons.
1477 * On Unix-like systems a GTK message dialog box is shown, on Win32 systems a native Windows
1478 * message dialog box is shown.
1480 * @param text Printf()-style format string.
1481 * @param ... Arguments for the @a text format string.
1483 * @return @c TRUE if the user answered with Yes, otherwise @c FALSE.
1485 gboolean
dialogs_show_question(const gchar
*text
, ...)
1489 GtkWidget
*parent
= (main_status
.main_window_realized
) ? main_widgets
.window
: NULL
;
1492 va_start(args
, text
);
1493 string
= g_strdup_vprintf(text
, args
);
1495 result
= show_prompt(parent
,
1496 NULL
, GTK_RESPONSE_NONE
,
1497 GTK_STOCK_NO
, GTK_RESPONSE_NO
,
1498 GTK_STOCK_YES
, GTK_RESPONSE_YES
,
1501 return (result
== GTK_RESPONSE_YES
);
1505 /* extra_text can be NULL; otherwise it is displayed below main_text.
1506 * if parent is NULL, main_widgets.window will be used
1507 * yes_btn, no_btn can be NULL. */
1508 gboolean
dialogs_show_question_full(GtkWidget
*parent
, const gchar
*yes_btn
, const gchar
*no_btn
,
1509 const gchar
*extra_text
, const gchar
*main_text
, ...)
1515 va_start(args
, main_text
);
1516 string
= g_strdup_vprintf(main_text
, args
);
1518 result
= show_prompt(parent
,
1519 NULL
, GTK_RESPONSE_NONE
,
1520 no_btn
, GTK_RESPONSE_NO
,
1521 yes_btn
, GTK_RESPONSE_YES
,
1522 string
, extra_text
);
1524 return (result
== GTK_RESPONSE_YES
);
1528 /* extra_text can be NULL; otherwise it is displayed below main_text.
1529 * if parent is NULL, main_widgets.window will be used
1530 * btn_1, btn_2, btn_3 can be NULL.
1531 * returns response_1, response_2 or response_3 */
1532 gint
dialogs_show_prompt(GtkWidget
*parent
,
1533 const gchar
*btn_1
, GtkResponseType response_1
,
1534 const gchar
*btn_2
, GtkResponseType response_2
,
1535 const gchar
*btn_3
, GtkResponseType response_3
,
1536 const gchar
*extra_text
, const gchar
*main_text
, ...)
1542 va_start(args
, main_text
);
1543 string
= g_strdup_vprintf(main_text
, args
);
1545 result
= show_prompt(parent
, btn_1
, response_1
, btn_2
, response_2
, btn_3
, response_3
,
1546 string
, extra_text
);