Files
aistudio-wpf-diagram/AIStudio.Wpf.Mind/ViewModels/MindNode.cs
2023-03-25 22:10:49 +08:00

743 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Linq;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using AIStudio.Wpf.DiagramDesigner.Models;
using AIStudio.Wpf.DiagramModels;
using AIStudio.Wpf.DiagramModels.ViewModels;
using AIStudio.Wpf.Flowchart.Models;
using AIStudio.Wpf.Mind.Helpers;
using AIStudio.Wpf.Mind.Models;
namespace AIStudio.Wpf.Mind.ViewModels
{
public class MindNode : DiagramItemViewModel
{
public MindNode() : this(null)
{
}
public MindNode(IDiagramViewModel root) : base(root)
{
}
public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
{
InitLayout(false);
}
public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
{
InitLayout(false);
}
public override SelectableItemBase GetSerializableObject()
{
return new MindNodeDesignerItem(this);
}
public override DiagramNode ToDiagram()
{
var mindNodeModel = new MindNodeModel();
mindNodeModel.Spacing = Spacing;
mindNodeModel.Offset = Offset;
mindNodeModel.IsExpanded = IsExpanded;
mindNodeModel.LinkInfoModel = new LinkInfoModel(LinkInfo);
mindNodeModel.ImageInfoModel = new ImageInfoModel(ImageInfo);
mindNodeModel.Remark = Remark;
mindNodeModel.Priority = Priority;
mindNodeModel.Rate = Rate;
if (Tags != null)
{
mindNodeModel.Tags = new List<string>(Tags);
}
return mindNodeModel;
}
protected override void Init(IDiagramViewModel root, bool initNew)
{
base.Init(root, initNew);
EnabledForConnection = false;
AlwayForResized = true;
CustomText = true;
AddChildCommand = (Root as IMindDiagramViewModel)?.AddChildCommand;
AddParentCommand = (Root as IMindDiagramViewModel)?.AddParentCommand;
AddPearCommand = (Root as IMindDiagramViewModel)?.AddPearCommand;
DeleteCommand = (Root as IMindDiagramViewModel)?.DeleteCommand;
MoveForwardCommand = (Root as IMindDiagramViewModel)?.MoveForwardCommand;
MoveBackCommand = (Root as IMindDiagramViewModel)?.MoveBackCommand;
BuildMenuOptions();
Tags = new ObservableCollection<string>();
LinkInfo = new LinkInfo();
ImageInfo = new ImageInfo();
}
protected override void InitNew()
{
this.ClearConnectors();
}
public void InitLayout(bool initAppearance)
{
var layout = TypeHelper.GetType(MindType.ToString() + "Layout");
MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout();
this.PropertyChanged -= this.Item_PropertyChanged;
IsInnerConnector = true;
MindLayout.Appearance(this, MindThemeModel, initAppearance);
this.PropertyChanged += this.Item_PropertyChanged;
}
public void ThemeChange()
{
MindThemeHelper.ThemeChange(this, MindThemeModel);
}
protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
{
base.LoadDesignerItemViewModel(designerbase);
if (designerbase is MindNodeDesignerItem designer)
{
Spacing = designer.Spacing;
Offset = designer.Offset;
IsExpanded = designer.IsExpanded;
LinkInfo = new LinkInfo() { Link = designer.LinkInfoItem?.Link, Text = designer.LinkInfoItem?.Text };
ImageInfo = new ImageInfo() { Url = designer.ImageInfoItem?.Url, Text = designer.ImageInfoItem?.Text };
Remark = designer.Remark;
Priority = designer.Priority;
Rate = designer.Rate;
if (designer.Tags != null)
{
Tags = new ObservableCollection<string>(designer.Tags);
}
}
}
#region
public IMindLayout MindLayout
{
get; set;
}
public MindNode ParentNode
{
get
{
return Parent as MindNode;
}
}
public MindNode RootNode
{
get
{
return GetLevel1Node();
}
}
public int NodeLevel
{
get
{
if (ParentNode == null)
{
return 0;
}
else
{
return ParentNode.NodeLevel + 1;
}
}
}
public MindType MindType
{
get
{
return (Root as IMindDiagramViewModel)?.MindType ?? MindType.Mind;
}
}
public MindThemeModel MindThemeModel
{
get
{
return (Root as IMindDiagramViewModel)?.MindThemeModel ?? MindThemeHelper.GetTheme("天空蓝");
}
}
private bool _isExpanded = true;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
SetProperty(ref _isExpanded, value);
}
}
public SizeBase Spacing
{
get; set;
} = new SizeBase(15, 15);
private ObservableCollection<MindNode> _children = new ObservableCollection<MindNode>();
public ObservableCollection<MindNode> Children
{
get
{
return _children;
}
set
{
SetProperty(ref _children, value);
}
}
public SizeBase SizeWithSpacing
{
get
{
return this.Size.Add(Spacing.Width * 2, Spacing.Height * 2);
}
}
public SizeBase DesiredSize
{
get; set;
}
public PointBase? DesiredPosition
{
get; set;
}
public PointBase Offset
{
get
{
PointBase point;
if (NodeLevel == 0)
{
if (DesiredPosition == null)
{
point = new PointBase();
}
else
{
point = new PointBase(Position.X - DesiredPosition.Value.X, Position.Y - DesiredPosition.Value.Y);
}
}
else
{
if (DesiredPosition == null)
{
point = new PointBase();
}
else
{
point = new PointBase(Position.X - DesiredPosition.Value.X - RootNode.Offset.X, Position.Y - DesiredPosition.Value.Y - RootNode.Offset.Y);
}
}
return point;
}
set
{
if (NodeLevel == 0)
{
DesiredPosition = new PointBase(Position.X - value.X, Position.Y - value.Y);
}
else
{
DesiredPosition = new PointBase(Position.X - value.X - RootNode.Offset.X, Position.Y - value.Y - RootNode.Offset.Y);
}
}
}
private ConnectorOrientation _connectorOrientation = ConnectorOrientation.Left;
public ConnectorOrientation ConnectorOrientation
{
get
{
return _connectorOrientation;
}
set
{
SetProperty(ref _connectorOrientation, value);
}
}
public bool LayoutUpdating
{
get; set;
}
#endregion
#region
private LinkInfo _linkInfo;
public LinkInfo LinkInfo
{
get
{
return _linkInfo;
}
set
{
if (_linkInfo != null)
{
_linkInfo.PropertyChanged -= Item_PropertyChanged;
}
SetProperty(ref _linkInfo, value);
if (_linkInfo != null)
{
_linkInfo.PropertyChanged += Item_PropertyChanged; ;
}
}
}
private ImageInfo _imageInfo;
public ImageInfo ImageInfo
{
get
{
return _imageInfo;
}
set
{
if (_imageInfo != null)
{
_imageInfo.PropertyChanged -= Item_PropertyChanged;
}
SetProperty(ref _imageInfo, value);
if (_imageInfo != null)
{
_imageInfo.PropertyChanged += Item_PropertyChanged;
}
}
}
private string _remark;
public string Remark
{
get
{
return _remark;
}
set
{
SetProperty(ref _remark, value);
}
}
private double? _priority;
public double? Priority
{
get
{
return _priority;
}
set
{
SetProperty(ref _priority, value);
}
}
private double? _rate;
public double? Rate
{
get
{
return _rate;
}
set
{
SetProperty(ref _rate, value);
}
}
private ObservableCollection<string> _tags;
public ObservableCollection<string> Tags
{
get
{
return _tags;
}
set
{
if (_tags != null)
{
_tags.CollectionChanged -= _tags_CollectionChanged;
}
SetProperty(ref _tags, value);
if (_tags != null)
{
_tags.CollectionChanged += _tags_CollectionChanged;
}
}
}
private void _tags_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (var item in e.NewItems.OfType<string>())
{
var width = GetTextDisplayWidthHelper.GetTextDisplayWidth(item, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, 12) + 6;
ItemWidth += width;
}
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems.OfType<string>())
{
var width = GetTextDisplayWidthHelper.GetTextDisplayWidth(item, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, 12) + 6;
ItemWidth -= width;
}
}
}
#endregion
#region
public ICommand AddParentCommand
{
get; private set;
}
public ICommand AddChildCommand
{
get; private set;
}
public ICommand AddPearCommand
{
get; private set;
}
public ICommand DeleteCommand
{
get; private set;
}
public ICommand MoveForwardCommand
{
get; private set;
}
public ICommand MoveBackCommand
{
get; private set;
}
#endregion
#region
private void BuildMenuOptions()
{
menuOptions = new ObservableCollection<CinchMenuItem>();
CinchMenuItem menuItem = new CinchMenuItem();
menuItem.Text = "下级";
menuItem.Command = AddChildCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "同级";
menuItem.Command = AddPearCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "上级";
menuItem.Command = AddParentCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "前移";
menuItem.Command = MoveForwardCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "后移";
menuItem.Command = MoveBackCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
menuItem = new CinchMenuItem();
menuItem.Text = "删除";
menuItem.Command = DeleteCommand;
menuItem.CommandParameter = this;
menuOptions.Add(menuItem);
}
#endregion
#region
public void AddChild(MindNode item, int index = -1)
{
if (index >= 0)
{
this.Children.Insert(index, item);
}
else
{
this.Children.Add(item);
}
item.Parent = this;
item.ParentId = this.Id;
item.InitLayout(true);//因为节点的层级不同的样式所以需要Parent确定后才能初始化
ConnectionViewModel connector = MindLayout?.GetOrSetConnectionViewModel(this, item);
Root?.DirectAddItemCommand.Execute(new SelectableDesignerItemViewModelBase[] { item, connector });
connector.ZIndex = -1;
connector.IsSelected = false;
item.IsSelected = false;
this.IsSelected = true;
}
public void RemoveChild(MindNode item, bool removeall = false)
{
item.PropertyChanged -= Item_PropertyChanged;
this.Children.Remove(item);
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == item).ToList();
Root?.DirectRemoveItemCommand.Execute(item);
Root?.DirectRemoveItemCommand.Execute(connectors);
if (removeall)
{
if (item.Children?.Count > 0)
{
foreach (var child in item.Children.ToList())
{
item.RemoveChild(child, removeall);
}
}
}
}
public void Remove(bool removeall = false)
{
this.PropertyChanged -= Item_PropertyChanged;
if (this.ParentNode != null)
{
this.ParentNode.Children.Remove(this);
}
var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == this).ToList();
Root?.DirectRemoveItemCommand.Execute(this);
Root?.DirectRemoveItemCommand.Execute(connectors);
if (removeall)
{
if (this.Children?.Count > 0)
{
foreach (var child in this.Children.ToList())
{
child.Remove(removeall);
}
}
}
}
public void InitConnectLayout()
{
var connector = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.IsFullConnection).FirstOrDefault(p => p.SinkConnectorInfoFully.DataItem == this);
if (connector != null)
{
MindLayout?.GetOrSetConnectionViewModel(connector.SourceConnectorInfo.DataItem as MindNode, connector.SinkConnectorInfoFully.DataItem as MindNode, connector);
}
else if (ParentNode != null)
{
connector = MindLayout?.GetOrSetConnectionViewModel(ParentNode, this, null);
Root?.DirectAddItemCommand.Execute(new SelectableDesignerItemViewModelBase[] { connector });
connector.ZIndex = -1;
connector.IsSelected = false;
}
}
#endregion
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (GetLevel1Node()?.LayoutUpdating == true) return;
switch (e.PropertyName)
{
case nameof(IsExpanded):
case nameof(ItemWidth):
case nameof(ItemHeight):
{
LayoutUpdated();
break;
}
case nameof(NodeLevel):
MindLayout?.Appearance(this);
break;
case nameof(Text):
{
ItemWidth = Math.Max(ItemWidth, GetTextDisplayWidthHelper.GetTextDisplayWidth(Text, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, FontViewModel.FontSize) + 30);
break;
}
case nameof(Rate):
case nameof(Priority):
case nameof(Remark):
case nameof(LinkInfo.Link):
{
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
{
if (string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && !string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
{
ItemWidth += 24;
}
else if (!string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
{
ItemWidth -= 24;
}
}
break;
}
case nameof(ImageInfo.Url):
{
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
{
if (string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && !string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
{
ItemWidth = Math.Max(ItemWidth, 160);
ItemHeight += 135;
}
else if (!string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
{
ItemHeight -= 135;
}
}
break;
}
}
}
public override void AddToSelection(bool selected)
{
foreach (SelectableDesignerItemViewModelBase item in Root.SelectedItems.ToList())
item.IsSelected = false;
Root.SelectedItems.Clear();
IsSelected = selected;
}
#region
public MindNode GetLevel1Node()
{
var node = this;
while (node.Parent is MindNode mindNode)
{
node = mindNode;
}
return node;
}
public MindNode GetLevel2Node()
{
var node = this;
while (node.Parent is MindNode mindNode && mindNode.NodeLevel == 1)
{
node = mindNode;
}
return node;
}
protected void UpdateOffsetX(double oldvalue, double newvalue)
{
Offset += new VectorBase(newvalue - oldvalue, 0);
}
protected void UpdateOffsetY(double oldvalue, double newvalue)
{
Offset += new VectorBase(0, newvalue - oldvalue);
}
public void LayoutUpdated()
{
MindLayout?.LayoutUpdated(GetLevel1Node());
}
#endregion
}
public class LinkInfo : BindableBase
{
private string _link;
public string Link
{
get
{
return _link;
}
set
{
SetProperty(ref _link, value);
}
}
private string _text;
public string Text
{
get
{
return _text;
}
set
{
SetProperty(ref _text, value);
}
}
}
public class ImageInfo : BindableBase
{
private string _url;
public string Url
{
get
{
return _url;
}
set
{
SetProperty(ref _url, value);
}
}
private string _text;
public string Text
{
get
{
return _text;
}
set
{
SetProperty(ref _text, value);
}
}
}
}