|
|
|
@ -14,7 +14,7 @@
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//fileBrowser类的具体实现
|
|
|
|
|
#include "fileBrowser.h"
|
|
|
|
|
#include "resource.h"
|
|
|
|
|
#include "tinyxml.h"
|
|
|
|
@ -41,7 +41,7 @@
|
|
|
|
|
#define FB_CMD_FOLDALL 2
|
|
|
|
|
#define FB_CMD_EXPANDALL 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//停止所有文件监视器
|
|
|
|
|
FileBrowser::~FileBrowser()
|
|
|
|
|
{
|
|
|
|
|
for (const auto folder : _folderUpdaters)
|
|
|
|
@ -55,7 +55,7 @@ FileBrowser::~FileBrowser()
|
|
|
|
|
delete cd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//将一个字符串分割成多个子字符串,函数使用了for循环依次检查字符串中的每个字符,当找到等于`sep`或者空字符的字符时,就把这之前的字符作为一个子字符串存储在`splitedStrings`向量中。
|
|
|
|
|
vector<generic_string> split(const generic_string & string2split, TCHAR sep)
|
|
|
|
|
{
|
|
|
|
|
vector<generic_string> splitedStrings;
|
|
|
|
@ -71,7 +71,7 @@ vector<generic_string> split(const generic_string & string2split, TCHAR sep)
|
|
|
|
|
}
|
|
|
|
|
return splitedStrings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//检查子文件夹是否与根文件相关
|
|
|
|
|
bool isRelatedRootFolder(const generic_string & relatedRoot, const generic_string & subFolder)
|
|
|
|
|
{
|
|
|
|
|
if (relatedRoot.empty())
|
|
|
|
@ -91,11 +91,11 @@ bool isRelatedRootFolder(const generic_string & relatedRoot, const generic_strin
|
|
|
|
|
|
|
|
|
|
return relatedRootArray[index2Compare] == subFolderArray[index2Compare];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//消息处理
|
|
|
|
|
intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
{
|
|
|
|
|
switch (message)
|
|
|
|
|
{
|
|
|
|
|
{//会话框初始化,包括创建工具条,树状视图的初始化等。
|
|
|
|
|
case WM_INITDIALOG :
|
|
|
|
|
{
|
|
|
|
|
NppParameters& nppParam = NppParameters::getInstance();
|
|
|
|
@ -175,7 +175,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//处理黑暗模式刷新的消息
|
|
|
|
|
case NPPM_INTERNAL_REFRESHDARKMODE:
|
|
|
|
|
{
|
|
|
|
|
if (static_cast<BOOL>(lParam) != TRUE)
|
|
|
|
@ -185,7 +185,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
NppDarkMode::setTreeViewStyle(_treeView.getHSelf());
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//鼠标消息
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
|
if (_treeView.isDragging())
|
|
|
|
|
_treeView.dragItem(_hSelf, LOWORD(lParam), HIWORD(lParam));
|
|
|
|
@ -197,13 +197,13 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
//通知消息
|
|
|
|
|
case WM_NOTIFY:
|
|
|
|
|
{
|
|
|
|
|
notified((LPNMHDR)lParam);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
//得到窗体的新宽度和高度,然后调整工具条和树形视图的位置和大小。
|
|
|
|
|
case WM_SIZE:
|
|
|
|
|
{
|
|
|
|
|
int width = LOWORD(lParam);
|
|
|
|
@ -220,28 +220,28 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
::MoveWindow(hwnd, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//文本菜单
|
|
|
|
|
case WM_CONTEXTMENU:
|
|
|
|
|
if (!_treeView.isDragging())
|
|
|
|
|
showContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
//来自菜单的选择
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
|
{
|
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
|
{
|
|
|
|
|
{//选择当前正在编辑的文件。
|
|
|
|
|
case FB_CMD_AIMFILE:
|
|
|
|
|
{
|
|
|
|
|
selectCurrentEditingFile();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//折叠
|
|
|
|
|
case FB_CMD_FOLDALL:
|
|
|
|
|
{
|
|
|
|
|
_treeView.foldAll();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//展开
|
|
|
|
|
case FB_CMD_EXPANDALL:
|
|
|
|
|
{
|
|
|
|
|
_treeView.expandAll();
|
|
|
|
@ -253,7 +253,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//销毁
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
|
{
|
|
|
|
|
::DestroyWindow(_hToolbarMenu);
|
|
|
|
@ -261,7 +261,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
destroyMenus();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//添加
|
|
|
|
|
case FB_ADDFILE:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
@ -274,7 +274,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//移除
|
|
|
|
|
case FB_RMFILE:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
@ -287,7 +287,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//重命名
|
|
|
|
|
case FB_RNFILE:
|
|
|
|
|
{
|
|
|
|
|
const std::vector<generic_string> file2Change = *(std::vector<generic_string> *)lParam;
|
|
|
|
@ -324,7 +324,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l
|
|
|
|
|
}
|
|
|
|
|
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//创建一个文件浏览器的时候,初始化弹出菜单。首先收集各种与菜单项相关的字符串,然后创建三种不同的菜单:全局菜单、根菜单、文件夹菜单和文件菜单,向这些菜单中插入各种菜单项。
|
|
|
|
|
void FileBrowser::initPopupMenus()
|
|
|
|
|
{
|
|
|
|
|
NativeLangSpeaker* pNativeSpeaker = NppParameters::getInstance().getNativeLangSpeaker();
|
|
|
|
@ -370,7 +370,7 @@ void FileBrowser::initPopupMenus()
|
|
|
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_FILEBROWSER_EXPLORERHERE, explorerHere.c_str());
|
|
|
|
|
::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_FILEBROWSER_CMDHERE, cmdHere.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//通过一个给定的路径选中文件浏览器中的一个项目。它首先检查路径是否为空,然后通过遍历所有的文件夹来寻找对应的项目。
|
|
|
|
|
bool FileBrowser::selectItemFromPath(const generic_string& itemPath) const
|
|
|
|
|
{
|
|
|
|
|
if (itemPath.empty())
|
|
|
|
@ -409,7 +409,7 @@ bool FileBrowser::selectItemFromPath(const generic_string& itemPath) const
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//选择当前正在编辑的文件。
|
|
|
|
|
bool FileBrowser::selectCurrentEditingFile() const
|
|
|
|
|
{
|
|
|
|
|
TCHAR currentDocPath[MAX_PATH] = { '\0' };
|
|
|
|
@ -418,7 +418,7 @@ bool FileBrowser::selectCurrentEditingFile() const
|
|
|
|
|
|
|
|
|
|
return selectItemFromPath(currentDocPathStr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//摧毁创建的菜单
|
|
|
|
|
void FileBrowser::destroyMenus()
|
|
|
|
|
{
|
|
|
|
|
::DestroyMenu(_hGlobalMenu);
|
|
|
|
@ -426,7 +426,7 @@ void FileBrowser::destroyMenus()
|
|
|
|
|
::DestroyMenu(_hFolderMenu);
|
|
|
|
|
::DestroyMenu(_hFileMenu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//返回一个给定节点的完整路径。
|
|
|
|
|
generic_string FileBrowser::getNodePath(HTREEITEM node) const
|
|
|
|
|
{
|
|
|
|
|
if (!node) return TEXT("");
|
|
|
|
@ -460,12 +460,12 @@ generic_string FileBrowser::getNodePath(HTREEITEM node) const
|
|
|
|
|
|
|
|
|
|
return fullPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//返回一个给定节点的名称。
|
|
|
|
|
generic_string FileBrowser::getNodeName(HTREEITEM node) const
|
|
|
|
|
{
|
|
|
|
|
return node ? _treeView.getItemDisplayName(node) : TEXT("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//打开选定的文件。如果选定的项目是一个文件,那么就打开它;否则,不执行任何操作。
|
|
|
|
|
void FileBrowser::openSelectFile()
|
|
|
|
|
{
|
|
|
|
|
// Get the selected item
|
|
|
|
@ -483,7 +483,7 @@ void FileBrowser::openSelectFile()
|
|
|
|
|
::PostMessage(_hParent, NPPM_DOOPEN, 0, reinterpret_cast<LPARAM>(_selectedNodeFullPath.c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//处理各种菜单操作的事件。例如,如果一个菜单项被双击,那么就调用函数进行对应的处理;如果一个节点标签被编辑,那么函数就保存新的标签。
|
|
|
|
|
void FileBrowser::notified(LPNMHDR notification)
|
|
|
|
|
{
|
|
|
|
|
if (notification->code == DMN_CLOSE)
|
|
|
|
@ -673,7 +673,7 @@ void FileBrowser::notified(LPNMHDR notification)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//获取给定项目(`hItem`)的节点类型。函数首先获取项目的索引(`iImage`),如果索引为`INDEX_LEAF`,则节点类型为文件;如果项目的参数(`lParam`)不为空并且`SortingData4lParam`类中`_rootPath`成员不为空,那么节点类型为根;否则,节点类型为文件夹。
|
|
|
|
|
BrowserNodeType FileBrowser::getNodeType(HTREEITEM hItem)
|
|
|
|
|
{
|
|
|
|
|
TVITEM tvItem;
|
|
|
|
@ -697,7 +697,7 @@ BrowserNodeType FileBrowser::getNodeType(HTREEITEM hItem)
|
|
|
|
|
return browserNodeType_folder;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//(x, y)位置显示上下文菜单。函数首先检测给定位置是否在一个元素上,如果是的话就选中该元素,并获取该元素的节点类型,然后根据节点类型显示相应的上下文菜单。
|
|
|
|
|
void FileBrowser::showContextMenu(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
TVHITTESTINFO tvHitInfo{};
|
|
|
|
@ -735,7 +735,7 @@ void FileBrowser::showContextMenu(int x, int y)
|
|
|
|
|
x, y, 0, _hSelf, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//执行与给定命令ID(`cmdID`)关联的上下文菜单命令。例如,如果命令ID为`IDM_FILEBROWSER_REMOVEROOTFOLDER`,则函数将删除选定的根文件夹。
|
|
|
|
|
void FileBrowser::popupMenuCmd(int cmdID)
|
|
|
|
|
{
|
|
|
|
|
// get selected item handle
|
|
|
|
@ -872,7 +872,7 @@ void FileBrowser::popupMenuCmd(int cmdID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//在目录`dir`中获取符合`patterns`模式的所有文件和子目录的结构信息,并将其保存到`directoryStructure`中。`isRecursive`参数指定是否递归遍历子目录,`isInHiddenDir`参数指示当前目录是否为隐藏目录。
|
|
|
|
|
void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<generic_string> & patterns, FolderInfo & directoryStructure, bool isRecursive, bool isInHiddenDir)
|
|
|
|
|
{
|
|
|
|
|
if (directoryStructure._parent == nullptr) // Root!
|
|
|
|
@ -954,12 +954,13 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
|
|
|
|
|
}
|
|
|
|
|
::FindClose(hFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//添加根文件夹
|
|
|
|
|
void FileBrowser::addRootFolder(generic_string rootFolderPath)
|
|
|
|
|
{
|
|
|
|
|
{//检查根文件夹路径是否存在
|
|
|
|
|
if (!::PathFileExists(rootFolderPath.c_str()))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// 检查根文件夹路径是否是一个目录
|
|
|
|
|
if (!::PathIsDirectory(rootFolderPath.c_str()))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
@ -968,13 +969,13 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath)
|
|
|
|
|
{
|
|
|
|
|
rootFolderPath = rootFolderPath.substr(0, rootFolderPath.length() - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遍历已添加的根文件夹更新器
|
|
|
|
|
for (const auto f : _folderUpdaters)
|
|
|
|
|
{
|
|
|
|
|
{ // 检查是否已经添加相同路径的根文件夹
|
|
|
|
|
if (f->_rootFolder._rootPath == rootFolderPath)
|
|
|
|
|
return;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
{ // 检查是否存在相关的根文件夹,以便选择目录
|
|
|
|
|
if (isRelatedRootFolder(f->_rootFolder._rootPath, rootFolderPath))
|
|
|
|
|
{
|
|
|
|
|
//do nothing, go down to select the dir
|
|
|
|
@ -987,9 +988,9 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath)
|
|
|
|
|
_treeView.selectItem(foundItem);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否存在相对于要添加的根文件夹的子文件夹
|
|
|
|
|
if (isRelatedRootFolder(rootFolderPath, f->_rootFolder._rootPath))
|
|
|
|
|
{
|
|
|
|
|
{// 显示消息框,指示存在子文件夹,需要先移除
|
|
|
|
|
NppParameters::getInstance().getNativeLangSpeaker()->messageBox("FolderAsWorspaceSubfolderExists",
|
|
|
|
|
_hParent,
|
|
|
|
|
TEXT("A sub-folder of the folder you want to add exists.\rPlease remove its root from the panel before you add folder \"$STR_REPLACE$\"."),
|
|
|
|
@ -1001,10 +1002,10 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置要匹配的文件模式
|
|
|
|
|
std::vector<generic_string> patterns2Match;
|
|
|
|
|
patterns2Match.push_back(TEXT("*.*"));
|
|
|
|
|
|
|
|
|
|
// 获取根文件夹的名称并创建相应的文件夹信息对象
|
|
|
|
|
TCHAR *label = ::PathFindFileName(rootFolderPath.c_str());
|
|
|
|
|
TCHAR rootLabel[MAX_PATH] = {'\0'};
|
|
|
|
|
wcscpy_s(rootLabel, label);
|
|
|
|
@ -1019,10 +1020,11 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath)
|
|
|
|
|
_folderUpdaters.push_back(new FolderUpdater(directoryStructure, this));
|
|
|
|
|
_folderUpdaters[_folderUpdaters.size() - 1]->startWatcher();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//创建文件夹项目从目录结构
|
|
|
|
|
HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, const FolderInfo & directoryStructure)
|
|
|
|
|
{
|
|
|
|
|
HTREEITEM hFolderItem = nullptr;
|
|
|
|
|
// 如果是根目录,则创建根节点
|
|
|
|
|
if (directoryStructure._parent == nullptr && hParentItem == nullptr)
|
|
|
|
|
{
|
|
|
|
|
TCHAR rootPath[MAX_PATH] = { '\0' };
|
|
|
|
@ -1033,14 +1035,14 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con
|
|
|
|
|
|
|
|
|
|
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<LPARAM>(customData));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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<LPARAM>(customData));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1053,7 +1055,7 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con
|
|
|
|
|
{
|
|
|
|
|
SortingData4lParam* customData = new SortingData4lParam(TEXT(""), file._name, false);
|
|
|
|
|
sortingDataArray.push_back(customData);
|
|
|
|
|
|
|
|
|
|
// 添加文件节点到树视图
|
|
|
|
|
_treeView.addItem(file._name.c_str(), hFolderItem, INDEX_LEAF, reinterpret_cast<LPARAM>(customData));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1061,7 +1063,7 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con
|
|
|
|
|
|
|
|
|
|
return hFolderItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据路径找到根目录
|
|
|
|
|
HTREEITEM FileBrowser::getRootFromFullPath(const generic_string & rootPath) const
|
|
|
|
|
{
|
|
|
|
|
HTREEITEM node = nullptr;
|
|
|
|
@ -1080,7 +1082,7 @@ HTREEITEM FileBrowser::getRootFromFullPath(const generic_string & rootPath) cons
|
|
|
|
|
}
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//在指定父节点下查找具有特定名称的子节点。
|
|
|
|
|
HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, const generic_string& label) const
|
|
|
|
|
{
|
|
|
|
|
for (HTREEITEM hItemNode = _treeView.getChildFrom(parent);
|
|
|
|
@ -1102,7 +1104,7 @@ HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, const generic_str
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//得到所有根节点的路径
|
|
|
|
|
vector<generic_string> FileBrowser::getRoots() const
|
|
|
|
|
{
|
|
|
|
|
vector<generic_string> roots;
|
|
|
|
@ -1121,7 +1123,7 @@ vector<generic_string> FileBrowser::getRoots() const
|
|
|
|
|
}
|
|
|
|
|
return roots;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//获取选中文件的路径
|
|
|
|
|
generic_string FileBrowser::getSelectedItemPath() const
|
|
|
|
|
{
|
|
|
|
|
generic_string itemPath;
|
|
|
|
@ -1132,7 +1134,7 @@ generic_string FileBrowser::getSelectedItemPath() const
|
|
|
|
|
}
|
|
|
|
|
return itemPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//将传递的文件路径信息分组,按照共同路径和根路径进行分类。
|
|
|
|
|
std::vector<FileBrowser::FilesToChange> FileBrowser::getFilesFromParam(LPARAM lParam) const
|
|
|
|
|
{
|
|
|
|
|
const std::vector<generic_string> filesToChange = *(std::vector<generic_string>*)lParam;
|
|
|
|
@ -1189,7 +1191,7 @@ std::vector<FileBrowser::FilesToChange> FileBrowser::getFilesFromParam(LPARAM lP
|
|
|
|
|
|
|
|
|
|
return groupedFiles;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//将文件组添加到树中,根据文件类型在树中创建相应的节点。
|
|
|
|
|
bool FileBrowser::addToTree(FilesToChange & group, HTREEITEM node)
|
|
|
|
|
{
|
|
|
|
|
if (node == nullptr) // it's a root. Search the right root with rootPath
|
|
|
|
@ -1266,7 +1268,7 @@ bool FileBrowser::addToTree(FilesToChange & group, HTREEITEM node)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//在树中查找并删除指定的文件组。
|
|
|
|
|
bool FileBrowser::deleteFromTree(FilesToChange & group)
|
|
|
|
|
{
|
|
|
|
|
std::vector<HTREEITEM> foundItems = findInTree(group, nullptr);
|
|
|
|
@ -1283,7 +1285,7 @@ bool FileBrowser::deleteFromTree(FilesToChange & group)
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//在树形结构中查找指定路径,首先判断当前节点是否为根节点,若是则根据根路径查找对应的根节点。然后根据路径数组的大小,判断是否继续查找子节点或者返回当前节点。
|
|
|
|
|
HTREEITEM FileBrowser::findInTree(const generic_string& rootPath, HTREEITEM node, std::vector<generic_string> linarPathArray) const
|
|
|
|
|
{
|
|
|
|
|
if (node == nullptr) // it's a root. Search the right root with rootPath
|
|
|
|
@ -1326,7 +1328,7 @@ HTREEITEM FileBrowser::findInTree(const generic_string& rootPath, HTREEITEM node
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//该函数也用于在树形结构中查找指定路径,但参数不同。参数group是一个包含文件信息和路径的对象,node表示当前节点。函数首先判断当前节点是否为根节点,若是则根据路径信息查找对应的根节点。然后根据路径信息的大小,判断是否继续查找子节点或者返回找到的节点集合。
|
|
|
|
|
std::vector<HTREEITEM> FileBrowser::findInTree(FilesToChange & group, HTREEITEM node) const
|
|
|
|
|
{
|
|
|
|
|
if (node == nullptr) // it's a root. Search the right root with rootPath
|
|
|
|
@ -1367,7 +1369,7 @@ std::vector<HTREEITEM> FileBrowser::findInTree(FilesToChange & group, HTREEITEM
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//找到指定父节点的子节点
|
|
|
|
|
std::vector<HTREEITEM> FileBrowser::findChildNodesFromNames(HTREEITEM parent, std::vector<generic_string> & labels) const
|
|
|
|
|
{
|
|
|
|
|
std::vector<HTREEITEM> itemNodes;
|
|
|
|
@ -1394,6 +1396,7 @@ std::vector<HTREEITEM> FileBrowser::findChildNodesFromNames(HTREEITEM parent, st
|
|
|
|
|
}
|
|
|
|
|
return itemNodes;
|
|
|
|
|
}
|
|
|
|
|
//移除已经在父节点中的名字。它遍历父节点的所有子节点,并将与给定标签集合中名字相匹配的标签清除。
|
|
|
|
|
|
|
|
|
|
void FileBrowser::removeNamesAlreadyInNode(HTREEITEM parent, std::vector<generic_string> & labels) const
|
|
|
|
|
{
|
|
|
|
@ -1418,7 +1421,7 @@ void FileBrowser::removeNamesAlreadyInNode(HTREEITEM parent, std::vector<generic
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//在树形结构中重命名节点,找到匹配给定线性路径数组的节点,并将其重新命名为指定的字符串。
|
|
|
|
|
bool FileBrowser::renameInTree(const generic_string& rootPath, HTREEITEM node, const std::vector<generic_string>& linarPathArrayFrom, const generic_string & renameTo)
|
|
|
|
|
{
|
|
|
|
|
HTREEITEM foundItem = findInTree(rootPath, node, linarPathArrayFrom);
|
|
|
|
@ -1433,7 +1436,7 @@ bool FileBrowser::renameInTree(const generic_string& rootPath, HTREEITEM node, c
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//排序回调函数,按照文件夹和文件名进行排序。首先是文件夹,然后是文件。如果两者都是文件夹或文件,那么比较它们的名字。
|
|
|
|
|
int CALLBACK FileBrowser::categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM /*lParamSort*/)
|
|
|
|
|
{
|
|
|
|
|
SortingData4lParam* item1 = reinterpret_cast<SortingData4lParam*>(lParam1);
|
|
|
|
@ -1449,7 +1452,7 @@ int CALLBACK FileBrowser::categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARA
|
|
|
|
|
else
|
|
|
|
|
return lstrcmpi(item1->_label.c_str(), item2->_label.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//将给定的完整路径添加到文件夹信息结构中。该路径可能是文件或目录,如果该路径已经存在于结构中,则返回false,如果成功添加,则返回true。
|
|
|
|
|
bool FolderInfo::addToStructure(generic_string & fullpath, std::vector<generic_string> linarPathArray)
|
|
|
|
|
{
|
|
|
|
|
if (linarPathArray.size() == 1) // could be file or folder
|
|
|
|
@ -1494,7 +1497,7 @@ bool FolderInfo::addToStructure(generic_string & fullpath, std::vector<generic_s
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//从文件夹信息结构中删除给定的线性路径数组。成功删除返回true,否则返回false。
|
|
|
|
|
bool FolderInfo::removeFromStructure(std::vector<generic_string> linarPathArray)
|
|
|
|
|
{
|
|
|
|
|
if (linarPathArray.size() == 1) // could be file or folder
|
|
|
|
@ -1532,7 +1535,7 @@ bool FolderInfo::removeFromStructure(std::vector<generic_string> linarPathArray)
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//在文件夹信息结构中重命名给定的线性路径。它将 "linarPathArrayFrom" 指定的路径的名字更改为 "linarPathArrayTo" 指定的名字。
|
|
|
|
|
bool FolderInfo::renameInStructure(std::vector<generic_string> linarPathArrayFrom, std::vector<generic_string> linarPathArrayTo)
|
|
|
|
|
{
|
|
|
|
|
if (linarPathArrayFrom.size() == 1) // could be file or folder
|
|
|
|
@ -1572,6 +1575,7 @@ bool FolderInfo::renameInStructure(std::vector<generic_string> linarPathArrayFro
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//打开监视器,创建一个事件对象并开启一个新的线程,线程开始运行 `watching` 函数。
|
|
|
|
|
|
|
|
|
|
void FolderUpdater::startWatcher()
|
|
|
|
|
{
|
|
|
|
@ -1579,6 +1583,7 @@ void FolderUpdater::startWatcher()
|
|
|
|
|
_EventHandle = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
|
|
|
_watchThreadHandle = ::CreateThread(NULL, 0, watching, this, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
//停止监视器。它通过设定事件和关闭对应的线程实现。
|
|
|
|
|
|
|
|
|
|
void FolderUpdater::stopWatcher()
|
|
|
|
|
{
|
|
|
|
@ -1586,6 +1591,7 @@ void FolderUpdater::stopWatcher()
|
|
|
|
|
::CloseHandle(_watchThreadHandle);
|
|
|
|
|
::CloseHandle(_EventHandle);
|
|
|
|
|
}
|
|
|
|
|
//根据动作类型的代码返回相应的动作名字。
|
|
|
|
|
|
|
|
|
|
LPCWSTR explainAction(DWORD dwAction)
|
|
|
|
|
{
|
|
|
|
@ -1606,6 +1612,7 @@ LPCWSTR explainAction(DWORD dwAction)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//负责监视目录下的文件变化。当有文件被创建、删除、重命名等操作时,就会将这个改动放入改动队列,并通过事件提醒主线程进行处理。
|
|
|
|
|
|
|
|
|
|
DWORD WINAPI FolderUpdater::watching(void *params)
|
|
|
|
|
{
|
|
|
|
@ -1704,6 +1711,7 @@ DWORD WINAPI FolderUpdater::watching(void *params)
|
|
|
|
|
//printStr(L"Quit watching thread");
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
//根据改动的类型,调用不同的文件浏览器的方法,例如文件创建、删除、重命名等。
|
|
|
|
|
|
|
|
|
|
void FolderUpdater::processChange(DWORD dwAction, std::vector<generic_string> filesToChange, FolderUpdater* thisFolderUpdater)
|
|
|
|
|
{
|
|
|
|
|