Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

DataStorage: Store settings type-safe

Rate me:
Please Sign up or sign in to vote.
4.50/5 (3 votes)
8 Aug 2012GPL33 min read 26.1K   234   9  
Shows how to use the DataStorage classes to generate type-safe settings classes.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.ComponentModel;
using Aga.Controls.Tree;
using System.Drawing;

namespace pdfforge.DataStorageGenerator.DataGeneration
{
    public enum ClassType
    {
        Class,
        Struct
    }
    
    public class DataClass : IDataElement
    {
        private string name;
        private List<IDataElement> values = new List<IDataElement>();

        private Dictionary<string, string> customCode = new Dictionary<string, string>();

        private bool _isReadOnly = false;
        private ClassType _classType = ClassType.Class;

        [Description("Set whether this class will be generated writable or read-only")]
        public bool ReadOnly
        {
            get { return _isReadOnly; }
            set { _isReadOnly = value; }
        }

        [DefaultValue(ClassType.Class), Description("Set the type of which the class will be generated")]
        public ClassType ClassType
        {
            get { return _classType; }
            set { _classType = value; }
        }

        [Description("The name of the class")]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [Browsable(false)]
        public Image Icon
        {
            get
            {
                return new Bitmap(DataStorageGenerator.Properties.Resources.Class);
            }
        }

        public DataClass(string name)
        {
            this.name = name;
        }

        public DataClass(XmlNode node)
        {
            this.name = node.Attributes["name"].Value;
            if (this.name.Length == 0)
            {
                name = "NewClass";
            }

            foreach (XmlNode n in node.ChildNodes)
            {
                switch(n.Name) {
                    case "class":
                        xmlAddClass(n);
                        break;
                    case "value":
                        xmlAddValue(n);
                        break;
                    default:
                        throw new Exception("Unknown XML Node: " + n.Name);
                }
            }
        }

        private void xmlAddClass(XmlNode n)
        {
            try
            {
                DataClass val = new DataClass(n);
                values.Add(val);
            }
            catch { }
        }

        private void xmlAddValue(XmlNode n)
        {
            string type = "";

            try
            {
                type = n.Attributes["type"].Value;
            }
            catch { }

            if (type != "")
            {
                DataValue val = null;
                switch (type)
                {
                    case "value":
                        val = new SimpleValue(n);
                        break;
                    default:
                        throw new Exception("Type not known");
                }
                values.Add(val);
            }
        }

        public System.Collections.IEnumerable getChildren()
        {
            return values;
        }

        public bool hasChildren()
        {
            return values.Count > 0;
        }

        public bool propertyExists(string name)
        {
            foreach (IDataElement v in values)
            {
                if (v.getName().Equals(name))
                    return true;
            }

            return false;
        }

        public void addProperty(string name)
        {
            addProperty(new SimpleValue(name, DataType.String));
        }

        public void addProperty(DataValue value)
        {
            if (propertyExists(value.getName()))
                throw new ArgumentException("A property with the name " + value.getName() + " already exists!");
            
            values.Add(value);
        }

        public void addClass(DataClass value)
        {
            if (propertyExists(value.getName()))
                throw new ArgumentException("A property with the name " + value.getName() + " already exists!");

            values.Add(value);
        }

        public void addClass(string name)
        {
            DataClass c = new DataClass(name);
            addClass(c);
        }

        public bool classExists(string name)
        {
            foreach (IDataElement e in values)
            {
                if (e is DataClass)
                {
                    DataClass c = e as DataClass;
                    if (c.classExists(name))
                        return true;
                }
            }
            return false;
        }

        public void collectSubClasses(List<DataClass> classes)
        {
            foreach (IDataElement e in values)
            {
                if (e is DataClass)
                {
                    DataClass c = e as DataClass;
                    classes.Add(c);
                    c.collectSubClasses(classes);
                }
            }
        }

        public void removeElement(string name)
        {
            foreach (IDataElement v in values)
            {
                if (v.getName().Equals(name))
                {
                    values.Remove(v);
                    return;
                }
            }
        }

        public string getName()
        {
            return name;
        }

        public IEnumerable<DataClass> getClasses()
        {
            List<DataClass> lst = new List<DataClass>();
            foreach (IDataElement e in values)
            {
                if (e is DataClass)
                    lst.Add(e as DataClass);
            }

            return lst;
        }

