Skip to content

Commit dd49ed9

Browse files
committed
refactored RubberduckCommandBar to use CommandMenuItems. Still doesn't unload correctly.
1 parent 22366a6 commit dd49ed9

18 files changed

+426
-234
lines changed

RetailCoder.VBE/App.cs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System;
1212
using System.Globalization;
1313
using System.Windows.Forms;
14+
using Rubberduck.UI.Command.MenuItems.CommandBars;
1415
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1516

1617
namespace Rubberduck
@@ -64,7 +65,7 @@ private void State_StatusMessageUpdate(object sender, RubberduckStatusMessageEve
6465
message = RubberduckUI.ParserState_LoadingReference;
6566
}
6667

67-
_stateBar.SetStatusText(message);
68+
_stateBar.SetStatusLabelCaption(message);
6869
}
6970

7071
private void _hooks_MessageReceived(object sender, HookEventArgs e)
@@ -83,20 +84,70 @@ private void RefreshSelection()
8384
if (!pane.IsWrappingNullReference)
8485
{
8586
selectedDeclaration = _parser.State.FindSelectedDeclaration(pane);
86-
_stateBar.SetSelectionText(selectedDeclaration);
87+
_stateBar.SetContextSelectionCaption(GetSelectionText(selectedDeclaration));
8788
}
8889

8990
var currentStatus = _parser.State.Status;
9091
if (ShouldEvaluateCanExecute(selectedDeclaration, currentStatus))
9192
{
9293
_appMenus.EvaluateCanExecute(_parser.State);
94+
_stateBar.EvaluateCanExecute(_parser.State);
9395
}
9496

9597
_lastStatus = currentStatus;
9698
_lastSelectedDeclaration = selectedDeclaration;
9799
}
98100
}
99101

