/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.ValidatePrimarySelection"]/*' /> /// <devdoc> /// Ensures that a valid primary selection exists. /// </devdoc> private void ValidatePrimarySelection() { if (primarySelection == null) { IDictionaryEnumerator selections = (IDictionaryEnumerator)selectionsByComponent.GetEnumerator(); bool valueFound = selections.MoveNext(); if (valueFound) { primarySelection = (SelectionItem)selections.Value; primarySelection.Primary = true; } } }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.SetPrimarySelection"]/*' /> /// <devdoc> /// Sets the given selection object to be the primary selection. /// </devdoc> internal void SetPrimarySelection(SelectionItem sel) { if (sel != primarySelection) { if (null != primarySelection) { primarySelection.Primary = false; } primarySelection = sel; } if (null != primarySelection) { primarySelection.Primary = true; } }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.Dispose"]/*' /> /// <devdoc> /// Disposes the entire selection manager. /// </devdoc> public void Dispose() { // We've got to be careful here. We're one of the last things to go away when // a form is being torn down, and we've got to be wary if things have pulled out // already. // host.RemoveService(typeof(ISelectionService)); host.TransactionOpened -= new EventHandler(this.OnTransactionOpened); host.TransactionClosed -= new DesignerTransactionCloseEventHandler(this.OnTransactionClosed); if (host.InTransaction) { OnTransactionClosed(host, new DesignerTransactionCloseEventArgs(true)); } host.LoadComplete -= new EventHandler(this.OnLoadComplete); // And configure the events we want to listen to. // IComponentChangeService cs = (IComponentChangeService)host.GetService(typeof(IComponentChangeService)); Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || cs != null, "IComponentChangeService not found"); if (cs != null) { cs.ComponentAdded -= new ComponentEventHandler(this.OnComponentAdd); cs.ComponentRemoved -= new ComponentEventHandler(this.OnComponentRemove); cs.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged); } SelectionItem[] sels = new SelectionItem[selectionsByComponent.Values.Count]; selectionsByComponent.Values.CopyTo(sels, 0); for (int i = 0; i < sels.Length; i++) { sels[i].Dispose(); } selectionsByComponent.Clear(); primarySelection = null; }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.SetSelectedComponents1"]/*' /> /// <devdoc> /// Changes the user's current set of selected components to the components /// in the given array. If the array is null or doesn't contain any /// components, this will select the top level component in the designer. /// </devdoc> public void SetSelectedComponents(ICollection components, SelectionTypes selectionType) { bool fToggle = false; bool fControl = false; bool fClick = false; bool fChanged = false; // did we actually change something? // We always want to allow NULL arrays coming in. // if (components == null) { components = new object[0]; } #if DEBUG foreach (object comp in components) { Debug.Assert(comp != null, "NULL component pushed into SetSelectedComponents"); if (comp is IComponent) { Debug.Assert(((IComponent)comp).Site != null, "Component of type " + comp.GetType().Name + " doesn't have a site!"); } } #endif if ((selectionType & SelectionTypes.Normal) == SelectionTypes.Normal || (selectionType & SelectionTypes.Click) == SelectionTypes.Click) { fControl = ((Control.ModifierKeys & Keys.Control) == Keys.Control); // Only toggle when we are affecting a single control, and // when we are handling the "mouse" state events (i.e. up/down // used to show/hide the selection). // fToggle = ((Control.ModifierKeys & Keys.Control) != 0 || (Control.ModifierKeys & Keys.Shift) != 0) && components.Count == 1 && (selectionType & SelectionTypes.MouseUp) != SelectionTypes.MouseUp; } if ((selectionType & SelectionTypes.Click) == SelectionTypes.Click) { fClick = true; } #if DEBUG if (Switches.SETSELECT.TraceVerbose) { Debug.Write("SETSELECT: ["); bool first = true; foreach (object comp in components) { if (first) { first = false; Debug.Write(" "); } Debug.Write(((IComponent)comp).Site.Name); } Debug.Write("] "); Debug.Write(" fToggle=" + fToggle.ToString()); Debug.Write(" fControl=" + fControl.ToString()); Debug.Write(" fClick=" + fClick.ToString()); Debug.WriteLine(""); Debug.WriteLine(Environment.StackTrace); } #endif // If we are replacing the selection, only remove the ones that are not in our new list. // We also handle the special case here of having a singular component selected that's // already selected. In this case we just move it to the primary selection. // if (!fToggle && !fControl) { object firstSelection = null; foreach (object o in components) { firstSelection = o; break; } if (fClick && 1 == components.Count && GetComponentSelected(firstSelection)) { SelectionItem oldPrimary = primarySelection; SetPrimarySelection((SelectionItem)selectionsByComponent[firstSelection]); if (oldPrimary != primarySelection) { fChanged = true; } } else { SelectionItem[] selections = new SelectionItem[selectionsByComponent.Values.Count]; selectionsByComponent.Values.CopyTo(selections, 0); // Yucky and N^2, but even with several hundred components this should be fairly fast // foreach (SelectionItem item in selections) { bool remove = true; foreach (object comp in components) { if (comp == item.component) { remove = false; break; } } if (remove) { Debug.WriteLineIf(Switches.SETSELECT.TraceVerbose, "Removing selection due to replace selection"); RemoveSelection(item); fChanged = true; } } } } SelectionItem primarySel = null; int selectedCount = selectionsByComponent.Count; // Now do the selection! // foreach (object comp in components) { if (comp != null) { SelectionItem s = (SelectionItem)selectionsByComponent[comp]; if (null == s) { Debug.WriteLineIf(Switches.SETSELECT.TraceVerbose, "Adding selection due to no selection existing"); s = new SelectionItem(this, comp); AddSelection(s); if (fControl || fToggle) { primarySel = s; } fChanged = true; } else { if (fToggle) { // remove the selection from our list // Debug.WriteLineIf(Switches.SETSELECT.TraceVerbose, "Removing selection due to toggle"); RemoveSelection(s); fChanged = true; } } } } if (primarySel != null) { SetPrimarySelection(primarySel); } // Now notify that our selection has changed // if (fChanged) { Debug.WriteLineIf(Switches.SETSELECT.TraceVerbose, "Selection changed, calling OnSelectionChanged"); OnSelectionChanged(); } }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.RemoveSelection"]/*' /> /// <devdoc> /// Removes the given selection from our selection list, keeping everything nicely in /// ssync. /// </devdoc> internal void RemoveSelection(SelectionItem s) { selectionsByComponent.Remove(s.component); s.Dispose(); }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.OnComponentRemove"]/*' /> /// <devdoc> /// called by the formcore when someone has removed a component. This will /// remove any selection on the component without disturbing the rest of /// the selection /// </devdoc> private void OnComponentRemove(object sender, ComponentEventArgs ce) { SelectionItem sel = (SelectionItem)selectionsByComponent[ce.Component]; if (sel != null) { RemoveSelection(sel); // IF allowNoSelection has been set, then we need to return before // we change the selection to something we shouldn't // if (AllowNoSelection) { return; } // If we removed the last selection and we have a designer host, then select the base // component of the host. Otherwise, it is OK to have an empty selection. // if (selectionsByComponent.Count == 0 && host != null) { // now we have to run through all the components and pick // the control with the highest zorder. For v.next we should // consider providing a service that allows a designer to decide // a new selection to pick when the existing one dies. // IComponent[] comps = new IComponent[host.Container.Components.Count]; host.Container.Components.CopyTo(comps, 0); if (comps == null) { return; } int maxZOrder = -1; int defaultIndex = -1; object maxIndexComp = null; object baseComp = host.RootComponent; if (baseComp == null) { return; } for (int i = comps.Length - 1; i >= 0; i--) { if (comps[i] == baseComp) { continue; } else if (defaultIndex == -1) { defaultIndex = i; } if (comps[i] is Control) { int zorder = ((Control)comps[i]).TabIndex; if (zorder > maxZOrder) { maxZOrder = zorder; maxIndexComp = (object)comps[i]; } } } if (maxIndexComp == null) { if (defaultIndex != -1) { maxIndexComp = comps[defaultIndex]; } else { maxIndexComp = baseComp; } } SetSelectedComponents(new object[] { maxIndexComp }, SelectionTypes.Replace); } else { OnSelectionChanged(); } } else { // Component isn't selected, but our list of selectable components is // different. // OnSelectionContentsChanged(); } }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.AddSelection"]/*' /> /// <devdoc> /// Adds the given selection to our selection list. /// </devdoc> internal void AddSelection(SelectionItem sel) { selectionsByComponent[sel.component] = sel; }
/// <include file='doc\SelectionService.uex' path='docs/doc[@for="SelectionService.UpdateHelpContext"]/*' /> /// <devdoc> /// Pushes the help context into the help service for the /// current set of selected objects. /// </devdoc> private void UpdateHelpContext() { IHelpService helpService = (IHelpService)host.GetService(typeof(IHelpService)); IEnumerator e; if (helpService == null) { return; } // If there is an old set of context attributes, remove them. // if (contextAttributes != null && contextAttributes.Keys.Count > 0) { e = contextAttributes.Keys.GetEnumerator(); while (e.MoveNext()) { helpService.RemoveContextAttribute("Keyword", (string)e.Current); } contextAttributes.Clear(); } IComponent rootComponent = host.RootComponent; IDesigner baseDesigner = null; if (rootComponent != null) { baseDesigner = host.GetDesigner(rootComponent); if (baseDesigner != null) { helpService.RemoveContextAttribute("Keyword", "Designer_" + baseDesigner.GetType().FullName); } } // Clear the selection keyword // helpService.RemoveContextAttribute("Selection", selectionKeywords[contextKeyword]); if (contextAttributes == null) { contextAttributes = new Hashtable(); } // Get a list of unique class names. // e = selectionsByComponent.Values.GetEnumerator(); bool baseComponentSelected = false; if (rootComponent != null && (selectionsByComponent.Count == 0 || (selectionsByComponent.Count == 1 && selectionsByComponent[rootComponent] != null))) { baseComponentSelected = true; } while (e.MoveNext()) { SelectionItem s = (SelectionItem)e.Current; contextAttributes[s.component.GetType().FullName] = null; } // And push them into the help context as keywords. // e = contextAttributes.Keys.GetEnumerator(); HelpKeywordType selectionType = baseComponentSelected ? HelpKeywordType.GeneralKeyword : HelpKeywordType.F1Keyword; while (e.MoveNext()) { helpService.AddContextAttribute("Keyword", (string)e.Current, selectionType); } // Now add the form designer context as well // if (baseDesigner != null) { helpService.AddContextAttribute("Keyword", "Designer_" + baseDesigner.GetType().FullName, baseComponentSelected ? HelpKeywordType.F1Keyword : HelpKeywordType.GeneralKeyword); } // Now add the appropriate selection keyword. Note that we do not count // the base component as being selected if it is the only thing selected. // int count = SelectionCount; if (rootComponent != null && count == 1 && selectionsByComponent[rootComponent] != null) { count--; } contextKeyword = (short)Math.Min(count, selectionKeywords.Length - 1); helpService.AddContextAttribute("Selection", selectionKeywords[contextKeyword], HelpKeywordType.FilterKeyword); }