ide/Project: Fixes to prevent ever saving empty arrays/objects [ Comprehensive fix...
authorJerome St-Louis <jerome@ecere.com>
Sun, 16 Oct 2011 04:43:25 +0000 (00:43 -0400)
committerJerome St-Louis <jerome@ecere.com>
Sun, 16 Oct 2011 04:43:25 +0000 (00:43 -0400)
e.g. to fix a .epj with arrays/objects already empty
Implemented as properties in ProjectNode: options, platforms and configurations; Smart handling of topNode mirroring project's
Implemented as properties in ProjectConfig: options and platforms
Implemented as properties in Project: options and platforms
When these properties are set, the ownership of the value is transferred to the object
Careful not to call delete on those properties, the assignment to null will crash! http://ecere.com/mantis/view.php?id=658
The Project's topNode's properties automatically map the Project's, so they should not be accessed within ProjectNode as data members

ide/src/ProjectSettings.ec
ide/src/dialogs/NewProjectDialog.ec
ide/src/project/Project.ec
ide/src/project/ProjectConfig.ec
ide/src/project/ProjectNode.ec

index 078717c..e426c21 100644 (file)
@@ -446,7 +446,7 @@ class OptionBox<class Z> : CommonControl
                         }
                      }
                      if(!c.platforms.count)
-                        delete c.platforms;
+                        c.platforms = null;
                   }
                   Load();
                   return;
@@ -468,7 +468,7 @@ class OptionBox<class Z> : CommonControl
                }
             }
             if(!currentNode.configurations.count)
-               delete currentNode.configurations;
+               currentNode.configurations = null;
          }
          Load();
          return;
@@ -496,7 +496,7 @@ class OptionBox<class Z> : CommonControl
                }
             }
             if(!currentNode.platforms.count)
-               delete currentNode.platforms;
+               currentNode.platforms = null;
          }
          Load();
          return;
@@ -1668,9 +1668,11 @@ class BuildTab : Tab
 
       project.config = null;
 
+      /* // THIS IS NOW AUTOMATED WITH A project CHECK IN ProjectNode
       project.configurations = project.topNode.configurations;
       project.platforms = project.topNode.platforms;
       project.options = project.topNode.options;
+      */
 
       if(project.topNode.configurations)
       {
index 0c1801f..945bfa5 100644 (file)
@@ -140,7 +140,7 @@ class NewProjectDialog : Window
             topNode.type = NodeTypes::project;
             config = debug;
          };
-         project.topNode.options = project.options =
+         /*project.topNode.options = */project.options =
          {
             warnings = all;
             // TOFIX: Precomp problems withou the extra ( )
@@ -408,7 +408,7 @@ class QuickProjectDialog : Window
             topNode.type = NodeTypes::project;
             config = debug;
          };
-         project.topNode.options = project.options =
+         /*project.topNode.options = */project.options =
          {
             warnings = all;
             // TOFIX: Precomp problems withou the extra ( )
index 164de70..b321b98 100644 (file)
@@ -636,8 +636,36 @@ public:
    String description;
    String license;
 
-   ProjectOptions options;
-   Array<PlatformOptions> platforms;
+   property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
+   property Array<PlatformOptions> platforms
+   {
+      get { return platforms; }
+      set
+      {
+         if(platforms) { platforms.Free(); delete platforms; }
+         if(value)
+         {
+            List<PlatformOptions> empty { };
+            Iterator<PlatformOptions> it { value };
+            platforms = value;
+            for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
+            for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
+            delete empty;
+         }
+      }
+      isset
+      {
+         if(platforms)
+         {
+            for(p : platforms)
+            {
+               if(p.options && !p.options.isEmpty)
+                  return true;
+            }
+         }
+         return false;
+      }
+   }
    List<ProjectConfig> configurations;
    LinkList<ProjectNode> files;
    String resourcesPath;
@@ -645,6 +673,8 @@ public:
 
 private:
    // topNode.name holds the file name (.epj)
+   ProjectOptions options;
+   Array<PlatformOptions> platforms;
    ProjectNode topNode { type = project, icon = epjFile, files = LinkList<ProjectNode>{ }, project = this };
    ProjectNode resNode;
 
@@ -656,9 +686,11 @@ private:
 
    ~Project()
    {
+      /* // THIS IS NOW AUTOMATED WITH A project CHECK IN ProjectNode
       topNode.configurations = null;
       topNode.platforms = null;
       topNode.options = null;
+      */
 
       if(platforms) { platforms.Free(); delete platforms; }
       if(configurations) { configurations.Free(); delete configurations; }
@@ -3278,9 +3310,10 @@ Project LoadProject(char * filePath)
             project.topNode.name = CopyString(project.config.options.targetFileName);
          }
 
+         /* // THIS IS NOW AUTOMATED WITH A project CHECK IN ProjectNode
          project.topNode.configurations = project.configurations;
          project.topNode.platforms = project.platforms;
-         project.topNode.options = project.options;
+         project.topNode.options = project.options;*/
       }
    }
    return project;