102+
private string GetSelectionText(Declaration declaration)
103+
{
104+
if (declaration == null && _vbe.ActiveCodePane != null)
105+
{
106+
var selection = _vbe.ActiveCodePane.GetQualifiedSelection();
107+
if (selection.HasValue)
108+
{
109+
return selection.Value.ToString();
110+
}
111+
}
112+
else if (declaration == null && _vbe.ActiveCodePane == null)
113+
{
114+
return string.Empty;
115+
}
116+
else if (declaration != null && !declaration.IsBuiltIn && declaration.DeclarationType != DeclarationType.ClassModule && declaration.DeclarationType != DeclarationType.ProceduralModule)
117+
{
118+
var typeName = declaration.HasTypeHint
119+
? Declaration.TypeHintToTypeName[declaration.TypeHint]
120+
: declaration.AsTypeName;
121+
122+
return string.Format("{0}|{1}: {2} ({3}{4})",
123+
declaration.QualifiedSelection.Selection,
124+
declaration.QualifiedName.QualifiedModuleName,
125+
declaration.IdentifierName,
126+
RubberduckUI.ResourceManager.GetString("DeclarationType_" + declaration.DeclarationType, UI.Settings.Settings.Culture),
127+
string.IsNullOrEmpty(declaration.AsTypeName) ? string.Empty : ": " + typeName);
128+
}
129+
else if (declaration != null)
130+
{
131+
// todo: confirm this is what we want, and then refator
132+
var selection = _vbe.ActiveCodePane.GetQualifiedSelection();
133+
if (selection.HasValue)
134+
{
135+
var typeName = declaration.HasTypeHint
136+
? Declaration.TypeHintToTypeName[declaration.TypeHint]
137+
: declaration.AsTypeName;
138+
139+
return string.Format("{0}|{1}: {2} ({3}{4})",
140+
selection.Value.Selection,
141+
declaration.QualifiedName.QualifiedModuleName,
142+
declaration.IdentifierName,
143+
RubberduckUI.ResourceManager.GetString("DeclarationType_" + declaration.DeclarationType, UI.Settings.Settings.Culture),
144+
string.IsNullOrEmpty(declaration.AsTypeName) ? string.Empty : ": " + typeName);
145+
}
146+
}
147+
148+
return string.Empty;
149+
}
150+
100151
private bool ShouldEvaluateCanExecute(Declaration selectedDeclaration, ParserState currentStatus)
101152
{
102153
return _lastStatus != currentStatus ||
@@ -110,6 +161,7 @@ private void _configService_SettingsChanged(object sender, ConfigurationChangedE
110161
_hooks.HookHotkeys();
111162
// also updates the ShortcutKey text
112163
_appMenus.Localize();
164+
_stateBar.Localize();
113165
UpdateLoggingLevel();
114166

115167
if (e.LanguageChanged)
@@ -146,7 +198,7 @@ public void Startup()
146198
_stateBar.Initialize();
147199
_hooks.HookHotkeys(); // need to hook hotkeys before we localize menus, to correctly display ShortcutTexts
148200
_appMenus.Localize();
149-
_stateBar.SetStatusText(RubberduckUI.ParserState_Pending);
201+
_stateBar.SetStatusLabelCaption(ParserState.Pending);
150202
UpdateLoggingLevel();
151203
}
152204

@@ -166,7 +218,8 @@ private void Parser_StateChanged(object sender, EventArgs e)
166218
{
167219
Logger.Debug("App handles StateChanged ({0}), evaluating menu states...", _parser.State.Status);
168220
_appMenus.EvaluateCanExecute(_parser.State);
169-
_stateBar.SetSelectionText();
221+
_stateBar.EvaluateCanExecute(_parser.State);
222+
_stateBar.SetStatusLabelCaption(_parser.State.Status);
170223
}
171224

172225
private void LoadConfig()
@@ -179,6 +232,7 @@ private void LoadConfig()
179232
{
180233
CultureManager.UICulture = CultureInfo.GetCultureInfo(_config.UserSettings.GeneralSettings.Language.Code);
181234
_appMenus.Localize();
235+
_stateBar.Localize();
182236
}
183237
catch (CultureNotFoundException exception)
184238
{

RetailCoder.VBE/Root/RubberduckModule.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
using Ninject.Extensions.NamedScope;
3131
using Rubberduck.Parsing.Symbols;
3232
using Rubberduck.UI.CodeExplorer.Commands;
33+
using Rubberduck.UI.Command.MenuItems.CommandBars;
3334
using Rubberduck.VBEditor.Application;
3435
using Rubberduck.VBEditor.Events;
3536
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
3637
using Rubberduck.VBEditor.SafeComWrappers.Office.Core.Abstract;
38+
using ReparseCommandMenuItem = Rubberduck.UI.Command.MenuItems.CommandBars.ReparseCommandMenuItem;
3739

3840
namespace Rubberduck.Root
3941
{
@@ -63,7 +65,6 @@ public override void Load()
6365
Bind<App>().ToSelf().InSingletonScope();
6466
Bind<RubberduckParserState>().ToSelf().InSingletonScope();
6567
Bind<GitProvider>().ToSelf().InSingletonScope();
66-
Bind<RubberduckCommandBar>().ToSelf().InSingletonScope();
6768
Bind<TestExplorerModel>().ToSelf().InSingletonScope();
6869
Bind<IOperatingSystem>().To<WindowsOperatingSystem>().InSingletonScope();
6970

@@ -134,6 +135,7 @@ public override void Load()
134135

135136
BindDockableToolwindows();
136137
BindCommandsToCodeExplorer();
138+
ConfigureRubberduckCommandBar();
137139
ConfigureRubberduckMenu();
138140
ConfigureCodePaneContextMenu();
139141
ConfigureFormDesignerContextMenu();
@@ -247,6 +249,17 @@ private void BindCodeInspectionTypes()
247249
}
248250
}
249251

252+
private void ConfigureRubberduckCommandBar()
253+
{
254+
var commandBars = _vbe.CommandBars;
255+
var items = GetRubberduckCommandBarItems();
256+
Bind<RubberduckCommandBar>()
257+
.ToSelf()
258+
.InCallScope()
259+
.WithPropertyValue("Parent", commandBars)
260+
.WithConstructorArgument("items", items);
261+
}
262+
250263
private void ConfigureRubberduckMenu()
251264
{
252265
const int windowMenuId = 30009;
@@ -389,6 +402,16 @@ private void BindCustomDeclarationLoadersToParser()
389402
}
390403
}
391404

