using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Windows.Forms; using UniversalEditor.Accessors; using UniversalEditor.ObjectModels.PropertyList; using UniversalEditor.DataFormats.PropertyList.XML; namespace UniversalEditor.UserInterface.WindowsForms { public partial class Editor : UserControl, IEditorImplementation { private bool mvarInhibitUndo = false; protected bool InhibitUndo { get { return mvarInhibitUndo; } set { mvarInhibitUndo = value; } } private Toolbox mvarToolbox = new Toolbox(); protected Toolbox Toolbox { get { return mvarToolbox; } } private AwesomeControls.PropertyGrid.PropertyGroup.PropertyGroupCollection mvarPropertyGroups = new AwesomeControls.PropertyGrid.PropertyGroup.PropertyGroupCollection(null); public AwesomeControls.PropertyGrid.PropertyGroup.PropertyGroupCollection PropertyGroups { get { return mvarPropertyGroups; } } /// /// The event raised when a toolbox item is selected. Use this to change the current Editor's internal mode without /// actually affecting the content of the ObjectModel. /// public event ToolboxItemEventHandler ToolboxItemSelected; protected virtual void OnToolboxItemSelected(ToolboxItemEventArgs e) { if (ToolboxItemSelected != null) ToolboxItemSelected(this, e); } /// /// The event raised when a toolbox item is added to the Editor. Use this to adjust the content of the ObjectModel /// based on which toolbox item was added. /// public event ToolboxItemEventHandler ToolboxItemAdded; protected virtual void OnToolboxItemAdded(ToolboxItemEventArgs e) { if (ToolboxItemAdded != null) ToolboxItemAdded(this, e); } /// /// Causes the editor to select the specified toolbox item. /// /// /// True if the editor accepted the new selection; false otherwise. Update the toolbox user interface accordingly. public bool SelectToolboxItem(ToolboxItem item) { ToolboxItemEventArgs e = new ToolboxItemEventArgs(item); OnToolboxItemSelected(e); if (e.Cancel) return false; return true; } protected override void OnDragEnter(DragEventArgs e) { base.OnDragEnter(e); if (e.Data.GetDataPresent(typeof(ToolboxItem))) { e.Effect = DragDropEffects.Copy; } } protected override void OnDragDrop(DragEventArgs e) { base.OnDragDrop(e); if (e.Data.GetDataPresent(typeof(ToolboxItem))) { ToolboxItem item = (e.Data.GetData(typeof(ToolboxItem)) as ToolboxItem); ToolboxItemEventArgs e1 = new ToolboxItemEventArgs(item); OnToolboxItemAdded(e1); } } public event CancelEventHandler DocumentClosing; protected virtual void OnDocumentClosing(CancelEventArgs e) { if (DocumentClosing != null) DocumentClosing(this, e); } public event EventHandler DocumentClosed; protected virtual void OnDocumentClosed(EventArgs e) { if (DocumentClosed != null) DocumentClosed(this, e); } private UniversalEditor.ObjectModels.PropertyList.PropertyListObjectModel mvarConfiguration = new UniversalEditor.ObjectModels.PropertyList.PropertyListObjectModel(); public UniversalEditor.ObjectModels.PropertyList.PropertyListObjectModel Configuration { get { return mvarConfiguration; } } public Editor() { InitializeComponent(); mvarLargeImageList.ColorDepth = ColorDepth.Depth32Bit; mvarLargeImageList.ImageSize = new System.Drawing.Size(32, 32); IconMethods.PopulateSystemIcons(ref mvarLargeImageList); string largeImageListPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { DataPath, "Images", "ImageList", "32x32" }); if (System.IO.Directory.Exists(largeImageListPath)) { string[] fileNames = System.IO.Directory.GetFiles(largeImageListPath); foreach (string fileName in fileNames) { try { Image image = Image.FromFile(fileName); mvarLargeImageList.Images.Add(System.IO.Path.GetFileNameWithoutExtension(fileName), image); } catch (System.OutOfMemoryException) { } } } mvarSmallImageList.ColorDepth = ColorDepth.Depth32Bit; mvarSmallImageList.ImageSize = new System.Drawing.Size(16, 16); IconMethods.PopulateSystemIcons(ref mvarSmallImageList); string smallImageListPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { DataPath, "Images", "ImageList", "16x16" }); if (System.IO.Directory.Exists(smallImageListPath)) { string[] fileNames = System.IO.Directory.GetFiles(smallImageListPath); foreach (string fileName in fileNames) { try { Image image = Image.FromFile(fileName); mvarSmallImageList.Images.Add(System.IO.Path.GetFileNameWithoutExtension(fileName), image); } catch (System.OutOfMemoryException) { } } } string configurationPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { DataPath, "Configuration" }); if (System.IO.Directory.Exists(configurationPath)) { string[] fileNames = System.IO.Directory.GetFiles(configurationPath, "*.xml"); XMLPropertyListDataFormat xmpl = new XMLPropertyListDataFormat(); foreach (string fileName in fileNames) { try { PropertyListObjectModel plom = new PropertyListObjectModel(); Document.Load(plom, xmpl, new FileAccessor(fileName), true); plom.CopyTo(mvarConfiguration); } catch (InvalidDataFormatException ex) { } } } } private ImageList mvarLargeImageList = new ImageList(); protected ImageList LargeImageList { get { return mvarLargeImageList; } } private ImageList mvarSmallImageList = new ImageList(); protected ImageList SmallImageList { get { return mvarSmallImageList; } } #region IEditorImplementation Members public virtual string Title { get { return String.Empty; } } public virtual void Copy() { } public virtual void Paste() { } /// /// Causes the editor to delete the currently-selected item. /// public virtual void Delete() { } private ObjectModelReference.ObjectModelReferenceCollection mvarSupportedObjectModels = new ObjectModelReference.ObjectModelReferenceCollection(); public ObjectModelReference.ObjectModelReferenceCollection SupportedObjectModels { get { return mvarSupportedObjectModels; } } private ObjectModel mvarObjectModel = null; public ObjectModel ObjectModel { get { return mvarObjectModel; } set { ObjectModelChangingEventArgs omce = new ObjectModelChangingEventArgs(mvarObjectModel, value); OnObjectModelChanging(omce); if (omce.Cancel) return; mvarObjectModel = omce.NewObjectModel; OnObjectModelChanged(EventArgs.Empty); } } #endregion #region Implementation public event ObjectModelChangingEventHandler ObjectModelChanging; protected virtual void OnObjectModelChanging(ObjectModelChangingEventArgs e) { if (ObjectModelChanging != null) ObjectModelChanging(this, e); } public event EventHandler ObjectModelChanged; protected virtual void OnObjectModelChanged(EventArgs e) { if (ObjectModelChanged != null) ObjectModelChanged(this, e); } public event CancelEventHandler ObjectModelSaving; protected virtual void OnObjectModelSaving(CancelEventArgs e) { if (ObjectModelSaving != null) ObjectModelSaving(this, e); } private struct EDITINFO { public object item; public string propertyName; public object oldValue; public bool closed; public EDITINFO(object item, string propertyName, object oldValue) { this.item = item; this.propertyName = propertyName; this.oldValue = oldValue; this.closed = false; } } private Stack undo = new Stack(); public int UndoItemCount { get { return undo.Count; } } private Stack redo = new Stack(); public int RedoItemCount { get { return redo.Count; } } public event EventHandler DocumentEdited; protected virtual void OnDocumentEdited(EventArgs e) { if (DocumentEdited != null) DocumentEdited(this, e); } private int mvarEditing = 0; protected void BeginEdit() { if (mvarEditing > 0) { mvarEditing++; return; } mvarEditing++; // check to see if this property has been edited before if (undo.Count > 0) { EDITINFO oldedit = undo.Pop(); if (oldedit.closed) undo.Push(oldedit); } // push the new edit EDITINFO edit = new EDITINFO(null, null, mvarObjectModel); undo.Push(edit); // clear out all the redos redo.Clear(); } protected void BeginEdit(string PropertyName, object Value = null, object ParentObject = null) { if (mvarEditing > 0) { mvarEditing++; return; } mvarEditing++; if (ParentObject == null) ParentObject = ObjectModel; // check to see if this property has been edited before if (undo.Count > 0) { EDITINFO oldedit = undo.Pop(); if (oldedit.propertyName != PropertyName || oldedit.closed) undo.Push(oldedit); } // push the new edit if (Value == null) { System.Reflection.PropertyInfo pi = ParentObject.GetType().GetProperty(PropertyName); if (pi != null) { Value = ParentObject.GetType().GetProperty(PropertyName).GetValue(ParentObject, null); } } EDITINFO edit = new EDITINFO(ParentObject, PropertyName, Value); undo.Push(edit); // clear out all the redos redo.Clear(); } protected void EndEdit() { if (mvarEditing == 0) return; // throw new InvalidOperationException(); if (mvarEditing > 1) { mvarEditing--; return; } if (undo.Count == 0) return; EDITINFO oldedit = undo.Pop(); oldedit.closed = true; undo.Push(oldedit); // notify the object model that it's being edited OnDocumentEdited(EventArgs.Empty); mvarEditing--; } public virtual void Undo() { if (undo.Count == 0) return; EDITINFO edi = undo.Pop(); EDITINFO newedi = edi; if (edi.propertyName != null) { // get the property that owns this edit System.Reflection.PropertyInfo pi = edi.item.GetType().GetProperty(edi.propertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); // get the current value of the property, for a "redo" object newValue = pi.GetValue(edi.item, null); newedi = new EDITINFO(edi.item, edi.propertyName, newValue); // set the current value to the "un-done" value pi.SetValue(edi.item, edi.oldValue, null); } else { newedi = new EDITINFO(null, null, mvarObjectModel); mvarObjectModel = (edi.oldValue as ObjectModel); } // cause a refresh of the editor OnObjectModelChanged(EventArgs.Empty); // push the previous value into the redo log redo.Push(newedi); } public virtual void Redo() { // this is EXACTLY like undo, only in reverse ;) if (redo.Count == 0) return; EDITINFO edi = redo.Pop(); EDITINFO newedi = edi; if (edi.propertyName != null) { // get the property that owns this edit System.Reflection.PropertyInfo pi = edi.item.GetType().GetProperty(edi.propertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); // get the current value of the property, for a "redo" object newValue = pi.GetValue(edi.item, null); newedi = new EDITINFO(edi.item, edi.propertyName, newValue); // set the current value to the "un-done" value pi.SetValue(edi.item, edi.oldValue, null); } else { newedi = new EDITINFO(null, null, mvarObjectModel); mvarObjectModel = (edi.oldValue as ObjectModel); } // cause a refresh of the editor OnObjectModelChanged(EventArgs.Empty); // push the previous value into the undo log undo.Push(newedi); } #endregion private MenuBar mvarMenuBar = new MenuBar(); public MenuBar MenuBar { get { return mvarMenuBar; } } private Toolbar.ToolbarCollection mvarToolbars = new Toolbar.ToolbarCollection(); public Toolbar.ToolbarCollection Toolbars { get { return mvarToolbars; } } public bool NotifySaving() { CancelEventArgs ce = new CancelEventArgs(); OnObjectModelSaving(ce); if (ce.Cancel) return false; return true; } public void NotifyClosing(CancelEventArgs ce) { OnDocumentClosing(ce); } public void NotifyClosed(EventArgs e) { OnDocumentClosed(e); } public string DataPath { get { return String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { "Editors", this.GetType().FullName }); } } } }