index 88ee1c6..0a1e462 100644 (file)
@@ -395,7 +395,7 @@ public class PlatformOptions
 {
 public:
    String name;
-   ProjectOptions options;
+   property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
 
    ~PlatformOptions()
    {
@@ -411,19 +411,50 @@ public:
          options ? options.Copy() : null
       };
    }
+private:
+   ProjectOptions options;
 }
 
 class ProjectConfig : struct
 {
 public:
    String name;
-   ProjectOptions options;
-   Array<PlatformOptions> platforms;
+   property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
+   property Array<PlatformOptions> platforms
+   {
+      get { return platforms; }
+      set
+      {
+         if(platforms) { platforms.Free(); delete platforms; }
+         if(value)
+         {
+            List<PlatformOptions> empty { };
+            Iterator<PlatformOptions> it { value };
+            platforms = value;
+            for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
+            for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
+            delete empty;
+         }
+      }
+      isset
+      {
+         if(platforms)
+         {
+            for(p : platforms)
+            {
+               if(p.options && !p.options.isEmpty)
+                  return true;
+            }
+         }
+         return false;
+      }
+   }
 
 private:
-
+   ProjectOptions options;
    bool makingModified;
    bool compilingModified, linkingModified, symbolGenModified;
+   Array<PlatformOptions> platforms;
 
    ~ProjectConfig()
    {
index c44a5ce..cffbfde 100644 (file)
@@ -245,9 +245,108 @@ public:
    };
 
    LinkList<ProjectNode> files;
-   ProjectOptions options;
-   Array<PlatformOptions> platforms;
-   List<ProjectConfig> configurations;
+   property ProjectOptions options
+   {
+      get { return project ? project.options : options; }
+      set { if(project) project.options = value; else options = value; }
+      isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
+   }
+   property Array<PlatformOptions> platforms
+   {
+      get { return project ? project.platforms : platforms; }
+      set
+      {
+         if(project) { project.platforms = value; }
+         else
+         {
+            if(platforms) { platforms.Free(); delete platforms; }
+            if(value)
+            {
+               List<PlatformOptions> empty { };
+               Iterator<PlatformOptions> it { value };
+               platforms = value;
+               for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
+               for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
+               delete empty;
+            }
+         }
+      }
+      isset
+      {
+         Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
+         if(platforms)
+         {
+            for(p : platforms)
+            {
+               if(p.options && !p.options.isEmpty)
+                  return true;
+            }
+         }
+         return false;
+      }
+   }
+   property List<ProjectConfig> configurations
+   {
+      get { return project ? project.configurations : configurations; }
+      set
+      {
+         if(project) { project.configurations = value; }
+         else
+         {
+            if(configurations) { configurations.Free(); delete configurations; }
+            if(value)
+            {
+               List<ProjectConfig> empty { };
+               Iterator<ProjectConfig> it { value };
+               configurations = value;
+               for(c : configurations)
+               {
+                  bool somethingSet = c.options && !c.options.isEmpty;
+                  // TODO: Implement isset keyword
+                  if(!somethingSet && c.platforms && c.platforms.count)
+                  {
+                     for(p : c.platforms)
+                     {
+                        if(p.options && !p.options.isEmpty)
+                        {
+                           somethingSet = true;
+                           break;
+                        }
+                     }
+                  }
+                  if(!somethingSet)
+                     empty.Add(c);
+               }
+               for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
+               delete empty;
+            }
+         }
+      }
+      isset
+      {
+         if(!parent) return true;
+         if(configurations)
+         {
+            for(c : configurations)
+            {
+               bool somethingSet = c.options && !c.options.isEmpty;
+               if(!somethingSet && c.platforms && c.platforms.count)
+               {
+                  for(p : c.platforms)
+                  {
+                     if(p.options && !p.options.isEmpty)
+                     {
+                        somethingSet = true;
+                        break;
+                     }
+                  }
+               }
+               return somethingSet;
+            }
+         }
+         return false;
+      }
+   }
 
    property ProjectConfig config
    {
@@ -255,10 +354,6 @@ public:
       {
          Project prj;
          ProjectConfig result = null;
-         /*if(configurations)
-            printf("test\n");
-         if(prj)
-            printf("test\n");*/
          if(configurations && (prj = property::project) && prj.config)
          {
             const char * projectConfigName = prj.config.name;
@@ -278,10 +373,10 @@ public:
    ProjectConfig GetMatchingNodeConfig(ProjectConfig config)
    {
       ProjectConfig nodeConfig = null;
-      if(configurations)
+      if(property::configurations)
       {
          const char * configName = config.name;
-         for(cfg : configurations)
+         for(cfg : property::configurations)
          {
             if(!strcmpi(cfg.name, configName))
             {
@@ -298,7 +393,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool memoryGuard = localMemoryGuard;
          String defaultNameSpace = localDefaultNameSpace;
          SetBool strictNameSpaces = localStrictNameSpaces;
@@ -317,7 +412,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool memoryGuard = localMemoryGuard;
          if(!memoryGuard)
          {
@@ -332,7 +427,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          String defaultNameSpace = localDefaultNameSpace;
          if(!defaultNameSpace)
          {
@@ -347,7 +442,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool strictNameSpaces = localStrictNameSpaces;
          if(!strictNameSpaces)
          {
@@ -362,7 +457,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool noLineNumbers = localNoLineNumbers;
          if(!noLineNumbers)
          {
@@ -442,9 +537,10 @@ public:
       // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
       while((node = nodeStack.lastIterator.data))
       {
-         if(node.options && node.options.preprocessorDefinitions)
+         ProjectOptions nodeOptions = node.property::options;
+         if(nodeOptions && nodeOptions.preprocessorDefinitions)
          {
-            for(def : node.options.preprocessorDefinitions)
+            for(def : nodeOptions.preprocessorDefinitions)
                perFilePreprocessorDefs.Add(CopyString(def));
          }
          if(config && config.options && config.options.preprocessorDefinitions)
@@ -452,9 +548,9 @@ public:
             for(def : config.options.preprocessorDefinitions)
                perFilePreprocessorDefs.Add(CopyString(def));
          }
-         if(node.options && node.options.includeDirs)
+         if(nodeOptions && nodeOptions.includeDirs)
          {
-            for(dir : node.options.includeDirs)
+            for(dir : nodeOptions.includeDirs)
                perFileIncludeDirs.Add(CopySystemPath(dir));
          }
          if(config && config.options && config.options.includeDirs)
@@ -468,6 +564,9 @@ public:
    }
 
 private:
+   ProjectOptions options;
+   Array<PlatformOptions> platforms;
+   List<ProjectConfig> configurations;
    ProjectNodeType nodeType;
    ProjectNode parent;
    char * name;
@@ -505,9 +604,9 @@ private:
       {
          for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
       }
-      if(configurations)
+      if(property::configurations)
       {
-         for(c : configurations; !strcmp(c.name, oldName))
+         for(c : property::configurations; !strcmp(c.name, oldName))
          {
             delete c.name;
             c.name = CopyString(newName);
@@ -521,9 +620,9 @@ private:
       {
          for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
       }
-      if(configurations)
+      if(property::configurations)
       {
-         Iterator<ProjectConfig> c { configurations };
+         Iterator<ProjectConfig> c { property::configurations };
          while(c.Next())
          {
             ProjectConfig config = c.data;
@@ -534,10 +633,8 @@ private:
                break;
             }
          }
-         if(!configurations.count)
-         {
-            delete configurations;
-         }
+         if(!property::configurations.count)
+            property::configurations = null;
       }
    }
 
@@ -550,20 +647,20 @@ private:
          backupNode.files = { };
          for(f : files) backupNode.files.Add(f.Backup());
       }
-      if(options)
-         backupNode.options = options.Copy();
+      if(property::options)
+         backupNode.options = property::options.Copy();
 
-      if(platforms)
+      if(property::platforms)
       {
          backupNode.platforms = { };
-         for(p : platforms)
+         for(p : property::platforms)
             backupNode.platforms.Add(p.Copy());
       }
 
-      if(configurations)
+      if(property::configurations)
       {
          backupNode.configurations = { };
-         for(c : configurations)
+         for(c : property::configurations)
             backupNode.configurations.Add(c.Copy());
       }
       return backupNode;
@@ -581,28 +678,19 @@ private:
          }
       }
 
-      delete options;
-      if(platforms)
-      {
-         platforms.Free();
-         delete platforms;
-      }
-      if(configurations)
-      {
-         configurations.Free();
-         delete configurations;
-      }
-
-      options = backupNode.options ? backupNode.options.Copy() : null;
+      property::options = backupNode.options ? backupNode.options.Copy() : null;
       if(backupNode.platforms)
       {
-         platforms = { };
+         Array<PlatformOptions> platforms { };
+         property::platforms = platforms;
+
          for(p : backupNode.platforms)
             platforms.Add(p.Copy());
       }
       if(backupNode.configurations)
       {
-         configurations = { };
+         List<ProjectConfig> configurations { };
+         property::configurations = configurations;
          for(c : backupNode.configurations)
             configurations.Add(c.Copy());
       }
@@ -663,7 +751,7 @@ private:
       if(!needClass)
       {
          // TOCHECK: Called from JSON writer
-         if(nodeType == file && !options && !configurations && !platforms && name)
+         if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
          {
             strcpy(tempString, "\"");
             strcat(tempString, property::fileName);
@@ -685,14 +773,15 @@ private:
          files.Free();
          delete files;
       }
-      delete options;
+      if(!project)
+         delete options;
 
-      if(platforms)
+      if(!project && platforms)
       {
          platforms.Free();
          delete platforms;
       };
-      if(configurations)
+      if(!project && configurations)
       {
          configurations.Free();
          delete configurations;
@@ -848,6 +937,9 @@ private:
       // note: unknown platform is for common
       Platform platform;
       ProjectConfig config = property::config;
+      ProjectOptions options = property::options;
+      Array<PlatformOptions> platforms = property::platforms;
+      List<ProjectConfig> configurations = property::configurations;
 
       if(parent)
          parent.CollectExclusionInfo(output);
@@ -1206,13 +1298,14 @@ private:
 
       while((node = nodeStack.lastIterator.data))
       {
+         ProjectOptions nodeOptions = node.property::options;
          ProjectConfig config = node.config;
-         if(node.options && node.options.preprocessorDefinitions)
-            OutputListOption(f, "D", node.options.preprocessorDefinitions, inPlace, false);
+         if(nodeOptions && nodeOptions.preprocessorDefinitions)
+            OutputListOption(f, "D", nodeOptions.preprocessorDefinitions, inPlace, false);
          if(config && config.options && config.options.preprocessorDefinitions)
             OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
-         if(node.options && node.options.includeDirs)
-            OutputListOption(f, "I", node.options.includeDirs, inPlace, true);
+         if(nodeOptions && nodeOptions.includeDirs)
+            OutputListOption(f, "I", nodeOptions.includeDirs, inPlace, true);
          if(config && config.options && config.options.includeDirs)
             OutputListOption(f, "I", config.options.includeDirs, inPlace, true);