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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 // Martin Fuchs, 23.07.2003
35 FileChildWndInfo::FileChildWndInfo(HWND hmdiclient
, LPCTSTR path
, ENTRY_TYPE etype
)
40 if (etype
== ET_UNKNOWN
)
51 _pos
.length
= sizeof(WINDOWPLACEMENT
);
53 _pos
.showCmd
= SW_SHOWNORMAL
;
54 _pos
.rcNormalPosition
.left
= CW_USEDEFAULT
;
55 _pos
.rcNormalPosition
.top
= CW_USEDEFAULT
;
56 _pos
.rcNormalPosition
.right
= CW_USEDEFAULT
;
57 _pos
.rcNormalPosition
.bottom
= CW_USEDEFAULT
;
59 _open_mode
= OWM_EXPLORE
|OWM_DETAILS
;
63 ShellChildWndInfo::ShellChildWndInfo(HWND hmdiclient
, LPCTSTR path
, const ShellPath
& root_shell_path
)
64 : FileChildWndInfo(hmdiclient
, path
, ET_SHELL
),
65 _shell_path(path
&&*path
? path
: root_shell_path
),
66 _root_shell_path(root_shell_path
)
71 NtObjChildWndInfo::NtObjChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
72 : FileChildWndInfo(hmdiclient
, path
, ET_NTOBJS
)
77 RegistryChildWndInfo::RegistryChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
78 : FileChildWndInfo(hmdiclient
, path
, ET_REGISTRY
)
83 FATChildWndInfo::FATChildWndInfo(HWND hmdiclient
, LPCTSTR path
)
84 : FileChildWndInfo(hmdiclient
, path
, ET_FAT
)
89 WebChildWndInfo::WebChildWndInfo(HWND hmdiclient
, LPCTSTR url
)
90 : FileChildWndInfo(hmdiclient
, url
, ET_WEB
)
95 INT_PTR CALLBACK
ExecuteDialog::WndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
97 static struct ExecuteDialog
* dlg
;
101 dlg
= (struct ExecuteDialog
*) lparam
;
105 int id
= (int)wparam
;
108 GetWindowText(GetDlgItem(hwnd
, 201), dlg
->cmd
, COUNTOF(dlg
->cmd
));
109 dlg
->cmdshow
= Button_GetState(GetDlgItem(hwnd
,214))&BST_CHECKED
?
110 SW_SHOWMINIMIZED
: SW_SHOWNORMAL
;
112 } else if (id
== IDCANCEL
)
124 FileChildWindow::FileChildWindow(HWND hwnd
, const FileChildWndInfo
& info
)
127 CONTEXT("FileChildWindow::FileChildWindow()");
129 TCHAR drv
[_MAX_DRIVE
+1];
135 switch(info
._etype
) {
138 _root
._drive_type
= GetDriveType(info
._path
);
139 _root
._sort_order
= SORT_NAME
;
141 _tsplitpath(info
._path
, drv
, NULL
, NULL
, NULL
);
142 lstrcat(drv
, TEXT("/"));
143 lstrcpy(_root
._volname
, TEXT("root fs"));
145 lstrcpy(_root
._fs
, TEXT("unixfs"));
146 lstrcpy(_root
._path
, TEXT("/"));
147 _root
._entry
= new UnixDirectory(_root
._path
);
148 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
153 _root
._drive_type
= DRIVE_UNKNOWN
;
154 _root
._sort_order
= SORT_NAME
;
156 _tsplitpath_s(info
._path
, drv
, COUNTOF(drv
), NULL
, 0, NULL
, 0, NULL
, 0);
157 lstrcat(drv
, TEXT("\\"));
158 lstrcpy(_root
._volname
, TEXT("NT Object Namespace"));
159 lstrcpy(_root
._fs
, TEXT("NTOBJ"));
160 lstrcpy(_root
._path
, drv
);
161 _root
._entry
= new NtObjDirectory(_root
._path
);
162 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
166 _root
._drive_type
= DRIVE_UNKNOWN
;
167 _root
._sort_order
= SORT_NONE
;
169 _tsplitpath_s(info
._path
, drv
, COUNTOF(drv
), NULL
, 0, NULL
, 0, NULL
, 0);
170 lstrcat(drv
, TEXT("\\"));
171 lstrcpy(_root
._volname
, TEXT("Registry"));
172 lstrcpy(_root
._fs
, TEXT("Registry"));
173 lstrcpy(_root
._path
, drv
);
174 _root
._entry
= new RegistryRoot();
175 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
179 _root
._drive_type
= DRIVE_UNKNOWN
;
180 _root
._sort_order
= SORT_NONE
;
182 _tsplitpath_s(info
._path
, drv
, COUNTOF(drv
), NULL
, 0, NULL
, 0, NULL
, 0);
183 lstrcat(drv
, TEXT("\\"));
184 lstrcpy(_root
._volname
, TEXT("FAT XXX")); //@@
185 lstrcpy(_root
._fs
, TEXT("FAT"));
186 lstrcpy(_root
._path
, drv
);
187 FATDrive
* drive
= new FATDrive(TEXT("c:/reactos-emu/c.img")); //TEXT("\\\\.\\F:")); //@@
189 if (drive
->_hDrive
!= INVALID_HANDLE_VALUE
) {
190 _root
._entry
= drive
;
191 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
196 default: // ET_WINDOWS
197 _root
._drive_type
= GetDriveType(info
._path
);
198 _root
._sort_order
= SORT_NAME
;
200 _tsplitpath_s(info
._path
, drv
, COUNTOF(drv
), NULL
, 0, NULL
, 0, NULL
, 0);
201 lstrcat(drv
, TEXT("\\"));
202 GetVolumeInformation(drv
, _root
._volname
, _MAX_FNAME
, 0, 0, &_root
._fs_flags
, _root
._fs
, COUNTOF(_root
._fs
));
203 lstrcpy(_root
._path
, drv
);
204 _root
._entry
= new WinDirectory(_root
._path
);
205 entry
= _root
.read_tree(info
._path
+_tcslen(_root
._path
));
211 case ET_SHELL
: { //@@ separate FileChildWindow into ShellChildWindow, WinChildWindow, UnixChildWindow ?
212 _root
._drive_type
= DRIVE_UNKNOWN
;
213 _root
._sort_order
= SORT_NAME
;
215 lstrcpy(drv
, TEXT("\\"));
216 lstrcpy(_root
._volname
, TEXT("Desktop"));
218 lstrcpy(_root
._fs
, TEXT("Shell"));
220 _root
._entry
= new ShellDirectory(GetDesktopFolder(), DesktopFolderPath(), hwnd
);
221 const ShellChildWndInfo
& shell_info
= static_cast<const ShellChildWndInfo
&>(info
);
222 entry
= _root
.read_tree(&*shell_info
._shell_path
);
227 if (info
._etype
!= ET_SHELL
)
228 wsprintf(_root
._entry
->_data
.cFileName
, TEXT("%s - %s"), drv
, _root
._fs
);
230 lstrcpy(_root._entry->_data.cFileName, TEXT("GetDesktopFolder"));*/
232 _root
._entry
->_data
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
235 ///@todo use OWM_ROOTED flag
237 if (info
._open_mode
& OWM_EXPLORE
) ///@todo Is not-explore-mode for FileChildWindow completely implemented?
238 _left_hwnd
= *(_left
=new Pane(_hwnd
, IDW_TREE_LEFT
, IDW_HEADER_LEFT
, _root
._entry
, true, COL_CONTENT
));
240 _right_hwnd
= *(_right
=new Pane(_hwnd
, IDW_TREE_RIGHT
, IDW_HEADER_RIGHT
, NULL
, false,
241 COL_TYPE
|COL_SIZE
|COL_DATE
|COL_TIME
|COL_ATTRIBUTES
|COL_INDEX
|COL_LINKS
|COL_CONTENT
));
244 _header_wdths_ok
= false;
246 if (!_left_hwnd
&& !_right_hwnd
)
251 else if (_root
._entry
)
252 set_curdir(_root
._entry
);
255 int idx
= ListBox_FindItemData(_left_hwnd
, ListBox_GetCurSel(_left_hwnd
), _left
->_cur
);
256 ListBox_SetCurSel(_left_hwnd
, idx
);
257 //SetFocus(_left_hwnd);
260 // store path into history
261 if (info
._path
&& *info
._path
)
262 _url_history
.push(info
._path
);
266 void FileChildWindow::set_curdir(Entry
* entry
)
268 CONTEXT("FileChildWindow::set_curdir()");
270 _path
[0] = TEXT('\0');
273 _right
->_root
= entry
&&entry
->_down
? entry
->_down
: entry
;
274 _right
->_cur
= entry
;
279 if (!entry
->_scanned
)
282 HiddenWindow
hide(_right_hwnd
);
284 ListBox_ResetContent(_right_hwnd
);
285 _right
->insert_entries(entry
->_down
);
287 _right
->calc_widths(false); ///@todo make configurable (This call takes really _very_ long compared to all other processing!)
289 _right
->set_header();
292 entry
->get_path(_path
, COUNTOF(_path
));
295 if (_hwnd
) // only change window title if the window already exists
296 SetWindowText(_hwnd
, _path
);
300 if (SetCurrentDirectory(_path
))
301 set_url(_path
); //set_url(FmtString(TEXT("file://%s"), _path));
303 _path
[0] = TEXT('\0');
308 // expand a directory entry
310 bool FileChildWindow::expand_entry(Entry
* dir
)
315 if (!dir
|| dir
->_expanded
|| !dir
->_down
)
320 if (p
->_data
.cFileName
[0]=='.' && p
->_data
.cFileName
[1]=='\0' && p
->_next
) {
323 if (p
->_data
.cFileName
[0]=='.' && p
->_data
.cFileName
[1]=='.' &&
324 p
->_data
.cFileName
[2]=='\0' && p
->_next
)
328 // no subdirectories ?
329 if (!(p
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) && // not a directory?
330 !p
->_down
) // not a file with NTFS sub-streams?
333 idx
= ListBox_FindItemData(_left_hwnd
, 0, dir
);
335 dir
->_expanded
= true;
337 // insert entries in left pane
338 HiddenWindow
hide(_left_hwnd
);
340 _left
->insert_entries(p
, idx
);
342 if (!_header_wdths_ok
) {
343 if (_left
->calc_widths(false)) {
346 _header_wdths_ok
= true;
354 void FileChildWindow::collapse_entry(Pane
* pane
, Entry
* dir
)
356 int idx
= ListBox_FindItemData(*pane
, 0, dir
);
358 SendMessage(*pane
, WM_SETREDRAW
, FALSE
, 0); //ShowWindow(*pane, SW_HIDE);
362 LRESULT res
= ListBox_GetItemData(*pane
, idx
+1);
363 Entry
* sub
= (Entry
*) res
;
365 if (res
==LB_ERR
|| !sub
|| sub
->_level
<=dir
->_level
)
368 ListBox_DeleteString(*pane
, idx
+1);
371 dir
->_expanded
= false;
373 SendMessage(*pane
, WM_SETREDRAW
, TRUE
, 0); //ShowWindow(*pane, SW_SHOW);
377 FileChildWindow
* FileChildWindow::create(const FileChildWndInfo
& info
)
379 CONTEXT("FileChildWindow::create()");
383 mcs
.szClass
= CLASSNAME_WINEFILETREE
;
384 mcs
.szTitle
= (LPTSTR
)info
._path
;
385 mcs
.hOwner
= g_Globals
._hInstance
;
386 mcs
.x
= info
._pos
.rcNormalPosition
.left
;
387 mcs
.y
= info
._pos
.rcNormalPosition
.top
;
388 mcs
.cx
= info
._pos
.rcNormalPosition
.right
- info
._pos
.rcNormalPosition
.left
;
389 mcs
.cy
= info
._pos
.rcNormalPosition
.bottom
- info
._pos
.rcNormalPosition
.top
;
393 FileChildWindow
* child
= static_cast<FileChildWindow
*>(
394 create_mdi_child(info
, mcs
, WINDOW_CREATOR_INFO(FileChildWindow
,FileChildWndInfo
)));
396 if (!child
->_left_hwnd
&& !child
->_right_hwnd
) {
397 SendMessage(info
._hmdiclient
, WM_MDIDESTROY
, (WPARAM
)child
->_hwnd
, 0);
398 MessageBox(info
._hmdiclient
, TEXT("Error opening child window"), TEXT("ROS Explorer"), MB_OK
);
405 void FileChildWindow::resize_children(int cx
, int cy
)
407 HDWP hdwp
= BeginDeferWindowPos(4);
415 cx
= _split_pos
+ SPLIT_WIDTH
/2;
417 if (_left
&& _right
) {
424 Header_Layout(_left
->_hwndHeader
, &hdl
);
426 hdwp
= DeferWindowPos(hdwp
, _left
->_hwndHeader
, wp
.hwndInsertAfter
,
427 wp
.x
-1, wp
.y
, _split_pos
-SPLIT_WIDTH
/2+1, wp
.cy
, wp
.flags
);
429 hdwp
= DeferWindowPos(hdwp
, _right
->_hwndHeader
, wp
.hwndInsertAfter
,
430 rt
.left
+cx
+1, wp
.y
, wp
.cx
-cx
+2, wp
.cy
, wp
.flags
);
434 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
);
437 hdwp
= DeferWindowPos(hdwp
, _right_hwnd
, 0, rt
.left
+cx
+1, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
439 EndDeferWindowPos(hdwp
);
443 LRESULT
FileChildWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
447 LPDRAWITEMSTRUCT dis
= (LPDRAWITEMSTRUCT
)lparam
;
448 Entry
* entry
= (Entry
*) dis
->itemData
;
450 if (dis
->CtlID
== IDW_TREE_LEFT
) {
451 _left
->draw_item(dis
, entry
);
453 } else if (dis
->CtlID
== IDW_TREE_RIGHT
) {
454 _right
->draw_item(dis
, entry
);
461 if (wparam
!= SIZE_MINIMIZED
)
462 resize_children(LOWORD(lparam
), HIWORD(lparam
));
463 return DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
465 case PM_GET_FILEWND_PTR
:
466 return (LRESULT
)this;
469 TCHAR path
[MAX_PATH
];
471 if (_left
&& _left
->_cur
) {
472 _left
->_cur
->get_path(path
, COUNTOF(path
));
473 SetCurrentDirectory(path
);
476 SetFocus(_focus_pane
? _right_hwnd
: _left_hwnd
);
479 case PM_DISPATCH_COMMAND
: {
480 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
482 switch(LOWORD(wparam
)) {
483 case ID_WINDOW_NEW
: {CONTEXT("FileChildWindow PM_DISPATCH_COMMAND ID_WINDOW_NEW");
484 if (_root
._entry
->_etype
== ET_SHELL
)
485 FileChildWindow::create(ShellChildWndInfo(GetParent(_hwnd
)/*_hmdiclient*/, _path
, DesktopFolderPath()));
487 FileChildWindow::create(FileChildWndInfo(GetParent(_hwnd
)/*_hmdiclient*/, _path
));
490 case ID_REFRESH
: {CONTEXT("ID_REFRESH");
494 case ID_ACTIVATE
: {CONTEXT("ID_ACTIVATE");
495 activate_entry(pane
);
499 if (pane
->command(LOWORD(wparam
)))
502 return super::WndProc(nmsg
, wparam
, lparam
);
507 case WM_CONTEXTMENU
: {
508 // first select the current item in the listbox
509 HWND hpanel
= (HWND
) wparam
;
511 pt
.x
= LOWORD(lparam
);
512 pt
.y
= HIWORD(lparam
);
513 POINT pt_screen
= pt
;
514 ScreenToClient(hpanel
, &pt
);
515 SendMessage(hpanel
, WM_LBUTTONDOWN
, 0, MAKELONG(pt
.x
, pt
.y
));
516 SendMessage(hpanel
, WM_LBUTTONUP
, 0, MAKELONG(pt
.x
, pt
.y
));
518 // now create the popup menu using shell namespace and IContextMenu
519 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
520 int idx
= ListBox_GetCurSel(*pane
);
522 Entry
* entry
= (Entry
*) ListBox_GetItemData(*pane
, idx
);
524 HRESULT hr
= entry
->do_context_menu(_hwnd
, pt_screen
, _cm_ifs
);
534 return super::WndProc(nmsg
, wparam
, lparam
);
541 void FileChildWindow::refresh()
544 bool expanded
= _left
->_cur
->_expanded
;
546 scan_entry(_left
->_cur
);
549 expand_entry(_left
->_cur
);
553 int FileChildWindow::Command(int id
, int code
)
555 Pane
* pane
= GetFocus()==_left_hwnd
? _left
: _right
;
558 case LBN_SELCHANGE
: {
559 int idx
= ListBox_GetCurSel(*pane
);
560 Entry
* entry
= (Entry
*) ListBox_GetItemData(*pane
, idx
);
569 activate_entry(pane
);
577 void FileChildWindow::activate_entry(Pane
* pane
) ///@todo enable using RETURN key accelerator
579 Entry
* entry
= pane
->_cur
;
586 if ((entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) || // a directory?
587 entry
->_down
) // a file with NTFS sub-streams?
589 int scanned_old
= entry
->_scanned
;
594 if (entry
->_data
.cFileName
[0]==TEXT('.') && entry
->_data
.cFileName
[1]==TEXT('\0'))
597 if (entry
->_data
.cFileName
[0]==TEXT('.') && entry
->_data
.cFileName
[1]==TEXT('.') && entry
->_data
.cFileName
[2]==TEXT('\0')) {
598 entry
= _left
->_cur
->_up
;
599 collapse_entry(_left
, entry
);
601 } else if (entry
->_expanded
)
602 collapse_entry(pane
, _left
->_cur
);
604 expand_entry(_left
->_cur
);
606 if (!pane
->_treePane
) focus_entry
: {
607 int idx
= ListBox_FindItemData(_left_hwnd
, ListBox_GetCurSel(_left_hwnd
), entry
);
608 ListBox_SetCurSel(_left_hwnd
, idx
);
615 pane
->calc_widths(false);
620 entry
->launch_entry(_hwnd
);
625 void FileChildWindow::scan_entry(Entry
* entry
)
627 CONTEXT("FileChildWindow::scan_entry()");
629 int idx
= ListBox_GetCurSel(_left_hwnd
);
631 // delete sub entries in left pane
633 LRESULT res
= ListBox_GetItemData(_left_hwnd
, idx
+1);
634 Entry
* sub
= (Entry
*) res
;
636 if (res
==LB_ERR
|| !sub
|| sub
->_level
<=entry
->_level
)
639 ListBox_DeleteString(_left_hwnd
, idx
+1);
643 ListBox_ResetContent(_right_hwnd
);
646 entry
->free_subentries();
647 entry
->_expanded
= false;
649 // read contents from disk
650 entry
->read_directory_base(_root
._sort_order
); ///@todo use modifyable sort order instead of fixed file system default
652 // insert found entries in right pane
653 HiddenWindow
hide(_right_hwnd
);
654 _right
->insert_entries(entry
->_down
);
656 _right
->calc_widths(false);
657 _right
->set_header();
659 _header_wdths_ok
= false;
663 int FileChildWindow::Notify(int id
, NMHDR
* pnmh
)
665 return (pnmh
->idFrom
==IDW_HEADER_LEFT
? _left
: _right
)->Notify(id
, pnmh
);
669 String
FileChildWindow::jump_to_int(LPCTSTR url
)
673 if (SplitFileSysURL(url
, dir
, fname
)) {
676 // call read_tree() to iterate through the hierarchy and open all folders to reach dir
678 switch(_root
._entry
->_etype
) {
679 case ET_SHELL
: { //@@ separate into FileChildWindow in ShellChildWindow, WinChildWindow, UnixChildWindow ?
680 ShellPath
shell_path(dir
);
681 entry
= _root
.read_tree(&*shell_path
);
688 if (!_tcsicmp(path
, _root
._path
, _tcslen(_root
._path
)))
689 path
+= _tcslen(_root
._path
);
691 entry
= _root
.read_tree(path
);
695 default: { // ET_NTOBJS, ET_REGISTRY, ET_FAT, ET_WINDOWS
698 if (!_tcsnicmp(path
, _root
._path
, _tcslen(_root
._path
)))
699 path
+= _tcslen(_root
._path
);
701 entry
= _root
.read_tree(path
);
706 // refresh left pane entries
707 HiddenWindow
hide(_left_hwnd
);
709 ListBox_ResetContent(_left_hwnd
);
711 _left
->insert_entries(_root
._entry
);
713 if (!_header_wdths_ok
) {
714 if (_left
->calc_widths(false)) {
717 _header_wdths_ok
= true;
724 int idx
= ListBox_FindItemData(_left_hwnd
, -1, entry
);
726 if (idx
!= -1) { // The item should always be found.
727 ListBox_SetCurSel(_left_hwnd
, idx
);
728 SetFocus(_left_hwnd
);
734 return dir
; //FmtString(TEXT("file://%s"), (LPCTSTR)dir);