/// <summary> /// Refreshes the glyphs of the specified hierarchy nodes /// </summary> public void RefreshNodesGlyphs(IList <VSITEMSELECTION> selectedNodes, IList <string> files) { RefreshNodesGlyphsArgs args = new RefreshNodesGlyphsArgs(selectedNodes, files); if (Preferences.LocalSettings.GetBool("AsyncRefreshNodesGlyphs", false)) { Thread refreshProc = new Thread(new ParameterizedThreadStart(SyncAsyncRefreshNodesGlyphs)); refreshProc.IsBackground = true; refreshProc.Name = "AsyncRefreshNodesGlyphs"; refreshProc.Start(args); } else { SyncAsyncRefreshNodesGlyphs(args); } }
/// <summary> /// Refreshes the glyphs of the specified hierarchy nodes /// </summary> private void SyncAsyncRefreshNodesGlyphs(object parm) { RefreshNodesGlyphsArgs parms = parm as RefreshNodesGlyphsArgs; if (parms == null) { return; } IList <VSITEMSELECTION> selectedNodes = parms.selectedNodes; IList <string> files = parms.files; if (SccService.IsSolutionSelected) { selectedNodes = null; } P4VsProvider.Instance.ResetCommandStatus(); if (!P4VsProvider.Instance.IsThereASolution()) { return; } // make sure the context menus update for the new state P4VsProvider.Instance.ResetCommandStatus(); if (selectedNodes == null) { bool TreatProjectsAsFolders = Preferences.LocalSettings.GetBool("TreatProjectsAsFolders", true); if (TreatProjectsAsFolders) { string slnPath = Path.GetDirectoryName(P4VsProvider.Instance.GetSolutionFileName()); slnPath = string.Format("{0}\\...", slnPath); files = new List <string>(); files.Add(slnPath); } else { files = P4VsProvider.Instance.GetSolutionFiles(); } selectedNodes = new List <VSITEMSELECTION>(); IList <IVsHierarchy> controlledProjects = SccService.GetControlledProjects(); if (controlledProjects != null) { foreach (IVsHierarchy node in controlledProjects) { VSITEMSELECTION vsItem; vsItem.itemid = VSConstants.VSITEMID_ROOT; vsItem.pHier = node; selectedNodes.Add(vsItem); } } } if (SccService.ScmProvider != null) { if ((files != null) && (files.Count > 0)) { if (Preferences.LocalSettings.GetBool("LazyLoadStatus", false) == false) { SccService.ScmProvider.UpdateFiles(files, true); } foreach (string file in files) { if ((file.EndsWith("\\...")) || (file.EndsWith("\\*"))) { //wildcard SccService.ScmProvider.ResetIgnoredFilesMap(); break; } SccService.ScmProvider.ResetIgnoredFilesMap(file); } } else { SccService.ScmProvider.ResetIgnoredFilesMap(); } } foreach (VSITEMSELECTION vsItemSel in selectedNodes) { IVsSccProject2 sccProject2 = vsItemSel.pHier as IVsSccProject2; if (vsItemSel.itemid == VSConstants.VSITEMID_ROOT) { string name = ""; if (vsItemSel.pHier != null) { vsItemSel.pHier.GetCanonicalName(vsItemSel.itemid, out name); } if (sccProject2 == null) { // Note: The solution's hierarchy does not implement IVsSccProject2, IVsSccProject interfaces // It may be a pain to treat the solution as special case everywhere; a possible workaround is // to implement a solution-wrapper class, that will implement IVsSccProject2, IVsSccProject and // IVsHierarhcy interfaces, and that could be used in provider's code wherever a solution is needed. // This approach could unify the treatment of solution and projects in the provider's code. // Until then, solution is treated as special case string[] rgpszFullPaths = new string[1]; rgpszFullPaths[0] = P4VsProvider.Instance.GetSolutionFileName(); VsStateIcon[] rgsiGlyphs = new VsStateIcon[1]; uint[] rgdwSccStatus = new uint[1]; if (SccService.ScmProvider != null) { SccService.ScmProvider.UpdateFileInCache(rgpszFullPaths[0], true); } SccService.GetSccGlyph(1, rgpszFullPaths, rgsiGlyphs, rgdwSccStatus); // Set the solution's glyph directly in the hierarchy solHier.SetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_StateIconIndex, rgsiGlyphs[0]); } else { if ((SccService.UiDispatcher != null) && (SccService.UiDispatcher.Thread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)) { SccService.UiDispatcher.BeginInvoke( new SccGlyphChangedDelegate(SccGlyphChanged), sccProject2, 0, null, null, null); } else { sccProject2.SccGlyphChanged(0, null, null, null); } } } else { // Refresh all the glyphs in the project; the project will call back GetSccGlyphs() // with the files for each node that will need new glyph //sccProject2.SccGlyphChanged(0,null,null,null); // It may be easier/faster to simply refresh all the nodes in the project, // and let the project call back on GetSccGlyphs, but just for the sake of the demo, // let's refresh ourselves only one node at a time IList <string> sccFiles = P4VsProvider.Instance.GetNodeFiles(sccProject2, vsItemSel.itemid); //// We'll use for the node glyph just the Master file's status (ignoring special files of the node) if (sccFiles.Count > 0) { for (int idx = 0; idx < sccFiles.Count; idx++) { string[] rgpszFullPaths = new string[1]; rgpszFullPaths[0] = sccFiles[idx]; VsStateIcon[] rgsiGlyphs = new VsStateIcon[1]; uint[] rgdwSccStatus = new uint[1]; if ((SccService.ScmProvider != null) && (files == null) || (files.Count <= 0)) { // update if not already updated SccService.ScmProvider.UpdateFileInCache(sccFiles[idx], true); } SccService.GetSccGlyph(1, rgpszFullPaths, rgsiGlyphs, rgdwSccStatus); uint[] rguiAffectedNodes = new uint[1]; if (idx == 0) { rguiAffectedNodes[0] = vsItemSel.itemid; if (sccProject2 != null) { // Don't async update the node's glyph if the new status is deleted // The mode might not exist anymore when the update is actually run if ((SccService.UiDispatcher != null) && (SccService.UiDispatcher.Thread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) && ((rgdwSccStatus[0] & (uint)__SccStatus.SCC_STATUS_DELETED) == 0)) { SccService.UiDispatcher.BeginInvoke( new SccGlyphChangedDelegate(SccGlyphChanged), sccProject2, 1, rguiAffectedNodes, rgsiGlyphs, rgdwSccStatus); } else { sccProject2.SccGlyphChanged(1, rguiAffectedNodes, rgsiGlyphs, rgdwSccStatus); } } } else { uint itemid; int fFound; IVsProject pscp = sccProject2 as IVsProject; VSDOCUMENTPRIORITY[] prio = new VSDOCUMENTPRIORITY[1]; if (pscp != null && pscp.IsDocumentInProject(sccFiles[idx], out fFound, prio, out itemid) == VSConstants.S_OK && fFound != 0) { rguiAffectedNodes[0] = itemid; // Don't async update the node's glyph if the new status is deleted // The mode might not exist anymore when the update is actually run if ((SccService.UiDispatcher != null) && (SccService.UiDispatcher.Thread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) && ((rgdwSccStatus[0] & (uint)__SccStatus.SCC_STATUS_DELETED) == 0)) { SccService.UiDispatcher.BeginInvoke( new SccGlyphChangedDelegate(SccGlyphChanged), sccProject2, 1, rguiAffectedNodes, rgsiGlyphs, rgdwSccStatus); } else { sccProject2.SccGlyphChanged(1, rguiAffectedNodes, rgsiGlyphs, rgdwSccStatus); } } } } } else { // could not find files based on the nodes selected, so use the list of files passed in SccService.RefreshProjectGlyphs(files, true); } } } }