1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        gtk/filedlg.cpp 
   3 // Purpose:     native implementation of wxFileDialog 
   4 // Author:      Robert Roebling, Zbigniew Zagorski 
   6 // Copyright:   (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11 #pragma implementation "filedlggtk.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  19 #include "wx/filedlg.h" 
  22 #include "wx/filename.h" 
  23 #include "wx/msgdlg.h" 
  29 #include "wx/gtk/private.h" 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 extern void wxapp_install_idle_handler(); 
  38 //----------------------------------------------------------------------------- 
  39 // "clicked" for OK-button 
  40 //----------------------------------------------------------------------------- 
  43 static void gtk_filedialog_ok_callback(GtkWidget 
*widget
, wxFileDialog 
*dialog
) 
  45     int style 
= dialog
->GetStyle(); 
  46     gchar
* text 
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget
)); 
  47     wxString 
filename(wxGTK_CONV_BACK(text
)); 
  48     if ( filename
.empty() ) 
  50         // this is totally lame but better than silent error 
  51         wxLogWarning(_("This filename can't be used by wxWidgets because it contains invalid UTF-8 characters, please rename the file.")); 
  55     if ((style 
& wxSAVE
) && (style 
& wxOVERWRITE_PROMPT
)) 
  57         if (wxFileExists(filename
)) 
  61              _("File '%s' already exists, do you really want to overwrite it?"), 
  64             wxMessageDialog 
dlg(dialog
, msg
, _("Confirm"), 
  65                                wxYES_NO 
| wxICON_QUESTION
); 
  66             if (dlg
.ShowModal() != wxID_YES
) 
  70     else if ((style 
& wxOPEN
) && ( style 
& wxFILE_MUST_EXIST
)) 
  72         if (!wxFileExists( filename 
)) 
  74             wxMessageDialog 
dlg(dialog
, 
  75                                 _("Please choose an existing file."), 
  76                                 _("Error"), wxOK 
| wxICON_ERROR
); 
  83     // change to the directory where the user went if asked 
  84     if (style 
& wxCHANGE_DIR
) 
  87         wxSplitPath(filename
, &cwd
, NULL
, NULL
); 
  89         if (cwd 
!= wxGetCwd()) 
  91             wxSetWorkingDirectory(cwd
); 
  95     dialog
->SetPath(filename
); 
  96     dialog
->UpdateFromDialog(); 
  98     wxCommandEvent 
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_OK
); 
  99     event
.SetEventObject(dialog
); 
 100     dialog
->GetEventHandler()->ProcessEvent(event
); 
 104 //----------------------------------------------------------------------------- 
 105 // "clicked" for Cancel-button 
 106 //----------------------------------------------------------------------------- 
 109 static void gtk_filedialog_cancel_callback(GtkWidget 
*WXUNUSED(w
), 
 110                                            wxFileDialog 
*dialog
) 
 112     wxCommandEvent 
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
); 
 113     event
.SetEventObject(dialog
); 
 114     dialog
->GetEventHandler()->ProcessEvent(event
); 
 119 static void gtk_filedialog_response_callback(GtkWidget 
*w
, 
 121                                              wxFileDialog 
*dialog
) 
 123     wxapp_install_idle_handler(); 
 125     if (response 
== GTK_RESPONSE_ACCEPT
) 
 126         gtk_filedialog_ok_callback(w
, dialog
); 
 127     else if (response 
== GTK_RESPONSE_CANCEL
) 
 128         gtk_filedialog_cancel_callback(w
, dialog
); 
 131         gtk_filedialog_cancel_callback(w
, dialog
); 
 132         dialog
->m_destroyed_by_delete 
= true; 
 137 #endif // __WXGTK24__ 
 139 //----------------------------------------------------------------------------- 
 141 //----------------------------------------------------------------------------- 
 143 IMPLEMENT_DYNAMIC_CLASS(wxFileDialog
,wxGenericFileDialog
) 
 145 BEGIN_EVENT_TABLE(wxFileDialog
,wxGenericFileDialog
) 
 146         EVT_BUTTON(wxID_OK
, wxFileDialog::OnFakeOk
) 
 149 wxFileDialog::wxFileDialog(wxWindow 
*parent
, const wxString
& message
, 
 150                            const wxString
& defaultDir
, 
 151                            const wxString
& defaultFileName
, 
 152                            const wxString
& wildCard
, 
 153                            long style
, const wxPoint
& pos
) 
 154     : wxGenericFileDialog(parent
, message
, defaultDir
, defaultFileName
, 
 155                        wildCard
, style
, pos
, true ) 
 158     if (!gtk_check_version(2,4,0)) 
 160         m_needParent 
= false; 
 161         m_destroyed_by_delete 
