1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/filepicker.cpp 
   3 // Purpose:     implementation of wxFileButton and wxDirButton 
   4 // Author:      Francesco Montorsi 
   8 // Copyright:   (c) Francesco Montorsi 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 // ---------------------------------------------------------------------------- 
  15 // ---------------------------------------------------------------------------- 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  20 #if wxUSE_FILEPICKERCTRL && defined(__WXGTK26__) 
  22 #include "wx/filepicker.h" 
  23 #include "wx/tooltip.h" 
  25 #include "wx/gtk/private.h" 
  27 // ============================================================================ 
  29 // ============================================================================ 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 IMPLEMENT_DYNAMIC_CLASS(wxFileButton
, wxButton
) 
  37 bool wxFileButton::Create( wxWindow 
*parent
, wxWindowID id
, 
  38                         const wxString 
&label
, const wxString 
&path
, 
  39                         const wxString 
&message
, const wxString 
&wildcard
, 
  40                         const wxPoint 
&pos
, const wxSize 
&size
, 
  41                         long style
, const wxValidator
& validator
, 
  42                         const wxString 
&name 
) 
  44     // we can't use the native button for wxFLP_SAVE pickers as it can only 
  45     // open existing files and there is no way to create a new file using it 
  46     if ( !(style 
& wxFLP_SAVE
) && !(style 
& wxFLP_USE_TEXTCTRL
) && !gtk_check_version(2,6,0) ) 
  48         // VERY IMPORTANT: this code is identical to relative code in wxDirButton; 
  49         //                 if you find a problem here, fix it also in wxDirButton ! 
  51         if (!PreCreation( parent
, pos
, size 
) || 
  52             !wxControl::CreateBase(parent
, id
, pos
, size
, style 
& wxWINDOW_STYLE_MASK
, 
  55             wxFAIL_MSG( wxT("wxFileButton creation failed") ); 
  59         // create the dialog associated with this button 
  60         // NB: unlike generic implementation, native GTK implementation needs to create 
  61         //     the filedialog here as it needs to use gtk_file_chooser_button_new_with_dialog() 
  62         SetWindowStyle(style
); 
  65         m_wildcard 
= wildcard
; 
  66         if ((m_dialog 
= CreateDialog()) == NULL
) 
  69         // little trick used to avoid problems when there are other GTK windows 'grabbed': 
  70         // GtkFileChooserDialog won't be responsive to user events if there is another 
  71         // window which called gtk_grab_add (and this happens if e.g. a wxDialog is running 
  72         // in modal mode in the application - see wxDialogGTK::ShowModal). 
  73         // An idea could be to put the grab on the m_dialog->m_widget when the GtkFileChooserButton 
  74         // is clicked and then remove it as soon as the user closes the dialog itself. 
  75         // Unfortunately there's no way to hook in the 'clicked' event of the GtkFileChooserButton, 
  76         // thus we add grab on m_dialog->m_widget when it's shown and remove it when it's 
  77         // hidden simply using its "show" and "hide" events - clean & simple :) 
  78         g_signal_connect(m_dialog
->m_widget
, "show", G_CALLBACK(gtk_grab_add
), NULL
); 
  79         g_signal_connect(m_dialog
->m_widget
, "hide", G_CALLBACK(gtk_grab_remove
), NULL
); 
  81         //       use as label the currently selected file 
  82         m_widget 
= gtk_file_chooser_button_new_with_dialog( m_dialog
->m_widget 
); 
  84         g_object_ref(m_widget
); 
  85         gtk_widget_show(m_widget
); 
  87         // we need to know when the dialog has been dismissed clicking OK... 
  88         // NOTE: the "clicked" signal is not available for a GtkFileChooserButton 
  89         //       thus we are forced to use wxFileDialog's event 
  90         m_dialog
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
, 
  91                 wxCommandEventHandler(wxFileButton::OnDialogOK
), 
  94         m_parent
->DoAddChild( this ); 
 100         return wxGenericFileButton::Create(parent
, id
, label
, path
, message
, wildcard
, 
 101                                            pos
, size
, style
, validator
, name
); 
 105 wxFileButton::~wxFileButton() 
 109 void wxFileButton::OnDialogOK(wxCommandEvent
& ev
) 
 111     // the wxFileDialog associated with the GtkFileChooserButton has been closed 
 112     // using the OK button, thus the selected file has changed... 
 113     if (ev
.GetId() == wxID_OK
) 
 115         // ...update our path 
 116         UpdatePathFromDialog(m_dialog
); 
 118         // ...and fire an event 
 119         wxFileDirPickerEvent 
event(wxEVT_COMMAND_FILEPICKER_CHANGED
, this, GetId(), m_path
); 
 120         HandleWindowEvent(event
); 
 124 void wxFileButton::SetPath(const wxString 
&str
) 
 129         UpdateDialogPath(m_dialog
); 
 132 #endif      // wxUSE_FILEPICKERCTRL && defined(__WXGTK26__) 
 137 #if wxUSE_DIRPICKERCTRL && defined(__WXGTK26__) 
 139 #include <unistd.h> // chdir 
 141 //----------------------------------------------------------------------------- 
 142 // "current-folder-changed" 
 143 //----------------------------------------------------------------------------- 
 146 static void gtk_dirbutton_currentfolderchanged_callback(GtkFileChooserButton 
*widget
, 
 149     // update the m_path member of the wxDirButtonGTK 
 150     // unless the path was changed by wxDirButton::SetPath() 
 151     if (p
->m_bIgnoreNextChange
) 
 153         p
->m_bIgnoreNextChange
=false; 
 158     // NB: it's important to use gtk_file_chooser_get_filename instead of 
 159     //     gtk_file_chooser_get_current_folder (see GTK docs) ! 
 160     wxGtkString 
filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget
))); 
 161     p
