2 * Copyright 2003, 2004, 2005 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Martin Fuchs, 23.07.2003
35 #include "../resource.h"
38 FileChildWndInfo::FileChildWndInfo(HWND hmdiclient
, LPCTSTR path
, ENTRY_TYPE etype
)
42 if (etype
== ET_UNKNOWN
)
52 _pos
.length
= sizeof(WINDOWPLACEMENT
);
54 _pos
.showCmd
= SW_SHOWNORMAL
;
55 _pos
.rcNormalPosition
.left
= CW_USEDEFAULT
;
56 _pos
.rcNormalPosition
.top
= CW_USEDEFAULT
;
57 _pos
.rcNormalPosition
.right
= CW_USEDEFAULT
;
58 _pos
.rcNormalPosition
.bottom
= CW_USEDEFAULT
;
60 _open_mode
= OWM_EXPLORE
|OWM_DETAILS
;
64 ShellChildWndInfo::ShellChildWndInfo(HWND hmdiclient
, LPCTSTR path
, const ShellPath
& root_shell_path
)
65 : FileChildWndInfo(hmdiclient
, path
, ET_SHELL
),
66 _shell_path(path
&&*path
? path
: root_shell_path
),
67 _root_shell_path(root_shell_path
)
72 NtObjChildWndInfo::NtObjChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
73 : FileChildWndInfo(hmdiclient
, path
, ET_NTOBJS
)
78 RegistryChildWndInfo::RegistryChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
79 : FileChildWndInfo(hmdiclient
, path
, ET_REGISTRY
)
84 FATChildWndInfo::FATChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
85 : FileChildWndInfo(hmdiclient
, path
, ET_FAT
)
90 WebChildWndInfo::WebChildWndInfo(HWND hmdiclient
, LPCTSTR url
)
91 : FileChildWndInfo(hmdiclient
, url
, ET_WEB
)
96 INT_PTR CALLBACK
ExecuteDialog::WndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
98 static struct ExecuteDialog
* dlg
;
102 dlg
= (struct ExecuteDialog
*) lparam
;
106 int id
= (int)wparam
;
109 GetWindowText(GetDlgItem(hwnd
, 201), dlg
->cmd
, MAX_PATH
);
110 dlg
->cmdshow
= Button_GetState(GetDlgItem(hwnd
,214))&BST_CHECKED
?
111 SW_SHOWMINIMIZED
: SW_SHOWNORMAL
;
113 } else if (id
== IDCANCEL
)
125 FileChildWindow::FileChildWindow(HWND hwnd
, const FileChildWndInfo
& info
)
128 CONTEXT("FileChildWindow::FileChildWindow()");
130 TCHAR drv
[_MAX_DRIVE
+1];
136 switch(info
._etype
) {
137 case ET_SHELL
: { //@@ separate FileChildWindow into ShellChildWindow, WinChildWindow, UnixChildWindow ?
138 _root
._drive_type
= DRIVE_UNKNOWN
;
139 _root
._sort_order
= SORT_NAME
;
141 lstrcpy(drv
, TEXT("\\"));
142 lstrcpy(_root
._volname
, TEXT("Desktop"));
144 lstrcpy(_root
._fs
, TEXT("Shell"));
146 _root
._entry
= new ShellDirectory(GetDesktopFolder(), DesktopFolderPath(), hwnd
);
147 const ShellChildWndInfo
& shell_info
= static_cast<const ShellChildWndInfo
&>(info
);
148 entry
= _root
.read_tree(&*shell_info
._shell_path
);
153 _root
._drive_type
= GetDriveType(info
._path
);
154 _root
._sort_order
= SORT_NAME
;
156 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
157 lstrcat(drv
, TEXT("/"));
158 lstrcpy(_root
._volname
, TEXT("root fs"));
160 lstrcpy(_root
._fs
, TEXT("unixfs"));
161 lstrcpy(_root
._path
, TEXT("/"));
162 _root
._entry
= new UnixDirectory(_root
._path
);
163 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
168 _root
._drive_type
= DRIVE_UNKNOWN
;
169 _root
._sort_order
= SORT_NAME
;
171 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
172 lstrcat(drv
, TEXT("\\"));
173 lstrcpy(_root
._volname
, TEXT("NT Object Namespace"));
174 lstrcpy(_root
._fs
, TEXT("NTOBJ"));
175 lstrcpy(_root
._path
, drv
);
176 _root
._entry
= new NtObjDirectory(_root
._path
);
177 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
181 _root
._drive_type
= DRIVE_UNKNOWN
;
182 _root
._sort_order
= SORT_NONE
;
184 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
185 lstrcat(drv
, TEXT("\\"));
186 lstrcpy(_root
._volname
, TEXT("Registry"));
187 lstrcpy(_root
._fs
, TEXT("Registry"));
188 lstrcpy(_root
._path
, drv
);
189 _root
._entry
= new RegistryRoot();
190 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
194 _root
._drive_type
= DRIVE_UNKNOWN
;
195 _root
._sort_order
= SORT_NONE
;
197 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
198 lstrcat(drv
, TEXT("\\"));
199 lstrcpy(_root
._volname
, TEXT("FAT XXX")); //@@
200 lstrcpy(_root
._fs
, TEXT("FAT"));
201 lstrcpy(_root
._path
, drv
);
202 FATDrive
* drive
= new FATDrive(TEXT("c:/reactos-emu/c.img")); //TEXT("\\\\.\\F:")); //@@
204 if (drive
->_hDrive
!= INVALID_HANDLE_VALUE
) {
205 _root
._entry
= drive
;
206 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
210 default: // ET_WINDOWS
211 _root
._drive_type
= GetDriveType(info
._path
);
212 _root
._sort_order
= SORT_NAME
;
214 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
215 lstrcat(drv
, TEXT("\\"));
216 GetVolumeInformation(drv
, _root
._volname
, _MAX_FNAME
, 0, 0, &_root
._fs_flags
, _root
._fs
, _MAX_DIR
);
217 lstrcpy(_root
._path
, drv
);
218 _root
._entry
= new WinDirectory(_root
._path
);
219 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
223 if (info
._etype
!= ET_SHELL
)
224 wsprintf(_root
._entry
->_data
.cFileName
, TEXT("%s - %s"), drv
, _root
._fs
);
226 lstrcpy(_root._entry->_data.cFileName, TEXT("GetDesktopFolder"));*/
228 _root
._entry
->_data
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
231 ///@todo use OWM_ROOTED flag
233 if (info
._open_mode
& OWM_EXPLORE
) ///@todo Is not-explore-mode for FileChildWindow completely implemented?
234 _left_hwnd
= *(_left
=new Pane(_hwnd
, IDW_TREE_LEFT
, IDW_HEADER_LEFT
, _root
._entry
, true, COL_CONTENT
));
236 _right_hwnd
= *(_right
=new Pane(_hwnd
, IDW_TREE_RIGHT
, IDW_HEADER_RIGHT
, NULL
, false,
237 COL_TYPE
|COL_SIZE
|COL_DATE
|COL_TIME
|COL_ATTRIBUTES
|COL_INDEX
|COL_LINKS
|COL_CONTENT
));
240 _header_wdths_ok
= false;
245 set_curdir(_root
._entry
);
248 int idx
= ListBox_FindItemData(_left_hwnd
, ListBox_GetCurSel(_left_hwnd
), _left
->_cur
);
249 ListBox_SetCurSel(_left_hwnd
, idx
);
250 //SetFocus(_left_hwnd);
253 // store path into history
254 if (info
._path
&& *info
._path
)
255 _url_history
.push(info
._path
);
259 void FileChildWindow::set_curdir(Entry
* entry
)
261 CONTEXT("FileChildWindow::set_curdir()");
263 _path
[0] = TEXT('\0');
266 _right
->_root
= entry
&&entry
->_down
? entry
->_down
: entry
;
267 _right
->_cur
= entry
;
272 if (!entry
->_scanned
)
275 HiddenWindow
hide(_right_hwnd
);
277 ListBox_ResetContent(_right_hwnd
);
278 _right
->insert_entries(entry
->_down
);
280 _right
->calc_widths(false); ///@todo make configurable (This call takes really _very_ long compared to all other processing!)
282 _right
->set_header();
285 entry
->get_path(_path
, COUNTOF(_path
));
288 if (_hwnd
) // only change window title if the window already exists
289 SetWindowText(_hwnd
, _path
);
292 if (SetCurrentDirectory(_path
))
293 set_url(_path
); //set_url(FmtString(TEXT("file://%s"), _path));
295 _path
[0] = TEXT('\0');
299 // expand a directory entry
301 bool FileChildWindow::expand_entry(Entry
* dir
)
306 if (!dir
|| dir
->_expanded
|| !dir
->_down
)
311 if (p
->_data
.cFileName
[0]=='.' && p
->_data
.cFileName
[1]=='\0' && p
->_next
) {
314 if (p
->_data
.cFileName
[0]=='.' && p
->_data
.cFileName
[1]=='.' &&
315 p
->_data
.cFileName
[2]=='\0' && p
->_next
)
319 // no subdirectories ?
320 if (!(p
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) && // not a directory?
321 !p
->_down
) // not a file with NTFS sub-streams?
324 idx
= ListBox_FindItemData(_left_hwnd
, 0, dir
);
326 dir
->_expanded
= true;
328 // insert entries in left pane
329 HiddenWindow
hide(_left_hwnd
);
331 _left
->insert_entries(p
, idx
);
333 if (!_header_wdths_ok
) {
334 if (_left
->calc_widths(false)) {
337 _header_wdths_ok
= true;
345 void FileChildWindow::collapse_entry(Pane
* pane
, Entry
* dir
)
347 int idx
= ListBox_FindItemData(*pane
, 0, dir
);
349 SendMessage(*pane
, WM_SETREDRAW
, FALSE
, 0); //ShowWindow(*pane, SW_HIDE);
353 LRESULT res
= ListBox_GetItemData(*pane
, idx
+1);
354 Entry
* sub
= (Entry
*) res
;
356 if (res
==LB_ERR
|| !sub
|| sub
->_level
<=dir
->_level
)
359 ListBox_DeleteString(*pane
, idx
+1);
362 dir
->_expanded
= false;
364 SendMessage(*pane
, WM_SETREDRAW
, TRUE
, 0); //ShowWindow(*pane, SW_SHOW);
368 FileChildWindow
* FileChildWindow::create(const FileChildWndInfo
& info
)
370 CONTEXT("FileChildWindow::create()");
374 mcs
.szClass
= CLASSNAME_WINEFILETREE
;
375 mcs
.szTitle
= (LPTSTR
)info
._path
;
376 mcs
.hOwner
= g_Globals
._hInstance
;
377 mcs
.x
= info
._pos
.rcNormalPosition
.left
;
378 mcs
.y
= info
._pos
.rcNormalPosition
.top
;
379 mcs
.cx
= info
._pos
.rcNormalPosition
.right
- info
._pos
.rcNormalPosition
.left
;
380 mcs
.cy
= info
._pos
.rcNormalPosition
.bottom
- info
._pos
.rcNormalPosition
.top
;
384 FileChildWindow
* child
= static_cast<FileChildWindow
*>(
385 create_mdi_child(info
, mcs
, WINDOW_CREATOR_INFO(FileChildWindow
,FileChildWndInfo
)));
391 void FileChildWindow::resize_children(int cx
, int cy
)
393 HDWP hdwp
= BeginDeferWindowPos(4);
401 cx
= _split_pos
+ SPLIT_WIDTH
/2;
403 if (_left
&& _right
) {
410 Header_Layout(_left
->_hwndHeader
, &hdl
);
412 hdwp
= DeferWindowPos(hdwp
, _left
->_hwndHeader
, wp
.hwndInsertAfter
,
413 wp
.x
-1, wp
.y
, _split_pos
-SPLIT_WIDTH
/2+1, wp
.cy
, wp
.flags
);
415 hdwp
= DeferWindowPos(hdwp
, _right
->_hwndHeader
, wp
.hwndInsertAfter
,
416 rt
.left
+cx
+1, wp
.y
, wp
.cx
-cx
+2, wp
.cy
, wp
.flags
);
420 hdwp
= DeferWindowPos(hdwp
, _left_hwnd
, 0, rt
.left
, rt
.top
, _split_pos
-SPLIT_WIDTH
/2-rt
.left
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
423 hdwp
= DeferWindowPos(hdwp
, _right_hwnd
, 0, rt
.left
+cx
+1, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
425 EndDeferWindowPos(hdwp
);
429 LRESULT
FileChildWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
433 LPDRAWITEMSTRUCT dis
= (LPDRAWITEMSTRUCT
)lparam
;
434 Entry
* entry
= (Entry
*) dis
->itemData
;
436 if (dis
->CtlID
== IDW_TREE_LEFT
) {
437 _left
->draw_item(dis
, entry
);
439 } else if (dis
->CtlID
== IDW_TREE_RIGHT
) {
440 _right
->draw_item(dis
, entry
);
447 if (wparam
!= SIZE_MINIMIZED
)
448 resize_children(LOWORD(lparam
), HIWORD(lparam
));
449 return DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
451 case PM_GET_FILEWND_PTR
:
452 return (LRESULT
)this;
455 TCHAR path
[MAX_PATH
];
457 if (_left
&& _left
->_cur
) {
458 _left
->_cur
->get_path(path
, COUNTOF(path
));
459 SetCurrentDirectory(path
);
462 SetFocus(_focus_pane
? _right_hwnd
: _left_hwnd
);
465 case PM_DISPATCH_COMMAND
: {
466 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
468 switch(LOWORD(wparam
)) {
469 case ID_WINDOW_NEW
: {CONTEXT("FileChildWindow PM_DISPATCH_COMMAND ID_WINDOW_NEW");
470 if (_root
._entry
->_etype
== ET_SHELL
)
471 FileChildWindow::create(ShellChildWndInfo(GetParent(_hwnd
)/*_hmdiclient*/, _path
, DesktopFolderPath()));
473 FileChildWindow::create(FileChildWndInfo(GetParent(_hwnd
)/*_hmdiclient*/, _path
));
476 case ID_REFRESH
: {CONTEXT("ID_REFRESH");
478 bool expanded
= _left
->_cur
->_expanded
;
480 scan_entry(_left
->_cur
);
483 expand_entry(_left
->_cur
);
486 case ID_ACTIVATE
: {CONTEXT("ID_ACTIVATE");
487 activate_entry(pane
);
491 if (pane
->command(LOWORD(wparam
)))
494 return super::WndProc(nmsg
, wparam
, lparam
);
499 case WM_CONTEXTMENU
: {
500 // first select the current item in the listbox
501 HWND hpanel
= (HWND
) wparam
;
502 const POINTS
& pos
= MAKEPOINTS(lparam
);
503 POINT pt
; POINTSTOPOINT(pt
, pos
);
504 POINT pt_screen
= pt
;
505 ScreenToClient(hpanel
, &pt
);
506 SendMessage(hpanel
, WM_LBUTTONDOWN
, 0, MAKELONG(pt
.x
, pt
.y
));
507 SendMessage(hpanel
, WM_LBUTTONUP
, 0, MAKELONG(pt
.x
, pt
.y
));
509 // now create the popup menu using shell namespace and IContextMenu
510 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
511 int idx
= ListBox_GetCurSel(*pane
);
513 Entry
* entry
= (Entry
*) ListBox_GetItemData(*pane
, idx
);
515 CHECKERROR(entry
->do_context_menu(_hwnd
, pt_screen
, _cm_ifs
));
520 return super::WndProc(nmsg
, wparam
, lparam
);
527 int FileChildWindow::Command(int id
, int code
)
529 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
532 case LBN_SELCHANGE
: {
533 int idx
= ListBox_GetCurSel(*pane
);
534 Entry
* entry
= (Entry
*) ListBox_GetItemData(*pane
, idx
);
543 activate_entry(pane
);
551 void FileChildWindow::activate_entry(Pane
* pane
) ///@todo enable using RETURN key accelerator
553 Entry
* entry
= pane
->_cur
;
560 if ((entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) || // a directory?
561 entry
->_down
) // a file with NTFS sub-streams?
563 int scanned_old
= entry
->_scanned
;
568 if (entry
->_data
.cFileName
[0]==TEXT('.') && entry
->_data
.cFileName
[1]==TEXT('\0'))
571 if (entry
->_data
.cFileName
[0]==TEXT('.') && entry
->_data
.cFileName
[1]==TEXT('.') && entry
->_data
.cFileName
[2]==TEXT('\0')) {
572 entry
= _left
->_cur
->_up
;
573 collapse_entry(_left
, entry
);
575 } else if (entry
->_expanded
)
576 collapse_entry(pane
, _left
->_cur
);
578 expand_entry(_left
->_cur
);
580 if (!pane
->_treePane
) focus_entry
: {
581 int idx
= ListBox_FindItemData(_left_hwnd
, ListBox_GetCurSel(_left_hwnd
), entry
);
582 ListBox_SetCurSel(_left_hwnd
, idx
);
589 pane
->calc_widths(false);
594 entry
->launch_entry(_hwnd
);
599 void FileChildWindow::scan_entry(Entry
* entry
)
601 CONTEXT("FileChildWindow::scan_entry()");
603 int idx
= ListBox_GetCurSel(_left_hwnd
);
605 // delete sub entries in left pane
607 LRESULT res
= ListBox_GetItemData(_left_hwnd
, idx
+1);
608 Entry
* sub
= (Entry
*) res
;
610 if (res
==LB_ERR
|| !sub
|| sub
->_level
<=entry
->_level
)
613 ListBox_DeleteString(_left_hwnd
, idx
+1);
617 ListBox_ResetContent(_right_hwnd
);
620 entry
->free_subentries();
621 entry
->_expanded
= false;
623 // read contents from disk
624 entry
->read_directory_base(_root
._sort_order
); ///@todo use modifyable sort order instead of fixed file system default
626 // insert found entries in right pane
627 HiddenWindow
hide(_right_hwnd
);
628 _right
->insert_entries(entry
->_down
);
630 _right
->calc_widths(false);
631 _right
->set_header();
633 _header_wdths_ok
= false;
637 int FileChildWindow::Notify(int id
, NMHDR
* pnmh
)
639 return (pnmh
->idFrom
==IDW_HEADER_LEFT
? _left
: _right
)->Notify(id
, pnmh
);
643 String
FileChildWindow::jump_to_int(LPCTSTR url
)
647 if (SplitFileSysURL(url
, dir
, fname
)) {
650 // call read_tree() to iterate through the hierarchy and open all folders to reach dir
652 switch(_root
._entry
->_etype
) {
653 case ET_SHELL
: { //@@ separate into FileChildWindow in ShellChildWindow, WinChildWindow, UnixChildWindow ?
654 ShellPath
shell_path(dir
);
655 entry
= _root
.read_tree(&*shell_path
);
662 if (!_tcsicmp(path
, _root
._path
, _tcslen(_root
._path
)))
663 path
+= _tcslen(_root
._path
);
665 entry
= _root
.read_tree(path
);
669 default: { // ET_NTOBJS, ET_REGISTRY, ET_FAT, ET_WINDOWS
672 if (!_tcsnicmp(path
, _root
._path
, _tcslen(_root
._path
)))
673 path
+= _tcslen(_root
._path
);
675 entry
= _root
.read_tree(path
);
680 // refresh left pane entries
681 HiddenWindow
hide(_left_hwnd
);
683 ListBox_ResetContent(_left_hwnd
);
685 _left
->insert_entries(_root
._entry
);
687 if (!_header_wdths_ok
) {
688 if (_left
->calc_widths(false)) {
691 _header_wdths_ok
= true;
698 int idx
= ListBox_FindItemData(_left_hwnd
, -1, entry
);
700 if (idx
!= -1) { // The item should always be found.
701 ListBox_SetCurSel(_left_hwnd
, idx
);
702 SetFocus(_left_hwnd
);
708 return dir
; //FmtString(TEXT("file://%s"), (LPCTSTR)dir);