Click here to Skip to main content
15,885,985 members
Articles / Containers / Docker

SVG Artiste - An SVG Editor

Rate me:
Please Sign up or sign in to vote.
4.69/5 (23 votes)
3 Aug 2010CPOL14 min read 95.9K   15.4K   93  
A Vector based tool to create and edit SVG images
/***************************************************************************
 *   CopyRight (C) 2009 by Cristinel Mazarine                              *
 *   Author:   Cristinel Mazarine                                          *
 *   Contact:  cristinel@osec.ro                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the Crom Free License as published by           *
 *   the SC Crom-Osec SRL; version 1 of the License                        *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   Crom Free License for more details.                                   *
 *                                                                         *
 *   You should have received a copy of the Crom Free License along with   *
 *   this program; if not, write to the contact@osec.ro                    *
 ***************************************************************************/

using System;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Collections.Generic;
using System.Drawing;

namespace Crom.Controls.Docking
{
   /// <summary>
   /// Serializer for dock state
   /// </summary>
   public class DockStateSerializer
   {
      #region Delegates

      /// <summary>
      /// Form factory handler
      /// </summary>
      /// <param name="identifier">identifier</param>
      /// <returns>form created</returns>
      public delegate Form FormFactoryHandler(Guid identifier);

      #endregion Delegates

      #region Embedded types

      /// <summary>
      /// Control size info
      /// </summary>
      private class ControlSizeInfo
      {
         #region Fields

         private Control   _control    = null;
         private int       _width      = 0;
         private int       _height     = 0;

         #endregion Fields

         #region Instance

         /// <summary>
         /// Constructor
         /// </summary>
         /// <param name="control">control</param>
         /// <param name="width">width</param>
         /// <param name="height">height</param>
         public ControlSizeInfo(Control control, int width, int height)
         {
            _control    = control;
            _width   = width;
            _height  = height;
         }

         #endregion Instance

         #region Public section

         /// <summary>
         /// Accessor of the control
         /// </summary>
         public Control Control
         {
            get { return _control; }
         }

         /// <summary>
         /// Accessor of the width
         /// </summary>
         public int Width
         {
            get { return _width; }
         }

         /// <summary>
         /// Accessor of the height
         /// </summary>
         public int Height
         {
            get { return _height; }
         }

         /// <summary>
         /// Text representation
         /// </summary>
         /// <returns>text</returns>
         public override string ToString()
         {
            return Control.ToString() + " W:" + Width.ToString() + " H:" + Height.ToString();
         }

         #endregion Public section
      }

      #endregion Embedded types

      #region Fields

      private string          _savePath         = null;
      private DockContainer   _container        = null;
      private FormWrapper     _host             = null;

      #endregion Fields

      #region Instance

