File Browser (in progress)

Make file and folder add/delete/rename detection from outside work.
This commit is contained in:
Don Ho 2016-01-28 19:05:41 +01:00
parent a1c608ba61
commit 0ad1964d1d
4 changed files with 440 additions and 319 deletions

View File

@ -580,7 +580,7 @@ POINT FileBrowser::getMenuDisplayPoint(int iButton)
return p;
}
HTREEITEM FileBrowser::addFolder(HTREEITEM hTreeItem, const TCHAR *folderName)
HTREEITEM FileBrowser::createNewFolder(HTREEITEM hTreeItem, const TCHAR *folderName)
{
HTREEITEM addedItem = _treeView.addItem(folderName, hTreeItem, INDEX_CLOSED_NODE);
@ -639,7 +639,7 @@ void FileBrowser::popupMenuCmd(int cmdID)
{
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance())->getNativeLangSpeaker();
generic_string newFolderLabel = pNativeSpeaker->getAttrNameStr(PM_NEWFOLDERNAME, "ProjectManager", "NewFolderName");
addFolder(hTreeItem, newFolderLabel.c_str());
createNewFolder(hTreeItem, newFolderLabel.c_str());
}
break;
@ -655,6 +655,7 @@ void FileBrowser::popupMenuCmd(int cmdID)
}
break;
/*
case IDM_FILEBROWSER_ADDFILES :
{
addFiles(hTreeItem);
@ -662,6 +663,7 @@ void FileBrowser::popupMenuCmd(int cmdID)
_treeView.setItemImage(hTreeItem, INDEX_OPEN_NODE, INDEX_OPEN_NODE);
}
break;
*/
case IDM_FILEBROWSER_DELETEFOLDER :
{
@ -701,84 +703,12 @@ void FileBrowser::popupMenuCmd(int cmdID)
}
}
void FileBrowser::addFiles(HTREEITEM hTreeItem)
{
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
{
size_t sz = pfns->size();
for (size_t i = 0 ; i < sz ; ++i)
{
TCHAR *strValueLabel = ::PathFindFileName(pfns->at(i).c_str());
_treeView.addItem(strValueLabel, hTreeItem, INDEX_LEAF, pfns->at(i).c_str());
}
_treeView.expand(hTreeItem);
}
}
void FileBrowser::recursiveAddFilesFrom(const TCHAR *folderPath, HTREEITEM hTreeItem)
{
bool isRecursive = true;
bool isInHiddenDir = false;
generic_string dirFilter(folderPath);
if (folderPath[lstrlen(folderPath)-1] != '\\')
dirFilter += TEXT("\\");
dirFilter += TEXT("*.*");
WIN32_FIND_DATA foundData;
std::vector<generic_string> files;
HANDLE hFile = ::FindFirstFile(dirFilter.c_str(), &foundData);
do {
if (hFile == INVALID_HANDLE_VALUE)
break;
if (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!isInHiddenDir && (foundData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
{
// do nothing
}
else if (isRecursive)
{
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
{
generic_string pathDir(folderPath);
if (folderPath[lstrlen(folderPath)-1] != '\\')
pathDir += TEXT("\\");
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
HTREEITEM addedItem = addFolder(hTreeItem, foundData.cFileName);
recursiveAddFilesFrom(pathDir.c_str(), addedItem);
}
}
}
else
{
files.push_back(foundData.cFileName);
}
} while (::FindNextFile(hFile, &foundData));
for (size_t i = 0, len = files.size() ; i < len ; ++i)
{
generic_string pathFile(folderPath);
if (folderPath[lstrlen(folderPath)-1] != '\\')
pathFile += TEXT("\\");
pathFile += files[i];
_treeView.addItem(files[i].c_str(), hTreeItem, INDEX_LEAF, pathFile.c_str());
}
::FindClose(hFile);
}
void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<generic_string> & patterns, FolderInfo & directoryStructure, bool isRecursive, bool isInHiddenDir)
{
directoryStructure.setPath(dir);
if (directoryStructure._parent == nullptr) // Root!
directoryStructure.setRootPath(dir);
generic_string dirFilter(dir);
dirFilter += TEXT("*.*");
@ -803,7 +733,7 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
FolderInfo subDirectoryStructure;
FolderInfo subDirectoryStructure(foundData.cFileName, &directoryStructure);
getDirectoryStructure(pathDir.c_str(), patterns, subDirectoryStructure, isRecursive, isInHiddenDir);
directoryStructure.addSubFolder(subDirectoryStructure);
}
@ -813,12 +743,11 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
{
if (matchInList(foundData.cFileName, patterns))
{
generic_string pathFile(dir);
pathFile += foundData.cFileName;
directoryStructure.addFile(pathFile.c_str());
directoryStructure.addFile(foundData.cFileName);
}
}
}
while (::FindNextFile(hFile, &foundData))
{
if (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -835,7 +764,7 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
FolderInfo subDirectoryStructure;
FolderInfo subDirectoryStructure(foundData.cFileName, &directoryStructure);
getDirectoryStructure(pathDir.c_str(), patterns, subDirectoryStructure, isRecursive, isInHiddenDir);
directoryStructure.addSubFolder(subDirectoryStructure);
}
@ -845,9 +774,7 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
{
if (matchInList(foundData.cFileName, patterns))
{
generic_string pathFile(dir);
pathFile += foundData.cFileName;
directoryStructure.addFile(pathFile.c_str());
directoryStructure.addFile(foundData.cFileName);
}
}
}
@ -856,40 +783,40 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
void FileBrowser::addRootFolder(generic_string rootFolderPath)
{
for (size_t i = 0; i < _folderUpdaters.size(); ++i)
size_t nbFolderUpdaters = _folderUpdaters.size();
for (size_t i = 0; i < nbFolderUpdaters; ++i)
{
if (_folderUpdaters[i]._rootFolder._path == rootFolderPath)
if (_folderUpdaters[i]._rootFolder._rootPath == rootFolderPath)
return;
}
std::vector<generic_string> patterns2Match;
patterns2Match.push_back(TEXT("*.*"));
FolderInfo directoryStructure;
TCHAR *label = ::PathFindFileName(rootFolderPath.c_str());
FolderInfo directoryStructure(label, nullptr);
getDirectoryStructure(rootFolderPath.c_str(), patterns2Match, directoryStructure, true, false);
HTREEITEM hRootItem = createFolderItemsFromDirStruct(nullptr, directoryStructure);
_treeView.expand(hRootItem);
_folderUpdaters.push_back(FolderUpdater(directoryStructure, _hSelf));
_folderUpdaters.push_back(FolderUpdater(directoryStructure, this));
_folderUpdaters[_folderUpdaters.size() - 1].startWatcher();
}
HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, const FolderInfo & directoryStructure)
{
TCHAR rootPath[MAX_PATH];
lstrcpy(rootPath, directoryStructure._path.c_str());
size_t len = lstrlen(rootPath);
if (rootPath[len-1] == '\\')
rootPath[len-1] = '\0';
TCHAR *rootName = ::PathFindFileName(rootPath);
HTREEITEM hFolderItem = nullptr;
if (hParentItem == nullptr)
if (directoryStructure._parent == nullptr && hParentItem == nullptr)
{
hFolderItem = _treeView.addItem(rootName, TVI_ROOT, INDEX_CLOSED_NODE);
TCHAR rootPath[MAX_PATH];
lstrcpy(rootPath, directoryStructure._rootPath.c_str());
size_t len = lstrlen(rootPath);
if (rootPath[len - 1] == '\\')
rootPath[len - 1] = '\0';
hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), TVI_ROOT, INDEX_CLOSED_NODE, rootPath);
}
else
{
hFolderItem = addFolder(hParentItem, rootName);
hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), hParentItem, INDEX_CLOSED_NODE);
}
for (size_t i = 0; i < directoryStructure._subFolders.size(); ++i)
@ -899,218 +826,328 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con
for (size_t i = 0; i < directoryStructure._files.size(); ++i)
{
TCHAR filePath[MAX_PATH];
lstrcpy(filePath, directoryStructure._files[i]._path.c_str());
TCHAR *fileName = ::PathFindFileName(filePath);
_treeView.addItem(fileName, hFolderItem, INDEX_LEAF, directoryStructure._files[i]._path.c_str());
_treeView.addItem(directoryStructure._files[i]._name.c_str(), hFolderItem, INDEX_LEAF);
}
_treeView.fold(hParentItem);
return hFolderItem;
}
bool FolderInfo::compare(const FolderInfo & struct2compare, std::vector<changeInfo> & result)
HTREEITEM FileBrowser::getRootFromFullPath(generic_string rootPath)
{
if (_contentHash == struct2compare._contentHash)
HTREEITEM node = nullptr;
for (HTREEITEM hItemNode = _treeView.getRoot();
hItemNode != nullptr && node == nullptr;
hItemNode = _treeView.getNextSibling(hItemNode))
{
if (_path == struct2compare._path) // Everything is fine
TVITEM tvItem;
tvItem.mask = TVIF_PARAM;
tvItem.cchTextMax = MAX_PATH;
tvItem.hItem = hItemNode;
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, (LPARAM)&tvItem);
if (tvItem.lParam != 0 && rootPath == *((generic_string *)tvItem.lParam))
node = hItemNode;
}
return node;
}
HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, generic_string label)
{
HTREEITEM childNodeFound = nullptr;
for (HTREEITEM hItemNode = _treeView.getChildFrom(parent);
hItemNode != NULL && childNodeFound == nullptr;
hItemNode = _treeView.getNextSibling(hItemNode))
{
TCHAR textBuffer[MAX_PATH];
TVITEM tvItem;
tvItem.mask = TVIF_TEXT;
tvItem.pszText = textBuffer;
tvItem.cchTextMax = MAX_PATH;
tvItem.hItem = hItemNode;
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, (LPARAM)&tvItem);
if (label == tvItem.pszText)
{
return true;
}
else // folder is renamed
{
// put result in the vector
changeInfo info;
info._action = info.rename;
info._fullFilePath = struct2compare._path;
return false;
childNodeFound = hItemNode;
}
}
else // sub-folders or files/sub-files deleted or renamed
return childNodeFound;
}
bool FileBrowser::addInTree(generic_string rootPath, generic_string addItemFullPath, HTREEITEM node, vector<generic_string> linarPathArray)
{
if (node == nullptr) // it's a root. Search the right root with rootPath
{
if (_path != struct2compare._path) // both content and path are different, stop to compare
{
return true; // everything could be fine
}
// Search
if ((node = getRootFromFullPath(rootPath)) == nullptr)
return false;
}
//check folder (maybe go deeper)
for (size_t i = 0; i < _subFolders.size(); ++i)
if (linarPathArray.size() == 1)
{
// Search : if no found, add
HTREEITEM childNodeFound = findChildNodeFromName(node, linarPathArray[0]);
if (childNodeFound != nullptr)
return false;
// No found, good - Action
if (::PathIsDirectory(addItemFullPath.c_str()))
{
bool isFound = false;
for (size_t j = 0; j < struct2compare._subFolders.size(); ++j)
_treeView.addItem(linarPathArray[0].c_str(), node, INDEX_CLOSED_NODE);
}
else
{
_treeView.addItem(linarPathArray[0].c_str(), node, INDEX_LEAF);
}
return true;
}
else
{
HTREEITEM childNodeFound = nullptr;
for (HTREEITEM hItemNode = _treeView.getChildFrom(node);
hItemNode != NULL && childNodeFound == nullptr;
hItemNode = _treeView.getNextSibling(hItemNode))
{
TCHAR textBuffer[MAX_PATH];
TVITEM tvItem;
tvItem.mask = TVIF_TEXT;
tvItem.pszText = textBuffer;
tvItem.cchTextMax = MAX_PATH;
tvItem.hItem = hItemNode;
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, (LPARAM)&tvItem);
if (linarPathArray[0] == tvItem.pszText)
{
if ((_subFolders[i]._path == struct2compare._subFolders[j]._path) &&
(_subFolders[i]._contentHash == struct2compare._subFolders[j]._contentHash))
{
isFound = true;
}
else
{
if ((_subFolders[i]._path != struct2compare._subFolders[j]._path) &&
(_subFolders[i]._contentHash == struct2compare._subFolders[j]._contentHash)) // rename
{
changeInfo info;
info._action = info.rename;
info._fullFilePath = struct2compare._path;
}
else if ((_subFolders[i]._path == struct2compare._subFolders[j]._path) &&
(_subFolders[i]._contentHash != struct2compare._subFolders[j]._contentHash)) // problem of sub-files or sub-folders. go deeper
{
_subFolders[i].compare(struct2compare._subFolders[j], result);
}
}
}
if (not isFound) // folder is deleted
{
// put result in the vector
changeInfo info;
info._action = info.remove;
info._fullFilePath = _subFolders[i]._path;
result.push_back(info);
// search recursively the node for an action
linarPathArray.erase(linarPathArray.begin());
return addInTree(rootPath, addItemFullPath, hItemNode, linarPathArray);
}
}
return false;
}
}
//check files
bool FileBrowser::deleteFromTree(generic_string rootPath, HTREEITEM node, std::vector<generic_string> linarPathArray)
{
if (node == nullptr) // it's a root. Search the right root with rootPath
{
// Search
if ((node = getRootFromFullPath(rootPath)) == nullptr)
return false;
}
if (linarPathArray.size() == 1)
{
// Search
HTREEITEM childNodeFound = findChildNodeFromName(node, linarPathArray[0]);
if (childNodeFound == nullptr)
return false;
// found it, delete it
_treeView.removeItem(childNodeFound);
return true;
}
else
{
HTREEITEM childNodeFound = nullptr;
for (HTREEITEM hItemNode = _treeView.getChildFrom(node);
hItemNode != NULL && childNodeFound == nullptr;
hItemNode = _treeView.getNextSibling(hItemNode))
{
TCHAR textBuffer[MAX_PATH];
TVITEM tvItem;
tvItem.mask = TVIF_TEXT;
tvItem.pszText = textBuffer;
tvItem.cchTextMax = MAX_PATH;
tvItem.hItem = hItemNode;
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, (LPARAM)&tvItem);
if (linarPathArray[0] == tvItem.pszText)
{
// search recursively the node for an action
linarPathArray.erase(linarPathArray.begin());
return deleteFromTree(rootPath, hItemNode, linarPathArray);
}
}
return false;
}
}
bool FileBrowser::renameInTree(generic_string rootPath, HTREEITEM node, std::vector<generic_string> linarPathArrayFrom, std::vector<generic_string> linarPathArrayTo)
{
if (node == nullptr) // it's a root. Search the right root with rootPath
{
// Search
if ((node = getRootFromFullPath(rootPath)) == nullptr)
return false;
}
if (linarPathArrayFrom.size() == 1)
{
// Search
HTREEITEM childNodeFound = findChildNodeFromName(node, linarPathArrayFrom[0]);
if (childNodeFound == nullptr)
return false;
// found it, rename it
_treeView.renameItem(childNodeFound, linarPathArrayTo[0].c_str());
return true;
}
else
{
HTREEITEM childNodeFound = nullptr;
for (HTREEITEM hItemNode = _treeView.getChildFrom(node);
hItemNode != NULL && childNodeFound == nullptr;
hItemNode = _treeView.getNextSibling(hItemNode))
{
TCHAR textBuffer[MAX_PATH];
TVITEM tvItem;
tvItem.mask = TVIF_TEXT;
tvItem.pszText = textBuffer;
tvItem.cchTextMax = MAX_PATH;
tvItem.hItem = hItemNode;
SendMessage(_treeView.getHSelf(), TVM_GETITEM, 0, (LPARAM)&tvItem);
if (linarPathArrayFrom[0] == tvItem.pszText)
{
// search recursively the node for an action
linarPathArrayFrom.erase(linarPathArrayFrom.begin());
linarPathArrayTo.erase(linarPathArrayTo.begin());
return renameInTree(rootPath, hItemNode, linarPathArrayFrom, linarPathArrayTo);
}
}
return false;
}
}
bool FolderInfo::addToStructure(generic_string & fullpath, std::vector<generic_string> linarPathArray)
{
if (linarPathArray.size() == 1) // could be file or folder
{
fullpath += TEXT("\\");
fullpath += linarPathArray[0];
if (PathIsDirectory(fullpath.c_str()))
{
// search in folders, if found - no good
size_t nbFolder = _subFolders.size();
for (size_t i = 0; i < nbFolder; ++i)
{
if (linarPathArray[0] == _subFolders[i].getName())
return false; // Maybe already added?
}
_subFolders.push_back(FolderInfo(linarPathArray[0], this));
return true;
}
else
{
// search in files, if found - no good
size_t nbFile = _files.size();
for (size_t i = 0; i < nbFile; ++i)
{
if (linarPathArray[0] == _files[i].getName())
return false; // Maybe already added?
}
_files.push_back(FileInfo(linarPathArray[0], this));
return true;
}
}
else // folder
{
size_t nbFolder = _subFolders.size();
for (size_t i = 0; i < nbFolder; ++i)
{
if (_subFolders[i].getName() == linarPathArray[0])
{
fullpath += TEXT("\\");
fullpath += linarPathArray[0];
linarPathArray.erase(linarPathArray.begin());
return _subFolders[i].addToStructure(fullpath, linarPathArray);
}
}
return false;
}
}
bool FolderInfo::removeFromStructure(std::vector<generic_string> linarPathArray)
{
if (linarPathArray.size() == 1) // could be file or folder
{
for (size_t i = 0; i < _files.size(); ++i)
{
bool isFound = false;
for (size_t j = 0; not isFound && j < struct2compare._files.size(); ++j)
if (_files[i].getName() == linarPathArray[0])
{
if (_files[i]._path == struct2compare._files[j]._path)
isFound = true;
}
if (not isFound) // file is deleted
{
// put result in the vector
changeInfo info;
info._action = info.remove;
info._fullFilePath = _files[i]._path;
result.push_back(info);
// remove this file
_files.erase(_files.begin() + i);
return true;
}
}
/*
for (size_t i = 0; i < struct2compare._files.size(); ++i)
for (size_t i = 0; i < _subFolders.size(); ++i)
{
bool isFound = false;
for (size_t j = 0; not isFound && j < _files.size(); ++j)
if (_subFolders[i].getName() == linarPathArray[0])
{
if (_files[i]._path == struct2compare._files[j]._path)
isFound = true;
}
if (not isFound) // file is deleted
{
// put result in the vector
changeInfo info;
info._action = info.add;
info._fullFilePath = struct2compare._files[i]._path;
result.push_back(info);
// remove this folder
_subFolders.erase(_subFolders.begin() + i);
return true;
}
}
*/
return true;
}
else // folder
{
for (size_t i = 0; i < _subFolders.size(); ++i)
{
if (_subFolders[i].getName() == linarPathArray[0])
{
linarPathArray.erase(linarPathArray.begin());
return _subFolders[i].removeFromStructure(linarPathArray);
}
}
}
return false;
}
bool FolderInfo::makeDiff(FolderInfo & struct1, FolderInfo & struct2, std::vector<changeInfo> result)
bool FolderInfo::renameInStructure(std::vector<generic_string> linarPathArrayFrom, std::vector<generic_string> linarPathArrayTo)
{
if (struct1._contentHash == struct2._contentHash)
if (linarPathArrayFrom.size() == 1) // could be file or folder
{
if (struct1._path == struct2._path) // Everything is fine
for (size_t i = 0; i < _files.size(); ++i)
{
// remove both
return true;
if (_files[i].getName() == linarPathArrayFrom[0])
{
// rename this file
_files[i].setName(linarPathArrayTo[0]);
return true;
}
}
else // folder is renamed
for (size_t i = 0; i < _subFolders.size(); ++i)
{
// put result in the vector
changeInfo info;
info._action = info.rename;
info._fullFilePath = struct2._path;
result.push_back(info);
return false;
if (_subFolders[i].getName() == linarPathArrayFrom[0])
{
// rename this folder
_subFolders[i].setName(linarPathArrayTo[0]);
return true;
}
}
return false;
}
else // sub-folders or files/sub-files deleted or renamed
else // folder
{
if (struct1._path != struct2._path) // both content and path are different, stop to compare
for (size_t i = 0; i < _subFolders.size(); ++i)
{
return true; // everything could be fine
}
//check folder (maybe go deeper)
for (int i = struct1._subFolders.size(); i >= 0; --i)
{
bool isFound = false;
for (int j = struct2._subFolders.size(); not isFound && j >= 0; --j)
if (_subFolders[i].getName() == linarPathArrayFrom[0])
{
if ((struct1._subFolders[i]._path == struct2._subFolders[j]._path) &&
(struct1._subFolders[i]._contentHash == struct2._subFolders[j]._contentHash))
{
struct1._subFolders.erase(struct1._subFolders.begin() + i);
struct2._subFolders.erase(struct2._subFolders.begin() + j);
isFound = true;
}
else
{
if ((struct1._subFolders[i]._path != struct2._subFolders[j]._path) &&
(struct1._subFolders[i]._contentHash == struct2._subFolders[j]._contentHash)) // rename
{
changeInfo info;
info._action = info.rename;
info._fullFilePath = struct2._path;
result.push_back(info);
}
else if ((struct1._subFolders[i]._path == struct2._subFolders[j]._path) &&
(struct1._subFolders[i]._contentHash != struct2._subFolders[j]._contentHash)) // problem of sub-files or sub-folders. go deeper
{
makeDiff(struct1._subFolders[i], struct2._subFolders[j], result);
}
}
}
if (not isFound) // folder is deleted
{
// put result in the vector
changeInfo info;
info._action = info.remove;
info._fullFilePath = struct1._subFolders[i]._path;
result.push_back(info);
linarPathArrayFrom.erase(linarPathArrayFrom.begin());
linarPathArrayTo.erase(linarPathArrayTo.begin());
return _subFolders[i].renameInStructure(linarPathArrayFrom, linarPathArrayTo);
}
}
//check files
for (int i = struct1._files.size(); i >= 0; --i)
{
bool isFound = false;
for (int j = struct2._files.size(); not isFound && j >= 0; --j)
{
if (struct1._files[i]._path == struct2._files[j]._path)
{
struct1._subFolders.erase(struct1._subFolders.begin() + i);
struct2._subFolders.erase(struct2._subFolders.begin() + j);
isFound = true;
}
}
if (not isFound) // file is deleted
{
// put result in the vector
changeInfo info;
info._action = info.remove;
info._fullFilePath = struct1._files[i]._path;
result.push_back(info);
}
}
return true;
return false;
}
}
generic_string FolderInfo::getLabel()
{
return ::PathFindFileName(_path.c_str());
}
void FolderUpdater::startWatcher()
{
// no thread yet, create a event with non-signaled, to block all threads
@ -1144,45 +1181,113 @@ LPCWSTR explainAction(DWORD dwAction)
}
};
vector<generic_string> split(const generic_string & string2split, TCHAR sep)
{
vector<generic_string> splitedStrings;
size_t len = string2split.length();
size_t beginPos = 0;
for (size_t i = 0; i < len + 1; ++i)
{
if (string2split[i] == sep || string2split[i] == '\0')
{
splitedStrings.push_back(string2split.substr(beginPos, i - beginPos));
beginPos = i + 1;
}
}
return splitedStrings;
};
bool FolderUpdater::updateTree(DWORD action, const std::vector<generic_string> & file2Change)
{
//TCHAR msg2show[1024];
/*
TCHAR msg2show[1024];
switch (action)
{
case FILE_ACTION_ADDED:
//swprintf(msg2show, L"%s %s\n", explainAction(action), file2Change[0].c_str());
//printStr(msg2show);
//::PostMessage(thisFolderUpdater->_hFileBrowser, FB_ADDFILE, nullptr, (LPARAM)wstrFilename.GetString());
break;
case FILE_ACTION_ADDED:
swprintf(msg2show, L"%s %s\n", explainAction(action), file2Change[0].c_str());
printStr(msg2show);
//::PostMessage(thisFolderUpdater->_hFileBrowser, FB_ADDFILE, nullptr, (LPARAM)wstrFilename.GetString());
break;
case FILE_ACTION_REMOVED:
//swprintf(msg2show, L"%s %s\n", explainAction(action), file2Change[0].c_str());
//printStr(msg2show);
case FILE_ACTION_REMOVED:
swprintf(msg2show, L"%s %s\n", explainAction(action), file2Change[0].c_str());
printStr(msg2show);
break;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
//swprintf(msg2show, L"%s from %s \rto %s", explainAction(action), file2Change[0].c_str(), file2Change[1].c_str());
//printStr(msg2show);
case FILE_ACTION_RENAMED_NEW_NAME:
swprintf(msg2show, L"%s from %s \rto %s", explainAction(action), file2Change[0].c_str(), file2Change[1].c_str());
printStr(msg2show);
break;
break;
default:
break;
default:
break;
}
*/
generic_string separator = TEXT("\\\\");
size_t sepPos = file2Change[0].find(separator);
if (sepPos == generic_string::npos)
return false;
generic_string rootPrefix = file2Change[0].substr(0, sepPos);
generic_string pathSuffix = file2Change[0].substr(sepPos + separator.length(), file2Change[0].length() - 1);
// found: remove prefix of file/folder in changeInfo, splite the remained path
// remove prefix of file/folder in changeInfo, splite the remained path
vector<generic_string> linarPathArray = split(pathSuffix, '\\');
// search recursively according indication (file or folder)
if (action == FILE_ACTION_ADDED)
{
generic_string rootPath = file2Change[0].substr(0, sepPos);
generic_string path = rootPath;
// search recursively and modify the tree structure
bool foundAndModified = _rootFolder.addToStructure(path, linarPathArray);
if (foundAndModified)
{
generic_string addedFilePath = file2Change[0].substr(0, sepPos + 1);
addedFilePath += pathSuffix;
bool isAdded = _pFileBrowser->addInTree(rootPath, addedFilePath, nullptr, linarPathArray);
if (not isAdded)
MessageBox(NULL, addedFilePath.c_str(), TEXT("file/folder is not added"), MB_OK);
}
else
printStr(TEXT("addToStructure pb"));
}
else if (action == FILE_ACTION_REMOVED)
{
generic_string rootPath = file2Change[0].substr(0, sepPos);
// search recursively and modify the tree structure
bool foundAndModified = _rootFolder.removeFromStructure(linarPathArray);
if (foundAndModified)
{
bool isRemoved = _pFileBrowser->deleteFromTree(rootPath, nullptr, linarPathArray);
if (not isRemoved)
MessageBox(NULL, file2Change[0].c_str(), TEXT("file/folder is not removed"), MB_OK);
}
else
printStr(TEXT("removeFromStructure pb"));
}
else if (action == FILE_ACTION_RENAMED_NEW_NAME)
{
generic_string rootPath = file2Change[0].substr(0, sepPos);
size_t sepPos2 = file2Change[1].find(separator);
if (sepPos2 == generic_string::npos)
return false;
generic_string pathSuffix2 = file2Change[1].substr(sepPos2 + separator.length(), file2Change[1].length() - 1);
vector<generic_string> linarPathArray2 = split(pathSuffix2, '\\');
bool foundAndModified = _rootFolder.renameInStructure(linarPathArray, linarPathArray2);
if (foundAndModified)
{
bool isRenamed = _pFileBrowser->renameInTree(rootPath, nullptr, linarPathArray, linarPathArray2);
if (not isRenamed)
MessageBox(NULL, file2Change[0].c_str(), TEXT("file/folder is not removed"), MB_OK);
}
else
printStr(TEXT("removeFromStructure pb"));
}
return true;
}
@ -1191,7 +1296,7 @@ bool FolderUpdater::updateTree(DWORD action, const std::vector<generic_string> &
DWORD WINAPI FolderUpdater::watching(void *params)
{
FolderUpdater *thisFolderUpdater = (FolderUpdater *)params;
const TCHAR *dir2Watch = (thisFolderUpdater->_rootFolder)._path.c_str();
const TCHAR *dir2Watch = (thisFolderUpdater->_rootFolder)._rootPath.c_str();
const DWORD dwNotificationFlags = FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME;

View File

@ -60,52 +60,48 @@
class TiXmlNode;
class changeInfo final
{
friend class FolderInfo;
public:
enum folderChangeAction{
add, remove, rename
};
private:
bool isFile; // true: file, false: folder
generic_string _fullFilePath;
std::vector<generic_string> _relativePath;
folderChangeAction _action;
};
class FileInfo final
{
friend class FileBrowser;
friend class FolderInfo;
public:
FileInfo(const generic_string & fn) { _path = fn; };
generic_string getLabel() { return ::PathFindFileName(_path.c_str()); };
FileInfo(const generic_string & name, FolderInfo *parent) : _name(name), _parent(parent) {};
generic_string getName() const { return _name; };
void setName(generic_string name) { _name = name; };
private:
generic_string _path;
FileInfo(){}; // constructor by default is forbidden
FolderInfo *_parent = nullptr;
generic_string _name;
};
class FolderInfo final
{
friend class FileBrowser;
friend class FolderUpdater;
public:
void setPath(generic_string dn) { _path = dn; };
void addFile(generic_string fn) { _files.push_back(FileInfo(fn)); };
FolderInfo(const generic_string & name, FolderInfo *parent) : _name(name), _parent(parent) {};
void setRootPath(generic_string rootPath) { _rootPath = rootPath; };
generic_string getRootPath() const { return _rootPath; };
void setName(generic_string name) { _name = name; };
generic_string getName() const { return _name; };
void addFile(generic_string fn) { _files.push_back(FileInfo(fn, this)); };
void addSubFolder(FolderInfo subDirectoryStructure) { _subFolders.push_back(subDirectoryStructure); };
bool compare(const FolderInfo & struct2compare, std::vector<changeInfo> & result);
static bool makeDiff(FolderInfo & struct1, FolderInfo & struct2static, std::vector<changeInfo> result);
generic_string getLabel();
bool addToStructure(generic_string & fullpath, std::vector<generic_string> linarPathArray);
bool removeFromStructure(std::vector<generic_string> linarPathArray);
bool renameInStructure(std::vector<generic_string> linarPathArrayFrom, std::vector<generic_string> linarPathArrayTo);
private:
FolderInfo(){}; // constructor by default is forbidden
std::vector<FolderInfo> _subFolders;
std::vector<FileInfo> _files;
generic_string _path;
generic_string _contentHash;
FolderInfo *_parent = nullptr;
generic_string _name;
generic_string _rootPath; // set only for root folder; empty for normal folder
};
enum BrowserNodeType {
@ -115,17 +111,16 @@ enum BrowserNodeType {
class FolderUpdater {
friend class FileBrowser;
public:
FolderUpdater(FolderInfo fi, HWND hFileBrowser) : _rootFolder(fi), _hFileBrowser(hFileBrowser) {};
FolderUpdater(FolderInfo fi, FileBrowser *pFileBrowser) : _rootFolder(fi), _pFileBrowser(pFileBrowser) {};
~FolderUpdater() {};
bool updateTree(DWORD action, const std::vector<generic_string> & file2Change); // postMessage to FileBrowser to upgrade GUI
void startWatcher();
void stopWatcher();
private:
FolderInfo _rootFolder;
HWND _hFileBrowser = nullptr;
FileBrowser *_pFileBrowser = nullptr;
HANDLE _watchThreadHandle = nullptr;
HANDLE _EventHandle = nullptr;
@ -157,6 +152,13 @@ public:
void addRootFolder(generic_string);
HTREEITEM getRootFromFullPath(generic_string rootPath);
HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, generic_string);
bool addInTree(generic_string rootPath, generic_string addItemFullPath, HTREEITEM node, std::vector<generic_string> linarPathArray);
bool deleteFromTree(generic_string rootPath, HTREEITEM node, std::vector<generic_string> linarPathArray);
bool renameInTree(generic_string rootPath, HTREEITEM node, std::vector<generic_string> linarPathArrayFrom, std::vector<generic_string> linarPathArrayTo);
protected:
TreeView _treeView;
HIMAGELIST _hImaLst;
@ -170,9 +172,8 @@ protected:
void initMenus();
void destroyMenus();
BOOL setImageList(int root_clean_id, int root_dirty_id, int project_id, int open_node_id, int closed_node_id, int leaf_id, int ivalid_leaf_id);
void addFiles(HTREEITEM hTreeItem);
void recursiveAddFilesFrom(const TCHAR *folderPath, HTREEITEM hTreeItem);
HTREEITEM addFolder(HTREEITEM hTreeItem, const TCHAR *folderName);
HTREEITEM createNewFolder(HTREEITEM hTreeItem, const TCHAR *folderName);
generic_string getRelativePath(const generic_string & fn, const TCHAR *workSpaceFileName);
void buildProjectXml(TiXmlNode *root, HTREEITEM hItem, const TCHAR* fn2write);

View File

@ -91,6 +91,20 @@ bool TreeView::setItemParam(HTREEITEM Item2Set, const TCHAR *paramStr)
return true;
}
bool TreeView::renameItem(HTREEITEM Item2Set, const TCHAR *newName)
{
if (not Item2Set || not newName)
return false;
TVITEM tvItem;
tvItem.hItem = Item2Set;
tvItem.mask = TVIF_TEXT;
tvItem.pszText = (LPWSTR)newName;
tvItem.cchTextMax = MAX_PATH;
SendMessage(_hSelf, TVM_SETITEM, 0, (LPARAM)&tvItem);
return true;
}
HTREEITEM TreeView::addItem(const TCHAR *itemName, HTREEITEM hParentItem, int iImage, const TCHAR *filePath)
{
TVITEM tvi;

View File

@ -54,6 +54,7 @@ public:
HTREEITEM searchSubItemByName(const TCHAR *itemName, HTREEITEM hParentItem);
void removeItem(HTREEITEM hTreeItem);
void removeAllItems();
bool renameItem(HTREEITEM Item2Set, const TCHAR *newName);
HTREEITEM getChildFrom(HTREEITEM hTreeItem) const {
return TreeView_GetChild(_hSelf, hTreeItem);