DXPExpertModule.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // DXPExpertModule
  2. {
  3. Provides MenuItems, common resources, and event handling for the DXP Expert.
  4. Licensed under MPL (http://www.mozilla.org/MPL/)
  5. Copyright 2003 - Eric Grange
  6. }
  7. unit DXPExpertModule;
  8. interface
  9. uses
  10. Windows, SysUtils, Forms, Classes, Menus, ToolsAPI, Dialogs, ActnList, ImgList,
  11. Graphics, Controls, DXPFPCConfig;
  12. type
  13. TDMDXPExpertModule = class(TDataModule)
  14. PMFreePascal: TPopupMenu;
  15. MIExecute: TMenuItem;
  16. N2: TMenuItem;
  17. MICompile: TMenuItem;
  18. MIBuild: TMenuItem;
  19. ActionList: TActionList;
  20. ACFPCExecute: TAction;
  21. ACFPCBuild: TAction;
  22. ACFPCCompile: TAction;
  23. ACFPCOptions: TAction;
  24. PMDXP: TPopupMenu;
  25. MenuItem1: TMenuItem;
  26. ACDXPOptions: TAction;
  27. N1: TMenuItem;
  28. View1: TMenuItem;
  29. MICompilerMessages: TMenuItem;
  30. ACViewCompilerMessages: TAction;
  31. N3: TMenuItem;
  32. Options1: TMenuItem;
  33. procedure ACDXPOptionsExecute(Sender: TObject);
  34. procedure ACFPCCompileExecute(Sender: TObject);
  35. procedure ActionListUpdate(Action: TBasicAction; var Handled: Boolean);
  36. procedure ACViewCompilerMessagesExecute(Sender: TObject);
  37. procedure ACFPCExecuteExecute(Sender: TObject);
  38. procedure ACFPCBuildExecute(Sender: TObject);
  39. procedure ACFPCOptionsExecute(Sender: TObject);
  40. procedure DataModuleCreate(Sender: TObject);
  41. procedure DataModuleDestroy(Sender: TObject);
  42. private
  43. { Déclarations privées }
  44. FFPCConfig : TDXPFPCConfig;
  45. FFPCConfigFileName : String;
  46. FFPCCFGBackedUp : Boolean;
  47. procedure AddMenuInIDE(popup : TPopupMenu; const aDelphiMenu : String);
  48. function GetProjectGroup : IOTAProjectGroup;
  49. function GetProject : IOTAProject;
  50. function GetModule(const moduleName : String) : IOTAModule;
  51. function ProjectBinaryName : String;
  52. function FPCConfig : TDXPFPCConfig;
  53. function FPCCommandLine(const extraOptions : String = '') : String;
  54. procedure BackupFPCConfigFile;
  55. procedure RestoreFPCConfigFile;
  56. function FPCErrorFile : String;
  57. function FPCLinkerErrorFile : String;
  58. //: Returns True if compilation succeeded
  59. function FPCCompile(const compileType : String; const extraOptions : String = '') : Boolean;
  60. public
  61. { Déclarations publiques }
  62. FOTAServices : IOTAServices;
  63. FNTAServices : INTAServices;
  64. procedure HookIDE;
  65. procedure UnHookIDE;
  66. procedure WarpTo(const moduleName : String; col, line : Integer);
  67. function FPCLocateFile(const fileName : String) : String;
  68. end;
  69. implementation
  70. {$R *.dfm}
  71. uses DXPGlobals, FDXPOptions, DXPUtils, FDXPCompileLog, FDXPFPCOptions,
  72. FDXPProgress;
  73. procedure TDMDXPExpertModule.DataModuleCreate(Sender: TObject);
  74. begin
  75. FFPCConfig:=nil; // initialized upon request
  76. end;
  77. procedure TDMDXPExpertModule.DataModuleDestroy(Sender: TObject);
  78. begin
  79. FFPCConfig.Free;
  80. end;
  81. procedure TDMDXPExpertModule.AddMenuInIDE(popup : TPopupMenu; const aDelphiMenu : String);
  82. var
  83. k, i : Integer;
  84. mm : TMainMenu;
  85. begin
  86. mm:=FNTAServices.MainMenu;
  87. k:=-1;
  88. if aDelphiMenu<>'' then for i:=0 to mm.Items.Count-1 do begin
  89. if mm.Items[i].Name=aDelphiMenu then begin
  90. k:=i;
  91. Break;
  92. end;
  93. end;
  94. if k>=0 then
  95. mm.Items.Insert(k+1, popup.Items)
  96. else mm.Items.Add(popup.Items);
  97. popup.Items.Caption:=Copy(popup.Name, 3, MaxInt);
  98. popup.Images:=mm.Images;
  99. end;
  100. procedure TDMDXPExpertModule.HookIDE;
  101. begin
  102. ActionList.Images:=FNTAServices.MainMenu.Images;
  103. AddMenuInIDE(PMFreePascal, 'RunMenu');
  104. AddMenuInIDE(PMDXP, '');
  105. end;
  106. procedure TDMDXPExpertModule.UnHookIDE;
  107. var
  108. mm : TMainMenu;
  109. begin
  110. mm:=FNTAServices.MainMenu;
  111. mm.Items.Remove(PMFreePascal.Items);
  112. mm.Items.Remove(PMDXP.Items);
  113. end;
  114. function TDMDXPExpertModule.GetProjectGroup : IOTAProjectGroup;
  115. var
  116. IModuleServices : IOTAModuleServices;
  117. i : Integer;
  118. begin
  119. Result:=nil;
  120. IModuleServices:=BorlandIDEServices as IOTAModuleServices;
  121. for i:=0 to IModuleServices.ModuleCount-1 do
  122. if Supports(IModuleServices.Modules[i], IOTAProjectGroup, Result) then
  123. Break;
  124. end;
  125. function TDMDXPExpertModule.GetProject : IOTAProject;
  126. var
  127. grp : IOTAProjectGroup;
  128. begin
  129. grp:=GetProjectGroup;
  130. if grp<>nil then
  131. Result:=grp.ActiveProject
  132. else Result:=nil;
  133. end;
  134. function TDMDXPExpertModule.ProjectBinaryName : String;
  135. var
  136. prj : IOTAProject;
  137. begin
  138. prj:=GetProject;
  139. if Assigned(prj) then
  140. Result:=ChangeFileExt(prj.FileName, '.exe')
  141. else Result:='';
  142. end;
  143. function TDMDXPExpertModule.GetModule(const moduleName : String) : IOTAModule;
  144. var
  145. i : Integer;
  146. modules : IOTAModuleServices;
  147. begin
  148. modules:=(BorlandIDEServices as IOTAModuleServices);
  149. Result:=nil;
  150. for i:=0 to modules.ModuleCount-1 do begin
  151. if CompareText(ExtractFileName(modules.Modules[i].FileName), moduleName)=0 then begin
  152. Result:=modules.Modules[i];
  153. Break;
  154. end;
  155. end;
  156. end;
  157. procedure TDMDXPExpertModule.WarpTo(const moduleName : String; col, line : Integer);
  158. var
  159. i, j : Integer;
  160. module : IOTAModule;
  161. editor : IOTASourceEditor;
  162. editPos : TOTAEditPos;
  163. view : IOTAEditView;
  164. fileName : String;
  165. begin
  166. module:=GetModule(moduleName);
  167. if not Assigned(module) then begin
  168. fileName:=FindFileInPaths(moduleName, vFPC_SourcePaths);
  169. if fileName<>'' then begin
  170. (BorlandIDEServices as IOTAActionServices).OpenFile(fileName);
  171. module:=GetModule(moduleName);
  172. end;
  173. end;
  174. if Assigned(module) then begin
  175. for i:=0 to module.ModuleFileCount-1 do begin
  176. module.ModuleFileEditors[i].QueryInterface(IOTASourceEditor, editor);
  177. if Assigned(editor) then begin
  178. editor:=(module.ModuleFileEditors[i] as IOTASourceEditor);
  179. editor.Show;
  180. editPos.Col:=col;
  181. editPos.Line:=line;
  182. for j:=0 to editor.EditViewCount-1 do begin
  183. view:=editor.EditViews[j];
  184. view.CursorPos:=editPos;
  185. view.MoveViewToCursor;
  186. view.Paint;
  187. end;
  188. end;
  189. end;
  190. end;
  191. end;
  192. function TDMDXPExpertModule.FPCLocateFile(const fileName : String) : String;
  193. function LocateInDirectory(const fileName, directory : String) : String;
  194. var
  195. sr : TSearchRec;
  196. begin
  197. if directory<>'' then begin
  198. if directory[Length(directory)]='\' then begin
  199. if FindFirst(directory+fileName, faAnyFile, sr)=0 then
  200. Result:=directory+sr.Name
  201. else Result:='';
  202. end else begin
  203. if FindFirst(directory+'\'+fileName, faAnyFile, sr)=0 then
  204. Result:=directory+'\'+sr.Name
  205. else Result:='';
  206. end;
  207. FindClose(sr);
  208. end else Result:='';
  209. end;
  210. var
  211. i : Integer;
  212. paths : TStringList;
  213. prj : IOTAProject;
  214. begin
  215. prj:=GetProject;
  216. if prj<>nil then begin
  217. Result:=LocateInDirectory(fileName, ExtractFilePath(prj.FileName));
  218. if Result<>'' then Exit;
  219. end;
  220. paths:=TStringList.Create;
  221. try
  222. StringToPaths(vFPC_SourcePaths, paths);
  223. for i:=0 to paths.Count-1 do begin
  224. Result:=LocateInDirectory(fileName, MacroExpandPath(paths[i]));
  225. if Result<>'' then Exit;
  226. end;
  227. finally
  228. paths.Free;
  229. end;
  230. Result:=fileName;
  231. end;
  232. function TDMDXPExpertModule.FPCConfig : TDXPFPCConfig;
  233. var
  234. cfgFileName : String;
  235. begin
  236. cfgFileName:=ChangeFileExt(GetProject.FileName, '.fpc-cfg');
  237. if cfgFileName<>FFPCConfigFileName then
  238. FreeAndNil(FFPCConfig);
  239. if not Assigned(FFPCConfig) then begin
  240. FFPCConfig:=TDXPFPCConfig.Create;
  241. FFPCConfigFileName:=cfgFileName;
  242. if FileExists(FFPCConfigFileName) then
  243. FFPCConfig.LoadFromFile(FFPCConfigFileName);
  244. end;
  245. Result:=FFPCConfig;
  246. end;
  247. procedure TDMDXPExpertModule.BackupFPCConfigFile;
  248. var
  249. cfgFile, cfgFileBkp : String;
  250. sl : TStringList;
  251. begin
  252. FFPCCFGBackedUp:=False;
  253. cfgFile:=vFPC_BinaryPath+'\fpc.cfg';
  254. if FileExists(cfgFile) then begin
  255. sl:=TStringList.Create;
  256. try
  257. sl.LoadFromFile(cfgFile);
  258. if (sl.Count>0) and (sl[0]<>'# DXP') then begin
  259. cfgFileBkp:=vFPC_BinaryPath+'\fpc.cfg.bak';
  260. DeleteFile(cfgFileBkp);
  261. RenameFile(cfgFile, cfgFileBkp);
  262. FFPCCFGBackedUp:=True;
  263. end;
  264. finally
  265. sl.Free;
  266. end;
  267. end;
  268. end;
  269. procedure TDMDXPExpertModule.RestoreFPCConfigFile;
  270. var
  271. cfgFile, cfgFileBkp : String;
  272. begin
  273. if FFPCCFGBackedUp then begin
  274. FFPCCFGBackedUp:=False;
  275. cfgFile:=vFPC_BinaryPath+'\fpc.cfg';
  276. cfgFileBkp:=vFPC_BinaryPath+'\fpc.cfg.bak';
  277. DeleteFile(cfgFile);
  278. RenameFile(cfgFileBkp, cfgFile);
  279. end;
  280. end;
  281. function TDMDXPExpertModule.FPCCommandLine(const extraOptions : String = '') : String;
  282. var
  283. i : Integer;
  284. prj : IOTAProject;
  285. paths : TStringList;
  286. pathName : String;
  287. cfgFile : TStringList;
  288. configOptions : String;
  289. config : TDXPFPCConfig;
  290. begin
  291. Result:='';
  292. prj:=GetProject;
  293. if not Assigned(prj) then Exit;
  294. configOptions:='';
  295. config:=FPCConfig;
  296. cfgFile:=TStringList.Create;
  297. try
  298. for i:=0 to config.Options.Count-1 do
  299. configOptions:=configOptions+' '+config.Options[i];
  300. cfgFile.CommaText:=configOptions;
  301. cfgFile.Insert(0, '# DXP');
  302. cfgFile.Insert(1, '-Sd');
  303. // cfgFile.Insert(1, '-Mobjfpc');
  304. cfgFile.Insert(2, '-l');
  305. cfgFile.Insert(2, '-k -Map d:\map.txt');
  306. cfgFile.Insert(2, '-CX');
  307. Result:= vFPC_BinaryPath+'\fpc.exe '+extraOptions
  308. +' -Fe'+FPCErrorFile+' 2> '+FPCLinkerErrorFile;
  309. paths:=TStringList.Create;
  310. try
  311. StringToPaths(vFPC_LibraryPaths, paths);
  312. for i:=0 to paths.Count-1 do begin
  313. pathName:=MacroExpandPath(paths[i]);
  314. // cfgFile.Add('-Fu'+pathName);
  315. cfgFile.Add('-Fo'+pathName);
  316. cfgFile.Add('-Fl'+pathName);
  317. end;
  318. StringToPaths(vFPC_SourcePaths, paths);
  319. for i:=0 to paths.Count-1 do begin
  320. pathName:=MacroExpandPath(paths[i]);
  321. cfgFile.Add('-Fu'+pathName);
  322. cfgFile.Add('-Fi'+pathName);
  323. end;
  324. finally
  325. paths.Free;
  326. end;
  327. Result:=Result+' "'+prj.FileName+'"';
  328. cfgFile.SaveToFile(vFPC_BinaryPath+'\fpc.cfg');
  329. finally
  330. cfgFile.Free;
  331. end;
  332. end;
  333. function TDMDXPExpertModule.FPCErrorFile : String;
  334. begin
  335. Result:='c:\dxp.tmp';
  336. end;
  337. function TDMDXPExpertModule.FPCLinkerErrorFile : String;
  338. begin
  339. Result:='c:\dxp-link.tmp';
  340. end;
  341. function TDMDXPExpertModule.FPCCompile(const compileType : String;
  342. const extraOptions : String = '') : Boolean;
  343. var
  344. res : Integer;
  345. cmdLine, verbose, verboseLink : String;
  346. prj : IOTAProject;
  347. progress : TDXPProgress;
  348. begin
  349. Result:=False;
  350. prj:=GetProject;
  351. if prj=nil then Exit;
  352. LoadDXPGlobals;
  353. BackupFPCConfigFile;
  354. progress:=TDXPProgress.Create(nil);
  355. try
  356. progress.SetProject(ProjectBinaryName);
  357. progress.SetStatus('Compiling');
  358. progress.SetStat(0, 0, 0, 0);
  359. progress.Show;
  360. Application.ProcessMessages;
  361. cmdLine:=FPCCommandLine(extraOptions);
  362. if cmdLine='' then Exit;
  363. try
  364. verbose:=FPCErrorFile;
  365. verboseLink:=FPCLinkerErrorFile;
  366. DeleteFile(verbose);
  367. Screen.Cursor:=crHourGlass;
  368. try
  369. res:=ExecuteAndWait(cmdLine, SW_SHOWMINNOACTIVE, vFPC_TimeOut, True);
  370. finally
  371. Screen.Cursor:=crDefault;
  372. end;
  373. if res=-1 then
  374. progress.SetStatus('Failed to start compiler')
  375. else begin
  376. if res=0 then
  377. Result:=True;
  378. DXPCompileLog.ExecuteOnFPC(prj.FileName, verbose, verboseLink, Self,
  379. progress);
  380. with DXPCompileLog.MERaw.Lines do begin
  381. Insert(0, cmdLine);
  382. Insert(1, '');
  383. end;
  384. end;
  385. if Result then
  386. progress.SetStatus(compileType+' successful')
  387. else progress.SetStatus(compileType+' failed');
  388. progress.Timer.Enabled:=False;
  389. progress.BUOk.Enabled:=True;
  390. while progress.Visible do begin
  391. Sleep(100);
  392. Application.ProcessMessages;
  393. end;
  394. finally
  395. DeleteFile(verbose);
  396. DeleteFile(verboseLink);
  397. end;
  398. finally
  399. progress.Release;
  400. RestoreFPCConfigFile;
  401. end;
  402. end;
  403. procedure TDMDXPExpertModule.ACFPCExecuteExecute(Sender: TObject);
  404. begin
  405. if FPCCompile('Compile & Execute') then
  406. WinExec(PAnsiChar(AnsiString(ProjectBinaryName)), SW_SHOW);
  407. end;
  408. procedure TDMDXPExpertModule.ACFPCCompileExecute(Sender: TObject);
  409. begin
  410. (BorlandIDEServices as IOTAModuleServices).SaveAll;
  411. FPCCompile('Compilation');
  412. end;
  413. procedure TDMDXPExpertModule.ACFPCBuildExecute(Sender: TObject);
  414. begin
  415. (BorlandIDEServices as IOTAModuleServices).SaveAll;
  416. FPCCompile('Build', '-B');
  417. end;
  418. procedure TDMDXPExpertModule.ACDXPOptionsExecute(Sender: TObject);
  419. begin
  420. LoadDXPGlobals;
  421. with TDXPOptions.Create(nil) do begin
  422. try
  423. if Execute then
  424. StoreDXPGlobals;
  425. finally
  426. Free;
  427. end;
  428. end;
  429. end;
  430. procedure TDMDXPExpertModule.ActionListUpdate(Action: TBasicAction;
  431. var Handled: Boolean);
  432. var
  433. gotProject : Boolean;
  434. begin
  435. gotProject:=(GetProject<>nil);
  436. ACFPCCompile.Enabled:=gotProject;
  437. ACFPCCompile.ShortCut:=ShortCut(VK_F9, [ssCtrl, ssShift]);
  438. ACFPCBuild.Enabled:=gotProject;
  439. ACFPCExecute.Enabled:=gotProject;
  440. ACFPCExecute.ShortCut:=ShortCut(VK_F9, [ssShift]);
  441. ACFPCOptions.Enabled:=gotProject;
  442. ACViewCompilerMessages.Checked:=DXPCompileLogVisible;
  443. Handled:=True;
  444. end;
  445. procedure TDMDXPExpertModule.ACViewCompilerMessagesExecute(
  446. Sender: TObject);
  447. begin
  448. if DXPCompileLog.Visible then
  449. DXPCompileLog.Hide
  450. else DXPCompileLog.Show;
  451. end;
  452. procedure TDMDXPExpertModule.ACFPCOptionsExecute(Sender: TObject);
  453. var
  454. config : TDXPFPCConfig;
  455. begin
  456. with TDXPFPCOptions.Create(nil) do begin
  457. config:=FPCConfig;
  458. if Execute(config.Options) then
  459. config.SaveToFile(FFPCConfigFileName);
  460. Free;
  461. end;
  462. end;
  463. end.