->GTKUpdatePath(filename
); 
 163     // since GtkFileChooserButton when used to pick directories also uses a combobox, 
 164     // maybe that the current folder has been changed but not through the GtkFileChooserDialog 
 165     // and thus the 'gtk_filedialog_ok_callback' could have not been called... 
 166     // thus we need to make sure the current working directory is updated if wxDIRP_CHANGE_DIR 
 168     if (p
->HasFlag(wxDIRP_CHANGE_DIR
)) 
 171     // ...and fire an event 
 172     wxFileDirPickerEvent 
event(wxEVT_COMMAND_DIRPICKER_CHANGED
, p
, p
->GetId(), p
->GetPath()); 
 173     p
->HandleWindowEvent(event
); 
 178 //----------------------------------------------------------------------------- 
 180 //----------------------------------------------------------------------------- 
 182 IMPLEMENT_DYNAMIC_CLASS(wxDirButton
, wxButton
) 
 184 bool wxDirButton::Create( wxWindow 
*parent
, wxWindowID id
, 
 185                         const wxString 
&label
, const wxString 
&path
, 
 186                         const wxString 
&message
, const wxString 
&wildcard
, 
 187                         const wxPoint 
&pos
, const wxSize 
&size
, 
 188                         long style
, const wxValidator
& validator
, 
 189                         const wxString 
&name 
) 
 191     if ( !(style 
& wxDIRP_USE_TEXTCTRL
) && !gtk_check_version(2,6,0) ) 
 193         // VERY IMPORTANT: this code is identic to relative code in wxFileButton; 
 194         //                 if you find a problem here, fix it also in wxFileButton ! 
 196         if (!PreCreation( parent
, pos
, size 
) || 
 197             !wxControl::CreateBase(parent
, id
, pos
, size
, style 
& wxWINDOW_STYLE_MASK
, 
 200             wxFAIL_MSG( wxT("wxDirButtonGTK creation failed") ); 
 204         // create the dialog associated with this button 
 205         SetWindowStyle(style
); 
 207         m_wildcard 
= wildcard
; 
 208         if ((m_dialog 
= CreateDialog()) == NULL
) 
 212         // little trick used to avoid problems when there are other GTK windows 'grabbed': 
 213         // GtkFileChooserDialog won't be responsive to user events if there is another 
 214         // window which called gtk_grab_add (and this happens if e.g. a wxDialog is running 
 215         // in modal mode in the application - see wxDialogGTK::ShowModal). 
 216         // An idea could be to put the grab on the m_dialog->m_widget when the GtkFileChooserButton 
 217         // is clicked and then remove it as soon as the user closes the dialog itself. 
 218         // Unfortunately there's no way to hook in the 'clicked' event of the GtkFileChooserButton, 
 219         // thus we add grab on m_dialog->m_widget when it's shown and remove it when it's 
 220         // hidden simply using its "show" and "hide" events - clean & simple :) 
 221         g_signal_connect(m_dialog
->m_widget
, "show", G_CALLBACK(gtk_grab_add
), NULL
); 
 222         g_signal_connect(m_dialog
->m_widget
, "hide", G_CALLBACK(gtk_grab_remove
), NULL
); 
 225         // NOTE: we deliberately ignore the given label as GtkFileChooserButton 
 226         //       use as label the currently selected file 
 227         m_widget 
= gtk_file_chooser_button_new_with_dialog( m_dialog
->m_widget 
); 
 228         g_object_ref(m_widget
); 
 231         gtk_widget_show(m_widget
); 
 233         // GtkFileChooserButton signals 
 234         g_signal_connect(m_widget
, "current-folder-changed", 
 235                          G_CALLBACK(gtk_dirbutton_currentfolderchanged_callback
), this); 
 237         m_parent
->DoAddChild( this ); 
 240         SetInitialSize(size
); 
 243         return wxGenericDirButton::Create(parent
, id
, label
, path
, message
, wildcard
, 
 244                                           pos
, size
, style
, validator
, name
); 
 248 wxDirButton::~wxDirButton() 
 252 void wxDirButton::GTKUpdatePath(const char *gtkpath
) 
 254     m_path 
= wxString::FromUTF8(gtkpath
); 
 256 void wxDirButton::SetPath(const wxString
& str
) 
 260         // don't do anything and especially don't set m_bIgnoreNextChange 
 266     // wxDirButton uses the "current-folder-changed" signal which is triggered also 
 267     // when we set the path on the dialog associated with this button; thus we need 
 268     // to set the following flag to avoid sending a wxFileDirPickerEvent from this 
 269     // function (which would be inconsistent with wxFileButton's behaviour and in 
 270     // general with all wxWidgets control-manipulation functions which do not send events). 
 271     m_bIgnoreNextChange 
= true; 
 274         UpdateDialogPath(m_dialog
); 
 277 #endif      // wxUSE_DIRPICKERCTRL && defined(__WXGTK26__)