        public void writeXml(XmlTextWriter textWriter)
        {
            textWriter.WriteStartElement("class");
            textWriter.WriteStartAttribute("name");
            textWriter.WriteString(name);
            textWriter.WriteEndAttribute();

            textWriter.WriteStartAttribute("readonly");
            textWriter.WriteString(_isReadOnly.ToString());
            textWriter.WriteEndAttribute();
            textWriter.WriteStartAttribute("classtype");
            textWriter.WriteString(_classType.ToString());
            textWriter.WriteEndAttribute();

            foreach (IDataElement value in values)
                value.writeXml(textWriter);

            textWriter.WriteEndElement();
        }

        public DataValue getProperty(string name)
        {
            foreach (DataValue v in values)
                if (v.getName().Equals(name))
                    return v;
            return null;
        }

        public List<string> getProperties()
        {
            List<string> myValues = new List<string>();

            foreach (DataValue v in values)
            {
                myValues.Add(v.getName());
            }

            return myValues;
        }

        public void parseCurrentClass(string file) {
            string start = "// START_CUSTOM_SECTION:";
            string end = "// END_CUSTOM_SECTION";

            if (!File.Exists(file))
                return;

            try
            {
                customCode.Clear();
                string text = File.ReadAllText(file);
                int pos = text.IndexOf(start);
                int pos2;
                int pos3;

                string sectionName = "";
                string sectionContent = "";

                while (pos >= 0)
                {
                    pos3 = text.IndexOf('\n', pos);
                    pos2 = text.IndexOf(end, pos);
                    sectionName = text.Substring(pos + start.Length, pos3 - pos - start.Length);
                    sectionName = sectionName.Trim();
                    sectionContent = text.Substring(pos3 + 1, pos2 - pos3 - 1);
                    if (sectionName != "")
                    {
                        customCode.Add(sectionName, sectionContent);
                    }

                    pos = text.IndexOf(start, pos2);
                }
            }
            catch { }
        }

        private string getPropertyName()
        {
            string tmp = Name;
            tmp = char.ToLower(tmp[0]) + tmp.Substring(1);
            return tmp;
        }

        public void generatePropertyCS(ClassStringBuilder sb)
        {
            string tmp = getPropertyName();
            sb.AppendLine("public " + Name + " " + tmp + " = new " + Name + "();");
        }

        public void generateLoadPropertyCS(ClassStringBuilder sb, string path)
        {
            string tmp = getPropertyName();
            sb.AppendLine(tmp + ".readValues(data);");
        }

        public void generateSavePropertyCS(ClassStringBuilder sb, string path)
        {
            string tmp = getPropertyName();
            sb.AppendLine(tmp + ".storeValues(data);");
        }

        /*public void generateCS(ClassStringBuilder sb)
        {
            generateCS(sb, Name + "\\", true);
        }*/

        public void generateCS(ClassStringBuilder sb, string path)
        {
            generateCS(sb, path + Name + "\\", "", path.Length == 0);
        }

        public void generateCS(ClassStringBuilder sb, string path, string nameSpace)
        {
            generateCS(sb, path + Name + "\\", nameSpace, path.Length == 0);
        }

