a4959344d37a02b1146e23ea78a3a08871d48c39
[sdk] / ide / src / dialogs / NewProjectDialog.ec
1 import "ide"
2
3 FileDialog fileDialog { type = selectDir, text = $"Select project directory" };
4
5 class NewProjectDialog : Window
6 {
7    background = formColor;
8    minClientSize = { 316, 170 };
9    maxClientSize = { 640, 170 };
10    borderStyle = sizable;
11    tabCycle = true;
12    hasClose = true;
13    text = $"New Project";
14
15    char path[MAX_LOCATION];
16    char name[MAX_FILENAME];
17
18    Project project;
19    Workspace workspace;
20
21    char projectLocation[MAX_LOCATION];
22    bool createFormOption;
23
24    PathBox locationEditBox
25    {
26       this, position = { 10, 80 }, size = { 120, 22 }, anchor = { left = 10, top = 80, right = 10 };
27       hotKey = altL, text = $"Location";
28       typeExpected = directory, browseDialog = fileDialog;
29
30       NotifyModified = NotifyModifiedLocation;
31    };
32    Label { this, position = { 10, 60 }, labeledWindow = locationEditBox };
33
34    DropBox targetType { this, position = { 10, 130 }, size = { 130 }, hotKey = altT, text = $"Target Type" };
35
36    Label { this, position = { 10, 110 }, labeledWindow = targetType };
37
38    Button okBtn
39    {
40       parent = this, isDefault = true, disabled = true, position = { 170, 130 }, size = { 60 }, text = $"OK";
41       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
42       {
43          const char * prjName = projectName.contents;
44          char filePath[MAX_LOCATION];
45          char extension[MAX_EXTENSION];
46          ProjectConfig debug, release;
47
48          strcpy(projectLocation, locationEditBox.slashPath);
49          strcpy(filePath, projectLocation);
50          PathCatSlash(filePath, prjName);
51          GetExtension(filePath, extension);
52          //if(!extension[0])
53             ChangeExtension(filePath, ProjectExtension, filePath);
54
55          debug = ProjectConfig
56          {
57             name = CopyString("Debug");
58             options =
59             {
60                optimization = none;
61                fastMath = false;
62                debug = true;
63                preprocessorDefinitions = { [ CopyString("_DEBUG") ] };
64             };
65             makingModified = true;
66             compilingModified = true;
67             linkingModified = true;
68          };
69
70          release = ProjectConfig
71          {
72             name = CopyString("Release");
73             options =
74             {
75                optimization = speed;
76                fastMath = true;
77                debug = false;
78             };
79             makingModified = true;
80             compilingModified = true;
81             linkingModified = true;
82          };
83
84          /* error: too few arguments to function ‘__ecereProp_DirExpression_Set_char__PTR_’ -- debug.objDir = "debug";*/
85
86          project = Project
87          {
88             property::filePath = filePath;
89             moduleName = CopyString(name);
90             topNode.type = NodeTypes::project;
91             config = debug;
92          };
93          /*project.topNode.options = */project.options =
94          {
95             warnings = all;
96             // TOFIX: Precomp problems withou the extra ( )
97             targetType = ((TargetTypes)targetType.GetTag());
98             targetFileName = /*CopyString(*/name/*)*/;
99          };
100          if(project.options.targetType != staticLibrary)
101          {
102             project.options.libraries = { [ CopyString("ecere") ] };
103          }
104
105          project.topNode.configurations = /*project.configurations = */{ [ debug, release ] };
106          project.resNode = project.topNode.Add(project, "Resources", null, resources, archiveFile, false);
107
108          createFormOption = createForm.checked;
109
110          Destroy(DialogResult::ok);
111          return true;
112       }
113    };
114
115    void CreateNewProject()
116    {
117       char fileName[MAX_LOCATION];  // Windows Friendly path
118       ProjectView projectWindow;
119       Project prj = project;
120
121       if(!FileExists(projectLocation).isDirectory)
122       {
123          if(MessageBox { type = yesNo, master = ide,
124                text = $"Directory doesn't exist", contents = $"Create directory?" }.Modal() == yes)
125          {
126             if(!MakeDir(projectLocation))
127             {
128                MessageBox { type = ok, master = ide, text = projectLocation, contents = $"Error creating directory" }.Modal();
129                return;
130             }
131          }
132          else
133             return;
134       }
135
136       GetSystemPathBuffer(fileName, prj.filePath);
137
138       if(FileExists(prj.filePath))
139       {
140          if(MessageBox { type = yesNo, master = ide,
141                text = $"Project Already Exists", contents = $"Replace existing project?" }.Modal() == no)
142             return;
143       }
144
145       {
146          char workspaceFile[MAX_LOCATION];
147          strcpy(workspaceFile, prj.filePath);
148          ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
149          workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
150       }
151       workspace.projects.Add(prj);
152       ide.findInFilesDialog.AddProjectItem(prj);
153       ide.findInFilesDialog.mode = FindInFilesMode::project;
154       ide.findInFilesDialog.currentDirectory = prj.topNode.path;
155
156       if(!prj.Save(prj.filePath))
157       {
158          MessageBox { type = ok, master = this, text = prj.filePath, contents = $"Error writing project file" }.Modal();
159          delete prj;
160          return;
161       }
162
163       projectWindow = ide.CreateProjectView(workspace, fileName);
164
165       {
166          char newWorkingDir[MAX_LOCATION];
167          StripLastDirectory(prj.filePath, newWorkingDir);
168
169          ide.ChangeFileDialogsDirectory(newWorkingDir, false);
170
171          StripLastDirectory(newWorkingDir, newWorkingDir);
172          ide.ChangeProjectFileDialogDirectory(newWorkingDir);
173       }
174       ide.toolBox.visible = true;
175
176       if(createFormOption)
177       {
178          char className[256];
179          char varName[256];
180          CodeEditor codeEditor = projectWindow.CreateNew("Form", "form", "Window", className);
181          EditBox editBox = codeEditor.editBox;
182          strcpy(varName, className);
183          if(islower(varName[0]))
184          {
185             memmove(varName+1, varName, strlen(varName)+1);
186             varName[0] = '_';
187          }
188          else
189             varName[0] = (char)tolower(varName[0]);
190
191          editBox.End();
192          editBox.Printf("\n%s %s {};\n", className, varName);
193
194          codeEditor.EnsureUpToDate();
195
196          prj.Save(prj.filePath);
197
198          projectWindow.modifiedDocument = false;
199          prj.topNode.modified = false;
200
201          /*
202          editBox.Printf("class FormApplication : GuiApplication\n");
203          editBox.Printf("{\n");
204          editBox.Printf("   %s %s {};\n", className, varName);
205          editBox.Printf("}\n");
206          editBox.Home();
207          */
208       }
209       prj.StartMonitoring();
210
211       if(prj && projectWindow)
212       {
213          CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
214          ProjectConfig config = prj.config;
215          projectWindow.ShowOutputBuildLog(true);
216          projectWindow.DisplayCompiler(compiler, false);
217          projectWindow.ProjectPrepareCompiler(prj, compiler, false);
218          projectWindow.ProjectPrepareMakefile(prj, force, compiler, config);
219          delete compiler;
220
221          ide.UpdateToolBarActiveConfigs(false);
222       }
223    }
224
225    Button
226    {
227       parent = this, position = { 240, 130 }, size = { 60 }, hotKey = escape, text = $"Cancel";
228       NotifyClicked = ButtonCloseDialog;
229    };
230    Button createForm
231    {
232       parent = this, text = $"Create Form", hotKey = altF, position = { 200, 30 };
233       isCheckbox = true, checked = true;
234    };
235
236    EditBox projectName
237    {
238       parent = this, textHorzScroll = true, position = { 10, 30 }, size = { 160 };
239       hotKey = altP, text = $"Project Name";
240       NotifyUpdate = EditBoxUpdate;
241
242       bool NotifyModified(EditBox editBox)
243       {
244          char name[MAX_FILENAME];
245          char tmp[MAX_FILENAME];
246          char lastPart[MAX_LOCATION];
247          const char * text = editBox.contents;
248
249          // drop leading path stuff that has no business here
250          GetLastDirectory(text, tmp);
251          ValidProjectNameBufCopy(name, tmp);
252
253          GetLastDirectory(path, lastPart);
254          if(name[0] && (!strcmp(path, lastPart) || !path[0] || !strcmp(this.name, lastPart)))
255          {
256             if(strcmp(path, lastPart))
257                StripLastDirectory(path, path);
258             PathCatSlash(path, name);
259             locationEditBox.path = path;
260          }
261          else if(!name[0] && !strcmp(this.name, lastPart))
262          {
263             if(strcmp(path, lastPart))
264                StripLastDirectory(path, path);
265             locationEditBox.path = path;
266          }
267          else if(strcmp(name, lastPart))
268          {
269             PathCatSlash(path, name);
270             locationEditBox.path = path;
271          }
272          strcpy(this.name, name);
273          editBox.contents = name;
274          return true;
275       }
276    };
277    Label { this, position = { 10, 10 }, labeledWindow = projectName };
278
279    void EditBoxUpdate(EditBox editBox)
280    {
281       okBtn.disabled = !(locationEditBox.path[0] && projectName.contents[0]);
282    }
283
284    bool NotifyModifiedLocation(PathBox pathBox)
285    {
286       char location[MAX_LOCATION];
287       char lastPart[MAX_FILENAME];
288       char * text;
289
290       BasicValidatePathBoxPath(pathBox);
291
292       text = pathBox.slashPath;
293
294       //replacing this: NotifyUpdate = EditBoxUpdate;
295       okBtn.disabled = !(text[0] && projectName.contents[0]);
296
297       strcpy(location, ideSettings.ideProjectFileDialogLocation);
298       PathCatSlash(location, text);
299
300       GetLastDirectory(path, lastPart);
301       /*if(text[0] && (!name[0] || !strcmp(lastPart, name)))
302       {
303          char newName[MAX_FILENAME];
304          GetLastDirectory(location, newName);
305          if(strcmp(newName, location))
306          {
307             strcpy(name, newName);
308             projectName.contents = name;
309          }
310       }*/
311       strcpy(path, location);
312       pathBox.path = path;
313       return true;
314    }
315
316    NewProjectDialog()
317    {
318       char location[MAX_LOCATION];
319
320       strcpy(location, ideSettings.ideProjectFileDialogLocation);
321
322       locationEditBox.path = location;
323       strcpy(path, location);
324
325       {
326          DataRow row;
327
328          //targetType.AddField("String", null, 0);
329
330          row = targetType.AddRow();
331          row.tag = TargetTypes::executable;
332          row.SetData(null, $"Executable");
333
334          row = targetType.AddRow();
335          row.tag = TargetTypes::sharedLibrary;
336          row.SetData(null, $"Shared Library");
337
338          row = targetType.AddRow();
339          row.tag = TargetTypes::staticLibrary;
340          row.SetData(null, $"Static Library");
341
342          targetType.currentRow = targetType.FindRow(TargetTypes::executable);
343       }
344    }
345 }
346
347 class QuickProjectDialog : Window
348 {
349    background = formColor;
350    minClientSize = { 316, 110 };
351    maxClientSize = { 640, 110 };
352    borderStyle = sizable;
353    tabCycle = true;
354    hasClose = true;
355    text = $"Quick Project";
356
357    char path[MAX_LOCATION];
358    char name[MAX_FILENAME];
359
360    Label message { this, position = { 10, 10 }, text = $"Do you want to quickly create a temporary project?" };
361
362    DropBox targetType { this, position = { 10, 70 }, size = { 130 }, hotKey = altT, text = $"Target Type" };
363    Label { this, position = { 10, 50 }, labeledWindow = targetType };
364
365    Button okBtn
366    {
367       parent = this, isDefault = true, position = { 170, 70 }, size = { 60 }, text = $"OK";
368       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
369       {
370          char tempDir[MAX_LOCATION] = "";
371          char filePath[MAX_LOCATION];
372          char prjName[MAX_LOCATION] = "quick_project";
373          Project project;
374          Workspace workspace;
375          ProjectView projectWindow;
376          ProjectConfig debug, release;
377
378          /*if(!*/CreateTemporaryDir(tempDir, "ecereide");/*)
379          {
380             MessageBox { type = ok, master = this, text = tempDir, contents = "Error creating temporary directory." }.Modal();
381             return true;
382          }*/
383
384          GetLastDirectory(tempDir, prjName);
385          {
386             char * dot;
387             if((dot = strstr(prjName, ".")))
388                dot[0] = '_';
389          }
390
391          if(!FileExists(tempDir).isDirectory)
392          {
393             MessageBox { type = ok, master = this, text = tempDir, contents = $"Temporary directory does not exist." }.Modal();
394             return true;
395          }
396
397          ide.tmpPrjDir = tempDir;
398
399          strcpy(filePath, tempDir);
400          PathCatSlash(filePath, prjName);
401          //GetExtension(filePath, extension);
402          //if(!extension[0])
403             ChangeExtension(filePath, ProjectExtension, filePath);
404          GetSystemPathBuffer(filePath, filePath);
405
406          debug = ProjectConfig
407          {
408             name = CopyString("Debug");
409             options =
410             {
411                optimization = none;
412                fastMath = false;
413                debug = true;
414                preprocessorDefinitions = { [ CopyString("_DEBUG") ] };
415             };
416             makingModified = true;
417             compilingModified = true;
418             linkingModified = true;
419          };
420
421          release = ProjectConfig
422          {
423             name = CopyString("Release");
424             options =
425             {
426                optimization = speed;
427                fastMath = true;
428                debug = false;
429             };
430             makingModified = true;
431             compilingModified = true;
432             linkingModified = true;
433          };
434
435          project = Project
436          {
437             filePath = filePath;
438             moduleName = CopyString(prjName);
439             topNode.type = NodeTypes::project;
440             config = debug;
441          };
442          /*project.topNode.options = */project.options =
443          {
444             warnings = all;
445             // TOFIX: Precomp problems withou the extra ( )
446             targetType = ((TargetTypes)targetType.GetTag());
447             targetFileName = /*CopyString(*/prjName/*)*/;
448          };
449
450          if(project.options.targetType != staticLibrary)
451          {
452             project.options.libraries = { [ CopyString("ecere") ] };
453          }
454
455          {
456             char workspaceFile[MAX_LOCATION];
457             strcpy(workspaceFile, filePath);
458             ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
459             workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = workspaceFile };
460          }
461
462          workspace.projects.Add(project);
463          ide.findInFilesDialog.AddProjectItem(project);
464          ide.findInFilesDialog.mode = FindInFilesMode::project;
465          ide.findInFilesDialog.currentDirectory = project.topNode.path;
466
467          // *** Don't set this directly on project, it must be set on top ProjectNode ***
468          project.topNode.configurations = { [ debug, release ] };
469
470          project.resNode = project.topNode.Add(project, "Resources", null, resources, archiveFile, false);
471
472          if(!project.Save(filePath))
473          {
474             MessageBox { type = ok, master = this, text = filePath, contents = $"Error writing project file" }.Modal();
475             delete project;
476             delete workspace;
477             ide.DestroyTemporaryProjectDir();
478             return true;
479          }
480
481          projectWindow = ide.CreateProjectView(workspace, filePath);
482
483          {
484             char extension[MAX_EXTENSION];
485             Window document = null;
486             for(document = ide.firstChild; document; document = document.next)
487             {
488                if(document.created && document.isDocument && document._class == class(CodeEditor))
489                {
490                   const char * fileName = document.fileName;
491                   if(strstr(fileName, "http://") == fileName)
492                   {
493                      char name[MAX_LOCATION];
494                      char newFileName[MAX_LOCATION];
495                      GetLastDirectory(fileName, name);
496                      strcpy(newFileName, tempDir);
497                      PathCat(newFileName, name);
498
499                      // TODO: this should be in Windows::SaveAs(char* asFileName)
500                      // start
501                      //document.saving = true;
502                      if(document.OnSaveFile(newFileName))
503                      {
504                         document.fileName = newFileName;
505                         document.NotifySaved(document.master, /*this*/document, newFileName);
506                      }
507                      //document.saving = false;
508                      // end
509                      // TODO else MessageBox unable to save and cancel the whole project creation thing
510                      fileName = document.fileName;
511                   }
512                   if(fileName)
513                   {
514                      CodeEditor codeEditor = (CodeEditor)document;
515                      ide.projectView.AddFile(project.topNode, fileName, false, false);
516                      codeEditor.AdjustDebugMenus();
517                   }
518                }
519             }
520          }
521
522          ide.toolBox.visible = true;
523
524          if(project.topNode.modified)
525          {
526             project.Save(filePath);
527             projectWindow.modifiedDocument = false;
528             project.topNode.modified = false;
529          }
530          else
531          {
532             // TOCHECK: Why is the Quick project creating a form???
533             char className[256];
534             char varName[256];
535             CodeEditor codeEditor = projectWindow.CreateNew("Form", "form", "Window", className);
536             EditBox editBox = codeEditor.editBox;
537             strcpy(varName, className);
538             if(islower(varName[0]))
539             {
540                memmove(varName+1, varName, strlen(varName)+1);
541                varName[0] = '_';
542             }
543             else
544                varName[0] = (char)tolower(varName[0]);
545
546             editBox.End();
547             editBox.Printf("\n%s %s {};\n", className, varName);
548
549             codeEditor.EnsureUpToDate();
550
551             // TODO: how to save that new file?
552
553             project.Save(filePath);
554             projectWindow.modifiedDocument = false;
555             project.topNode.modified = false;
556          }
557          project.StartMonitoring();
558
559          visible = false;
560
561          if(project && projectWindow)
562          {
563             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
564             ProjectConfig config = project.config;
565             projectWindow.ShowOutputBuildLog(true);
566             projectWindow.DisplayCompiler(compiler, false);
567             projectWindow.ProjectPrepareCompiler(project, compiler, false);
568             projectWindow.ProjectPrepareMakefile(project, force, compiler, config);
569             delete compiler;
570          }
571
572          ide.projectView.ProjectBuild(null, Modifiers { });
573
574          Destroy(0);
575          return true;
576       }
577    };
578
579    Button
580    {
581       parent = this, position = { 240, 70 }, size = { 60 }, hotKey = escape, text = $"Cancel";
582       NotifyClicked = ButtonCloseDialog;
583    };
584
585    QuickProjectDialog()
586    {
587       DataRow row;
588
589       row = targetType.AddRow();
590       row.tag = TargetTypes::executable;
591       row.SetData(null, $"Executable");
592
593       row = targetType.AddRow();
594       row.tag = TargetTypes::sharedLibrary;
595       row.SetData(null, $"Shared Library");
596
597       row = targetType.AddRow();
598       row.tag = TargetTypes::staticLibrary;
599       row.SetData(null, $"Static Library");
600
601       targetType.currentRow = targetType.FindRow(TargetTypes::executable);
602    }
603
604    bool OnPostCreate()
605    {
606       okBtn.Activate();
607       return true;
608    }
609 }
610
611 void ValidProjectNameBufCopy(char *output, const char *input)
612 {
613    strcpy(output, input);
614    TrimLSpaces(output, output);
615    TrimRSpaces(output, output);
616    {
617       // todo: support '&', '.' and ' ' in project name on windows so that it may be used by all platforms.
618       const char * chars = "*|:\",<>?\\/&. ";
619       char ch, * s = output, * o = output;
620       while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
621       *o = '\0';
622    }
623 }