This is a big big GTK file dialog change in Rambetter-temp-fixes branch.

Thank you to Markus Fischer who	provided some example code on how to
use the	"new" method of	GTK file dialogs.  I then did a	lot of research	into
how to shape his code into exactly what	I wanted.

This is	an incomplete change in	that I have not	cleaned	up the code such
as removing unused local variables and unused functions	yet.  However, I
wanted to commit this now because it really works beautifully (the GTK file
dialog that is).

- In CFileType,	m_pstrGTKMasks now contains string like
"quake3 maps (*.map)" instead of like "quake3 maps <*.map>".  Nobody else
is using this code except in gtkmisc.cpp so it's a safe	change.

- Removing all FILEDLG_DBG blocks in gtkmisc.cpp.  It really clutters up the
code and since it's completely overhauled, it's	OK to remove.

- Instead of the "old" way of gtk_file_selection_new(),	now using
gtk_file_chooser_dialog_new() instead. 	Thx to Markus Fischer for examples.

- Actually adding GTK file dialog filters.  It works really nice!  :-)

- Now using the	same file extension logic on Windows file dialogs and GTK
file dialogs.

- Improved file	extension logic.  "No file extension specified in file to       
be saved.  Attempt to save anyways?"

Tested on Win7 and Linux.
More related changes on the way.

THIS SHOULD BE MERGED INTO TRUNK.


git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/Rambetter-temp-fixes@355 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
rambetter 2010-12-19 03:44:26 +00:00
parent 2c799718d7
commit b292b8db59
1 changed files with 68 additions and 147 deletions

View File