        protected void generateCS(ClassStringBuilder sb, string path, string nameSpace, bool isRoot)
        {
            sb.AppendLine("using System;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine("using System.Text;");
            sb.AppendLine("using pdfforge.DataStorage;");

            addCustomCodeSection(sb, "INCLUDES", true);

            sb.AppendLine("");
            sb.AppendLine("// ! This file is generated automatically.");
            sb.AppendLine("// ! Do not edit it outside the sections for custom code.");
            sb.AppendLine("// ! These changes will be deleted during the next generation run");
            sb.AppendLine("");

            if (!String.IsNullOrEmpty(nameSpace))
            {
                sb.AppendLine("namespace " + nameSpace);
                sb.AppendLine("{");
                sb.incIndent();
            }
            
            sb.AppendLine("public class " + name + "{");
            sb.incIndent();

            if (isRoot)
            {
                sb.AppendLine("private Data data = Data.createDataStorage();");
                sb.AppendLine("private DataReader dataReader = null;");
                sb.AppendLine("private DataWriter dataWriter = null;");
            }
            sb.AppendLine();

            foreach (IDataElement value in values)
            {
                value.generatePropertyCS(sb);
            }

            if (isRoot)
            {
                sb.AppendLine("");
                sb.AppendLine("public " + name + "(DataReader dataReader, DataWriter dataWriter) {");
                sb.incIndent();
                sb.AppendLine("this.dataReader = dataReader;");
                sb.AppendLine("this.dataWriter = dataWriter;");
                sb.AppendLine("data = Data.createDataStorage();");
                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine();

                sb.AppendLine("public void setDataReader(DataReader dataReader) {");
                sb.incIndent();
                sb.AppendLine("this.dataReader = dataReader;");
                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine();

                sb.AppendLine("public void setDataWriter(DataWriter dataWriter) {");
                sb.incIndent();
                sb.AppendLine("this.dataWriter = dataWriter;");
                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine("");

                sb.AppendLine("public bool loadData(DataReader dataReader, string path) {");
                sb.incIndent();

                sb.AppendLine("try {");
                sb.incIndent();
                sb.AppendLine("data.clear();");
                sb.AppendLine("dataReader.setData(data);");
                sb.AppendLine("dataReader.readData(path);");
                sb.AppendLine("readValues(data);");
                sb.AppendLine("return true;");
                sb.decIndent();
                sb.AppendLine("} catch { return false; }");
                sb.AppendLine();

                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine("");

                sb.AppendLine("public bool loadData(string path) {");
                sb.incIndent();

                sb.AppendLine("return loadData(dataReader, path);");
                sb.AppendLine();

                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine("");

                sb.AppendLine("public bool saveData(DataWriter dataWriter, string path) {");
                sb.incIndent();

                sb.AppendLine("try {");
                sb.incIndent();
                sb.AppendLine("data.clear();");
                sb.AppendLine("storeValues(data);");
                sb.AppendLine("dataWriter.setData(data);");
                sb.AppendLine("dataWriter.writeData(path);");
                sb.AppendLine("return true;");
                sb.decIndent();
                sb.AppendLine("} catch { return false; }");
                sb.AppendLine();

                sb.decIndent();
                sb.AppendLine("}");
                sb.AppendLine("");

                sb.AppendLine("public bool saveData(string path) {");
                sb.incIndent();

                sb.AppendLine("return saveData(dataWriter, path);");
                sb.AppendLine();

                sb.decIndent();
                sb.AppendLine("}");
            }

            sb.AppendLine();

            sb.AppendLine("public void readValues(Data data) {");
            sb.incIndent();

            foreach (IDataElement value in values)
            {
                value.generateLoadPropertyCS(sb, path);
            }

            sb.decIndent();
            sb.AppendLine("}");
            sb.AppendLine("");

            sb.AppendLine("public void storeValues(Data data) {");
            sb.incIndent();

            foreach (IDataElement value in values)
            {
                value.generateSavePropertyCS(sb, path);
            }

            sb.decIndent();
            sb.AppendLine("}");
            sb.AppendLine("");

            addCustomCodeSection(sb, "GENERAL", true);

            foreach (KeyValuePair<string, string> section in customCode)
            {
                addCustomCodeSection(sb, section.Key, false);
            }

            // Close Class
            sb.decIndent();
            sb.AppendLine("}");

            // Close namespace
            if (!String.IsNullOrEmpty(nameSpace))
            {
                sb.decIndent();
                sb.AppendLine("}");
            }
        }

        /// <summary>
        /// Adds a custom code section to the generated class. Things that are inserted in these sections will not be removed during a regeneration
        /// </summary>
        /// <param name="sb">The current StringBuilder</param>
        /// <param name="section">Name of the code section</param>
        /// <param name="delete">If false, the section will not be rermoved from the section list and will be added again on the bottom of the file</param>
        private void addCustomCodeSection(ClassStringBuilder sb, string section, bool delete)
        {
            string code;
            if (customCode.TryGetValue(section, out code))
            {
                if (delete)
                    customCode.Remove(section);
            }
            else
                code = "";
            int indent = sb.getIndent();
            sb.setIndent(0);
            sb.AppendLine("// Custom Code starts here");
            sb.AppendLine("// START_CUSTOM_SECTION:" + section);
            sb.Append(code);
            sb.AppendLine("// END_CUSTOM_SECTION:" + section);
            sb.AppendLine("// Custom Code ends here. Do not edit below");
            sb.setIndent(indent);
            sb.AppendLine();
        }
    }
}

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 GNU General Public License (GPLv3)


Written By
pdfforge GbR
Germany Germany
Philip is a Software Architect with severaly years of experience. He studied business IT in the University of Wedel, Germany, and has reached his Masters degree in 2010. Back in 2002, he started his so far best-known software PDFCreator. The second developer joined two years later and since then, both constantly improve this piece of open source software.

Comments and Discussions