diff options
author | Dominique Louis <savagesoftware@gmail.com> | 2018-09-01 17:37:54 +0300 |
---|---|---|
committer | Dominique Louis <savagesoftware@gmail.com> | 2018-10-05 18:47:49 +0300 |
commit | 78168fadcb3f920e53f5ebdd2ac868ef1cea13b7 (patch) | |
tree | 7a2a03b47bf6b393e3435f61b652edd454edcca6 | |
parent | cb3324c1ed09ce873b82607c184176651745b736 (diff) |
[Mac] Inital ObjectName implementation.
7 files changed, 254 insertions, 77 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/PanelHeaderEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/PanelHeaderEditorControl.cs new file mode 100644 index 0000000..aaa4ce3 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/PanelHeaderEditorControl.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using System.ComponentModel; +using AppKit; +using Xamarin.PropertyEditing.Mac.Resources; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class PanelHeaderLabelControl : NSView + { + public const string PanelHeaderLabelIdentifierString = "PanelHeaderLabelIdentifier"; + public PanelHeaderLabelControl () + { + Identifier = PanelHeaderLabelIdentifierString; + + var propertyObjectNameLabel = new UnfocusableTextField { + Alignment = NSTextAlignment.Right, + StringValue = Properties.Resources.Name + ":", + TranslatesAutoresizingMaskIntoConstraints = false, + }; + AddSubview (propertyObjectNameLabel); + + this.DoConstraints (new NSLayoutConstraint[] { + propertyObjectNameLabel.ConstraintTo(this, (ol, c) => ol.Top == c.Top), + propertyObjectNameLabel.ConstraintTo(this, (ol, c) => ol.Left == c.Left + 182), + propertyObjectNameLabel.ConstraintTo(this, (ol, c) => ol.Width == 40), + propertyObjectNameLabel.ConstraintTo(this, (ol, c) => ol.Height == PropertyEditorControl.DefaultControlHeight), + }); + } + } + + internal class PanelHeaderEditorControl : PropertyEditorControl + { + private NSTextField propertyObjectName; + private PanelViewModel viewModel; + + public PanelHeaderEditorControl (PanelViewModel viewModel) + { + if (viewModel == null) + throw new ArgumentNullException (nameof (viewModel)); + + this.viewModel = viewModel; + this.viewModel.PropertyChanged += ViewModel_PropertyChanged; + + NSControlSize controlSize = NSControlSize.Small; + TranslatesAutoresizingMaskIntoConstraints = false; + + this.propertyObjectName = new NSTextField { + ControlSize = controlSize, + Font = NSFont.FromFontName (DefaultFontName, DefaultFontSize), + PlaceholderString = LocalizationResources.ObjectNamePlaceholder, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.propertyObjectName.Activated += PropertyObjectName_Activated; + + AddSubview (this.propertyObjectName); + + this.DoConstraints (new NSLayoutConstraint[] { + this.propertyObjectName.ConstraintTo(this, (on, c) => on.Top == c.Top + 2), + this.propertyObjectName.ConstraintTo(this, (on, c) => on.Left == c.Left + 4), + this.propertyObjectName.ConstraintTo(this, (on, c) => on.Width == c.Width - 34), + this.propertyObjectName.ConstraintTo(this, (on, c) => on.Height == DefaultControlHeight - 3), + }); + + // We won't enable or show the PropertyButton for the header + this.PropertyButton.Enabled = false; + this.PropertyButton.Hidden = true; + + UpdateValue (); + } + + void PropertyObjectName_Activated (object sender, EventArgs e) + { + this.viewModel.ObjectName = this.propertyObjectName.StringValue; + } + + public override NSView FirstKeyView => this.propertyObjectName; + + public override NSView LastKeyView => this.propertyObjectName; + + protected override void HandleErrorsChanged (object sender, DataErrorsChangedEventArgs e) + { + UpdateErrorsDisplayed (viewModel.GetErrors (viewModel.GetType ().Name)); + } + + protected override void SetEnabled () + { + this.propertyObjectName.Editable = !this.viewModel.IsObjectNameReadOnly; + } + + protected override void UpdateAccessibilityValues () + { + this.propertyObjectName.AccessibilityTitle = string.Format (LocalizationResources.AccessibilityObjectName, nameof (viewModel.ObjectName)); + } + + protected override void UpdateErrorsDisplayed (IEnumerable errors) + { + if (this.viewModel.HasErrors) { + SetErrors (errors); + } else { + SetErrors (null); + SetEnabled (); + } + } + + protected override void UpdateValue () + { + if (this.propertyObjectName != null) { + this.propertyObjectName.StringValue = this.viewModel.ObjectName ?? string.Empty; + this.propertyObjectName.Editable = !this.viewModel.IsObjectNameReadOnly; + } + } + + void ViewModel_PropertyChanged (object sender, PropertyChangedEventArgs e) + { + if ( e.PropertyName == nameof (PanelViewModel.ObjectName)) { + UpdateValue (); + } + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs b/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs index a9d1ae7..8d21189 100644 --- a/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs +++ b/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs @@ -10,7 +10,7 @@ using System.ComponentModel; namespace Xamarin.PropertyEditing.Mac { - public partial class PropertyEditorPanel : AppKit.NSView + public partial class PropertyEditorPanel : NSView { internal const string PropertyListColId = "PropertiesList"; internal const string PropertyEditorColId = "PropertyEditors"; @@ -143,7 +143,7 @@ namespace Xamarin.PropertyEditing.Mac AddSubview (this.propertyFilter); // If either the Filter Mode or PropertySearchFilter Change Filter the Data - this.propertyArrangeMode.SelectionChanged += OnArrageModeChanged; + this.propertyArrangeMode.SelectionChanged += OnArrangeModeChanged; this.propertyFilter.Changed += OnPropertyFilterChanged; this.propertyTable = new FirstResponderOutlineView { @@ -191,7 +191,7 @@ namespace Xamarin.PropertyEditing.Mac tableContainer.ConstraintTo(this, (t, c) => t.Top == c.Top + 30), tableContainer.ConstraintTo(this, (t, c) => t.Left == c.Left + 10), tableContainer.ConstraintTo(this, (t, c) => t.Width == c.Width - 20), - tableContainer.ConstraintTo(this, (t, c) => t.Height == c.Height - 40), + tableContainer.ConstraintTo(this, (t, c) => t.Height == c.Height - 37), }); ThemeManager.ThemeChanged += ThemeManager_ThemeChanged; @@ -218,7 +218,7 @@ namespace Xamarin.PropertyEditing.Mac ((PropertyTableDelegate)this.propertyTable.Delegate).UpdateExpansions (this.propertyTable); } - private void OnArrageModeChanged (object sender, EventArgs e) + private void OnArrangeModeChanged (object sender, EventArgs e) { Enum.TryParse<PropertyArrangeMode> (this.propertyArrangeMode.GetItemObject (this.propertyArrangeMode.SelectedIndex).ToString (), out PropertyArrangeMode filterMode); this.viewModel.ArrangeMode = filterMode; @@ -239,7 +239,7 @@ namespace Xamarin.PropertyEditing.Mac private void OnVmPropertyChanged (object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof (PanelViewModel.ArrangeMode)) - OnArrageModeChanged (sender, e); + OnArrangeModeChanged (sender, e); } class FirstResponderOutlineView : NSOutlineView @@ -260,4 +260,4 @@ namespace Xamarin.PropertyEditing.Mac } } } -} +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs b/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs index 5153562..24a14cb 100644 --- a/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs +++ b/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs @@ -10,6 +10,8 @@ namespace Xamarin.PropertyEditing.Mac internal class PropertyTableDataSource : NSOutlineViewDataSource { + bool Filtering => !string.IsNullOrEmpty (this.vm.FilterText); + internal PropertyTableDataSource (PanelViewModel panelVm) { if (panelVm == null) @@ -25,26 +27,36 @@ namespace Xamarin.PropertyEditing.Mac if (this.vm.ArrangedEditors.Count == 0) return 0; - if (this.vm.ArrangeMode == PropertyArrangeMode.Name) - return this.vm.ArrangedEditors[0].Count; + var childCount = 0; - if (item == null) - return this.vm.ArrangedEditors.Count; + if (this.vm.ArrangeMode == PropertyArrangeMode.Name) + childCount = Filtering ? this.vm.ArrangedEditors[0].Count : this.vm.ArrangedEditors[0].Count + 1; else { - return ((IGroupingList<string, EditorViewModel>)((NSObjectFacade)item).Target).Count; + if (item == null) + childCount = Filtering ? this.vm.ArrangedEditors.Count : this.vm.ArrangedEditors.Count + 1; + else + childCount = ((IGroupingList<string, EditorViewModel>)((NSObjectFacade)item).Target).Count; } + + return childCount; } public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) { object element; - if (this.vm.ArrangeMode == PropertyArrangeMode.Name) { - element = (this.vm.ArrangedEditors[0][(int)childIndex]); - } else { - if (item == null) - element = this.vm.ArrangedEditors[(int)childIndex]; + + // We only want the Header to appear at the top of both Category and Name Modes, which means item is null in both. + if (childIndex == 0 && item == null && !Filtering) + element = new PanelHeaderEditorControl (this.vm); + else { + if (this.vm.ArrangeMode == PropertyArrangeMode.Name) + element = Filtering ? this.vm.ArrangedEditors[0][(int)childIndex] : this.vm.ArrangedEditors[0][(int)childIndex - 1]; else { - element = ((IGroupingList<string, EditorViewModel>)((NSObjectFacade)item).Target)[(int)childIndex]; + if (item == null) + element = Filtering ? this.vm.ArrangedEditors[(int)childIndex] : this.vm.ArrangedEditors[(int)childIndex - 1]; + else { + element = ((IGroupingList<string, EditorViewModel>)((NSObjectFacade)item).Target)[(int)childIndex]; + } } } diff --git a/Xamarin.PropertyEditing.Mac/PropertyTableDelegate.cs b/Xamarin.PropertyEditing.Mac/PropertyTableDelegate.cs index 511b8fd..112ad6b 100644 --- a/Xamarin.PropertyEditing.Mac/PropertyTableDelegate.cs +++ b/Xamarin.PropertyEditing.Mac/PropertyTableDelegate.cs @@ -38,15 +38,9 @@ namespace Xamarin.PropertyEditing.Mac this.isExpanding = false; } - // the table is looking for this method, picks it up automagically - public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) + public override void DidAddRowView (NSOutlineView outlineView, NSTableRowView rowView, nint row) { - PropertyViewModel vm; - IGroupingList<string, EditorViewModel> group; - string cellIdentifier; - GetVMGroupCellItendifiterFromFacade (item, out vm, out group, out cellIdentifier); - - // Let's make the columns look pretty + // Let's make the columns look pretty by applying the Golden Ratio if (!goldenRatioApplied) { int middleColumnWidth = 5; nfloat rightColumnWidth = (outlineView.Frame.Width - middleColumnWidth) / 1.618f; @@ -55,48 +49,66 @@ namespace Xamarin.PropertyEditing.Mac outlineView.TableColumns ()[1].Width = rightColumnWidth; goldenRatioApplied = true; } + } + + // the table is looking for this method, picks it up automagically + public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) + { + PropertyViewModel vm; + IGroupingList<string, EditorViewModel> group; + string cellIdentifier; + GetVMGroupCellItendifiterFromFacade (item, out vm, out group, out cellIdentifier); + var isGrouping = group != null; // Setup view based on the column switch (tableColumn.Identifier) { case PropertyEditorPanel.PropertyListColId: - var view = (UnfocusableTextField)outlineView.MakeView (LabelIdentifier, this); - if (view == null) { - view = new UnfocusableTextField { - Identifier = LabelIdentifier, - Alignment = NSTextAlignment.Right, - }; + if (vm != null || isGrouping) { + + var view = (UnfocusableTextField)outlineView.MakeView (LabelIdentifier, this); + if (view == null) { + view = new UnfocusableTextField { + Identifier = LabelIdentifier, + Alignment = NSTextAlignment.Right, + }; + } + + view.StringValue = (isGrouping ? group.Key : vm.Property.Name + ":") ?? String.Empty; + + // Set tooltips only for truncated strings + var stringWidth = view.AttributedStringValue.Size.Width + 30; + if (stringWidth > tableColumn.Width) { + view.ToolTip = vm.Property.Name; + } + + return view; + } else { + var view = (PanelHeaderLabelControl)outlineView.MakeView (PanelHeaderLabelControl.PanelHeaderLabelIdentifierString, this); + if (view == null) { + view = new PanelHeaderLabelControl (); + } + return view; } - view.StringValue = ((group == null) ? vm.Property.Name + ":" : group.Key) ?? String.Empty; - - // Set tooltips only for truncated strings - var stringWidth = view.AttributedStringValue.Size.Width + 30; - if (stringWidth > tableColumn.Width) { - view.ToolTip = vm.Property.Name; - } - - return view; - case PropertyEditorPanel.PropertyEditorColId: - if (vm == null) - return null; - - if (this.firstCache.TryGetValue (cellIdentifier, out PropertyEditorControl editor)) { + if (cellIdentifier != null && this.firstCache.TryGetValue (cellIdentifier, out PropertyEditorControl editor)) { this.firstCache.Remove (cellIdentifier); } else - editor = GetEditor (cellIdentifier, vm, outlineView); + editor = GetEditor (cellIdentifier, vm, outlineView, isGrouping); // If still null we have no editor yet. if (editor == null) return new NSView (); - // we must reset these every time, as the view may have been reused - editor.TableRow = outlineView.RowForItem (item); - editor.ViewModel = vm; + if (vm != null) { + // we must reset these every time, as the view may have been reused + editor.TableRow = outlineView.RowForItem (item); + editor.ViewModel = vm; - // Force a row update due to new height, but only when we are non-default - if (editor.TriggerRowChange) - outlineView.NoteHeightOfRowsWithIndexesChanged (new NSIndexSet (editor.TableRow)); + // Force a row update due to new height, but only when we are non-default + if (editor.TriggerRowChange) + outlineView.NoteHeightOfRowsWithIndexesChanged (new NSIndexSet (editor.TableRow)); + } return editor; } @@ -138,11 +150,12 @@ namespace Xamarin.PropertyEditing.Mac string cellIdentifier; GetVMGroupCellItendifiterFromFacade (item, out vm, out group, out cellIdentifier); - if (group != null) + var isGrouping = group != null; + if (isGrouping) return 30; if (!this.registrations.TryGetValue (cellIdentifier, out EditorRegistration registration)) { - var view = GetEditor (cellIdentifier, vm, outlineView); + var view = GetEditor (cellIdentifier, vm, outlineView, isGrouping); if (view == null) { this.registrations[cellIdentifier] = registration = new EditorRegistration { RowSize = PropertyEditorControl.DefaultControlHeight @@ -181,7 +194,7 @@ namespace Xamarin.PropertyEditing.Mac } } - private const string LabelIdentifier = "label"; + public const string LabelIdentifier = "label"; private PropertyTableDataSource dataSource; private bool isExpanding; @@ -190,38 +203,45 @@ namespace Xamarin.PropertyEditing.Mac private readonly Dictionary<string, EditorRegistration> registrations = new Dictionary<string, EditorRegistration> (); private readonly Dictionary<string, PropertyEditorControl> firstCache = new Dictionary<string, PropertyEditorControl> (); - private PropertyEditorControl GetEditor (string identifier, EditorViewModel vm, NSOutlineView outlineView) + private PropertyEditorControl GetEditor (string identifier, EditorViewModel vm, NSOutlineView outlineView, bool isGrouping) { var view = (PropertyEditorControl)outlineView.MakeView (identifier, this); if (view != null) return view; - Type[] genericArgs = null; - Type controlType; - Type propertyType = vm.GetType (); - if (!ViewModelTypes.TryGetValue (propertyType, out controlType)) { - if (propertyType.IsConstructedGenericType) { - genericArgs = propertyType.GetGenericArguments (); - propertyType = propertyType.GetGenericTypeDefinition (); - ViewModelTypes.TryGetValue (propertyType, out controlType); + if (vm != null) { + Type[] genericArgs = null; + Type controlType; + Type propertyType = vm.GetType (); + if (!ViewModelTypes.TryGetValue (propertyType, out controlType)) { + if (propertyType.IsConstructedGenericType) { + genericArgs = propertyType.GetGenericArguments (); + propertyType = propertyType.GetGenericTypeDefinition (); + ViewModelTypes.TryGetValue (propertyType, out controlType); + } } - } - if (controlType == null) - return null; + if (controlType == null) + return null; - if (controlType.IsGenericTypeDefinition) { - if (genericArgs == null) - genericArgs = propertyType.GetGenericArguments (); + if (controlType.IsGenericTypeDefinition) { + if (genericArgs == null) + genericArgs = propertyType.GetGenericArguments (); - controlType = controlType.MakeGenericType (genericArgs); - } + controlType = controlType.MakeGenericType (genericArgs); + } - view = (PropertyEditorControl)Activator.CreateInstance (controlType); - view.Identifier = identifier; - view.TableView = outlineView; + view = (PropertyEditorControl)Activator.CreateInstance (controlType); + view.Identifier = identifier; + view.TableView = outlineView; - return view; + return view; + } else { + if (isGrouping) + return null; + else + return new PanelHeaderEditorControl (dataSource.DataContext); + } } private void GetVMGroupCellItendifiterFromFacade (NSObject item, out PropertyViewModel vm, out IGroupingList<string, EditorViewModel> group, out string cellIdentifier) @@ -229,7 +249,9 @@ namespace Xamarin.PropertyEditing.Mac var facade = (NSObjectFacade)item; vm = facade.Target as PropertyViewModel; group = facade.Target as IGroupingList<string, EditorViewModel>; - cellIdentifier = (group == null) ? vm.GetType ().FullName : group.Key; + cellIdentifier = facade.Target is PanelHeaderEditorControl pvh + ? nameof (PanelHeaderEditorControl) + : (group == null) ? vm.GetType ().FullName : group.Key; } private static readonly Dictionary<Type, Type> ViewModelTypes = new Dictionary<Type, Type> { diff --git a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs index eacabab..e22166a 100644 --- a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs +++ b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs @@ -190,5 +190,17 @@ namespace Xamarin.PropertyEditing.Mac.Resources { return ResourceManager.GetString("CommonBrushTitleGradient", resourceCulture); } } + + internal static string AccessibilityObjectName { + get { + return ResourceManager.GetString("AccessibilityObjectName", resourceCulture); + } + } + + internal static string ObjectNamePlaceholder { + get { + return ResourceManager.GetString("ObjectNamePlaceholder", resourceCulture); + } + } } } diff --git a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx index e768be7..16a5da3 100644 --- a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx +++ b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx @@ -95,4 +95,11 @@ <data name="CommonBrushTitleGradient" xml:space="preserve"> <value>Gradient</value>> </data> + <data name="AccessibilityObjectName" xml:space="preserve"> + <value>{0} Object Name Editor</value> + <comment>Editor for Object Name Value</comment> + </data> + <data name="ObjectNamePlaceholder" xml:space="preserve"> + <value>No Name</value>> + </data> </root> diff --git a/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj b/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj index 284d0fd..8fdb333 100644 --- a/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj +++ b/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj @@ -134,6 +134,7 @@ <Compile Include="Controls\RequestResource\ResourceTableDataSource.cs" />
<Compile Include="Controls\RequestResource\ResourceTableDelegate.cs" />
<Compile Include="Controls\RequestResource\RequestResourcePreviewPanel.cs" />
+ <Compile Include="Controls\PanelHeaderEditorControl.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controls\" />
|