Backport wxFileDialog::AddShortcut() changes to 3.2

This is a backport of #22635 with the following changes:

- Don't make the new function virtual to avoid changing ABI.
- Use wxABI_VERSION checks around the declarations of the new
  functions (and also constants, for good measure).
- Add new symbol to the linker version script (creating a new
  section for it).
- Document the function as being new in 3.2.1, not 3.3.0.

See #22543.
This commit is contained in:
Vadim Zeitlin 2022-07-24 15:09:04 +01:00
parent 973fc9a897
commit d013367c24
12 changed files with 237 additions and 9 deletions

View File

@ -237,6 +237,7 @@ Changes in behaviour which may result in build errors
All (GUI):
- Add wxFileDialog::AddShortcut() (#22543).
- Fix grid window scrollbars when freezing part of the grid (#22602).
- Avoid warnings with wxStaticText flags in C++20 (David Connet, #22656).
- Fix AUI floating pane position when dragging (Konstantin S. Matveyev, #22533).

View File

@ -56,6 +56,17 @@ enum
#define wxFD_DEFAULT_STYLE wxFD_OPEN
#if wxABI_VERSION >= 30201
// Flags for wxFileDialog::AddShortcut().
enum
{
wxFD_SHORTCUT_TOP = 0x0001,
wxFD_SHORTCUT_BOTTOM = 0x0002
};
#endif // wxABI_VERSION >= 3.2.1
extern WXDLLIMPEXP_DATA_CORE(const char) wxFileDialogNameStr[];
extern WXDLLIMPEXP_DATA_CORE(const char) wxFileSelectorPromptStr[];
extern WXDLLIMPEXP_DATA_CORE(const char) wxFileSelectorDefaultWildcardStr[];
@ -130,6 +141,14 @@ public:
{ return m_currentlySelectedFilterIndex; }
#if defined(__WXUNIVERSAL__) || !(defined(__WXMSW__) || defined(__WXGTK20__))
#if wxABI_VERSION >= 30201
// Add a shortcut to the given directory in the sidebar containing such
// shortcuts if supported.
bool AddShortcut(const wxString& directory, int flags = 0);
#endif // wxABI_VERSION >= 3.2.1
#endif // Platforms without native implementation.
// A customize hook methods will be called by wxFileDialog later if this
// function returns true, see its documentation for details.
//

View File

@ -55,6 +55,9 @@ public:
virtual int ShowModal() wxOVERRIDE;
#if wxABI_VERSION >= 30201
bool AddShortcut(const wxString& directory, int flags = 0);
#endif // wxABI_VERSION >= 3.2.1
virtual bool SupportsExtraControl() const wxOVERRIDE { return true; }
// Implementation only.

View File

@ -33,6 +33,9 @@ public:
virtual void GetPaths(wxArrayString& paths) const wxOVERRIDE;
virtual void GetFilenames(wxArrayString& files) const wxOVERRIDE;
#if wxABI_VERSION >= 30201
bool AddShortcut(const wxString& directory, int flags = 0);
#endif // wxABI_VERSION >= 3.2.1
virtual bool SupportsExtraControl() const wxOVERRIDE { return true; }
virtual int ShowModal() wxOVERRIDE;

View File

@ -55,6 +55,9 @@ public:
// Set the initial path to show in the dialog.
void SetInitialPath(const wxString& path);
// Add a shortcut.
void AddPlace(const wxString& path, FDAP fdap);
// Show the file dialog with the given parent window and options.
//
// Returns the selected path, or paths, in the provided output parameters,
@ -73,6 +76,9 @@ private:
wxCOMPtr<IFileDialog> m_fileDialog;
};
// Initialize an IShellItem object with the given path.
HRESULT InitShellItemFromPath(wxCOMPtr<IShellItem>& item, const wxString& path);
// Extract the filesystem path corresponding to the given shell item.
HRESULT GetFSPathFromShellItem(const wxCOMPtr<IShellItem>& item, wxString& path);

View File

@ -232,6 +232,46 @@ public:
*/
virtual ~wxFileDialog();
/**
Add a directory to the list of shortcuts shown in the dialog.
File dialogs on many platforms display a fixed list of directories
which can be easily selected by the user. This function allows to add
an application-defined directory to this list, which can be convenient
for the programs that use specific directories for their files instead
of the default user document directory (see wxStandardPaths).
Currently this function is only implemented in wxMSW and wxGTK and does
nothing under the other platforms. Moreover, in wxMSW this function is
incompatible with the use of SetExtraControlCreator(), if you need to
use this function and customize the dialog contents, please use the
newer SetCustomizeHook() instead.
The @ref page_samples_dialogs "dialogs sample" shows the use of this
function by adding two custom shortcuts corresponding to the
subdirectories of @c WXWIN environment variable if it is defined.
@note In wxMSW, the shortcuts appear in a separate section called
"Application Links" by default. To change the title of this
section, the application can specify a value of the @c
FileDescription field of the version information structure in its
resource file -- if present, this string will be used as the
section title.
@param directory The full path to the directory, which should exist.
@param flags Can be set to @c wxFD_SHORTCUT_BOTTOM (which is also the
default behaviour) to add the shortcut after the existing ones,
or @c wxFD_SHORTCUT_TOP to add it before them. Support for the
latter flag is only available in wxMSW, in wxGTK the shortcuts are
always added to the bottom of the list.
@return @true on success or @false if shortcut couldn't be added, e.g.
because this functionality is not available on the current
platform.
@since 3.2.1
*/
bool AddShortcut(const wxString& directory, int flags = 0);
/**
Returns the path of the file currently selected in dialog.

View File

@ -1824,6 +1824,18 @@ void MyFrame::FileOpen(wxCommandEvent& WXUNUSED(event) )
)
);
// For demonstration purposes, add wxWidgets directories to the sidebar.
wxString wxdir;
if ( wxGetEnv("WXWIN", &wxdir) )
{
dialog.AddShortcut(wxdir + "/src");
// By default shortcuts are added at the bottom, but we can override
// this in the ports that support it (currently only wxMSW) and add a
// shortcut added later at the top instead.
dialog.AddShortcut(wxdir + "/include", wxFD_SHORTCUT_TOP);
}
// Note: this object must remain alive until ShowModal() returns.
MyCustomizeHook myCustomizer(dialog);

View File

@ -851,6 +851,17 @@ wxString wxFileDialogBase::AppendExtension(const wxString &filePath,
return filePath + ext;
}
#if defined(__WXUNIVERSAL__) || !(defined(__WXMSW__) || defined(__WXGTK20__))
bool wxFileDialogBase::AddShortcut(const wxString& WXUNUSED(directory),
int WXUNUSED(flags))
{
// Not implemented by default.
return false;
}
#endif // Platforms without native implementation.
bool wxFileDialogBase::SetCustomizeHook(wxFileDialogCustomizeHook& customizeHook)
{
if ( !SupportsExtraControl() )

View File

@ -20,6 +20,7 @@
#endif
#include "wx/gtk/private.h"
#include "wx/gtk/private/error.h"
#include "wx/gtk/private/mnemonics.h"
#ifdef __UNIX__
@ -499,4 +500,21 @@ void wxFileDialog::GTKSelectionChanged(const wxString& filename)
UpdateExtraControlUI();
}
bool wxFileDialog::AddShortcut(const wxString& directory, int WXUNUSED(flags))
{
wxGtkError error;
if ( !gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(m_widget),
directory.utf8_str(),
error.Out()) )
{
wxLogDebug("Failed to add shortcut \"%s\": %s",
directory, error.GetMessage());
return false;
}
return true;
}
#endif // wxUSE_FILEDLG

View File

@ -352,7 +352,7 @@ void wxIFileDialog::SetTitle(const wxString& message)
}
}
void wxIFileDialog::SetInitialPath(const wxString& defaultPath)
HRESULT InitShellItemFromPath(wxCOMPtr<IShellItem>& item, const wxString& path)
{
HRESULT hr;
@ -383,20 +383,52 @@ void wxIFileDialog::SetInitialPath(const wxString& defaultPath)
if ( !s_pfnSHCreateItemFromParsingName )
{
// There is nothing we can do and the error was already reported.
return;
return E_FAIL;
}
// SHCreateItemFromParsingName() doesn't support slashes, so if the path
// uses them, replace them with the backslashes.
wxString pathBS;
const wxString* pathWithoutSlashes;
if ( path.find('/') != wxString::npos )
{
pathBS = path;
pathBS.Replace("/", "\\", true);
pathWithoutSlashes = &pathBS;
}
else // Just use the original path without copying.
{
pathWithoutSlashes = &path;
}
wxCOMPtr<IShellItem> folder;
hr = s_pfnSHCreateItemFromParsingName
(
defaultPath.wc_str(),
pathWithoutSlashes->wc_str(),
NULL,
wxIID_PPV_ARGS(IShellItem, &folder)
wxIID_PPV_ARGS(IShellItem, &item)
);
if ( FAILED(hr) )
{
wxLogApiError
(
wxString::Format(wxS("SHCreateItemFromParsingName(\"%s\")"),
*pathWithoutSlashes),
hr
);
}
// Failing to parse the folder name or set it is not really an error,
// we'll just ignore the initial directory in this case, but we should
// still show the dialog.
return hr;
}
void wxIFileDialog::SetInitialPath(const wxString& defaultPath)
{
wxCOMPtr<IShellItem> folder;
HRESULT hr = InitShellItemFromPath(folder, defaultPath);
// Failing to parse the folder name is not really an error, e.g. it might
// not exist, so we'll just ignore the initial directory in this case.
if ( SUCCEEDED(hr) )
{
hr = m_fileDialog->SetFolder(folder);
@ -405,6 +437,27 @@ void wxIFileDialog::SetInitialPath(const wxString& defaultPath)
}
}
void wxIFileDialog::AddPlace(const wxString& path, FDAP fdap)
{
wxCOMPtr<IShellItem> place;
HRESULT hr = InitShellItemFromPath(place, path);
// Don't bother with doing anything else if we couldn't parse the path
// (debug message about failing to do it was already logged).
if ( FAILED(hr) )
return;
hr = m_fileDialog->AddPlace(place, fdap);
if ( FAILED(hr) )
{
wxLogApiError
(
wxString::Format(wxS("IFileDialog::AddPlace(\"%s\")"), path), hr
);
}
}
} // namespace wxMSWImpl
// ----------------------------------------------------------------------------

View File

@ -714,6 +714,20 @@ public:
#if wxUSE_IFILEOPENDIALOG
// Store the extra shortcut directories and their flags.
struct ShortcutData
{
ShortcutData(const wxString& path_, int flags_)
: path(path_), flags(flags_)
{
}
wxString path;
int flags;
};
wxVector<ShortcutData> m_customShortcuts;
// IUnknown
wxSTDMETHODIMP QueryInterface(REFIID iid, void** ppv)
@ -1181,6 +1195,28 @@ void wxFileDialog::MSWOnInitDialogHook(WXHWND hwnd)
CreateExtraControl();
}
bool wxFileDialog::AddShortcut(const wxString& directory, int flags)
{
#if wxUSE_IFILEOPENDIALOG
if ( !HasExtraControlCreator() )
{
MSWData().m_customShortcuts.push_back(
wxFileDialogMSWData::ShortcutData(directory, flags)
);
return true;
}
else
{
// It could be surprising if AddShortcut() silently didn't work, so
// warn the developer about this incompatibility.
wxFAIL_MSG("Can't use both AddShortcut() and SetExtraControlCreator()");
}
#endif // wxUSE_IFILEOPENDIALOG
return false;
}
int wxFileDialog::ShowModal()
{
WX_HOOK_MODAL_DIALOG();
@ -1576,6 +1612,23 @@ int wxFileDialog::ShowIFileDialog(WXHWND hWndParent)
}
for ( wxVector<wxFileDialogMSWData::ShortcutData>::const_iterator
it = data.m_customShortcuts.begin();
it != data.m_customShortcuts.end();
++it )
{
FDAP fdap = FDAP_BOTTOM;
if ( it->flags & wxFD_SHORTCUT_TOP )
{
wxASSERT_MSG( !(it->flags & wxFD_SHORTCUT_BOTTOM),
wxS("Can't use both wxFD_SHORTCUT_TOP and BOTTOM") );
fdap = FDAP_TOP;
}
fileDialog.AddPlace(it->path, fdap);
}
// We never set the following flags currently:
//
// - FOS_STRICTFILETYPES

View File

@ -12,7 +12,9 @@
#
# # public symbols added in release @WX_VERSION_TAG@.2 (please keep in alphabetical order):
# @WX_VERSION_TAG@.2 {
# *wxChoice*GetCurrentSelection*;
# extern "C++"
# "wxChoice::GetCurrentSelection()";
# };
# };
#
# If a symbols should have been added in this way, but is forgotten then it
@ -21,6 +23,13 @@
# and once released its version cannot be changed.
# public symbols added in 3.2.1 (please keep in alphabetical order):
@WX_VERSION_TAG@.1 {
extern "C++" {
"wxFileDialog::AddShortcut(const wxString&, int)";
};
};
# symbols available since the beginning of this branch are only given
# generic branch tag (don't remove this!):