= false; 
 163         if (!PreCreation(parent
, pos
, wxDefaultSize
) || 
 164             !CreateBase(parent
, wxID_ANY
, pos
, wxDefaultSize
, style
, 
 165                     wxDefaultValidator
, wxT("filedialog"))) 
 167             wxFAIL_MSG( wxT("wxFileDialog creation failed") ); 
 171         bool multiple 
= (style 
& wxMULTIPLE
) == wxMULTIPLE
; 
 172         GtkFileChooserAction gtk_action
; 
 173         GtkWindow
* gtk_parent 
= NULL
; 
 175             gtk_parent 
= GTK_WINDOW(parent
->m_widget
); 
 178         if ((style 
& wxSAVE
) == wxSAVE
) 
 180             gtk_action 
= GTK_FILE_CHOOSER_ACTION_SAVE
; 
 181             ok_btn_stock 
= GTK_STOCK_SAVE
; 
 185             gtk_action 
= GTK_FILE_CHOOSER_ACTION_OPEN
; 
 186             ok_btn_stock 
= GTK_STOCK_OPEN
; 
 188         m_widget 
= gtk_file_chooser_dialog_new( 
 189                        wxGTK_CONV(m_message
), 
 192                        GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
, 
 193                        ok_btn_stock
, GTK_RESPONSE_ACCEPT
, 
 196         gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget
), multiple
); 
 198         gtk_signal_connect(GTK_OBJECT(m_widget
), 
 200                              GTK_SIGNAL_FUNC(gtk_filedialog_response_callback
), 
 204         if (!m_path
.empty() && m_path
.Last() != wxT('/')) 
 206         m_path 
+= m_fileName
; 
 209         SetWildcard(wildCard
); 
 214         wxGenericFileDialog::Create( parent
, message
, defaultDir
, defaultFileName
, wildCard
, style
, pos 
); 
 217 wxFileDialog::~wxFileDialog() 
 220     if (!gtk_check_version(2,4,0)) 
 222         if (m_destroyed_by_delete
) 
 228 void wxFileDialog::OnFakeOk( wxCommandEvent 
&event 
) 
 231     if (!gtk_check_version(2,4,0)) 
 232         wxDialog::OnOK( event 
); 
 235         wxGenericFileDialog::OnListOk( event 
); 
 238 int wxFileDialog::ShowModal() 
 241     if (!gtk_check_version(2,4,0)) 
 242         return wxDialog::ShowModal(); 
 245         return wxGenericFileDialog::ShowModal(); 
 248 bool wxFileDialog::Show( bool show 
) 
 251     if (!gtk_check_version(2,4,0)) 
 252         return wxDialog::Show( show 
); 
 255         return wxGenericFileDialog::Show( show 
); 
 258 void wxFileDialog::GetFilenames(wxArrayString
& files
) const 
 261     if (!gtk_check_version(2,4,0)) 
 264         for (size_t n 
= 0; n 
< files
.GetCount(); n
++ ) 
 267             wxSplitPath(files
[n
], NULL
, &name
, &ext
); 
 278         wxGenericFileDialog::GetFilenames( files 
); 
 281 void wxFileDialog::GetPaths(wxArrayString
& paths
) const 
 284     if (!gtk_check_version(2,4,0)) 
 287         if (GetWindowStyle() & wxMULTIPLE
) 
 290                 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget
)); 
 291             GSList 
*gpaths 
= gpathsi
; 
 294                 wxString file 
= wxGTK_CONV_BACK((gchar
*) gpathsi
->data
); 
 296                 g_free(gpathsi
->data
); 
 297                 gpathsi 
= gpathsi
->next
; 
 300                 g_slist_free(gpaths
); 
 303         if ( paths
.IsEmpty() ) 
 305             paths
.Add(m_fileName
); 
 310         wxGenericFileDialog::GetPaths( paths 
); 
 313 void wxFileDialog::SetMessage(const wxString
& message
) 
 316     if (!gtk_check_version(2,4,0)) 
 323         wxGenericFileDialog::SetMessage( message 
); 
 326 void wxFileDialog::SetPath(const wxString
& path
) 
 329     if (!gtk_check_version(2,4,0)) 
 331         if (path
.empty()) return; 
 334         m_path 
= fn
.GetFullPath(); 
 335         m_dir 
= fn
.GetPath(); 
 336         m_fileName 
= fn
.GetFullName(); 
 341         wxGenericFileDialog::SetPath( path 
); 
 344 void wxFileDialog::SetDirectory(const wxString
& dir
) 
 347     if (!gtk_check_version(2,4,0)) 
 349         if (wxPathExists(dir
)) 
 352             m_path 