@ -1025,8 +1025,6 @@ int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCapti
// fenris #3078 WHENHELLISFROZENOVER // fenris #3078 WHENHELLISFROZENOVER
//#define FILEDLG_DBG
static void file_sel_callback (GtkWidget *widget, gpointer data) static void file_sel_callback (GtkWidget *widget, gpointer data)
{ {
GtkWidget *parent; GtkWidget *parent;
@ -1040,11 +1038,6 @@ static void file_sel_callback (GtkWidget *widget, gpointer data)
if (GPOINTER_TO_INT (data) == IDOK) if (GPOINTER_TO_INT (data) == IDOK)
*success = true; *success = true;
#ifdef FILEDLG_DBG
else
Sys_Printf("file_sel_callback != IDOK\n");
#endif
*loop = 0; *loop = 0;
} }
@ -1197,10 +1190,10 @@ private:
for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++) for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
*w = *r; *w = *r;
*w++ = ' '; *w++ = ' ';
*w++ = '<'; *w++ = '(';
for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++) for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
*w = *r; *w = *r;
*w++ = '>'; *w++ = ')';
*w++ = '\0'; *w++ = '\0';
} }
m_pstrGTKMasks[m_nTypes] = NULL; m_pstrGTKMasks[m_nTypes] = NULL;
@ -1253,31 +1246,15 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
char *new_path = NULL; char *new_path = NULL;
const char* r; const char* r;
char* w; char *v, *w;
filetype_t type; filetype_t type;
CFileType typelist; CFileType typelist;
if(pattern != NULL) if(pattern != NULL)
GetFileTypeRegistry()->getTypeList(pattern, &typelist); GetFileTypeRegistry()->getTypeList(pattern, &typelist);
#ifdef FILEDLG_DBG
Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path);
if (pattern)
{
Sys_Printf("Patterns:\n");
char** p = typelist.m_pstrGTKMasks;
while(*p!=NULL)
Sys_Printf("%s\n", *p++);
}
else
Sys_Printf("no patterns\n");
#endif
#ifdef _WIN32 #ifdef _WIN32
if (g_PrefsDlg.m_bNativeGUI) if (g_PrefsDlg.m_bNativeGUI)
{ {
#ifdef FILEDLG_DBG
Sys_Printf("Doing win32 file dialog...");
#endif
// do that the native way // do that the native way
if (in_file_dialog) return NULL; // Avoid recursive entry. if (in_file_dialog) return NULL; // Avoid recursive entry.
@ -1354,9 +1331,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
if(pattern != NULL) if(pattern != NULL)
type = typelist.GetTypeForIndex(ofn.nFilterIndex - 1); type = typelist.GetTypeForIndex(ofn.nFilterIndex - 1);
#ifdef FILEDLG_DBG
Sys_Printf("Done.\n");
#endif
} }
else else
{ {
@ -1366,9 +1340,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
if (title == NULL) if (title == NULL)
title = open ? _("Open File") : _("Save File"); title = open ? _("Open File") : _("Save File");
#ifdef FILEDLG_DBG
Sys_Printf("Doing Gtk file dialog:\nBuilding new_path..");
#endif
// we expect an actual path below, if the path is NULL we might crash // we expect an actual path below, if the path is NULL we might crash
if (!path || path[0] == '\0') if (!path || path[0] == '\0')
{ {
@ -1390,101 +1361,51 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
// terminate string // terminate string
*w = '\0'; *w = '\0';
#ifdef FILEDLG_DBG file_sel = gtk_file_chooser_dialog_new(title,
Sys_Printf("Done.\n"); GTK_WINDOW(parent),
Sys_Printf("Calling gtk_file_selection_new with title: %s...", title); open ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE,
#endif GTK_STOCK_CANCEL,
file_sel = gtk_file_selection_new (title); GTK_RESPONSE_CANCEL,
#ifdef FILEDLG_DBG open ? GTK_STOCK_OPEN : GTK_STOCK_SAVE,
Sys_Printf("Done.\n"); GTK_RESPONSE_ACCEPT,
Sys_Printf("Set the masks..."); NULL);
#endif gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_sel), new_path);
delete[] new_path;
#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0 // Setting the file chooser dialog to modal and centering it on the parent is done automatically.
// set the masks
if (pattern)
{
gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel));
gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast<const char**>(typelist.m_pstrGTKMasks));
}
#endif
#ifdef FILEDLG_DBG if (pattern != NULL) {
Sys_Printf("Done.\n"); for (int i = 0; i < typelist.GetNumTypes(); i++) {
#endif GtkFileFilter *filter = gtk_file_filter_new();
type = typelist.GetTypeForIndex(i);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", // We can use type.name here, or m_pstrGTKMasks[i], which includes the actual pattern.
GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); gtk_file_filter_set_name(filter, typelist.m_pstrGTKMasks[i]);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", gtk_file_filter_add_pattern(filter, type.pattern);
GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); // "Note that the chooser takes ownership of the filter, so
gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", // you have to ref and sink it if you want to keep a reference."
GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); // So I guess we won't need to garbage collect this.
gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_sel), filter);
}
if (parent != NULL)
gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
#ifdef FILEDLG_DBG
Sys_Printf("set_data...");
#endif
bool success = false;
g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
g_object_set_data (G_OBJECT (file_sel), "success", &success);
#ifdef FILEDLG_DBG
Sys_Printf("Done.\n");
#endif
if (!open)
{
#ifdef FILEDLG_DBG
Sys_Printf("set_data \"overwrite\" ...");
#endif
g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1));
#ifdef FILEDLG_DBG
Sys_Printf("Done.\n");
#endif
} }
if (new_path != NULL) if (gtk_dialog_run(GTK_DIALOG(file_sel)) == GTK_RESPONSE_ACCEPT) {
{ strcpy(szFile, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel)));
#ifdef FILEDLG_DBG }
Sys_Printf("gtk_file_selection_set_filename... %p (%s)", file_sel, new_path); else {
#endif szFile[0] = '\0';
gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path);
delete[] new_path;
#ifdef FILEDLG_DBG
Sys_Printf("Done.\n");
#endif
} }
gtk_grab_add (file_sel); if (pattern != NULL) {
#ifdef FILEDLG_DBG GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(file_sel));
Sys_Printf("gtk_widget_show... %p", file_sel); if (filter == NULL) {
#endif type = filetype_t();
gtk_widget_show (file_sel); }
#ifdef FILEDLG_DBG else {
Sys_Printf("Done.\n"); type = typelist.GetTypeForGTKMask(gtk_file_filter_get_name(filter));
#endif }
#ifdef FILEDLG_DBG
Sys_Printf("gtk_main_iteration...");
#endif
while (loop)
gtk_main_iteration ();
if(success)
{
#if 0 //!\todo Add masks to GtkFileSelection in gtk2
if(pattern!=NULL)
type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask);
#endif
strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
} }
#ifdef FILEDLG_DBG gtk_widget_destroy(file_sel);
Sys_Printf("Done.\n");
#endif
gtk_grab_remove (file_sel);
gtk_widget_destroy (file_sel);
#ifdef _WIN32 #ifdef _WIN32
} }
#endif #endif
@ -1497,37 +1418,42 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
if(*w=='\\') if(*w=='\\')
*w = '/'; *w = '/';
#if defined(WIN32) /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
if (g_PrefsDlg.m_bNativeGUI) if(!open && pattern != NULL) {
{ v = strrchr(szFile, '/');
/* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */ w = strrchr(szFile, '.');
if(!open && pattern != NULL) if ((v && w && w < v) || // Last '.' is before the file.
{ w == NULL) { // Extension missing.
// last ext separator if (type.pattern[0]) {
w = strrchr(szFile, '.');
if (w == NULL) { // No extension.
w = szFile + strlen(szFile); w = szFile + strlen(szFile);
strcpy(w, type.pattern + 1); // Add extension of selected filter type. strcpy(w, type.pattern + 1); // Add extension of selected filter type.
} }
else { // An extension was explicitly in the filename. else {
int knownExtension = 0; // type will be empty if for example there were no filters for pattern,
for (int i = typelist.GetNumTypes() - 1; i >= 0; i--) { // or if some other UI inconsistencies happen.
type = typelist.GetTypeForIndex(i); if (gtk_MessageBox(parent, "No file extension specified in file to be saved.\nAttempt to save anyways?",
if (strcmp(w, type.pattern + 1) == 0) { "GtkRadiant", MB_YESNO) == IDNO) {
knownExtension = 1; return NULL;
break;
}
} }
if (!knownExtension) { }
if (gtk_MessageBox(parent, "Unknown file extension for this save operation.\nAttempt to save anyways?", }
"GtkRadiant", MB_YESNO) == IDNO) { else { // An extension was explicitly in the filename.
return NULL; bool knownExtension = false;
} for (int i = typelist.GetNumTypes() - 1; i >= 0; i--) {
type = typelist.GetTypeForIndex(i);
if (type.pattern[0] && strcmp(w, type.pattern + 1) == 0) {
knownExtension = true;
break;
}
}
if (!knownExtension) {
if (gtk_MessageBox(parent, "Unknown file extension for this save operation.\nAttempt to save anyways?",
"GtkRadiant", MB_YESNO) == IDNO) {
return NULL;
} }
} }
} }
} }
#endif
// prompt to overwrite existing files // prompt to overwrite existing files
if (!open) if (!open)
@ -1535,11 +1461,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO) if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO)
return NULL; return NULL;
#ifdef FILEDLG_DBG
// ... let's use a static filename
Sys_Printf("filename: %p\n", szFile);
#endif
return szFile; return szFile;
} }