geany/src/dialogs.c
Enrico Tröger de3d3b42fb Add document_save_file_as and document_rename_file to the plugin API.
If GIO is available, use GFileMonitor to watch for file disk changes and indicate them immediately using an orange tab label colour.
Break plugin ABI for this and the last commits.

git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3484 ea778897-0a13-0410-b9d1-a72fbfd435f5
2009-01-18 18:19:58 +00:00

1415 lines
47 KiB
C

/*
* dialogs.c - this file is part of Geany, a fast and lightweight IDE
*
* Copyright 2005-2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* Copyright 2006-2009 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Id$
*/
/*
* File related dialogs, miscellaneous dialogs, font dialog.
*/
#include "geany.h"
#include <gdk/gdkkeysyms.h>
#include <string.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <time.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
/* gstdio.h also includes sys/stat.h */
#include <glib/gstdio.h>
#include "dialogs.h"
#include "callbacks.h"
#include "document.h"
#include "filetypes.h"
#include "win32.h"
#include "sciwrappers.h"
#include "support.h"
#include "utils.h"
#include "ui_utils.h"
#include "keybindings.h"
#include "encodings.h"
#include "build.h"
#include "main.h"
enum
{
GEANY_RESPONSE_RENAME,
GEANY_RESPONSE_VIEW
};
#if ! GEANY_USE_WIN32_DIALOG
static GtkWidget *add_file_open_extra_widget(void);
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void
on_file_open_dialog_response (GtkDialog *dialog,
gint response,
gpointer user_data)
{
gtk_widget_hide(ui_widgets.open_filesel);
if (response == GTK_RESPONSE_ACCEPT || response == GEANY_RESPONSE_VIEW)
{
GSList *filelist;
gint filetype_idx = gtk_combo_box_get_active(GTK_COMBO_BOX(
ui_lookup_widget(GTK_WIDGET(dialog), "filetype_combo")));
gint encoding_idx = gtk_combo_box_get_active(GTK_COMBO_BOX(
ui_lookup_widget(GTK_WIDGET(dialog), "encoding_combo")));
GeanyFiletype *ft = NULL;
gchar *charset = NULL;
gboolean ro = (response == GEANY_RESPONSE_VIEW); /* View clicked */
/* ignore detect from file item */
if (filetype_idx >= 0 && filetype_idx < GEANY_FILETYPES_NONE)
ft = filetypes[filetype_idx];
if (encoding_idx >= 0 && encoding_idx < GEANY_ENCODINGS_MAX)
charset = encodings[encoding_idx].charset;
filelist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(ui_widgets.open_filesel));
if (filelist != NULL)
{
document_open_files(filelist, ro, ft, charset);
g_slist_foreach(filelist, (GFunc) g_free, NULL); /* free filenames */
}
g_slist_free(filelist);
}
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
/* callback for the text entry for typing in filename */
static void
on_file_open_entry_activate (GtkEntry *entry,
gpointer user_data)
{
gchar *locale_filename = utils_get_locale_from_utf8(gtk_entry_get_text(entry));
if (g_file_test(locale_filename, G_FILE_TEST_IS_DIR))
{
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ui_widgets.open_filesel), locale_filename);
}
else if (g_file_test(locale_filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
{
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ui_widgets.open_filesel), locale_filename);
on_file_open_dialog_response(GTK_DIALOG(ui_widgets.open_filesel), GTK_RESPONSE_ACCEPT, NULL);
}
g_free(locale_filename);
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void
on_file_open_selection_changed (GtkFileChooser *filechooser,
gpointer user_data)
{
gchar *filename = gtk_file_chooser_get_filename(filechooser);
gboolean is_on = gtk_file_chooser_get_show_hidden(filechooser);
if (filename)
{
/* try to get the UTF-8 equivalent for the filename, fallback to filename if error */
gchar *utf8_filename = utils_get_utf8_from_locale(filename);
gtk_entry_set_text(GTK_ENTRY(ui_lookup_widget(
GTK_WIDGET(filechooser), "file_entry")), utf8_filename);
g_free(utf8_filename);
g_free(filename);
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
ui_lookup_widget(GTK_WIDGET(filechooser), "check_hidden")), is_on);
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void
on_file_open_check_hidden_toggled (GtkToggleButton *togglebutton,
gpointer user_data)
{
gboolean is_on = gtk_toggle_button_get_active(togglebutton);
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(ui_widgets.open_filesel), is_on);
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void create_open_file_dialog(void)
{
GtkWidget *filetype_combo, *encoding_combo;
GtkWidget *viewbtn;
guint i;
gchar *encoding_string;
ui_widgets.open_filesel = gtk_file_chooser_dialog_new(_("Open File"), GTK_WINDOW(main_widgets.window),
GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
gtk_widget_set_name(ui_widgets.open_filesel, "GeanyDialog");
viewbtn = gtk_dialog_add_button(GTK_DIALOG(ui_widgets.open_filesel), _("_View"),
GEANY_RESPONSE_VIEW);
ui_widget_set_tooltip_text(viewbtn,
_("Opens the file in read-only mode. If you choose more than one file to open, all files will be opened read-only."));
gtk_dialog_add_buttons(GTK_DIALOG(ui_widgets.open_filesel),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
gtk_dialog_set_default_response(GTK_DIALOG(ui_widgets.open_filesel), GTK_RESPONSE_ACCEPT);
gtk_widget_set_size_request(ui_widgets.open_filesel, -1, 460);
gtk_window_set_modal(GTK_WINDOW(ui_widgets.open_filesel), TRUE);
gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets.open_filesel), TRUE);
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets.open_filesel), FALSE);
gtk_window_set_type_hint(GTK_WINDOW(ui_widgets.open_filesel), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_transient_for(GTK_WINDOW(ui_widgets.open_filesel), GTK_WINDOW(main_widgets.window));
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(ui_widgets.open_filesel), TRUE);
#if GTK_CHECK_VERSION(2, 14, 0)
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(ui_widgets.open_filesel), FALSE);
#endif
/* add checkboxes and filename entry */
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ui_widgets.open_filesel),
add_file_open_extra_widget());
filetype_combo = ui_lookup_widget(ui_widgets.open_filesel, "filetype_combo");
/* add FileFilters(start with "All Files") */
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets.open_filesel),
filetypes_create_file_filter(filetypes[GEANY_FILETYPES_NONE]));
/* now create meta filter "All Source" */
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets.open_filesel),
filetypes_create_file_filter_all_source());
for (i = 0; i < filetypes_array->len; i++)
{
if (i == GEANY_FILETYPES_NONE)
continue;
gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo), filetypes[i]->title);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(ui_widgets.open_filesel),
filetypes_create_file_filter(filetypes[i]));
}
gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo), _("Detect by file extension"));
gtk_combo_box_set_active(GTK_COMBO_BOX(filetype_combo), filetypes_array->len - 1);
/* fill encoding combo box */
encoding_combo = ui_lookup_widget(ui_widgets.open_filesel, "encoding_combo");
for (i = 0; i < GEANY_ENCODINGS_MAX; i++)
{
encoding_string = encodings_to_string(&encodings[i]);
gtk_combo_box_append_text(GTK_COMBO_BOX(encoding_combo), encoding_string);
g_free(encoding_string);
}
gtk_combo_box_append_text(GTK_COMBO_BOX(encoding_combo), _("Detect from file"));
gtk_combo_box_set_active(GTK_COMBO_BOX(encoding_combo), GEANY_ENCODINGS_MAX);
g_signal_connect(ui_widgets.open_filesel, "selection-changed",
G_CALLBACK(on_file_open_selection_changed), NULL);
g_signal_connect(ui_widgets.open_filesel, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(ui_widgets.open_filesel, "response",
G_CALLBACK(on_file_open_dialog_response), NULL);
}
#endif
/* This shows the file selection dialog to open a file. */
void dialogs_show_open_file()
{
gchar *initdir;
/* set dialog directory to the current file's directory, if present */
initdir = utils_get_current_file_dir_utf8();
/* use project or default startup directory (if set) if no files are open */
/** TODO should it only be used when initally open the dialog and not on every show? */
if (! initdir)
initdir = g_strdup(utils_get_default_dir_utf8());
setptr(initdir, utils_get_locale_from_utf8(initdir));
#if GEANY_USE_WIN32_DIALOG
win32_show_file_dialog(TRUE, initdir);
#else /* X11, not win32: use GTK_FILE_CHOOSER */
/* We use the same file selection widget each time, so first of all we create it
* if it hasn't already been created. */
if (ui_widgets.open_filesel == NULL)
create_open_file_dialog();
if (initdir != NULL)
{
if (g_path_is_absolute(initdir))
gtk_file_chooser_set_current_folder(
GTK_FILE_CHOOSER(ui_widgets.open_filesel), initdir);
}
gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(ui_widgets.open_filesel));
gtk_window_present(GTK_WINDOW(ui_widgets.open_filesel));
#endif
g_free(initdir);
}
#if ! GEANY_USE_WIN32_DIALOG
static GtkWidget *add_file_open_extra_widget()
{
GtkWidget *vbox, *table, *file_entry, *check_hidden;
GtkWidget *filetype_ebox, *filetype_label, *filetype_combo;
GtkWidget *encoding_ebox, *encoding_label, *encoding_combo;
vbox = gtk_vbox_new(FALSE, 6);
table = gtk_table_new(2, 4, FALSE);
/* line 1 with checkbox and encoding combo */
check_hidden = gtk_check_button_new_with_mnemonic(_("Show _hidden files"));
gtk_widget_show(check_hidden);
gtk_table_attach(GTK_TABLE(table), check_hidden, 0, 1, 0, 1,
(GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
(GtkAttachOptions) (0), 0, 5);
/* spacing */
gtk_table_attach(GTK_TABLE(table), gtk_label_new(""), 1, 2, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 5, 5);
encoding_label = gtk_label_new(_("Set encoding:"));
gtk_misc_set_alignment(GTK_MISC(encoding_label), 1, 0);
gtk_table_attach(GTK_TABLE(table), encoding_label, 2, 3, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 4, 5);
/* the ebox is for the tooltip, because gtk_combo_box can't show tooltips */
encoding_ebox = gtk_event_box_new();
encoding_combo = gtk_combo_box_new_text();
gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(encoding_combo), 3);
ui_widget_set_tooltip_text(encoding_ebox,
_("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."));
gtk_container_add(GTK_CONTAINER(encoding_ebox), encoding_combo);
gtk_table_attach(GTK_TABLE(table), encoding_ebox, 3, 4, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 5);
/* line 2 with filename entry and filetype combo */
file_entry = gtk_entry_new();
gtk_widget_show(file_entry);
/*gtk_editable_set_editable(GTK_EDITABLE(file_entry), FALSE);*/
gtk_entry_set_activates_default(GTK_ENTRY(file_entry), TRUE);
gtk_table_attach(GTK_TABLE(table), file_entry, 0, 1, 1, 2,
(GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
(GtkAttachOptions) (0), 0, 5);
/* spacing */
gtk_table_attach(GTK_TABLE(table), gtk_label_new(""), 1, 2, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 5, 5);
filetype_label = gtk_label_new(_("Set filetype:"));
gtk_misc_set_alignment(GTK_MISC(filetype_label), 1, 0);
gtk_table_attach(GTK_TABLE(table), filetype_label, 2, 3, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 4, 5);
/* the ebox is for the tooltip, because gtk_combo_box can't show tooltips */
filetype_ebox = gtk_event_box_new();
filetype_combo = gtk_combo_box_new_text();
gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(filetype_combo), 2);
ui_widget_set_tooltip_text(filetype_ebox,
_("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."));
gtk_container_add(GTK_CONTAINER(filetype_ebox), filetype_combo);
gtk_table_attach(GTK_TABLE(table), filetype_ebox, 3, 4, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 5);
gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
gtk_widget_show_all(vbox);
g_signal_connect(file_entry, "activate",
G_CALLBACK(on_file_open_entry_activate), NULL);
g_signal_connect(check_hidden, "toggled",
G_CALLBACK(on_file_open_check_hidden_toggled), NULL);
g_object_set_data_full(G_OBJECT(ui_widgets.open_filesel), "file_entry",
g_object_ref(file_entry), (GDestroyNotify)g_object_unref);
g_object_set_data_full(G_OBJECT(ui_widgets.open_filesel), "check_hidden",
g_object_ref(check_hidden), (GDestroyNotify)g_object_unref);
g_object_set_data_full(G_OBJECT(ui_widgets.open_filesel), "filetype_combo",
g_object_ref(filetype_combo), (GDestroyNotify)g_object_unref);
g_object_set_data_full(G_OBJECT(ui_widgets.open_filesel), "encoding_combo",
g_object_ref(encoding_combo), (GDestroyNotify)g_object_unref);
return vbox;
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void on_save_as_new_tab_toggled(GtkToggleButton *togglebutton, gpointer user_data)
{
gtk_widget_set_sensitive(GTK_WIDGET(user_data),
! gtk_toggle_button_get_active(togglebutton));
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void handle_save_as(const gchar *utf8_filename, gboolean open_new_tab, gboolean rename_file)
{
GeanyDocument *doc = document_get_current();
g_return_if_fail(NZV(utf8_filename));
if (open_new_tab)
{ /* "open" the saved file in a new tab and switch to it */
doc = document_clone(doc, utf8_filename);
document_save_file_as(doc, NULL);
}
else
{
if (doc->file_name != NULL)
{
if (rename_file)
{
document_rename_file(doc, utf8_filename);
}
/* create a new tm_source_file object otherwise tagmanager won't work correctly */
tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
doc->tm_file = NULL;
}
document_save_file_as(doc, utf8_filename);
build_menu_update(doc);
}
}
static void
on_file_save_dialog_response (GtkDialog *dialog,
gint response,
gpointer user_data)
{
gboolean rename_file = FALSE;
switch (response)
{
case GEANY_RESPONSE_RENAME:
rename_file = TRUE;
/* fall through */
case GTK_RESPONSE_ACCEPT:
{
gchar *new_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ui_widgets.save_filesel));
gboolean open_new_tab = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(ui_lookup_widget(ui_widgets.save_filesel, "check_open_new_tab")));
gchar *utf8_filename;
if (! NZV(new_filename)) /* rename doesn't check for empty filename */
{
utils_beep();
g_free(new_filename);
return;
}
utf8_filename = utils_get_utf8_from_locale(new_filename);
/* check if file exists and ask whether to overwrite or not */
if (g_file_test(new_filename, G_FILE_TEST_EXISTS))
{
if (dialogs_show_question(
_("The file '%s' already exists. Do you want to overwrite it?"),
utf8_filename) == FALSE)
{
g_free(utf8_filename);
g_free(new_filename);
return;
}
}
handle_save_as(utf8_filename, open_new_tab, rename_file);
g_free(utf8_filename);
g_free(new_filename);
}
}
gtk_widget_hide(ui_widgets.save_filesel);
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static void create_save_file_dialog(void)
{
GtkWidget *vbox, *check_open_new_tab, *rename_btn;
ui_widgets.save_filesel = gtk_file_chooser_dialog_new(_("Save File"), GTK_WINDOW(main_widgets.window),
GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
gtk_window_set_modal(GTK_WINDOW(ui_widgets.save_filesel), TRUE);
gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets.save_filesel), TRUE);
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets.save_filesel), FALSE);
gtk_window_set_type_hint(GTK_WINDOW(ui_widgets.save_filesel), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_widget_set_name(ui_widgets.save_filesel, "GeanyDialog");
rename_btn = gtk_dialog_add_button(GTK_DIALOG(ui_widgets.save_filesel), _("R_ename"),
GEANY_RESPONSE_RENAME);
ui_widget_set_tooltip_text(rename_btn, _("Save the file and rename it"));
gtk_dialog_add_buttons(GTK_DIALOG(ui_widgets.save_filesel),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
gtk_dialog_set_default_response(GTK_DIALOG(ui_widgets.save_filesel), GTK_RESPONSE_ACCEPT);
vbox = gtk_vbox_new(FALSE, 0);
check_open_new_tab = gtk_check_button_new_with_mnemonic(_("_Open file in a new tab"));
ui_widget_set_tooltip_text(check_open_new_tab,
_("Keep the current unsaved document open"
" and open the newly saved file in a new tab"));
gtk_box_pack_start(GTK_BOX(vbox), check_open_new_tab, FALSE, FALSE, 0);
gtk_widget_show_all(vbox);
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ui_widgets.save_filesel), vbox);
#if GTK_CHECK_VERSION(2, 14, 0)
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(ui_widgets.save_filesel), FALSE);
#endif
g_signal_connect(check_open_new_tab, "toggled",
G_CALLBACK(on_save_as_new_tab_toggled), rename_btn);
g_object_set_data_full(G_OBJECT(ui_widgets.save_filesel), "check_open_new_tab",
g_object_ref(check_open_new_tab), (GDestroyNotify)g_object_unref);
g_signal_connect(ui_widgets.save_filesel, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(ui_widgets.save_filesel, "response",
G_CALLBACK(on_file_save_dialog_response), NULL);
gtk_window_set_transient_for(GTK_WINDOW(ui_widgets.save_filesel), GTK_WINDOW(main_widgets.window));
}
#endif
#if ! GEANY_USE_WIN32_DIALOG
static gboolean gtk_show_save_as(const gchar *initdir)
{
GeanyDocument *doc = document_get_current();
gint resp;
gboolean folder_set = FALSE;
if (ui_widgets.save_filesel == NULL)
create_save_file_dialog();
gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(ui_widgets.save_filesel));
if (doc->file_name != NULL)
{
if (g_path_is_absolute(doc->file_name))
{
gchar *locale_filename = utils_get_locale_from_utf8(doc->file_name);
gchar *locale_basename = g_path_get_basename(locale_filename);
gchar *locale_dirname = g_path_get_dirname(locale_filename);
folder_set = TRUE;
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ui_widgets.save_filesel),
locale_dirname);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets.save_filesel),
locale_basename);
g_free(locale_filename);
g_free(locale_basename);
g_free(locale_dirname);
}
else
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets.save_filesel),
doc->file_name);
}
else
{
gchar *fname = NULL;
if (doc->file_type != NULL && doc->file_type->id != GEANY_FILETYPES_NONE &&
doc->file_type->extension != NULL)
fname = g_strconcat(GEANY_STRING_UNTITLED, ".",
doc->file_type->extension, NULL);
else
fname = g_strdup(GEANY_STRING_UNTITLED);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ui_widgets.save_filesel), fname);
g_free(fname);
}
/* if the folder wasn't set so far, we set it to the given directory */
if (! folder_set && initdir != NULL && g_path_is_absolute(initdir))
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ui_widgets.save_filesel), initdir);
/* Run the dialog synchronously, pausing this function call */
resp = gtk_dialog_run(GTK_DIALOG(ui_widgets.save_filesel));
return (resp == GTK_RESPONSE_ACCEPT);
}
#endif
/**
* Show the Save As dialog for the current notebook page.
*
* @return @a TRUE if the file was saved, otherwise @a FALSE.
**/
gboolean dialogs_show_save_as()
{
gboolean result;
gchar *initdir = NULL;
initdir = utils_get_current_file_dir_utf8();
/* use project or default startup directory (if set) if no files are open */
/** TODO should it only be used when initally open the dialog and not on every show? */
if (! initdir)
initdir = g_strdup(utils_get_default_dir_utf8());
setptr(initdir, utils_get_locale_from_utf8(initdir));
#if GEANY_USE_WIN32_DIALOG
result = win32_show_file_dialog(FALSE, initdir);
#else
result = gtk_show_save_as(initdir);
#endif
g_free(initdir);
return result;
}
/**
* Show a message box of the type @c type with @c text.
* On Unix-like systems a GTK message dialog box is shown, on Win32 systems a native Windows
* message dialog box is shown.
*
* @param type A GtkMessageType, can be one of: GTK_MESSAGE_INFO, GTK_MESSAGE_WARNING,
* GTK_MESSAGE_QUESTION, GTK_MESSAGE_ERROR
* @param text Printf()-style format string.
* @param ... Arguments for the @c text format string.
**/
void dialogs_show_msgbox(gint type, const gchar *text, ...)
{
#ifndef G_OS_WIN32
GtkWidget *dialog;
#endif
gchar string[512];
va_list args;
va_start(args, text);
g_vsnprintf(string, 511, text, args);
va_end(args);
#ifdef G_OS_WIN32
win32_message_dialog(NULL, type, string);
#else
dialog = gtk_message_dialog_new(GTK_WINDOW(main_widgets.window), GTK_DIALOG_DESTROY_WITH_PARENT,
type, GTK_BUTTONS_OK, "%s", string);
gtk_widget_set_name(dialog, "GeanyDialog");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
#endif
}
void dialogs_show_msgbox_with_secondary(gint type, const gchar *text, const gchar *secondary)
{
#ifdef G_OS_WIN32
/* put the two strings together because Windows message boxes don't support secondary texts */
gchar *string = g_strconcat(text, "\n", secondary, NULL);
win32_message_dialog(NULL, type, string);
g_free(string);
#else
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(main_widgets.window), GTK_DIALOG_DESTROY_WITH_PARENT,
type, GTK_BUTTONS_OK, "%s", text);
gtk_widget_set_name(dialog, "GeanyDialog");
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", secondary);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
#endif
}
#ifndef G_OS_WIN32
static gint run_unsaved_dialog(const gchar *msg, const gchar *msg2)
{
GtkWidget *dialog, *button;
gint ret;
dialog = gtk_message_dialog_new(GTK_WINDOW(main_widgets.window), GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", msg);
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", msg2);
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
button = ui_button_new_with_image(GTK_STOCK_CLEAR, _("_Don't save"));
gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_NO);
gtk_widget_show(button);
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_YES);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
ret = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return ret;
}
#endif
gboolean dialogs_show_unsaved_file(GeanyDocument *doc)
{
gchar *msg, *short_fn = NULL;
const gchar *msg2;
gint ret;
gboolean old_quitting_state = main_status.quitting;
/* display the file tab to remind the user of the document */
main_status.quitting = FALSE;
gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook),
document_get_notebook_page(doc));
main_status.quitting = old_quitting_state;
if (doc->file_name != NULL)
{
short_fn = g_path_get_basename(doc->file_name);
}
msg = g_strdup_printf(_("The file '%s' is not saved."),
(short_fn != NULL) ? short_fn : GEANY_STRING_UNTITLED);
msg2 = _("Do you want to save it before closing?");
g_free(short_fn);
#ifdef G_OS_WIN32
setptr(msg, g_strconcat(msg, "\n", msg2, NULL));
ret = win32_message_dialog_unsaved(msg);
#else
ret = run_unsaved_dialog(msg, msg2);
#endif
g_free(msg);
switch(ret)
{
case GTK_RESPONSE_YES:
{
if (doc->file_name == NULL)
{
ret = dialogs_show_save_as();
}
else
/* document_save_file() returns the status if the file could be saved */
ret = document_save_file(doc, FALSE);
break;
}
case GTK_RESPONSE_NO: ret = TRUE; break;
case GTK_RESPONSE_CANCEL: /* fall through to default and leave the function */
default: ret = FALSE; break;
}
return (gboolean) ret;
}
#ifndef G_OS_WIN32
static void
on_font_apply_button_clicked (GtkButton *button,
gpointer user_data)
{
gchar *fontname;
fontname = gtk_font_selection_dialog_get_font_name(
GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel));
ui_set_editor_font(fontname);
g_free(fontname);
}
static void
on_font_ok_button_clicked (GtkButton *button,
gpointer user_data)
{
/* We do the same thing as apply, but we close the dialog after. */
on_font_apply_button_clicked(button, NULL);
gtk_widget_hide(ui_widgets.open_fontsel);
}
static void
on_font_cancel_button_clicked (GtkButton *button,
gpointer user_data)
{
gtk_widget_hide(ui_widgets.open_fontsel);
}
#endif
/* This shows the font selection dialog to choose a font. */
void dialogs_show_open_font()
{
#ifdef G_OS_WIN32
win32_show_font_dialog();
#else
if (ui_widgets.open_fontsel == NULL)
{
ui_widgets.open_fontsel = gtk_font_selection_dialog_new(_("Choose font"));;
gtk_container_set_border_width(GTK_CONTAINER(ui_widgets.open_fontsel), 4);
gtk_window_set_modal(GTK_WINDOW(ui_widgets.open_fontsel), TRUE);
gtk_window_set_destroy_with_parent(GTK_WINDOW(ui_widgets.open_fontsel), TRUE);
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ui_widgets.open_fontsel), TRUE);
gtk_window_set_type_hint(GTK_WINDOW(ui_widgets.open_fontsel), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_widget_set_name(ui_widgets.open_fontsel, "GeanyDialog");
gtk_widget_show(GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel)->apply_button);
g_signal_connect(ui_widgets.open_fontsel,
"delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel)->ok_button,
"clicked", G_CALLBACK(on_font_ok_button_clicked), NULL);
g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel)->cancel_button,
"clicked", G_CALLBACK(on_font_cancel_button_clicked), NULL);
g_signal_connect(GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel)->apply_button,
"clicked", G_CALLBACK(on_font_apply_button_clicked), NULL);
gtk_font_selection_dialog_set_font_name(
GTK_FONT_SELECTION_DIALOG(ui_widgets.open_fontsel), interface_prefs.editor_font);
gtk_window_set_transient_for(GTK_WINDOW(ui_widgets.open_fontsel), GTK_WINDOW(main_widgets.window));
}
/* We make sure the dialog is visible. */
gtk_window_present(GTK_WINDOW(ui_widgets.open_fontsel));
#endif
}
static void
on_input_dialog_show(GtkDialog *dialog, GtkWidget *entry)
{
gtk_widget_grab_focus(entry);
}
static void
on_input_entry_activate(GtkEntry *entry, GtkDialog *dialog)
{
gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT);
}
static void
on_input_numeric_activate(GtkEntry *entry, GtkDialog *dialog)
{
gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT);
}
static void
on_input_dialog_response(GtkDialog *dialog,
gint response,
GtkWidget *entry)
{
gboolean persistent = (gboolean) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog), "has_combo"));
if (response == GTK_RESPONSE_ACCEPT)
{
const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry));
InputCallback input_cb =
(InputCallback) g_object_get_data(G_OBJECT(dialog), "input_cb");
if (persistent)
{
GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(dialog), "combo");
ui_combo_box_add_to_history(GTK_COMBO_BOX(combo), str);
}
input_cb(str);
}
if (persistent)
gtk_widget_hide(GTK_WIDGET(dialog));
else
gtk_widget_destroy(GTK_WIDGET(dialog));
}
static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox,
const gchar *label_text, const gchar *default_text, gboolean persistent)
{
GtkWidget *label, *entry;
label = gtk_label_new(label_text);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_container_add(GTK_CONTAINER(vbox), label);
if (persistent) /* remember previous entry text in a combo box */
{
GtkWidget *combo = gtk_combo_box_entry_new_text();
entry = GTK_BIN(combo)->child;
g_object_set_data(G_OBJECT(dialog), "combo", combo);
gtk_container_add(GTK_CONTAINER(vbox), combo);
}
else
{
entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(vbox), entry);
}
if (default_text != NULL)
{
gtk_entry_set_text(GTK_ENTRY(entry), default_text);
}
gtk_entry_set_max_length(GTK_ENTRY(entry), 255);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 30);
g_signal_connect(entry, "activate", G_CALLBACK(on_input_entry_activate), dialog);
g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), entry);
g_signal_connect(dialog, "response", G_CALLBACK(on_input_dialog_response), entry);
}
/* Create and display an input dialog.
* persistent: whether to remember previous entry text in a combo box;
* in this case the dialog returned is not destroyed on a response,
* and can be reshown.
* Returns: the dialog widget. */
GtkWidget *
dialogs_show_input(const gchar *title, const gchar *label_text, const gchar *default_text,
gboolean persistent, InputCallback input_cb)
{
GtkWidget *dialog, *vbox;
dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(main_widgets.window),
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
gtk_widget_set_name(dialog, "GeanyDialog");
gtk_box_set_spacing(GTK_BOX(vbox), 6);
g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent));
g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb);
add_input_widgets(dialog, vbox, label_text, default_text, persistent);
if (persistent)
g_signal_connect(dialog, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
else
g_signal_connect(dialog, "delete-event", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_widget_show_all(dialog);
return dialog;
}
gboolean dialogs_show_input_numeric(const gchar *title, const gchar *label_text,
gdouble *value, gdouble min, gdouble max, gdouble step)
{
GtkWidget *dialog, *label, *spin, *vbox;
gboolean res = FALSE;
dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(main_widgets.window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
gtk_widget_set_name(dialog, "GeanyDialog");
label = gtk_label_new(label_text);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
spin = gtk_spin_button_new_with_range(min, max, step);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), *value);
g_signal_connect(spin, "activate", G_CALLBACK(on_input_numeric_activate), dialog);
gtk_container_add(GTK_CONTAINER(vbox), label);
gtk_container_add(GTK_CONTAINER(vbox), spin);
gtk_widget_show_all(vbox);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
*value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
res = TRUE;
}
gtk_widget_destroy(dialog);
return res;
}
void dialogs_show_file_properties(GeanyDocument *doc)
{
GtkWidget *dialog, *label, *table, *hbox, *image, *perm_table, *check, *vbox;
gchar *file_size, *title, *base_name, *time_changed, *time_modified, *time_accessed, *enctext;
#ifdef HAVE_SYS_TYPES_H
struct stat st;
off_t filesize;
mode_t mode;
gchar *locale_filename;
#else
gint filesize = 0;
gint mode = 0;
#endif
/* define this ones, to avoid later trouble */
#ifndef S_IRUSR
# define S_IRUSR 0
# define S_IWUSR 0
# define S_IXUSR 0
#endif
#ifndef S_IRGRP
# define S_IRGRP 0
# define S_IWGRP 0
# define S_IXGRP 0
# define S_IROTH 0
# define S_IWOTH 0
# define S_IXOTH 0
#endif
if (doc == NULL || doc->file_name == NULL)
{
dialogs_show_msgbox(GTK_MESSAGE_ERROR,
_("An error occurred or file information could not be retrieved (e.g. from a new file)."));
return;
}
#ifdef HAVE_SYS_TYPES_H
locale_filename = utils_get_locale_from_utf8(doc->file_name);
if (g_stat(locale_filename, &st) == 0)
{
/* first copy the returned string and the trim it, to not modify the static glibc string
* g_strchomp() is used to remove trailing EOL chars, which are there for whatever reason */
time_changed = g_strchomp(g_strdup(ctime(&st.st_ctime)));
time_modified = g_strchomp(g_strdup(ctime(&st.st_mtime)));
time_accessed = g_strchomp(g_strdup(ctime(&st.st_atime)));
filesize = st.st_size;
mode = st.st_mode;
}
else
{
time_changed = g_strdup(_("unknown"));
time_modified = g_strdup(_("unknown"));
time_accessed = g_strdup(_("unknown"));
filesize = (off_t) 0;
mode = (mode_t) 0;
}
g_free(locale_filename);
#else
time_changed = g_strdup(_("unknown"));
time_modified = g_strdup(_("unknown"));
time_accessed = g_strdup(_("unknown"));
#endif
base_name = g_path_get_basename(doc->file_name);
title = g_strconcat(base_name, " ", _("Properties"), NULL);
dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(main_widgets.window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, NULL);
g_free(title);
gtk_widget_set_name(dialog, "GeanyDialog");
vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
g_signal_connect(dialog, "delete-event", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
title = g_strdup_printf("<b>%s</b>", base_name);
label = gtk_label_new(title);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
image = gtk_image_new_from_stock("gtk-file", GTK_ICON_SIZE_BUTTON);
gtk_misc_set_alignment(GTK_MISC(image), 1.0, 0.5);
hbox = gtk_hbox_new(FALSE, 6);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_container_add(GTK_CONTAINER(hbox), image);
gtk_container_add(GTK_CONTAINER(hbox), label);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
g_free(title);
table = gtk_table_new(8, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
label = gtk_label_new(_("<b>Type:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
label = gtk_label_new(doc->file_type->title);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
label = gtk_label_new(_("<b>Size:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
file_size = utils_make_human_readable_str(filesize, 1, 0);
label = gtk_label_new(file_size);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
g_free(file_size);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
label = gtk_label_new(_("<b>Location:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
label = gtk_label_new(doc->file_name);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 2, 3,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0);
label = gtk_label_new(_("<b>Read-only:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
check = gtk_check_button_new_with_label(_("(only inside Geany)"));
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), doc->readonly);
gtk_table_attach(GTK_TABLE(table), check, 1, 2, 3, 4,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.0, 0);
label = gtk_label_new(_("<b>Encoding:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
enctext = g_strdup_printf("%s %s",
doc->encoding,
(encodings_is_unicode_charset(doc->encoding)) ?
((doc->has_bom) ? _("(with BOM)") : _("(without BOM)")) : "");
label = gtk_label_new(enctext);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
g_free(enctext);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 4, 5,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0);
label = gtk_label_new(_("<b>Modified:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
label = gtk_label_new(time_modified);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 5, 6,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
label = gtk_label_new(_("<b>Changed:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 6, 7,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
label = gtk_label_new(time_changed);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 6, 7,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
label = gtk_label_new(_("<b>Accessed:</b>"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 7, 8,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0);
label = gtk_label_new(time_accessed);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 7, 8,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
/* add table */
gtk_container_add(GTK_CONTAINER(vbox), table);
/* create table with the permissions */
perm_table = gtk_table_new(5, 4, TRUE);
gtk_table_set_row_spacings(GTK_TABLE(perm_table), 5);
gtk_table_set_col_spacings(GTK_TABLE(perm_table), 5);
label = gtk_label_new(_("<b>Permissions:</b>"));
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_table_attach(GTK_TABLE(perm_table), label, 0, 4, 0, 1,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
/* Header */
label = gtk_label_new(_("Read:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 1, 2, 1, 2,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0);
label = gtk_label_new(_("Write:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 2, 3, 1, 2,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0);
label = gtk_label_new(_("Execute:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 3, 4, 1, 2,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0);
/* Owner */
label = gtk_label_new(_("Owner:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 0, 1, 2, 3,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IRUSR);
gtk_table_attach(GTK_TABLE(perm_table), check, 1, 2, 2, 3,
(GtkAttachOptions) (GTK_EXPAND | GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IWUSR);
gtk_table_attach(GTK_TABLE(perm_table), check, 2, 3, 2, 3,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IXUSR);
gtk_table_attach(GTK_TABLE(perm_table), check, 3, 4, 2, 3,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
/* Group */
label = gtk_label_new(_("Group:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 0, 1, 3, 4,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IRGRP);
gtk_table_attach(GTK_TABLE(perm_table), check, 1, 2, 3, 4,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IWGRP);
gtk_table_attach(GTK_TABLE(perm_table), check, 2, 3, 3, 4,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IXGRP);
gtk_table_attach(GTK_TABLE(perm_table), check, 3, 4, 3, 4,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
/* Other */
label = gtk_label_new(_("Other:"));
gtk_table_attach(GTK_TABLE(perm_table), label, 0, 1, 4, 5,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IROTH);
gtk_table_attach(GTK_TABLE(perm_table), check, 1, 2, 4, 5,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IWOTH);
gtk_table_attach(GTK_TABLE(perm_table), check, 2, 3, 4, 5,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
check = gtk_check_button_new();
gtk_widget_set_sensitive(check, FALSE);
gtk_button_set_focus_on_click(GTK_BUTTON(check), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), mode & S_IXOTH);
gtk_table_attach(GTK_TABLE(perm_table), check, 3, 4, 4, 5,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_button_set_alignment(GTK_BUTTON(check), 0.5, 0);
gtk_container_add(GTK_CONTAINER(vbox), perm_table);
g_free(base_name);
g_free(time_changed);
g_free(time_modified);
g_free(time_accessed);
gtk_widget_show_all(dialog);
}
static gboolean show_question(GtkWidget *parent, const gchar *yes_btn, const gchar *no_btn,
const gchar *question_text, const gchar *extra_text)
{
gboolean ret = FALSE;
#ifdef G_OS_WIN32
gchar *string = (extra_text == NULL) ? g_strdup(question_text) :
g_strconcat(question_text, "\n\n", extra_text, NULL);
ret = win32_message_dialog(parent, GTK_MESSAGE_QUESTION, string);
g_free(string);
#else
GtkWidget *dialog;
if (parent == NULL)
parent = main_widgets.window;
dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE, "%s", question_text);
gtk_widget_set_name(dialog, "GeanyDialog");
/* question_text will be in bold if optional extra_text used */
if (extra_text != NULL)
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s", extra_text);
/* For a cancel button, use cancel response so user can press escape to cancel */
gtk_dialog_add_button(GTK_DIALOG(dialog), no_btn,
utils_str_equal(no_btn, GTK_STOCK_CANCEL) ? GTK_RESPONSE_CANCEL : GTK_RESPONSE_NO);
gtk_dialog_add_button(GTK_DIALOG(dialog), yes_btn, GTK_RESPONSE_YES);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
ret = TRUE;
gtk_widget_destroy(dialog);
#endif
return ret;
}
/**
* Show a question message box with @c text and Yes/No buttons.
* On Unix-like systems a GTK message dialog box is shown, on Win32 systems a native Windows
* message dialog box is shown.
*
* @param text Printf()-style format string.
* @param ... Arguments for the @c text format string.
*
* @return @a TRUE if the user answered with Yes, otherwise @a FALSE.
**/
gboolean dialogs_show_question(const gchar *text, ...)
{
gboolean ret = FALSE;
gchar string[512];
va_list args;
va_start(args, text);
g_vsnprintf(string, 511, text, args);
va_end(args);
ret = show_question(main_widgets.window, GTK_STOCK_YES, GTK_STOCK_NO, string, NULL);
return ret;
}
/* extra_text can be NULL; otherwise it is displayed below main_text.
* if parent is NULL, main_widgets.window will be used */
gboolean dialogs_show_question_full(GtkWidget *parent, const gchar *yes_btn, const gchar *no_btn,
const gchar *extra_text, const gchar *main_text, ...)
{
gboolean ret = FALSE;
gchar string[512];
va_list args;
va_start(args, main_text);
g_vsnprintf(string, 511, main_text, args);
va_end(args);
ret = show_question(parent, yes_btn, no_btn, string, extra_text);
return ret;
}