Correctly deallocate buffer
[TortoiseGit.git] / src / Utils / MiscUI / BrowseFolder.cpp
blob1958160c7ae03c7806d69824e25bc1b618ff4147
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2012 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include <windowsx.h>
21 #include "BrowseFolder.h"
22 #include <strsafe.h>
24 BOOL CBrowseFolder::m_bCheck = FALSE;
25 BOOL CBrowseFolder::m_bCheck2 = FALSE;
26 WNDPROC CBrowseFolder::CBProc = NULL;
27 HWND CBrowseFolder::checkbox = NULL;
28 HWND CBrowseFolder::checkbox2 = NULL;
29 HWND CBrowseFolder::ListView = NULL;
30 TCHAR CBrowseFolder::m_CheckText[200];
31 TCHAR CBrowseFolder::m_CheckText2[200];
32 CString CBrowseFolder::m_sDefaultPath;
33 bool CBrowseFolder::m_DisableCheckbox2WhenCheckbox1IsChecked = false;
36 CBrowseFolder::CBrowseFolder(void)
37 : m_style(0),
38 m_root(NULL)
40 memset(m_displayName, 0, sizeof(m_displayName));
41 memset(m_title, 0, sizeof(m_title));
42 memset(m_CheckText, 0, sizeof(m_CheckText));
45 CBrowseFolder::~CBrowseFolder(void)
49 //show the dialog
50 CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, LPTSTR path, size_t pathlen, LPCTSTR szDefaultPath /* = NULL */)
52 CString temp;
53 temp = path;
54 CString sDefault;
55 if (szDefaultPath)
56 sDefault = szDefaultPath;
57 CBrowseFolder::retVal ret = Show(parent, temp, sDefault);
58 _tcscpy_s(path, pathlen, temp);
59 return ret;
61 CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, CString& path, const CString& sDefaultPath /* = CString() */)
63 retVal ret = OK; //assume OK
64 m_sDefaultPath = sDefaultPath;
65 if (m_sDefaultPath.IsEmpty() && !path.IsEmpty())
67 // if the result path already contains a path, use that as the default path
68 m_sDefaultPath = path;
70 LPITEMIDLIST itemIDList;
72 BROWSEINFO browseInfo;
74 browseInfo.hwndOwner = parent;
75 browseInfo.pidlRoot = m_root;
76 browseInfo.pszDisplayName = m_displayName;
77 browseInfo.lpszTitle = m_title;
78 browseInfo.ulFlags = m_style;
79 browseInfo.lpfn = NULL;
80 browseInfo.lParam = (LPARAM)this;
82 if ((_tcslen(m_CheckText) > 0)||(!m_sDefaultPath.IsEmpty()))
84 browseInfo.lpfn = BrowseCallBackProc;
87 itemIDList = SHBrowseForFolder(&browseInfo);
89 //is the dialog canceled?
90 if (!itemIDList)
91 ret = CANCEL;
93 if (ret != CANCEL)
95 if (!SHGetPathFromIDList(itemIDList, path.GetBuffer(MAX_PATH))) // MAX_PATH ok. Explorer can't handle paths longer than MAX_PATH.
96 ret = NOPATH;
98 path.ReleaseBuffer();
100 LPMALLOC shellMalloc;
101 HRESULT hr;
103 hr = SHGetMalloc(&shellMalloc);
105 if (SUCCEEDED(hr))
107 //free memory
108 shellMalloc->Free(itemIDList);
109 //release interface
110 shellMalloc->Release();
113 return ret;
116 void CBrowseFolder::SetInfo(LPCTSTR title)
118 ASSERT(title);
120 if (title)
121 _tcscpy_s(m_title, 200, title);
124 void CBrowseFolder::SetCheckBoxText(LPCTSTR checktext)
126 ASSERT(checktext);
128 if (checktext)
129 _tcscpy_s(m_CheckText, 200, checktext);
132 void CBrowseFolder::SetCheckBoxText2(LPCTSTR checktext)
134 ASSERT(checktext);
136 if (checktext)
137 _tcscpy_s(m_CheckText2, 200, checktext);
140 void CBrowseFolder::SetFont(HWND hwnd,LPTSTR FontName,int FontSize)
143 HFONT hf;
144 LOGFONT lf={0};
145 HDC hdc=GetDC(hwnd);
147 GetObject(GetWindowFont(hwnd),sizeof(lf),&lf);
148 lf.lfWeight = FW_REGULAR;
149 lf.lfHeight = (LONG)FontSize;
150 StringCchCopy( lf.lfFaceName, _countof(lf.lfFaceName), FontName );
151 hf=CreateFontIndirect(&lf);
152 SetBkMode(hdc,OPAQUE);
153 SendMessage(hwnd,WM_SETFONT,(WPARAM)hf,TRUE);
154 ReleaseDC(hwnd,hdc);
158 int CBrowseFolder::BrowseCallBackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM /*lpData*/)
160 RECT ListViewRect,Dialog;
161 //Initialization callback message
162 if (uMsg == BFFM_INITIALIZED)
164 if (_tcslen(m_CheckText) > 0)
166 bool bSecondCheckbox = (_tcslen(m_CheckText2)!=0);
167 //Rectangles for getting the positions
168 checkbox = CreateWindowEx( 0,
169 _T("BUTTON"),
170 m_CheckText,
171 WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|BS_AUTOCHECKBOX,
172 0,100,100,50,
173 hwnd,
175 NULL,
176 NULL);
177 if (checkbox == NULL)
178 return 0;
180 if (bSecondCheckbox)
182 //Rectangles for getting the positions
183 checkbox2 = CreateWindowEx( 0,
184 _T("BUTTON"),
185 m_CheckText2,
186 WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|BS_AUTOCHECKBOX,
187 0,100,100,50,
188 hwnd,
190 NULL,
191 NULL);
192 if (checkbox2 == NULL)
193 return 0;
196 ListView = FindWindowEx(hwnd,NULL,_T("SysTreeView32"),NULL);
197 if (ListView == NULL)
198 ListView = FindWindowEx(hwnd,NULL,_T("SHBrowseForFolder ShellNameSpace Control"),NULL);
200 if (ListView == NULL)
201 return 0;
203 //Gets the dimensions of the windows
204 GetWindowRect(hwnd,&Dialog);
205 GetWindowRect(ListView,&ListViewRect);
206 POINT pt;
207 pt.x = ListViewRect.left;
208 pt.y = ListViewRect.top;
209 ScreenToClient(hwnd, &pt);
210 ListViewRect.top = pt.y;
211 ListViewRect.left = pt.x;
212 pt.x = ListViewRect.right;
213 pt.y = ListViewRect.bottom;
214 ScreenToClient(hwnd, &pt);
215 ListViewRect.bottom = pt.y;
216 ListViewRect.right = pt.x;
217 //Sets the list view controls dimensions
218 SetWindowPos(ListView,0,ListViewRect.left,
219 bSecondCheckbox ? ListViewRect.top+40 : ListViewRect.top+20,
220 (ListViewRect.right-ListViewRect.left),
221 bSecondCheckbox ? (ListViewRect.bottom - ListViewRect.top)-40 : (ListViewRect.bottom - ListViewRect.top)-20,
222 SWP_NOZORDER);
223 //Sets the window positions of checkbox and dialog controls
224 SetWindowPos(checkbox,HWND_BOTTOM,ListViewRect.left,
225 ListViewRect.top,
226 (ListViewRect.right-ListViewRect.left),
228 SWP_NOZORDER);
229 if (bSecondCheckbox)
231 SetWindowPos(checkbox2,HWND_BOTTOM,ListViewRect.left,
232 ListViewRect.top+20,
233 (ListViewRect.right-ListViewRect.left),
235 SWP_NOZORDER);
237 HWND label = FindWindowEx(hwnd, NULL, _T("STATIC"), NULL);
238 if (label)
240 HFONT hFont = (HFONT)::SendMessage(label, WM_GETFONT, 0, 0);
241 LOGFONT lf = {0};
242 GetObject(hFont, sizeof(lf), &lf);
243 HFONT hf2 = CreateFontIndirect(&lf);
244 ::SendMessage(checkbox, WM_SETFONT, (WPARAM)hf2, TRUE);
245 if (bSecondCheckbox)
246 ::SendMessage(checkbox2, WM_SETFONT, (WPARAM)hf2, TRUE);
248 else
250 //Sets the fonts of static controls
251 SetFont(checkbox,_T("MS Sans Serif"),12);
252 if (bSecondCheckbox)
253 SetFont(checkbox2,_T("MS Sans Serif"),12);
256 // Subclass the checkbox control.
257 CBProc = (WNDPROC) SetWindowLongPtr(checkbox,GWLP_WNDPROC, (LONG_PTR) CheckBoxSubclassProc);
258 //Sets the checkbox to checked position
259 SendMessage(checkbox,BM_SETCHECK,(WPARAM)m_bCheck,0);
260 if (bSecondCheckbox)
262 CBProc = (WNDPROC) SetWindowLongPtr(checkbox2,GWLP_WNDPROC, (LONG_PTR) CheckBoxSubclassProc2);
263 SendMessage(checkbox2,BM_SETCHECK,(WPARAM)m_bCheck,0);
265 // send a resize message to the resized list view control. Otherwise it won't show
266 // up properly until the user resizes the window!
267 SendMessage(ListView, WM_SIZE, SIZE_RESTORED, MAKELONG(ListViewRect.right-ListViewRect.left, bSecondCheckbox ? (ListViewRect.bottom - ListViewRect.top)-40 : (ListViewRect.bottom - ListViewRect.top)-20));
270 // now set the default directory
271 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)m_sDefaultPath);
273 if (uMsg == BFFM_SELCHANGED)
275 // Set the status window to the currently selected path.
276 TCHAR szDir[MAX_PATH];
277 if (SHGetPathFromIDList((LPITEMIDLIST)lParam, szDir))
279 SendMessage(hwnd,BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
283 return 0;
286 LRESULT CBrowseFolder::CheckBoxSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
288 if (uMsg == WM_LBUTTONUP)
290 m_bCheck = (SendMessage(hwnd,BM_GETCHECK,0,0)==BST_UNCHECKED);
291 if (m_bCheck && m_DisableCheckbox2WhenCheckbox1IsChecked)
293 ::EnableWindow(checkbox2, !m_bCheck);
295 else
296 ::EnableWindow(checkbox2, true);
299 return CallWindowProc(CBProc, hwnd, uMsg,
300 wParam, lParam);
303 LRESULT CBrowseFolder::CheckBoxSubclassProc2(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
305 if (uMsg == WM_LBUTTONUP)
307 m_bCheck2 = (SendMessage(hwnd,BM_GETCHECK,0,0)==BST_UNCHECKED);
310 return CallWindowProc(CBProc, hwnd, uMsg,
311 wParam, lParam);