From 641d1994a1d03b3034538e524f14d085c933ef49 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 5 Aug 2008 19:00:23 +0000 Subject: [PATCH] Add ToolBar. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0wpf@3298 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/ICSharpCode.SharpDevelop.csproj | 1 + .../Project/Src/Gui/Workbench/WpfWorkbench.cs | 28 ++--- .../Src/Gui/Workbench/WpfWorkbench.xaml | 22 ++++ .../ConditionalSeparator.cs | 44 +++++++ .../ICSharpCode.Core.Presentation.csproj | 6 + .../IStatusUpdate.cs | 17 +++ .../Menu/CoreMenuItem.cs | 59 ++++----- .../Menu/MenuCommand.cs | 69 +++++++++++ .../Menu/MenuService.cs | 16 ++- .../ToolBar/ToolBarButton.cs | 100 +++++++++++++++ .../ToolBar/ToolBarService.cs | 117 ++++++++++++++++++ .../ICSharpCode.SharpDevelop.Sda.csproj | 5 + .../Src/CallHelper.cs | 1 + 13 files changed, 431 insertions(+), 54 deletions(-) create mode 100644 src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml create mode 100644 src/Main/ICSharpCode.Core.Presentation/ConditionalSeparator.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/IStatusUpdate.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 80ef5694e7..4dd62c3ba6 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -795,6 +795,7 @@ ICSharpCode.SharpDevelop.Widgets True + \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index 49c6ab0620..b5443f0a1e 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.SharpDevelop.Gui /// /// Workbench implementation using WPF and AvalonDock. /// - sealed class WpfWorkbench : Window, IWorkbench + sealed partial class WpfWorkbench : Window, IWorkbench { const string mainMenuPath = "/SharpDevelop/Workbench/MainMenu"; const string viewContentPath = "/SharpDevelop/Workbench/Pads"; @@ -34,29 +34,29 @@ namespace ICSharpCode.SharpDevelop.Gui public ISynchronizeInvoke SynchronizingObject { get; set; } public Window MainWindow { get { return this; } } - DockPanel dockPanel; - Menu mainMenu; - ContentControl mainContent; + ToolBar[] toolBars; public WpfWorkbench() { - this.Title = "SharpDevelop (experimental WPF build)"; this.SynchronizingObject = new WpfSynchronizeInvoke(this.Dispatcher); this.MainWin32Window = this.GetWin32Window(); - this.WindowStartupLocation = WindowStartupLocation.Manual; + InitializeComponent(); } public void Initialize() { - this.Content = dockPanel = new DockPanel(); - mainMenu = new Menu() { - ItemsSource = MenuService.CreateMenuItems(this, mainMenuPath) - }; - DockPanel.SetDock(mainMenu, Dock.Top); - dockPanel.Children.Add(mainMenu); + mainMenu.ItemsSource = MenuService.CreateMenuItems(this, mainMenuPath); - mainContent = new ContentControl(); - dockPanel.Children.Add(mainContent); + toolBars = ToolBarService.CreateToolBars(this, "/SharpDevelop/Workbench/ToolBar"); + foreach (ToolBar tb in toolBars) { + DockPanel.SetDock(tb, Dock.Top); + dockPanel.Children.Insert(1, tb); + } + + MenuService.UpdateStatus(mainMenu.ItemsSource); + foreach (ToolBar tb in toolBars) { + ToolBarService.UpdateStatus(tb.ItemsSource); + } } public ICollection ViewContentCollection { diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml new file mode 100644 index 0000000000..b894428800 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Main/ICSharpCode.Core.Presentation/ConditionalSeparator.cs b/src/Main/ICSharpCode.Core.Presentation/ConditionalSeparator.cs new file mode 100644 index 0000000000..9bf65f80e8 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/ConditionalSeparator.cs @@ -0,0 +1,44 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows; +using System.Windows.Controls; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// A Separator that is invisible when it is excluded by a condition. + /// + sealed class ConditionalSeparator : Separator, IStatusUpdate + { + readonly Codon codon; + readonly object caller; + + public ConditionalSeparator(Codon codon, object caller, bool inToolbar) + { + this.codon = codon; + this.caller = caller; + + if (inToolbar) { + SetResourceReference(FrameworkElement.StyleProperty, ToolBar.SeparatorStyleKey); + } + } + + public void UpdateText() + { + } + + public void UpdateStatus() + { + if (codon.GetFailedAction(caller) == ConditionFailedAction.Exclude) + this.Visibility = Visibility.Collapsed; + else + this.Visibility = Visibility.Visible; + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj index 43d9280f4f..1e24f64a6d 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj +++ b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj @@ -59,11 +59,16 @@ Properties\GlobalAssemblyInfo.cs + + + + + @@ -72,5 +77,6 @@ False + \ No newline at end of file diff --git a/src/Main/ICSharpCode.Core.Presentation/IStatusUpdate.cs b/src/Main/ICSharpCode.Core.Presentation/IStatusUpdate.cs new file mode 100644 index 0000000000..41049c3470 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/IStatusUpdate.cs @@ -0,0 +1,17 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace ICSharpCode.Core.Presentation +{ + public interface IStatusUpdate + { + void UpdateText(); + void UpdateStatus(); + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs index c33e3c8ce9..2d226e42d1 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs @@ -7,6 +7,7 @@ using System; using System.Collections; +using System.Windows; using System.Windows.Controls; namespace ICSharpCode.Core.Presentation @@ -14,7 +15,7 @@ namespace ICSharpCode.Core.Presentation /// /// A menu item representing an AddIn-Tree element. /// - class CoreMenuItem : MenuItem + class CoreMenuItem : MenuItem, IStatusUpdate { protected readonly Codon codon; protected readonly object caller; @@ -27,9 +28,14 @@ namespace ICSharpCode.Core.Presentation if (codon.Properties.Contains("shortcut")) { InputGestureText = codon.Properties["shortcut"]; } - + this.SubmenuOpened += CoreMenuItem_SubmenuOpened; UpdateText(); } + + void CoreMenuItem_SubmenuOpened(object sender, RoutedEventArgs e) + { + MenuService.UpdateStatus(this.ItemsSource); + } public void UpdateText() { @@ -37,46 +43,25 @@ namespace ICSharpCode.Core.Presentation Header = MenuService.ConvertLabel(StringParser.Parse(codon.Properties["label"])); } } - } - - class MenuCommand : CoreMenuItem - { - ICommand menuCommand; - - public MenuCommand(Codon codon, object caller, bool createCommand) : base(codon, caller) - { - if (createCommand) { - CreateCommand(); - } - } - void CreateCommand() + public virtual void UpdateStatus() { - try { - string link = codon.Properties["link"]; - if (link != null && link.Length > 0) { - if (MenuService.LinkCommandCreator == null) - throw new NotSupportedException("MenuCommand.LinkCommandCreator is not set, cannot create LinkCommands."); - menuCommand = MenuService.LinkCommandCreator(codon.Properties["link"]); - } else { - menuCommand = (ICommand)codon.AddIn.CreateObject(codon.Properties["class"]); - } - if (menuCommand != null) { - menuCommand.Owner = caller; - } - } catch (Exception e) { - MessageService.ShowError(e, "Can't create menu command : " + codon.Id); + this.IsEnabled = this.IsEnabledCore; + if (this.IsEnabled) { + this.Visibility = Visibility.Visible; + } else { + if (codon.GetFailedAction(caller) == ConditionFailedAction.Exclude) + this.Visibility = Visibility.Collapsed; + else + this.Visibility = Visibility.Visible; } } - protected override void OnClick() - { - base.OnClick(); - if (menuCommand == null) { - CreateCommand(); - } - if (menuCommand != null) { - menuCommand.Run(); + protected override bool IsEnabledCore { + get { + ConditionFailedAction failedAction = codon.GetFailedAction(caller); + bool isEnabled = failedAction == ConditionFailedAction.Nothing; + return isEnabled; } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs new file mode 100644 index 0000000000..f6ad1443e8 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs @@ -0,0 +1,69 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Windows; +using System.Windows.Controls; + +namespace ICSharpCode.Core.Presentation +{ + class MenuCommand : CoreMenuItem + { + ICommand menuCommand; + + public MenuCommand(Codon codon, object caller, bool createCommand) : base(codon, caller) + { + if (createCommand) { + CreateCommand(); + } + } + + protected override bool IsEnabledCore { + get { + if (!base.IsEnabledCore) + return false; + + if (menuCommand != null && menuCommand is IMenuCommand) { + return ((IMenuCommand)menuCommand).IsEnabled; + } else { + return true; + } + } + } + + void CreateCommand() + { + try { + string link = codon.Properties["link"]; + if (link != null && link.Length > 0) { + if (MenuService.LinkCommandCreator == null) + throw new NotSupportedException("MenuCommand.LinkCommandCreator is not set, cannot create LinkCommands."); + menuCommand = MenuService.LinkCommandCreator(codon.Properties["link"]); + } else { + menuCommand = (ICommand)codon.AddIn.CreateObject(codon.Properties["class"]); + } + if (menuCommand != null) { + menuCommand.Owner = caller; + } + } catch (Exception e) { + MessageService.ShowError(e, "Can't create menu command : " + codon.Id); + } + } + + protected override void OnClick() + { + base.OnClick(); + if (menuCommand == null) { + CreateCommand(); + } + if (menuCommand != null && IsEnabledCore) { + menuCommand.Run(); + } + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs index a175aae105..2c7ce9434a 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs @@ -17,12 +17,23 @@ namespace ICSharpCode.Core.Presentation /// public static class MenuService { + public static void UpdateStatus(IEnumerable menuItems) + { + if (menuItems == null) + return; + foreach (object o in menuItems) { + IStatusUpdate cmi = o as IStatusUpdate; + if (cmi != null) + cmi.UpdateStatus(); + } + } + public static IList CreateMenuItems(object owner, string addInTreePath) { return CreateMenuItems(AddInTree.BuildItems(addInTreePath, owner, false)); } - static IList CreateMenuItems(IEnumerable descriptors) + internal static IList CreateMenuItems(IEnumerable descriptors) { ArrayList result = new ArrayList(); foreach (MenuItemDescriptor descriptor in descriptors) { @@ -45,8 +56,7 @@ namespace ICSharpCode.Core.Presentation switch (type) { case "Separator": - return new Separator(); - //return new MenuSeparator(codon, descriptor.Caller); + return new ConditionalSeparator(codon, descriptor.Caller, false); case "CheckBox": return "CheckBox"; //return new MenuCheckBox(codon, descriptor.Caller); diff --git a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs new file mode 100644 index 0000000000..5c48bd415a --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs @@ -0,0 +1,100 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows; +using System.Windows.Controls; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// + /// + sealed class ToolBarButton : Button, IStatusUpdate + { + readonly Codon codon; + readonly object caller; + ICommand menuCommand; + + public ToolBarButton(Codon codon, object caller, bool createCommand) + { + ToolTipService.SetShowOnDisabled(this, true); + + this.codon = codon; + this.caller = caller; + + if (createCommand) { + CreateCommand(); + } + + if (codon.Properties.Contains("icon")) { + Image image = new Image { + Source = PresentationResourceService.GetBitmapSource(StringParser.Parse(codon.Properties["icon"])), + Height = 16 + }; + image.SetResourceReference(StyleProperty, ToolBarService.ImageStyleKey); + this.Content = image; + } + UpdateText(); + + SetResourceReference(FrameworkElement.StyleProperty, ToolBar.ButtonStyleKey); + } + + protected override void OnClick() + { + base.OnClick(); + if (menuCommand == null) { + CreateCommand(); + } + if (menuCommand != null) { + menuCommand.Run(); + } + } + + void CreateCommand() + { + menuCommand = (ICommand)codon.AddIn.CreateObject(codon.Properties["class"]); + if (menuCommand != null) { + menuCommand.Owner = caller; + } + } + + public void UpdateText() + { + if (codon.Properties.Contains("label")){ + this.Content = StringParser.Parse(codon.Properties["label"]); + } + if (codon.Properties.Contains("tooltip")) { + this.ToolTip = StringParser.Parse(codon.Properties["tooltip"]); + } + } + + public void UpdateStatus() + { + this.IsEnabled = this.IsEnabledCore; + if (this.IsEnabled) { + this.Visibility = Visibility.Visible; + } else { + if (codon.GetFailedAction(caller) == ConditionFailedAction.Exclude) + this.Visibility = Visibility.Collapsed; + else + this.Visibility = Visibility.Visible; + } + } + + protected override bool IsEnabledCore { + get { + ConditionFailedAction failedAction = codon.GetFailedAction(caller); + bool isEnabled = failedAction == ConditionFailedAction.Nothing; + if (isEnabled && menuCommand != null && menuCommand is IMenuCommand) { + isEnabled = ((IMenuCommand)menuCommand).IsEnabled; + } + return isEnabled; + } + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs new file mode 100644 index 0000000000..82b4c5231b --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs @@ -0,0 +1,117 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows.Controls; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// Creates WPF toolbars from the AddIn Tree. + /// + public static class ToolBarService + { + /// + /// Style key used for toolbar images. + /// + public static readonly object ImageStyleKey = new object(); + + public static void UpdateStatus(IEnumerable toolBarItems) + { + MenuService.UpdateStatus(toolBarItems); + } + + public static IList CreateToolBarItems(object owner, string addInTreePath) + { + return CreateToolBarItems(AddInTree.BuildItems(addInTreePath, owner, false)); + } + + static IList CreateToolBarItems(IEnumerable descriptors) + { + ArrayList result = new ArrayList(); + foreach (ToolbarItemDescriptor descriptor in descriptors) { + object item = CreateToolBarItemFromDescriptor(descriptor); + if (item is IMenuItemBuilder) { + IMenuItemBuilder submenuBuilder = (IMenuItemBuilder)item; + result.AddRange(submenuBuilder.BuildItems(descriptor.Codon, descriptor.Caller)); + } else { + result.Add(item); + } + } + return result; + } + + static object CreateToolBarItemFromDescriptor(ToolbarItemDescriptor descriptor) + { + Codon codon = descriptor.Codon; + object caller = descriptor.Caller; + string type = codon.Properties.Contains("type") ? codon.Properties["type"] : "Item"; + + bool createCommand = codon.Properties["loadclasslazy"] == "false"; + + switch (type) { + case "Separator": + return new ConditionalSeparator(codon, caller, true); + case "CheckBox": + return "CheckBox"; + //return new ToolBarCheckBox(codon, caller); + case "Item": + return new ToolBarButton(codon, caller, createCommand); + case "ComboBox": + return "ComboBox"; + //return new ToolBarComboBox(codon, caller); + case "TextBox": + return "TextBox"; + //return new ToolBarTextBox(codon, caller); + case "Label": + return "Label"; + //return new ToolBarLabel(codon, caller); + case "DropDownButton": + return "DropDownButton"; + //return new ToolBarDropDownButton(codon, caller, MenuService.CreateMenuItems(descriptor.SubItems)); + case "SplitButton": + return "SplitButton"; + //return new ToolBarSplitButton(codon, caller, MenuService.CreateMenuItems(descriptor.SubItems)); + case "Builder": + return codon.AddIn.CreateObject(codon.Properties["class"]); + default: + throw new System.NotSupportedException("unsupported menu item type : " + type); + } + } + + static ToolBar CreateToolBar(object owner, AddInTreeNode treeNode) + { + ToolBar tb = new ToolBar(); + tb.ItemsSource = CreateToolBarItems(treeNode.BuildChildItems(owner)); + UpdateStatus(tb.ItemsSource); // setting Visible is only possible after the items have been added + //new LanguageChangeWatcher(toolStrip); + return tb; + } + + public static ToolBar CreateToolBar(object owner, string addInTreePath) + { + return CreateToolBar(owner, AddInTree.GetTreeNode(addInTreePath)); + } + + public static ToolBar[] CreateToolBars(object owner, string addInTreePath) + { + AddInTreeNode treeNode; + try { + treeNode = AddInTree.GetTreeNode(addInTreePath); + } catch (TreePathNotFoundException) { + return null; + } + List toolBars = new List(); + foreach (AddInTreeNode childNode in treeNode.ChildNodes.Values) { + toolBars.Add(CreateToolBar(owner, childNode)); + } + return toolBars.ToArray(); + } + } +} diff --git a/src/Main/ICSharpCode.SharpDevelop.Sda/ICSharpCode.SharpDevelop.Sda.csproj b/src/Main/ICSharpCode.SharpDevelop.Sda/ICSharpCode.SharpDevelop.Sda.csproj index 4b6d7a2712..688989b111 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Sda/ICSharpCode.SharpDevelop.Sda.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.Sda/ICSharpCode.SharpDevelop.Sda.csproj @@ -97,6 +97,11 @@ Always + + {7E4A7172-7FF5-48D0-B719-7CD959DD1AC9} + ICSharpCode.Core.Presentation + False + {857CA1A3-FC88-4BE0-AB6A-D1EE772AB288} ICSharpCode.Core.WinForms diff --git a/src/Main/ICSharpCode.SharpDevelop.Sda/Src/CallHelper.cs b/src/Main/ICSharpCode.SharpDevelop.Sda/Src/CallHelper.cs index 154c6f18ef..9e7dbc94e8 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Sda/Src/CallHelper.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Sda/Src/CallHelper.cs @@ -67,6 +67,7 @@ namespace ICSharpCode.SharpDevelop.Sda ResourceService.RegisterNeutralImages(new ResourceManager("Resources.BitmapResources", exe)); MenuCommand.LinkCommandCreator = delegate(string link) { return new LinkCommand(link); }; + Core.Presentation.MenuService.LinkCommandCreator = MenuCommand.LinkCommandCreator; StringParser.RegisterStringTagProvider(new SharpDevelopStringTagProvider()); LoggingService.Info("Looking for AddIns...");