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