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.
21 #include "BrowseFolder.h"
22 #include "SmartHandle.h"
25 BOOL
CBrowseFolder::m_bCheck
= FALSE
;
26 BOOL
CBrowseFolder::m_bCheck2
= FALSE
;
27 WNDPROC
CBrowseFolder::CBProc
= NULL
;
28 HWND
CBrowseFolder::checkbox
= NULL
;
29 HWND
CBrowseFolder::checkbox2
= NULL
;
30 HWND
CBrowseFolder::ListView
= NULL
;
31 TCHAR
CBrowseFolder::m_CheckText
[200];
32 TCHAR
CBrowseFolder::m_CheckText2
[200];
33 CString
CBrowseFolder::m_sDefaultPath
;
34 bool CBrowseFolder::m_DisableCheckbox2WhenCheckbox1IsChecked
= false;
37 CBrowseFolder::CBrowseFolder(void)
41 memset(m_displayName
, 0, sizeof(m_displayName
));
42 memset(m_title
, 0, sizeof(m_title
));
43 memset(m_CheckText
, 0, sizeof(m_CheckText
));
46 CBrowseFolder::~CBrowseFolder(void)
51 CBrowseFolder::retVal
CBrowseFolder::Show(HWND parent
, LPTSTR path
, size_t pathlen
, LPCTSTR szDefaultPath
/* = NULL */)
57 sDefault
= szDefaultPath
;
58 CBrowseFolder::retVal ret
= Show(parent
, temp
, sDefault
);
59 _tcscpy_s(path
, pathlen
, temp
);
62 CBrowseFolder::retVal
CBrowseFolder::Show(HWND parent
, CString
& path
, const CString
& sDefaultPath
/* = CString() */)
64 retVal ret
= OK
; //assume OK
65 m_sDefaultPath
= sDefaultPath
;
66 if (m_sDefaultPath
.IsEmpty() && !path
.IsEmpty())
68 // if the result path already contains a path, use that as the default path
69 m_sDefaultPath
= path
;
74 // Create a new common open file dialog
75 IFileOpenDialog
* pfd
= NULL
;
76 hr
= CoCreateInstance(CLSID_FileOpenDialog
, NULL
, CLSCTX_INPROC_SERVER
, IID_PPV_ARGS(&pfd
));
79 // Set the dialog as a folder picker
81 if (SUCCEEDED(hr
= pfd
->GetOptions(&dwOptions
)))
83 hr
= pfd
->SetOptions(dwOptions
| FOS_PICKFOLDERS
| FOS_FORCEFILESYSTEM
| FOS_PATHMUSTEXIST
);
89 TCHAR
* nl
= _tcschr(m_title
, '\n');
92 pfd
->SetTitle(m_title
);
95 // set the default folder
98 typedef HRESULT (WINAPI
*SHCIFPN
)(PCWSTR pszPath
, IBindCtx
* pbc
, REFIID riid
, void ** ppv
);
100 CAutoLibrary hLib
= AtlLoadSystemLibraryUsingFullPath(L
"shell32.dll");
103 SHCIFPN pSHCIFPN
= (SHCIFPN
)GetProcAddress(hLib
, "SHCreateItemFromParsingName");
106 IShellItem
*psiDefault
= 0;
107 hr
= pSHCIFPN(m_sDefaultPath
, NULL
, IID_PPV_ARGS(&psiDefault
));
110 hr
= pfd
->SetFolder(psiDefault
);
111 psiDefault
->Release();
117 if (m_CheckText
[0] != 0)
119 IFileDialogCustomize
* pfdCustomize
= 0;
120 hr
= pfd
->QueryInterface(IID_PPV_ARGS(&pfdCustomize
));
123 pfdCustomize
->StartVisualGroup(100, L
"");
124 pfdCustomize
->AddCheckButton(101, m_CheckText
, FALSE
);
125 if (m_CheckText2
[0] != 0)
127 pfdCustomize
->AddCheckButton(102, m_CheckText2
, FALSE
);
129 pfdCustomize
->EndVisualGroup();
130 pfdCustomize
->Release();
134 // Show the open file dialog
135 if (SUCCEEDED(hr
) && SUCCEEDED(hr
= pfd
->Show(parent
)))
137 // Get the selection from the user
138 IShellItem
* psiResult
= NULL
;
139 hr
= pfd
->GetResult(&psiResult
);
142 PWSTR pszPath
= NULL
;
143 hr
= psiResult
->GetDisplayName(SIGDN_FILESYSPATH
, &pszPath
);
147 CoTaskMemFree(pszPath
);
149 psiResult
->Release();
151 IFileDialogCustomize
* pfdCustomize
= 0;
152 hr
= pfd
->QueryInterface(IID_PPV_ARGS(&pfdCustomize
));
155 pfdCustomize
->GetCheckButtonState(101, &m_bCheck
);
156 pfdCustomize
->GetCheckButtonState(102, &m_bCheck2
);
157 pfdCustomize
->Release();
170 BROWSEINFO browseInfo
= {};
171 browseInfo
.hwndOwner
= parent
;
172 browseInfo
.pidlRoot
= m_root
;
173 browseInfo
.pszDisplayName
= m_displayName
;
174 browseInfo
.lpszTitle
= m_title
;
175 browseInfo
.ulFlags
= m_style
;
176 browseInfo
.lParam
= (LPARAM
)this;
178 if ((_tcslen(m_CheckText
) > 0)||(!m_sDefaultPath
.IsEmpty()))
180 browseInfo
.lpfn
= BrowseCallBackProc
;
183 PCIDLIST_ABSOLUTE itemIDList
= SHBrowseForFolder(&browseInfo
);
185 //is the dialog canceled?
191 if (!SHGetPathFromIDList(itemIDList
, path
.GetBuffer(MAX_PATH
))) // MAX_PATH ok. Explorer can't handle paths longer than MAX_PATH.
194 path
.ReleaseBuffer();
196 CoTaskMemFree((LPVOID
)itemIDList
);
203 void CBrowseFolder::SetInfo(LPCTSTR title
)
208 _tcscpy_s(m_title
, 200, title
);
211 void CBrowseFolder::SetCheckBoxText(LPCTSTR checktext
)
216 _tcscpy_s(m_CheckText
, 200, checktext
);
219 void CBrowseFolder::SetCheckBoxText2(LPCTSTR checktext
)
224 _tcscpy_s(m_CheckText2
, 200, checktext
);
227 void CBrowseFolder::SetFont(HWND hwnd
,LPTSTR FontName
,int FontSize
)
234 GetObject(GetWindowFont(hwnd
),sizeof(lf
),&lf
);
235 lf
.lfWeight
= FW_REGULAR
;
236 lf
.lfHeight
= (LONG
)FontSize
;
237 StringCchCopy( lf
.lfFaceName
, _countof(lf
.lfFaceName
), FontName
);
238 hf
=CreateFontIndirect(&lf
);
239 SetBkMode(hdc
,OPAQUE
);
240 SendMessage(hwnd
,WM_SETFONT
,(WPARAM
)hf
,TRUE
);
245 int CBrowseFolder::BrowseCallBackProc(HWND hwnd
, UINT uMsg
, LPARAM lParam
, LPARAM
/*lpData*/)
247 RECT ListViewRect
,Dialog
;
248 //Initialization callback message
249 if (uMsg
== BFFM_INITIALIZED
)
251 if (_tcslen(m_CheckText
) > 0)
253 bool bSecondCheckbox
= (_tcslen(m_CheckText2
)!=0);
254 //Rectangles for getting the positions
255 checkbox
= CreateWindowEx( 0,
258 WS_CHILD
|WS_VISIBLE
|WS_CLIPCHILDREN
|BS_AUTOCHECKBOX
,
264 if (checkbox
== NULL
)
269 //Rectangles for getting the positions
270 checkbox2
= CreateWindowEx( 0,
273 WS_CHILD
|WS_VISIBLE
|WS_CLIPCHILDREN
|BS_AUTOCHECKBOX
,
279 if (checkbox2
== NULL
)
283 ListView
= FindWindowEx(hwnd
,NULL
,_T("SysTreeView32"),NULL
);
284 if (ListView
== NULL
)
285 ListView
= FindWindowEx(hwnd
,NULL
,_T("SHBrowseForFolder ShellNameSpace Control"),NULL
);
287 if (ListView
== NULL
)
290 //Gets the dimensions of the windows
291 GetWindowRect(hwnd
,&Dialog
);
292 GetWindowRect(ListView
,&ListViewRect
);
294 pt
.x
= ListViewRect
.left
;
295 pt
.y
= ListViewRect
.top
;
296 ScreenToClient(hwnd
, &pt
);
297 ListViewRect
.top
= pt
.y
;
298 ListViewRect
.left
= pt
.x
;
299 pt
.x
= ListViewRect
.right
;
300 pt
.y
= ListViewRect
.bottom
;
301 ScreenToClient(hwnd
, &pt
);
302 ListViewRect
.bottom
= pt
.y
;
303 ListViewRect
.right
= pt
.x
;
304 //Sets the list view controls dimensions
305 SetWindowPos(ListView
,0,ListViewRect
.left
,
306 bSecondCheckbox
? ListViewRect
.top
+40 : ListViewRect
.top
+20,
307 (ListViewRect
.right
-ListViewRect
.left
),
308 bSecondCheckbox
? (ListViewRect
.bottom
- ListViewRect
.top
)-40 : (ListViewRect
.bottom
- ListViewRect
.top
)-20,
310 //Sets the window positions of checkbox and dialog controls
311 SetWindowPos(checkbox
,HWND_BOTTOM
,ListViewRect
.left
,
313 (ListViewRect
.right
-ListViewRect
.left
),
318 SetWindowPos(checkbox2
,HWND_BOTTOM
,ListViewRect
.left
,
320 (ListViewRect
.right
-ListViewRect
.left
),
324 HWND label
= FindWindowEx(hwnd
, NULL
, _T("STATIC"), NULL
);
327 HFONT hFont
= (HFONT
)::SendMessage(label
, WM_GETFONT
, 0, 0);
329 GetObject(hFont
, sizeof(lf
), &lf
);
330 HFONT hf2
= CreateFontIndirect(&lf
);
331 ::SendMessage(checkbox
, WM_SETFONT
, (WPARAM
)hf2
, TRUE
);
333 ::SendMessage(checkbox2
, WM_SETFONT
, (WPARAM
)hf2
, TRUE
);
337 //Sets the fonts of static controls
338 SetFont(checkbox
,_T("MS Sans Serif"),12);
340 SetFont(checkbox2
,_T("MS Sans Serif"),12);
343 // Subclass the checkbox control.
344 CBProc
= (WNDPROC
) SetWindowLongPtr(checkbox
,GWLP_WNDPROC
, (LONG_PTR
) CheckBoxSubclassProc
);
345 //Sets the checkbox to checked position
346 SendMessage(checkbox
,BM_SETCHECK
,(WPARAM
)m_bCheck
,0);
349 CBProc
= (WNDPROC
) SetWindowLongPtr(checkbox2
,GWLP_WNDPROC
, (LONG_PTR
) CheckBoxSubclassProc2
);
350 SendMessage(checkbox2
,BM_SETCHECK
,(WPARAM
)m_bCheck
,0);
352 // send a resize message to the resized list view control. Otherwise it won't show
353 // up properly until the user resizes the window!
354 SendMessage(ListView
, WM_SIZE
, SIZE_RESTORED
, MAKELONG(ListViewRect
.right
-ListViewRect
.left
, bSecondCheckbox
? (ListViewRect
.bottom
- ListViewRect
.top
)-40 : (ListViewRect
.bottom
- ListViewRect
.top
)-20));
357 // now set the default directory
358 SendMessage(hwnd
, BFFM_SETSELECTION
, TRUE
, (LPARAM
)(LPCTSTR
)m_sDefaultPath
);
360 if (uMsg
== BFFM_SELCHANGED
)
362 // Set the status window to the currently selected path.
363 TCHAR szDir
[MAX_PATH
] = {0};
364 if (SHGetPathFromIDList((LPITEMIDLIST
)lParam
, szDir
))
366 SendMessage(hwnd
,BFFM_SETSTATUSTEXT
, 0, (LPARAM
)szDir
);
373 LRESULT
CBrowseFolder::CheckBoxSubclassProc(HWND hwnd
,UINT uMsg
,WPARAM wParam
,LPARAM lParam
)
375 if (uMsg
== WM_LBUTTONUP
)
377 m_bCheck
= (SendMessage(hwnd
,BM_GETCHECK
,0,0)==BST_UNCHECKED
);
378 if (m_bCheck
&& m_DisableCheckbox2WhenCheckbox1IsChecked
)
380 ::EnableWindow(checkbox2
, !m_bCheck
);
383 ::EnableWindow(checkbox2
, true);
386 return CallWindowProc(CBProc
, hwnd
, uMsg
,
390 LRESULT
CBrowseFolder::CheckBoxSubclassProc2(HWND hwnd
,UINT uMsg
,WPARAM wParam
,LPARAM lParam
)
392 if (uMsg
== WM_LBUTTONUP
)
394 m_bCheck2
= (SendMessage(hwnd
,BM_GETCHECK
,0,0)==BST_UNCHECKED
);
397 return CallWindowProc(CBProc
, hwnd
, uMsg
,