4 using System.Collections.Generic;
5 using System.Collections.ObjectModel;
8 using System.Linq.Expressions;
9 using System.Windows.Input;
11 using SiliconStudio.Presentation.Collections;
12 using SiliconStudio.Presentation.Core;
13 using SiliconStudio.Presentation.ViewModel;
14 using SiliconStudio.Quantum;
15 using SiliconStudio.Quantum.Contents;
17 namespace SiliconStudio.Presentation.Quantum
21 private readonly SortedObservableCollection<IObservableNode> children =
new SortedObservableCollection<IObservableNode>(
new AnonymousComparer<IObservableNode>(CompareChildren));
23 private readonly ObservableCollection<INodeCommandWrapper> commands =
new ObservableCollection<INodeCommandWrapper>();
24 private bool isVisible;
25 private bool isReadOnly;
26 private string displayName;
29 : base(ownerViewModel.ServiceProvider)
31 Owner = ownerViewModel;
34 Guid = Guid.NewGuid();
47 public string Name {
get;
protected set; }
52 public string DisplayName {
get {
return displayName; } set { SetValue(ref displayName, value); } }
57 public string Path {
get {
return Parent != null ? Parent.Path +
'.' + Name : Name; } }
72 public abstract Type Type {
get; }
77 public abstract bool IsPrimitive {
get; }
82 public bool IsVisible {
get {
return isVisible; } set { SetValue(ref isVisible, value); } }
87 public bool IsReadOnly {
get {
return isReadOnly; } set { SetValue(ref isReadOnly, value); } }
92 public abstract object Value {
get; set; }
97 public object Index {
get;
private set; }
102 public Guid Guid {
get;
private set; }
107 public IReadOnlyCollection<IObservableNode> Children {
get {
return children; } }
122 public abstract int? Order {
get; }
127 public abstract bool HasList {
get; }
132 public abstract bool HasDictionary {
get; }
159 var parent = newParent;
160 while (parent != null)
164 parent = parent.Parent;
177 throw new InvalidOperationException(
"A CombinedObservableNode cannot be moved.");
178 if (newParent is CombinedObservableNode)
179 throw new ArgumentException(
"The new parent cannot be a CombinedObservableNode");
182 while (parent != null)
185 throw new InvalidOperationException(
"A node cannot be moved into itself or one of its children.");
189 if (newParent.
Children.Any(x => (newName == null && x.Name == Name) || x.Name == newName))
190 throw new InvalidOperationException(
"Unable to move this node, a node with the same name already exists.");
195 parent.RemoveChild(
this);
214 return (
ObservableNode)Children.FirstOrDefault(x => x.Name == name);
224 return Commands.FirstOrDefault(x => x.Name == name);
234 return AssociatedData.FirstOrDefault(x => x.Key == name).Value;
244 return GetChild(name) ?? GetCommand(name) ?? GetAssociatedData(name);
250 return new ObservableNodeDynamicMetaObject(parameter,
this);
265 if (node == null)
throw new ArgumentNullException(
"node");
266 if (children.Contains(node))
throw new InvalidOperationException(
"The node is already in the children list of its parent.");
267 NotifyPropertyChanging(node.
Name);
269 NotifyPropertyChanged(node.
Name);
272 internal void RemoveChild(IObservableNode node)
274 if (node == null)
throw new ArgumentNullException(
"node");
275 if (!children.Contains(node))
throw new InvalidOperationException(
"The node is not in the children list of its parent.");
276 NotifyPropertyChanging(node.Name);
277 children.Remove(node);
278 NotifyPropertyChanged(node.Name);
283 if (command == null)
throw new ArgumentNullException(
"command");
285 OnPropertyChanging(command.
Name);
286 commands.Add(command);
287 OnPropertyChanged(command.
Name);
293 var commandNames = commands.Select(x => x.Name).ToList();
294 foreach (
string commandName
in commandNames)
297 OnPropertyChanging(commandName);
300 for (
int i = commandNames.Count - 1; i >= 0; --i)
302 OnPropertyChanged(commandNames[i]);
309 var memberNames =
new HashSet<string>();
310 foreach (var child
in Children)
312 if (
string.IsNullOrWhiteSpace(child.Name))
313 throw new InvalidOperationException(
"This node has a child with a null or blank name");
315 if (child.Name.Contains(
'.'))
316 throw new InvalidOperationException(
string.Format(
"This node has a child which contains a period (.) in its name: {0}", child.Name));
318 if (memberNames.Contains(child.Name))
319 throw new InvalidOperationException(
string.Format(
"This node contains several members named {0}", child.Name));
321 memberNames.Add(child.Name);
326 if (
string.IsNullOrWhiteSpace(command.Name))
327 throw new InvalidOperationException(
"This node has a command with a null or blank name {0}");
329 if (memberNames.Contains(command.Name))
330 throw new InvalidOperationException(
string.Format(
"This node contains several members named {0}", command.Name));
332 memberNames.Add(command.Name);
335 foreach (var associatedDataKey
in AssociatedData.Keys)
337 if (
string.IsNullOrWhiteSpace(associatedDataKey))
338 throw new InvalidOperationException(
"This node has associated data with a null or blank name {0}");
340 if (memberNames.Contains(associatedDataKey))
341 throw new InvalidOperationException(
string.Format(
"This node contains several members named {0}", associatedDataKey));
343 memberNames.Add(associatedDataKey);
347 private void UpdateCommandPath()
351 commandWrapper.ObservableNodePath = Path;
353 foreach (var child
in Children.OfType<ObservableNode>())
355 child.UpdateCommandPath();
359 private static int CompareChildren(IObservableNode
a, IObservableNode
b)
362 if (a.Order != null && b.Order != null)
363 return ((
int)a.Order).CompareTo(b.Order);
366 if (a.Index != null && b.Index != null)
368 if (a.Index.GetType() == b.Index.GetType() && a.Index is
IComparable)
370 return ((IComparable)a.Index).CompareTo(b.Index);
375 if (a.Order == null && b.Order == null)
376 return string.Compare(a.Name, b.Name, StringComparison.InvariantCultureIgnoreCase);
379 return a.Order == null ? 1 : -1;
void NotifyPropertyChanged(string propertyName)
ObservableNode(ObservableViewModel ownerViewModel, IObservableNode parentNode, object index=null)
const string HasChildPrefix
object GetDynamicObject(string name)
Returns the child node, the command or the additional data with the matching name.
bool CanMove(IObservableNode newParent)
Indicates whether this node can be moved.
IReadOnlyCollection< IObservableNode > Children
Gets the list of children nodes.
DynamicMetaObject GetMetaObject(Expression parameter)
const string HasCommandPrefix
void Move(IObservableNode newParent, string newName=null)
Moves the node by setting it a new parent.
Flags
Enumeration of the new Assimp's flags.
This abstract class is an implementation of ViewModelBase that uses a dispatcher to invoke OnProperty...
A base class to wrap one or multiple INodeCommand instances into a CancellableCommand.
string Name
Gets or sets the name of this node. Note that the name can be used to access this node from its paren...
ViewModelContentSerializeFlags
Flags applying to IContent.
IObservableNode Parent
Gets or the parent of this node.
ObservableNode GetChild(string name)
Returns the child node with the matching name.
ICommand GetCommand(string name)
Returns the command with the matching name.
void CheckDynamicMemberConsistency()
object GetAssociatedData(string name)
Returns the additionnal data with the matching name.
void NotifyPropertyChanging(string propertyName)
void AddCommand(INodeCommandWrapper command)