= wxFileName(m_dir
, m_fileName
).GetFullPath(); 
 358         wxGenericFileDialog::SetDirectory( dir 
); 
 361 void wxFileDialog::SetFilename(const wxString
& name
) 
 364     if (!gtk_check_version(2,4,0)) 
 367         m_path 
= wxFileName(m_dir
, m_fileName
).GetFullPath(); 
 372         wxGenericFileDialog::SetFilename( name 
); 
 375 void wxFileDialog::SetWildcard(const wxString
& wildCard
) 
 378     if (!gtk_check_version(2,4,0)) 
 380         m_wildCard 
= wildCard
; 
 381         GtkFileChooser
* chooser 
= GTK_FILE_CHOOSER(m_widget
); 
 383         // empty current filter list: 
 384         GSList
* ifilters 
= gtk_file_chooser_list_filters(chooser
); 
 385         GSList
* filters 
= ifilters
; 
 388             gtk_file_chooser_remove_filter(chooser
,GTK_FILE_FILTER(ifilters
->data
)); 
 389             ifilters 
= ifilters
->next
; 
 391         g_slist_free(filters
); 
 394         wxArrayString wildDescriptions
, wildFilters
; 
 395         if (!wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
)) 
 397             wxFAIL_MSG( wxT("Wrong file type description") ); 
 401             // add parsed to GtkChooser 
 402             for (size_t n 
= 0; n 
< wildFilters
.GetCount(); n
++) 
 404                 GtkFileFilter
* filter 
= gtk_file_filter_new(); 
 405                 gtk_file_filter_set_name(filter
,wxGTK_CONV(wildDescriptions
[n
])); 
 406                 wxString after 
= wildFilters
[n
]; 
 409                     wxString ext 
= after
.BeforeFirst(wxT(';')); 
 410                     gtk_file_filter_add_pattern(filter
,wxGTK_CONV(ext
)); 
 411                     if (after
.Find(wxT(';')) == wxNOT_FOUND
) 
 413                     after 
= after
.AfterLast(wxT(';')); 
 415                 while (!after
.empty()); 
 417                 gtk_file_chooser_add_filter(chooser
, filter
); 
 423         wxGenericFileDialog::SetWildcard( wildCard 
); 
 426 void wxFileDialog::SetFilterIndex(int filterIndex
) 
 429     if (!gtk_check_version(2,4,0)) 
 431         m_filterIndex 
= filterIndex
; 
 433         GtkFileChooser 
*chooser 
= GTK_FILE_CHOOSER(m_widget
); 
 434         GSList 
*fnode 
= gtk_file_chooser_list_filters(chooser
); 
 435         GSList 
*filters 
= fnode
; 
 439             if (i 
== filterIndex
) 
 441                 gtk_file_chooser_set_filter(chooser
, GTK_FILE_FILTER(fnode
->data
)); 
 448         g_slist_free(filters
); 
 452         wxGenericFileDialog::SetFilterIndex( filterIndex 
); 
 455 void wxFileDialog::UpdateDialog() 
 458     // set currently selected directory to match the path: 
 459     if (!m_dir
.empty() && wxPathExists(m_dir
)) 
 461         // NB: This is important -- if we set directory only and not the path, 
 462         //     then dialog will still remember old path set using previous 
 463         //     call to gtk_chooser_set_filename. If the previous directory 
 464         //     was a subdirectory of the directory we want to select now, 
 465         //     the dialog would still contain directory selector controls 
 466         //     for the subdirectory (with the parent directory selected), 
 467         //     instead of showing only the parent directory as expected. 
 468         //     This way, we force GtkFileChooser to really change the 
 469         //     directory. Finally, it doesn't have to be done if filename 
 470         //     is not empty because of the code that sets the filename below. 
 471         if (m_fileName
.empty()) 
 472             gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget
), 
 475         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget
), 
 479     // if the user set only the directory (e.g. by calling SetDirectory) 
 480     // and not the default filename, then we don't want to set the filename: 
 481     if (!m_fileName
.empty()) 
 483         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget
), 
 486         // pre-fill the filename when saving, too (there's no text entry 
 487         // control when opening a file, so it doesn't make sense to 
 488         // do this when opening files): 
 489         if (GetWindowStyle() & wxSAVE
) 
 491             gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget
), 
 492                                               wxGTK_CONV(m_fileName
)); 
 498 void wxFileDialog::UpdateFromDialog() 
 501     // update filterIndex 
 502     GSList 
*fnode 
= gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(m_widget
)); 
 503     GSList 
*filters 
= fnode
; 
 504     GtkFileFilter 
*current 
= 
 505         gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_widget
)); 
 511         if (fnode
->data 
== (gpointer
)current
) 
 519     g_slist_free(filters
); 
 523 #endif // wxUSE_FILEDLG