Allow to move item past last item
[TortoiseGit.git] / src / Utils / MiscUI / BrowseFolder.cpp
bloba59c245e160743418c15981d7138d42f0249a863
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2016 - TortoiseGit
4 // Copyright (C) 2003-2014, 2016 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include <windowsx.h>
22 #include "BrowseFolder.h"
23 #include "SmartHandle.h"
24 #include "FileDlgEventHandler.h"
25 #include <strsafe.h>
27 BOOL CBrowseFolder::m_bCheck = FALSE;
28 BOOL CBrowseFolder::m_bCheck2 = FALSE;
29 CString CBrowseFolder::m_sDefaultPath;
31 class BrowseFolderDlgEventHandler : public CFileDlgEventHandler
33 public:
34 BrowseFolderDlgEventHandler()
35 : m_DisableCheckbox2WhenCheckbox1IsChecked(false)
39 bool m_DisableCheckbox2WhenCheckbox1IsChecked;
41 STDMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *pfdc, DWORD dwIDCtl, BOOL bChecked) override
43 if (m_DisableCheckbox2WhenCheckbox1IsChecked && dwIDCtl == 101)
45 if (bChecked)
46 pfdc->SetControlState(102, CDCS_VISIBLE | CDCS_INACTIVE);
47 else
48 pfdc->SetControlState(102, CDCS_VISIBLE | CDCS_ENABLED);
50 return S_OK;
54 CBrowseFolder::CBrowseFolder(void)
55 : m_style(0)
56 , m_DisableCheckbox2WhenCheckbox1IsChecked(false)
58 SecureZeroMemory(&m_title, sizeof(m_title));
61 CBrowseFolder::~CBrowseFolder(void)
65 //show the dialog
66 CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, LPTSTR path, size_t pathlen, LPCTSTR szDefaultPath /* = nullptr */)
68 CString temp;
69 temp = path;
70 CString sDefault;
71 if (szDefaultPath)
72 sDefault = szDefaultPath;
73 CBrowseFolder::retVal ret = Show(parent, temp, sDefault);
74 wcscpy_s(path, pathlen, temp);
75 return ret;
77 CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, CString& path, const CString& sDefaultPath /* = CString() */)
79 m_sDefaultPath = sDefaultPath;
80 if (m_sDefaultPath.IsEmpty() && !path.IsEmpty())
82 while (!PathFileExists(path) && !path.IsEmpty())
84 CString p = path.Left(path.ReverseFind(L'\\'));
85 if ((p.GetLength() == 2) && (p[1] == L':'))
87 p += L'\\';
88 if (p.Compare(path) == 0)
89 p.Empty();
91 if (p.GetLength() < 2)
92 p.Empty();
93 path = p;
95 // if the result path already contains a path, use that as the default path
96 m_sDefaultPath = path;
99 // Create a new common open file dialog
100 CComPtr<IFileOpenDialog> pfd;
101 if (FAILED(pfd.CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER)))
102 return CANCEL;
104 // Set the dialog as a folder picker
105 DWORD dwOptions;
106 if (FAILED(pfd->GetOptions(&dwOptions)))
107 return CANCEL;
108 if (FAILED(pfd->SetOptions(dwOptions | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST)))
109 return CANCEL;
111 // Set a title
112 TCHAR* nl = wcschr(m_title, L'\n');
113 if (nl)
114 *nl = L'\0';
115 pfd->SetTitle(m_title);
117 // set the default folder
118 CComPtr<IShellItem> psiDefault;
119 if (FAILED(SHCreateItemFromParsingName(m_sDefaultPath, nullptr, IID_PPV_ARGS(&psiDefault))))
120 return CANCEL;
121 if (FAILED(pfd->SetFolder(psiDefault)))
122 return CANCEL;
124 CComObjectStackEx<BrowseFolderDlgEventHandler> cbk;
125 cbk.m_DisableCheckbox2WhenCheckbox1IsChecked = m_DisableCheckbox2WhenCheckbox1IsChecked;
126 CComQIPtr<IFileDialogEvents> pEvents = cbk.GetUnknown();
128 if (!m_CheckText.IsEmpty())
130 CComPtr<IFileDialogCustomize> pfdCustomize;
131 if (FAILED(pfd.QueryInterface(&pfdCustomize)))
132 return CANCEL;
134 pfdCustomize->StartVisualGroup(100, L"");
135 pfdCustomize->AddCheckButton(101, m_CheckText, FALSE);
136 if (!m_CheckText2.IsEmpty())
137 pfdCustomize->AddCheckButton(102, m_CheckText2, FALSE);
138 pfdCustomize->EndVisualGroup();
141 DWORD eventsCookie;
142 if (FAILED(pfd->Advise(pEvents, &eventsCookie)))
143 return CANCEL;
144 SCOPE_EXIT { pfd->Unadvise(eventsCookie); };
146 // Show the open file dialog
147 if (FAILED(pfd->Show(parent)))
148 return CANCEL;
150 // Get the selection from the user
151 CComPtr<IShellItem> psiResult;
152 if (FAILED(pfd->GetResult(&psiResult)))
153 return CANCEL;
155 PWSTR pszPath = nullptr;
156 if (SUCCEEDED(psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath)))
158 path = pszPath;
159 CoTaskMemFree(pszPath);
162 CComPtr<IFileDialogCustomize> pfdCustomize;
163 if (SUCCEEDED(pfd.QueryInterface(&pfdCustomize)))
165 pfdCustomize->GetCheckButtonState(101, &m_bCheck);
166 pfdCustomize->GetCheckButtonState(102, &m_bCheck2);
169 return OK;
172 void CBrowseFolder::SetInfo(LPCTSTR title)
174 ASSERT(title);
176 if (title)
177 wcscpy_s(m_title, title);
180 void CBrowseFolder::SetCheckBoxText(LPCTSTR checktext)
182 ASSERT(checktext);
184 if (checktext)
185 m_CheckText = checktext;
188 void CBrowseFolder::SetCheckBoxText2(LPCTSTR checktext)
190 ASSERT(checktext);
192 if (checktext)
193 m_CheckText2 = checktext;