merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / subsys / system / explorer / shell / entries.cpp
index 063ebfd..ab75f9d 100644 (file)
  //
 
 
-#include "../utility/utility.h"
-#include "../utility/shellclasses.h"
-#include "../globals.h"        // for _prescan_nodes
+#include "precomp.h"
 
-#include "entries.h"
+//#include "entries.h"
 
 
  // allocate and initialise a directory entry
@@ -112,39 +110,38 @@ Entry::~Entry()
 
 
  // read directory tree and expand to the given location
-Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder)
+Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder, int scan_flags)
 {
        CONTEXT("Entry::read_tree()");
 
-       HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
+       WaitCursor wait;
 
        Entry* entry = this;
-       Entry* next_entry = entry;
 
-       for(const void*p=path; p&&next_entry; p=entry->get_next_path_component(p)) {
-               entry = next_entry;
-
-               entry->read_directory(sortOrder);
+       for(const void*p=path; p && entry; ) {
+               entry->smart_scan(sortOrder, scan_flags);
 
                if (entry->_down)
                        entry->_expanded = true;
 
-               next_entry = entry->find_entry(p);
-       }
+               Entry* found = entry->find_entry(p);
+               p = entry->get_next_path_component(p);
 
-       SetCursor(old_cursor);
+               entry = found;
+       }
 
        return entry;
 }
 
 
-void Entry::read_directory(SORT_ORDER sortOrder, int scan_flags)
+void Entry::read_directory_base(SORT_ORDER sortOrder, int scan_flags)
 {
-       CONTEXT("Entry::read_directory(SORT_ORDER)");
+       CONTEXT("Entry::read_directory_base()");
 
         // call into subclass
        read_directory(scan_flags);
 
+#ifndef ROSSHELL
        if (g_Globals._prescan_nodes) { //@todo _prescan_nodes should not be used for reading the start menu.
                for(Entry*entry=_down; entry; entry=entry->_next)
                        if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
@@ -152,6 +149,7 @@ void Entry::read_directory(SORT_ORDER sortOrder, int scan_flags)
                                entry->sort_directory(sortOrder);
                        }
        }
+#endif
 
        sort_directory(sortOrder);
 }
@@ -172,10 +170,16 @@ Root::~Root()
  // directories first...
 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
 {
-       int dir1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
-       int dir2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+       int order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+       int order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
 
-       return dir2==dir1? 0: dir2<dir1? -1: 1;
+       /* Handle "." and ".." as special case and move them at the very first beginning. */
+       if (order1 && order2) {
+               order1 = fd1->cFileName[0]!='.'? 1: fd1->cFileName[1]=='.'? 2: fd1->cFileName[1]=='\0'? 3: 1;
+               order2 = fd2->cFileName[0]!='.'? 1: fd2->cFileName[1]=='.'? 2: fd2->cFileName[1]=='\0'? 3: 1;
+       }
+
+       return order2==order1? 0: order2<order1? -1: 1;
 }
 
 
@@ -304,13 +308,13 @@ void Entry::sort_directory(SORT_ORDER sortOrder)
 }
 
 
-void Entry::smart_scan(int scan_flags)
+void Entry::smart_scan(SORT_ORDER sortOrder, int scan_flags)
 {
        CONTEXT("Entry::smart_scan()");
 
        if (!_scanned) {
                free_subentries();
-               read_directory(SORT_NAME, scan_flags);  // we could use IShellFolder2::GetDefaultColumn to determine sort order
+               read_directory_base(sortOrder, scan_flags);     ///@todo We could use IShellFolder2::GetDefaultColumn to determine sort order.
        }
 }
 
@@ -321,7 +325,7 @@ void Entry::extract_icon()
 
        ICON_ID icon_id = ICID_NONE;
 
-       if (get_path(path))
+       if (get_path(path) && _tcsncmp(path,TEXT("::{"),3))
                icon_id = g_Globals._icon_cache.extract(path);
 
        if (icon_id == ICID_NONE) {
@@ -399,6 +403,52 @@ BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow)
 }
 
 
+HRESULT Entry::do_context_menu(HWND hwnd, const POINT& pos, CtxMenuInterfaces& cm_ifs)
+{
+       ShellPath shell_path = create_absolute_pidl();
+       LPCITEMIDLIST pidl_abs = shell_path;
+
+       if (!pidl_abs)
+               return S_FALSE; // no action for registry entries, etc.
+
+       static DynamicFct<HRESULT(WINAPI*)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*)> SHBindToParent(TEXT("SHELL32"), "SHBindToParent");
+
+       if (SHBindToParent) {
+               IShellFolder* parentFolder;
+               LPCITEMIDLIST pidlLast;
+
+                // get and use the parent folder to display correct context menu in all cases -> correct "Properties" dialog for directories, ...
+               HRESULT hr = (*SHBindToParent)(pidl_abs, IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast);
+
+               if (SUCCEEDED(hr)) {
+                       hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pos.x, pos.y, cm_ifs);
+
+                       parentFolder->Release();
+               }
+
+               return hr;
+       } else {
+               /**@todo use parent folder instead of desktop folder
+               Entry* dir = _up;
+
+               ShellPath parent_path;
+
+               if (dir)
+                       parent_path = dir->create_absolute_pidl();
+               else
+                       parent_path = DesktopFolderPath();
+
+               ShellPath shell_path = create_relative_pidl(parent_path);
+               LPCITEMIDLIST pidl = shell_path;
+
+               ShellFolder parent_folder = parent_path;
+               return ShellFolderContextMenu(parent_folder, hwnd, 1, &pidl, pos.x, pos.y);
+               */
+               return ShellFolderContextMenu(GetDesktopFolder(), hwnd, 1, &pidl_abs, pos.x, pos.y, cm_ifs);
+       }
+}
+
+
 HRESULT Entry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut)
 {
        TCHAR path[MAX_PATH];
@@ -475,18 +525,26 @@ void Entry::free_subentries()
 }
 
 
-const void* Directory::get_next_path_component(const void* p)
+Entry* Root::read_tree(LPCTSTR path, int scan_flags)
 {
-       LPCTSTR s = (LPCTSTR) p;
+       Entry* entry;
 
-       while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
-               ++s;
+       if (path && *path)
+               entry = _entry->read_tree(path, _sort_order);
+       else {
+               entry = _entry->read_tree(NULL, _sort_order);
 
-       while(*s==TEXT('\\') || *s==TEXT('/'))
-               ++s;
+               _entry->smart_scan();
 
-       if (!*s)
-               return NULL;
+               if (_entry->_down)
+                       _entry->_expanded = true;
+       }
 
-       return s;
+       return entry;
+}
+
+
+Entry* Root::read_tree(LPCITEMIDLIST pidl, int scan_flags)
+{
+       return _entry->read_tree(pidl, _sort_order);
 }