You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
9.8 KiB
377 lines
9.8 KiB
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.Diagnostics; |
|
using System.Collections.Generic; |
|
using System.Collections.ObjectModel; |
|
using System.Windows; |
|
using ICSharpCode.WpfDesign.XamlDom; |
|
using ICSharpCode.WpfDesign.Designer.Services; |
|
using System.Collections.Specialized; |
|
|
|
namespace ICSharpCode.WpfDesign.Designer.Xaml |
|
{ |
|
sealed class XamlModelCollectionElementsCollection : IList<DesignItem>, INotifyCollectionChanged |
|
{ |
|
readonly XamlModelProperty modelProperty; |
|
readonly XamlProperty property; |
|
readonly XamlDesignContext context; |
|
|
|
public event NotifyCollectionChangedEventHandler CollectionChanged; |
|
|
|
public XamlModelCollectionElementsCollection(XamlModelProperty modelProperty, XamlProperty property) |
|
{ |
|
this.modelProperty = modelProperty; |
|
this.property = property; |
|
this.context = (XamlDesignContext)modelProperty.DesignItem.Context; |
|
} |
|
|
|
public int Count { |
|
get { |
|
return property.CollectionElements.Count; |
|
} |
|
} |
|
|
|
public bool IsReadOnly { |
|
get { |
|
return false; |
|
} |
|
} |
|
|
|
public void Add(DesignItem item) |
|
{ |
|
Insert(this.Count, item); |
|
} |
|
|
|
public void Clear() |
|
{ |
|
while (this.Count > 0) { |
|
RemoveAt(this.Count - 1); |
|
} |
|
|
|
if (CollectionChanged != null) |
|
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
|
} |
|
|
|
public bool Contains(DesignItem item) |
|
{ |
|
XamlDesignItem xitem = CheckItemNoException(item); |
|
if (xitem != null) |
|
return property.CollectionElements.Contains(xitem.XamlObject); |
|
else |
|
return false; |
|
} |
|
|
|
public int IndexOf(DesignItem item) |
|
{ |
|
XamlDesignItem xitem = CheckItemNoException(item); |
|
if (xitem != null) |
|
return property.CollectionElements.IndexOf(xitem.XamlObject); |
|
else |
|
return -1; |
|
} |
|
|
|
public void CopyTo(DesignItem[] array, int arrayIndex) |
|
{ |
|
for (int i = 0; i < this.Count; i++) { |
|
array[arrayIndex + i] = this[i]; |
|
} |
|
} |
|
|
|
public bool Remove(DesignItem item) |
|
{ |
|
int index = IndexOf(item); |
|
if (index < 0) |
|
return false; |
|
|
|
RemoveAt(index); |
|
|
|
return true; |
|
} |
|
|
|
public IEnumerator<DesignItem> GetEnumerator() |
|
{ |
|
foreach (XamlPropertyValue val in property.CollectionElements) { |
|
var item = GetItem(val); |
|
if (item != null) |
|
yield return item; |
|
} |
|
} |
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
{ |
|
return this.GetEnumerator(); |
|
} |
|
|
|
DesignItem GetItem(XamlPropertyValue val) |
|
{ |
|
if (val is XamlObject) { |
|
return context._componentService.GetDesignItem( ((XamlObject)val).Instance ); |
|
} else { |
|
return null; // throw new NotImplementedException(); |
|
} |
|
} |
|
|
|
XamlDesignItem CheckItem(DesignItem item) |
|
{ |
|
if (item == null) |
|
throw new ArgumentNullException("item"); |
|
if (item.Context != modelProperty.DesignItem.Context) |
|
throw new ArgumentException("The item must belong to the same context as this collection", "item"); |
|
XamlDesignItem xitem = item as XamlDesignItem; |
|
Debug.Assert(xitem != null); |
|
return xitem; |
|
} |
|
|
|
XamlDesignItem CheckItemNoException(DesignItem item) |
|
{ |
|
return item as XamlDesignItem; |
|
} |
|
|
|
public DesignItem this[int index] { |
|
get { |
|
return GetItem(property.CollectionElements[index]); |
|
} |
|
set { |
|
RemoveAt(index); |
|
Insert(index, value); |
|
} |
|
} |
|
|
|
public void Insert(int index, DesignItem item) |
|
{ |
|
Execute(new InsertAction(this, index, CheckItem(item))); |
|
} |
|
|
|
public void RemoveAt(int index) |
|
{ |
|
Execute(new RemoveAtAction(this, index, (XamlDesignItem)this[index])); |
|
} |
|
|
|
internal ITransactionItem CreateResetTransaction() |
|
{ |
|
return new ResetAction(this); |
|
} |
|
|
|
void Execute(ITransactionItem item) |
|
{ |
|
UndoService undoService = context.Services.GetService<UndoService>(); |
|
if (undoService != null) |
|
undoService.Execute(item); |
|
else |
|
item.Do(); |
|
} |
|
|
|
void RemoveInternal(int index, XamlDesignItem item) |
|
{ |
|
RemoveFromNamescopeRecursive(item); |
|
|
|
Debug.Assert(property.CollectionElements[index] == item.XamlObject); |
|
property.CollectionElements.RemoveAt(index); |
|
|
|
if (CollectionChanged != null) |
|
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); |
|
} |
|
|
|
void InsertInternal(int index, XamlDesignItem item) |
|
{ |
|
property.CollectionElements.Insert(index, item.XamlObject); |
|
|
|
if (CollectionChanged != null) |
|
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); |
|
|
|
AddToNamescopeRecursive(item); |
|
} |
|
|
|
private static void RemoveFromNamescopeRecursive(XamlDesignItem designItem) |
|
{ |
|
NameScopeHelper.NameChanged(designItem.XamlObject, designItem.Name, null); |
|
|
|
foreach (var p in designItem.Properties) |
|
{ |
|
if (p.Value != null) { |
|
RemoveFromNamescopeRecursive((XamlDesignItem)p.Value); |
|
} |
|
else if (p.IsCollection && p.CollectionElements != null) { |
|
foreach (var c in p.CollectionElements) { |
|
RemoveFromNamescopeRecursive((XamlDesignItem)c); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private static void AddToNamescopeRecursive(XamlDesignItem designItem) |
|
{ |
|
NameScopeHelper.NameChanged(designItem.XamlObject, null, designItem.Name); |
|
|
|
foreach (var p in designItem.Properties) |
|
{ |
|
if (p.Value != null) { |
|
AddToNamescopeRecursive((XamlDesignItem)p.Value); |
|
} |
|
else if (p.IsCollection && p.CollectionElements != null) { |
|
foreach (var c in p.CollectionElements) { |
|
AddToNamescopeRecursive((XamlDesignItem)c); |
|
} |
|
} |
|
} |
|
} |
|
|
|
sealed class InsertAction : ITransactionItem |
|
{ |
|
readonly XamlModelCollectionElementsCollection collection; |
|
readonly int index; |
|
readonly XamlDesignItem item; |
|
|
|
public InsertAction(XamlModelCollectionElementsCollection collection, int index, XamlDesignItem item) |
|
{ |
|
this.collection = collection; |
|
this.index = index; |
|
this.item = item; |
|
} |
|
|
|
public ICollection<DesignItem> AffectedElements { |
|
get { |
|
return new DesignItem[] { item }; |
|
} |
|
} |
|
|
|
public string Title { |
|
get { |
|
return "Insert into collection"; |
|
} |
|
} |
|
|
|
public void Do() |
|
{ |
|
collection.InsertInternal(index, item); |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
|
|
public void Undo() |
|
{ |
|
collection.RemoveInternal(index, item); |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
|
|
public bool MergeWith(ITransactionItem other) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
sealed class RemoveAtAction : ITransactionItem |
|
{ |
|
readonly XamlModelCollectionElementsCollection collection; |
|
readonly int index; |
|
readonly XamlDesignItem item; |
|
|
|
public RemoveAtAction(XamlModelCollectionElementsCollection collection, int index, XamlDesignItem item) |
|
{ |
|
this.collection = collection; |
|
this.index = index; |
|
this.item = item; |
|
} |
|
|
|
public ICollection<DesignItem> AffectedElements { |
|
get { |
|
return new DesignItem[] { collection.modelProperty.DesignItem }; |
|
} |
|
} |
|
|
|
public string Title { |
|
get { |
|
return "Remove from collection"; |
|
} |
|
} |
|
|
|
public void Do() |
|
{ |
|
collection.RemoveInternal(index, item); |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
|
|
public void Undo() |
|
{ |
|
collection.InsertInternal(index, item); |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
|
|
public bool MergeWith(ITransactionItem other) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
sealed class ResetAction : ITransactionItem |
|
{ |
|
readonly XamlModelCollectionElementsCollection collection; |
|
readonly XamlDesignItem[] items; |
|
|
|
public ResetAction(XamlModelCollectionElementsCollection collection) |
|
{ |
|
this.collection = collection; |
|
|
|
items = new XamlDesignItem[collection.Count]; |
|
for (int i = 0; i < collection.Count; i++) { |
|
items[i] = (XamlDesignItem)collection[i]; |
|
} |
|
} |
|
|
|
#region ITransactionItem implementation |
|
|
|
public void Do() |
|
{ |
|
for (int i = items.Length - 1; i >= 0; i--) { |
|
collection.RemoveInternal(i, items[i]); |
|
} |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
public void Undo() |
|
{ |
|
for (int i = 0; i < items.Length; i++) { |
|
collection.InsertInternal(i, items[i]); |
|
} |
|
collection.modelProperty.XamlDesignItem.NotifyPropertyChanged(collection.modelProperty); |
|
} |
|
public bool MergeWith(ITransactionItem other) |
|
{ |
|
return false; |
|
} |
|
|
|
#endregion |
|
|
|
#region IUndoAction implementation |
|
|
|
public ICollection<DesignItem> AffectedElements { |
|
get { |
|
return new DesignItem[] { collection.modelProperty.DesignItem }; |
|
} |
|
} |
|
|
|
public string Title { |
|
get { |
|
return "Reset collection"; |
|
} |
|
} |
|
|
|
#endregion |
|
} |
|
} |
|
}
|
|
|