diff options
author | Alan McGovern <alan.mcgovern@gmail.com> | 2015-09-18 21:20:36 +0300 |
---|---|---|
committer | Alan McGovern <alan.mcgovern@gmail.com> | 2015-09-18 21:20:36 +0300 |
commit | 324ed342c08e2d35c4738f5cbb99f43d57186f90 (patch) | |
tree | d232280b8aad6ec4978c6d6cd56f25dfe5928c2e | |
parent | bc963f957eeb4b018f5e7d029104a42d1a9355f9 (diff) | |
parent | 90afd0c3393cb57340174e1cda444b9566ef7d1e (diff) |
Merge pull request #1045 from mono/cycle6-bug31116monodevelop-5.10.0.799
Fixup Mac toolbar crashers
5 files changed, 344 insertions, 186 deletions
diff --git a/main/src/addins/MacPlatform/MainToolbar/MainToolbar.cs b/main/src/addins/MacPlatform/MainToolbar/MainToolbar.cs index ff5e092854..0f736344e7 100644 --- a/main/src/addins/MacPlatform/MainToolbar/MainToolbar.cs +++ b/main/src/addins/MacPlatform/MainToolbar/MainToolbar.cs @@ -33,6 +33,7 @@ using AppKit; using CoreGraphics; using Foundation; using MonoDevelop.Ide; +using Xwt; namespace MonoDevelop.MacIntegration.MainToolbar { @@ -66,6 +67,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar } int selectorIdx; + SelectorView selector { + get { return (SelectorView)widget.Items[selectorIdx].View; } + } + SelectorView.PathSelectorView selectorView { get { return (SelectorView.PathSelectorView)widget.Items[selectorIdx].View.Subviews [0]; } } @@ -96,6 +101,35 @@ namespace MonoDevelop.MacIntegration.MainToolbar return item; } + OverflowInfoEventArgs FillOverflowInfo (OverflowInfoEventArgs e) + { + var visibleItems = widget.VisibleItems; + var allItems = widget.Items; + + e.WindowWidth = gtkWindow.Allocation.Width; + foreach (var iter in allItems) { + e.AllItemsWidth += iter.MinSize.Width; + if (!visibleItems.Contains (iter)) + e.ItemsInOverflowWidth += iter.MinSize.Width; + } + // Add spacings. + nfloat spacing = (allItems.Length - 1) * 16; + e.AllItemsWidth += spacing; + + return e; + } + + bool IsCorrectNotification (NSView view, NSObject notifObject) + { + var window = selector.Window; + + // Skip updates with a null Window. Only crashes on Mavericks. + // The View gets updated once again when the window resize finishes. + // We're getting notified about all windows in the application (for example, NSPopovers) that change size when really we only care about + // the window the bar is in. + return window != null && notifObject == window; + } + NSToolbarItem CreateSelectorToolbarItem () { var selector = new SelectorView (); @@ -109,6 +143,43 @@ namespace MonoDevelop.MacIntegration.MainToolbar item.MinSize = item.MaxSize = e.Size; centeringSpace.UpdateWidth (); }; + selector.OverflowInfoRequested += (o, e) => { + FillOverflowInfo (e); + }; + + IDisposable resizeTimer = null; + NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.WillStartLiveResizeNotification, notif => DispatchService.GuiDispatch (() => { + if (!IsCorrectNotification (selector, notif.Object)) + return; + + if (resizeTimer != null) + resizeTimer.Dispose (); + + resizeTimer = Application.TimeoutInvoke (100, () => { + if (widget.Items.Length != widget.VisibleItems.Length) + selector.RequestResize (); + return true; + }); + })); + + NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.DidResizeNotification, notif => DispatchService.GuiDispatch (() => { + if (!IsCorrectNotification (selector, notif.Object)) + return; + + // Don't check difference in overflow menus. This could cause issues since we're doing resizing of widgets and the views might go in front + // or behind while we're doing the resize request. + selector.RequestResize (); + })); + + NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.DidEndLiveResizeNotification, notif => DispatchService.GuiDispatch (() => { + if (!IsCorrectNotification (selector, notif.Object)) + return; + + if (resizeTimer != null) + resizeTimer.Dispose (); + + resizeTimer = Application.TimeoutInvoke (300, selector.RequestResize); + })); var pathSelector = (SelectorView.PathSelectorView)selector.Subviews [0]; pathSelector.ConfigurationChanged += (sender, e) => { @@ -143,6 +214,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar nfloat resize = 6 + 33 * bar.SegmentCount; item.MinSize = new CGSize (resize, bar.FittingSize.Height); item.MaxSize = new CGSize (resize, bar.FittingSize.Height); + selector.RequestResize (); centeringSpace.UpdateWidth (); }; return item; @@ -181,15 +253,9 @@ namespace MonoDevelop.MacIntegration.MainToolbar bar.GainedFocus += (o, e) => IdeApp.Workbench.RootWindow.Focus = null; viewCache.Add (bar); - var menuBar = new SearchBar { - Frame = new CGRect (0, 0, 180, bar.FittingSize.Height), - }; var item = new NSToolbarItem (SearchBarId) { View = bar, - MenuFormRepresentation = new NSMenuItem { - View = menuBar, - }, - MinSize = new CGSize (180, bar.FittingSize.Height), + MinSize = new CGSize (150, bar.FittingSize.Height), MaxSize = new CGSize (270, bar.FittingSize.Height), }; AttachToolbarEvents (bar); @@ -207,7 +273,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar MaxSize = new CGSize (360, 22), }; - NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.DidResizeNotification, notif => DispatchService.GuiDispatch (() => { + Action<NSNotification> resizeAction = notif => DispatchService.GuiDispatch (() => { // Skip updates with a null Window. Only crashes on Mavericks. // The View gets updated once again when the window resize finishes. if (bar.Window == null) @@ -220,10 +286,13 @@ namespace MonoDevelop.MacIntegration.MainToolbar double maxSize = Math.Round (bar.Window.Frame.Width * 0.30f); double minSize = Math.Round (bar.Window.Frame.Width * 0.25f); - item.MinSize = new CGSize ((nfloat)Math.Max (280, minSize), 22); + item.MinSize = new CGSize ((nfloat)Math.Max (220, minSize), 22); item.MaxSize = new CGSize ((nfloat)Math.Min (700, maxSize), 22); bar.RepositionStatusLayers (); - })); + }); + + NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.DidResizeNotification, resizeAction); + NSNotificationCenter.DefaultCenter.AddObserver (NSWindow.DidEndLiveResizeNotification, resizeAction); return item; } @@ -284,32 +353,12 @@ namespace MonoDevelop.MacIntegration.MainToolbar public event EventHandler SearchEntryResized; #pragma warning restore 0067 - bool IsSearchEntryInOverflow { - get { return widget.Items.Length != widget.VisibleItems.Length; } - } - public void FocusSearchBar () { searchEntry.Focus (); var entry = searchEntry; - if (!IsSearchEntryInOverflow) - entry.SelectText (entry); - else { - // NSSearchField -> NSToolbarItemViewer -> _NSToolbarClipView -> NSToolbarView -> NSToolbarClippedItemsIndicator - var clipItem = (NSButton)searchEntry.Superview.Superview.Superview.Subviews [1]; - var sel = new ObjCRuntime.Selector ("_computeMenuForClippedItemsIfNeeded"); - if (!clipItem.RespondsToSelector (sel)) - throw new Exception ("Cocoa selector changed for clipped items menu."); - - clipItem.PerformSelector (sel); - var menu = clipItem.Menu; - var searchItem = menu.ItemAt (0); - var searchView = (SearchBar)searchItem.View; - AttachToolbarEvents (searchView); - menu.PopUpMenu (menu.ItemAt (0), new CGPoint (0, -5), clipItem); - searchView.SelectText (searchView); - } + entry.SelectText (entry); } List<IButtonBarButton> barItems = new List<IButtonBarButton> (); @@ -409,44 +458,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar public string SearchText { get { - if (!IsSearchEntryInOverflow) { - return searchEntry.StringValue; - } - - // NSSearchField -> NSToolbarItemViewer -> _NSToolbarClipView -> NSToolbarView -> NSToolbarClippedItemsIndicator - var clipItem = (NSButton)searchEntry.Superview.Superview.Superview.Subviews [1]; - var sel = new ObjCRuntime.Selector ("_computeMenuForClippedItemsIfNeeded"); - if (!clipItem.RespondsToSelector (sel)) - throw new Exception ("Cocoa selector changed for clipped items menu."); - - clipItem.PerformSelector (sel); - - var menuBar = (SearchBar)clipItem.Menu.ItemAt (0).View; - AttachToolbarEvents (menuBar); - return menuBar.StringValue; + return searchEntry.StringValue; } set { - if (!IsSearchEntryInOverflow) { - searchEntry.StringValue = value; - return; - } - - // NSSearchField -> NSToolbarItemViewer -> _NSToolbarClipView -> NSToolbarView -> NSToolbarClippedItemsIndicator - var clipItem = (NSButton)searchEntry.Superview.Superview.Superview.Subviews [1]; - var sel = new ObjCRuntime.Selector ("_computeMenuForClippedItemsIfNeeded"); - if (!clipItem.RespondsToSelector (sel)) - throw new Exception ("Cocoa selector changed for clipped items menu."); - - clipItem.PerformSelector (sel); - - foreach (NSMenuItem item in clipItem.Menu.ItemArray ()) { - if (item.View is SearchBar) { - var menuBar = (SearchBar)item.View; - AttachToolbarEvents (menuBar); - menuBar.StringValue = value; - break; - } - } + searchEntry.StringValue = value; } } diff --git a/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs b/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs index 4778e27954..3c4c4fbfc4 100644 --- a/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs +++ b/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs @@ -45,10 +45,18 @@ namespace MonoDevelop.MacIntegration.MainToolbar } } + class OverflowInfoEventArgs : EventArgs + { + public nfloat WindowWidth { get; set; } + public nfloat AllItemsWidth { get; set; } + public nfloat ItemsInOverflowWidth { get; set; } + } + [Register] class SelectorView : NSButton { public event EventHandler<SizeRequestedEventArgs> ResizeRequested; + public event EventHandler<OverflowInfoEventArgs> OverflowInfoRequested; internal const int ConfigurationIdx = 0; internal const int RuntimeIdx = 1; @@ -61,28 +69,104 @@ namespace MonoDevelop.MacIntegration.MainToolbar AddSubview (pathSelectorView); } - public override void DrawRect (CGRect dirtyRect) + public bool RequestResize () + { + var p = (PathSelectorView)Subviews [0]; + var overflowInfo = new OverflowInfoEventArgs (); + if (OverflowInfoRequested != null) + OverflowInfoRequested (this, overflowInfo); + + var size = new CGSize (p.ResizeIfNeeded (overflowInfo), Frame.Height); + + if (size != Frame.Size) { + if (ResizeRequested != null) + ResizeRequested (this, new SizeRequestedEventArgs (size)); + + SetFrameSize (size); + p.SetFrameSize (size); + + SetNeedsDisplay (); + p.SetNeedsDisplay (); + return true; + } + return false; + } + + public override void ViewWillDraw () { - var p = (NSPathControl)Subviews [0]; - var size = new CGSize (10 + - p.PathComponentCells [ConfigurationIdx].CellSize.Width + - p.PathComponentCells [RuntimeIdx].CellSize.Width + p.Frame.Left, - Frame.Size.Height); - if (ResizeRequested != null) - ResizeRequested (this, new SizeRequestedEventArgs (size)); - - SetFrameSize (size); - p.SetFrameSize (size); - p.SetNeedsDisplay (); - base.DrawRect (new CGRect (CGPoint.Empty, size)); + RequestResize (); + base.ViewWillDraw (); } #region PathSelectorView [Register] public class PathSelectorView : NSPathControl { + [Flags] + enum CellState + { + AllHidden = 0x0, + RuntimeShown = 0x1, + ConfigurationShown = 0x2, + AllShown = 0x3, + } + static readonly string ConfigurationPlaceholder = GettextCatalog.GetString ("Default"); static readonly string RuntimePlaceholder = GettextCatalog.GetString ("Default"); + CellState state = CellState.AllShown; + + nfloat UpdatePathCellForSize (int idx, nfloat remaining, CellState newStateIfEnoughSize) + { + var cell = PathComponentCells [idx]; + string text; + if (idx == ConfigurationIdx) { + if (ActiveConfiguration != null) + text = ActiveConfiguration.DisplayString; + else + text = ConfigurationPlaceholder; + } else { + if (ActiveRuntime != null) { + using (var mutableModel = ActiveRuntime.GetMutableModel ()) + text = mutableModel.FullDisplayString; + } else + text = RuntimePlaceholder; + } + var size = new NSAttributedString (text, new NSStringAttributes { Font = cell.Font }).Size.Width + 20; + if (size < remaining) { + state |= newStateIfEnoughSize; + UpdatePathText (idx, text); + } + return remaining - size; + } + + internal nfloat ResizeIfNeeded (OverflowInfoEventArgs args) + { + var remaining = args.WindowWidth - args.AllItemsWidth; + if (remaining < 0 || args.ItemsInOverflowWidth > 0) { + var cell = PathComponentCells [RuntimeIdx]; + var size = new NSAttributedString (cell.Title, new NSStringAttributes { Font = cell.Font }).Size.Width; + remaining += size; + args.ItemsInOverflowWidth -= size; + if ((state & CellState.RuntimeShown) != 0) { + state &= ~CellState.RuntimeShown; + UpdatePathText (RuntimeIdx, string.Empty); + } + if ((remaining < 0 || args.ItemsInOverflowWidth > 0) && (state & CellState.ConfigurationShown) != 0) { + state &= ~CellState.ConfigurationShown; + UpdatePathText (ConfigurationIdx, string.Empty); + } + } else { + remaining = remaining - args.ItemsInOverflowWidth; + if ((state & CellState.ConfigurationShown) == 0) + remaining = UpdatePathCellForSize (ConfigurationIdx, remaining, CellState.ConfigurationShown); + if ((state & CellState.RuntimeShown) == 0) + UpdatePathCellForSize (RuntimeIdx, remaining, CellState.RuntimeShown); + } + + return 10 + + PathComponentCells [ConfigurationIdx].CellSize.Width + + PathComponentCells [RuntimeIdx].CellSize.Width + Frame.Left; + } NSMenu CreateSubMenuForRuntime (IRuntimeModel runtime) { @@ -101,14 +185,21 @@ namespace MonoDevelop.MacIntegration.MainToolbar void CreateMenuItem (NSMenu menu, IRuntimeModel runtime) { - var menuItem = new NSMenuItem { - IndentationLevel = runtime.IsIndented ? 2 : 1, - Enabled = runtime.Enabled, - Hidden = !runtime.Visible, - AttributedTitle = new NSAttributedString (runtime.DisplayString, new NSStringAttributes { - Font = runtime.Notable ? NSFontManager.SharedFontManager.ConvertFont (menu.Font, NSFontTraitMask.Bold) : menu.Font, - }), - }; + NSMenuItem menuItem; + string runtimeFullDisplayString; + + using (var mutableModel = runtime.GetMutableModel ()) { + runtimeFullDisplayString = mutableModel.FullDisplayString; + + menuItem = new NSMenuItem { + IndentationLevel = runtime.IsIndented ? 2 : 1, + AttributedTitle = new NSAttributedString (mutableModel.DisplayString, new NSStringAttributes { + Font = runtime.Notable ? NSFontManager.SharedFontManager.ConvertFont (menu.Font, NSFontTraitMask.Bold) : menu.Font, + }), + Enabled = mutableModel.Enabled, + Hidden = !mutableModel.Visible, + }; + } var subMenu = CreateSubMenuForRuntime (runtime); if (subMenu != null) { @@ -116,8 +207,14 @@ namespace MonoDevelop.MacIntegration.MainToolbar menuItem.Enabled = true; } else { menuItem.Activated += (o2, e2) => { - string old = ActiveRuntime.FullDisplayString; - IRuntimeModel newRuntime = runtimeModel.FirstOrDefault (r => r.FullDisplayString == runtime.FullDisplayString); + string old; + using (var activeMutableModel = ActiveRuntime.GetMutableModel ()) + old = activeMutableModel.FullDisplayString; + + IRuntimeModel newRuntime = runtimeModel.FirstOrDefault (r => { + using (var newRuntimeMutableModel = r.GetMutableModel ()) + return newRuntimeMutableModel.FullDisplayString == runtimeFullDisplayString; + }); if (newRuntime == null) return; @@ -127,7 +224,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar RuntimeChanged (o2, ea); if (ea.Handled) - ActiveRuntime = runtimeModel.First (r => r.FullDisplayString == old); + ActiveRuntime = runtimeModel.First (r => { + using (var newRuntimeMutableModel = r.GetMutableModel ()) + return newRuntimeMutableModel.FullDisplayString == old; + }); }; } menu.AddItem (menuItem); @@ -168,6 +268,9 @@ namespace MonoDevelop.MacIntegration.MainToolbar Font = NSFont.MenuFontOfSize (12), }; if (object.ReferenceEquals (ClickedPathComponentCell, PathComponentCells [ConfigurationIdx])) { + if (ActiveConfiguration == null) + return; + foreach (var configuration in ConfigurationModel) { if (idx == -1 && configuration.OriginalId == ActiveConfiguration.OriginalId) idx = i; @@ -185,18 +288,25 @@ namespace MonoDevelop.MacIntegration.MainToolbar ++i; } } else if (object.ReferenceEquals (ClickedPathComponentCell, PathComponentCells [RuntimeIdx])) { - foreach (var runtime in RuntimeModel) { - if (idx == -1 && runtime.DisplayString == ActiveRuntime.DisplayString) - idx = i; - - if (runtime.HasParent) - continue; - - if (runtime.IsSeparator) - menu.AddItem (NSMenuItem.SeparatorItem); - else - CreateMenuItem (menu, runtime); - ++i; + if (ActiveRuntime == null) + return; + + using (var activeMutableModel = ActiveRuntime.GetMutableModel ()) { + foreach (var runtime in RuntimeModel) { + using (var mutableModel = runtime.GetMutableModel ()) { + if (idx == -1 && mutableModel.DisplayString == activeMutableModel.DisplayString) + idx = i; + } + + if (runtime.HasParent) + continue; + + if (runtime.IsSeparator) + menu.AddItem (NSMenuItem.SeparatorItem); + else + CreateMenuItem (menu, runtime); + ++i; + } } } else throw new NotSupportedException (); @@ -234,7 +344,8 @@ namespace MonoDevelop.MacIntegration.MainToolbar void UpdatePathText (int idx, string text) { - PathComponentCells [idx].Title = text; + bool showText = (idx == ConfigurationIdx && (state & CellState.ConfigurationShown) != 0) || (idx == RuntimeIdx && (state & CellState.RuntimeShown) != 0); + PathComponentCells [idx].Title = showText ? text : "\u00A0"; PathComponentCells [ConfigurationIdx].Image = ImageService.GetIcon ("project").ToNSImage (); PathComponentCells [RuntimeIdx].Image = ImageService.GetIcon ("device").ToNSImage (); @@ -246,6 +357,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar get { return activeConfiguration; } set { activeConfiguration = value; + state |= CellState.ConfigurationShown; UpdatePathText (ConfigurationIdx, value.DisplayString); } } @@ -255,7 +367,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar get { return activeRuntime; } set { activeRuntime = value; - UpdatePathText (RuntimeIdx, value.FullDisplayString); + using (var mutableModel = value.GetMutableModel ()) { + state |= CellState.RuntimeShown; + UpdatePathText (RuntimeIdx, mutableModel.FullDisplayString); + } } } @@ -265,8 +380,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar set { configurationModel = value; int count = value.Count (); - if (count == 0) + if (count == 0) { + state |= CellState.ConfigurationShown; UpdatePathText (ConfigurationIdx, ConfigurationPlaceholder); + } PathComponentCells [ConfigurationIdx].Enabled = count > 1; } } @@ -277,8 +394,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar set { runtimeModel = value; int count = value.Count (); - if (count == 0) + if (count == 0) { + state |= CellState.RuntimeShown; UpdatePathText (RuntimeIdx, RuntimePlaceholder); + } PathComponentCells [RuntimeIdx].Enabled = count > 1; } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbar.cs index 0c2f09ee5c..751ebc8329 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbar.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbar.cs @@ -110,19 +110,22 @@ namespace MonoDevelop.Components.MainToolbar return; } - renderer.Visible = runtime.Visible; - renderer.Sensitive = runtime.Enabled; - renderer.Xpad = (uint)(runtime.IsIndented ? 18 : 3); - - if (!runtimeCombo.PopupShown) { - // no need to ident text when the combo dropdown is not showing - if (Platform.IsWindows) - renderer.Xpad = 3; - renderer.Text = runtime.FullDisplayString; - renderer.Attributes = normalAttributes; - } else { - renderer.Text = runtime.DisplayString; - renderer.Attributes = runtime.Notable ? boldAttributes : normalAttributes; + using (var mutableModel = runtime.GetMutableModel ()) { + renderer.Visible = mutableModel.Visible; + renderer.Sensitive = mutableModel.Enabled; + renderer.Xpad = (uint)(runtime.IsIndented ? 18 : 3); + + if (!runtimeCombo.PopupShown) { + // no need to ident text when the combo dropdown is not showing + if (Platform.IsWindows) + renderer.Xpad = 3; + renderer.Text = mutableModel.FullDisplayString; + renderer.Attributes = normalAttributes; + } else { + renderer.Text = mutableModel.DisplayString; + renderer.Attributes = runtime.Notable ? boldAttributes : normalAttributes; + } + } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs index e07e8dd7e3..46bb8df993 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs @@ -343,8 +343,10 @@ namespace MonoDevelop.Components.MainToolbar var runtimes = ToolbarView.RuntimeModel.Cast<RuntimeModel> ().ToList (); for (int iter = 0; iter < runtimes.Count; ++iter) { var item = runtimes [iter]; - if (!item.Enabled) - continue; + using (var model = item.GetMutableModel ()) { + if (!model.Enabled) + continue; + } var target = item.ExecutionTarget; if (target == null || !target.Enabled) @@ -762,8 +764,6 @@ namespace MonoDevelop.Components.MainToolbar public RuntimeModel (MainToolbarController controller, ExecutionTarget target) : this (controller) { ExecutionTarget = target; - Enabled = !(ExecutionTarget is ExecutionTargetGroup); - Visible = true; } public RuntimeModel (MainToolbarController controller, ExecutionTarget target, RuntimeModel parent) : this (controller, target) @@ -785,6 +785,7 @@ namespace MonoDevelop.Components.MainToolbar public IEnumerable<IRuntimeModel> Children { get { return children; } } + public bool Notable { get { return ExecutionTarget != null && ExecutionTarget.Notable; } } @@ -799,16 +800,6 @@ namespace MonoDevelop.Components.MainToolbar set; } - public bool Visible { - get; - private set; - } - - public bool Enabled { - get; - private set; - } - public bool IsSeparator { get { return Command == null && ExecutionTarget == null; } } @@ -818,43 +809,64 @@ namespace MonoDevelop.Components.MainToolbar set; } - public string DisplayString { - get { - if (Command != null) { - var ci = IdeApp.CommandService.GetCommandInfo (Command, new CommandTargetRoute (Controller.lastCommandTarget)); - Visible = ci.Visible; - Enabled = ci.Enabled; - return RemoveUnderline (ci.Text); - } + public bool NotifyActivated () + { + if (Command != null && IdeApp.CommandService.DispatchCommand (Command, CommandSource.ContextMenu)) + return true; + return false; + } - if (ExecutionTarget == null) - return ""; + public IRuntimeMutableModel GetMutableModel () + { + return Command != null ? new RuntimeMutableModel (Controller, Command) : new RuntimeMutableModel (ExecutionTarget, HasParent); + } + } + + class RuntimeMutableModel : IRuntimeMutableModel + { + public RuntimeMutableModel (MainToolbarController controller, object command) + { + var ci = IdeApp.CommandService.GetCommandInfo (command, new CommandTargetRoute (controller.lastCommandTarget)); + Visible = ci.Visible; + Enabled = ci.Enabled; + DisplayString = FullDisplayString = RemoveUnderline (ci.Text); + } - return !HasParent ? ExecutionTarget.FullName : ExecutionTarget.Name; + public RuntimeMutableModel (ExecutionTarget target, bool hasParent) + { + Enabled = !(target is ExecutionTargetGroup); + Visible = true; + if (target == null) + DisplayString = FullDisplayString = string.Empty; + else { + FullDisplayString = target.FullName; + DisplayString = !hasParent ? target.FullName : target.Name; } } - public string FullDisplayString { - get { - if (Command != null) { - var ci = IdeApp.CommandService.GetCommandInfo (Command, new CommandTargetRoute (Controller.lastCommandTarget)); - Visible = ci.Visible; - Enabled = ci.Enabled; - return RemoveUnderline (ci.Text); - } + // Marker so it won't be reused. + public void Dispose () + { + } - if (ExecutionTarget == null) - return ""; + public bool Visible { + get; + private set; + } - return ExecutionTarget.FullName; - } + public bool Enabled { + get; + private set; } - public bool NotifyActivated () - { - if (Command != null && IdeApp.CommandService.DispatchCommand (Command, CommandSource.ContextMenu)) - return true; - return false; + public string DisplayString { + get; + private set; + } + + public string FullDisplayString { + get; + private set; } static string RemoveUnderline (string s) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarModels.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarModels.cs index bdd0036f0d..eb814b067b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarModels.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarModels.cs @@ -51,30 +51,6 @@ namespace MonoDevelop.Components.MainToolbar IEnumerable<IRuntimeModel> Children { get; } /// <summary> - /// Gets the display string to be used inside a context menu. - /// </summary> - /// <value>The display string.</value> - string DisplayString { get; } - - /// <summary> - /// Gets the display string to be for selected items. - /// </summary> - /// <value>The full display string.</value> - string FullDisplayString { get; } - - /// <summary> - /// Gets whether the menu item is visible. - /// </summary> - /// <value><c>true</c> if visible; otherwise, <c>false</c>.</value> - bool Visible { get; } - - /// <summary> - /// Gets whether the menu item is enabled. - /// </summary> - /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value> - bool Enabled { get; } - - /// <summary> /// Gets whether the menu item is a separator. /// </summary> /// <value><c>true</c> if this instance is separator; otherwise, <c>false</c>.</value> @@ -100,6 +76,39 @@ namespace MonoDevelop.Components.MainToolbar /// </remarks> /// <value><c>true</c> if this instance has a parent; otherwise, <c>false</c>.</value> bool HasParent { get; } + + /// <summary> + /// Gets the runtime combo item model. + /// </summary> + /// <value>The runtime combo item.</value> + IRuntimeMutableModel GetMutableModel(); + } + + public interface IRuntimeMutableModel : IDisposable + { + /// <summary> + /// Gets the display string to be used inside a context menu. + /// </summary> + /// <value>The display string.</value> + string DisplayString { get; } + + /// <summary> + /// Gets the display string to be for selected items. + /// </summary> + /// <value>The full display string.</value> + string FullDisplayString { get; } + + /// <summary> + /// Gets whether the menu item is visible. + /// </summary> + /// <value><c>true</c> if visible; otherwise, <c>false</c>.</value> + bool Visible { get; } + + /// <summary> + /// Gets whether the menu item is enabled. + /// </summary> + /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value> + bool Enabled { get; } } public interface ISearchMenuModel |