ide: workspace: (#882) save workspace file (.ews) in json format.
authorRejean Loyer <rejean.loyer@gmail.com>
Thu, 4 Apr 2013 13:53:07 +0000 (09:53 -0400)
committerRejean Loyer <redj@ecere.com>
Mon, 16 Mar 2015 05:31:44 +0000 (01:31 -0400)
 - (#56) save opened files with relative file paths.
 - discard old or broken opened files entries.

ide/src/debugger/Debugger.ec
ide/src/designer/CodeEditor.ec
ide/src/dialogs/NewProjectDialog.ec
ide/src/ide.ec
ide/src/project/Project.ec
ide/src/project/ProjectConfig.ec
ide/src/project/ProjectView.ec
ide/src/project/Workspace.ec

index 408450e..6efff9f 100644 (file)
@@ -1205,22 +1205,25 @@ class Debugger
 
       Link bpLink, next;
       //_dpcl(_dpct, dplchan::debuggerCall, 0, "Debugger::MoveIcons()");
-      for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
+      if(ide.workspace.breakpoints)
       {
-         Breakpoint bp = (Breakpoint)(intptr)bpLink.data;
-         next = bpLink.next;
-
-         if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
+         for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
          {
-            if(bp.line > lineNumber || (bp.line == lineNumber && start))
+            Breakpoint bp = (Breakpoint)(intptr)bpLink.data;
+            next = bpLink.next;
+
+            if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
             {
-               if(move < 0 && (bp.line < lineNumber - move))
-                  ide.workspace.RemoveBreakpoint(bp);
-               else
+               if(bp.line > lineNumber || (bp.line == lineNumber && start))
                {
-                  bp.line += move;
-                  ide.breakpointsView.UpdateBreakpoint(bp.row);
-                  ide.workspace.Save();
+                  if(move < 0 && (bp.line < lineNumber - move))
+                     ide.workspace.RemoveBreakpoint(bp);
+                  else
+                  {
+                     bp.line += move;
+                     ide.breakpointsView.UpdateBreakpoint(bp.row);
+                     ide.workspace.Save();
+                  }
                }
             }
          }
@@ -4770,21 +4773,24 @@ class Breakpoint : struct
 {
    class_no_expansion;
 
-   char * function;
+public:
    property const char * function { set { delete function; if(value) function = CopyString(value); } }
-   char * relativeFilePath;
    property const char * relativeFilePath { set { delete relativeFilePath; if(value) relativeFilePath = CopyString(value); } }
-   char * absoluteFilePath;
    property const char * absoluteFilePath { set { delete absoluteFilePath; if(value) absoluteFilePath = CopyString(value); } }
    char * location;
    property const char * location { set { delete location; if(value) location = CopyString(value); } }
    int line;
    bool enabled;
-   int hits;
-   int breaks;
    int ignore;
    int level;
    Watch condition;
+
+private:
+   char * function;
+   char * relativeFilePath;
+   char * absoluteFilePath;
+   int hits;
+   int breaks;
    bool inserted;
    BreakpointType type;
    DataRow row;
@@ -4943,8 +4949,11 @@ class Watch : struct
 {
    class_no_expansion;
 
-   Type type;
+public:
    char * expression;
+
+private:
+   Type type;
    char * value;
    DataRow row;
 
index 758e740..de4ec14 100644 (file)
@@ -2050,7 +2050,7 @@ class CodeEditor : Window
          int line = editBox.lineNumber + 1;
          if(projectView)
          {
-            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
             ProjectConfig config = projectView.project.config;
             int bitDepth = ide.workspace.bitDepth;
             bool useValgrind = ide.workspace.useValgrind;
@@ -2863,7 +2863,7 @@ class CodeEditor : Window
 
       if(ide.workspace)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          SetTargetBits(ide.workspace.bitDepth ? ide.workspace.bitDepth : GetHostBits());
          delete compiler;
       }
@@ -2916,7 +2916,7 @@ class CodeEditor : Window
       // TODO: Get symbolsDir from project settings instead...
       if(ide.projectView)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          ProjectConfig config = project.config;
          int bitDepth = ide.workspace.bitDepth;
          DirExpression objDir = project.GetObjDir(compiler, config, bitDepth);
index bbdb833..0918314 100644 (file)
@@ -146,9 +146,10 @@ class NewProjectDialog : Window
          char workspaceFile[MAX_LOCATION];
          strcpy(workspaceFile, prj.filePath);
          ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
-         workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
+         workspace = Workspace { activeCompiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
+         workspace.Init();
       }
-      workspace.projects.Add(prj);
+      workspace.AddProject(prj, null);
       ide.findInFilesDialog.AddProjectItem(prj);
       ide.findInFilesDialog.mode = FindInFilesMode::project;
       ide.findInFilesDialog.currentDirectory = prj.topNode.path;
@@ -210,7 +211,7 @@ class NewProjectDialog : Window
 
       if(prj && projectWindow)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          ProjectConfig config = prj.config;
          projectWindow.ShowOutputBuildLog(true);
          projectWindow.DisplayCompiler(compiler, false);
@@ -456,10 +457,10 @@ class QuickProjectDialog : Window
             char workspaceFile[MAX_LOCATION];
             strcpy(workspaceFile, filePath);
             ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
-            workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
+            workspace = Workspace { activeCompiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
          }
 
-         workspace.projects.Add(project);
+         workspace.AddProject(project, null);
          ide.findInFilesDialog.AddProjectItem(project);
          ide.findInFilesDialog.mode = FindInFilesMode::project;
          ide.findInFilesDialog.currentDirectory = project.topNode.path;
@@ -559,7 +560,7 @@ class QuickProjectDialog : Window
 
          if(project && projectWindow)
          {
-            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
             ProjectConfig config = project.config;
             projectWindow.ShowOutputBuildLog(true);
             projectWindow.DisplayCompiler(compiler, false);
index 694f520..c34cb54 100755 (executable)
@@ -303,11 +303,11 @@ class IDEToolbar : ToolBar
       this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
       {
-         if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
+         if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
          {
             bool silent = ide.projectView.buildInProgress == none ? false : true;
             CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
-            ide.workspace.compiler = row.string;
+            ide.workspace.activeCompiler = row.string;
             ide.projectView.ShowOutputBuildLog(!silent);
             if(!silent)
                ide.projectView.DisplayCompiler(compiler, false);
@@ -328,7 +328,7 @@ class IDEToolbar : ToolBar
          if(ide.workspace && ide.projectView && row)
          {
             bool silent = ide.projectView.buildInProgress == none ? false : true;
-            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
             ide.workspace.bitDepth = (int)row.tag;
             ide.projectView.ShowOutputBuildLog(!silent);
             if(!silent)
@@ -439,14 +439,14 @@ class IDEWorkSpace : Window
 
       void OnGotoError(const char * line, bool noParsing)
       {
-         CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
+         CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
          const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
          ide.GoToError(line, noParsing, objectFileExt);
       }
 
       void OnCodeLocationParseAndGoTo(const char * line)
       {
-         CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
+         CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
          const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
          ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
       }
@@ -723,8 +723,8 @@ class IDEWorkSpace : Window
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             globalSettingsDialog.master = this;
-            if(ide.workspace && ide.workspace.compiler)
-               globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
+            if(ide.workspace && ide.workspace.activeCompiler)
+               globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
             else if(ideSettings.defaultCompiler)
                globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
             globalSettingsDialog.Modal();
@@ -1858,7 +1858,7 @@ class IDEWorkSpace : Window
    {
       if(workspace)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
          for(prj : workspace.projects)
             projectView.ProjectUpdateMakefileForAllConfigs(prj);
          delete compiler;
@@ -1871,7 +1871,7 @@ class IDEWorkSpace : Window
       if(workspace)
       {
          bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
          if(!silent)
          {
             projectView.ShowOutputBuildLog(true);
@@ -1889,7 +1889,7 @@ class IDEWorkSpace : Window
       for(compiler : ideSettings.compilerConfigs)
       {
          DataRow row = toolBar.activeCompiler.AddString(compiler.name);
-         if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
+         if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
             toolBar.activeCompiler.currentRow = row;
       }
       if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
@@ -2326,7 +2326,7 @@ class IDEWorkSpace : Window
 
                         ide.projectView.ShowOutputBuildLog(true);
                         {
-                           CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+                           CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
                            ide.projectView.DisplayCompiler(compiler, false);
                            delete compiler;
                         }
@@ -2345,23 +2345,8 @@ class IDEWorkSpace : Window
                         // this crashes on starting ide with epj file, solution please?
                         // app.UpdateDisplay();
 
+                        workspace.OpenPreviouslyOpenedFiles(noParsing);
                         workspace.holdTracking = true;
-                        for(ofi : workspace.openedFiles)
-                        {
-                           if(ofi.state != closed)
-                           {
-                              Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
-                              if(file)
-                              {
-                                 char fileName[MAX_LOCATION];
-                                 ProjectNode node;
-                                 GetLastDirectory(ofi.path, fileName);
-                                 node = projectView.project.topNode.Find(fileName, true);
-                                 if(node)
-                                    node.EnsureVisible();
-                              }
-                           }
-                        }
                         ide.RepositionWindows(false);
                         workspace.holdTracking = false;
 
@@ -2444,9 +2429,9 @@ class IDEWorkSpace : Window
                   if(prj)
                   {
                      const char * activeConfigName = null;
-                     CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+                     CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
                      prj.StartMonitoring();
-                     workspace.projects.Add(prj);
+                     workspace.AddProject(prj, null);
                      if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
                            toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
                         activeConfigName = toolBar.activeConfig.currentRow.string;
@@ -2569,21 +2554,7 @@ class IDEWorkSpace : Window
       if(document)
       {
          if(projectView && document._class == class(CodeEditor) && workspace)
-         {
-            int lineNumber, position;
-            Point scroll;
-            CodeEditor editor = (CodeEditor)document;
-            editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
-            editor.openedFileInfo.holdTracking = true;
-            lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
-            position = Max(editor.openedFileInfo.position - 1, 0);
-            if(editor.editBox.GoToLineNum(lineNumber))
-               editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
-            scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
-            scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
-            editor.editBox.scroll = scroll;
-            editor.openedFileInfo.holdTracking = false;
-         }
+            workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
 
          if(needFileModified)
             document.OnFileModified = OnFileModified;
index a7ebc95..b232d9a 100644 (file)
@@ -680,7 +680,7 @@ CompilerConfig GetCompilerConfig()
 #ifndef MAKEFILE_GENERATOR
    CompilerConfig compiler = null;
    if(ide && ide.workspace)
-      compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
    return compiler;
 #else
    incref defaultCompiler;
@@ -934,7 +934,7 @@ private:
 
                if(projectView)
                {
-                  CompilerConfig compiler = ideSettings.GetCompilerConfig(projectView.workspace.compiler);
+                  CompilerConfig compiler = ideSettings.GetCompilerConfig(projectView.workspace.activeCompiler);
                   projectView.AddNode(topNode, null);
                   topNode.row.Move(prev);
 
@@ -1208,9 +1208,6 @@ private:
    bool Save(const char * fileName)
    {
       File f;
-      /*char output[MAX_LOCATION];
-       ChangeExtension(fileName, "json", output);
-      f = FileOpen(output, write);*/
       f = FileOpen(fileName, write);
       if(f)
       {
@@ -2147,8 +2144,9 @@ private:
                      targetPlatform,
                      bitDepth ? " ARCH=" : "", bitDepth == 32 ? "32" : bitDepth == 64 ? "64" : "",
                      /*(bitDepth == 64 && compiler.targetPlatform == win32) ? " GCC_PREFIX=x86_64-w64-mingw32-" : (bitDepth == 32 && compiler.targetPlatform == win32) ? " GCC_PREFIX=i686-w64-mingw32-" : */"",
-
-                     compilerName, topNode.path, justPrint ? " -n" : "", makeFilePath);
+                     compilerName,
+                     objFileExt ? " O=." : "", objFileExt ? objFileExt : "",
+                     topNode.path, justPrint ? " -n" : "", makeFilePath);
                if(justPrint || raw)
                   ide.outputView.buildBox.Logf("%s\n", command);
                Execute(command);
@@ -2374,7 +2372,7 @@ private:
       sprintf(target, "%s %s", target, args);
       GetWorkingDir(oldDirectory, MAX_LOCATION);
 
-      if(strlen(ide.workspace.debugDir))
+      if(ide.workspace.debugDir && strlen(ide.workspace.debugDir))
       {
          char temp[MAX_LOCATION];
          strcpy(temp, topNode.path);
index 362b542..6fff990 100644 (file)
@@ -415,9 +415,6 @@ public:
       //PrintLn("noLineNumbers:", noLineNumbers);
       PrintLn("optimization:", optimization);
 
-      //...
-      //PrintLn("dddddddd:", dddddddd);
-
       PrintLn("fastMath:", fastMath);
 
       PrintLn("preprocessorDefinitions:", preprocessorDefinitions);
@@ -425,9 +422,6 @@ public:
       PrintLn("linkerOptions:", linkerOptions);
       PrintLn("includeDirs:", includeDirs);
 
-      //...
-      //PrintLn("dddddddd:", dddddddd);
-
       PrintLn("");
    }
 #endif
index 8690d11..b306607 100644 (file)
@@ -876,7 +876,7 @@ class ProjectView : Window
       if(buildInProgress == none)
       {
          Project prj = project;
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          int bitDepth = ide.workspace.bitDepth;
          ProjectConfig config;
          if(selection || !ide.activeClient)
@@ -906,7 +906,7 @@ class ProjectView : Window
    bool ProjectInstall(MenuItem selection, Modifiers mods)
    {
       Project prj = project;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       int bitDepth = ide.workspace.bitDepth;
       ProjectConfig config;
       if(selection || !ide.activeClient)
@@ -939,7 +939,7 @@ class ProjectView : Window
    bool ProjectLink(MenuItem selection, Modifiers mods)
    {
       Project prj = project;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       int bitDepth = ide.workspace.bitDepth;
       ProjectConfig config;
       if(selection || !ide.activeClient)
@@ -972,7 +972,7 @@ class ProjectView : Window
 
    bool ProjectRebuild(MenuItem selection, Modifiers mods)
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       int bitDepth = ide.workspace.bitDepth;
       Project prj = project;
       ProjectConfig config;
@@ -1029,7 +1029,7 @@ class ProjectView : Window
    {
       Project prj = project;
       Array<Project> projects { };
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       int bitDepth = ide.workspace.bitDepth;
       if(selection)
       {
@@ -1089,7 +1089,7 @@ class ProjectView : Window
    bool ProjectRegenerate(MenuItem selection, Modifiers mods)
    {
       Project prj = project;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ShowOutputBuildLog(true);
       if(selection || !ide.activeClient)
       {
@@ -1139,7 +1139,7 @@ class ProjectView : Window
 
       if(result)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          int bitDepth = ide.workspace.bitDepth;
          result = false;
          if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
@@ -1189,7 +1189,7 @@ class ProjectView : Window
 
       if(result)
       {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
          int bitDepth = ide.workspace.bitDepth;
          result = false;
          if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
@@ -1315,7 +1315,7 @@ class ProjectView : Window
 
    bool ProjectUpdateMakefileForAllConfigs(Project project)
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
 
       // This call really does not belong here:
       ide.UpdateToolBarActiveConfigs(false);
@@ -1546,7 +1546,7 @@ class ProjectView : Window
 
    bool Run(MenuItem selection, Modifiers mods)
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       String args = new char[maxPathLen];
@@ -1568,7 +1568,7 @@ class ProjectView : Window
    bool DebugStart()
    {
       bool result = false;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       bool useValgrind = ide.workspace.useValgrind;
@@ -1985,7 +1985,7 @@ class ProjectView : Window
 
    bool DebugRestart()
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       bool useValgrind = ide.workspace.useValgrind;
@@ -2024,7 +2024,7 @@ class ProjectView : Window
 
    bool DebugStepInto()
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       bool useValgrind = ide.workspace.useValgrind;
@@ -2037,7 +2037,7 @@ class ProjectView : Window
 
    bool DebugStepOver(bool skip)
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       bool useValgrind = ide.workspace.useValgrind;
@@ -2051,7 +2051,7 @@ class ProjectView : Window
 
    bool DebugStepUntil(bool skip)
    {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
       bool useValgrind = ide.workspace.useValgrind;
index 57876ae..5290e2d 100644 (file)
@@ -1,26 +1,5 @@
 import "ide"
 
-/*static void ParseListValue(List<String> list, char * equal)
-{
-   char * start, * comma;
-   char * string;
-   string = CopyString(equal);
-   start = string;
-   while(start)
-   {
-      comma = strstr(start, ",");
-      if(comma)
-         comma[0] = '\0';
-      list.Add(CopyString(start));
-      if(comma)
-         comma++;
-      if(comma)
-         comma++;
-      start = comma;
-   }
-   delete string;
-}*/
-
 enum OpenedFileState { unknown, opened, closed };
 enum ValgrindLeakCheck
 {
@@ -46,15 +25,19 @@ enum ValgrindLeakCheck
 };
 static const char * valgrindLeakCheckNames[ValgrindLeakCheck] = { "no", "summary", "yes", "full" };
 
-class OpenedFileInfo
+class OpenedFileInfo : struct
 {
    class_no_expansion;
-//public:
+public:
 //   class_fixed
    char * path;
    OpenedFileState state;
-   int lineNumber, position;
+   int lineNumber;
+   int position;
    Point scroll;
+   TimeStamp modified;
+
+private:
    bool holdTracking;
 
    property bool trackingAllowed
@@ -88,50 +71,166 @@ class OpenedFileInfo
       {
          List<OpenedFileInfo> files = ide.workspace.openedFiles;
          Iterator<OpenedFileInfo> it { files };
-         if(it.Find(this) && it.pointer != files.GetLast())
+         IteratorPointer last;
+         if(it.Find(this) && it.pointer != (last = files.GetLast()))
          {
-            files.Move(it.pointer, files.GetPrev(files.GetLast()));
+            files.Move(it.pointer, last);
             ide.workspace.modified = true;
          }
+         modified = GetLocalTimeStamp();
       }
    }
+
+   void SetCodeEditorState(CodeEditor editor)
+   {
+      int num = Max(lineNumber - 1, 0);
+      Point scrl;
+      holdTracking = true;
+      if(editor.editBox.GoToLineNum(num))
+      {
+         int pos = Max(Min(editor.editBox.line.count, position - 1), 0);
+         editor.editBox.GoToPosition(editor.editBox.line, num, pos);
+      }
+      scrl.x = Max(scroll.x, 0);
+      scrl.y = Max(scroll.y, 0);
+      editor.editBox.scroll = scrl;
+      holdTracking = false;
+   }
+
    ~OpenedFileInfo()
    {
       delete path;
    }
 };
 
-class Workspace
+class WorkspaceFile : struct
+{
+   class_no_expansion;
+public:
+   property const char * format
+   {
+      set { }
+      get { return "Ecere IDE Workspace File"; }
+      isset { return true; }
+   }
+   property const char * version
+   {
+      set { }
+      get { return "0.1"; }
+      isset { return true; }
+   }
+   Workspace workspace;
+}
+
+class AddedProjectInfo : struct
+{
+   class_no_expansion;
+public:
+   property const char * path
+   {
+      set { delete path; if(value && value[0]) path = CopyString(value); }
+      get { return path && path[0] ? path : null; }
+      isset { return path != null; }
+   }
+   property const char * activeConfig
+   {
+      set { delete activeConfig; if(value && value[0]) activeConfig = CopyString(value); }
+      get
+      {
+         char * config;
+         if(project && project.config)
+            config = project.config.name;
+         else
+            config = activeConfig;
+         return config && config[0] ? config : null;
+      }
+      isset { return property::activeConfig != null; }
+   }
+private:
+   char * path;
+   char * activeConfig;
+   Project project;
+
+   void Free()
+   {
+      delete path;
+      delete activeConfig;
+   }
+
+   void OnFree()
+   {
+      Free();
+      class::OnFree();
+   }
+
+   ~AddedProjectInfo()
+   {
+      Free();
+   }
+}
+
+class Workspace : struct
 {
+   class_no_expansion;
 public:
+   property const char * name
+   {
+      set { delete name; if(value && value[0]) name = CopyString(value); }
+      get { return name && name[0] ? name : null; }
+      isset { return name != null; }
+   }
+   property const char * activeCompiler
+   {
+      set { delete activeCompiler; if(value && value[0]) activeCompiler = CopyString(value); }
+      get { return activeCompiler && activeCompiler[0] ? activeCompiler : null; }
+      isset { return activeCompiler != null; }
+   }
+   int bitDepth;
+   property const char * commandLineArgs
+   {
+      set { delete commandLineArgs; if(value && value[0]) commandLineArgs = CopyString(value); }
+      get { return commandLineArgs && commandLineArgs[0] ? commandLineArgs : null; }
+      isset { return commandLineArgs != null; }
+   }
+   property const char * debugDir
+   {
+      set { delete debugDir; if(value && value[0]) debugDir = CopyString(value); }
+      get { return debugDir && debugDir[0] ? debugDir : null; }
+      isset { return debugDir != null; }
+   }
+
+   List<AddedProjectInfo> addedProjects;
+   List<String> sourceDirs;
+   Array<NamedString> environmentVars;
+   List<Breakpoint> breakpoints;
+   List<Watch> watches;
+   List<OpenedFileInfo> openedFiles;
+
+   bool useValgrind;
+   ValgrindLeakCheck vgLeakCheck;
+   bool vgTrackOrigins;
+   int vgRedzoneSize;
+
+private:
    char * name;
-   char * workspaceFile;
-   char * workspaceDir;
+   char * activeCompiler;
    char * commandLineArgs;
-   property const char * commandLineArgs { set { delete commandLineArgs; if(value) commandLineArgs = CopyString(value); } }
    char * debugDir;
-   property const char * debugDir { set { delete debugDir; if(value) debugDir = CopyString(value); } }
 
-   int bpCount;
+   char * workspaceFile;
+   char * workspaceDir;
 
-   property const char * compiler
-   {
-      set { delete compiler; if(value && value[0]) compiler = CopyString(value); }
-      get { return compiler && compiler[0] ? compiler : null; }
-   }
+   int bpCount;
 
-   List<String> sourceDirs { };
-   Array<NamedString> environmentVars { };
-   List<Breakpoint> breakpoints { };
-   List<Watch> watches { };
-   List<OpenedFileInfo> openedFiles { };
    List<Project> projects { };
-
    //Project project;
 
    bool modified;
    bool holdTracking;
 
+   vgRedzoneSize = -1;
+   vgLeakCheck = summary;
+
    Timer timer
    {
       userData = this, delay = 1.0;
@@ -162,6 +261,26 @@ public:
       }
    };
 
+   void AddProject(Project project, AddedProjectInfo addedProject)
+   {
+      if(addedProject)
+      {
+         ProjectConfig activeConfig = project.GetConfig(addedProject.activeConfig);
+         if(activeConfig)
+            project.config = activeConfig;
+         addedProject.project = project;
+      }
+      else
+      {
+         char location[MAX_LOCATION];
+         GetRelativePathForProject(location, project);
+         if(!addedProjects)
+            addedProjects = { };
+         addedProjects.Add(AddedProjectInfo { path = location, project = project });
+      }
+      projects.Add(project);
+   }
+
    property const char * workspaceFile
    {
       set
@@ -217,163 +336,20 @@ public:
       get { return project; }
    }*/
 
-private:
-   String compiler;
-   int bitDepth;
-   // TODO: save these new settings when json format is ready
-   bool useValgrind;
-   ValgrindLeakCheck vgLeakCheck;
-   bool vgTrackOrigins;
-   int vgRedzoneSize;
-
-   vgRedzoneSize = -1;
-   vgLeakCheck = summary;
-
 public:
    void Save()
    {
-      bool bkpts = false;
-      File file;
-
-      file = FileOpen(workspaceFile, write);
-      if(file)
+      if(workspaceFile && workspaceFile[0])
       {
-         /*
-         for(bp : breakpoints)
-         {
-            if(bp.type == user)
-            {
-               if(bp.enabled)
-                  file.Printf("Breakpoint=1,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
-               else
-                  file.Printf("Breakpoint=0,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
-            }
-         }
-
-         for(wh : watches)
-            file.Printf("Watch=%s\n", wh.expression);
-
-         for(dir : sourceDirs)
-            file.Printf("SourceDir=%s\n", dir);
-
-         if(debugDir && debugDir[0])
-            file.Printf("DebugDir=%s\n", debugDir);
-
-         if(commandLineArgs && commandLineArgs[0])
-            file.Printf("CommandLineArgs=%s\n", commandLineArgs);
-         */
-
-         /*
-         char indentation[128*3];
-         char path[MAX_LOCATION];
-         */
-         file.Printf("\nECERE Workspace File\n");
-         file.Printf("\nVersion 0.02\n");
-         file.Printf("\nWorkspace\n");
-         file.Printf("\n   Active Compiler = %s\n", compiler ? compiler : defaultCompilerName);
-         file.Printf("\n   Active Bit Depth = %d\n", bitDepth);
-
-         if(projects.first)
-         {
-            file.Printf("\n   Projects\n\n");
-            for(prj : projects)
-            {
-               char location[MAX_LOCATION];
-               MakePathRelative(prj.topNode.path, workspaceDir, location);
-               MakeSlashPath(location);
-               PathCatSlash(location, prj.topNode.name);
-               //strcat(location, ".epj");
-
-               file.Printf("    %s %s\n", "-", location);
-
-               if(prj.config)
-                  file.Printf("         Active Configuration = %s\n", prj.config.name);
-               for(cfg : prj.configurations)
-               {
-                  if(cfg.compilingModified)
-                     file.Printf("         Modified Compiler Config = %s\n", cfg.name);
-                  else if(cfg.linkingModified)
-                     file.Printf("         Modified Linker Config = %s\n", cfg.name);
-               }
-            }
-         }
-
-         file.Printf("\n   Execution Data\n");
-         if(commandLineArgs && commandLineArgs[0])
-         {
-            file.Printf("\n      Command Line Arguments = ");
-            file.Puts(commandLineArgs);
-            file.Printf("\n");
-         }
-
-         if(environmentVars.count)
-         {
-            file.Printf("\n      Environment Variables\n\n");
-            for(v : environmentVars)
-            {
-               file.Printf("       ~ ");
-               file.Puts(v.name);
-               file.Printf(" = ");
-               file.Puts(v.string);
-               file.Printf("\n");
-            }
-         }
-
-         file.Printf("\n   Debugger Data\n");
-         // This really belonged in Execution Data...
-         if(debugDir && debugDir[0])
-            file.Printf("\n      Debug Working Directory = %s\n", debugDir);
-         if(sourceDirs.count)
+         File file = FileOpen(workspaceFile, write);
+         if(file)
          {
-            file.Printf("\n      Source Directories\n");
-            for(dir : sourceDirs)
-               file.Printf("       = %s\n", dir);
+            WorkspaceFile wf { workspace = this };
+            WriteJSONObject(file, class(WorkspaceFile), wf, 0);
+            delete wf;
+            delete file;
+            modified = false;
          }
-
-         for(bp : breakpoints)
-         {
-            if(bp.type == user)
-            {
-               if(!bkpts)
-               {
-                  bkpts = true;
-                  file.Printf("\n   Breakpoints\n\n");
-               }
-               bp.Save(file);
-            }
-         }
-
-         if(watches.count)
-         {
-            file.Printf("\n   Watches\n\n");
-            for(wh : watches)
-               wh.Save(file);
-         }
-
-         if(openedFiles.count)
-         {
-            file.Printf("\n   Opened Files\n\n");
-            for(ofi : openedFiles)
-            {
-               char * location;
-               char chr[2];
-               char relativePath[MAX_LOCATION];
-               if(IsPathInsideOf(ofi.path, workspaceDir))
-               {
-                  MakePathRelative(ofi.path, workspaceDir, relativePath);
-                  MakeSlashPath(relativePath);
-                  location = relativePath;
-               }
-               else
-                  location = ofi.path;
-               strcpy(chr, "=");
-
-               file.Printf("    %s %s:%d:%d:%d:%d:%s\n", chr, ofi.state == closed ? "C" : "O", ofi.lineNumber, ofi.position, ofi.scroll.x, ofi.scroll.y, location);
-            }
-         }
-
-         modified = false;
-         delete file;
       }
    }
 
@@ -563,25 +539,21 @@ public:
 
    OpenedFileInfo UpdateOpenedFileInfo(const char * fileName, OpenedFileState state)
    {
-      char filePath[MAX_LOCATION];
-      OpenedFileInfo ofi = null;
-      GetSlashPathBuffer(filePath, fileName);
-      for(item : openedFiles)
-      {
-         if(!fstrcmp(item.path, filePath))
-         {
-            ofi = item;
-            break;
-         }
-      }
+      char absolutePath[MAX_LOCATION];
+      char relativePath[MAX_LOCATION];
+      OpenedFileInfo ofi;
+      GetSlashPathBuffer(absolutePath, fileName);
+      MakeRelativePath(relativePath, fileName);
+      ofi = FindOpenedFileInfo(relativePath, absolutePath);
       if(state)
       {
          if(!ofi)
          {
-            ofi = OpenedFileInfo { path = CopyString(filePath) };
+            ofi = OpenedFileInfo { path = CopyString(relativePath) };
             openedFiles.Add(ofi);
          }
          ofi.state = state;
+         ofi.modified = GetLocalTimeStamp();
          if(!holdTracking)
             modified = true;
       }
@@ -596,6 +568,84 @@ public:
       return ofi;
    }
 
+   void LoadOpenedFileInfo(const char * path, OpenedFileState state, int lineNumber, int position, Point scroll, TimeStamp modified, Array<String> openedFilesNotFound)
+   {
+      char absolutePath[MAX_LOCATION];
+      char relativePath[MAX_LOCATION];
+      TimeStamp stamp = modified;
+      bool exists;
+      strcpy(absolutePath, workspaceDir);
+      PathCatSlash(absolutePath, path);
+      MakeRelativePath(relativePath, absolutePath);
+      if(!(exists = FileExists(absolutePath)))
+         stamp -= 60*60*24*20; // Days { 20 };
+      if(stamp > GetLocalTimeStamp() - 60*60*24*384) // Days { 384 });
+      {
+         if(state == closed || exists)
+         {
+            OpenedFileInfo ofi = FindOpenedFileInfo(relativePath, absolutePath);
+            if(!ofi)
+               openedFiles.Add(OpenedFileInfo { CopyString(relativePath), state, lineNumber, position, scroll, stamp });
+            // else silently drop duplicates if they should ever occur;
+         }
+         else
+            openedFilesNotFound.Add(CopyString(absolutePath));
+      }
+      // else silently discarding old or broken OpenedFileInfo entries;
+   }
+
+   void OpenPreviouslyOpenedFiles(bool noParsing)
+   {
+      holdTracking = true;
+      for(ofi : openedFiles)
+      {
+         if(ofi.state != closed)
+         {
+            Window file;
+            char absolutePath[MAX_LOCATION];
+            strcpy(absolutePath, workspaceDir);
+            PathCatSlash(absolutePath, ofi.path);
+            file = ide.OpenFile(absolutePath, false, true, null, no, normal, noParsing);
+            if(file)
+            {
+               for(prj : projects)
+               {
+                  ProjectNode node = prj.topNode.FindByFullPath(absolutePath, true);
+                  if(node)
+                     node.EnsureVisible();
+               }
+            }
+         }
+      }
+      holdTracking = false;
+   }
+
+   OpenedFileInfo FindOpenedFileInfo(const char * relativePath, const char * absolutePath)
+   {
+      OpenedFileInfo result = null;
+      for(e : openedFiles)
+      {
+         bool switchToRelative;
+         if((switchToRelative = !fstrcmp(absolutePath, e.path)) || !fstrcmp(relativePath, e.path))
+         {
+            result = e;
+            if(switchToRelative)
+            {
+               delete result.path;
+               result.path = CopyString(relativePath);
+            }
+            break;
+         }
+      }
+      return result;
+   }
+
+   void RestorePreviouslyOpenedFileState(CodeEditor editor)
+   {
+      if((editor.openedFileInfo = UpdateOpenedFileInfo(editor.fileName, opened)))
+         editor.openedFileInfo.SetCodeEditorState(editor);
+   }
+
    void UpdateSourceDirsArray(Array<String> dirs)
    {
       sourceDirs.Free();
@@ -610,11 +660,17 @@ public:
 
    void RemoveProject(Project project)
    {
-      Iterator<Project> it { projects };
-      if(it.Find(project))
-         it.Remove();
+      Iterator<AddedProjectInfo> it { addedProjects };
+      while(it.Next())
+      {
+         if(it.data.project == project)
+         {
+            addedProjects.Remove(it.pointer);
+            break;
+         }
+      }
+      projects.TakeOut(project);
 
-      for(bp : breakpoints)
       DropInvalidBreakpoints(project);
       modified = true;
       ide.findInFilesDialog.RemoveProjectItem(project);
@@ -799,16 +855,15 @@ public:
       }
    }
 
-   void DropInvalidBreakpoints(Project removedProject)
-   {
-      Link bpLink, next;
-      for(bpLink = breakpoints.first; bpLink; bpLink = next)
+   void DropInvalidBreakpoints(Project removedProject) // think about not dropping BPs that are past end of file but simply disable them
+   {                                                   // why? when using a scm/vcs you might be alternating between two version of a file
+      if(breakpoints)                                  // and anoyingly keep loosing breakpoints in the version of the file you are working on
       {
-         Breakpoint bp = (Breakpoint)(intptr)bpLink.data;
-         next = bpLink.next;
-
-         if(bp.type == user)
+         Link bpLink, next;
+         for(bpLink = breakpoints.first; bpLink; bpLink = next)
          {
+            Breakpoint bp = (Breakpoint)(intptr)bpLink.data;
+            next = bpLink.next;
             if(removedProject)
             {
                if(bp.project == removedProject)
@@ -863,8 +918,18 @@ public:
                }
             }
          }
+         ide.breakpointsView.Update(null);
       }
-      ide.breakpointsView.Update(null);
+   }
+
+   void Init()
+   {
+      if(!addedProjects) addedProjects = { };
+      if(!sourceDirs) sourceDirs = { };
+      if(!environmentVars) environmentVars = { };
+      if(!breakpoints) breakpoints = { };
+      if(!watches) watches = { };
+      if(!openedFiles) openedFiles = { };
    }
 
    void Free()
@@ -873,12 +938,18 @@ public:
       delete workspaceDir;
       delete commandLineArgs;
       delete debugDir;
+      delete activeCompiler;
 
       //project = null;
 
+      if(addedProjects) { addedProjects.Free(); delete addedProjects; }
+      if(sourceDirs) { sourceDirs.Free(); delete sourceDirs; }
+      if(environmentVars) { environmentVars.Free(); delete environmentVars; }
+      if(breakpoints) { breakpoints.Free(); delete breakpoints; }
+      if(watches) { watches.Free(); delete watches; }
+      if(openedFiles) { openedFiles.Free(); delete openedFiles; }
+
       projects.Free();
-      breakpoints.Free();
-      watches.Free();
    }
 
    Workspace()
@@ -900,30 +971,215 @@ public:
       Save();
       timer.Stop();
 
-      sourceDirs.Free();
-      environmentVars.Free();
       SetSourceDirs(null);
       Free();
-      openedFiles.Free();
-      delete compiler;
    }
 
 }
 
 Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
 {
+   File f;
+   Workspace workspace = null;
+
+   f = FileOpen(filePath, read);
+   if(f)
+   {
+      Array<String> openedFilesNotFound { };
+      WorkspaceFile wf = null;
+      JSONParser parser { f = f };
+      /*JSONResult result = */parser.GetObject(class(WorkspaceFile), &wf);
+      if(!wf)
+         workspace = LoadLegacyWorkspace(filePath, openedFilesNotFound);
+      else
+      {
+         workspace = wf.workspace;
+         //incref workspace;
+         workspace.workspaceFile = filePath;
+         {
+            char absolutePath[MAX_LOCATION];
+            bool done = false;
+            bool ahead = false;
+            Iterator<AddedProjectInfo> it { workspace.addedProjects };
+            while(!done && (ahead || !(done = !it.Next())))
+            {
+               // TODO: implement some type of time based pruning of "dea" added projects instead of just dropping them on the spot
+               //         TimeStamp modified; modified = GetLocalTimeStamp();
+               //               TimeStamp stamp = modified; if(stamp > GetLocalTimeStamp() - 60*60*24*20) // Days { 20 });
+               AddedProjectInfo addedPrj = it.data;
+               strcpy(absolutePath, workspace.workspaceDir);
+               PathCatSlash(absolutePath, addedPrj.path);
+               if(FileExists(absolutePath))
+               {
+                  Project loadedProject = LoadProject(absolutePath, null);
+                  if(loadedProject)
+                  {
+                     workspace.AddProject(loadedProject, addedPrj);
+                     loadedProject.StartMonitoring();
+                  }
+                  else if(workspace.projects.count == 0)
+                  {
+                     delete workspace;
+                     break;
+                  }
+                  else
+                  {
+                     // TODO: (#524) show message or something when added project fails to load;
+                  }
+                  ahead = false;
+               }
+               else
+               {
+                  IteratorPointer notFound = it.pointer;
+                  done = !it.Next();
+                  workspace.addedProjects.Delete(notFound);
+                  ahead = true;
+               }
+            }
+            if(workspace)
+            {
+               for(bp : workspace.breakpoints)
+               {
+                  char * path = workspace.CopyAbsolutePathFromRelative(bp.relativeFilePath);
+                  bp.type = user;
+                  if(path)
+                  {
+                     bp.absoluteFilePath = path;
+                     delete path;
+                  }
+                  else
+                     bp.absoluteFilePath = "";
+               }
+               if(workspace.openedFiles && workspace.openedFiles.count)
+               {
+                  List<OpenedFileInfo> openedFiles = workspace.openedFiles;
+                  workspace.openedFiles = { };
+                  for(of : openedFiles)
+                  {
+                     workspace.LoadOpenedFileInfo(of.path, of.state, of.lineNumber, of.position, of.scroll, of.modified, openedFilesNotFound);
+                  }
+                  openedFiles.Free();
+                  delete openedFiles;
+               }
+            }
+         }
+      }
+
+      if(workspace)
+      {
+         workspace.Init();
+         if(!workspace.projects.first)
+         {
+            Project project;
+            if(fromProjectFile)
+               project = LoadProject(fromProjectFile /*projectFilePath*/, null);
+            else
+            {
+               char projectFilePath[MAX_LOCATION];
+               strcpy(projectFilePath, workspace.workspaceFile);
+               ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
+               project = LoadProject(projectFilePath, null);
+            }
+            if(project)
+            {
+               project.StartMonitoring();
+               workspace.AddProject(project, null);
+               workspace.name = CopyString(project.name);
+            }
+            else
+            {
+               MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
+               delete workspace;
+               return null;
+            }
+         }
+
+         if(openedFilesNotFound.count)
+         {
+            int c = 0;
+            char s[2] = "";
+            String files = new char[MAX_LOCATION * 16];
+            char title[512];
+            String msg = new char[MAX_LOCATION * 16 + 2048];
+            strcpy(files,"\n");
+
+            if(openedFilesNotFound.count > 1)
+               strcpy(s, "s");
+
+            for(item : openedFilesNotFound)
+            {
+               c++;
+               if(c == 16)
+               {
+                  strcat(files, "\n...");
+                  break;
+               }
+               strcat(files, "\n");
+               strcat(files, item);
+            }
+
+            sprintf(title, $"File%s not found", s);
+            sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
+
+            MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
+
+            delete files;
+            delete msg;
+         }
+      }
+      openedFilesNotFound.Free();
+      delete openedFilesNotFound;
+      delete parser;
+      delete wf;
+      delete f;
+   }
+   else if(fromProjectFile)
+   {
+      //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
+
+      //char projectFile[MAX_LOCATION];
+      Project newProject;
+
+      //strcpy(projectFile, filePath);
+      //ChangeExtension(projectFile, ProjectExtension, projectFile);
+      newProject = LoadProject(fromProjectFile /*projectFile*/, null);
+
+      if(newProject)
+      {
+         newProject.StartMonitoring();
+         workspace = Workspace { property::workspaceFile = filePath };
+
+         workspace.Init();
+         workspace.AddProject(newProject, null);
+         workspace.Save();
+      }
+   }
+
+   if(workspace)
+   {
+      ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
+
+      if(!workspace.activeCompiler || !workspace.activeCompiler[0])
+         workspace.activeCompiler = defaultCompilerName;
+   }
+
+   return workspace;
+}
+
+Workspace LoadLegacyWorkspace(const char * filePath, Array<String> openedFilesNotFound)
+{
    File file;
    Workspace workspace = null;
 
    file = FileOpen(filePath, read);
    if(file)
    {
-      OldList openedFilesNotFound { };
       double version = 0;
       char section[128];
       char subSection[128];
 
-      workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = filePath };
+      workspace = Workspace { activeCompiler = ideSettings.defaultCompiler, property::workspaceFile = filePath };
+      workspace.Init();
 
       file.Seek(0, start);
       while(!file.Eof())
@@ -947,6 +1203,7 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
                {
                   wh = Watch { };
+                  if(!workspace.watches) workspace.watches = { };
                   workspace.watches.Add(wh);
                   wh.expression = CopyString(equal);
                }
@@ -1035,6 +1292,8 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                      line = atoi(strLine);
 
                      bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
+                     if(!workspace.breakpoints)
+                        workspace.breakpoints = { };
                      workspace.breakpoints.Add(bp);
                      bp.location = strFile;
                   }
@@ -1053,8 +1312,6 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                   int lineNumber = 0;
                   int position = 0;
                   Point scroll { };
-                  char absolutePath[MAX_LOCATION];
-                  strcpy(absolutePath, workspace.workspaceDir);
                   if(version == 0.01)
                   {
                      char * comma = strchr(equal, ',');
@@ -1109,12 +1366,7 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                         }
                      }
                   }
-                  PathCatSlash(absolutePath, equal);
-
-                  if(state == closed || FileExists(absolutePath))
-                     workspace.openedFiles.Add(OpenedFileInfo { path = CopyString(absolutePath), state = state, lineNumber = lineNumber, position = position, scroll = scroll });
-                  else
-                     openedFilesNotFound.Add(NamedItem { name = CopyString(equal) });
+                  workspace.LoadOpenedFileInfo(equal, state, lineNumber, position, scroll, GetLocalTimeStamp(), openedFilesNotFound);
                }
                else if(!strcmpi(section, "Projects"))
                {
@@ -1125,7 +1377,7 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                   newProject = LoadProject(projectFilePath, null);
                   if(newProject)
                   {
-                     workspace.projects.Add(newProject);
+                     workspace.AddProject(newProject, null);
                      newProject.StartMonitoring();
                   }
                   else if(workspace.projects.count == 0)
@@ -1135,8 +1387,7 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                   }
                   else
                   {
-                     // TODO: show message or something when added project fails to load
-                     // http://ecere.com/mantis/view.php?id=524
+                     // TODO: (#524) show message or something when added project fails to load;
                   }
                }
             }
@@ -1162,7 +1413,10 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
             else if(!strcmpi(buffer, "Environment Variables"))
                strcpy(subSection, buffer);
             else if(!strcmpi(buffer, "Opened Files"))
+            {
                strcpy(section, buffer);
+               if(!workspace.openedFiles) workspace.openedFiles = { };
+            }
             else if(!strcmpi(buffer, ""))      // | These two lines were commented out
                strcpy(subSection, buffer);     // | Do they serve a purpose? They were there for copy paste when adding a new subsection
             else
@@ -1180,9 +1434,9 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
                      {
                         CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
                         if(!compiler)
-                           workspace.compiler = defaultCompilerName;
+                           workspace.activeCompiler = defaultCompilerName;
                         else
-                           workspace.compiler = equal;
+                           workspace.activeCompiler = equal;
                         delete compiler;
                      }
                      if(!strcmpi(buffer, "Active Bit Depth"))
@@ -1321,102 +1575,16 @@ Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
             }
          }
       }
-
       delete file;
-
-      if(workspace)
-      {
-         if(!workspace.projects.first)
-         {
-            Project project;
-            if(fromProjectFile)
-               project = LoadProject(fromProjectFile /*projectFilePath*/, null);
-            else
-            {
-               char projectFilePath[MAX_LOCATION];
-               strcpy(projectFilePath, workspace.workspaceFile);
-               ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
-               project = LoadProject(projectFilePath, null);
-            }
-            if(project)
-            {
-               project.StartMonitoring();
-               workspace.projects.Add(project);
-               workspace.name = CopyString(project.name);
-            }
-            else
-            {
-               MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
-               delete workspace;
-               return null;
-            }
-         }
-
-         if(openedFilesNotFound.first)
-         {
-            int c = 0;
-            char s[2] = "";
-            String files = new char[MAX_LOCATION * 16];
-            char title[512];
-            String msg = new char[MAX_LOCATION * 16 + 2048];
-            NamedItem item;
-            strcpy(files,"\n");
-
-            item = openedFilesNotFound.first;
-            if(item.next)
-               strcpy(s, "s");
-
-            for(item = openedFilesNotFound.first; item; item = item.next)
-            {
-               c++;
-               if(c == 16)
-               {
-                  strcat(files, "\n...");
-                  break;
-               }
-               strcat(files, "\n");
-               strcat(files, item.name);
-            }
-
-            sprintf(title, $"File%s not found", s);
-            sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
-
-            MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
-
-            delete files;
-            delete msg;
-         }
-         openedFilesNotFound.Free(OldLink::Free);
-      }
-      else
-         openedFilesNotFound.Free(OldLink::Free);
-   }
-   else if(fromProjectFile)
-   {
-      //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
-      //char projectFile[MAX_LOCATION];
-      Project newProject;
-
-      //strcpy(projectFile, filePath);
-      //ChangeExtension(projectFile, ProjectExtension, projectFile);
-      newProject = LoadProject(fromProjectFile /*projectFile*/, null);
-
-      if(newProject)
-      {
-         newProject.StartMonitoring();
-         workspace = Workspace { workspaceFile = filePath };
-
-         workspace.projects.Add(newProject);
-         workspace.Save();
-      }
-   }
-
-   if(workspace)
-   {
-      ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
-
-      if(!workspace.compiler || !workspace.compiler[0])
-         workspace.compiler = defaultCompilerName;
    }
    return workspace;
 }
+
+TimeStamp GetLocalTimeStamp()
+{
+   TimeStamp now;
+   DateTime time { };
+   time.GetLocalTime();
+   now = time;
+   return now;
+}