Initial git commit -- Transition from CodeGuard repository
[sdk] / ide / src / project / ProjectView.ec
1 import "ide"
2
3 import "FileSystemIterator"
4
5 class ImportFolderFSI : NormalFileSystemIterator
6 {
7    ProjectView projectView;
8    Array<ProjectNode> stack { };
9
10    bool OnFolder(char * folderPath)
11    {
12       char name[MAX_LOCATION];
13       ProjectNode parentNode = stack.lastIterator.data;
14       ProjectNode folder;
15       GetLastDirectory(folderPath, name);
16       folder = parentNode.FindSpecial(name, false, true, true);
17       if(!folder)
18          folder = projectView.NewFolder(parentNode, name, false);
19       stack.Add(folder);
20       return true;
21    }
22
23    void OutFolder(char * folderPath, bool isRoot)
24    {
25       stack.lastIterator.Remove(); //stack.Remove();
26    }
27
28    bool OnFile(char * filePath)
29    {
30       ProjectNode parentNode = stack.lastIterator.data;
31       projectView.AddFile(parentNode, filePath, parentNode.isInResources);
32       return true;
33    }
34 }
35
36 static FileFilter fileFilters[] =
37 {
38    { 
39       "EC/C/C++ Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)",
40       "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx"
41    },
42    {
43       "EC/C/C++ Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)",
44       "ec, eh, c, cpp, cc, cxx"
45    },
46    {
47       "Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)",
48       "eh, h, hpp, hh, hxx"
49    },
50    { "All files", null }
51 };
52
53 static FileFilter resourceFilters[] =
54 {
55    {
56       "Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png,*.gif)",
57       "jpg, jpeg, bmp, pcx, png, gif"
58    },
59    {
60       "3D Studio Model Files (*.3ds)",
61       "3ds"
62    },
63    { "All files", null }
64 };
65
66 static FileType fileTypes[] =
67 {
68    { "Based on extension", null },
69    { "Text",               "txt" },
70    { "Image",              "jpg" },
71    { "3D Studio Model",    "3ds" }
72 };
73
74 static FileFilter projectFilters[] =
75 {
76    { "Project Files (*.epj)", ProjectExtension },
77    { "Workspace Files (*.ews)", WorkspaceExtension }
78 };
79
80 static FileType projectTypes[] =
81 {
82    { "ECERE Project", ProjectExtension },
83    { "ECERE Workspace", WorkspaceExtension }
84 };
85
86 static char * iconNames[] = 
87 {
88    "<:ecere>mimeTypes/file.png",                   /*genFile*/
89    "<:ecere>mimeTypes/textEcereWorkspace.png",     /*ewsFile*/
90    "<:ecere>mimeTypes/textEcereProject.png",       /*epjFile*/
91    "<:ecere>places/folder.png",                    /*folder*/
92    "<:ecere>status/folderOpen.png",                /*openFolder*/
93    "<:ecere>mimeTypes/textEcereSource.png",        /*ecFile*/
94    "<:ecere>mimeTypes/textEcereHeader.png",        /*ehFile*/
95    "<:ecere>mimeTypes/textCSource.png",            /*cFile*/
96    "<:ecere>mimeTypes/textCHeader.png",            /*hFile*/
97    "<:ecere>mimeTypes/textC++Source.png",          /*cppFile*/
98    "<:ecere>mimeTypes/textC++Header.png",          /*hppFile*/
99    "<:ecere>mimeTypes/text.png",                   /*textFile*/
100    "<:ecere>mimeTypes/textHyperTextMarkup.png",    /*webFile*/
101    "<:ecere>mimeTypes/image.png",                  /*pictureFile*/
102    "<:ecere>status/audioVolumeHigh.png",           /*soundFile*/
103    "<:ecere>mimeTypes/package.png",                /*archiveFile*/
104    "<:ecere>mimeTypes/packageSoftware.png",        /*packageFile*/
105    "<:ecere>mimeTypes/packageOpticalDisc.png"      /*opticalMediaImageFile*/
106 };
107
108 enum PrepareMakefileMethod { normal, force, forceExists };
109
110 enum BuildType { build, rebuild, relink, run, debug };
111
112 class ProjectView : Window
113 {
114    isDocument = true;
115    //hasMinimize = true;
116    hasClose = true;
117    borderStyle = sizable;
118    hasHorzScroll = true;
119    hasVertScroll = true;
120    background = white;
121    size = { 300 };
122    anchor = Anchor { left = 0, top = 0, bottom = 0 };
123    menu = Menu { };
124    
125    //hasMinimize = true;
126    saveDialog = projectFileDialog;
127    
128    DataRow resourceRow;
129    bool buildInProgress;
130    BitmapResource icons[NodeIcons];
131    Project project;
132    Workspace workspace;
133    property Workspace workspace
134    {
135       set
136       {
137          if(workspace)
138          {
139             for(prj : workspace.projects)
140             {
141                DeleteNode(prj.topNode);
142             }
143             workspace.projects.Free();
144             ide.debugger.CleanUp();
145          }
146          workspace = value;
147          if(workspace)
148          {
149             fileDialog.currentDirectory = workspace.workspaceDir;
150             resourceFileDialog.currentDirectory = workspace.workspaceDir;
151             for(prj : workspace.projects)
152                AddNode(prj.topNode, null);
153             ide.statusBar.text = "Generating Makefile & Dependencies...";
154             app.UpdateDisplay();
155             for(prj : workspace.projects)
156                prj.ModifiedAllConfigs(true, false, false, false);
157             ide.statusBar.text = "Initializing Debugger"; app.UpdateDisplay();
158             ide.statusBar.text = null;
159             app.UpdateDisplay();
160          }
161       }
162       get { return workspace; }
163    }
164    
165    /*property Project project
166    {
167       set
168       {
169          if(project)
170          {
171             DeleteNode(project.topNode);
172             project.Free();
173          }
174          project = value;
175          if(project)
176          {
177             AddNode(project.topNode, null);
178             fileDialog.currentDirectory = project.topNode.path;
179             resourceFileDialog.currentDirectory = project.topNode.path;
180
181             // Make sure this is done already...
182             {
183                char filePath[MAX_LOCATION];
184                strcpy(filePath, project.topNode.path);
185                PathCat(filePath, project.topNode.name);
186                strcat(filePath, ".epj");
187                fileName = filePath;
188             }
189
190             ide.statusBar.text = "Generating Makefile & Dependencies...";
191             app.UpdateDisplay();
192             // REDJ set makefile generation flag so generation occurs only when compiling instead of generating on the spot
193             project.config.makingModified = true;
194             ide.statusBar.text = "Initializing Debugger";
195             ide.statusBar.text = null;
196             app.UpdateDisplay();
197          }
198       }
199       get { return project; }
200    }*/
201
202    bool drawingInProjectSettingsDialog;
203    bool drawingInProjectSettingsDialogHeader;
204    ProjectSettings projectSettingsDialog;
205
206    ListBox fileList
207    {
208       multiSelect = true, fullRowSelect = false, hasVertScroll = true, hasHorzScroll = true;
209       borderStyle = deep, parent = this, collapseControl = true, treeBranches = true;
210       anchor = Anchor { left = 0, right = 0, top = 0 , bottom = 0 };
211
212       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
213       {
214          if(!active) Update(null);
215          return ListBox::OnActivate(active, previous, goOnWithActivation, direct);
216       }
217       
218       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
219       {
220          OpenSelectedNodes();
221          return true;
222       }
223
224       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
225       {
226          DataRow row = listBox.currentRow;
227          if(row)
228          {
229             ProjectNode node = (ProjectNode)row.tag;
230             if(node.type == NodeTypes::project || node.type == resources || node.type == file || node.type == folder)
231             {
232                PopupMenu popupMenu;
233                Menu popupContent { };
234                
235                if(node.type == NodeTypes::project)
236                {
237                   //if(node == ((Project)workspace.projects.first).topNode)
238                   {
239                      MenuItem { popupContent, "Build", b, NotifySelect = ProjectBuild }.disabled = buildInProgress;
240                      MenuItem { popupContent, "Relink", l, NotifySelect = ProjectLink }.disabled = buildInProgress;
241                      MenuItem { popupContent, "Rebuild", r, NotifySelect = ProjectRebuild }.disabled = buildInProgress;
242                      MenuItem { popupContent, "Clean", c, NotifySelect = ProjectClean }.disabled = buildInProgress;
243                      MenuItem { popupContent, "Regenerate Makefile", m, NotifySelect = ProjectRegenerate }.disabled = buildInProgress;
244                      MenuDivider { popupContent };
245                   }
246                   MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
247                   MenuItem { popupContent, "Import Folder...", f, NotifySelect = ProjectImportFolder };
248                   MenuItem { popupContent, "Add Files to Project...", f, NotifySelect = ProjectAddFiles };
249                   MenuDivider { popupContent };
250                   MenuItem { popupContent, "Add New Form...", o, NotifySelect = ProjectAddNewForm };
251                   // MenuItem { popupContent, "Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
252                   MenuDivider { popupContent };
253                   if(node != ((Project)workspace.projects.first).topNode)
254                   {
255                      MenuItem { popupContent, "Remove project from workspace", r, NotifySelect = ProjectRemove }.disabled = buildInProgress;
256                      MenuDivider { popupContent };
257                   }
258                   MenuItem { popupContent, "Active Configuration...", s, Key { f5, alt = true } , NotifySelect = MenuConfig };
259                   MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
260                   MenuDivider { popupContent };
261                   MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
262                   MenuDivider { popupContent };
263                   MenuItem { popupContent, "Save", v, Key { s, ctrl = true }, NotifySelect = ProjectSave }.disabled = !node.modified;
264                   MenuDivider { popupContent };
265                   MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
266                }
267                else if(node.type == resources)
268                {
269                   MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
270                   MenuItem { popupContent, "Add Resources to Project...", f, NotifySelect = ResourcesAddFiles };
271                   MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
272                   MenuDivider { popupContent };
273                   MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
274                   MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
275                }
276                else if(node.type == file)
277                {
278                   MenuItem { popupContent, "Open", o, NotifySelect = FileOpenFile };
279                   MenuItem { popupContent, "Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile }.disabled = buildInProgress;
280                   MenuDivider { popupContent };
281                   MenuItem { popupContent, "Remove", r, NotifySelect = FileRemoveFile };
282                   MenuDivider { popupContent };
283                   MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
284                   MenuDivider { popupContent };
285                   MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
286                   MenuItem { popupContent, "Properties..", p, Key { enter, alt = true }, NotifySelect = FileProperties };
287                }
288                else if(node.type == folder)
289                {
290                   bool isInResources = node.isInResources;
291
292                   MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
293                   MenuItem { popupContent, "Import Folder...", f, NotifySelect = ProjectImportFolder };
294                   if(isInResources)
295                   {
296                      MenuItem { popupContent, "Add Resources to Folder...", f, NotifySelect = ResourcesAddFiles };
297                   }
298                   else
299                   {
300                      MenuItem { popupContent, "Add Files to Folder...", f, NotifySelect = ProjectAddFiles };
301                   }
302                   if(!isInResources)
303                   {
304                      MenuDivider { popupContent };
305                      MenuItem { popupContent, "Add New Form...", o, NotifySelect = ProjectAddNewForm };
306                      MenuItem { popupContent, "Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
307                   }
308                   MenuDivider { popupContent };
309                   MenuItem { popupContent, "Remove", r, NotifySelect = FileRemoveFile };
310                   MenuDivider { popupContent };
311                   MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
312                   MenuDivider { popupContent };
313                   MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
314                   MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
315                }
316
317                popupMenu = 
318                {
319                   master = this, menu = popupContent;
320                   position = {
321                      x + clientStart.x + absPosition.x - app.desktop.position.x, 
322                      y + clientStart.y + absPosition.y - app.desktop.position.y };
323                };
324                popupMenu.Create();
325             }
326          }
327          return true;
328       }
329
330       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
331       {
332          if(row)
333          {
334             ProjectNode node = (ProjectNode)row.tag;
335             switch(key)
336             {
337                case altEnter: case Key { keyPadEnter, alt = true }:
338                {
339                   NodeProperties { parent = parent, master = this, 
340                      position = { position.x + 100, position.y + 100 }, node = node }.Create();
341                   return false;
342                }
343                case enter: case keyPadEnter:
344                {
345                   ProjectNode resNode;
346                   for(resNode = node.parent; resNode; resNode = resNode.parent)
347                      if(resNode.type == resources)
348                         break;
349                   if(node.type == project || (node.type == folder && !resNode))
350                   {
351                      AddFiles(false);
352                      return false;
353                   }
354                   else if(node.type == resources || node.type == folder)
355                   {
356                      AddFiles(true);
357                      return false;
358                   }
359                   break;
360                }
361                case ctrlI:
362                {
363                   if(node.type == project || node.type == folder || node.type == resources)
364                   {
365                      ImportFolder(node);
366                      return false;
367                   }
368                   break;
369                }
370                case ctrlF:
371                {
372                   if(node.type == project || node.type == folder || node.type == resources)
373                   {
374                      NewFolder(node, null, true);
375                      return false;
376                   }
377                   break;
378                }
379                case ctrlF7:
380                {
381                   if(node.type == file)
382                   {
383                      FileCompile(null, (Modifiers)key);
384                      return false;
385                   }
386                   break;
387                }
388                case Key { space, shift = true }:
389                case space:
390                {
391                   if(node.type == NodeTypes::project)
392                   {
393                      Project prj = null;
394                      for(p : workspace.projects)
395                      {
396                         if(p.topNode == node)
397                         {
398                            prj = p;
399                            break;
400                         }
401                      }
402                      prj.RotateActiveConfig(!key.shift);
403                      if(prj == project)
404                         ide.UpdateDisabledMenus();
405                      return false;
406                   }
407                   break;
408                }
409             }
410          }
411          switch(key)
412          {
413             case enter: case keyPadEnter:  OpenSelectedNodes();   break;
414             case del:                      RemoveSelectedNodes(); break;
415             case escape:                      
416             {
417                Window activeClient = ide.activeClient;
418                if(activeClient)
419                   activeClient.Activate();
420                else
421                   ide.RepositionWindows(true);
422                break;
423             }
424          }
425          return true;
426       }
427
428       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
429       {
430          ProjectNode node = (ProjectNode)row.tag;
431          if(node.type == folder)
432             node.icon = collapsed ? folder : openFolder;
433          return true;
434       }
435    };
436
437    FileDialog importFileDialog { autoCreate = false, type = selectDir, text = "Import Folder" };
438    FileDialog projectFileDialog
439    {
440       autoCreate = false, filters = projectFilters, sizeFilters = sizeof(projectFilters);
441       types = projectTypes, sizeTypes = sizeof(projectTypes);
442    };
443    FileDialog fileDialog
444    {
445       autoCreate = false, mayNotExist = true, filters = fileFilters, sizeFilters = sizeof(fileFilters);
446       types = fileTypes, sizeTypes = sizeof(fileTypes);
447    };
448    FileDialog resourceFileDialog
449    {
450       autoCreate = false, mayNotExist = true, filters = resourceFilters, sizeFilters = sizeof(resourceFilters);
451       types = fileTypes, sizeTypes = sizeof(fileTypes);
452    };
453
454    Menu fileMenu { menu, "File", f };
455    MenuItem { fileMenu, "Save", s, Key { s, ctrl = true }, NotifySelect = MenuFileSave };
456    // MenuItem { fileMenu, "Save As...", a, NotifySelect = MenuFileSaveAs };
457
458    bool OnClose(bool parentClosing)
459    {
460       if(!parentClosing && visible)
461       {
462          visible = false;
463          return false;
464       }
465       if(buildInProgress)
466          return false;
467       return true;
468    }
469
470    void OnDestroy(void)
471    {
472       //if(ide.findInFilesDialog && ide.findInFilesDialog.created && ide.findInFilesDialog.mode != directory)
473       //   ide.findInFilesDialog.SearchStop();
474
475       ide.outputView.buildBox.Clear();
476       ide.outputView.debugBox.Clear();
477       //ide.outputView.findBox.Clear();
478       ide.callStackView.Clear();
479       ide.watchesView.Clear();
480       ide.threadsView.Clear();
481       ide.breakpointsView.Clear();
482       ide.outputView.ShowClearSelectTab(find); // why this? 
483    }
484
485    bool OnSaveFile(char * fileName)
486    {
487       for(prj : ide.workspace.projects)
488       {
489          if(prj.topNode.modified && prj.Save(prj.filePath))
490          {
491             // ProjectUpdateMakefileForAllConfigs(prj, true, true);
492             prj.topNode.modified = false;
493          }
494       }
495       modifiedDocument = false;
496       Update(null);
497       return true;
498    }
499
500    bool IsModuleInProject(char * filePath)
501    {
502       char moduleName[MAX_FILENAME]; //, modulePath[MAX_LOCATION];
503       GetLastDirectory(filePath, moduleName);
504       return project.topNode.Find(moduleName, false) != null;
505    }
506
507    bool GetRelativePath(char * filePath, char * relativePath)
508    {
509       /*ProjectNode node;
510       char moduleName[MAX_FILENAME]; //, modulePath[MAX_LOCATION];
511       GetLastDirectory(filePath, moduleName);
512       
513       // try with workspace dir first?
514       if((node = project.topNode.Find(moduleName, false)))
515       {
516          strcpy(relativePath, node.path);
517          PathCatSlash(relativePath, node.name);
518          return true;
519       }
520       // WARNING: On failure, relative path is uninitialized
521       return false;   */
522       return project.GetRelativePath(filePath, relativePath);
523    }
524
525    ProjectNode GetNodeFromWindow(Window document, Project project)
526    {
527       if(document.fileName)
528       {
529          char winFileName[MAX_LOCATION];
530          char * documentFileName = GetSlashPathBuffer(winFileName, document.fileName);
531          for(p : ide.workspace.projects)
532          {
533             Project prj = project ? project : p;
534             ProjectNode node;
535             char moduleName[MAX_FILENAME], modulePath[MAX_LOCATION];
536             GetLastDirectory(document.fileName, moduleName);
537
538             if((node = prj.topNode.Find(moduleName, false)))
539             {
540                strcpy(modulePath, prj.topNode.path);
541                PathCatSlash(modulePath, node.path);
542                PathCatSlash(modulePath, node.name);
543                if(!fstrcmp(documentFileName, modulePath))
544                {
545                   return node;
546                }
547             }
548             if(project) break;
549          }
550       }
551       return null;
552    }
553
554    void Compile(ProjectNode node)
555    {
556       char fileName[MAX_LOCATION];
557       char extension[MAX_EXTENSION];
558       Window document;
559       Project prj = node.project;
560       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
561       DirExpression objDir = prj.objDir;
562
563       strcpy(fileName, prj.topNode.path);
564       PathCatSlash(fileName, objDir.dir);
565       PathCatSlash(fileName, node.name);
566       StripExtension(fileName);
567       strcat(fileName, ".o");
568       if(FileExists(fileName))
569          DeleteFile(fileName);
570
571       GetExtension(node.name, extension);
572       if(!strcmp(extension, "ec"))
573       {
574          // Delete generated C file
575          strcpy(fileName, prj.topNode.path);
576          PathCat(fileName, objDir.dir);
577          PathCat(fileName, node.name);
578          StripExtension(fileName);
579          strcat(fileName, ".c");
580          if(FileExists(fileName))
581             DeleteFile(fileName);
582
583          // Delete symbol file
584          strcpy(fileName, prj.topNode.path);
585          PathCat(fileName, node.path);
586          PathCat(fileName, node.name);
587          StripExtension(fileName);
588          strcat(fileName, ".sym");
589          if(FileExists(fileName))
590             DeleteFile(fileName);
591       }
592
593       ide.StopBuild(false);
594
595       // Check if we have to save
596       strcpy(fileName, prj.topNode.path);
597       PathCatSlash(fileName, node.path);
598       PathCatSlash(fileName, node.name);
599       for(document = ide.firstChild; document; document = document.next)
600       {
601          if(document.modifiedDocument)
602          {
603             char documentFileName[MAX_LOCATION];
604             if(!fstrcmp(GetSlashPathBuffer(documentFileName, document.fileName), fileName))
605                if(!document.MenuFileSave(null, 0))
606                   return;
607          }
608       }
609
610       if(ProjectPrepareForToolchain(prj, normal, true, true))
611       {
612          if(!node.isExcluded)
613          {
614             buildInProgress = true;
615
616             //ide.outputView.ShowClearSelectTab(build);
617             // this stuff doesn't even appear
618             //ide.outputView.buildBox.Logf("%s Compiler\n", compiler.name);
619             if(prj.config)
620                ide.outputView.buildBox.Logf("Compiling single file %s in project %s using the %s configuration...\n", node.name, prj.name, prj.config.name);
621             else
622                ide.outputView.buildBox.Logf("Compiling single file %s in project %s...\n", node.name, prj.name);
623
624             ide.DisableBuildItems(true, false);
625             prj.Compile(node);
626             ide.DisableBuildItems(false, false);
627             buildInProgress = false;
628          }
629          else
630             ide.outputView.buildBox.Logf("File %s is excluded from current build configuration.\n", node.name);
631       }
632       delete objDir;
633       delete compiler;
634    }
635
636    void GoToError(const char * line)
637    {
638       char * colon;
639       char * parenthesisOpen;
640       char * parenthesisClose;
641       
642       while(isspace(*line)) line++;
643       colon = strstr(line, ":");
644       parenthesisOpen = strstr(line, "(");
645       if(parenthesisOpen)
646       {
647          parenthesisClose = strstr(parenthesisOpen, ")");
648          if(parenthesisOpen && parenthesisClose)
649          {
650             int len = parenthesisOpen - line;
651             char * errorFilePath = new char[len+1];
652             int lineNumber = atoi(parenthesisOpen+1);
653             char filePath[MAX_LOCATION];
654             strncpy(errorFilePath, line, len);
655             errorFilePath[len] = '\0';
656             GetWorkingDir(filePath, sizeof(filePath));
657             strcpy(filePath, project.topNode.path);
658             MakeSlashPath(errorFilePath);
659             PathCatSlash(filePath, errorFilePath);
660             if(FileExists(filePath).isFile)
661             {
662                CodeEditor codeEditor;
663                codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, true, null, no, normal);
664                if(!codeEditor)
665                   PrintLn("Could not open ", filePath, " file."); // might want to add added project support here
666                if(codeEditor && lineNumber)
667                {
668                   EditBox editBox = codeEditor.editBox;
669                   editBox.GoToLineNum(lineNumber - 1);
670                   //editBox.GoToPosition(editBox.line, lineNumber - 1, col ? (col - 1) : 0);
671                }
672             }
673             delete errorFilePath;
674             return;
675          }
676       }
677
678       {
679          int lineNumber = 0;
680          int col = 1;
681          bool lookForLineNumber = true;
682
683          // deal with linking error
684          if(colon && colon[1] == ' ')
685          {
686             colon = strstr(colon + 1, ":");
687             if(colon && !colon[1])
688             {
689                colon = strstr(line, ":");
690                lookForLineNumber = false;
691             }
692             else if(colon && !isdigit(colon[1]))
693             {
694                line = colon + 1;
695                colon = strstr(line, ":");
696             }
697          }
698          // Don't be mistaken by the drive letter colon
699          if(colon && (colon[1] == '/' || colon[1] == '\\'))
700             colon = strstr(colon + 1, ":");
701          if(colon && lookForLineNumber)
702          {
703             char * comma;
704             if((colon+1)[0] == ' ')
705             {
706                // NOTE: This is the same thing as saying 'colon = line'
707                for( ; colon != line; colon--)
708                   /*if(*colon == '(')
709                      break*/;
710             }
711             lineNumber = atoi(colon + 1);
712             /*
713             comma = strchr(colon, ',');
714             if(comma)
715                col = atoi(comma+1);
716             */
717             comma = strchr(colon+1, ':');
718             if(comma)
719                col = atoi(comma+1);
720          }
721          
722          {
723             char moduleName[MAX_LOCATION], filePath[MAX_LOCATION];
724             char * bracket;
725             if(colon)
726             {
727                // Cut module name
728                strncpy(moduleName, line, colon - line);                  
729                moduleName[colon - line] = '\0';
730             }
731             else
732                strcpy(moduleName, line);
733
734             // Remove stuff in brackets
735             /*
736             bracket = strstr(moduleName, "(");
737             if(bracket) *bracket = '\0';
738             */
739             MakeSlashPath(moduleName);
740
741             if(!colon)
742             {
743                // Check if it's one of our modules
744                ProjectNode node = project.topNode.Find(moduleName, false);
745                if(node)
746                {
747                   strcpy(moduleName, node.path);
748                   PathCatSlash(moduleName, node.name);
749                }
750                else
751                   moduleName[0] = '\0';
752             }
753             if(moduleName[0])
754             {
755                CodeEditor codeEditor;
756                strcpy(filePath, project.topNode.path);
757                PathCatSlash(filePath, moduleName);
758       
759                codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, true, null, no, normal);
760                if(!codeEditor)
761                {
762                   char name[MAX_LOCATION];
763                   // TOFIX: Improve on this, don't use only filename, make a function
764                   if(ide && ide.workspace)
765                   {
766                      for(prj : ide.workspace.projects)
767                      {
768                         if(prj.topNode.FindWithPath(moduleName, false))
769                         {
770                            strcpy(filePath, prj.topNode.path);
771                            PathCatSlash(filePath, moduleName);
772                            codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, true, null, no, normal);
773                            if(codeEditor)
774                               break;
775                         }
776                      }
777                   }
778                }
779                if(codeEditor && lineNumber)
780                {
781                   EditBox editBox = codeEditor.editBox;
782                   editBox.GoToLineNum(lineNumber - 1);
783                   editBox.GoToPosition(editBox.line, lineNumber - 1, col ? (col - 1) : 0);
784                }
785             }
786          }
787       }
788    }
789
790    bool OpenNode(ProjectNode node)
791    {
792       char filePath[MAX_LOCATION];
793       ProjectNode nodeRoot;
794
795       for(nodeRoot = node; nodeRoot.parent; nodeRoot = nodeRoot.parent) { }
796
797       strcpy(filePath, nodeRoot.path);
798       PathCat(filePath, node.path);
799       PathCat(filePath, node.name);
800       
801       return ide.OpenFile(filePath, normal, true/*false Why was it opening hidden?*/, null, something, normal) ? true : false;
802    }
803
804    void AddNode(ProjectNode node, DataRow addTo)
805    {
806       DataRow row = addTo ? addTo.AddRow() : fileList.AddRow();
807
808       row.tag = (int)node;
809       node.row = row;
810
811       if(node.type == resources)
812          resourceRow = row;
813
814       row.SetData(null, node);
815
816       if(node.files && node.files.first && node.parent && 
817             !(!node.parent.parent && 
818                (!strcmpi(node.name, "notes") || !strcmpi(node.name, "sources") || 
819                   !strcmpi(node.name, "src") || !strcmpi(node.name, "tools"))))
820          row.collapsed = true;
821       else if(node.type == folder)
822          node.icon = openFolder;
823
824       if(node.files)
825       {
826          for(child : node.files)
827             AddNode(child, row);
828       }
829    }
830
831    void DeleteNode(ProjectNode projectNode)
832    {
833       if(projectNode.files)
834       {
835          ProjectNode child;
836          while(child = projectNode.files.first)
837             DeleteNode(child);
838       }
839       fileList.DeleteRow(projectNode.row);
840       projectNode.Delete();
841    }
842
843    ProjectView()
844    {
845       NodeIcons c;
846       for(c = 0; c < NodeIcons::enumSize; c++)
847       {
848          icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
849          AddResource(icons[c]);
850       }
851       fileList.AddField(DataField { dataType = class(ProjectNode), freeData = false, userData = this });
852    }
853
854    ~ProjectView()
855    {
856       ide.debugger.Stop();
857       ide.DestroyTemporaryProjectDir();
858       if(project)
859       {
860          workspace.Free();
861          delete workspace;
862       }
863    }
864
865    bool ProjectSave(MenuItem selection, Modifiers mods)
866    {
867       DataRow row = fileList.currentRow;
868       ProjectNode node = row ? (ProjectNode)row.tag : null;
869       Project prj = node ? node.project : null;
870       if(prj)
871       {
872          if(prj.Save(prj.filePath))
873          {
874             // ProjectUpdateMakefileForAllConfigs(prj, true, true);
875             prj.topNode.modified = false;
876             prj = null;
877             for(p : ide.workspace.projects)
878             {
879                if(p.topNode.modified)
880                { 
881                   prj = p;
882                   break;
883                }
884             }
885             if(!prj)
886                modifiedDocument = false;
887             Update(null);
888          }
889       }
890       return true;
891    }
892
893    bool ShowOutputBuildLog(bool cleanLog)
894    {
895       OutputView output = ide.outputView;
896       if(cleanLog)
897          output.ShowClearSelectTab(build);
898       else
899       {
900          output.SelectTab(build);
901          output.Show();
902       }
903    }
904
905    bool DisplayCompiler(bool cleanLog)
906    {
907       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
908       LogBox logBox = ide.outputView.buildBox;
909       ShowOutputBuildLog(cleanLog);
910       logBox.Logf("%s Compiler\n", compiler ? compiler.name : "{problem with compiler selection}");
911       delete compiler;
912    }
913
914    bool ProjectUpdateMakefileForAllConfigs(Project project, bool cleanLog, bool displayCompiler)
915    {
916       ProjectConfig currentConfig = project.config;
917       ShowOutputBuildLog(cleanLog);
918
919       if(displayCompiler)
920          DisplayCompiler(false);
921       
922       for(config : project.configurations)
923       {
924          project.config = config;
925          ProjectPrepareMakefile(project, forceExists, false, false);
926       }
927
928       project.config = currentConfig;
929
930       ide.Update(null);
931    }
932
933    bool ProjectPrepareForToolchain(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler)
934    {
935       bool isReady = true;
936       char message[MAX_F_STRING];
937       LogBox logBox = ide.outputView.buildBox;
938
939       ShowOutputBuildLog(cleanLog);
940
941       if(displayCompiler)
942          DisplayCompiler(false);
943
944       ProjectPrepareMakefile(project, method, false, false);
945       return true;
946    }
947
948    bool ProjectPrepareMakefile(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler)
949    {
950       char makefilePath[MAX_LOCATION];
951       char makefileName[MAX_LOCATION];
952       bool exists;
953       LogBox logBox = ide.outputView.buildBox;
954       
955       ShowOutputBuildLog(cleanLog);
956
957       if(displayCompiler)
958          DisplayCompiler(false);
959
960       strcpy(makefilePath, project.topNode.path);
961       project.CatMakeFileName(makefileName);
962       PathCatSlash(makefilePath, makefileName);
963
964       exists = FileExists(makefilePath);
965       if((method == normal && (!exists || project.config.makingModified/*|| project.topNode.modified*/)) ||
966             (method == forceExists && exists) || 
967             method == force) // || project.config.makingModified || makefileDirty
968       {
969          char * reason;
970          char * action;
971          ide.statusBar.text = "Generating Makefile & Dependencies..."; // Dependencies?
972          app.UpdateDisplay();
973          
974          if((method == normal && !exists) || (method == force && !exists))
975             action = "Generating ";
976          else if(method == force)
977             action = "Regenerating ";
978          else if(method == normal || method == forceExists)
979             action = "Updating ";
980          else
981             action = "";
982          if(!exists)
983             reason = "Makefile doesn't exist. ";
984          else if(project.topNode.modified)
985             reason = "Project has been modified. ";
986          else
987             reason = "";
988
989          //logBox.Logf("%s\n", makefileName);
990          logBox.Logf("%s - %s%smakefile for %s config...\n", makefileName, reason, action, project.configName);
991          project.GenerateMakefile(null, false, null);
992
993          ide.statusBar.text = null;
994          app.UpdateDisplay();
995          return true;
996       }
997       return false;
998    }
999    
1000    bool ProjectBuild(MenuItem selection, Modifiers mods)
1001    {
1002       Project prj = project;
1003       if(selection || !ide.activeClient || activeClient == this)
1004       {
1005          DataRow row = fileList.currentRow;
1006          ProjectNode node = row ? (ProjectNode)row.tag : null;
1007          if(node) prj = node.project;
1008       }
1009       // Added this code here until dependencies work:
1010       else //if(ide.activeClient)
1011       {
1012          ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
1013          if(node)
1014             prj = node.project;
1015       }
1016       if(prj != project || !ide.DontTerminateDebugSession("Project Build"))
1017          BuildInterrim(prj, build, false);
1018       return true;
1019    }
1020
1021    bool BuildInterrim(Project prj, BuildType buildType, bool disableDebugStart)
1022    {
1023       if(ProjectPrepareForToolchain(prj, normal, true, true))
1024       {
1025          ide.outputView.buildBox.Logf("Building project %s using the %s configuration...\n", prj.name, prj.configName);
1026          return Build(prj, buildType, disableDebugStart);
1027       }
1028       return false;
1029    }
1030
1031    bool ProjectLink(MenuItem selection, Modifiers mods)
1032    {
1033       Project prj = project;
1034       if(selection || !ide.activeClient || activeClient == this)
1035       {
1036          DataRow row = fileList.currentRow;
1037          ProjectNode node = row ? (ProjectNode)row.tag : null;
1038          if(node) prj = node.project;
1039       }
1040       // Added this code here until dependencies work:
1041       else //if(ide.activeClient)
1042       {
1043          ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
1044          if(node)
1045             prj = node.project;
1046       }
1047       if(ProjectPrepareForToolchain(prj, normal, true, true))
1048       {
1049          ide.outputView.buildBox.Logf("Relinking project %s using the %s configuration...\n", prj.name, prj.configName);
1050          if(prj.config)
1051             prj.config.linkingModified = true;
1052          Build(prj, relink, false);
1053       }
1054       return true;
1055    }
1056
1057    bool ProjectRebuild(MenuItem selection, Modifiers mods)
1058    {
1059       Project prj = GetSelectedProject((bool)selection);
1060       if(ProjectPrepareForToolchain(prj, normal, true, true))
1061       {
1062          ide.outputView.buildBox.Logf("Rebuilding project %s using the %s configuration...\n", prj.name, prj.configName);
1063          /*if(prj.config)
1064          {
1065             prj.config.compilingModified = true;
1066             prj.config.makingModified = true;
1067          }*/ // -- should this still be used depite the new solution of BuildType?
1068          Build(prj, rebuild, false);
1069       }
1070       return true;
1071    }
1072
1073    bool ProjectClean(MenuItem selection, Modifiers mods)
1074    {
1075       Project prj = GetSelectedProject((bool)selection);
1076       if(ProjectPrepareForToolchain(prj, normal, true, true))
1077       {
1078          ide.outputView.buildBox.Logf("Cleaning project %s using the %s configuration...\n", prj.name, prj.configName);
1079          
1080          buildInProgress = true;
1081          ide.DisableBuildItems(true, false);
1082
1083          prj.Clean();
1084          ide.DisableBuildItems(false, false);
1085          buildInProgress = false;
1086       }
1087       return true;
1088    }
1089
1090    bool ProjectRegenerate(MenuItem selection, Modifiers mods)
1091    {
1092       Project prj = project;
1093       if(selection || !ide.activeClient || activeClient == this)
1094       {
1095          DataRow row = fileList.currentRow;
1096          ProjectNode node = row ? (ProjectNode)row.tag : null;
1097          if(node)
1098             prj = node.project;
1099       }
1100       // Added this code here until dependencies work:
1101       else //if(ide.activeClient)
1102       {
1103          ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
1104          if(node)
1105             prj = node.project;
1106       }
1107
1108       ProjectPrepareMakefile(prj, force, true, true);
1109       return true;
1110    }
1111
1112    bool ProjectNewFolder(MenuItem selection, Modifiers mods)
1113    {
1114       DataRow row = fileList.currentRow;
1115       if(row)
1116       {
1117          ProjectNode parentNode = (ProjectNode)row.tag;
1118          NewFolder(parentNode, null, true);
1119       }
1120       return true;
1121    }
1122
1123    bool ResourcesAddFiles(MenuItem selection, Modifiers mods)
1124    {
1125       AddFiles(true);
1126       return true;
1127    }
1128
1129    bool ProjectAddFiles(MenuItem selection, Modifiers mods)
1130    {
1131       AddFiles(false);
1132       return true;
1133    }
1134
1135    bool ProjectImportFolder(MenuItem selection, Modifiers mods)
1136    {
1137       DataRow row = fileList.currentRow;
1138       if(row)
1139       {
1140          ProjectNode toNode = (ProjectNode)row.tag;
1141          ImportFolder(toNode);
1142       }
1143       return true;
1144    }
1145
1146    bool ProjectAddNewForm(MenuItem selection, Modifiers mods)
1147    {
1148       CodeEditor codeEditor = CreateNew("Form", "form", "Window", null);
1149       codeEditor.EnsureUpToDate();
1150       return true;
1151    }
1152
1153    bool ProjectAddNewGraph(MenuItem selection, Modifiers mods)
1154    {
1155       CodeEditor codeEditor = CreateNew("Graph", "graph", "Block", null);
1156       if(codeEditor)
1157          codeEditor.EnsureUpToDate();
1158       return true;
1159    }
1160
1161    bool ProjectRemove(MenuItem selection, Modifiers mods)
1162    {
1163       DataRow row = fileList.currentRow;
1164       if(row)
1165       {
1166          ProjectNode node = (ProjectNode)row.tag;
1167          if(node.type == project)
1168             RemoveSelectedNodes();
1169       }
1170       return true;
1171    }
1172
1173    bool MenuConfig(MenuItem selection, Modifiers mods)
1174    {
1175       if(ProjectActiveConfig { parent = parent.parent, master = parent, project = project }.Modal() == ok)
1176          ide.UpdateDisabledMenus();
1177       return true;
1178    }
1179
1180    bool MenuCompiler(MenuItem selection, Modifiers mods)
1181    {
1182       ActiveCompilerDialog compilerDialog
1183       {
1184          parent = parent.parent, master = parent;
1185          ideSettings = ideSettings, workspaceActiveCompiler = ide.workspace.compiler;
1186       };
1187       incref compilerDialog;
1188       if(compilerDialog.Modal() == ok && strcmp(compilerDialog.workspaceActiveCompiler, ide.workspace.compiler))
1189       {
1190          ide.workspace.compiler = compilerDialog.workspaceActiveCompiler;
1191          for(prj : ide.workspace.projects)
1192             ide.projectView.ProjectUpdateMakefileForAllConfigs(prj, true, true);
1193       }
1194       delete compilerDialog;
1195       return true;
1196    }
1197
1198    bool MenuSettings(MenuItem selection, Modifiers mods)
1199    {
1200       ProjectNode node = GetSelectedNode(true);
1201       Project prj = node ? node.project : project;
1202       projectSettingsDialog = ProjectSettings { parent = parent.parent, master = parent, project = prj, projectNode = node };
1203       projectSettingsDialog.Modal();
1204
1205       Update(null);
1206       ide.UpdateDisabledMenus();
1207       return true;
1208    }
1209
1210    bool FileProperties(MenuItem selection, Modifiers mods)
1211    {
1212       DataRow row = fileList.currentRow;
1213       if(row)
1214       {
1215          ProjectNode node = (ProjectNode)row.tag;
1216          NodeProperties { parent = parent, master = this, node = node, 
1217                position = { position.x + 100, position.y + 100 } }.Create();
1218       }
1219       return true;
1220    }
1221
1222    bool FileOpenFile(MenuItem selection, Modifiers mods)
1223    {
1224       OpenSelectedNodes();
1225       return true;
1226    }
1227
1228    bool FileRemoveFile(MenuItem selection, Modifiers mods)
1229    {
1230       RemoveSelectedNodes();
1231       return true;
1232    }
1233
1234    bool FileCompile(MenuItem selection, Modifiers mods)
1235    {
1236       DataRow row = fileList.currentRow;
1237       if(row)
1238       {
1239          ProjectNode node = (ProjectNode)row.tag;
1240          Compile(node);
1241       }
1242       return true;
1243    }
1244
1245    /*bool IsProjectModified()
1246    {
1247       Window document;
1248
1249       for(document = master.firstChild; document; document = document.next)
1250       {
1251          if(document.modifiedDocument)
1252             if(GetNodeFromWindow(document), project)
1253                return true;
1254       }
1255       return false;
1256    }
1257    */
1258
1259    bool Build(Project prj, BuildType buildType, bool disableDebugStart)
1260    {
1261       bool result = true;
1262       Window document;
1263
1264       ide.StopBuild(false);
1265       for(document = master.firstChild; document; document = document.next)
1266       {
1267          if(document.modifiedDocument)
1268          {
1269             ProjectNode node = GetNodeFromWindow(document, prj);
1270             if(node && !document.MenuFileSave(null, 0))
1271             {
1272                result = false;
1273                break;
1274             }
1275          }
1276       }
1277       if(result)
1278       {
1279          DirExpression targetDir = prj.targetDir;
1280
1281          if(buildType != run && prj == project)
1282             ide.debugger.Stop();
1283          
1284          // TODO: Disabled until problems fixed... is it fixed?
1285          if(buildType == rebuild || (prj.config && prj.config.compilingModified))
1286             prj.Clean();
1287          else
1288          {
1289             if(buildType == relink || (prj.config && prj.config.linkingModified))
1290             {
1291                char target[MAX_LOCATION];
1292
1293                strcpy(target, prj.topNode.path);
1294                PathCat(target, targetDir.dir);
1295                prj.CatTargetFileName(target);
1296                if(FileExists(target))
1297                   DeleteFile(target);
1298             }
1299             if(prj.config && prj.config.symbolGenModified)
1300             {
1301                DirExpression objDir = prj.objDir;
1302                char fileName[MAX_LOCATION];
1303                char moduleName[MAX_FILENAME];
1304                strcpy(fileName, prj.topNode.path);
1305                PathCatSlash(fileName, objDir.dir);
1306                strcpy(moduleName, prj.moduleName);
1307                strcat(moduleName, ".main.ec");
1308                PathCatSlash(fileName, moduleName);
1309                if(FileExists(fileName))
1310                   DeleteFile(fileName);
1311                ChangeExtension(fileName, "c", fileName);
1312                if(FileExists(fileName))
1313                   DeleteFile(fileName);
1314                ChangeExtension(fileName, "o", fileName);
1315                if(FileExists(fileName))
1316                   DeleteFile(fileName);
1317
1318                delete objDir;
1319             }
1320          }
1321          buildInProgress = true;
1322          //if(prj == project)    // Why did we put these here? There was nothing to prevent building an added project multiple times at once
1323             ide.DisableBuildItems(true, true);
1324
1325          result = prj.Build(buildType == run, null);
1326
1327          if(prj.config)
1328          {
1329             prj.config.compilingModified = false;
1330             if(!ide.ShouldStopBuild())
1331                prj.config.linkingModified = false;
1332
1333             prj.config.symbolGenModified = false;
1334          }
1335          //if(prj == project)
1336             ide.DisableBuildItems(false, disableDebugStart);
1337          buildInProgress = false;
1338
1339          ide.workspace.modified = true;
1340
1341          delete targetDir;
1342       }
1343       return result;
1344    }
1345
1346    Project GetSelectedProject(bool useSelection)
1347    {
1348       Project prj = project;
1349       if(useSelection)
1350       {
1351          DataRow row = fileList.currentRow;
1352          ProjectNode node = row ? (ProjectNode)row.tag : null;
1353          if(node)
1354             prj = node.project;
1355       }
1356       return prj;
1357    }
1358    
1359    ProjectNode GetSelectedNode(bool useSelection)
1360    {
1361       ProjectNode node = null;
1362       if(useSelection)
1363       {
1364          DataRow row = fileList.currentRow;
1365          if(row)
1366             node = (ProjectNode)row.tag;
1367       }
1368       return node;
1369    }
1370
1371    bool MenuBrowseFolder(MenuItem selection, Modifiers mods)
1372    {
1373       char folder[MAX_LOCATION];
1374       Project prj;
1375       ProjectNode node = GetSelectedNode(true);
1376       if(!node)
1377          node = project.topNode;
1378       prj = node.project;
1379
1380       strcpy(folder, prj.topNode.path);
1381       if(node != prj.topNode)
1382          PathCatSlash(folder, node.path);
1383       ShellOpen(folder);
1384    }
1385
1386    bool Run(MenuItem selection, Modifiers mods)
1387    {
1388       char args[MAX_LOCATION * 64];
1389       args[0] = '\0';
1390       if(ide.workspace.commandLineArgs)
1391          //ide.debugger.GetCommandLineArgs(args);
1392          strcpy(args, ide.workspace.commandLineArgs);
1393       if(ide.debugger.isInDebugMode)
1394          project.Run(args);
1395       /*else if(project.config.targetType == sharedLibrary || project.config.targetType == staticLibrary)
1396          MessageBox { type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();*/
1397       else if(BuildInterrim(project, run, false))
1398          project.Run(args);
1399       return true;
1400    }
1401
1402    bool DebugStart()
1403    {
1404       bool result = false;
1405       if(project.targetType == sharedLibrary || project.targetType == staticLibrary)
1406          MessageBox { type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();
1407       else if(project.compress)
1408          MessageBox { text = "Starting Debug", contents = "Debugging compressed applications is not supported\n" }.Modal();
1409       else if(project.debug ||
1410          MessageBox { type = okCancel, text = "Starting Debug", contents = "Attempting to debug non-debug configuration\nProceed anyways?" }.Modal() == ok)
1411       {
1412          if(/*!IsProjectModified() ||*/ BuildInterrim(project, debug, true))
1413          {
1414             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1415             if(compiler.type.isVC)
1416             {
1417                //bool result = false;
1418                char oldwd[MAX_LOCATION];
1419                char oldPath[MAX_LOCATION * 65];
1420                char command[MAX_LOCATION];
1421
1422                GetEnvironment("PATH", oldPath, sizeof(oldPath));
1423                ide.SetPath(false); //true
1424                
1425                GetWorkingDir(oldwd, sizeof(oldwd));
1426                ChangeWorkingDir(project.topNode.path);
1427
1428                sprintf(command, "%s /useenv %s.sln /projectconfig \"%s|Win32\" /command \"%s\"" , "devenv", project.name, project.config.name, "Debug.Start");
1429                //ide.outputView.buildBox.Logf("command: %s\n", command);
1430                Execute(command);
1431                ChangeWorkingDir(oldwd);
1432                SetEnvironment("PATH", oldPath);
1433             }
1434             else
1435             {
1436                ide.debugger.Start();
1437                result = true;
1438             }
1439
1440             delete compiler;
1441          }
1442       }
1443       return result;      
1444    }
1445
1446    bool DebugRestart()
1447    {
1448       if(/*!IsProjectModified() ||*/ BuildInterrim(project, debug, true))
1449       {
1450          ide.debugger.Restart();
1451          return true;
1452       }
1453       return false;
1454    }
1455
1456    bool DebugResume()
1457    {
1458       ide.debugger.Resume();
1459       return true;
1460    }
1461
1462    bool DebugBreak()
1463    {
1464       ide.debugger.Break();
1465       return true;
1466    }
1467
1468    bool DebugStop()
1469    {
1470       ide.debugger.Stop();
1471       return true;
1472    }
1473
1474    bool DebugStepInto()
1475    {
1476       if((ide.debugger.isInDebugMode) || (!buildInProgress && BuildInterrim(project, debug, true)))
1477          ide.debugger.StepInto();
1478       return true;
1479    }
1480
1481    bool DebugStepOver(bool skip)
1482    {
1483       if((ide.debugger.isInDebugMode) || (!buildInProgress && BuildInterrim(project, debug, true)))
1484          ide.debugger.StepOver(skip);
1485       return true;
1486    }
1487
1488    bool DebugStepOut(bool skip)
1489    {
1490       ide.debugger.StepOut(skip);
1491       return true;
1492    }
1493
1494    void ImportFolder(ProjectNode toNode)
1495    {
1496       if(toNode)
1497       {
1498          //bool isFolder = toNode.type == folder;
1499          //bool isRes = toNode.isInResources;
1500          
1501          FileDialog fileDialog = importFileDialog;
1502          fileDialog.parent = parent;
1503          if(fileDialog.Modal() == ok)
1504          {
1505             ImportFolderFSI fsi { projectView = this };
1506             fsi.stack.Add(toNode);
1507             fsi.Iterate(fileDialog.filePath);
1508             delete fsi;
1509          }
1510       }
1511    }
1512
1513    ProjectNode NewFolder(ProjectNode parentNode, char * name, bool showProperties)
1514    {
1515       if(parentNode)
1516       {
1517          ProjectNode folderNode;
1518          Project prj = parentNode.project;
1519          int c;
1520          ProjectNode after = null;
1521          for(node : parentNode.files)
1522          {
1523             if(node.type != folder)
1524                break;
1525             after = node;
1526          }
1527          
1528          if(name && name[0])
1529             folderNode = parentNode.Add(prj, name, after, folder, folder, true);
1530          else
1531          {
1532             for(c = 0; c < 100; c++)
1533             {
1534                char string[16];
1535                sprintf(string, c ? "New Folder (%d)" : "New Folder", c);
1536                if((folderNode = parentNode.Add(prj, string, after, folder, folder, true)))
1537                   break;
1538             }
1539          }
1540
1541          if(folderNode)
1542          {
1543             NodeProperties nodeProperties;
1544             modifiedDocument = true;
1545             prj.topNode.modified = true;
1546             Update(null);
1547             folderNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
1548             folderNode.row.tag = (int)folderNode;
1549                
1550             folderNode.row.SetData(null, folderNode);
1551             fileList.currentRow = folderNode.row;
1552             
1553             if(showProperties)
1554             {
1555                nodeProperties = NodeProperties
1556                {
1557                   parent = parent, master = this, position = { position.x + 100, position.y + 100 };
1558                   node = folderNode, text = "New Folder";
1559                };
1560                nodeProperties.Create();   // Modal?
1561             }
1562             return folderNode;
1563          }
1564       }
1565       return null;
1566    }
1567
1568    void AddFiles(bool resources)
1569    {
1570       FileDialog fileDialog = (!resources) ? this.fileDialog : resourceFileDialog;
1571       fileDialog.type = multiOpen;
1572       fileDialog.text = !resources ? "Add Files to Project" : "Add Resources to Project";
1573       fileDialog.parent = parent;
1574       if(fileDialog.Modal() == ok)
1575       {
1576          int c;
1577          DataRow row = fileList.currentRow;
1578          ProjectNode parentNode = (ProjectNode)row.tag;
1579          bool addFailed = false;
1580          int numSelections = fileDialog.numSelections;
1581          char ** multiFilePaths = fileDialog.multiFilePaths;
1582
1583          Array<String> nameConflictFiles { };
1584
1585          for(c = 0; c < numSelections; c++)
1586          {
1587             char * filePath = multiFilePaths[c];
1588             FileAttribs exists = FileExists(filePath);
1589             bool addThisFile = true;
1590
1591             if(exists.isDirectory)
1592                addThisFile = false;
1593             else if(!exists)
1594             {
1595                if(MessageBox { type = yesNo, parent = parent, master = this, text = filePath, 
1596                      contents = "File doesn't exist. Create?" }.Modal() == yes)
1597                {
1598                   File f = FileOpen(filePath, write);
1599                   if(f)
1600                   {
1601                      addThisFile = true;
1602                      delete f;
1603                   }
1604                   else
1605                   {
1606                      MessageBox { type = ok, parent = parent, master = this, text = filePath, 
1607                            contents = "Couldn't create file."}.Modal();
1608                      addThisFile = false;
1609                   }
1610                }
1611             }
1612
1613             if(addThisFile)
1614             {
1615                /*addFailed = */if(!AddFile(parentNode, filePath, resources))//;
1616                {
1617                   nameConflictFiles.Add(CopyString(filePath));
1618                   addFailed = true;
1619                }
1620             }
1621          }
1622          if(addFailed)
1623          {
1624             int len = 0;
1625             char * part1 = "The following file";
1626             char * opt1 = " was ";
1627             char * opt2 = "s were ";
1628             char * part2 = "not added because of identical file name conflict within the project.\n\n";
1629             char * message;
1630             len += strlen(part1);
1631             len += strlen(part2);
1632             len += nameConflictFiles.count > 1 ? strlen(opt2) : strlen(opt1);
1633             for(s : nameConflictFiles)
1634                len += strlen(s) + 1;
1635             message = new char[len + 1];
1636             strcpy(message, part1);
1637             strcat(message, nameConflictFiles.count > 1 ? opt2 : opt1);
1638             strcat(message, part2);
1639             for(s : nameConflictFiles)
1640             {
1641                strcat(message, s);
1642                strcat(message, "\n");
1643             }
1644             MessageBox { type = ok, parent = parent, master = this, text = "Name Conflict", 
1645                   contents = message }.Modal();
1646             delete message;
1647          }
1648          nameConflictFiles.Free();
1649          delete nameConflictFiles;
1650       }
1651    }
1652
1653    ProjectNode AddFile(ProjectNode parentNode, char * filePath, bool resources)
1654    {
1655       ProjectNode result = null;
1656       ProjectNode after = null;
1657       for(node : parentNode.files)
1658       {
1659          if(node.type != folder && node.type != file && node.type)
1660             break;
1661          after = node;
1662       }
1663
1664       result = parentNode.Add(parentNode.project, filePath, after, file, NodeIcons::SelectFileIcon(filePath), !resources);
1665
1666       if(result)
1667       {
1668          modifiedDocument = true;
1669          parentNode.project.topNode.modified = true;
1670          Update(null);
1671          project.ModifiedAllConfigs(true, false, true, true);
1672          result.row = parentNode.row.AddRowAfter(after ? after.row : null);
1673          result.row.tag = (int)result;
1674          result.row.SetData(null, result);
1675       }
1676       return result;
1677    }
1678
1679    CodeEditor CreateNew(char * upper, char * lower, char * base, char * className)
1680    {
1681       CodeEditor codeEditor = null;
1682       ProjectNode projectNode;
1683       ProjectNode after = null;
1684       DataRow row = fileList.currentRow;
1685       ProjectNode parentNode;
1686       int c;
1687
1688       if(!row) row = project.topNode.row;
1689
1690       parentNode = (ProjectNode)row.tag;
1691
1692       for(node : parentNode.files)
1693       {
1694          if(node.type != folder && node.type != file && node.type)
1695             break;
1696          after = node;
1697       }
1698       for(c = 1; c < 100; c++)
1699       {
1700          char string[16];
1701          sprintf(string, c ? "%s%d.ec" : "%s.ec", lower, c);
1702          if((projectNode = parentNode.Add(project, string, after, file, genFile, true)))
1703             break;
1704       }
1705       if(projectNode)
1706       {
1707          char name[256];
1708          char filePath[MAX_LOCATION];
1709
1710          modifiedDocument = true;
1711          project.topNode.modified = true;
1712          Update(null);
1713          project.ModifiedAllConfigs(true, false, false, true);
1714          projectNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
1715          projectNode.row.tag =(int)projectNode;
1716             
1717          projectNode.row.SetData(null, projectNode);
1718          fileList.currentRow = projectNode.row;
1719
1720          strcpy(filePath, project.topNode.path);
1721          PathCat(filePath, projectNode.path);
1722          PathCat(filePath, projectNode.name);
1723
1724          codeEditor = (CodeEditor)ide.FindWindow(filePath);
1725          if(!codeEditor)
1726          {
1727             Class baseClass = eSystem_FindClass(__thisModule, base);
1728             subclass(ClassDesignerBase) designerClass = eClass_GetDesigner(baseClass);
1729             if(designerClass)
1730             {
1731                codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, false, null, whatever, normal);
1732                strcpy(name, projectNode.name);
1733                sprintf(name, "%s%d", upper, c);
1734                if(className)
1735                   strcpy(className, name);
1736
1737                designerClass.CreateNew(codeEditor.editBox, codeEditor.clientSize, name, base);
1738
1739                //codeEditor.modifiedDocument = false;
1740                //codeEditor.designer.modifiedDocument = false;
1741
1742                //Code_EnsureUpToDate(codeEditor);
1743             }
1744          }
1745          else // TODO: fix no symbols generated when ommiting {} for following else
1746          {
1747             codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, false, null, whatever, normal);
1748          }
1749          if(codeEditor)
1750          {
1751             codeEditor.ViewDesigner();
1752             codeEditor.codeModified = true;
1753          }
1754       }
1755       visible = false;
1756       return codeEditor;   
1757    }
1758
1759    void OpenSelectedNodes()
1760    {
1761       OldList selection;
1762       OldLink item;
1763
1764       fileList.GetMultiSelection(selection);
1765       for(item = selection.first; item; item = item.next)
1766       {
1767          DataRow row = item.data;
1768          ProjectNode node = (ProjectNode)row.tag;
1769          if(node.type == file)
1770             OpenNode(node);
1771       }
1772       selection.Free(null);
1773    }
1774
1775    void RemoveSelectedNodes()
1776    {
1777       OldList selection;
1778       OldLink item, next;
1779       
1780       fileList.GetMultiSelection(selection);
1781
1782       // Remove children of parents we're deleting
1783       for(item = selection.first; item; item = next)
1784       {
1785          OldLink i;
1786          DataRow row = item.data;
1787          ProjectNode n, node = (ProjectNode)row.tag;
1788          bool remove = false;
1789
1790          next = item.next;
1791          for(i = selection.first; i && !remove; i = i.next)
1792          {
1793             ProjectNode iNode = (ProjectNode)((DataRow)i.data).tag;
1794             for(n = node.parent; n; n = n.parent)
1795             {
1796                if(iNode == n)
1797                {
1798                   remove = true;
1799                   break;
1800                }
1801             }
1802          }
1803          if(remove)
1804             selection.Delete(item);
1805       }
1806
1807       for(item = selection.first; item; item = item.next)
1808       {
1809          DataRow row = item.data;
1810          ProjectNode node = (ProjectNode)row.tag;
1811          ProjectNode resNode;
1812          for(resNode = node.parent; resNode; resNode = resNode.parent)
1813             if(resNode.type == resources)
1814                break;
1815          if(node.type == file)
1816          {
1817             Project prj = node.project;
1818             DeleteNode(node);
1819             modifiedDocument = true;
1820             prj.topNode.modified = true;
1821             Update(null);
1822             prj.ModifiedAllConfigs(true, false, true, true);
1823          }
1824          else if(node.type == folder)
1825          {
1826             char message[1024];
1827             sprintf(message, "Are you sure you want to remove the folder \"%s\"\n"
1828                   "and all of its contents from the project?", node.name);
1829             if(MessageBox { type = yesNo, parent = parent, master = null, 
1830                   text = "Delete Folder", contents = message }.Modal() == yes)
1831             {
1832                Project prj = node.project;
1833                DeleteNode(node);
1834                modifiedDocument = true;
1835                prj.topNode.modified = true;
1836                //project.ModifiedAllConfigs(true, false, true, true);
1837             }
1838          }
1839          else if(node.type == project && node != project.topNode && !buildInProgress)
1840          {
1841             char message[1024];
1842             Project prj = null;
1843             for(p : workspace.projects)
1844             {
1845                if(p.topNode == node)
1846                {
1847                   prj = p;
1848                   break;
1849                }
1850             }
1851             sprintf(message, "Are you sure you want to remove the \"%s\" project\n" "from this workspace?", node.name);
1852             if(MessageBox { type = yesNo, parent = parent, master = null, 
1853                   text = "Remove Project", contents = message }.Modal() == yes)
1854             {
1855                // THIS GOES FIRST!
1856                DeleteNode(node);
1857                if(prj)
1858                   workspace.RemoveProject(prj);
1859                //modifiedDocument = true; // when project view is a workspace view
1860             }
1861          }
1862       }
1863       selection.Free(null);
1864    }
1865 }