Componentes.Terceros.RemObj.../internal/5.0.23.613/1/RemObjects SDK for Delphi/Source/IDE/uRORODLNotifier.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10
- Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
2007-09-10 14:06:19 +00:00

558 lines
18 KiB
ObjectPascal

unit uRORODLNotifier;
{----------------------------------------------------------------------------}
{ RemObjects SDK Library - Delphi IDE Integration
{
{ compiler: Delphi 5 and up
{ platform: Win32
{
{ (c)opyright RemObjects Software. all rights reserved.
{
{ Using this code requires a valid license of the RemObjects SDK
{ which can be obtained at http://www.remobjects.com.
{----------------------------------------------------------------------------}
{$I RemObjects.inc}
interface
uses Classes, ToolsApi, uROIDETools;
type
TROUnitType = (utIntf, utInvk, utImpl, utAsync, utRes);
TROUnitTypes = set of TROUnitType;
{ TRORODLNotifier }
TRORODLNotifier = class(TNotifierObject, IOTAIDENotifier, IOTAIDENotifier50)
private
fMessages : TIDEMessageList;
protected
procedure FileNotification(NotifyCode: TOTAFileNotification;
const FileName: string; var Cancel: Boolean);
procedure AfterCompile(Succeeded: Boolean); overload;
procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean); overload;
procedure AfterCompile(Succeeded: Boolean; IsCodeInsight: Boolean); overload;
public
procedure BeforeCompile(const Project: IOTAProject; IsCodeInsight: Boolean; var Cancel: Boolean); overload;
procedure GenerateUnits(const aProject: IOTAProject; aTypes: TROUnitTypes);
constructor Create;
destructor Destroy; override;
end;
function ProcessProject(const Project: IOTAProject; aMessageList : TIDEMessageList; aTypes: TROUnitTypes = [utIntf, utInvk, utImpl, utRes]) : boolean;
procedure Register;
implementation
uses
Controls, SysUtils, Dialogs,
uRODLGenTools, uRORes, uRODL, uROServer, uROClasses, uRODLToXML,
uRODLConvertersUtils,
{.$IFNDEF REMOBJECTS_CODEGEN2}
uRODLToPascalInvk, uRODLToPascalIntf, uRODLToPascalImpl, uRODLToPascalAsync,
{.$ENDIF}
{$IFDEF MSWINDOWS}fCustomIDEMessagesForm, fROServerClassForm{$ENDIF}
{$IFDEF LINUX}fCustomIDEMessagesFormKylix{$ENDIF}, uEWMenuManager, uEWOTAHelpers;
var notifieridx : integer = -1;
procedure Register;
begin
notifieridx := Services.AddNotifier(TRORODLNotifier.Create);
end;
procedure RemoveNotifier;
begin
if (notifieridx<>-1)
then Services.RemoveNotifier(notifieridx);
end;
{ RODL file processing }
function ProcessProject(const Project: IOTAProject; aMessageList : TIDEMessageList; aTypes: TROUnitTypes = [utIntf, utInvk, utImpl, utRes]) : boolean;
{$IFNDEF REMOBJECTS_CODEGEN2}
function GenUnit(aConverterClass : TRODLConverterClass; aLibrary : TRODLLibrary; aShortRodlFilename: string; aService : TRODLService = nil; SkipIfPresent : boolean = FALSE) : boolean; overload;
var
conv : TRODLConverter;
lAttributes: Integer;
lServiceName: string;
unitname : string;
module : IOTAModule;
clsnme, requnits : string;
passaveaborted : boolean;
begin
result := FALSE;
conv := NIL;
try
conv := aConverterClass.Create(NIL);
if Assigned(aService) then lServiceName := aService.Info.Name else lServiceName := '';
unitname := ExtractFilePath(Project.FileName)+conv.GetTargetFileName(aLibrary, lServiceName);
// Checks the module is already in the project
try
module := FindModuleByUnitName(Project, unitname);
except
on E:EFOpenError do module := nil;
else raise;
end;
// If it is and the file is not supposed to be regenerated just exists
if (module<>NIL) and SkipIfPresent then begin
aMessageList.Add(mWarning, aShortRodlFilename+': Skipping regeneration of unit '+ExtractFileName(unitname));
result := TRUE;
Exit;
end
{$IFDEF MSWINDOWS}
else if (conv is TRODLToImpl) and (aService.Ancestor='') then begin
if not SelectROServerClassType(lServiceName, clsnme, requnits) then Abort;
TRODLToImpl(conv).ServerClassName := clsnme;
TRODLToImpl(conv).RequiredUnits := requnits;
end{$ENDIF};
{$IFDEF MSWINDOWS}
if FileExists(unitname) then begin
lAttributes := FileGetAttr(unitname);
if (lAttributes and faReadOnly) = faReadOnly then begin
//case MessageDlg(Format('%s is readonly, overwrite anyway?',[ExtractFileName(unitname)]),
case MessageDlg(Format('%s is readonly and cannot be regenerated.',[ExtractFileName(unitname)]),
mtConfirmation, [{mbYes, mbYesToAll} mbCancel, mbIgnore], 0) of
mrCancel: Abort();
mrIgnore: begin
result := true;
exit;
end;
mrYes: begin
FileSetAttr(unitname, lAttributes xor faReadOnly);
//ToDo: need to turn buffer non-readonly, too.
exit;
end;
mrYesToAll: //ToDo.
end;
end;
end;
{$ENDIF}
// Converts the RODL file
conv.Convert(aLibrary, lServiceName);
if (module=NIL) then begin
// If not present adds it double checking for file existance if SkipIfPresent. It's for implementation
// units that might be there and have code already in but not be part of the DPR (for any weird reason)
passaveaborted := FALSE;
if SkipIfPresent and FileExists(unitname) then begin
case MessageDlg(
Format('Unit "%s" has been prepared but a file with the same name already exist in "%s".'#13+
'Do you want to overwrite file %s?',
[ExtractFileName(unitname), ExtractFilePath(unitname), ExtractFileName(unitname)]),
mtWarning, [mbYes, mbNo, mbCancel], 0) of
mrCancel : Exit;
mrNo : passaveaborted := TRUE;
mrYes: { no-op};
end
end;
if not passaveaborted then begin
if conv is TRODLToImpl then with conv as TRODLToImpl do begin
if WriteDataModule then
WriteDFM(aLibrary, lServiceName, ChangeFileExt(unitname, '.dfm'));
end;
conv.Buffer.SaveToFile(unitname);
end;
{$IFDEF BDS}
Project.AddFile(unitname, false);
{$ELSE}
Project.AddFile(unitname, (aConverterClass=TRODLToImpl) and TRODLToImpl(conv).WriteDataModule);
{$ENDIF}
if (aConverterClass <> TRODLToInvk)
then ActionServices.OpenFile(unitname);
end
else begin
// Otherwise updates the source
WriteModuleSource(module, Trim(conv.Buffer.Text), '');
end;
if SkipIfPresent then
aMessageList.Add(mInfo, Format(aShortRodlFilename+': Implementation unit for service %s generated',
[lServiceName]));
result := TRUE;
finally
conv.Free;
end;
end;
{$ENDIF}
function GenUnit(aType: TROCodeGenType; aLibrary : TRODLLibrary; aShortRodlFilename: string; aService : TRODLService = nil; SkipIfPresent : boolean = FALSE) : boolean; overload;
var
lAttributes: Integer;
lServiceName: string;
lLanguage: TROCodeGenLanguage;
lUnitname: string;
lModule : IOTAModule;
lClassname, lRequiredUnits: string;
lCodeStream, lHeaderStream: TStringStream;
begin
result := FALSE;
lLanguage := CodeGenLanuageFromProjectPersonality(Project);
if Assigned(aService) then lServiceName := aService.Info.Name else lServiceName := '';
lUnitname := ExtractFilePath(Project.FileName)+GetTargetFileName(aLibrary, aService, aType, lLanguage);
// Checks the module is already in the project
try
lModule := FindModuleByUnitName(Project, lUnitname);
except
on E:EFOpenError do lModule := nil;
else raise;
end;
// If it is and the file is not supposed to be regenerated just exists
if SkipIfPresent and assigned(lModule) then begin
aMessageList.Add(mWarning, aShortRodlFilename+': Skipping regeneration of unit '+ExtractFileName(lUnitname));
result := TRUE;
Exit;
end;
if SkipIfPresent and FileExists(lUnitname) then begin
case MessageDlg(Format('A unit named "%s" already exist, but is not part of the project.'#13+
'Do you want to overwrite the file?', [ExtractFileName(lUnitname)]),
mtWarning, [mbYes, mbNo, mbCancel], 0) of
mrCancel: Abort;
mrNo: begin
result := true;
Exit;
end;
mrYes: { no-op};
end
end;
lRequiredUnits := '';
lClassname := '';
if (aType = cgtImpl) and (aService.Ancestor='') then begin
{$IFDEF MSWINDOWS}
if not SelectROServerClassType(lServiceName, lClassname, lRequiredUnits) then Abort;
{$ELSE}
lClassname := 'TRORemoteDataModule';
{$ENDIF};
end;
{$IFDEF MSWINDOWS}
if FileExists(lUnitname) then begin
lAttributes := FileGetAttr(lUnitname);
if (lAttributes and faReadOnly) = faReadOnly then begin
//case MessageDlg(Format('%s is readonly, overwrite anyway?',[ExtractFileName(unitname)]),
case MessageDlg(Format('%s is readonly and cannot be regenerated.',[ExtractFileName(lUnitname)]),
mtConfirmation, [{mbYes, mbYesToAll} mbCancel, mbIgnore], 0) of
mrCancel: Abort();
mrIgnore: begin
result := true;
exit;
end;
mrYes: begin
FileSetAttr(lUnitname, lAttributes xor faReadOnly);
//ToDo: need to turn buffer non-readonly, too.
exit;
end;
mrYesToAll: //ToDo.
end;
end;
end;
{$ENDIF}
// Converts the RODL file
if (not assigned(lModule)) or (lLanguage = cglCppWin32) then begin // going via the Module doesn't work for .H files :(
GenerateUnitToFile(aLibrary, aService, aType, lLanguage, lClassname);
{$IFDEF BDS}
Project.AddFile(lUnitname, true); // false
if lLanguage = cglCppWin32 then
Project.AddFileWithParent(ChangeFileExt(lUnitname,'.h'), true, lUnitname);
{$ELSE}
Project.AddFile(lUnitname, true);
{$ENDIF}
if (aType <> cgtInvk) then
ActionServices.OpenFile(lUnitName);
end
else begin
lCodeStream := TStringStream.Create('');
lHeaderStream := TStringStream.Create(''); // C++ only
GenerateUnitToStream(aLibrary, aService, aType, lLanguage, lCodeStream, lHeaderStream, lClassname);
WriteModuleSource(lModule, Trim(lCodeStream.DataString), Trim(lHeaderStream.DataString));
end;
{if SkipIfPresent then
aMessageList.Add(mInfo, Format(aShortRodlFilename+': Implementation unit for service %s generated',
[lServiceName]));}
result := TRUE;
end;
procedure ProcessRodl(aFilename: string; aNested: boolean);
var
lShortRodlFilename: string;
lib : TRODLLibrary;
i : integer;
begin
if (aFileName = '') then exit;
if not FileExists(aFilename) then begin
aMessageList.Add(mError,Format('RODL file %s does not exist.',[aFilename]));
exit;
end;
lShortRodlFilename := ExtractFileName(aFilename);
// Processes RODL
lib := ReadRODLFromFile(TXMLToRODL, aFilename);
try
//aMessageList.Add(mInfo, rodlname+' has been loaded');
{$IFNDEF REMOBJECTS_CODEGEN2}
if CodeGenLanuageFromProjectPersonality(Project) = cglCppWin32 then begin
{$ENDIF}
if utIntf in aTypes then begin
if not GenUnit(cgtIntf, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Interface unit generated');
end;
if utAsync in aTypes then begin
if not GenUnit(cgtAsync, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Async Interface unit generated');
end;
if utInvk in aTypes then begin
if not GenUnit(cgtInvk, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Invoker unit generated');
end;
if utImpl in aTypes then begin
for i := 0 to (lib.ServiceCount-1) do if (not lib.Services[i].IsFromUsedRodl) then begin
if not GenUnit(cgtImpl, lib, lShortRodlFilename, lib.Services[i], true) then begin
result := FALSE;
Exit;
end
end;
end;
{$IFNDEF REMOBJECTS_CODEGEN2}
end
else begin
// Generates the units
if utIntf in aTypes then begin
if not GenUnit(TRODLToIntf, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Interface unit generated');
end;
if utAsync in aTypes then begin
if not GenUnit(TRODLToPascalAsync, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Async Interface unit generated');
end;
if utInvk in aTypes then begin
if not GenUnit(TRODLToInvk, lib, lShortRodlFilename) then begin
result := FALSE;
Exit;
end
else aMessageList.Add(mInfo, lShortRodlFilename+': Invoker unit generated');
end;
if utImpl in aTypes then begin
for i := 0 to (lib.ServiceCount-1) do if (not lib.Services[i].IsFromUsedRodl) then begin
if not GenUnit(TRODLToImpl, lib, lShortRodlFilename, lib.Services[i], true) then begin
result := FALSE;
Exit;
end
end;
end;
end;
{$ENDIF not REMOBJECTS_CODEGEN2}
for i := 0 to lib.UseCount-1 do begin
if (lib.Use[i].GenerateCode) then begin
if FileExists(ExpandVariables(lib.Use[i].RodlFile)) then
ProcessRodl(lib.Use[i].RodlFile, true)
else
ProcessRodl(lib.Use[i].AbsoluteRodlFile, true);
end;
end;
if (utRes in aTypes) and (not aNested) then begin
// flatten RODL if needed
if lib.UseCount > 0 then begin
aFilename := ExtractFilePath(aFilename)+'temp_'+NewStrippedGuidAsString()+'.rodl';
with TRODLToXML.Create(lib,true) do try
Buffer.SaveToFile(aFilename);
aMessageList.Add(mInfo,Format(lShortRodlFilename+': Flattening RODL to %s',[ExtractFileName(aFilename)]));
finally
Free;
end;
end;
// generate RES
if GenerateRESFromRODL(aFilename, aMessageList) then begin
aMessageList.Add(mInfo, lShortRodlFilename+': RODL resource generated.')
end
else begin
aMessageList.Add(mError, lShortRodlFilename+': RODL resource could not be generated.');
result := FALSE
end;
// delete temp file
if lib.UseCount > 0 then begin
DeleteFile(aFilename);
end;
end;
finally
FreeAndNil(lib);
end;
end;
var prjname,
source,
rodlname : string;
begin
result := TRUE;
// Only processes DPRs
prjname := Project.FileName;
{$IFDEF BDS}
if (CompareText(ExtractFileExt(prjname), '.bdsproj')<>0) and (CompareText(ExtractFileExt(prjname), '.dproj')<>0) then Exit;
{$ELSE}
if (CompareText(ExtractFileExt(prjname), '.dpr')<>0) then Exit;
{$ENDIF}
// Extract useful data and exists if the file does not reference a RODL file
source := ReadModuleSource(Project);
rodlname := ExtractRODLFileName(source);
if (rodlname='') then exit
else if (ExtractFilePath(rodlname)='') then
rodlname := ExtractFilePath(prjname)+rodlname; // If there's no path specified assumes the file is in the DPR folder
ProcessRodl(rodlname, false);
end;
{ TRORODLNotifier }
procedure TRORODLNotifier.AfterCompile(Succeeded, IsCodeInsight: Boolean);
begin
end;
procedure TRORODLNotifier.AfterCompile(Succeeded: Boolean);
begin
end;
procedure TRORODLNotifier.BeforeCompile(const Project: IOTAProject;
var Cancel: Boolean);
begin
end;
procedure TRORODLNotifier.BeforeCompile(const Project: IOTAProject;
IsCodeInsight: Boolean; var Cancel: Boolean);
begin
if IsCodeInsight then Exit;
fMessages.ClearMessages();
try
Cancel := not ProcessProject(Project, fMessages);
except
on E:Exception do begin
{ mh: for some reason, this message doesn't get displayed. So let's add a message box too, for now. }
fMessages.Add(mInfo, E.Message);
Cancel := TRUE;
raise;
end;
end;
if Cancel then begin
DisplayIDEMessageForm := TRUE;
end;
if (fMessages.Count>0)
then fMessages.FlushMessages;
end;
procedure TRORODLNotifier.GenerateUnits(const aProject: IOTAProject; aTypes: TROUnitTypes);
begin
ProcessProject(aProject, fMessages, aTypes);
end;
constructor TRORODLNotifier.Create;
begin
fMessages := TIDEMessageList.Create(str_ProductName);
end;
destructor TRORODLNotifier.Destroy;
begin
fMessages.Free;
inherited;
end;
procedure TRORODLNotifier.FileNotification(
NotifyCode: TOTAFileNotification; const FileName: string;
var Cancel: Boolean);
begin
end;
initialization
finalization
RemoveNotifier;
end.