/* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 1, or (at your option) ** any later version. ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Author : Alexandre Parenteau --- February 2000 */ /* * */ #include "stdafx.h" #if qGTK # include #endif #ifdef HAVE_UNISTD_H #include #endif #include "UCvsFolders.h" #include "UCvsDialogs.h" #include "UCvsApp.h" #include "UCvsFiles.h" #include "UCvsCommands.h" #include "UCvsFrame.h" #include "MultiString.h" #include "FileTraversal.h" #include "CvsEntries.h" #include "CvsPrefs.h" #include "AppConsole.h" #include "CvsCommands.h" #include "TclGlue.h" #include "MacrosSetup.h" #include "CvsArgs.h" #ifdef WIN32 static PCPStr gOldLoc("P_BrowserLoc", "C:\\"); #endif #ifdef qUnix static PCPStr gOldLoc("P_BrowserLoc"); #endif static const char *gDummyFile = "@@@dummy file@@@"; static CMString gHistoryLocs(100, "P_BrowserLocs"); static void *sFolderIcon; static void *sFolderUnknownIcon; static void *sFolderIgnoredIcon; static void *sFolderMissingIcon; enum { kIconFolderClosed, kIconFolderOpened, kIconFolderCVSClosed, kIconFolderCVSOpened, kIconFolderIgnoreClosed, kIconFolderIgnoreOpened, kIconFolderIgnoreLost }; UIMPLEMENT_DYNAMIC(UCvsFolders, UWidget) UBEGIN_MESSAGE_MAP(UCvsFolders, UWidget) ON_UUPDATECMD(cmdUPDATE, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdCOMMIT, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdDIFF, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdEDIT, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdEDITORS, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdLOCKF, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdLOG, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdRELEASE, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdSTATUS, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdUNEDIT, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdUPDATE, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdQUERYUPDATE, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdUNLOCKF, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdWATCHERS, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdWATCHON, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdWATCHOFF, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdTAGNEW, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdTAGDELETE, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdTAGBRANCH, UCvsFolders::OnCmdUIUpdate) ON_UUPDATECMD(cmdADD, UCvsFolders::OnCmdUIAdd) ON_UUPDATECMD(cmdEXPLORE, UCvsFolders::OnCmdUIExplore) ON_UUPDATECMD(cmdRELOAD, UCvsFolders::OnCmdUIReload) ON_UUPDATECMD(cmdIGNORE, UCvsFolders::OnCmdUIIgnore) ON_UUPDATECMD(cmdCHECKOUT, UCvsFolders::OnCmdUICheckout) ON_UUPDATECMD(cmdIMPORT, UCvsFolders::OnCmdUIImport) ON_UUPDATECMD_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFolders::OnCmdUIMacrosSel) ON_UDESTROY(UCvsFolders) ON_UCREATE(UCvsFolders) ON_TREE_EXPANDING(kUMainWidget, UCvsFolders::OnTreeExpanding) ON_TREE_SELECTING(kUMainWidget, UCvsFolders::OnTreeSelecting) ON_UCOMMAND(cmdUPDATE, UCvsFolders::OnCmdUpdate) ON_UCOMMAND(cmdADD, UCvsFolders::OnCmdAdd) ON_UCOMMAND(cmdCOMMIT, UCvsFolders::OnCmdCommit) ON_UCOMMAND(cmdQUERYUPDATE, UCvsFolders::OnCmdQueryUpdate) ON_UCOMMAND(cmdDIFF, UCvsFolders::OnCmdDiff) ON_UCOMMAND(cmdLOG, UCvsFolders::OnCmdLog) ON_UCOMMAND(cmdSTATUS, UCvsFolders::OnCmdStatus) ON_UCOMMAND(cmdLOCKF, UCvsFolders::OnCmdLock) ON_UCOMMAND(cmdUNLOCKF, UCvsFolders::OnCmdUnlock) ON_UCOMMAND(cmdWATCHON, UCvsFolders::OnCmdWatchOn) ON_UCOMMAND(cmdWATCHOFF, UCvsFolders::OnCmdWatchOff) ON_UCOMMAND(cmdEDIT, UCvsFolders::OnCmdEdit) ON_UCOMMAND(cmdUNEDIT, UCvsFolders::OnCmdUnedit) ON_UCOMMAND(cmdWATCHERS, UCvsFolders::OnCmdWatchers) ON_UCOMMAND(cmdEDITORS, UCvsFolders::OnCmdEditors) ON_UCOMMAND(cmdRELEASE, UCvsFolders::OnCmdRelease) ON_UCOMMAND(cmdTAGNEW, UCvsFolders::OnCmdTagNew) ON_UCOMMAND(cmdTAGDELETE, UCvsFolders::OnCmdTagDelete) ON_UCOMMAND(cmdTAGBRANCH, UCvsFolders::OnCmdTagBranch) ON_UCOMMAND(cmdEXPLORE, UCvsFolders::OnCmdExplore) ON_UCOMMAND(cmdRELOAD, UCvsFolders::OnCmdReload) ON_UCOMMAND(cmdIGNORE, UCvsFolders::OnCmdIgnore) ON_UCOMMAND(cmdCHECKOUT, UCvsFolders::OnCmdCheckout) ON_UCOMMAND(cmdIMPORT, UCvsFolders::OnCmdImport) ON_UCOMMAND_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFolders::OnCmdMacrosSel) UEND_MESSAGE_MAP() #if 0 ON_WM_RBUTTONDOWN() // TODO #endif static bool sTemporaryTurnOffNotify = false; class CTempToggleBool { public: CTempToggleBool(bool & value) : m_value(value), m_didSetIt(false) { if(!m_value) { m_didSetIt = true; m_value = true; } } ~CTempToggleBool() { if(m_didSetIt) m_value = false; } protected: bool & m_value; bool m_didSetIt; }; static void *GetIcon(UCvsFolders *treeCrtl, UTREEITEM item, bool hasCvsInfos, bool expand, EntnodeData *data) { int newImage; void *result = 0L; if(data == 0L) { if(expand) newImage = hasCvsInfos ? kIconFolderCVSOpened : kIconFolderOpened; else newImage = hasCvsInfos ? kIconFolderCVSClosed : kIconFolderClosed; } else { if(expand) { if(data->IsIgnored()) newImage = kIconFolderIgnoreOpened; else if(data->IsUnknown()) newImage = kIconFolderOpened; else if(data->IsMissing()) newImage = kIconFolderIgnoreLost; else newImage = kIconFolderCVSOpened; } else { if(data->IsIgnored()) newImage = kIconFolderIgnoreClosed; else if(data->IsUnknown()) newImage = kIconFolderClosed; else if(data->IsMissing()) newImage = kIconFolderIgnoreLost; else newImage = kIconFolderCVSClosed; } } #if qGTK void *pixmap = 0L; switch(newImage) { case kIconFolderClosed: case kIconFolderOpened: pixmap = sFolderUnknownIcon; break; case kIconFolderCVSClosed: case kIconFolderCVSOpened: pixmap = sFolderIcon; break; case kIconFolderIgnoreClosed: case kIconFolderIgnoreOpened: pixmap = sFolderIgnoredIcon; break; case kIconFolderIgnoreLost: pixmap = sFolderMissingIcon; break; } if(pixmap != 0L) { result = gtk_pixmap_new (GTK_PIXMAP(pixmap)->pixmap, GTK_PIXMAP(pixmap)->mask); } #endif return result; } // regarding a path and a root item, create an // item with a dummy item inside if and only if // the folder is not empty. class TBrowserFillDummy : public TraversalReport { public: UTREEITEM m_root; UTREEITEM m_item; UCvsFolders *m_treeCtrl; bool m_empty; bool m_hascvs; EntnodeData *m_data; UStr m_dirname; TBrowserFillDummy(UCvsFolders *treeCtrl, UTREEITEM root, UTREEITEM item, EntnodeData *data) : m_root(root), m_item(item), m_treeCtrl(treeCtrl), m_empty(true), m_hascvs(false), m_data(data) {} virtual ~TBrowserFillDummy() {} virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const FSSpec * macspec) { m_dirname = dirname; #if qUnix if(m_dirname.empty()) m_dirname = fullpath; // '/' #endif return kContinueTraversal; } virtual kTraversal ExitDirectory(const char *fullpath) { if(m_item == 0L) { UTREE_INSERT insert; insert.parent = m_root; insert.icon = GetIcon(m_treeCtrl, m_item, m_hascvs, false, m_data); insert.title = m_dirname; insert.data = 0L; UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert); m_item = insert.result; } // assign the entries to this item UTREE_INFO query; query.item = m_item; if(m_data != 0L) { UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); EntnodeData *data = (EntnodeData *)query.data; if(m_data != 0L) m_data->Ref(); query.data = m_data; UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETDATA, kUMainWidget, &query); if(data != 0L) data->UnRef(); } else { UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); m_data = (EntnodeData *)query.data; } if(m_empty) return kContinueTraversal; // add a dummy item to simulate the folder // is not empty. This dummy item will be // replaced by a complete listing when the // node is expanding... UTREE_INSERT insert; insert.parent = m_item; insert.icon = 0L; insert.title = gDummyFile; insert.data = 0L; UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert); return kContinueTraversal; } virtual kTraversal OnError(const char *err, int errcode) { cvs_err(err); cvs_err("\n"); cvs_err(strerror(errcode)); cvs_err("\n"); return kTraversalError; } virtual kTraversal OnIdle(const char *fullpath) { return kContinueTraversal; } virtual kTraversal OnDirectory(const char *fullpath, const char *fullname, const char *name, const struct stat & dir, const FSSpec * macspec) { #if qUnix if(strcmp(name, "CVS") == 0) #else if(stricmp(name, "cvs") == 0) #endif m_hascvs = true; else m_empty = false; return kSkipFile; } }; // regarding a path and a root item, create an // item with all the subdirectories inside. class TBrowserFill : public TraversalReport { public: UTREEITEM m_root; UTREEITEM m_item; UCvsFolders *m_treeCtrl; CSortList & m_entries; std::vector m_ignlist; TBrowserFill(UCvsFolders *treeCtrl, UTREEITEM root, UTREEITEM item, CSortList & entries) : m_root(root), m_item(item), m_treeCtrl(treeCtrl), m_entries(entries) {} virtual ~TBrowserFill() {} virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const FSSpec * macspec) { ASSERT(m_item != 0L); // assign the entries to this item Entries_Open (m_entries, fullpath); BuildIgnoredList(m_ignlist, fullpath); return kContinueTraversal; } virtual kTraversal ExitDirectory(const char *fullpath) { m_ignlist.erase(m_ignlist.begin(), m_ignlist.end()); UTREE_INFO query; query.item = m_item; UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); query.icon = GetIcon(m_treeCtrl, m_item, true /*ignored*/, true, (EntnodeData *)query.data); UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETICON, kUMainWidget, &query); return kContinueTraversal; } virtual kTraversal OnError(const char *err, int errcode) { return kTraversalError; } virtual kTraversal OnIdle(const char *fullpath) { return kContinueTraversal; } virtual kTraversal OnDirectory(const char *fullpath, const char *fullname, const char *name, const struct stat & dir, const FSSpec * macspec) { #if qUnix if(strcmp(name, "CVS") == 0) #else if(stricmp(name, "cvs") == 0) #endif return kSkipFile; // is the sub-directory ignored ? EntnodeData *data = Entries_SetVisited(fullpath, m_entries, name, dir, true, &m_ignlist); if(!(bool)gFileViewIgnore && data->IsIgnored()) return kSkipFile; // create the item for the sub-directory TBrowserFillDummy traverse(m_treeCtrl, m_item, 0L, data); /*kTraversal res = */FileTraverse(fullname, traverse); // assign the icon regarding our Entries info if(traverse.m_item != 0L) { UTREE_INFO query; query.item = traverse.m_item; query.icon = GetIcon(m_treeCtrl, m_item, true /*ignored*/, false, data); UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETICON, kUMainWidget, &query); } return kSkipFile; } }; UCvsFolders::UCvsFolders() : UWidget(kUCvsFoldersID) { } UCvsFolders::~UCvsFolders() { } void UCvsFolders::OnDestroy(void) { delete this; } void UCvsFolders::OnCreate(void) { if(sFolderIcon == 0L) { sFolderIcon = UCreate_pixmap(this, "folder.xpm"); sFolderUnknownIcon = UCreate_pixmap(this, "foldunk.xpm"); sFolderIgnoredIcon = UCreate_pixmap(this, "foldign.xpm"); sFolderMissingIcon = UCreate_pixmap(this, "foldmiss.xpm"); } UStr newpath; newpath = (const char *)gOldLoc; if(newpath.empty()) newpath = gCvsPrefs.Home(); // set the initial root ResetBrowser(newpath, true); } void UCvsFolders::ResetBrowser(const char *path, bool notifyView) { UWaitCursor wait; DeleteAllItems(); bool isReload = path != 0L && !m_root.empty() && stricmp(m_root, path) == 0; m_root = path; if(path == 0L) return; if(!isReload) { if(HasPersistentSettings(m_root)) LoadPersistentSettings(m_root); else { // check if the path has a CVS folder. If not, // we don't want the user to be prompted (like when // WinCvs is starting for the first time). UStr cvsFolder(m_root); if(!cvsFolder.endsWith(kPathDelimiter)) cvsFolder << kPathDelimiter; cvsFolder << "CVS"; struct stat sb; if (stat(cvsFolder, &sb) != -1 && S_ISDIR(sb.st_mode)) AskCreatePersistentSettings(m_root); } } if(stricmp(gOldLoc, m_root) != 0) gOldLoc = m_root; // update the history combo gHistoryLocs.Insert(m_root); UEventSendMessage(kUCvsFrameID, EV_COMBO_RESETALL, UCvsFrame::kDirCombo, 0L); const std::vector & list = gHistoryLocs.GetList(); std::vector::const_iterator i; int pos = 0; for(i = list.begin(); i != list.end(); ++i, pos++) { UEventSendMessage(kUCvsFrameID, EV_COMBO_APPEND, UCvsFrame::kDirCombo, (void *)(const char *)*i); } UEventSendMessage(kUCvsFrameID, EV_COMBO_SETSEL, UMAKEINT(UCvsFrame::kDirCombo, 0), 0L); // fill the browser TBrowserFillDummy traverse(this, 0L, 0L, 0L); /*kTraversal res = */FileTraverse(m_root, traverse); if(traverse.m_item != 0L) { UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), traverse.m_item); if(notifyView && UCvsApp::gApp->GetFilesView()) UCvsApp::gApp->GetFilesView()->ResetView(path); } } void UCvsFolders::ResetView(bool forceReload, bool notifyView) { UWaitCursor doWait; std::vector allExpanded; StoreExpanded(allExpanded); bool contentChanged = false; UStr selPath; UTREEITEM selItem; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem); if(selItem != 0L) RetrievePath(selItem, selPath); if(forceReload) { ResetBrowser(m_root); contentChanged = true; } if(contentChanged) { // restore the expanded paths and the selected item std::vector::const_iterator i; for(i = allExpanded.begin(); i != allExpanded.end(); ++i) { StepToLocation(*i); } if(!selPath.empty()) { selItem = GetItemByLocation(selPath); if(selItem != 0L) UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), selItem); } } // we don't need to notify the file view if we force the reload // because that's already done if(notifyView) { UCvsApp::gApp->GetFilesView()->ResetView(forceReload); } UEventSendMessage(GetWidID(), EV_CHGFOCUS, kUMainWidget, 0L); } void UCvsFolders::StoreExpanded(std::vector & allExpanded, UTREEITEM root) { UTREE_INFO query; query.item = root; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); UTREEITEM item = query.item; if(item == 0L) return; if(query.expanded) { UStr path; RetrievePath(item, path); allExpanded.push_back(path); } UTREEITEM childItem = query.child; while(childItem != 0L) { StoreExpanded(allExpanded, childItem); query.item = childItem; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); childItem = query.next; } } void UCvsFolders::StepToLocation(const char *path, bool notifyView) { UStr root(m_root); if(!root.endsWith(kPathDelimiter)) root << kPathDelimiter; UStr subpath(path); if(!subpath.endsWith(kPathDelimiter)) subpath << kPathDelimiter; // check if it is a sub-path if(strncmp(root, subpath, root.length()) != 0) return; UTREE_INFO query; query.item = 0L; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); UTREEITEM item = query.item; UTREEITEM lastitem = 0L; if(item == 0L) return; // step inside synchronized const char *tmp = (const char *)subpath + root.length() - 1; while((tmp = strchr(tmp, kPathDelimiter)) != 0L) { const char *name = ++tmp; if(name[0] == '\0') break; UStr subname; const char *tmp2 = strchr(name, kPathDelimiter); if(tmp2 == 0L) subname = name; else subname.set(name, tmp2 - name); query.item = item; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); UTREEITEM childItem = query.child; // find the subitem which matches this name while(childItem != 0L) { query.item = childItem; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); EntnodeData *data = (EntnodeData *)query.data; if(data != 0L) { #ifdef qUnix if(strcmp((*data)[EntnodeData::kName], subname) == 0) #else if(_stricmp((*data)[EntnodeData::kName], subname) == 0) #endif { // found it ! lastitem = item = childItem; UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), item); break; } } childItem = query.next; } } // in case this is called by the view, turn off notifying // when the item gets selected if(lastitem != 0L) { if(!notifyView) { CTempToggleBool toggler(sTemporaryTurnOffNotify); UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), lastitem); } else { UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), lastitem); } } } UTREEITEM UCvsFolders::GetItemByLocation(const char *path) { UStr root(m_root); if(!root.endsWith(kPathDelimiter)) root << kPathDelimiter; UStr subpath(path); if(!subpath.endsWith(kPathDelimiter)) subpath << kPathDelimiter; // check if it is a sub-path if(strncmp(root, subpath, root.length()) != 0) return 0L; UTREE_INFO query; query.item = 0L; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); UTREEITEM item = query.item; if(item == 0L) return 0L; // step inside synchronized const char *tmp = (const char *)subpath + root.length() - 1; while((tmp = strchr(tmp, kPathDelimiter)) != 0L) { const char *name = ++tmp; if(name[0] == '\0') break; CStr subname; const char *tmp2 = strchr(name, kPathDelimiter); if(tmp2 == 0L) subname = name; else subname.set(name, tmp2 - name); UTREEITEM childItem = query.child; // find the subitem which matches this name while(childItem != 0L) { query.item = childItem; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); EntnodeData *data = (EntnodeData *)query.data; if(data != 0L) { #if qUnix if(strcmp((*data)[EntnodeData::kName], subname) == 0) #else if(_stricmp((*data)[EntnodeData::kName], subname) == 0) #endif { item = childItem; break; } } childItem = query.next; } if(childItem == 0L) return 0L; } return item; } void UCvsFolders::OnTreeExpanding(int collapse, UTREEITEM item) { // many situations make that we enter here twice. Fortunately enough // we only dare the first signal. static bool sSemaphore = false; USemaphore policeman(sSemaphore); if(policeman.IsEnteredTwice()) return; UWaitCursor wait; UTREE_INFO query; query.item = item; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); EntnodeData *data = (EntnodeData *)query.data; // we refuse to expand in this case cause the folder is not really here if(data != 0L && data->IsMissing()) { UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 1), item); return; } // erase all the childs DeleteAllItems(item); UStr path; RetrievePath(item, path); if(collapse) { TBrowserFillDummy traverse(this, 0L, item, 0L); /*kTraversal res = */FileTraverse(path, traverse); } else { CSortList entries(200, ENTNODE::Compare); TBrowserFill traverse(this, 0L, item, entries); /*kTraversal res = */FileTraverse(path, traverse); #if qGTK // gtk is closing the tree when we removed everything in it UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), item); #endif // add the missing folders Entries_SetMissing(entries); int numEntries = entries.NumOfElements(); for(int i = 0; i < numEntries; i++) { const ENTNODE & theNode = entries.Get(i); EntnodeData *data = ((ENTNODE *)&theNode)->Data(); if(!data->IsMissing() || data->GetType() != ENT_SUBDIR) continue; UTREE_INSERT insert; insert.parent = item; insert.icon = GetIcon(this, item, false, false, data->Ref()); insert.title = (*data)[EntnodeData::kName]; insert.data = data; UEventSendMessage(GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert); } } } void UCvsFolders::OnTreeSelecting(int deselect, UTREEITEM item) { if(deselect) return; UTREE_INFO query; query.item = item; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); EntnodeData *data = (EntnodeData *)query.data; if(data != 0L && data->IsMissing()) return; if(!sTemporaryTurnOffNotify) { UStr path; RetrievePath(item, path); UCvsFiles *fileView = (UCvsFiles *)UEventQueryWidget(kUCvsFilesID); if(fileView != 0L) { ASSERT(fileView->IsKindOf(URUNTIME_CLASS(UCvsFiles))); fileView->ResetView( (const char *)path); } } } void UCvsFolders::SetDefaultRoot(const char *root) { struct stat sb; if (stat(root, &sb) == -1 || !S_ISDIR(sb.st_mode)) { cvs_err("Cannot access directory '%s' (error %d)\n", root, errno); return; } gOldLoc = root; } void UCvsFolders::RetrievePath(UTREEITEM item, UStr & path) { UStr tmp, newPath; path = ""; do { UTREE_INFO query; query.item = item; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); item = query.parent; tmp = path; newPath = item == 0L ? (const char *)m_root : query.title; if(!newPath.endsWith(kPathDelimiter)) newPath << kPathDelimiter; newPath << path; path = newPath; } while(item != 0L); } void UCvsFolders::DeleteAllItems(void) { DeleteAllItems(NULL); } void UCvsFolders::DeleteAllItems(UTREEITEM root) { // we don't want the file view to be notified when things get deleted CTempToggleBool toggler(sTemporaryTurnOffNotify); UTREE_INFO query; bool eraseRoot = false; query.item = root; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); if(root == 0L) { root = query.item; eraseRoot = true; } if(root == 0L) return; UTREEITEM childItem = query.child; // erase all the childs while(childItem != 0L) { UTREE_INFO queryChild; queryChild.item = childItem; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &queryChild); EntnodeData *data = (EntnodeData *)queryChild.data; if(data != 0L) { queryChild.data = 0L; // So that subsequent references after UnRef() won't SEGV UEventSendMessage(GetWidID(), EV_TREE_SETDATA, kUMainWidget, &queryChild); data->UnRef(); // Or move this one after DeleteAllItems? so we don't loose one system call. For now, safe way } DeleteAllItems(childItem); UEventSendMessage(GetWidID(), EV_TREE_DELETE, kUMainWidget, childItem); childItem = queryChild.next; } // erase the root only if initially root was 0L if(eraseRoot) { EntnodeData *data = (EntnodeData *)query.data; ASSERT(data == 0L); UEventSendMessage(GetWidID(), EV_TREE_DELETE, kUMainWidget, root); } } bool UCvsFolders::DisableGeneric() { UCvsApp *app = UCvsApp::gApp; return app->IsCvsRunning() || gCvsPrefs.empty() || !HasFocus(); } void UCvsFolders::OnUpdateGeneric(UCmdUI* pCmdUI, bool needCvsInfos) { if(DisableGeneric()) { pCmdUI->Enable(false); return; } UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); if(item == 0L) { pCmdUI->Enable(false); return; } UStr path; RetrievePath(item, path); if(!path.endsWith(kPathDelimiter)) path << kPathDelimiter; path << "CVS"; struct stat sb; if (stat(path, &sb) == -1 || !S_ISDIR(sb.st_mode)) pCmdUI->Enable(!needCvsInfos); else pCmdUI->Enable(needCvsInfos); } int UCvsFolders::OnCmdUpdate(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdUpdateFolder(path); return 0; } void UCvsFolders::OnCmdUIUpdate(UCmdUI *pCmdUI) { OnUpdateGeneric(pCmdUI, true); } int UCvsFolders::OnCmdAdd(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdAddFolder(path); return 0; } int UCvsFolders::OnCmdCommit(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdCommitFolder(path); return 0; } int UCvsFolders::OnCmdQueryUpdate(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdUpdateFolder(path, true); return 0; } int UCvsFolders::OnCmdDiff(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdDiffFolder(path); return 0; } int UCvsFolders::OnCmdLog(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdLogFolder(path); return 0; } int UCvsFolders::OnCmdStatus(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdStatusFolder(path); return 0; } int UCvsFolders::OnCmdLock(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdLockFolder(path); return 0; } int UCvsFolders::OnCmdUnlock(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdUnlockFolder(path); return 0; } int UCvsFolders::OnCmdWatchOn(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdWatchOnFolder(path); return 0; } int UCvsFolders::OnCmdWatchOff(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdWatchOffFolder(path); return 0; } int UCvsFolders::OnCmdEdit(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdEditFolder(path); return 0; } int UCvsFolders::OnCmdUnedit(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdUneditFolder(path); return 0; } int UCvsFolders::OnCmdWatchers(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdWatchersFolder(path); return 0; } int UCvsFolders::OnCmdEditors(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdEditorsFolder(path); return 0; } int UCvsFolders::OnCmdRelease(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdReleaseFolder(path); return 0; } int UCvsFolders::OnCmdTagNew(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdTagCreateFolder(path); return 0; } int UCvsFolders::OnCmdTagDelete(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdTagDeleteFolder(path); return 0; } int UCvsFolders::OnCmdTagBranch(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); CvsCmdTagBranchFolder(path); return 0; } int UCvsFolders::OnCmdExplore(void) { UTREEITEM *item; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item); ASSERT(item != 0L); UStr path; RetrievePath(item, path); #ifdef WIN32 HINSTANCE hInst = ShellExecute(*AfxGetMainWnd(), "explore", path, 0L, 0L, SW_SHOWDEFAULT); if((long)hInst < 32) { cvs_err("Unable to explore '%s' (error %d)\n", (const char *)path, GetLastError()); } #endif #ifdef qUnix CvsArgs args(false); args.add(gCvsPrefs.Browser()); args.add(path); UCvsApp::gApp->Execute(args.Argc(), args.Argv()); #endif return 0; } int UCvsFolders::OnCmdReload(void) { ResetView(true); return 0; } int UCvsFolders::OnCmdIgnore(void) { gFileViewIgnore = !(bool)gFileViewIgnore; ResetView(true, true); return 0; } int UCvsFolders::OnCmdCheckout(void) { CvsCmdCheckoutModule(); return 0; } int UCvsFolders::OnCmdImport(void) { CvsCmdImportModule(); return 0; } void UCvsFolders::OnCmdUIAdd(UCmdUI *pCmdUI) { OnUpdateGeneric(pCmdUI, false); } void UCvsFolders::OnCmdUIExplore(UCmdUI *pCmdUI) { if(DisableGeneric()) { pCmdUI->Enable(false); return; } UTREEITEM selItem; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem); pCmdUI->Enable(selItem != 0L); } void UCvsFolders::OnCmdUIReload(UCmdUI *pCmdUI) { UCvsApp *app = UCvsApp::gApp; pCmdUI->Enable(!app->IsCvsRunning()); } void UCvsFolders::OnCmdUIIgnore(UCmdUI *pCmdUI) { pCmdUI->Enable(!DisableGeneric()); pCmdUI->Check(gFileViewIgnore); } void UCvsFolders::OnCmdUICheckout(UCmdUI *pCmdUI) { UCvsApp *app = UCvsApp::gApp; pCmdUI->Enable(!app->IsCvsRunning() && !gCvsPrefs.empty()); } void UCvsFolders::OnCmdUIImport(UCmdUI *pCmdUI) { UCvsApp *app = UCvsApp::gApp; pCmdUI->Enable(!app->IsCvsRunning() && !gCvsPrefs.empty()); } void UCvsFolders::OnCmdUIMacrosSel(int cmd, UCmdUI *pCmdUI) { if(DisableGeneric()) { pCmdUI->Enable(false); return; } UTREEITEM selItem; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem); pCmdUI->Enable(selItem != 0L && CTcl_Interp::IsAvail()); } int UCvsFolders::OnCmdMacrosSel(int cmd) { CTcl_Interp interp; CMacroEntry & entry = gMacrosSel.entries[cmd - cmdSELMACRO]; CStr path = entry.path; CTcl_Interp::Unixfy(path); UTREEITEM selItem; UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem); CStr selPath; RetrievePath(selItem, selPath); CStr uppath, folder; SplitPath(selPath, uppath, folder); UTREE_INFO query; query.item = selItem; UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query); bool deleteData = false; EntnodeData *data = (EntnodeData *)query.data; if(data == 0L) { deleteData = true; EntnodePath *apath = new EntnodePath(uppath); data = new EntnodeFolder(folder, apath); apath->UnRef(); } TclBrowserReset(); TclBrowserAppend(uppath, data); interp.DoScriptVar("source \"%s\"", (const char *)path); if(deleteData) data->UnRef(); return 0; }