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" 
  29 // ============================================================================ 
  31 // ============================================================================ 
  33 //----------------------------------------------------------------------------- 
  35 //----------------------------------------------------------------------------- 
  37 IMPLEMENT_DYNAMIC_CLASS(wxFileButton
, wxButton
) 
  39 bool wxFileButton::Create( wxWindow 
*parent
, wxWindowID id
, 
  40                         const wxString 
&label
, const wxString 
&path
, 
  41                         const wxString 
&message
, const wxString 
&wildcard
, 
  42                         const wxPoint 
&pos
, const wxSize 
&size
, 
  43                         long style
, const wxValidator
& validator
, 
  44                         const wxString 
&name 
) 
  46     if (!gtk_check_version(2,6,0)) 
  48         // VERY IMPORTANT: this code is identic to relative code in wxDirButton; 
  49         //                 if you find a problem here, fix it also in wxDirButton ! 
  52         m_acceptsFocus 
= true; 
  54         if (!PreCreation( parent
, pos
, size 
) || 
  55             !wxControl::CreateBase(parent
, id
, pos
, size
, style 
& wxWINDOW_STYLE_MASK
, 
  58             wxFAIL_MSG( wxT("wxFileButton creation failed") ); 
  62         // create the dialog associated with this button 
  63         // NB: unlike generic implementation, native GTK implementation needs to create 
  64         //     the filedialog here as it needs to use gtk_file_chooser_button_new_with_dialog() 
  65         SetWindowStyle(style
); 
  68         m_wildcard 
= wildcard
; 
  69         if ((m_dialog 
= CreateDialog()) == NULL
) 
  72         // little trick used to avoid problems when there are other GTK windows 'grabbed': 
  73         // GtkFileChooserDialog won't be responsive to user events if there is another 
  74         // window which called gtk_grab_add (and this happens if e.g. a wxDialog is running 
  75         // in modal mode in the application - see wxDialogGTK::ShowModal). 
  76         // An idea could be to put the grab on the m_dialog->m_widget when the GtkFileChooserButton 
  77         // is clicked and then remove it as soon as the user closes the dialog itself. 
  78         // Unfortunately there's no way to hook in the 'clicked' event of the GtkFileChooserButton, 
  79         // thus we add grab on m_dialog->m_widget when it's shown and remove it when it's 
  80         // hidden simply using its "show" and "hide" events - clean & simple :) 
  81         g_signal_connect(m_dialog
->m_widget
, "show", G_CALLBACK(gtk_grab_add
), NULL
); 
  82         g_signal_connect(m_dialog
->m_widget
, "hide", G_CALLBACK(gtk_grab_remove
), NULL
); 
  84         // NOTE: we deliberately ignore the given label as GtkFileChooserButton 
  85         //       use as label the currently selected file 
  86         m_widget 
= gtk_file_chooser_button_new_with_dialog( m_dialog
->m_widget 
); 
  87         gtk_widget_show( GTK_WIDGET(m_widget
) ); 
  89         // we need to know when the dialog has been dismissed clicking OK... 
  90         // NOTE: the "clicked" signal is not available for a GtkFileChooserButton 
  91         //       thus we are forced to use wxFileDialog's event 
  92         m_dialog
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
, 
  93                 wxCommandEventHandler(wxFileButton::OnDialogOK
), 
  96         m_parent
->DoAddChild( this ); 
 102         return wxGenericFileButton::Create(parent
, id
, label
, path
, message
, wildcard
, 
 103                                            pos
, size
, style
, validator
, name
); 
 107 wxFileButton::~wxFileButton() 
 109     // GtkFileChooserButton will automatically destroy the 
 110     // GtkFileChooserDialog associated with m_dialog. 
 111     // Thus we have to set its m_widget to NULL to avoid 
 112     // double destruction on same widget 
 113     m_dialog
->m_widget 
= NULL
; 
 116 void wxFileButton::OnDialogOK(wxCommandEvent
& ev
) 
 118     // the wxFileDialog associated with the GtkFileChooserButton has been closed 
 119     // using the OK button, thus the selected file has changed... 
 120     if (ev
.GetId() == wxID_OK
) 
 122         // ...update our path 
 123         UpdatePathFromDialog(m_dialog
); 
 125         // ...and fire an event 
 126         wxFileDirPickerEvent 
event(wxEVT_COMMAND_FILEPICKER_CHANGED
, this, GetId(), m_path
); 
 127         GetEventHandler()->ProcessEvent(event
); 
 131 void wxFileButton::SetPath(const wxString 
&str
) 
 134     UpdateDialogPath(m_dialog
); 
 137 #endif      // wxUSE_FILEPICKERCTRL && defined(__WXGTK26__) 
 142 #if wxUSE_DIRPICKERCTRL && defined(__WXGTK26__) 
 144 #include <unistd.h> // chdir 
 146 //----------------------------------------------------------------------------- 
 147 // "current-folder-changed" 
 148 //----------------------------------------------------------------------------- 
 151 static void gtk_dirbutton_currentfolderchanged_callback(GtkFileChooserButton 
*widget
, 
 154     // update the m_path member of the wxDirButtonGTK 
 155     // unless the path was changed by wxDirButton::SetPath() 
 156     if (p
->m_bIgnoreNextChange
) 
 158         p
->m_bIgnoreNextChange
=false; 
 163     // NB: it's important to use gtk_file_chooser_get_filename instead of 
 164     //     gtk_file_chooser_get_current_folder (see GTK docs) ! 
 165     gchar
* filename 
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget
)); 
 166     p
->UpdatePath(filename
); 
 168     // since GtkFileChooserButton when used to pick directories also uses a combobox, 
 169     // maybe that the current folder has been changed but not through the GtkFileChooserDialog 
 170     // and thus the 'gtk_filedialog_ok_callback' could have not been called... 
 171     // thus we need to make sure the current working directory is updated if wxDIRP_CHANGE_DIR 
 173     if (p
->HasFlag(wxDIRP_CHANGE_DIR
)) 
 177     // ...and fire an event 
 178     wxFileDirPickerEvent 
event(wxEVT_COMMAND_DIRPICKER_CHANGED
, p
, p
->GetId(), p
->GetPath()); 
 179     p
->GetEventHandler()->ProcessEvent(event
); 
 184 //----------------------------------------------------------------------------- 
 186 //----------------------------------------------------------------------------- 
 188 IMPLEMENT_DYNAMIC_CLASS(wxDirButton
, wxButton
) 
 190 bool wxDirButton::Create( wxWindow 
*parent
, wxWindowID id
, 
 191                         const wxString 
&label
, const wxString 
&path
, 
 192                         const wxString 
&message
, const wxString 
&wildcard
, 
 193                         const wxPoint 
&pos
, const wxSize 
&size
, 
 194                         long style
, const wxValidator
& validator
, 
 195                         const wxString 
&name 
) 
 197     if (!gtk_check_version(2,6,0)) 
 199         // VERY IMPORTANT: this code is identic to relative code in wxFileButton; 
 200         //                 if you find a problem here, fix it also in wxFileButton ! 
 203         m_acceptsFocus 
= true; 
 205         if (!PreCreation( parent
, pos
, size 
) || 
 206             !wxControl::CreateBase(parent
, id
, pos
, size
, style 
& wxWINDOW_STYLE_MASK
, 
 209             wxFAIL_MSG( wxT("wxDirButtonGTK creation failed") ); 
 213         // create the dialog associated with this button 
 214         SetWindowStyle(style
); 
 216         m_wildcard 
= wildcard
; 
 217         if ((m_dialog 
= CreateDialog()) == NULL
) 
 221         // little trick used to avoid problems when there are other GTK windows 'grabbed': 
 222         // GtkFileChooserDialog won't be responsive to user events if there is another 
 223         // window which called gtk_grab_add (and this happens if e.g. a wxDialog is running 
 224         // in modal mode in the application - see wxDialogGTK::ShowModal). 
 225         // An idea could be to put the grab on the m_dialog->m_widget when the GtkFileChooserButton 
 226         // is clicked and then remove it as soon as the user closes the dialog itself. 
 227         // Unfortunately there's no way to hook in the 'clicked' event of the GtkFileChooserButton, 
 228         // thus we add grab on m_dialog->m_widget when it's shown and remove it when it's 
 229         // hidden simply using its "show" and "hide" events - clean & simple :) 
 230         g_signal_connect(m_dialog
->m_widget
, "show", G_CALLBACK(gtk_grab_add
), NULL
); 
 231         g_signal_connect(m_dialog
->m_widget
, "hide", G_CALLBACK(gtk_grab_remove
), NULL
); 
 234         // NOTE: we deliberately ignore the given label as GtkFileChooserButton 
 235         //       use as label the currently selected file 
 236         m_widget 
= gtk_file_chooser_button_new_with_dialog( m_dialog
->m_widget 
); 
 238         gtk_widget_show( GTK_WIDGET(m_widget
) ); 
 240         // GtkFileChooserButton signals 
 241         g_signal_connect(m_widget
, "current-folder-changed", 
 242                          G_CALLBACK(gtk_dirbutton_currentfolderchanged_callback
), this); 
 244         m_parent
->DoAddChild( this ); 
 250         return wxGenericDirButton::Create(parent
, id
, label
, path
, message
, wildcard
, 
 251                                           pos
, size
, style
, validator
, name
); 
 255 wxDirButton::~wxDirButton() 
 257     // GtkFileChooserButton will automatically destroy the 
 258     // GtkFileChooserDialog associated with m_dialog. 
 259     // Thus we have to set its m_widget to NULL to avoid 
 260     // double destruction on same widget 
 261     m_dialog
->m_widget 
= NULL
; 
 264 void wxDirButton::SetPath(const wxString 
&str
) 
 268     // wxDirButton uses the "current-folder-changed" signal which is triggered also 
 269     // when we set the path on the dialog associated with this button; thus we need 
 270     // to set the following flag to avoid sending a wxFileDirPickerEvent from this 
 271     // function (which would be inconsistent with wxFileButton's behaviour and in 
 272     // general with all wxWidgets control-manipulation functions which do not send events). 
 273     m_bIgnoreNextChange 
= true; 
 275     UpdateDialogPath(m_dialog
); 
 278 #endif      // wxUSE_DIRPICKERCTRL && defined(__WXGTK26__)