405+
private IEnumerable<ICommandMenuItem> GetRubberduckCommandBarItems()
406+
{
407+
return new ICommandMenuItem[]
408+
{
409+
KernelInstance.Get<ReparseCommandMenuItem>(),
410+
KernelInstance.Get<ShowParserErrorsCommandMenuItem>(),
411+
KernelInstance.Get<ContextSelectionLabelMenuItem>()
412+
};
413+
}
414+
392415
private IEnumerable<IMenuItem> GetRubberduckMenuItems()
393416
{
394417
return new[]

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,14 @@
446446
<Compile Include="UI\CodeExplorer\Commands\AddClassModuleCommand.cs" />
447447
<Compile Include="UI\CodeExplorer\Commands\AddStdModuleCommand.cs" />
448448
<Compile Include="UI\CodeExplorer\Commands\AddTestModuleCommand.cs" />
449+
<Compile Include="UI\Command\MenuItems\CommandBars\AppCommandBarBase.cs" />
450+
<Compile Include="UI\Command\MenuItems\CommandBars\ContextSelectionLabelMenuItem.cs" />
451+
<Compile Include="UI\Command\MenuItems\CommandBars\ReparseCommandMenuItem.cs" />
452+
<Compile Include="UI\Command\MenuItems\CommandBars\RubberduckCommandBar.cs" />
453+
<Compile Include="UI\Command\MenuItems\CommandBars\ShowParserErrorsCommandMenuItem.cs" />
454+
<Compile Include="UI\Command\MenuItems\ParentMenus\CommandBarButtonFactory.cs" />
455+
<Compile Include="UI\Command\MenuItems\ParentMenus\CommandBarPopupFactory.cs" />
456+
<Compile Include="UI\Command\MenuItems\CommandBars\IAppCommandBar.cs" />
449457
<Compile Include="UI\Command\MenuItems\RegexAssistantCommand.cs" />
450458
<Compile Include="UI\Command\MenuItems\RegexAssistantCommandMenuItem.cs" />
451459
<Compile Include="UI\Command\MenuItems\ParentMenus\ToolsParentMenu.cs" />
@@ -635,7 +643,6 @@
635643
<Compile Include="UI\Command\FindAllReferencesCommand.cs" />
636644
<Compile Include="UI\Command\MenuItems\ParentMenus\NavigateParentMenu.cs" />
637645
<Compile Include="UI\Command\MenuItems\ParentMenus\SmartIndenterParentMenu.cs" />
638-
<Compile Include="UI\Command\MenuItems\RubberduckCommandBar.cs" />
639646
<Compile Include="UI\Command\MenuItems\RefactorEncapsulateFieldCommandMenuItem.cs" />
640647
<Compile Include="UI\Command\MenuItems\RefactorImplementInterfaceCommandMenuItem.cs" />
641648
<Compile Include="UI\Command\MenuItems\RefactorExtractInterfaceCommandMenuItem.cs" />

RetailCoder.VBE/UI/Command/IMenuItem.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Drawing;
3-
using System.Windows.Input;
43
using Rubberduck.Parsing.VBA;
4+
using Rubberduck.VBEditor.SafeComWrappers.MSForms;
55

66
namespace Rubberduck.UI.Command
77
{
@@ -16,6 +16,8 @@ public interface IMenuItem
1616
public interface ICommandMenuItem : IMenuItem
1717
{
1818
bool EvaluateCanExecute(RubberduckParserState state);
19+
bool HiddenWhenDisabled { get; }
20+
ButtonStyle ButtonStyle { get; }
1921
CommandBase Command { get; }
2022
Image Image { get; }
2123
Image Mask { get; }
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using NLog;
4+
using Rubberduck.Parsing.VBA;
5+
using Rubberduck.UI.Command.MenuItems.ParentMenus;
6+
using Rubberduck.VBEditor.SafeComWrappers.Office.Core;
7+
using Rubberduck.VBEditor.SafeComWrappers.Office.Core.Abstract;
8+
9+
namespace Rubberduck.UI.Command.MenuItems.CommandBars
10+
{
11+
public abstract class AppCommandBarBase : IAppCommandBar
12+
{
13+
private readonly string _name;
14+
private readonly CommandBarPosition _position;
15+
private readonly IDictionary<ICommandMenuItem, ICommandBarControl> _items;
16+
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
17+
18+
protected AppCommandBarBase(string name, CommandBarPosition position, IEnumerable<ICommandMenuItem> items)
19+
{
20+
_name = name;
21+
_position = position;
22+
_items = items.ToDictionary(item => item, item => null as ICommandBarControl);
23+
}
24+
25+
protected ICommandMenuItem FindChildByTag(string tag)
26+
{
27+
var child = _items.FirstOrDefault(kvp => kvp.Value.Tag == tag);
28+
return Equals(child, default(KeyValuePair<ICommandMenuItem, ICommandBarControl>))
29+
? null
30+
: child.Key;
31+
}
32+
33+
public void Localize()
34+
{
35+
if (Item == null)
36+
{
37+
return;
38+
}
39+
40+
foreach (var kvp in _items)
41+
{
42+
var item = kvp;
43+
UiDispatcher.Invoke(() => item.Value.Caption = item.Key.Caption.Invoke());
44+
}
45+
}
46+
47+
public void Initialize()
48+
{
49+
if (Parent == null)
50+
{
51+
return;
52+
}
53+
54+
Item = Parent.Add(_name, _position);
55+
Item.IsVisible = true;
56+
foreach (var item in _items.Keys.OrderBy(item => item.DisplayOrder))
57+
{
58+
_items[item] = InitializeChildControl(item);
59+
}
60+
}
61+
62+
private ICommandBarControl InitializeChildControl(ICommandMenuItem item)
63+
{
64+
if (item == null)
65+
{
66+
return null;
67+
}
68+
69+
var child = CommandBarButtonFactory.Create(Item.Controls);
70+
child.Style = item.ButtonStyle;
71+
child.Picture = item.Image;
72+
child.Mask = item.Mask;
73+
child.ApplyIcon();
74+
75+
child.BeginsGroup = item.BeginGroup;
76+
child.Tag = item.GetType().FullName;
77+
child.Caption = item.Caption.Invoke();
78+
79+
if (item.Command != null)
80+
{
81+
child.Click += child_Click;
82+
((CommandBarButton)child).HandleEvents();
83+
}
84+
return child;
85+
}
86+
87+
public void EvaluateCanExecute(RubberduckParserState state)
88+
{
89+
foreach (var kvp in _items)
90+
{
91+
var commandItem = kvp.Key;
92+
if (commandItem != null && kvp.Value != null)
93+
{
94+
var canExecute = commandItem.EvaluateCanExecute(state);
95+
kvp.Value.IsEnabled = canExecute;
96+
if (commandItem.HiddenWhenDisabled)
97+
{
98+
kvp.Value.IsVisible = canExecute;
99+
}
100+
}
101+
}
102+
}
103+
104+
public ICommandBars Parent { get; set; }
105+
public ICommandBar Item { get; private set; }
106+
public void RemoveChildren()
107+
{
108+
foreach (var child in _items.Values.Select(item => item as CommandBarButton).Where(child => child != null))
109+
{
110+
child.Click -= child_Click;
111+
child.Delete();
112+
child.Release(true);
113+
}
114+
}
115+
116+
// note: HAAAAACK!!!
117+
private static int _lastHashCode;
118+
119+
private void child_Click(object sender, CommandBarButtonClickEventArgs e)
120+
{
121+
var item = _items.Select(kvp => kvp.Key).SingleOrDefault(menu => menu.GetType().FullName == e.Control.Tag);
122+
if (item == null || e.Control.Target.GetHashCode() == _lastHashCode)
123+
{
124+
return;
125+
}
126+
127+
// without this hack, handler runs once for each menu item that's hooked up to the command.
128+
// hash code is different on every frakkin' click. go figure. I've had it, this is the fix.
129+
_lastHashCode = e.Control.Target.GetHashCode();
130+
131+
Logger.Debug("({0}) Executing click handler for commandbar item '{1}', hash code {2}", GetHashCode(), e.Control.Caption, e.Control.Target.GetHashCode());
132+
item.Command.Execute(null);
133+
}
134+
}
135+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using Rubberduck.Parsing.VBA;
3+
4+
namespace Rubberduck.UI.Command.MenuItems.CommandBars
5+
{
6+
public class ContextSelectionLabelMenuItem : CommandMenuItemBase
7+
{
8+
public ContextSelectionLabelMenuItem()
9+
: base(null)
10+
{
11+
_caption = string.Empty;
12+
}
13+
14+
private string _caption;
15+
public void SetCaption(string caption)
16+
{
17+
_caption = caption;
18+
}
19+
20+
public override bool EvaluateCanExecute(RubberduckParserState state)
21+
{
22+
return false;
23+
}
24+
25+
public override Func<string> Caption { get { return () => _caption; } }
26+
public override string Key { get { return string.Empty; } }
27+
public override bool BeginGroup { get { return true; } }
28+
public override int DisplayOrder { get { return (int)RubberduckCommandBarItemDisplayOrder.ContextStatus; } }
29+
}
30+
}

0 commit comments

Comments
 (0)