// WinMerge: an interactive diff/merge utility
// Copyright (C) 1997-2000 Thingamahoochie Software
// Author: Dean Grimm
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
+// SPDX-License-Identifier: GPL-2.0-or-later
/////////////////////////////////////////////////////////////////////////////
/**
* @file FileOrFolderSelect.cpp
* @brief Implementation of the file and folder selection routines.
*/
+#include "pch.h"
#include <windows.h>
#include "FileOrFolderSelect.h"
+#pragma warning (push) // prevent "warning C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared"
+#pragma warning (disable:4091) // VC bug when using XP enabled toolsets.
#include <shlobj.h>
+#pragma warning (pop)
#include <sys/stat.h>
#include "Environment.h"
#include "paths.h"
#include "MergeApp.h"
-#include "resource.h"
-
-// VC 6 headers don't define these constants for folder browse dialog
-// so define them here. Copied from shlobj.h
-#ifndef BIF_EDITBOX
-#define BIF_EDITBOX 0x0010 // Add an editbox to the dialog
-#endif
-#ifndef BIF_NEWDIALOGSTYLE
-#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
- // Caller needs to call OleInitialize() before using this API
-#endif
-#ifndef BIF_USENEWUI
-#define BIF_USENEWUI (BIF_NEWDIALOGSTYLE | BIF_EDITBOX)
-#endif
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam,
LPARAM lpData);
* file or folder to open or file to save. The last parameter @p is_open selects
* between open or save modes. Biggest difference is that in save-mode Windows
* asks if user wants to override existing file.
- * @param [in] parent Handle to parent window. Can be a NULL, but then
+ * @param [in] parent Handle to parent window. Can be `nullptr`, but then
* CMainFrame is used which can cause modality problems.
* @param [out] path Selected path is returned in this string
* @param [in] initialPath Initial path (and file) shown when dialog is opened
* @param [in] filterid 0 or STRING ID for filter string
* - 0 means "All files (*.*)". Note the string formatting!
* @param [in] is_open Selects Open/Save -dialog (mode).
- * @note Be careful when setting @p parent to NULL as there are potential
+ * @note Be careful when setting @p parent to `nullptr` as there are potential
* modality problems with this. Dialog can be lost behind other windows!
* @param [in] defaultExtension Extension to append if user doesn't provide one
*/
-BOOL SelectFile(HWND parent, String& path, LPCTSTR initialPath /*=NULL*/,
- const String& stitle /*=_T("")*/, const String& sfilter /*=_T("")*/,
- BOOL is_open /*=TRUE*/, LPCTSTR defaultExtension /*=NULL*/)
+bool SelectFile(HWND parent, String& path, bool is_open /*= true*/,
+ LPCTSTR initialPath /*= nullptr*/, const String& stitle /*=_T("")*/,
+ const String& sfilter /*=_T("")*/, LPCTSTR defaultExtension /*= nullptr*/)
{
path.clear(); // Clear output param
// This will tell common file dialog what to show
// and also this will hold its return value
- TCHAR sSelectedFile[MAX_PATH] = {0};
+ TCHAR sSelectedFile[MAX_PATH_FULL] = {0};
+ String sInitialDir;
// check if specified path is a file
if (initialPath && initialPath[0])
// If initial path info includes a file
// we put the bare filename into sSelectedFile
// so the common file dialog will start up with that file selected
- if (paths_DoesPathExist(initialPath) == IS_EXISTING_FILE)
+ if (paths::DoesPathExist(initialPath) == paths::IS_EXISTING_FILE)
{
String temp;
- paths_SplitFilename(initialPath, 0, &temp, 0);
+ paths::SplitFilename(initialPath, 0, &temp, 0);
lstrcpy(sSelectedFile, temp.c_str());
+ sInitialDir = paths::GetParentPath(initialPath);
+ }
+ else
+ {
+ sInitialDir = initialPath;
}
}
if (sfilter.empty())
filters = _("All Files (*.*)|*.*||");
if (stitle.empty())
- title = _("Open");
+ {
+ title = is_open ? _("Open") : _("Save As");
+ }
// Convert extension mask from MFC style separators ('|')
// to Win32 style separators ('\0')
LPTSTR filtersStr = &*filters.begin();
ConvertFilter(filtersStr);
- OPENFILENAME_NT4 ofn;
- memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
+ OPENFILENAME_NT4 ofn = { sizeof OPENFILENAME_NT4 };
ofn.hwndOwner = parent;
ofn.lpstrFilter = filtersStr;
- ofn.lpstrCustomFilter = NULL;
+ ofn.lpstrCustomFilter = nullptr;
ofn.nFilterIndex = 1;
ofn.lpstrFile = sSelectedFile;
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrInitialDir = initialPath;
+ ofn.nMaxFile = MAX_PATH_FULL;
+ ofn.lpstrInitialDir = sInitialDir.empty() ? nullptr : sInitialDir.c_str();
ofn.lpstrTitle = title.c_str();
- ofn.lpstrFileTitle = NULL;
+ ofn.lpstrFileTitle = nullptr;
if (defaultExtension)
ofn.lpstrDefExt = defaultExtension;
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
- BOOL bRetVal = FALSE;
+ bool bRetVal = false;
if (is_open)
- bRetVal = GetOpenFileName((OPENFILENAME *)&ofn);
+ bRetVal = !!GetOpenFileName((OPENFILENAME *)&ofn);
else
- bRetVal = GetSaveFileName((OPENFILENAME *)&ofn);
+ bRetVal = !!GetSaveFileName((OPENFILENAME *)&ofn);
// common file dialog populated sSelectedFile variable's buffer
if (bRetVal)
* @param [out] path Selected path is returned in this string
* @param [in] root_path Initial path shown when dialog is opened
* @param [in] titleid Resource string ID for dialog title.
- * @param [in] hwndOwner Handle to owner window or NULL
- * @return TRUE if valid folder selected (not cancelled)
+ * @param [in] hwndOwner Handle to owner window or `nullptr`
+ * @return `true` if valid folder selected (not cancelled)
*/
-BOOL SelectFolder(String& path, LPCTSTR root_path /*=NULL*/,
+bool SelectFolder(String& path, LPCTSTR root_path /*= nullptr*/,
const String& stitle /*=_T("")*/,
- HWND hwndOwner /*=NULL*/)
+ HWND hwndOwner /*= nullptr*/)
{
BROWSEINFO bi;
- LPMALLOC pMalloc;
LPITEMIDLIST pidl;
- TCHAR szPath[MAX_PATH] = {0};
- BOOL bRet = FALSE;
+ TCHAR szPath[MAX_PATH_FULL] = {0};
+ bool bRet = false;
String title = stitle;
- if (root_path == NULL)
+ if (root_path == nullptr)
LastSelectedFolder.clear();
else
LastSelectedFolder = root_path;
bi.hwndOwner = hwndOwner;
- bi.pidlRoot = NULL; // Start from desktop folder
+ bi.pidlRoot = nullptr; // Start from desktop folder
bi.pszDisplayName = szPath;
bi.lpszTitle = title.c_str();
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI | BIF_VALIDATE;
bi.lParam = (LPARAM)root_path;
pidl = SHBrowseForFolder(&bi);
-
- if (pidl)
+ if (pidl != nullptr)
{
if (SHGetPathFromIDList(pidl, szPath))
{
path = szPath;
- bRet = TRUE;
+ bRet = true;
}
-
- SHGetMalloc(&pMalloc);
- pMalloc->Free(pidl);
- pMalloc->Release();
+ CoTaskMemFree(pidl);
}
return bRet;
}
// Look for BFFM_INITIALIZED
if (uMsg == BFFM_INITIALIZED)
{
- if (lpData)
+ if (lpData != NULL)
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
else
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)LastSelectedFolder.c_str());
}
else if (uMsg == BFFM_VALIDATEFAILED)
{
- String strMessage = (TCHAR *)lParam;
- strMessage += _T("\83t\83H\83\8b\83_\82Í\91¶\8dÝ\82µ\82Ü\82¹\82ñ\81B\8dì\90¬\82µ\82Ü\82·\82©?");
- int answer = MessageBox(hwnd, strMessage.c_str(), _T("\83t\83H\83\8b\83_\82Ì\8dì\90¬"), MB_YESNO);
+ String strMessage =
+ strutils::format_string1(_("%1 does not exist. Do you want to create it?"), (TCHAR *)lParam);
+ int answer = MessageBox(hwnd, strMessage.c_str(), nullptr, MB_YESNO);
if (answer == IDYES)
{
- if (!paths_CreateIfNeeded((TCHAR*)lParam))
+ if (!paths::CreateIfNeeded((TCHAR*)lParam))
{
- MessageBox(hwnd, _T("\83t\83H\83\8b\83_\82Ì\8dì\90¬\82É\8e¸\94s\82µ\82Ü\82µ\82½"), _T("\83t\83H\83\8b\83_\82Ì\8dì\90¬"), MB_OK | MB_ICONWARNING);
+ MessageBox(hwnd, _("Failed to create folder.").c_str(), nullptr, MB_OK | MB_ICONWARNING);
}
}
return 1;
* - If existing filename is selected return it
* - If filename in (CFileDialog) editbox and current folder doesn't form
* a valid path to file, return current folder.
- * @param [in] parent Handle to parent window. Can be a NULL, but then
+ * @param [in] parent Handle to parent window. Can be `nullptr`, but then
* CMainFrame is used which can cause modality problems.
* @param [out] path Selected folder/filename
* @param [in] initialPath Initial file or folder shown/selected.
- * @return TRUE if user choosed a file/folder, FALSE if user canceled dialog.
+ * @return `true` if user choosed a file/folder, `false` if user canceled dialog.
*/
-BOOL SelectFileOrFolder(HWND parent, String& path, LPCTSTR initialPath /*=NULL*/)
+bool SelectFileOrFolder(HWND parent, String& path, LPCTSTR initialPath /*= nullptr*/)
{
String title = _("Open");
// This will tell common file dialog what to show
// and also this will hold its return value
- TCHAR sSelectedFile[MAX_PATH];
+ TCHAR sSelectedFile[MAX_PATH_FULL];
// check if specified path is a file
- if (initialPath && initialPath[0])
+ if (initialPath!=nullptr && initialPath[0] != '\0')
{
// If initial path info includes a file
// we put the bare filename into sSelectedFile
// so the common file dialog will start up with that file selected
- if (paths_DoesPathExist(initialPath) == IS_EXISTING_FILE)
+ if (paths::DoesPathExist(initialPath) == paths::IS_EXISTING_FILE)
{
String temp;
- paths_SplitFilename(initialPath, 0, &temp, 0);
+ paths::SplitFilename(initialPath, 0, &temp, 0);
lstrcpy(sSelectedFile, temp.c_str());
}
}
dirSelTag += _T("."); // Treat it as filename
lstrcpy(sSelectedFile, dirSelTag.c_str()); // What is assignment above good for?
- OPENFILENAME_NT4 ofn;
- memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
+ OPENFILENAME_NT4 ofn = { sizeof OPENFILENAME_NT4 };
ofn.hwndOwner = parent;
ofn.lpstrFilter = filtersStr;
- ofn.lpstrCustomFilter = NULL;
+ ofn.lpstrCustomFilter = nullptr;
ofn.nFilterIndex = 1;
ofn.lpstrFile = sSelectedFile;
- ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFile = MAX_PATH_FULL;
ofn.lpstrInitialDir = initialPath;
ofn.lpstrTitle = title.c_str();
- ofn.lpstrFileTitle = NULL;
+ ofn.lpstrFileTitle = nullptr;
ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOTESTFILECREATE | OFN_NOCHANGEDIR;
- BOOL bRetVal = GetOpenFileName((OPENFILENAME *)&ofn);
+ bool bRetVal = !!GetOpenFileName((OPENFILENAME *)&ofn);
if (bRetVal)
{
path = sSelectedFile;
- struct _stati64 statBuffer;
- int nRetVal = _tstati64(path.c_str(), &statBuffer);
- if (nRetVal == -1)
+ if (paths::DoesPathExist(path) == paths::DOES_NOT_EXIST)
{
// We have a valid folder name, but propably garbage as a filename.
// Return folder name
- String folder = paths_GetPathOnly(sSelectedFile);
- path = paths_AddTrailingSlash(folder);
+ String folder = paths::GetPathOnly(sSelectedFile);
+ path = paths::AddTrailingSlash(folder);
}
}
return bRetVal;
*/
static void ConvertFilter(LPTSTR filterStr)
{
- while (TCHAR *ch = _tcschr(filterStr, '|'))
+ TCHAR *ch;
+ while ( (ch = _tcschr(filterStr, '|')) != nullptr)
{
filterStr = ch + 1;
*ch = '\0';