1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-17 16:40:07 +02:00
audacity/lib-src/FileDialog/gtk/FileDialogPrivate.cpp
lllucius c512822138 Additional changes for wx3
These are mostly for getting it to build on Linux, but I've
also created new configs in Visual Studio to make it easier
to switch between wx2 and wx3.

For Linux, you have to tell configure where to find the wx3
version of the wx-config script and, since some distros build
wxWidgets v3 against GTK+ v3, you may also need to enable
gtk3 with something like:

./configure --enable-gtk3 WX_CONFIG=/usr/bin/wx-config-3.0

On Windows, I've added "wx3-Debug" and "wx3-Release" to the
existing "Debug" and "Release" configurations.

They depend on you having your WXWIN environment variable
pointing to your wx2 directory and a new WXWIN3 environment
variable pointing to your wx3 directory.  For instance, I
have:

WXWIN=C:\Users\yam\Documents\wxWidgets-2.8.13
WXWIN3=C:\Users\yam\Documents\wxWidgets-3.0.2

Doing this allows you to switch freely among the 4 configurations
without having to get out of Visual Studio and monkey around with
the environment.

The project files will also add the location of the wxWidgets DLLs
to the PATH when running Audacity from within Visual Studio.  They
add %WXWIN%\lib\vc_dll or %WXWIN3%\lib\vc_dll at the beginning
of the PATH variable as appropriate.

I expect that once we convert to wx3 we'll just drop back down to
the normal Debug and Release configurations, but this should make
switching between wx2 and wx3 much easier during the transition.
2014-10-16 16:18:04 +00:00

