From 3a8b744dfe1d24289a1fea859694a6e308c148a2 Mon Sep 17 00:00:00 2001 From: Don HO Date: Sat, 28 Mar 2020 04:54:21 +0100 Subject: [PATCH] Folder as Workspace: Add dynamical sorting feature Fix #1541 --- .../WinControls/FileBrowser/fileBrowser.cpp | 67 ++++++++++++++----- .../src/WinControls/FileBrowser/fileBrowser.h | 11 ++- .../src/WinControls/ProjectPanel/TreeView.cpp | 11 +++ .../src/WinControls/ProjectPanel/TreeView.h | 1 + 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp b/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp index cdddcbbc..dd41b392 100644 --- a/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp +++ b/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp @@ -65,9 +65,9 @@ FileBrowser::~FileBrowser() delete folder; } - for (const auto s : rootPaths) + for (const auto cd : sortingDataArray) { - delete s; + delete cd; } } @@ -484,8 +484,8 @@ generic_string FileBrowser::getNodePath(HTREEITEM node) const HTREEITEM temp = _treeView.getParent(parent); if (temp == nullptr) { - LPARAM param = _treeView.getItemParam(parent); - folderName = (param == 0) ? TEXT("") : *((generic_string *)param); + SortingData4lParam* customData = reinterpret_cast(_treeView.getItemParam(parent)); + folderName = customData->_rootPath; } parent = temp; fullPathArray.push_back(folderName); @@ -564,7 +564,8 @@ void FileBrowser::notified(LPNMHDR notification) size_t len = lstrlen(tvItem.pszText); // Find the position of old label in File path - generic_string *filePath = (generic_string *)tvnotif->item.lParam; + SortingData4lParam* customData = reinterpret_cast(tvnotif->item.lParam); + generic_string *filePath = &(customData->_rootPath); size_t found = filePath->rfind(tvItem.pszText); // If found the old label, replace it with the modified one @@ -708,7 +709,7 @@ BrowserNodeType FileBrowser::getNodeType(HTREEITEM hItem) return browserNodeType_file; } // Root - else if (tvItem.lParam != NULL) + else if (tvItem.lParam != NULL && !reinterpret_cast(tvItem.lParam)->_rootPath.empty()) { return browserNodeType_root; } @@ -1049,14 +1050,17 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con if (rootPath[len - 1] == '\\') rootPath[len - 1] = '\0'; - generic_string* rootPathStr = new generic_string(rootPath); - rootPaths.push_back(rootPathStr); - LPARAM lParamRootPath = reinterpret_cast(rootPathStr); - hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), TVI_ROOT, INDEX_CLOSE_ROOT, lParamRootPath); + SortingData4lParam* customData = new SortingData4lParam(rootPath, TEXT(""), true); + sortingDataArray.push_back(customData); + + hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), TVI_ROOT, INDEX_CLOSE_ROOT, reinterpret_cast(customData)); } else { - hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), hParentItem, INDEX_CLOSE_NODE); + SortingData4lParam* customData = new SortingData4lParam(TEXT(""), directoryStructure._name, true); + sortingDataArray.push_back(customData); + + hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), hParentItem, INDEX_CLOSE_NODE, reinterpret_cast(customData)); } for (const auto& folder : directoryStructure._subFolders) @@ -1066,7 +1070,10 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con for (const auto& file : directoryStructure._files) { - _treeView.addItem(file._name.c_str(), hFolderItem, INDEX_LEAF); + SortingData4lParam* customData = new SortingData4lParam(TEXT(""), file._name, false); + sortingDataArray.push_back(customData); + + _treeView.addItem(file._name.c_str(), hFolderItem, INDEX_LEAF, reinterpret_cast(customData)); } _treeView.fold(hParentItem); @@ -1087,7 +1094,7 @@ HTREEITEM FileBrowser::getRootFromFullPath(const generic_string & rootPath) cons tvItem.hItem = hItemNode; SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, reinterpret_cast(&tvItem)); - if (tvItem.lParam != 0 && rootPath == *((generic_string *)tvItem.lParam)) + if (tvItem.lParam != 0 && rootPath == reinterpret_cast(tvItem.lParam)->_rootPath) node = hItemNode; } return node; @@ -1131,7 +1138,7 @@ vector FileBrowser::getRoots() const tvItem.hItem = hItemNode; SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, reinterpret_cast(&tvItem)); - roots.push_back(*((generic_string *)tvItem.lParam)); + roots.push_back(reinterpret_cast(tvItem.lParam)->_rootPath); } return roots; } @@ -1170,13 +1177,20 @@ bool FileBrowser::addInTree(const generic_string& rootPath, const generic_string // No found, good - Action if (::PathIsDirectory(addItemFullPath.c_str())) { - _treeView.addItem(linarPathArray[0].c_str(), node, INDEX_CLOSE_NODE); + SortingData4lParam* customData = new SortingData4lParam(TEXT(""), linarPathArray[0], true); + sortingDataArray.push_back(customData); + + _treeView.addItem(linarPathArray[0].c_str(), node, INDEX_CLOSE_NODE, reinterpret_cast(customData)); } else { - _treeView.addItem(linarPathArray[0].c_str(), node, INDEX_LEAF); + SortingData4lParam* customData = new SortingData4lParam(TEXT(""), linarPathArray[0], false); + sortingDataArray.push_back(customData); + + _treeView.addItem(linarPathArray[0].c_str(), node, INDEX_LEAF, reinterpret_cast(customData)); } + _treeView.customSorting(node, categorySortFunc, 0); return true; } else @@ -1262,10 +1276,29 @@ bool FileBrowser::renameInTree(const generic_string& rootPath, HTREEITEM node, c // found it, rename it _treeView.renameItem(foundItem, renameTo.c_str()); + SortingData4lParam* compareData = reinterpret_cast(_treeView.getItemParam(foundItem)); + compareData->_label = renameTo; + _treeView.customSorting(_treeView.getParent(foundItem), categorySortFunc, 0); return true; } +int CALLBACK FileBrowser::categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM /*lParamSort*/) +{ + SortingData4lParam* item1 = reinterpret_cast(lParam1); + SortingData4lParam* item2 = reinterpret_cast(lParam2); + + if (!item1 || !item2) + return 0; + + if (item1->_isFolder && !item2->_isFolder) + return -1; + else if (!item1->_isFolder && item2->_isFolder) + return 1; + else + return lstrcmpi(item1->_label.c_str(), item2->_label.c_str()); +} + bool FolderInfo::addToStructure(generic_string & fullpath, std::vector linarPathArray) { if (linarPathArray.size() == 1) // could be file or folder @@ -1467,14 +1500,12 @@ DWORD WINAPI FolderUpdater::watching(void *params) { case FILE_ACTION_ADDED: file2Change.push_back(wstrFilename); - //thisFolderUpdater->updateTree(dwAction, file2Change); ::SendMessage((thisFolderUpdater->_pFileBrowser)->getHSelf(), FB_ADDFILE, reinterpret_cast(nullptr), reinterpret_cast(&file2Change)); oldName = TEXT(""); break; case FILE_ACTION_REMOVED: file2Change.push_back(wstrFilename); - //thisFolderUpdater->updateTree(dwAction, file2Change); ::SendMessage((thisFolderUpdater->_pFileBrowser)->getHSelf(), FB_RMFILE, reinterpret_cast(nullptr), reinterpret_cast(&file2Change)); oldName = TEXT(""); break; diff --git a/PowerEditor/src/WinControls/FileBrowser/fileBrowser.h b/PowerEditor/src/WinControls/FileBrowser/fileBrowser.h index 1010b6c9..fb6daf2b 100644 --- a/PowerEditor/src/WinControls/FileBrowser/fileBrowser.h +++ b/PowerEditor/src/WinControls/FileBrowser/fileBrowser.h @@ -113,6 +113,14 @@ private: static DWORD WINAPI watching(void *param); }; +struct SortingData4lParam { + generic_string _rootPath; // Only for the root. It should be empty if it's not root + generic_string _label; // TreeView item label + bool _isFolder = false; // if it's not a folder, then it's a file + + SortingData4lParam(generic_string rootPath, generic_string label, bool isFolder) : _rootPath(rootPath), _label(label), _isFolder(isFolder) {} +}; + class FileBrowser : public DockingDlgInterface { public: FileBrowser(): DockingDlgInterface(IDD_FILEBROWSER) {}; @@ -168,7 +176,7 @@ protected: HMENU _hFileMenu = NULL; std::vector _folderUpdaters; - std::vector rootPaths; + std::vector sortingDataArray; void initPopupMenus(); void destroyMenus(); @@ -184,4 +192,5 @@ protected: void openSelectFile(); void getDirectoryStructure(const TCHAR *dir, const std::vector & patterns, FolderInfo & directoryStructure, bool isRecursive, bool isInHiddenDir); HTREEITEM createFolderItemsFromDirStruct(HTREEITEM hParentItem, const FolderInfo & directoryStructure); + static int CALLBACK categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); }; diff --git a/PowerEditor/src/WinControls/ProjectPanel/TreeView.cpp b/PowerEditor/src/WinControls/ProjectPanel/TreeView.cpp index 55470a61..140a17a2 100644 --- a/PowerEditor/src/WinControls/ProjectPanel/TreeView.cpp +++ b/PowerEditor/src/WinControls/ProjectPanel/TreeView.cpp @@ -690,3 +690,14 @@ void TreeView::sort(HTREEITEM hTreeItem, bool isRecusive) for (HTREEITEM hItem = getChildFrom(hTreeItem); hItem != NULL; hItem = getNextSibling(hItem)) sort(hItem, isRecusive); } + + +void TreeView::customSorting(HTREEITEM hTreeItem, PFNTVCOMPARE sortingCallbackFunc, LPARAM lParam) +{ + TVSORTCB treeViewSortCB; + treeViewSortCB.hParent = hTreeItem; + treeViewSortCB.lpfnCompare = sortingCallbackFunc; + treeViewSortCB.lParam = lParam; + + ::SendMessage(_hSelf, TVM_SORTCHILDRENCB, 0, reinterpret_cast(&treeViewSortCB)); +} diff --git a/PowerEditor/src/WinControls/ProjectPanel/TreeView.h b/PowerEditor/src/WinControls/ProjectPanel/TreeView.h index 9561ed95..7ebd207d 100644 --- a/PowerEditor/src/WinControls/ProjectPanel/TreeView.h +++ b/PowerEditor/src/WinControls/ProjectPanel/TreeView.h @@ -126,6 +126,7 @@ public: bool retrieveFoldingStateTo(TreeStateNode & treeState2Construct, HTREEITEM treeviewNode); bool searchLeafAndBuildTree(TreeView & tree2Build, const generic_string & text2Search, int index2Search); void sort(HTREEITEM hTreeItem, bool isRecusive); + void customSorting(HTREEITEM hTreeItem, PFNTVCOMPARE sortingCallbackFunc, LPARAM lParam); protected: WNDPROC _defaultProc;