      /// <summary>
      /// Constructor
      /// </summary>
      /// <param name="container">container</param>
      public DockStateSerializer(DockContainer container)
      {
         _container     = container;
         _host          = new FormWrapper(container, 0, 0);
         string appName = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
         _savePath      = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), appName);
         _savePath      = Path.Combine(_savePath, Resources.StateFileName);
      }

      #endregion Instance

      #region Public section

      /// <summary>
      /// Accessor of the path where to save the state serialization
      /// </summary>
      public string SavePath
      {
         get { return _savePath; }
         set { _savePath = value; }
      }

      /// <summary>
      /// Save the state of the container
      /// </summary>
      public void Save()
      {
         XmlDocument xmlDocument = new XmlDocument();

         XmlNode xmlForms = xmlDocument.AppendChild(xmlDocument.CreateElement(XmlTags.TagForms));

         for (int index = 0; index < _host.ControlsCount; index++)
         {
            DockableContainer container = _host.GetControlAt(index) as DockableContainer;
            if (container == null)
            {
               continue;
            }

            SaveContainer(container, Guid.Empty, xmlForms);
         }

         if (Directory.Exists(Path.GetDirectoryName(SavePath)) == false)
         {
            Directory.CreateDirectory(Path.GetDirectoryName(SavePath));
         }

         xmlDocument.Save(SavePath);
      }

      /// <summary>
      /// Save container
      /// </summary>
      /// <param name="container">container</param>
      /// <param name="containerOwnerId">container owner id</param>
      /// <param name="xmlForms">forms node</param>
      /// <returns>container id</returns>
      private Guid SaveContainer(DockableContainer container, Guid containerOwnerId, XmlNode xmlForms)
      {
         if (container.SingleChild != null)
         {
            return SaveView(container.SingleChild, containerOwnerId, xmlForms);
         }

         if (container.LinkedView != null)
         {
            return SaveView(container.LinkedView, containerOwnerId, xmlForms);
         }
         
         if (container.LeftPane != null)
         {
            Guid containerId = SaveContainer(container.LeftPane,  containerOwnerId, xmlForms);
            SaveContainer(container.RightPane, containerId, xmlForms);

            return containerId;
         }
         
         if (container.TopPane != null)
         {
            Guid containerId = SaveContainer(container.TopPane, containerOwnerId, xmlForms);
            SaveContainer(container.BottomPane, containerId, xmlForms);

            return containerId;
         }

         throw new NotSupportedException();
      }

      /// <summary>
      /// Load state
      /// </summary>
      /// <param name="clear">clear the existing forms</param>
      /// <param name="formsFactory">forms factory</param>
      public void Load(bool clear, FormFactoryHandler formsFactory)
      {
         if (clear)
         {
            _container.Clear();
         }

         XmlDocument xmlDocument = new XmlDocument();
         xmlDocument.Load(SavePath);

         _container.SuspendLayout();

         DockableFormInfo selected = null;
         List<DockableFormInfo> autoHide = new List<DockableFormInfo>();
         List<ControlSizeInfo> formsSize = LoadForms(xmlDocument, formsFactory, autoHide, out selected);

         RestoreSizes(formsSize);

         foreach (DockableFormInfo toAuto in autoHide)
         {
            _container.SetAutoHide(toAuto, true);
         }

         if (selected != null)
         {
            selected.IsSelected = true;
         }

         _container.ResumeLayout(true);
      }

      #endregion Public section

      #region Private section

      /// <summary>
      /// Save the view
      /// </summary>
      /// <param name="view">view to save</param>
      /// <param name="viewOwnerId">view owner identifier</param>
      /// <param name="xmlForms">forms node</param>
      /// <returns>identifier of the view</returns>
      private Guid SaveView(FormsTabbedView view, Guid viewOwnerId, XmlNode xmlForms)
      {
         Form firstDockedPage = null;
         for (int childIndex = 0; childIndex < view.Count; childIndex++)
         {
            DockableFormInfo childInfo = view.GetPageInfoAt(childIndex);
            if (childInfo.Dock != DockStyle.Fill)
            {
               firstDockedPage = childInfo.DockableForm;
               break;
            }
         }

         if (firstDockedPage == null)
         {
            firstDockedPage = view.GetPageAt(0);
         }

         DockableFormInfo info = _container.GetFormInfo(firstDockedPage);

         Save(info, viewOwnerId, xmlForms);

         for (int childIndex = 0; childIndex < view.Count; childIndex++)
         {
            DockableFormInfo siblingInfo = view.GetPageInfoAt(childIndex);
            if (siblingInfo == info)
            {
               continue;
            }

            Save(siblingInfo, info.Id, xmlForms);
         }

         return info.Id;
      }

      /// <summary>
      /// Save 
      /// </summary>
      /// <param name="info">info</param>
      /// <param name="parentId">parent id identifier</param>
      /// <param name="xmlForms">forms</param>
      private void Save(DockableFormInfo info, Guid parentId, XmlNode xmlForms)
      {
         XmlDocument xmlDocument = xmlForms.OwnerDocument;

         XmlNode xmlForm         = xmlForms.AppendChild(xmlDocument.CreateElement(XmlTags.TagForm));

         XmlNode xmlGuid         = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagGuid));
         XmlNode xmlAllowedDock  = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagAllowedDock));
         XmlNode xmlCurrentDock  = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagCurrentDock));
         XmlNode xmlCurrentMode  = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagCurrentMode));
         XmlNode xmlIsSelected   = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagIsSelected));
         XmlNode xmlIsAutoHide   = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagIsAutoHide));
         XmlNode xmlWidth        = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagWidth));
         XmlNode xmlHeight       = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagHeight));
         if (parentId != Guid.Empty)
         {
            XmlNode xmlParentGuid   = xmlForm.AppendChild(xmlDocument.CreateElement(XmlTags.TagParentGuid));
            xmlParentGuid.InnerText = parentId.ToString();
         }

         xmlGuid.InnerText          = info.Id.ToString();
         xmlAllowedDock.InnerText   = info.AllowedDock.ToString();
         xmlCurrentMode.InnerText   = info.DockMode.ToString();
         xmlIsSelected.InnerText    = info.IsSelected.ToString().ToLower();
         xmlIsAutoHide.InnerText    = info.IsAutoHideMode.ToString().ToLower();

         DockableContainer container = HierarchyUtility.GetClosestDockableContainer(info.DockableForm);

         xmlWidth.InnerText         = container.Width.ToString();
         xmlHeight.InnerText        = container.Height.ToString();

         if (parentId == Guid.Empty)
         {
            if (info.IsAutoHideMode == false)
            {
               xmlCurrentDock.InnerText = info.HostContainerDock.ToString();
            }
            else
            {
               xmlCurrentDock.InnerText = info.AutoHideSavedDock.ToString();
            }
         }
         else
         {
            xmlCurrentDock.InnerText = info.Dock.ToString();
         }
      }

      /// <summary>
      /// Load form
      /// </summary>
      /// <param name="xmlForm">xml form</param>
      /// <param name="formsFactory">forms factory</param>
      /// <param name="autoHide">list of autohide forms</param>
      /// <param name="selected">selected info</param>
      private ControlSizeInfo AddForm(XmlNode xmlForm, FormFactoryHandler formsFactory, List<DockableFormInfo> autoHide, out DockableFormInfo selected)
      {
         selected = null;

         XmlNode xmlGuid         = xmlForm.SelectSingleNode(XmlTags.TagGuid);
         XmlNode xmlParentGuid   = xmlForm.SelectSingleNode(XmlTags.TagParentGuid);
         XmlNode xmlAllowedDock  = xmlForm.SelectSingleNode(XmlTags.TagAllowedDock);
         XmlNode xmlCurrentDock  = xmlForm.SelectSingleNode(XmlTags.TagCurrentDock);
         XmlNode xmlCurrentMode  = xmlForm.SelectSingleNode(XmlTags.TagCurrentMode);
         XmlNode xmlIsSelected   = xmlForm.SelectSingleNode(XmlTags.TagIsSelected);
         XmlNode xmlIsAutoHide   = xmlForm.SelectSingleNode(XmlTags.TagIsAutoHide);
         XmlNode xmlWidth        = xmlForm.SelectSingleNode(XmlTags.TagWidth);
         XmlNode xmlHeight       = xmlForm.SelectSingleNode(XmlTags.TagHeight);

         Guid identifier            = new Guid(xmlGuid.InnerText);
         zAllowedDock allowedDock   = (zAllowedDock)Enum.Parse(typeof(zAllowedDock), xmlAllowedDock.InnerText);
         Form form                  = formsFactory(identifier);
         int width                  = Convert.ToInt32(xmlWidth.InnerText);
         int height                 = Convert.ToInt32(xmlHeight.InnerText);
         form.Width  = width;
         form.Height = height;

         DockableFormInfo info = _container.Add(form, allowedDock, identifier);

         if (Convert.ToBoolean(xmlIsSelected.InnerText))
         {
            selected = info;
         }

         if (Convert.ToBoolean(xmlIsAutoHide.InnerText))
         {
            autoHide.Add(info);
         }


         DockStyle currentDock = (DockStyle)Enum.Parse(typeof(DockStyle), xmlCurrentDock.InnerText);
         zDockMode currentMode = (zDockMode)Enum.Parse(typeof(zDockMode), xmlCurrentMode.InnerText);
         if (currentDock != DockStyle.None)
         {
            if (xmlParentGuid == null)
            {
               _container.DockForm(info, currentDock, currentMode);
            }
            else
            {
               Guid parentGuid = new Guid(xmlParentGuid.InnerText);
               DockableFormInfo parentInfo = _container.GetFormInfo(parentGuid);
               _container.DockForm(info, parentInfo, currentDock, currentMode);
            }
         }

         return new ControlSizeInfo(form, width, height);
      }

      /// <summary>
      /// Extract containers size info
      /// </summary>
      /// <param name="container">container</param>
      /// <param name="source">source</param>
      /// <param name="destination">destination</param>
      /// <returns>computed container size</returns>
      private static ControlSizeInfo ExtractContainersSizeInfo(DockableContainer container, List<ControlSizeInfo> source, List<ControlSizeInfo> destination)
      {
         DockableContainer currentContainer = container;
         if (currentContainer.SingleChild != null)
         {
            Size size = RemoveViewSizeInfo(currentContainer.SingleChild, source);
            ControlSizeInfo result = new ControlSizeInfo(container, size.Width, size.Height);
            destination.Add(result);
            return result;
         }
         
         if (currentContainer.TopPane != null)
         {
            ControlSizeInfo topSize    = ExtractContainersSizeInfo(container.TopPane, source, destination);
            ControlSizeInfo bottomSize = ExtractContainersSizeInfo(container.BottomPane, source, destination);

            Size size = new Size(Math.Max(topSize.Width, bottomSize.Width), topSize.Height + bottomSize.Height + container.TopPane.Splitter.Height);
            ControlSizeInfo result = new ControlSizeInfo(container, size.Width, size.Height);
            destination.Add(result);
            return result;
         }
         
         if (currentContainer.LeftPane != null)
         {
            ControlSizeInfo leftSize   = ExtractContainersSizeInfo(container.LeftPane, source, destination);
            ControlSizeInfo rightSize  = ExtractContainersSizeInfo(container.RightPane, source, destination);

            Size size = new Size(leftSize.Width + rightSize.Width + container.LeftPane.Splitter.Width, Math.Max(leftSize.Height, rightSize.Height));
            ControlSizeInfo result = new ControlSizeInfo(container, size.Width, size.Height);
            destination.Add(result);
            return result;
         }


         throw new NotSupportedException();
      }

      /// <summary>
      /// Move view size info
      /// </summary>
      /// <param name="view">view</param>
      /// <param name="source">source</param>
      /// <returns>view size</returns>
      private static Size RemoveViewSizeInfo(FormsTabbedView view, List<ControlSizeInfo> source)
      {
         Form form = view.GetPageAt(0);
         ControlSizeInfo firstInfo = GetInfo(form, source);

         for(int index = 0; index < view.Count; index++)
         {
            ControlSizeInfo info = GetInfo(view.GetPageAt(index), source);
            source.Remove(info);
         }

         return new Size(firstInfo.Width, firstInfo.Height);
      }

      /// <summary>
      /// Get form size info
      /// </summary>
      /// <param name="form">form </param>
      /// <param name="source">size infos</param>
      /// <returns>form size info</returns>
      private static ControlSizeInfo GetInfo(Form form, List<ControlSizeInfo> sizesInfo)
      {
         for (int index = 0; index < sizesInfo.Count; index++)
         {
            ControlSizeInfo info = sizesInfo[index];
            if (info.Control == form)
            {
               return info;
            }
         }

         return null;
      }

      /// <summary>
      /// Load forms 
      /// </summary>
      /// <param name="xmlDocument">document</param>
      /// <param name="formsFactory">forms factory</param>
      /// <returns>list of control size info</returns>
      /// <param name="autoHide">list of autohide forms</param>
      /// <param name="selected">selected info</param>
      private List<ControlSizeInfo> LoadForms(XmlDocument xmlDocument, FormFactoryHandler formsFactory, List<DockableFormInfo> autohide, out DockableFormInfo selected)
      {
         selected = null;

         List<ControlSizeInfo> formsSize = new List<ControlSizeInfo>();
         XmlNodeList xmlForms = xmlDocument.SelectNodes("//" + XmlTags.TagForms + "/" + XmlTags.TagForm);
         for (int index = 0; index < xmlForms.Count; index++)
         {
            XmlNode xmlForm = xmlForms[index];

            DockableFormInfo selectedForm = null;
            formsSize.Add(AddForm(xmlForm, formsFactory, autohide, out selectedForm));

            if (selectedForm != null)
            {
               selected = selectedForm;
            }
         }
         return formsSize;
      }

      /// <summary>
      /// Restore sizes
      /// </summary>
      /// <param name="formsSize">form sizes</param>
      private void RestoreSizes(List<ControlSizeInfo> formsSize)
      {
         while (formsSize.Count > 0)
         {
            ControlSizeInfo sizeInfo = formsSize[0];

            DockableContainer container = HierarchyUtility.GetClosestDockableContainer((Form)sizeInfo.Control);
            while (container.Parent.Handle != _container.Handle)
            {
               container = (DockableContainer)container.Parent;
            }

            List<ControlSizeInfo> containersSize = new List<ControlSizeInfo>();
            ExtractContainersSizeInfo(container, formsSize, containersSize);

            for (int index = containersSize.Count - 1; index >= 0; index--)
            {
               ControlSizeInfo info = containersSize[index];
               info.Control.Width   = info.Width;
               info.Control.Height  = info.Height;
            }
         }
      }

      #endregion Private section
   }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Singapore Singapore
He is a Microsoft technology enthusiast, who wish to create applications which others find useful.He loves making small tools and getting involved in architecting bigger systems.

He is currently working as a professional developer in a software development firm in .Net technologies.

He likes reading technical blogs, contributing to opensource and most importantly, enjoying life.

His ambition is to be an impressive software maker.

Comments and Discussions