487 lines
15 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: gtk/filedlg.cpp
// Purpose: native implementation of FileDialog
// Author: Robert Roebling, Zbigniew Zagorski, Mart Raudsepp
// Id: $Id: FileDialogPrivate.cpp,v 1.7 2009-05-25 11:10:00 llucius Exp $
// Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
// Licence: wxWindows licence
//
// Modified for Audacity to support an additional button on Save dialogs
//
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
// Include setup.h to get wxUSE flags for compilers that do not support precompilation of headers
#include "wx/setup.h"
#include "../FileDialog.h"
#include <gtk/gtk.h>
#include "private.h"
#include <unistd.h> // chdir
#include "wx/intl.h"
#include "wx/filename.h" // wxFilename
#include "wx/tokenzr.h" // wxStringTokenizer
#include "wx/filefn.h" // ::wxGetCwd
#include "wx/msgdlg.h" // wxMessageDialog
#include "wx/version.h"
//-----------------------------------------------------------------------------
// Pull in generic file dialog
//-----------------------------------------------------------------------------
#include "../generic/FileDialogPrivate.cpp"
//-----------------------------------------------------------------------------
// idle system
//-----------------------------------------------------------------------------
extern void wxapp_install_idle_handler();
//-----------------------------------------------------------------------------
// Open expanders on the dialog (really only the "Browser for other folders")
//-----------------------------------------------------------------------------
extern "C" {
static void SetExpanded(GtkWidget *widget, gpointer data)
{
if (GTK_IS_EXPANDER(widget))
{
gtk_expander_set_expanded(GTK_EXPANDER(widget), true);
}
else if (GTK_IS_CONTAINER(widget))
{
gtk_container_forall(GTK_CONTAINER(widget), SetExpanded, data);
}
return;
}
static void gtk_filedialog_show_callback(GtkWidget *widget, FileDialog *dialog)
{
gtk_container_forall(GTK_CONTAINER(widget), SetExpanded, NULL);
}
}
//-----------------------------------------------------------------------------
// "clicked" for OK-button
//-----------------------------------------------------------------------------
extern "C" {
static void gtk_filedialog_ok_callback(GtkWidget *widget, FileDialog *dialog)
{
int style = dialog->GetWindowStyle();
gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
// gtk version numbers must be identical with the one in ctor (that calls set_do_overwrite_confirmation)
#if GTK_CHECK_VERSION(2,7,3)
if(gtk_check_version(2,7,3) != NULL)
#endif
if ((style & wxFD_SAVE) && (style & wxFD_OVERWRITE_PROMPT))
{
if ( g_file_test(filename, G_FILE_TEST_EXISTS) )
{
wxString msg;
msg.Printf(
_("File '%s' already exists, do you really want to overwrite it?"),
wxString(wxConvFileName->cMB2WX(filename)).c_str());
wxMessageDialog dlg(dialog, msg, _("Confirm"),
wxYES_NO | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return;
}
}
// change to the directory where the user went if asked
if (style & wxFD_CHANGE_DIR)
{
// Use chdir to not care about filename encodings
gchar* folder = g_path_get_dirname(filename);
chdir(folder);
g_free(folder);
}
g_free(filename);
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
event.SetEventObject(dialog);
dialog->GetEventHandler()->ProcessEvent(event);
}
}
//-----------------------------------------------------------------------------
// "clicked" for Cancel-button
//-----------------------------------------------------------------------------
extern "C" {
static void gtk_filedialog_cancel_callback(GtkWidget *WXUNUSED(w),
FileDialog *dialog)
{
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
event.SetEventObject(dialog);
dialog->GetEventHandler()->ProcessEvent(event);
}
}
extern "C" {
static void gtk_filedialog_response_callback(GtkWidget *w,
gint response,
FileDialog *dialog)
{
#if !wxCHECK_VERSION(3, 0, 0)
wxapp_install_idle_handler();
#endif
if (response == GTK_RESPONSE_ACCEPT)
gtk_filedialog_ok_callback(w, dialog);
else if (response == GTK_RESPONSE_CANCEL)
gtk_filedialog_cancel_callback(w, dialog);
else // "delete"
{
gtk_filedialog_cancel_callback(w, dialog);
dialog->m_destroyed_by_delete = true;
}
}
}
//-----------------------------------------------------------------------------
// "clicked" for extra-button
//-----------------------------------------------------------------------------
extern "C" {
static void gtk_filedialog_extra_callback(GtkWidget *WXUNUSED(w),
FileDialog *dialog)
{
dialog->ClickButton(dialog->GetFilterIndex());
}
}
//-----------------------------------------------------------------------------
// FileDialog
//-----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(FileDialog, GenericFileDialog)
BEGIN_EVENT_TABLE(FileDialog, GenericFileDialog)
EVT_BUTTON(wxID_OK, FileDialog::OnFakeOk)
END_EVENT_TABLE()
FileDialog::FileDialog(wxWindow *parent, const wxString& message,
const wxString& defaultDir,
const wxString& defaultFileName,
const wxString& wildCard,
long style, const wxPoint& pos)
: GenericFileDialog(parent, message, defaultDir, defaultFileName,
wildCard, style, pos,
wxDefaultSize,
wxFileDialogNameStr,
true )
{
wxASSERT_MSG( !( (style & wxFD_SAVE) && (style & wxFD_MULTIPLE) ), wxT("FileDialog - wxFD_MULTIPLE used on a save dialog" ) );
#if !wxCHECK_VERSION(3, 0, 0)
m_needParent = false;
#endif
m_destroyed_by_delete = false;
if (!PreCreation(parent, pos, wxDefaultSize) ||
!CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
wxDefaultValidator, wxT("filedialog")))
{
wxFAIL_MSG( wxT("FileDialog creation failed") );
return;
}
GtkFileChooserAction gtk_action;
GtkWindow* gtk_parent = NULL;
if (parent)
gtk_parent = GTK_WINDOW( gtk_widget_get_toplevel(parent->m_widget) );
const gchar* ok_btn_stock;
if ( style & wxFD_SAVE )
{
gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
ok_btn_stock = GTK_STOCK_SAVE;
}
else
{
gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
ok_btn_stock = GTK_STOCK_OPEN;
}
m_widget = gtk_file_chooser_dialog_new(
wxGTK_CONV(m_message),
gtk_parent,
gtk_action,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
ok_btn_stock, GTK_RESPONSE_ACCEPT,
NULL);
// Allow pressing "Enter" key for default action
gtk_dialog_set_default_response(GTK_DIALOG(m_widget), GTK_RESPONSE_ACCEPT);
if ( style & wxFD_MULTIPLE )
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget), true);
// local-only property could be set to false to allow non-local files to be loaded.
// In that case get/set_uri(s) should be used instead of get/set_filename(s) everywhere
// and the GtkFileChooserDialog should probably also be created with a backend,
// e.g "gnome-vfs", "default", ... (gtk_file_chooser_dialog_new_with_backend).
// Currently local-only is kept as the default - true:
// gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(m_widget), true);
g_signal_connect(G_OBJECT(m_widget), "response",
G_CALLBACK(gtk_filedialog_response_callback), (gpointer)this);
g_signal_connect(G_OBJECT(m_widget), "show",
G_CALLBACK(gtk_filedialog_show_callback), (gpointer)this);
SetWildcard(wildCard);
if ( style & wxFD_SAVE )
{
if ( !defaultDir.empty() )
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
wxConvFileName->cWX2MB(defaultDir));
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget),
wxConvFileName->cWX2MB(defaultFileName));
#if GTK_CHECK_VERSION(2,7,3)
if (!gtk_check_version(2,7,3))
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(m_widget), FALSE);
#endif
}
else
{
if ( !defaultFileName.empty() )
{
wxString dir;
if ( defaultDir.empty() )
dir = ::wxGetCwd();
else
dir = defaultDir;
gtk_file_chooser_set_filename(
GTK_FILE_CHOOSER(m_widget),
wxConvFileName->cWX2MB( wxFileName(dir, defaultFileName).GetFullPath() ) );
}
else if ( !defaultDir.empty() )
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(m_widget),
wxConvFileName->cWX2MB(defaultDir) );
}
}
FileDialog::~FileDialog()
{
if (m_destroyed_by_delete)
m_widget = NULL;
}
void FileDialog::OnFakeOk( wxCommandEvent &event )
{
if (Validate() && TransferDataFromWindow())
EndModal(wxID_OK);
}
int FileDialog::ShowModal()
{
if ( !m_buttonlabel.IsEmpty() )
{
GtkWidget *widget;
wxString label = m_buttonlabel;
label.Replace(wxT("&"), wxT("_"));
widget = gtk_button_new_with_mnemonic(wxGTK_CONV(label));
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(m_widget), widget);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gtk_filedialog_extra_callback), (gpointer)this);
}
return wxDialog::ShowModal();
}
bool FileDialog::Show( bool show )
{
return wxDialog::Show( show );
}
void FileDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags )
{
if (!m_wxwindow)
return;
else
GenericFileDialog::DoSetSize( x, y, width, height, sizeFlags );
}
wxString FileDialog::GetPath() const
{
char *f = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget));
wxString path = wxConvFileName->cMB2WX(f);
g_free(f);
return path;
}
void FileDialog::GetFilenames(wxArrayString& files) const
{
GetPaths(files);
for (size_t n = 0; n < files.GetCount(); ++n )
{
wxFileName file(files[n]);
files[n] = file.GetFullName();
}
}
void FileDialog::GetPaths(wxArrayString& paths) const
{
paths.Empty();
if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(m_widget)))
{
GSList *gpathsi = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget));
GSList *gpaths = gpathsi;
while (gpathsi)
{
wxString file(wxConvFileName->cMB2WX((gchar*) gpathsi->data));
paths.Add(file);
g_free(gpathsi->data);
gpathsi = gpathsi->next;
}
g_slist_free(gpaths);
}
else
paths.Add(GetPath());
}
void FileDialog::SetMessage(const wxString& message)
{
m_message = message;
SetTitle(message);
}
void FileDialog::SetPath(const wxString& path)
{
if (path.empty()) return;
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(path));
}
void FileDialog::SetDirectory(const wxString& dir)
{
if (wxDirExists(dir))
{
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(dir));
}
}
wxString FileDialog::GetDirectory() const
{
return wxConvFileName->cMB2WX(gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER(m_widget) ) );
}
void FileDialog::SetFilename(const wxString& name)
{
if (GetWindowStyle() & wxFD_SAVE)
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(name));
else
SetPath(wxFileName(GetDirectory(), name).GetFullPath());
}
wxString FileDialog::GetFilename() const
{
char *f = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget));
wxFileName name(wxConvFileName->cMB2WX(f));
g_free(f);
return name.GetFullName();
}
void FileDialog::SetWildcard(const wxString& wildCard)
{
// parse filters
wxArrayString wildDescriptions, wildFilters;
if (!wxParseCommonDialogsFilter(wildCard, wildDescriptions, wildFilters))
{
wxFAIL_MSG( wxT("FileDialog::SetWildCard - bad wildcard string") );
}
else
{
// Parsing went fine. Set m_wildCard to be returned by FileDialogBase::GetWildcard
m_wildCard = wildCard;
GtkFileChooser* chooser = GTK_FILE_CHOOSER(m_widget);
// empty current filter list:
GSList* ifilters = gtk_file_chooser_list_filters(chooser);
GSList* filters = ifilters;
while (ifilters)
{
gtk_file_chooser_remove_filter(chooser,GTK_FILE_FILTER(ifilters->data));
ifilters = ifilters->next;
}
g_slist_free(filters);
// add parsed to GtkChooser
for (size_t n = 0; n < wildFilters.GetCount(); ++n)
{
GtkFileFilter* filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, wxGTK_CONV(wildDescriptions[n]));
wxStringTokenizer exttok(wildFilters[n], wxT(";"));
while (exttok.HasMoreTokens())
{
wxString token = exttok.GetNextToken();
gtk_file_filter_add_pattern(filter, wxGTK_CONV(token));
}
gtk_file_chooser_add_filter(chooser, filter);
}
// Reset the filter index
SetFilterIndex(0);
}
}
void FileDialog::SetFilterIndex(int filterIndex)
{
gpointer filter;
GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
GSList *filters = gtk_file_chooser_list_filters(chooser);
filter = g_slist_nth_data(filters, filterIndex);
if (filter != NULL)
{
gtk_file_chooser_set_filter(chooser, GTK_FILE_FILTER(filter));
}
else
{
wxFAIL_MSG( wxT("FileDialog::SetFilterIndex - bad filter index") );
}
g_slist_free(filters);
}
int FileDialog::GetFilterIndex() const
{
GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
GtkFileFilter *filter = gtk_file_chooser_get_filter(chooser);
GSList *filters = gtk_file_chooser_list_filters(chooser);
gint index = g_slist_index(filters, filter);
g_slist_free(filters);
if (index == -1)
{
wxFAIL_MSG( wxT("FileDialog::GetFilterIndex - bad filter index returned by gtk+") );
return 0;
}
else
return index;
}