iphonelazext: started the extension
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1115 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
34030812f8
commit
48d0e7d2f2
130
components/iphonelazext/environment_iphone_options.lfm
Normal file
130
components/iphonelazext/environment_iphone_options.lfm
Normal file
@ -0,0 +1,130 @@
|
||||
inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
|
||||
Height = 439
|
||||
Width = 485
|
||||
ClientHeight = 439
|
||||
ClientWidth = 485
|
||||
DesignLeft = 631
|
||||
DesignTop = 144
|
||||
object lblRTLUtils: TLabel[0]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 128
|
||||
Width = 92
|
||||
Caption = 'RTL units path'
|
||||
ParentColor = False
|
||||
end
|
||||
object lblCompilerPath: TLabel[1]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 96
|
||||
Width = 55
|
||||
Caption = 'Compiler'
|
||||
ParentColor = False
|
||||
end
|
||||
object edtCompilerPath: TEdit[2]
|
||||
Left = 125
|
||||
Height = 22
|
||||
Top = 96
|
||||
Width = 347
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 0
|
||||
Text = 'edtCompilerPath'
|
||||
end
|
||||
object lblXCodeProject: TLabel[3]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 72
|
||||
Width = 395
|
||||
Caption = 'Specific ARM compiler settings (for generated XCode projects)'
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object edtRTLPath: TEdit[4]
|
||||
Left = 125
|
||||
Height = 22
|
||||
Top = 128
|
||||
Width = 347
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 1
|
||||
Text = 'edtRTLPath'
|
||||
end
|
||||
object edtCompilerOptions: TEdit[5]
|
||||
Left = 125
|
||||
Height = 22
|
||||
Top = 160
|
||||
Width = 347
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 2
|
||||
Text = 'edtCompilerOptions'
|
||||
end
|
||||
object lblCmpOptions: TLabel[6]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 160
|
||||
Width = 106
|
||||
Caption = 'Compiler options'
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
OnClick = lblCmpOptionsClick
|
||||
end
|
||||
object Label5: TLabel[7]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 16
|
||||
Width = 97
|
||||
Caption = 'Platforms path:'
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object edtPlatformsPath: TEdit[8]
|
||||
Left = 125
|
||||
Height = 22
|
||||
Top = 16
|
||||
Width = 347
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 3
|
||||
Text = 'edtPlatformsPath'
|
||||
end
|
||||
object lblSimSettings: TLabel[9]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 232
|
||||
Width = 161
|
||||
Caption = 'iPhone Simulator settings'
|
||||
ParentColor = False
|
||||
end
|
||||
object edtSimBundle: TEdit[10]
|
||||
Left = 160
|
||||
Height = 22
|
||||
Top = 262
|
||||
Width = 312
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 4
|
||||
Text = 'edtSimBundle'
|
||||
end
|
||||
object edtSimApps: TEdit[11]
|
||||
Left = 160
|
||||
Height = 22
|
||||
Top = 294
|
||||
Width = 312
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 5
|
||||
Text = 'edtSimApps'
|
||||
end
|
||||
object lblSimBundle: TLabel[12]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 263
|
||||
Width = 111
|
||||
Caption = 'iPhoneSim bundle'
|
||||
ParentColor = False
|
||||
end
|
||||
object lblSimAppPath: TLabel[13]
|
||||
Left = 11
|
||||
Height = 18
|
||||
Top = 294
|
||||
Width = 141
|
||||
Caption = 'Sim Applications path:'
|
||||
ParentColor = False
|
||||
end
|
||||
end
|
39
components/iphonelazext/environment_iphone_options.lrs
Normal file
39
components/iphonelazext/environment_iphone_options.lrs
Normal file
@ -0,0 +1,39 @@
|
||||
{ This is an automatically generated lazarus resource file }
|
||||
|
||||
LazarusResources.Add('TiPhoneSpecificOptions','FORMDATA',[
|
||||
'TPF0'#241#22'TiPhoneSpecificOptions'#21'iPhoneSpecificOptions'#6'Height'#3
|
||||
+#183#1#5'Width'#3#229#1#12'ClientHeight'#3#183#1#11'ClientWidth'#3#229#1#10
|
||||
+'DesignLeft'#3'w'#2#9'DesignTop'#3#144#0#0#242#2#0#6'TLabel'#11'lblRTLUtils'
|
||||
+#4'Left'#2#11#6'Height'#2#18#3'Top'#3#128#0#5'Width'#2'\'#7'Caption'#6#14'RT'
|
||||
+'L units path'#11'ParentColor'#8#0#0#242#2#1#6'TLabel'#15'lblCompilerPath'#4
|
||||
+'Left'#2#11#6'Height'#2#18#3'Top'#2'`'#5'Width'#2'7'#7'Caption'#6#8'Compiler'
|
||||
+#11'ParentColor'#8#0#0#242#2#2#5'TEdit'#15'edtCompilerPath'#4'Left'#2'}'#6'H'
|
||||
+'eight'#2#22#3'Top'#2'`'#5'Width'#3'['#1#7'Anchors'#11#5'akTop'#6'akLeft'#7
|
||||
+'akRight'#0#8'TabOrder'#2#0#4'Text'#6#15'edtCompilerPath'#0#0#242#2#3#6'TLab'
|
||||
+'el'#15'lblXCodeProject'#4'Left'#2#11#6'Height'#2#18#3'Top'#2'H'#5'Width'#3
|
||||
+#139#1#7'Caption'#6'=Specific ARM compiler settings (for generated XCode pro'
|
||||
+'jects)'#11'ParentColor'#8#10'ParentFont'#8#0#0#242#2#4#5'TEdit'#10'edtRTLPa'
|
||||
+'th'#4'Left'#2'}'#6'Height'#2#22#3'Top'#3#128#0#5'Width'#3'['#1#7'Anchors'#11
|
||||
+#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#1#4'Text'#6#10'edtRTLPath'#0#0
|
||||
+#242#2#5#5'TEdit'#18'edtCompilerOptions'#4'Left'#2'}'#6'Height'#2#22#3'Top'#3
|
||||
+#160#0#5'Width'#3'['#1#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOr'
|
||||
+'der'#2#2#4'Text'#6#18'edtCompilerOptions'#0#0#242#2#6#6'TLabel'#13'lblCmpOp'
|
||||
+'tions'#4'Left'#2#11#6'Height'#2#18#3'Top'#3#160#0#5'Width'#2'j'#7'Caption'#6
|
||||
+#16'Compiler options'#11'ParentColor'#8#10'ParentFont'#8#7'OnClick'#7#18'lbl'
|
||||
+'CmpOptionsClick'#0#0#242#2#7#6'TLabel'#6'Label5'#4'Left'#2#11#6'Height'#2#18
|
||||
+#3'Top'#2#16#5'Width'#2'a'#7'Caption'#6#15'Platforms path:'#11'ParentColor'#8
|
||||
+#10'ParentFont'#8#0#0#242#2#8#5'TEdit'#16'edtPlatformsPath'#4'Left'#2'}'#6'H'
|
||||
+'eight'#2#22#3'Top'#2#16#5'Width'#3'['#1#7'Anchors'#11#5'akTop'#6'akLeft'#7
|
||||
+'akRight'#0#8'TabOrder'#2#3#4'Text'#6#16'edtPlatformsPath'#0#0#242#2#9#6'TLa'
|
||||
+'bel'#14'lblSimSettings'#4'Left'#2#11#6'Height'#2#18#3'Top'#3#232#0#5'Width'
|
||||
+#3#161#0#7'Caption'#6#25'iPhone Simulator settings'#11'ParentColor'#8#0#0#242
|
||||
+#2#10#5'TEdit'#12'edtSimBundle'#4'Left'#3#160#0#6'Height'#2#22#3'Top'#3#6#1#5
|
||||
+'Width'#3'8'#1#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#4
|
||||
+#4'Text'#6#12'edtSimBundle'#0#0#242#2#11#5'TEdit'#10'edtSimApps'#4'Left'#3
|
||||
+#160#0#6'Height'#2#22#3'Top'#3'&'#1#5'Width'#3'8'#1#7'Anchors'#11#5'akTop'#6
|
||||
+'akLeft'#7'akRight'#0#8'TabOrder'#2#5#4'Text'#6#10'edtSimApps'#0#0#242#2#12#6
|
||||
+'TLabel'#12'lblSimBundle'#4'Left'#2#11#6'Height'#2#18#3'Top'#3#7#1#5'Width'#2
|
||||
+'o'#7'Caption'#6#16'iPhoneSim bundle'#11'ParentColor'#8#0#0#242#2#13#6'TLabe'
|
||||
+'l'#13'lblSimAppPath'#4'Left'#2#11#6'Height'#2#18#3'Top'#3'&'#1#5'Width'#3
|
||||
+#141#0#7'Caption'#6#22'Sim Applications path:'#11'ParentColor'#8#0#0#0
|
||||
]);
|
119
components/iphonelazext/environment_iphone_options.pas
Normal file
119
components/iphonelazext/environment_iphone_options.pas
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit environment_iphone_options;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls,
|
||||
IDEOptionsIntf, ProjectIntf,
|
||||
iPhoneExtOptions;
|
||||
|
||||
type
|
||||
|
||||
{ TiPhoneSpecificOptions }
|
||||
|
||||
TiPhoneSpecificOptions = class(TAbstractIDEOptionsEditor)
|
||||
edtCompilerPath: TEdit;
|
||||
edtRTLPath: TEdit;
|
||||
edtCompilerOptions: TEdit;
|
||||
edtPlatformsPath: TEdit;
|
||||
edtSimBundle: TEdit;
|
||||
edtSimApps: TEdit;
|
||||
lblRTLUtils: TLabel;
|
||||
lblSimAppPath: TLabel;
|
||||
lblCompilerPath: TLabel;
|
||||
lblXCodeProject: TLabel;
|
||||
lblCmpOptions: TLabel;
|
||||
Label5: TLabel;
|
||||
lblSimSettings: TLabel;
|
||||
lblSimBundle: TLabel;
|
||||
procedure lblCmpOptionsClick(Sender: TObject);
|
||||
private
|
||||
{ private declarations }
|
||||
public
|
||||
{ public declarations }
|
||||
function GetTitle: String; override;
|
||||
class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
|
||||
procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
|
||||
procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
|
||||
procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TiPhoneSpecificOptions }
|
||||
|
||||
procedure TiPhoneSpecificOptions.lblCmpOptionsClick(Sender: TObject);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
function TiPhoneSpecificOptions.GetTitle: String;
|
||||
begin
|
||||
Result:='Files';
|
||||
end;
|
||||
|
||||
procedure TiPhoneSpecificOptions.Setup(ADialog: TAbstractOptionsEditorDialog);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TiPhoneSpecificOptions.ReadSettings(AOptions: TAbstractIDEOptions);
|
||||
var
|
||||
opt : TiPhoneEnvironmentOptions;
|
||||
begin
|
||||
if not Assigned(AOptions) or not (AOptions is TiPhoneEnvironmentOptions) then Exit;
|
||||
opt:=TiPhoneEnvironmentOptions(AOptions);
|
||||
opt.Load;
|
||||
|
||||
edtPlatformsPath.Text := opt.PlatformsBaseDir;
|
||||
edtCompilerPath.Text := opt.CompilerPath;
|
||||
edtRTLPath.Text := opt.BaseRTLPath;
|
||||
edtCompilerOptions.Text := opt.CommonOpt;
|
||||
edtSimBundle.Text := opt.SimBundle;
|
||||
edtSimApps.Text:= opt.SimAppsPath;
|
||||
end;
|
||||
|
||||
procedure TiPhoneSpecificOptions.WriteSettings(AOptions: TAbstractIDEOptions);
|
||||
var
|
||||
opt : TiPhoneEnvironmentOptions;
|
||||
begin
|
||||
if not Assigned(AOPtions) or not (AOptions is TiPhoneEnvironmentOptions) then Exit;
|
||||
opt:=TiPhoneEnvironmentOptions(AOptions);
|
||||
|
||||
opt.PlatformsBaseDir:=edtPlatformsPath.Text;
|
||||
opt.CompilerPath:=edtCompilerPath.Text;
|
||||
opt.BaseRTLPath:=edtRTLPath.Text;
|
||||
opt.CommonOpt:=edtCompilerOptions.Text;
|
||||
opt.SimBundle:=edtSimBundle.Text;
|
||||
opt.SimAppsPath:=edtSimApps.Text;
|
||||
|
||||
opt.Save;
|
||||
end;
|
||||
|
||||
class function TiPhoneSpecificOptions.SupportedOptionsClass: TAbstractIDEOptionsClass;
|
||||
begin
|
||||
Result:=TiPhoneEnvironmentOptions;
|
||||
end;
|
||||
|
||||
initialization
|
||||
{$I environment_iphone_options.lrs}
|
||||
RegisterIDEOptionsEditor(iPhoneEnvGroup, TiPhoneSpecificOptions, iPhoneEnvGroup+1);
|
||||
|
||||
end.
|
||||
|
442
components/iphonelazext/ideext.pas
Normal file
442
components/iphonelazext/ideext.pas
Normal file
@ -0,0 +1,442 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit ideext;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Unix, BaseUnix, process,
|
||||
Classes, SysUtils,
|
||||
Graphics, Controls, Forms, Dialogs, FileUtil,
|
||||
{Lazarus Interface}
|
||||
LazIDEIntf, MenuIntf, ProjectIntf, IDEOptionsIntf, PackageIntf, IDEMsgIntf,
|
||||
|
||||
project_iphone_options, xcodetemplate,
|
||||
|
||||
iPhoneExtOptions, iPhoneExtStr, iPhoneBundle, lazfilesutils;
|
||||
|
||||
procedure Register;
|
||||
|
||||
implementation
|
||||
|
||||
type
|
||||
{ TiPhoneExtension }
|
||||
|
||||
TiPhoneExtension = class(TObject)
|
||||
protected
|
||||
procedure FillBunldeInfo(forSimulator: Boolean; var info: TiPhoneBundleInfo);
|
||||
procedure InstallAppToSim;
|
||||
function FixCustomOptions(const Options: String; isRealDevice: Boolean): String;
|
||||
function ProjectBuilding(Sender: TObject): TModalResult;
|
||||
function ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult;
|
||||
function WriteIconTo(const FullName: String): Boolean;
|
||||
public
|
||||
isiPhoneMenu :TIDEMenuCommand;
|
||||
constructor Create;
|
||||
procedure UpdateXCode(Sender: TObject);
|
||||
procedure SimRun(Sender: TObject);
|
||||
procedure isProjectClicked(Sender: TObject);
|
||||
end;
|
||||
|
||||
var
|
||||
Extension : TiPhoneExtension = nil;
|
||||
|
||||
function GetProjectPlistName(Project: TLazProject): String;
|
||||
var
|
||||
ext : String;
|
||||
begin
|
||||
if Project.LazCompilerOptions.TargetFilename<>'' then
|
||||
Result:=Project.LazCompilerOptions.TargetFilename
|
||||
else begin
|
||||
Result:=Project.MainFile.Filename;
|
||||
ext:=ExtractFileExt(Result);
|
||||
Result:=Copy(Result, 1, length(Result)-length( ext ) );
|
||||
end;
|
||||
Result:=Result+'.plist';
|
||||
end;
|
||||
|
||||
function GetProjectExeName(Project: TLazProject): String;
|
||||
var
|
||||
ext : String;
|
||||
begin
|
||||
if Project.LazCompilerOptions.TargetFilename<>'' then
|
||||
Result:=Project.LazCompilerOptions.TargetFilename
|
||||
else begin
|
||||
Result:=Project.MainFile.Filename;
|
||||
ext:=ExtractFileExt(Result);
|
||||
Result:=Copy(Result, 1, length(Result)-length( ext ) );
|
||||
end;
|
||||
Project.LongenFilename(Result);
|
||||
end;
|
||||
|
||||
{ TiPhoneExtension }
|
||||
|
||||
procedure TiPhoneExtension.FillBunldeInfo(forSimulator: Boolean; var info: TiPhoneBundleInfo);
|
||||
begin
|
||||
Info.AppID:=ProjOptions.AppID;
|
||||
Info.DisplayName:=LazarusIDE.ActiveProject.Title;
|
||||
Info.iPlatform:=EnvOptions.GetSDKName(ProjOptions.SDK, forSimulator);
|
||||
Info.SDKVersion:=ProjOptions.SDK;
|
||||
end;
|
||||
|
||||
procedure TiPhoneExtension.InstallAppToSim;
|
||||
var
|
||||
bundlename : string;
|
||||
bundlepath : WideString;
|
||||
exepath : WideString;
|
||||
nm : String;
|
||||
symlink : String;
|
||||
Space : WideString;
|
||||
RealSpace : WideString;
|
||||
Info : TiPhoneBundleInfo;
|
||||
begin
|
||||
Space:=ProjOptions.SpaceName; // LazarusIDE.ActiveProject.CustomData.;
|
||||
|
||||
{todo:}
|
||||
|
||||
bundleName:=ExtractFileName(LazarusIDE.ActiveProject.ProjectInfoFile);
|
||||
bundleName:=Copy(bundleName, 1, length(bundleName)-length(ExtractFileExt(bundleName)));
|
||||
|
||||
nm:=GetProjectExeName(LazarusIDE.ActiveProject);
|
||||
|
||||
FillBunldeInfo(true, Info);
|
||||
CreateBundle(bundleName, Space, ExtractFileName(nm), Info, RealSpace, bundlepath, exepath);
|
||||
|
||||
WriteIconTo( IncludeTrailingPathDelimiter(bundlepath)+'Icon.png');
|
||||
|
||||
if nm<>'' then begin
|
||||
symlink:=UTF8Encode(exepath);
|
||||
FpUnlink(symlink);
|
||||
fpSymlink(PChar(nm), PChar(symlink));
|
||||
end;
|
||||
end;
|
||||
|
||||
function FindParam(const Source, ParamKey: String; var idx: Integer; var Content: String): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
quoted : Boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
idx:=0;
|
||||
for i := 1 to length(Source)-1 do
|
||||
if (Source[i]='-') and ((i=1) or (Source[i-1] in [#9,#32,#10,#13])) then
|
||||
if Copy(Source, i, 3) = ParamKey then begin
|
||||
idx:=i;
|
||||
Result:=true;
|
||||
Break;
|
||||
end;
|
||||
|
||||
if not Result then Exit;
|
||||
|
||||
i:=idx+3;
|
||||
quoted:=(i<=length(Source)) and (Source[i]='"');
|
||||
|
||||
if not quoted then begin
|
||||
for i:=i to length(Source) do
|
||||
if (Source[i] in [#9,#32,#10,#13]) then begin
|
||||
Content:=Copy(Source, idx+3, i-idx);
|
||||
Exit;
|
||||
end;
|
||||
end else begin
|
||||
i:=i+1;
|
||||
for i:=i to length(Source) do
|
||||
if (Source[i] = '"') then begin
|
||||
Content:=Copy(Source, idx+3, i-idx+1);
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Content:=Copy(Source, idx+3, length(Source)-1);
|
||||
end;
|
||||
|
||||
function TiPhoneExtension.FixCustomOptions(const Options: String; isRealDevice: Boolean): String;
|
||||
var
|
||||
prm : string;
|
||||
rawprm : string;
|
||||
idx : Integer;
|
||||
needfix : Boolean;
|
||||
sdkuse : String;
|
||||
sdkname : string;
|
||||
begin
|
||||
|
||||
if isRealDevice
|
||||
then EnvOptions.GetDeviceSDK(ProjOptions.SDK, sdkname, sdkuse)
|
||||
else EnvOptions.GetSimSDK(ProjOptions.SDK, sdkname, sdkuse);
|
||||
sdkuse:=sdkuse;
|
||||
|
||||
Result:=Options;
|
||||
if FindParam(Result, '-XR', idx, rawprm) then begin
|
||||
if (rawprm='') or(rawprm[1]<>'"')
|
||||
then prm:=rawprm
|
||||
else prm:=rawprm;
|
||||
|
||||
// there might be -XR option, and it might be the same as selected SDK
|
||||
needfix:=sdkuse<>prm;
|
||||
|
||||
// there's -XR option, but it doesn't match the selection options
|
||||
if needfix then
|
||||
Delete(Result, idx, length(rawprm)+3);
|
||||
|
||||
end else begin
|
||||
//there's no -XR string in custom options
|
||||
needfix:=true;
|
||||
idx:=1;
|
||||
sdkuse:=sdkuse+' ';
|
||||
end;
|
||||
|
||||
if needfix then Insert('-XR'+sdkuse, Result, idx);
|
||||
end;
|
||||
|
||||
constructor TiPhoneExtension.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
LazarusIDE.AddHandlerOnProjectOpened(@ProjectOpened);
|
||||
LazarusIDE.AddHandlerOnProjectBuilding(@ProjectBuilding);
|
||||
|
||||
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneSeparator', '-', nil, nil);
|
||||
|
||||
isiPhoneMenu:=RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneProject', striPhoneProject, @isProjectClicked, nil);
|
||||
|
||||
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneToXCode', strStartAtXCode, @UpdateXCode, nil);
|
||||
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneRunSim', strRunSimulator, @SimRun, nil);
|
||||
end;
|
||||
|
||||
function TiPhoneExtension.ProjectBuilding(Sender: TObject): TModalResult;
|
||||
begin
|
||||
//writeln('project building: ', Sender.ClassName);
|
||||
Result:=mrOk;
|
||||
if not Assigned(LazarusIDE.ActiveProject) or not ProjOptions.isIPhoneApp then Exit;
|
||||
|
||||
LazarusIDE.ActiveProject.LazCompilerOptions.CustomOptions :=
|
||||
FixCustomOptions( LazarusIDE.ActiveProject.LazCompilerOptions.CustomOptions, false );
|
||||
|
||||
//const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
|
||||
{MessageDlg('CustomOptions fixed = '+ LazarusIDE.ActiveProject.LazCompilerOptions.CustomOptions,
|
||||
mtInformation, [mbOK], 0);}
|
||||
|
||||
InstallAppToSim;
|
||||
Result:=mrOk;
|
||||
end;
|
||||
|
||||
function TiPhoneExtension.ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult;
|
||||
begin
|
||||
ProjOptions.Reset;
|
||||
ProjOptions.Load;
|
||||
isiPhoneMenu.Checked:=ProjOptions.isIPhoneApp;
|
||||
Result:=mrOk;
|
||||
end;
|
||||
|
||||
function TiPhoneExtension.WriteIconTo(const FullName: String): Boolean;
|
||||
var
|
||||
icofile : string;
|
||||
ico : TIcon;
|
||||
png : TPortableNetworkGraphic;
|
||||
i, idx : Integer;
|
||||
const
|
||||
iPhoneIconSize=57;
|
||||
begin
|
||||
Result:=false;
|
||||
//todo: find a better way of getting the file
|
||||
icofile:=ChangeFileExt(LazarusIDE.ActiveProject.MainFile.Filename, '.ico');
|
||||
LazarusIDE.ActiveProject.LongenFilename(icofile);
|
||||
if not FileExists(icofile) then begin
|
||||
// no icon. it should be deleted!
|
||||
DeleteFile(FullName);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
try
|
||||
ico:=TIcon.Create;
|
||||
png:=TPortableNetworkGraphic.Create;
|
||||
try
|
||||
png.Width:=iPhoneIconSize;
|
||||
png.Height:=iPhoneIconSize;
|
||||
ico.LoadFromFile(icofile);
|
||||
idx:=-1;
|
||||
for i:=0 to ico.Count- 1 do begin
|
||||
ico.Current:=i;
|
||||
if (ico.Width=iPhoneIconSize) and (ico.Height=iPhoneIconSize) then begin
|
||||
idx:=i;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if (idx<0) and (ico.Count>0) then idx:=0;
|
||||
|
||||
ico.Current:=idx;
|
||||
|
||||
if (ico.Width=iPhoneIconSize) and (ico.Height=iPhoneIconSize) then
|
||||
png.Assign(ico)
|
||||
else begin
|
||||
//resize to adjust the image
|
||||
png.Canvas.CopyRect( Rect(0,0, iPhoneIconSize, iPhoneIconSize), ico.Canvas, Rect(0,0, ico.Width, ico.Height));
|
||||
end;
|
||||
|
||||
png.SaveToFile(FullName);
|
||||
finally
|
||||
ico.free;
|
||||
png.free;
|
||||
end;
|
||||
Result:=true;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TiPhoneExtension.UpdateXCode(Sender: TObject);
|
||||
var
|
||||
templates : TStringList;
|
||||
build : TStringList;
|
||||
dir : string;
|
||||
projdir : string;
|
||||
proj : TStringList;
|
||||
projname : string;
|
||||
|
||||
ext : string;
|
||||
tname : string;
|
||||
plistname : string;
|
||||
|
||||
Info : TiPhoneBundleInfo;
|
||||
name : string;
|
||||
|
||||
opt : string;
|
||||
begin
|
||||
FillBunldeInfo(false, Info);
|
||||
// the create .plist would be used by XCode project
|
||||
// the simulator .plist in created with InstallAppToSim.
|
||||
// they differ with SDKs used
|
||||
|
||||
build := TStringList.Create;
|
||||
|
||||
tname:=ExtractFileName( ChangeFileExt(LazarusIDE.ActiveProject.MainFile.Filename, ''));
|
||||
plistname:=tname+'.plist';
|
||||
|
||||
build.Values['INFOPLIST_FILE'] := '"'+plistname+'"';
|
||||
build.Values['PRODUCT_NAME'] := '"'+tname+'"';
|
||||
build.Values['SDKROOT'] := EnvOptions.GetSDKName(ProjOptions.SDK, false);
|
||||
build.Values['FPC_COMPILER_PATH'] := '"'+EnvOptions.CompilerPath+'"';
|
||||
build.Values['FPC_MAIN_FILE'] := '"'+LazarusIDE.ActiveProject.MainFile.Filename+'"';
|
||||
opt :=
|
||||
' -XR'+EnvOptions.GetSDKFullPath(ProjOptions.SDK, false)+' ' +
|
||||
' -FD'+IncludeTrailingPathDelimiter(EnvOptions.PlatformsBaseDir)+'iPhoneOS.platform/Developer/usr/bin ' +
|
||||
EnvOptions.CommonOpt;
|
||||
|
||||
with LazarusIDE.ActiveProject.LazCompilerOptions do begin
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(OtherUnitFiles, '-Fu', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(IncludePath, '-Fi', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(ObjectPath, '-Fo', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(Libraries, '-Fl', '\"');
|
||||
end;
|
||||
|
||||
build.Values['FPC_CUSTOM_OPTIONS'] :='"'+opt+'"';
|
||||
|
||||
dir:='xcode';
|
||||
LazarusIDE.ActiveProject.LongenFilename(dir);
|
||||
dir:=dir+'/';
|
||||
|
||||
name:=ExtractFileName(GetProjectExeName(LazarusIDE.ActiveProject));
|
||||
ForceDirectories(dir);
|
||||
WriteDefInfoList( dir + GetProjectPlistName(LazarusIDE.ActiveProject),
|
||||
name, name, Info);
|
||||
|
||||
|
||||
projname:=ExtractFileName(LazarusIDE.ActiveProject.MainFile.Filename);
|
||||
ext:=ExtractFileExt(projname);
|
||||
projname:=Copy(projname, 1, length(projname)-length(ext));
|
||||
|
||||
projdir:=dir+projname+'.xcodeproj';
|
||||
ForceDirectories(projdir);
|
||||
|
||||
projname:=IncludeTrailingPathDelimiter(projdir)+'project.pbxproj';
|
||||
proj:=TStringList.Create;
|
||||
templates:=nil;
|
||||
try
|
||||
if not FileExists(projname) then begin
|
||||
templates:=TStringList.Create;
|
||||
|
||||
if WriteIconTo( IncludeTrailingPathDelimiter(dir)+'Icon.png') then begin
|
||||
templates.Values['icon']:=XCodeProjectTemplateIcon;
|
||||
templates.Values['iconid']:=XCodeProjectTemplateIconID;
|
||||
templates.Values['iconfile']:=XCodeIconFile;
|
||||
templates.Values['iconfileref']:=XCodeIconFileRef;
|
||||
end else begin
|
||||
templates.Values['icon']:='';
|
||||
templates.Values['iconid']:='';
|
||||
templates.Values['iconfile']:='';
|
||||
templates.Values['iconfileref']:='';
|
||||
end;
|
||||
|
||||
//todo:
|
||||
templates.Values['bundle']:=tname+'.app';
|
||||
templates.Values['plist']:=plistname;
|
||||
templates.Values['targetname']:=tname;
|
||||
templates.Values['productname']:=tname;
|
||||
|
||||
proj.Text:=XCodeProjectTemplate;
|
||||
end else
|
||||
proj.LoadFromFile(projname);
|
||||
|
||||
PrepareTemplateFile(proj, templates, build);
|
||||
proj.SaveToFile(projname);
|
||||
except
|
||||
on e: exception do
|
||||
ShowMessage(e.Message);
|
||||
end;
|
||||
|
||||
proj.Free;
|
||||
templates.Free;
|
||||
build.Free;
|
||||
|
||||
IDEMessagesWindow.AddMsg(strXcodeUpdated, '', 0);
|
||||
end;
|
||||
|
||||
procedure TiPhoneExtension.SimRun(Sender: TObject);
|
||||
var
|
||||
t : TProcess;
|
||||
path : String;
|
||||
begin
|
||||
t :=TProcess.Create(nil);
|
||||
try
|
||||
path:=IncludeTrailingPathDelimiter(EnvOptions.SimBundle)+'Contents/MacOS/iPhone Simulator';
|
||||
t.CommandLine:='"'+path+'"';
|
||||
t.Execute;
|
||||
except
|
||||
on E: Exception do
|
||||
MessageDlg(E.Message, mtInformation, [mbOK], 0);
|
||||
end;
|
||||
t.Free;
|
||||
end;
|
||||
|
||||
procedure TiPhoneExtension.isProjectClicked(Sender: TObject);
|
||||
begin
|
||||
if not Assigned(Sender) or not Assigned(LazarusIDE.ActiveProject) then Exit;
|
||||
TIDEMenuCommand(Sender).Checked:=not TIDEMenuCommand(Sender).Checked;
|
||||
ProjOptions.isIPhoneApp:=TIDEMenuCommand(Sender).Checked;
|
||||
//SwitchProject(TIDEMenuCommand(Sender).Checked);
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
// IDE integration is done in constructor
|
||||
Extension := TiPhoneExtension.Create;
|
||||
EnvOptions.Load;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
finalization
|
||||
Extension.Free;
|
||||
|
||||
end.
|
||||
|
98
components/iphonelazext/ioptionsdialog.lfm
Normal file
98
components/iphonelazext/ioptionsdialog.lfm
Normal file
@ -0,0 +1,98 @@
|
||||
object Form1: TForm1
|
||||
Left = 301
|
||||
Height = 431
|
||||
Top = 268
|
||||
Width = 629
|
||||
Caption = 'iPhone options'
|
||||
ClientHeight = 431
|
||||
ClientWidth = 629
|
||||
LCLVersion = '0.9.29'
|
||||
object PageControl1: TPageControl
|
||||
Left = 16
|
||||
Height = 347
|
||||
Top = 16
|
||||
Width = 597
|
||||
ActivePage = TabSheet2
|
||||
Anchors = [akTop, akLeft, akRight, akBottom]
|
||||
TabIndex = 1
|
||||
TabOrder = 0
|
||||
object TabSheet1: TTabSheet
|
||||
Caption = 'iPhone Project Options'
|
||||
end
|
||||
object TabSheet2: TTabSheet
|
||||
Caption = 'Global Options'
|
||||
ClientHeight = 308
|
||||
ClientWidth = 591
|
||||
object Label1: TLabel
|
||||
Left = 20
|
||||
Height = 18
|
||||
Top = 64
|
||||
Width = 119
|
||||
Alignment = taRightJustify
|
||||
Caption = 'iPhone Sim Bundle:'
|
||||
ParentColor = False
|
||||
end
|
||||
object Edit1: TEdit
|
||||
Left = 149
|
||||
Height = 22
|
||||
Top = 60
|
||||
Width = 416
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 0
|
||||
Text = 'Edit1'
|
||||
end
|
||||
object Label2: TLabel
|
||||
Left = 37
|
||||
Height = 18
|
||||
Top = 116
|
||||
Width = 102
|
||||
Caption = 'FPC arm-darwin:'
|
||||
ParentColor = False
|
||||
end
|
||||
object Edit2: TEdit
|
||||
Left = 149
|
||||
Height = 22
|
||||
Top = 116
|
||||
Width = 416
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 1
|
||||
Text = 'Edit2'
|
||||
end
|
||||
object Edit3: TEdit
|
||||
Left = 149
|
||||
Height = 22
|
||||
Top = 28
|
||||
Width = 416
|
||||
TabOrder = 2
|
||||
Text = 'Edit3'
|
||||
end
|
||||
object Label3: TLabel
|
||||
Left = 9
|
||||
Height = 18
|
||||
Top = 28
|
||||
Width = 130
|
||||
Alignment = taRightJustify
|
||||
Caption = 'iPhone Sim SDKs dir:'
|
||||
ParentColor = False
|
||||
end
|
||||
end
|
||||
end
|
||||
object Button1: TButton
|
||||
Left = 328
|
||||
Height = 20
|
||||
Top = 384
|
||||
Width = 75
|
||||
Anchors = [akLeft, akBottom]
|
||||
Caption = 'Save'
|
||||
TabOrder = 1
|
||||
end
|
||||
object Button2: TButton
|
||||
Left = 232
|
||||
Height = 20
|
||||
Top = 384
|
||||
Width = 75
|
||||
Anchors = [akLeft, akBottom]
|
||||
Caption = 'Cancel'
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
29
components/iphonelazext/ioptionsdialog.lrs
Normal file
29
components/iphonelazext/ioptionsdialog.lrs
Normal file
@ -0,0 +1,29 @@
|
||||
{ This is an automatically generated lazarus resource file }
|
||||
|
||||
LazarusResources.Add('TForm1','FORMDATA',[
|
||||
'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'-'#1#6'Height'#3#175#1#3'Top'#3#12#1#5'Wi'
|
||||
+'dth'#3'u'#2#7'Caption'#6#14'iPhone options'#12'ClientHeight'#3#175#1#11'Cli'
|
||||
+'entWidth'#3'u'#2#10'LCLVersion'#6#6'0.9.29'#0#12'TPageControl'#12'PageContr'
|
||||
+'ol1'#4'Left'#2#16#6'Height'#3'['#1#3'Top'#2#16#5'Width'#3'U'#2#10'ActivePag'
|
||||
+'e'#7#9'TabSheet2'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0
|
||||
+#8'TabIndex'#2#1#8'TabOrder'#2#0#0#9'TTabSheet'#9'TabSheet1'#7'Caption'#6#22
|
||||
+'iPhone Project Options'#0#0#9'TTabSheet'#9'TabSheet2'#7'Caption'#6#14'Globa'
|
||||
+'l Options'#12'ClientHeight'#3'4'#1#11'ClientWidth'#3'O'#2#0#6'TLabel'#6'Lab'
|
||||
+'el1'#4'Left'#2#20#6'Height'#2#18#3'Top'#2'@'#5'Width'#2'w'#9'Alignment'#7#14
|
||||
+'taRightJustify'#7'Caption'#6#18'iPhone Sim Bundle:'#11'ParentColor'#8#0#0#5
|
||||
+'TEdit'#5'Edit1'#4'Left'#3#149#0#6'Height'#2#22#3'Top'#2'<'#5'Width'#3#160#1
|
||||
+#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#0#4'Text'#6#5'E'
|
||||
+'dit1'#0#0#6'TLabel'#6'Label2'#4'Left'#2'%'#6'Height'#2#18#3'Top'#2't'#5'Wid'
|
||||
+'th'#2'f'#7'Caption'#6#15'FPC arm-darwin:'#11'ParentColor'#8#0#0#5'TEdit'#5
|
||||
+'Edit2'#4'Left'#3#149#0#6'Height'#2#22#3'Top'#2't'#5'Width'#3#160#1#7'Anchor'
|
||||
+'s'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#1#4'Text'#6#5'Edit2'#0#0
|
||||
+#5'TEdit'#5'Edit3'#4'Left'#3#149#0#6'Height'#2#22#3'Top'#2#28#5'Width'#3#160
|
||||
+#1#8'TabOrder'#2#2#4'Text'#6#5'Edit3'#0#0#6'TLabel'#6'Label3'#4'Left'#2#9#6
|
||||
+'Height'#2#18#3'Top'#2#28#5'Width'#3#130#0#9'Alignment'#7#14'taRightJustify'
|
||||
+#7'Caption'#6#20'iPhone Sim SDKs dir:'#11'ParentColor'#8#0#0#0#0#7'TButton'#7
|
||||
+'Button1'#4'Left'#3'H'#1#6'Height'#2#20#3'Top'#3#128#1#5'Width'#2'K'#7'Ancho'
|
||||
+'rs'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#4'Save'#8'TabOrder'#2#1#0#0#7'T'
|
||||
+'Button'#7'Button2'#4'Left'#3#232#0#6'Height'#2#20#3'Top'#3#128#1#5'Width'#2
|
||||
+'K'#7'Anchors'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#6'Cancel'#8'TabOrder'
|
||||
+#2#2#0#0#0
|
||||
]);
|
7
components/iphonelazext/ioptionsdialog.pas
Normal file
7
components/iphonelazext/ioptionsdialog.pas
Normal file
@ -0,0 +1,7 @@
|
||||
unit iOptionsDialog;
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
224
components/iphonelazext/iphonebundle.pas
Normal file
224
components/iphonelazext/iphonebundle.pas
Normal file
@ -0,0 +1,224 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit iPhoneBundle;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
|
||||
const
|
||||
platform_iPhoneSim = 'iphonesimulator';
|
||||
sdk_iPhoneSim2_0 = 'iphonesimulator2.0';
|
||||
sdk_iPhoneSim2_1 = 'iphonesimulator2.1';
|
||||
sdk_iPhoneSim2_2 = 'iphonesimulator2.2';
|
||||
sdk_iPhoneSim3_0 = 'iphonesimulator3.0';
|
||||
sdk_iPhoneSim3_1 = 'iphonesimulator3.1';
|
||||
|
||||
type
|
||||
TiPhoneBundleInfo = record
|
||||
DisplayName : WideString; {if DisplayName='' then DisplayName=BundleName}
|
||||
iPlatform : WideString;
|
||||
SDKVersion : WideString;
|
||||
AppID : WideString;
|
||||
end;
|
||||
|
||||
function GetUserHomeDir: WideString;
|
||||
|
||||
function GetiPhoneSimUserPath(const UserHomeDir: WideString=''): WideString;
|
||||
|
||||
procedure MakeSimSpaceStruct(const BundleName: WideString; var BundleAppDir: WideString);
|
||||
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, BundleName: WideString; var BundleAppDir: WideString);
|
||||
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, SpaceName, BundleName: WideString; var BundleAppDir: WideString);
|
||||
|
||||
function GetBundleExeName(const BundleAppDir, ExeName: WideString): WideString;
|
||||
|
||||
procedure WritePkgFile(const FileName: WideString);
|
||||
function WriteDefInfoList(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
|
||||
|
||||
procedure CreateBundle(const BundleName, ExeName: WideString; const Info: TiPhoneBundleInfo; var FullBundlePath, FullExeName: WideString);
|
||||
procedure CreateBundle(const BundleName, SpaceName, ExeName: WideString; const Info: TiPhoneBundleInfo; var RealSpace, FullBundlePath, FullExeName: WideString);
|
||||
|
||||
function AddPathDelim(const w: WideString): WideString;
|
||||
|
||||
function RandomSpaceName: WideString;
|
||||
|
||||
implementation
|
||||
|
||||
function RandomSpaceName: WideString;
|
||||
var
|
||||
g : TGUID;
|
||||
id : String;
|
||||
begin
|
||||
CreateGUID(g);
|
||||
id:=GUIDToString(g);
|
||||
id:=Copy(id, 2, length(id)-2);
|
||||
Result:=id;
|
||||
end;
|
||||
|
||||
|
||||
procedure CreateBundle(const BundleName, SpaceName, ExeName: WideString; const Info: TiPhoneBundleInfo; var RealSpace, FullBundlePath, FullExeName: WideString);
|
||||
var
|
||||
appdir : WideString;
|
||||
begin
|
||||
if SpaceName='' then
|
||||
RealSpace:=RandomSpaceName
|
||||
else
|
||||
RealSpace:=SpaceName;
|
||||
|
||||
MakeSimSpaceStruct(GetiPhoneSimUserPath, RealSpace, BundleName, appdir);
|
||||
FullBundlePath:=appdir;
|
||||
appdir:=AddPathDelim(appdir);
|
||||
FullExeName:=appdir+ExeName;
|
||||
WritePkgFile(appdir+'PkgInfo');
|
||||
WriteDefInfoList(appdir+'Info.plist', BundleName, ExeName, Info);
|
||||
end;
|
||||
|
||||
procedure CreateBundle(const BundleName, ExeName: WideString; const Info: TiPhoneBundleInfo; var FullBundlePath, FullExeName: WideString);
|
||||
var
|
||||
sp : WideString;
|
||||
begin
|
||||
CreateBundle(BundleName, '', ExeName, Info, sp, FullBundlePath, FullExeName);
|
||||
end;
|
||||
|
||||
function AddPathDelim(const w: WideString): WideString;
|
||||
begin
|
||||
if w='' then
|
||||
Result:=PathDelim
|
||||
else if w[length(w)]<>PathDelim then
|
||||
Result:=w+PathDelim;
|
||||
end;
|
||||
|
||||
function GetUserHomeDir: WideString;
|
||||
begin
|
||||
Result:=UTF8Decode(GetUserDir);
|
||||
end;
|
||||
|
||||
function GetiPhoneSimUserPath(const UserHomeDir: WideString=''): WideString;
|
||||
var
|
||||
nm : WideString;
|
||||
begin
|
||||
if UserHomeDir = '' then nm:=GetUserHomeDir
|
||||
else nm:=UserHomeDir;
|
||||
|
||||
if nm='' then Exit;
|
||||
if nm[length(nm)]<>'/' then nm:=nm+'/';
|
||||
Result:=nm+'Library/Application Support/iPhone Simulator/User/Applications/';
|
||||
end;
|
||||
|
||||
{
|
||||
~/Library/Application Support/iPhone Simulator/Users/%SPACENAME%
|
||||
|
||||
%SPACENAME%/Applications
|
||||
%SPACENAME%/Applications/%AppBundle.app%
|
||||
%SPACENAME%/Documents
|
||||
%SPACENAME%/tmp
|
||||
}
|
||||
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, SpaceName, BundleName: WideString; var BundleAppDir: WideString);
|
||||
var
|
||||
path8 : String;
|
||||
space8 : String;
|
||||
p : string;
|
||||
begin
|
||||
path8:=UTF8Encode(iPhoneSimUserPath);
|
||||
space8:=UTF8Encode(SpaceName);
|
||||
|
||||
p:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(path8)+space8);
|
||||
BundleAppDir:=UTF8Decode(p+UTF8Encode(BundleName)+'.app');
|
||||
ForceDirectories(UTF8Encode(BundleAppDir));
|
||||
ForceDirectories(p+'Documents');
|
||||
ForceDirectories(p+'tmp');
|
||||
|
||||
end;
|
||||
|
||||
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, BundleName: WideString; var BundleAppDir: WideString);
|
||||
begin
|
||||
MakeSimSpaceStruct(iPhoneSimUserPath, RandomSpaceName, BundleName, BundleAppDir);
|
||||
end;
|
||||
|
||||
procedure MakeSimSpaceStruct(const BundleName: WideString; var BundleAppDir: WideString);
|
||||
begin
|
||||
MakeSimSpaceStruct( GetiPhoneSimUserPath, BundleName, BundleAppDir);
|
||||
end;
|
||||
|
||||
function GetBundleExeName(const BundleAppDir, ExeName: WideString): WideString;
|
||||
begin
|
||||
Result:=AddPathDelim(BundleAppDir)+ExeName;
|
||||
end;
|
||||
|
||||
procedure WritePkgFile(const FileName: WideString);
|
||||
var
|
||||
fs : TFileStream;
|
||||
s : String;
|
||||
begin
|
||||
fs:=TFileStream.Create( UTF8Encode(FileName), fmCreate);
|
||||
s:='APPL????';
|
||||
fs.Write(s[1], length(s));
|
||||
fs.Free;
|
||||
end;
|
||||
|
||||
function WriteDefInfoList(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
|
||||
const
|
||||
BundleFormat : AnsiString =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'#10+
|
||||
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'#10+
|
||||
'<plist version="1.0">'#10+
|
||||
'<dict>'#10+
|
||||
' <key>CFBundleDevelopmentRegion</key>'#10+ ' <string>English</string>'#10+
|
||||
' <key>CFBundleDisplayName</key>'#10+ ' <string>%s</string>'#10+ {display name}
|
||||
' <key>CFBundleExecutable</key>'#10+ ' <string>%s</string>'#10+ {exe name}
|
||||
' <key>CFBundleIdentifier</key>'#10+ ' <string>%s</string>'#10+ {company + bundle name}
|
||||
' <key>CFBundleInfoDictionaryVersion</key>'#10+ ' <string>6.0</string>'#10+
|
||||
' <key>CFBundleName</key>'#10+ ' <string>%s</string>'#10+ {bundle name}
|
||||
' <key>CFBundlePackageType</key>'#10+ ' <string>APPL</string>'#10+
|
||||
' <key>CFBundleSignature</key>'#10+ ' <string>????</string>'#10+
|
||||
' <key>CFBundleSupportedPlatforms</key>'#10+ ' <array>'#10+' <string>%s</string>'#10+' </array>'#10+ {platform}
|
||||
' <key>CFBundleVersion</key>'#10+ ' <string>1.0</string>'#10+
|
||||
' <key>DTPlatformName</key>'#10+ ' <string>%s</string>'#10+ {platform}
|
||||
' <key>DTSDKName</key>'#10+ ' <string>%s</string>'#10+ {sdk version}
|
||||
' <key>LSRequiresIPhoneOS</key>'#10+ ' <true/>'#10+
|
||||
'</dict>'#10+
|
||||
'</plist>';
|
||||
var
|
||||
dispName : WideString;
|
||||
s : String;
|
||||
fs : TFileStream;
|
||||
begin
|
||||
Result:=false;
|
||||
if BundleName='' then Exit;
|
||||
|
||||
dispName:=info.DisplayName;
|
||||
if dispName='' then dispName:=BundleName;
|
||||
|
||||
with info do
|
||||
s:=Format( BundleFormat,
|
||||
[ UTF8Encode(dispName),
|
||||
UTF8Encode(ExeName),
|
||||
UTF8Encode(AppID),
|
||||
UTF8Encode(BundleName),
|
||||
UTF8Encode(iPlatform),
|
||||
UTF8Encode(iPlatform),
|
||||
UTF8Encode(SDKVersion)
|
||||
]);
|
||||
if FileExists(InfoFileName) then DeleteFile(InfoFileName);
|
||||
fs:=TFileStream.Create(InfoFileName, fmCreate or fmOpenWrite);
|
||||
if s<>'' then fs.Write(s[1], length(s));
|
||||
fs.Free;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
331
components/iphonelazext/iphoneextoptions.pas
Normal file
331
components/iphonelazext/iphoneextoptions.pas
Normal file
@ -0,0 +1,331 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
|
||||
unit iPhoneExtOptions;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, iPhoneBundle, XMLConf;
|
||||
|
||||
type
|
||||
|
||||
{ TiPhoneProjectOptions }
|
||||
|
||||
TiPhoneProjectOptions = class(TAbstractIDEProjectOptions)
|
||||
private
|
||||
fisiPhone : Boolean;
|
||||
fAppID : string;
|
||||
fSDK : string;
|
||||
DataWritten : Boolean;
|
||||
fSpaceName : string;
|
||||
public
|
||||
constructor Create;
|
||||
class function GetGroupCaption: string; override;
|
||||
class function GetInstance: TAbstractIDEOptions; override;
|
||||
function Load: Boolean;
|
||||
function Save: Boolean;
|
||||
procedure Reset;
|
||||
property isIPhoneApp: Boolean read fisIPhone write fisIPhone;
|
||||
property SDK: string read fSDK write fSDK;
|
||||
property AppID: string read fAppID write fAppID;
|
||||
property SpaceName: string read fSpaceName write fSpaceName;
|
||||
end;
|
||||
|
||||
{ TiPhoneEnvironmentOptions }
|
||||
|
||||
TiPhoneEnvironmentOptions = class(TAbstractIDEEnvironmentOptions)
|
||||
private
|
||||
fPlatformsBaseDir : string;
|
||||
fCompilerPath : string;
|
||||
fBaseRTLPath : string;
|
||||
fCommonOpt : string;
|
||||
fSimAppsPath : string;
|
||||
fSimBundle : string;
|
||||
protected
|
||||
function XMLFileName: string;
|
||||
public
|
||||
constructor Create;
|
||||
class function GetGroupCaption: string; override;
|
||||
class function GetInstance: TAbstractIDEOptions; override;
|
||||
|
||||
function Load: Boolean;
|
||||
function Save: Boolean;
|
||||
|
||||
function GetSimSDK(const ProjSDK: string; var SDKName, SDKFullPath: string): Boolean;
|
||||
function GetDeviceSDK(const ProjSDK: string; var SDKName, SDKFullPath: string): Boolean;
|
||||
|
||||
function GetSDKName(const SDKVer: string; simulator: Boolean): string;
|
||||
function GetSDKFullPath(const SDKVer: string; simulator: Boolean): string;
|
||||
|
||||
procedure GetSDKVersions(Strings: TStringList);
|
||||
|
||||
|
||||
property PlatformsBaseDir: string read fPlatformsBaseDir write fPlatformsBaseDir;
|
||||
property CompilerPath: string read fCompilerPath write fCompilerPath;
|
||||
property BaseRTLPath: string read fBaseRTLPath write fBaseRTLPath;
|
||||
property CommonOpt: string read fCommonOpt write fCommonOpt;
|
||||
|
||||
property SimBundle: string read fSimBundle write fSimBundle;
|
||||
property SimAppsPath: string read fSimAppsPath write fSimAppsPath;
|
||||
end;
|
||||
|
||||
function EnvOptions: TiPhoneEnvironmentOptions;
|
||||
function ProjOptions: TiPhoneProjectOptions;
|
||||
|
||||
var
|
||||
iPhoneEnvGroup : Integer;
|
||||
iPhonePrjGroup : Integer;
|
||||
|
||||
implementation
|
||||
|
||||
var
|
||||
fEnvOptions : TiPhoneEnvironmentOptions = nil;
|
||||
fProjOptions : TiPhoneProjectOptions = nil;
|
||||
|
||||
const
|
||||
DefaultXMLName = 'iphoneextconfig.xml';
|
||||
|
||||
optisIphone = 'iPhone/isiPhoneApp';
|
||||
optSDK = 'iPhone/SDK';
|
||||
optAppID = 'iPhone/AppID';
|
||||
optSpaceName = 'iPhone/SimSpaceName';
|
||||
|
||||
|
||||
function EnvOptions: TiPhoneEnvironmentOptions;
|
||||
begin
|
||||
if not Assigned(fEnvOptions) then
|
||||
fEnvOptions:=TiPhoneEnvironmentOptions.Create;
|
||||
Result:=fEnvOptions;
|
||||
end;
|
||||
|
||||
function ProjOptions: TiPhoneProjectOptions;
|
||||
begin
|
||||
if not Assigned(fProjOptions) then
|
||||
fProjOptions:=TiPhoneProjectOptions.Create;
|
||||
Result:=fProjOptions;
|
||||
end;
|
||||
|
||||
procedure InitOptions;
|
||||
begin
|
||||
iPhoneEnvGroup := GetFreeIDEOptionsGroupIndex(GroupEnvironment);
|
||||
iPhonePrjGroup := GetFreeIDEOptionsGroupIndex(GroupProject);
|
||||
RegisterIDEOptionsGroup(iPhoneEnvGroup, TiPhoneEnvironmentOptions);
|
||||
RegisterIDEOptionsGroup(iPhonePrjGroup, TiPhoneProjectOptions);
|
||||
end;
|
||||
|
||||
procedure FreeOptions;
|
||||
begin
|
||||
fEnvOptions.Free;
|
||||
end;
|
||||
|
||||
{ TiPhoneEnvironmentOptions }
|
||||
|
||||
class function TiPhoneEnvironmentOptions.GetGroupCaption: string;
|
||||
begin
|
||||
Result:='iPhone Environment';
|
||||
end;
|
||||
|
||||
class function TiPhoneEnvironmentOptions.GetInstance: TAbstractIDEOptions;
|
||||
begin
|
||||
Result:=EnvOptions;
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.XMLFileName: String;
|
||||
begin
|
||||
Result:=IncludeTrailingPathDelimiter(LazarusIDE.GetPrimaryConfigPath)+DefaultXMLName;
|
||||
end;
|
||||
|
||||
function GetDefaultPlatformPath: WideString;
|
||||
begin
|
||||
//todo:
|
||||
Result:='/Developer/Platforms';
|
||||
end;
|
||||
|
||||
function GetDefaultSimBundlePath: WideString;
|
||||
begin
|
||||
//todo:
|
||||
Result:=IncludeTrailingPathDelimiter(GetDefaultPlatformPath)+
|
||||
'iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app';
|
||||
end;
|
||||
|
||||
function GetDefaultSimAppPath: WideSTring;
|
||||
begin
|
||||
//todo:
|
||||
Result:=IncludeTrailingPathDelimiter(GetUserDir)+
|
||||
'Library/Applications Support/iPhone Simulator/User/Applications/';
|
||||
end;
|
||||
|
||||
constructor TiPhoneEnvironmentOptions.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
fPlatformsBaseDir := GetDefaultPlatformPath;
|
||||
fSimAppsPath := GetDefaultSimAppPath;
|
||||
fSimBundle := GetDefaultSimBundlePath;
|
||||
fCompilerPath := '/usr/local/bin/fpc';
|
||||
end;
|
||||
|
||||
|
||||
function TiPhoneEnvironmentOptions.Load: Boolean;
|
||||
var
|
||||
xmlcfg : TXMLConfig;
|
||||
begin
|
||||
Result:=true;
|
||||
try
|
||||
xmlcfg := TXMLConfig.Create(nil);
|
||||
try
|
||||
xmlcfg.RootName:='config';
|
||||
xmlcfg.Filename:=XMLFileName;
|
||||
fPlatformsBaseDir := UTF8Encode(xmlcfg.GetValue('Platforms', fPlatformsBaseDir ));
|
||||
fCompilerPath := UTF8Encode(xmlcfg.GetValue('Compiler', fCompilerPath));
|
||||
fBaseRTLPath := UTF8Encode(xmlcfg.GetValue('RTLPath', fBaseRTLPath));
|
||||
fCommonOpt := UTF8Encode(xmlcfg.GetValue('CompilerOptions', fCommonOpt));
|
||||
fSimBundle := UTF8Encode(xmlcfg.GetValue('SimBundle', fSimBundle));
|
||||
fSimAppsPath := UTF8Encode(xmlcfg.GetValue('SimAppPath', fSimAppsPath));
|
||||
finally
|
||||
xmlcfg.Free;
|
||||
end;
|
||||
except
|
||||
Result:=false;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.Save: Boolean;
|
||||
var
|
||||
xmlcfg : TXMLConfig;
|
||||
begin
|
||||
Result:=true;
|
||||
try
|
||||
xmlcfg := TXMLConfig.Create(nil);
|
||||
try
|
||||
xmlcfg.RootName:='config';
|
||||
xmlcfg.Filename:=XMLFileName;
|
||||
xmlcfg.SetValue('Platforms', UTF8Decode(fPlatformsBaseDir));
|
||||
xmlcfg.SetValue('Compiler', UTF8Decode(fCompilerPath));
|
||||
xmlcfg.SetValue('RTLPath', UTF8Decode(fBaseRTLPath));
|
||||
xmlcfg.SetValue('CompilerOptions', UTF8Decode(fCommonOpt));
|
||||
xmlcfg.SetValue('SimBundle', UTF8Decode(fSimBundle));
|
||||
xmlcfg.SetValue('SimAppPath', UTF8Decode(fSimAppsPath));
|
||||
finally
|
||||
xmlcfg.Free;
|
||||
end;
|
||||
except
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.GetSimSDK(const ProjSDK: string; var SDKName, SDKFullPath: string): Boolean;
|
||||
const
|
||||
iPhoneSimSDKDir = 'iPhoneSimulator2.0.sdk';
|
||||
begin
|
||||
SDKName:=sdk_iPhoneSim2_0;
|
||||
SDKFullPath:=IncludeTrailingPathDelimiter(fPlatformsBaseDir)+'iPhoneSimulator.platform/Developer/SDKs/'+iPhoneSimSDKDir;
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.GetDeviceSDK(const ProjSDK: string; var SDKName, SDKFullPath: string): Boolean;
|
||||
begin
|
||||
SDKName:='iphoneos2.0';
|
||||
SDKFullPath:='';
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.GetSDKName(const SDKVer: string;
|
||||
simulator: Boolean): string;
|
||||
begin
|
||||
if simulator then Result:='iphonesimulator2.0'
|
||||
else Result:='iphoneos2.0';
|
||||
end;
|
||||
|
||||
function TiPhoneEnvironmentOptions.GetSDKFullPath(const SDKVer: string; simulator: Boolean): string;
|
||||
begin
|
||||
if simulator then
|
||||
Result := IncludeTrailingPathDelimiter(fPlatformsBaseDir)+'iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.0.sdk'
|
||||
else
|
||||
Result := IncludeTrailingPathDelimiter(fPlatformsBaseDir)+'iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk';
|
||||
end;
|
||||
|
||||
procedure TiPhoneEnvironmentOptions.GetSDKVersions(Strings: TStringList);
|
||||
begin
|
||||
//todo:
|
||||
Strings.Add('iPhone OS 2.0');
|
||||
end;
|
||||
|
||||
{ TiPhoneProjectOptions }
|
||||
|
||||
procedure TiPhoneProjectOptions.Reset;
|
||||
begin
|
||||
fisiPhone:=false;
|
||||
fSDK:='iPhone 2.0';
|
||||
fAppID:='com.mycompany.myapplication';
|
||||
fSpaceName:='';
|
||||
DataWritten:=false;
|
||||
end;
|
||||
|
||||
constructor TiPhoneProjectOptions.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Reset;
|
||||
end;
|
||||
|
||||
class function TiPhoneProjectOptions.GetGroupCaption: string;
|
||||
begin
|
||||
Result:='iPhone';
|
||||
end;
|
||||
|
||||
class function TiPhoneProjectOptions.GetInstance: TAbstractIDEOptions;
|
||||
begin
|
||||
Result:=ProjOptions;
|
||||
end;
|
||||
|
||||
function TiPhoneProjectOptions.Load: Boolean;
|
||||
begin
|
||||
Result:=True;
|
||||
with LazarusIDE.ActiveProject do begin
|
||||
DataWritten:=CustomData.Contains(optisIphone);
|
||||
fisiPhone:=(DataWritten) and (CustomData.Values[optisIphone] = 'true');
|
||||
if CustomData.Contains(optSDK) then fSDK:=CustomData.Values[optSDK];
|
||||
if CustomData.Contains(optAppID) then fAppID:=CustomData.Values[optAppID];
|
||||
fSpaceName:=CustomData.Values[optSpaceName];
|
||||
if fSpaceName='' then fSpaceName:=RandomSpaceName;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TiPhoneProjectOptions.Save: Boolean;
|
||||
const
|
||||
BoolStr : array[Boolean] of string = ('false', 'true');
|
||||
begin
|
||||
Result:=True;
|
||||
{do not write iPhone related info to non-iPhone projects}
|
||||
if DataWritten or fisiPhone then
|
||||
with LazarusIDE.ActiveProject do begin
|
||||
CustomData.Values[optisIPhone] := BoolStr[fisiPhone];
|
||||
CustomData.Values[optSDK]:=fSDK;
|
||||
CustomData.Values[optAppID]:=fAppID;
|
||||
CustomData.Values[optSpaceName]:=fSpaceName;
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
InitOptions;
|
||||
|
||||
finalization
|
||||
FreeOptions;
|
||||
|
||||
end.
|
||||
|
38
components/iphonelazext/iphoneextstr.pas
Normal file
38
components/iphonelazext/iphoneextstr.pas
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit iPhoneExtStr;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
resourcestring
|
||||
striPhoneProject = 'iPhone Project';
|
||||
strStartAtXCode = 'Update XCode project';
|
||||
strRunSimulator = 'Run iPhone Simulator';
|
||||
|
||||
strPrjOptTitle = 'iPhone specific';
|
||||
strPrjOptIsiPhone = 'is iPhone application project';
|
||||
strPrjOptSDKver = 'SDK version:';
|
||||
strPrjOptCheckSDK = 'Check available SDKs';
|
||||
strPtrOptAppID = 'Application ID';
|
||||
strPtrOptAppIDHint = 'It''s recommended by Apple to use domain-structured identifier i.e. "com.mycompany.myApplication"';
|
||||
|
||||
strXcodeUpdated = 'Xcode project updated';
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
90
components/iphonelazext/iphonelazext.lpk
Normal file
90
components/iphonelazext/iphonelazext.lpk
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0"?>
|
||||
<CONFIG>
|
||||
<Package Version="3">
|
||||
<Name Value="iphonelazext"/>
|
||||
<Author Value="Dmitry 'skalogryz' Boyarintsev"/>
|
||||
<CompilerOptions>
|
||||
<Version Value="8"/>
|
||||
<SearchPaths>
|
||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Other>
|
||||
<CompilerMessages>
|
||||
<IgnoredMessages idx4055="True" idx4079="True" idx4080="True" idx4081="True" idx5024="True" idx5057="True" idx5060="True"/>
|
||||
</CompilerMessages>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Description Value="iPhone Development Lazarus extension
|
||||
"/>
|
||||
<License Value="LGPL"/>
|
||||
<Version Minor="5"/>
|
||||
<Files Count="11">
|
||||
<Item1>
|
||||
<Filename Value="ideext.pas"/>
|
||||
<HasRegisterProc Value="True"/>
|
||||
<UnitName Value="ideext"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Filename Value="iphoneextstr.pas"/>
|
||||
<UnitName Value="iPhoneExtStr"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Filename Value="iphonebundle.pas"/>
|
||||
<UnitName Value="iPhoneBundle"/>
|
||||
</Item3>
|
||||
<Item4>
|
||||
<Filename Value="xcodeproject.pas"/>
|
||||
<UnitName Value="XCodeProject"/>
|
||||
</Item4>
|
||||
<Item5>
|
||||
<Filename Value="environment_iphone_options.pas"/>
|
||||
<UnitName Value="environment_iphone_options"/>
|
||||
</Item5>
|
||||
<Item6>
|
||||
<Filename Value="project_iphone_options.pas"/>
|
||||
<UnitName Value="project_iphone_options"/>
|
||||
</Item6>
|
||||
<Item7>
|
||||
<Filename Value="iphoneextoptions.pas"/>
|
||||
<UnitName Value="iPhoneExtOptions"/>
|
||||
</Item7>
|
||||
<Item8>
|
||||
<Filename Value="xcodetemplate.pas"/>
|
||||
<UnitName Value="xcodetemplate"/>
|
||||
</Item8>
|
||||
<Item9>
|
||||
<Filename Value="environment_iphone_options.lfm"/>
|
||||
<Type Value="LFM"/>
|
||||
</Item9>
|
||||
<Item10>
|
||||
<Filename Value="project_iphone_options.lfm"/>
|
||||
<Type Value="LFM"/>
|
||||
</Item10>
|
||||
<Item11>
|
||||
<Filename Value="lazfilesutils.pas"/>
|
||||
<UnitName Value="lazfilesutils"/>
|
||||
</Item11>
|
||||
</Files>
|
||||
<Type Value="RunAndDesignTime"/>
|
||||
<RequiredPkgs Count="3">
|
||||
<Item1>
|
||||
<PackageName Value="LCL"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<PackageName Value="IDEIntf"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<PackageName Value="FCL"/>
|
||||
<MinVersion Major="1" Valid="True"/>
|
||||
</Item3>
|
||||
</RequiredPkgs>
|
||||
<UsageOptions>
|
||||
<UnitPath Value="$(PkgOutDir)/"/>
|
||||
</UsageOptions>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<IgnoreBinaries Value="False"/>
|
||||
</PublishOptions>
|
||||
</Package>
|
||||
</CONFIG>
|
23
components/iphonelazext/iphonelazext.pas
Normal file
23
components/iphonelazext/iphonelazext.pas
Normal file
@ -0,0 +1,23 @@
|
||||
{ This file was automatically created by Lazarus. do not edit!
|
||||
This source is only used to compile and install the package.
|
||||
}
|
||||
|
||||
unit iphonelazext;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
||||
environment_iphone_options, project_iphone_options, iPhoneExtOptions,
|
||||
xcodetemplate, lazfilesutils, LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterUnit('ideext', @ideext.Register);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterPackage('iphonelazext', @Register);
|
||||
end.
|
137
components/iphonelazext/lazfilesutils.pas
Normal file
137
components/iphonelazext/lazfilesutils.pas
Normal file
@ -0,0 +1,137 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit lazfilesutils;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil,
|
||||
LazIDEIntf,ProjectIntf;
|
||||
|
||||
|
||||
function ResolveProjectPath(const path: string; project: TLazProject = nil): string;
|
||||
|
||||
function BreakPathsStringToOption(const Paths, Switch: String; const Quotes: string = '"'; project: TLazProject = nil): String;
|
||||
|
||||
function RelativeToFullPath(const BasePath, Relative: string): String;
|
||||
function NeedQuotes(const path: string): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
function GetNextDir(const Path: string; var index: integer; var Name: string): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
Result:=index<=length(Path);
|
||||
if not Result then Exit;
|
||||
|
||||
if Path[index]=PathDelim then inc(index);
|
||||
Result:=index<=length(Path);
|
||||
if not Result then Exit;
|
||||
|
||||
for i:=index to length(Path) do
|
||||
if Path[i]=PathDelim then begin
|
||||
Name:=Copy(Path, index, i - index);
|
||||
index:=i+1;
|
||||
Exit;
|
||||
end;
|
||||
Name:=Copy(Path, index, length(Path) - index+1);
|
||||
index:=length(Path)+1;
|
||||
end;
|
||||
|
||||
function RelativeToFullPath(const BasePath, Relative: string): String;
|
||||
var
|
||||
i : integer;
|
||||
nm : string;
|
||||
begin
|
||||
Result:=ExcludeTrailingPathDelimiter(BasePath);
|
||||
i:=1;
|
||||
while GetNextDir(Relative, i, nm) do
|
||||
if nm = '..' then
|
||||
Result:=ExtractFileDir(Result)
|
||||
else if nm <> '.' then
|
||||
Result:=IncludeTrailingPathDelimiter(Result)+nm;
|
||||
end;
|
||||
|
||||
function NeedQuotes(const path: string): Boolean;
|
||||
var
|
||||
i : integer;
|
||||
const
|
||||
SpaceChars = [#32,#9];
|
||||
begin
|
||||
for i:=1 to length(path) do
|
||||
if path[i] in SpaceChars then begin
|
||||
Result:=true;
|
||||
Exit;
|
||||
end;
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
function QuoteStrIfNeeded(const path: string; const quotes: String): String;
|
||||
begin
|
||||
if NeedQuotes(path) then
|
||||
Result:=quotes+path+quotes
|
||||
else
|
||||
Result:=path;
|
||||
end;
|
||||
|
||||
function ResolveProjectPath(const path: string; project: TLazProject): string;
|
||||
var
|
||||
base : string;
|
||||
begin
|
||||
if project=nil then project:=LazarusIDE.ActiveProject;
|
||||
|
||||
if FilenameIsAbsolute(Path) then
|
||||
Result:=Path
|
||||
else begin
|
||||
base:='';
|
||||
base:=ExtractFilePath(project.ProjectInfoFile);
|
||||
Result:=RelativeToFullPath(base, Path);
|
||||
end;
|
||||
end;
|
||||
|
||||
function BreakPathsStringToOption(const Paths, Switch, Quotes: String; project: TLazProject): String;
|
||||
var
|
||||
i, j : Integer;
|
||||
fixed : String;
|
||||
begin
|
||||
Result:='';
|
||||
if not Assigned(project) then
|
||||
project:=LazarusIDE.ActiveProject;
|
||||
|
||||
if not Assigned(project) then Exit;
|
||||
|
||||
j:=1;
|
||||
for i:=1 to length(paths)-1 do
|
||||
if Paths[i]=';' then begin
|
||||
fixed:=Trim(Copy(paths,j, i-j) );
|
||||
if fixed<>'' then begin
|
||||
fixed:=ResolveProjectPath(fixed, project);
|
||||
Result:=Result+' ' + Switch + QuoteStrIfNeeded(fixed, quotes);
|
||||
end;
|
||||
j:=i+1;
|
||||
end;
|
||||
|
||||
fixed:=Trim(Copy(paths,j, length(paths)-j+1) );
|
||||
if fixed<>'' then begin
|
||||
fixed:=ResolveProjectPath(fixed, project);
|
||||
Result:=Result+' ' + Switch + QuoteStrIfNeeded(fixed, quotes);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
90
components/iphonelazext/project_iphone_options.lfm
Normal file
90
components/iphonelazext/project_iphone_options.lfm
Normal file
@ -0,0 +1,90 @@
|
||||
inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
Height = 374
|
||||
Width = 618
|
||||
ClientHeight = 374
|
||||
ClientWidth = 618
|
||||
OnClick = FrameClick
|
||||
DesignLeft = 355
|
||||
DesignTop = 224
|
||||
object chkisPhone: TCheckBox[0]
|
||||
Left = 16
|
||||
Height = 18
|
||||
Top = 16
|
||||
Width = 199
|
||||
Caption = 'is iPhone application project'
|
||||
TabOrder = 0
|
||||
end
|
||||
object lblAppID: TLabel[1]
|
||||
Left = 16
|
||||
Height = 18
|
||||
Top = 88
|
||||
Width = 87
|
||||
Caption = 'Application ID'
|
||||
ParentColor = False
|
||||
end
|
||||
object edtAppID: TEdit[2]
|
||||
Left = 112
|
||||
Height = 22
|
||||
Top = 85
|
||||
Width = 488
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 1
|
||||
Text = 'com.mycompany.myapp'
|
||||
end
|
||||
object lblAppIDHint: TLabel[3]
|
||||
Left = 16
|
||||
Height = 14
|
||||
Top = 117
|
||||
Width = 493
|
||||
Caption = 'It''s recommended by Apple to use domain-structured name, i.e. com.mycompany.myApplication as ID'
|
||||
Font.Height = -10
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object lblSDKVer: TLabel[4]
|
||||
Left = 16
|
||||
Height = 18
|
||||
Top = 51
|
||||
Width = 80
|
||||
Caption = 'SDK version:'
|
||||
ParentColor = False
|
||||
end
|
||||
object cmbSDKs: TComboBox[5]
|
||||
Left = 112
|
||||
Height = 20
|
||||
Top = 48
|
||||
Width = 184
|
||||
ItemHeight = 0
|
||||
ItemIndex = 0
|
||||
Items.Strings = (
|
||||
'iPhone 2.0'
|
||||
'iPhone 2.1'
|
||||
'iPhone 2.2'
|
||||
'iPhone 2.2.1'
|
||||
'iPhone 3.0'
|
||||
'iPhone 3.1'
|
||||
'iPhone 3.1.2'
|
||||
)
|
||||
OnChange = cmbSDKsChange
|
||||
Style = csDropDownList
|
||||
TabOrder = 2
|
||||
Text = 'iPhone 2.0'
|
||||
end
|
||||
object btnCheckSDK: TButton[6]
|
||||
Left = 312
|
||||
Height = 20
|
||||
Top = 48
|
||||
Width = 158
|
||||
AutoSize = True
|
||||
Caption = 'Check available SDKs'
|
||||
TabOrder = 3
|
||||
end
|
||||
object lblXibFiles: TLabel[7]
|
||||
Left = 16
|
||||
Height = 18
|
||||
Top = 168
|
||||
Width = 219
|
||||
Caption = '.XIB files might appear here soon...'
|
||||
ParentColor = False
|
||||
end
|
||||
end
|
29
components/iphonelazext/project_iphone_options.lrs
Normal file
29
components/iphonelazext/project_iphone_options.lrs
Normal file
@ -0,0 +1,29 @@
|
||||
{ This is an automatically generated lazarus resource file }
|
||||
|
||||
LazarusResources.Add('TiPhoneProjectOptionsEditor','FORMDATA',[
|
||||
'TPF0'#241#27'TiPhoneProjectOptionsEditor'#26'iPhoneProjectOptionsEditor'#6'H'
|
||||
+'eight'#3'v'#1#5'Width'#3'j'#2#12'ClientHeight'#3'v'#1#11'ClientWidth'#3'j'#2
|
||||
+#7'OnClick'#7#10'FrameClick'#10'DesignLeft'#3'c'#1#9'DesignTop'#3#224#0#0#242
|
||||
+#2#0#9'TCheckBox'#10'chkisPhone'#4'Left'#2#16#6'Height'#2#18#3'Top'#2#16#5'W'
|
||||
+'idth'#3#199#0#7'Caption'#6#29'is iPhone application project'#8'TabOrder'#2#0
|
||||
+#0#0#242#2#1#6'TLabel'#8'lblAppID'#4'Left'#2#16#6'Height'#2#18#3'Top'#2'X'#5
|
||||
+'Width'#2'W'#7'Caption'#6#14'Application ID'#11'ParentColor'#8#0#0#242#2#2#5
|
||||
+'TEdit'#8'edtAppID'#4'Left'#2'p'#6'Height'#2#22#3'Top'#2'U'#5'Width'#3#232#1
|
||||
+#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#1#4'Text'#6#19
|
||||
+'com.mycompany.myapp'#0#0#242#2#3#6'TLabel'#12'lblAppIDHint'#4'Left'#2#16#6
|
||||
+'Height'#2#14#3'Top'#2'u'#5'Width'#3#237#1#7'Caption'#6'_It''s recommended b'
|
||||
+'y Apple to use domain-structured name, i.e. com.mycompany.myApplication as '
|
||||
+'ID'#11'Font.Height'#2#246#11'ParentColor'#8#10'ParentFont'#8#0#0#242#2#4#6
|
||||
+'TLabel'#9'lblSDKVer'#4'Left'#2#16#6'Height'#2#18#3'Top'#2'3'#5'Width'#2'P'#7
|
||||
+'Caption'#6#12'SDK version:'#11'ParentColor'#8#0#0#242#2#5#9'TComboBox'#7'cm'
|
||||
+'bSDKs'#4'Left'#2'p'#6'Height'#2#20#3'Top'#2'0'#5'Width'#3#184#0#10'ItemHeig'
|
||||
+'ht'#2#0#9'ItemIndex'#2#0#13'Items.Strings'#1#6#10'iPhone 2.0'#6#10'iPhone 2'
|
||||
+'.1'#6#10'iPhone 2.2'#6#12'iPhone 2.2.1'#6#10'iPhone 3.0'#6#10'iPhone 3.1'#6
|
||||
+#12'iPhone 3.1.2'#0#8'OnChange'#7#13'cmbSDKsChange'#5'Style'#7#14'csDropDown'
|
||||
+'List'#8'TabOrder'#2#2#4'Text'#6#10'iPhone 2.0'#0#0#242#2#6#7'TButton'#11'bt'
|
||||
+'nCheckSDK'#4'Left'#3'8'#1#6'Height'#2#20#3'Top'#2'0'#5'Width'#3#158#0#8'Aut'
|
||||
+'oSize'#9#7'Caption'#6#20'Check available SDKs'#8'TabOrder'#2#3#0#0#242#2#7#6
|
||||
+'TLabel'#11'lblXibFiles'#4'Left'#2#16#6'Height'#2#18#3'Top'#3#168#0#5'Width'
|
||||
+#3#219#0#7'Caption'#6'$.XIB files might appear here soon...'#11'ParentColor'
|
||||
+#8#0#0#0
|
||||
]);
|
131
components/iphonelazext/project_iphone_options.pas
Normal file
131
components/iphonelazext/project_iphone_options.pas
Normal file
@ -0,0 +1,131 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit project_iphone_options;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls,
|
||||
IDEOPtionsIntf, ProjectIntf,
|
||||
iPhoneExtStr, iPhoneExtOptions;
|
||||
|
||||
type
|
||||
|
||||
{ TiPhoneProjectOptionsEditor }
|
||||
|
||||
TiPhoneProjectOptionsEditor = class(TAbstractIDEOptionsEditor)
|
||||
btnCheckSDK: TButton;
|
||||
chkisPhone: TCheckBox;
|
||||
cmbSDKs: TComboBox;
|
||||
edtAppID: TEdit;
|
||||
lblXibFiles: TLabel;
|
||||
lblAppID: TLabel;
|
||||
lblAppIDHint: TLabel;
|
||||
lblSDKVer: TLabel;
|
||||
procedure cmbSDKsChange(Sender: TObject);
|
||||
procedure FrameClick(Sender: TObject);
|
||||
private
|
||||
{ private declarations }
|
||||
public
|
||||
{ public declarations }
|
||||
class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
|
||||
function GetTitle: String; override;
|
||||
procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
|
||||
procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
|
||||
procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
|
||||
end;
|
||||
|
||||
|
||||
procedure EnableiPhoneAppProject(project: TLazProject);
|
||||
|
||||
implementation
|
||||
|
||||
procedure EnableiPhoneAppProject(project: TLazProject);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
{ TiPhoneProjectOptionsEditor }
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.FrameClick(Sender: TObject);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
function TiPhoneProjectOptionsEditor.GetTitle: String;
|
||||
begin
|
||||
Result:=strPrjOptTitle;
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.Setup(ADialog: TAbstractOptionsEditorDialog);
|
||||
begin
|
||||
chkisPhone.Caption := strPrjOptIsiPhone;
|
||||
lblSDKVer.Caption := strPrjOptSDKver;
|
||||
btnCheckSDK.Caption := strPrjOptCheckSDK;
|
||||
lblAppID.Caption := strPtrOptAppID;
|
||||
lblAppIDHint.Caption := strPtrOptAppIDHint;
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.ReadSettings(AOptions: TAbstractIDEOptions);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
|
||||
with TiPhoneProjectOptions(AOptions) do
|
||||
begin
|
||||
Load;
|
||||
chkisPhone.Checked:=isIPhoneApp;
|
||||
|
||||
i:=cmbSDKs.Items.IndexOf(SDK);
|
||||
if (i<0) and (cmbSDKs.Items.Count>0) then i:=0;
|
||||
cmbSDKs.ItemIndex:=i;
|
||||
|
||||
edtAppID.Text:=AppID;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.WriteSettings(AOptions: TAbstractIDEOptions);
|
||||
begin
|
||||
with TiPhoneProjectOptions(AOptions) do
|
||||
begin
|
||||
isIPhoneApp:=chkisPhone.Checked;
|
||||
SDK:=cmbSDKs.Caption;
|
||||
AppID:=edtAppID.Text;
|
||||
Save;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TiPhoneProjectOptionsEditor.SupportedOptionsClass: TAbstractIDEOptionsClass;
|
||||
begin
|
||||
Result:=TiPhoneProjectOptions;
|
||||
end;
|
||||
|
||||
const
|
||||
iPhoneOptions = 1;
|
||||
|
||||
initialization
|
||||
{$I project_iphone_options.lrs}
|
||||
RegisterIDEOptionsEditor(iPhonePrjGroup, TiPhoneProjectOptionsEditor, iPhoneOptions);
|
||||
|
||||
end.
|
||||
|
949
components/iphonelazext/xcodeproject.pas
Normal file
949
components/iphonelazext/xcodeproject.pas
Normal file
@ -0,0 +1,949 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit XCodeProject;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
// todo: re-write, using RTTI
|
||||
{$TYPEINFO ON}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
contnrs, Classes, SysUtils, TypInfo;
|
||||
|
||||
const
|
||||
UTF8Mark = '// !$*UTF8*$!';
|
||||
|
||||
FileType_AppWrapper = 'wrapper.application';
|
||||
FileType_Bundle = FileType_AppWrapper;
|
||||
FileType_PList = 'text.plist.xml';
|
||||
// sourceTree = BUILT_PRODUCTS_DIR
|
||||
|
||||
type
|
||||
TXCodeObjectID = string[24];
|
||||
|
||||
TStringValues = class(TStringList);
|
||||
|
||||
{ TXCodeObject }
|
||||
TXCodeObject = class(TObject)
|
||||
private
|
||||
fOwner : TXCodeObject;
|
||||
fChild : TFPList;
|
||||
fValues : TStringList;
|
||||
fID : TXCodeObjectID;
|
||||
protected
|
||||
procedure AddObject(const AName: String; AObject: TXCodeObject);
|
||||
function GetChild(i: Integer): TXCodeObject;
|
||||
function GetCount: Integer;
|
||||
procedure Clear;
|
||||
function GetValue(const AName: String): String;
|
||||
procedure SetValue(const AName: String; const AValue: String);
|
||||
public
|
||||
class function isa: ShortString; virtual; abstract;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
|
||||
property Child[i: integer]: TXCodeObject read GetChild;
|
||||
property ChildCount: Integer read GetCount;
|
||||
property Owner: TXCodeObject read fOwner;
|
||||
property ID: TXCodeObjectID read fID;
|
||||
|
||||
property StrValue[const AName: String]: String read GetValue write SetValue;
|
||||
function GetChildObject(const AName: String): TXCodeObject;
|
||||
function GetObjectArray(const AName: String): TFPObjectList;
|
||||
function GetStringArray(const AName: String): TStringList;
|
||||
function GetStringValues(const AName: String): TStringValues;
|
||||
end;
|
||||
TXCodeObjectClass = class of TXCodeObject;
|
||||
|
||||
{ TPBXFileReference }
|
||||
|
||||
TPBXFileReference = class(TXCodeObject)
|
||||
private
|
||||
function GetExplicitFileType: string;
|
||||
function GetPath: String;
|
||||
function GetSourceTree: String;
|
||||
procedure SetExplicitFileType(const AValue: string);
|
||||
procedure SetPath(const AValue: String);
|
||||
procedure SetSourceTree(const AValue: String);
|
||||
public
|
||||
class function isa: ShortString; override;
|
||||
property explicitFileType: string read GetExplicitFileType write SetExplicitFileType;
|
||||
property path : String read GetPath write SetPath;
|
||||
property sourceTree: String read GetSourceTree write SetSourceTree;
|
||||
end;
|
||||
// 0A7E1DA610EAD478000D7855 /* iPhoneApp.app */ =
|
||||
|
||||
{isa = PBXFileReference;
|
||||
explicitFileType = wrapper.application;
|
||||
includeInIndex = 0;
|
||||
path = iPhoneApp.app;
|
||||
sourceTree = BUILT_PRODUCTS_DIR; }
|
||||
|
||||
{isa = PBXFileReference;
|
||||
lastKnownFileType = text.plist.xml;
|
||||
path = "iPhoneApp-Info.plist"; sourceTree = "<group>"; }
|
||||
|
||||
|
||||
|
||||
TXCodeBuildPhase = class(TXCodeObject);
|
||||
|
||||
{ TPBXShellScriptBuildPhase }
|
||||
|
||||
TPBXShellScriptBuildPhase = class(TXCodeBuildPhase)
|
||||
private
|
||||
function GetBuildMask: Integer;
|
||||
function GetShellPath: string;
|
||||
function GetShellScript: String;
|
||||
procedure SetBuildMask(const AValue: Integer);
|
||||
procedure SetShellPath(const AValue: string);
|
||||
procedure SetShellScript(const AValue: String);
|
||||
public
|
||||
constructor Create;
|
||||
class function isa: ShortString; override;
|
||||
property BuildActionMask : Integer read GetBuildMask write SetBuildMask;
|
||||
property ShellPath : string read GetShellPath write SetShellPath;
|
||||
property ShellScript : String read GetShellScript write SetShellScript;
|
||||
end;
|
||||
|
||||
{ TPBXBuildFile }
|
||||
|
||||
TPBXBuildFile = class(TXCodeObject)
|
||||
public
|
||||
fileRef : TPBXFileReference;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
class function isa: ShortString; override;
|
||||
end;
|
||||
|
||||
{ TXCBuildConfiguration }
|
||||
|
||||
TXCBuildConfiguration = class(TXCodeObject)
|
||||
private
|
||||
function GetName: String;
|
||||
procedure SetName(const AValue: String);
|
||||
function GetBuildSettings: TStringValues;
|
||||
public
|
||||
class function isa: ShortString; override;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
property name: String read GetName write SetName;
|
||||
property Settings: TStringValues read GetBuildSettings;
|
||||
end;
|
||||
|
||||
{ TXCConfigurationList }
|
||||
|
||||
TXCConfigurationList = class(TXCodeObject)
|
||||
private
|
||||
fConfigs : TFPObjectList;
|
||||
protected
|
||||
function GetConfig(i: integer): TXCBuildConfiguration;
|
||||
function GetCount: Integer;
|
||||
|
||||
function GetName: string;
|
||||
procedure SetName(const AValue: string);
|
||||
function GetVisible: Boolean;
|
||||
procedure SetVisible(AVisible: Boolean);
|
||||
public
|
||||
class function isa: ShortString; override;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function AddList: TXCBuildConfiguration;
|
||||
property Config[i: Integer] : TXCBuildConfiguration read GetConfig;
|
||||
property ConfigCount: Integer read GetCount;
|
||||
property defaultVisible: Boolean read GetVisible write SetVisible;
|
||||
property defaulConfigName: string read GetName write SetName;
|
||||
end;
|
||||
|
||||
|
||||
{ TPBXNativeTarget }
|
||||
|
||||
TPBXNativeTarget = class(TXCodeObject)
|
||||
private
|
||||
fConfigList : TXCConfigurationList;
|
||||
fRef : TPBXFileReference;
|
||||
function GetName: String;
|
||||
function GetProductFile: TPBXFileReference;
|
||||
function GetProductName: String;
|
||||
function GetProductType: String;
|
||||
procedure SetName(const AValue: String);
|
||||
procedure SetProductName(const AValue: String);
|
||||
procedure SetProductType(const AValue: String);
|
||||
|
||||
function GetConfigList: TXCConfigurationList;
|
||||
public
|
||||
constructor Create;
|
||||
class function isa: ShortString; override;
|
||||
function AddBuildConfig: TXCBuildConfiguration;
|
||||
function AddScriptPhase: TPBXShellScriptBuildPhase;
|
||||
property name: String read GetName write SetName;
|
||||
property productName: String read GetProductName write SetProductName;
|
||||
property productType: String read GetProductType write SetProductType;
|
||||
property productFile: TPBXFileReference read GetProductFile;
|
||||
end;
|
||||
|
||||
{ TPBXProject }
|
||||
|
||||
TPBXProject = class(TXCodeObject)
|
||||
private
|
||||
fConfigList : TXCConfigurationList;
|
||||
function GetDirPath: string;
|
||||
function GetRoot: String;
|
||||
procedure SetDirPath(const AValue: string);
|
||||
procedure SetRoot(const AValue: String);
|
||||
protected
|
||||
function GetConfigList: TXCConfigurationList;
|
||||
function GetTargets: TFPObjectList;
|
||||
|
||||
function GetVersion: String;
|
||||
procedure SetVersion(const AVersion: string);
|
||||
public
|
||||
constructor Create;
|
||||
class function isa: ShortString; override;
|
||||
function AddTarget: TPBXNativeTarget;
|
||||
function AddBuildConfig: TXCBuildConfiguration;
|
||||
property DirPath: string read GetDirPath write SetDirPath;
|
||||
property Root: String read GetRoot write SetRoot;
|
||||
property compatibilityVersion: String read GetVersion write SetVersion;
|
||||
end;
|
||||
|
||||
{ TPBXGroup }
|
||||
|
||||
TPBXGroup = class(TXCodeObject)
|
||||
protected
|
||||
function GetPath: String;
|
||||
procedure SetPath(const APath: String);
|
||||
function GetSourceTree: String;
|
||||
procedure SetSourceTree(const ATree: String);
|
||||
public
|
||||
class function isa: ShortString; override;
|
||||
property Path: String read GetPath write SetPath;
|
||||
property sourceTree: String read GetSourceTree write SetSourceTree;
|
||||
end;
|
||||
|
||||
procedure WritePBXProjFile(RootObject: TXCodeObject; Dst: TStream);
|
||||
procedure WritePBXProjFile(RootObject: TXCodeObject; const FileName: String);
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
BoolVal : array[Boolean] of String = ('false', 'true');
|
||||
|
||||
function isQuotedStr(const s: string): Boolean;
|
||||
begin
|
||||
Result:=(length(s)>=2) and (s[1] = '"') and (s[length(s)]='"');
|
||||
end;
|
||||
|
||||
function QuotedStr(const s: string): String;
|
||||
begin
|
||||
if isQuotedStr(s) then Result:=s
|
||||
else Result:='"'+s+'"';
|
||||
end;
|
||||
|
||||
function UnquoteStr(const s: string): String;
|
||||
begin
|
||||
if not isQuotedStr(s) then Result:=s
|
||||
else Result:=Copy(s, 2, length(s)-2);
|
||||
end;
|
||||
|
||||
|
||||
function GetBoolValue(xobj: TXCodeObject; const AName: String): boolean;
|
||||
begin
|
||||
Result:=xobj.StrValue[AName]=BoolVal[True];
|
||||
end;
|
||||
|
||||
procedure SetBoolValue(xobj: TXCodeObject; const AName: String; AValue: Boolean);
|
||||
begin
|
||||
xobj.StrValue[AName]:=BoolVal[AValue];
|
||||
end;
|
||||
|
||||
{ TXCConfigurationList }
|
||||
|
||||
function TXCConfigurationList.GetName: string;
|
||||
begin
|
||||
Result:=StrValue['defaultConfigurationName'];
|
||||
end;
|
||||
|
||||
procedure TXCConfigurationList.SetName(const AValue: string);
|
||||
begin
|
||||
StrValue['defaultConfigurationName']:=AValue;
|
||||
end;
|
||||
|
||||
function TXCConfigurationList.GetVisible: Boolean;
|
||||
begin
|
||||
Result:=GetBoolValue(Self, 'defaultConfigurationIsVisible');
|
||||
end;
|
||||
|
||||
procedure TXCConfigurationList.SetVisible(AVisible: Boolean);
|
||||
begin
|
||||
SetBoolValue(Self, 'defaultConfigurationIsVisible', AVisible);
|
||||
end;
|
||||
|
||||
function TXCConfigurationList.GetConfig(i: integer): TXCBuildConfiguration;
|
||||
begin
|
||||
Result:=TXCBuildConfiguration(fConfigs[i]);
|
||||
end;
|
||||
|
||||
function TXCConfigurationList.GetCount: Integer;
|
||||
begin
|
||||
Result:=fConfigs.Count;
|
||||
end;
|
||||
|
||||
class function TXCConfigurationList.isa: ShortString;
|
||||
begin
|
||||
Result:='XCConfigurationList';
|
||||
end;
|
||||
|
||||
constructor TXCConfigurationList.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
fConfigs:=GetObjectArray('buildConfigurations');
|
||||
end;
|
||||
|
||||
destructor TXCConfigurationList.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TXCConfigurationList.AddList: TXCBuildConfiguration;
|
||||
begin
|
||||
Result:=TXCBuildConfiguration.Create;
|
||||
AddObject('', Result);
|
||||
fConfigs.Add(Result);
|
||||
end;
|
||||
|
||||
{ TXCBuildConfiguration }
|
||||
|
||||
constructor TXCBuildConfiguration.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
GetStringValues('buildSettings');
|
||||
end;
|
||||
|
||||
destructor TXCBuildConfiguration.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TXCBuildConfiguration.GetName: String;
|
||||
begin
|
||||
Result:=GetValue('name');
|
||||
end;
|
||||
|
||||
procedure TXCBuildConfiguration.SetName(const AValue: String);
|
||||
begin
|
||||
SetValue('name', AValue);
|
||||
end;
|
||||
|
||||
function TXCBuildConfiguration.getBuildSettings: TStringValues;
|
||||
begin
|
||||
Result:=GetStringValues('buildSettings');
|
||||
end;
|
||||
|
||||
class function TXCBuildConfiguration.isa: ShortString;
|
||||
begin
|
||||
Result:='XCBuildConfiguration';
|
||||
end;
|
||||
|
||||
{ TPBXGroup }
|
||||
|
||||
function TPBXGroup.GetPath: String;
|
||||
begin
|
||||
Result:=StrValue['Path'];
|
||||
end;
|
||||
|
||||
procedure TPBXGroup.SetPath(const APath: String);
|
||||
begin
|
||||
StrValue['Path']:=APath;
|
||||
end;
|
||||
|
||||
function TPBXGroup.GetSourceTree: String;
|
||||
begin
|
||||
Result:=StrValue['sourceTree'];
|
||||
end;
|
||||
|
||||
procedure TPBXGroup.SetSourceTree(const ATree: String);
|
||||
begin
|
||||
StrValue['sourceTree']:=ATree;
|
||||
end;
|
||||
|
||||
class function TPBXGroup.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXGroup';
|
||||
end;
|
||||
|
||||
{ TPBXFileReference }
|
||||
|
||||
class function TPBXFileReference.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXFileReference';
|
||||
end;
|
||||
|
||||
function TPBXFileReference.GetExplicitFileType: string;
|
||||
begin
|
||||
Result:=GetValue('explicitFileType');
|
||||
end;
|
||||
|
||||
function TPBXFileReference.GetPath: String;
|
||||
begin
|
||||
Result:=GetValue('path');
|
||||
end;
|
||||
|
||||
function TPBXFileReference.GetSourceTree: String;
|
||||
begin
|
||||
Result:=GetValue('sourceTree');
|
||||
end;
|
||||
|
||||
procedure TPBXFileReference.SetExplicitFileType(const AValue: string);
|
||||
begin
|
||||
SetValue('explicitFileType', AValue);
|
||||
end;
|
||||
|
||||
procedure TPBXFileReference.SetPath(const AValue: String);
|
||||
begin
|
||||
SetValue('path', AValue);
|
||||
end;
|
||||
|
||||
procedure TPBXFileReference.SetSourceTree(const AValue: String);
|
||||
begin
|
||||
SetValue('sourceTree', AValue);
|
||||
end;
|
||||
|
||||
{ TPBXBuildFile }
|
||||
|
||||
constructor TPBXBuildFile.Create;
|
||||
begin
|
||||
fileRef:=TPBXFileReference.Create;
|
||||
end;
|
||||
|
||||
destructor TPBXBuildFile.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class function TPBXBuildFile.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXBuildFile';
|
||||
end;
|
||||
|
||||
{ TXCodeObject }
|
||||
|
||||
procedure TXCodeObject.AddObject(const AName: String; AObject: TXCodeObject);
|
||||
begin
|
||||
AObject.fOwner:=Self;
|
||||
fChild.Add(AObject);
|
||||
if AName<>'' then
|
||||
fValues.AddObject(AName, AObject);
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetChild(i: Integer): TXCodeObject;
|
||||
begin
|
||||
Result:=TXCodeObject(fChild[i]);
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetCount: Integer;
|
||||
begin
|
||||
Result:=fChild.Count;
|
||||
end;
|
||||
|
||||
procedure TXCodeObject.Clear;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
for i:=0 to fValues.Count-1 do begin
|
||||
if Assigned(fValues.Objects[i]) and not (fValues.Objects[i] is TXCodeObject) then
|
||||
fValues.Objects[i].Free;
|
||||
end;
|
||||
fValues.Clear;
|
||||
|
||||
for i:=0 to fChild.Count-1 do
|
||||
TObject(fChild[i]).Free;
|
||||
fChild.Clear;
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetValue(const AName: String): String;
|
||||
begin
|
||||
Result:=fValues.Values[AName];
|
||||
end;
|
||||
|
||||
procedure TXCodeObject.SetValue(const AName, AValue: String);
|
||||
begin
|
||||
fValues.Values[AName]:=Avalue;
|
||||
end;
|
||||
|
||||
constructor TXCodeObject.Create;
|
||||
var
|
||||
q : Qword;
|
||||
begin
|
||||
inherited;
|
||||
fChild:=TFPList.Create;
|
||||
fValues:=TStringList.Create;
|
||||
Q:=PtrUInt(Self);
|
||||
fID:=hexStr(q, 24);
|
||||
end;
|
||||
|
||||
destructor TXCodeObject.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
fChild.Free;
|
||||
fValues.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetChildObject(const AName: String): TXCodeObject;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
Result:=nil;
|
||||
i:=fValues.IndexOfName(AName);
|
||||
if i>=0 then
|
||||
if fValues.Objects[i] is TXCodeObject then
|
||||
Result:=TXCodeObject(fValues.Objects[i]);
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetObjectArray(const AName: String): TFPObjectList;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
i:=fValues.IndexOfName(AName);
|
||||
if i<0 then begin
|
||||
Result:=TFPObjectList.Create(false);
|
||||
fValues.AddObject(AName, Result);
|
||||
end else begin
|
||||
if not (fValues.Objects[i] is TFPObjectList) then
|
||||
Result:=nil
|
||||
else
|
||||
Result:= TFPObjectList(fValues.Objects[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetStringArray(const AName: String): TStringList;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
i:=fValues.IndexOfName(AName);
|
||||
if i<0 then begin
|
||||
Result:=TStringList.Create;
|
||||
fValues.AddObject(AName, Result);
|
||||
end else begin
|
||||
if not (fValues.Objects[i] is TStringList) then
|
||||
Result:=nil
|
||||
else
|
||||
Result:= TStringList(fValues.Objects[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TXCodeObject.GetStringValues(const AName: String): TStringValues;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
i:=fValues.IndexOfName(AName);
|
||||
if i<0 then begin
|
||||
Result:=TStringValues.Create;
|
||||
fValues.Values[AName]:='?';
|
||||
i:=fValues.IndexOfName(AName);
|
||||
fValues.Objects[i]:=Result;
|
||||
//i:=fValues.AddObject(AName + ' = ', Result);
|
||||
end else begin
|
||||
if not (fValues.Objects[i] is TStringValues) then
|
||||
Result:=nil
|
||||
else
|
||||
Result:= TStringValues(fValues.Objects[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
type
|
||||
|
||||
{ TPBXWriter }
|
||||
|
||||
TPBXWriter = class(TObject)
|
||||
private
|
||||
fDst : TStream;
|
||||
fPrefix : String;
|
||||
fIndent : String;
|
||||
protected
|
||||
procedure WriteItems(data:TObject;arg:pointer);
|
||||
public
|
||||
constructor Create(Dst: TStream);
|
||||
destructor Destroy; override;
|
||||
procedure Indent;
|
||||
procedure Unindent;
|
||||
procedure WriteLn(const utf8: AnsiString);
|
||||
end;
|
||||
|
||||
{ TPBXWriter }
|
||||
|
||||
procedure TPBXWriter.WriteItems(data: TObject; arg: pointer);
|
||||
var
|
||||
list : TFPList;
|
||||
i : Integer;
|
||||
j : Integer;
|
||||
k : Integer;
|
||||
xobj : TXCodeObject;
|
||||
vobj : TObject;
|
||||
sublist : TFPObjectList;
|
||||
st : TStringList;
|
||||
prefix : String;
|
||||
begin
|
||||
list:=TFPList(data);
|
||||
if not Assigned(list) or (list.Count=0) then Exit;
|
||||
|
||||
for i:=0 to list.Count-1 do begin
|
||||
xobj:=TXCodeObject(list[i]);
|
||||
|
||||
Self.WriteLn( xobj.ID + ' = {');
|
||||
Self.Indent;
|
||||
|
||||
Self.Writeln('isa = ' + xobj.isa+';');
|
||||
|
||||
for j:=0 to xobj.fValues.Count - 1 do begin
|
||||
vobj:=xobj.fValues.Objects[j];
|
||||
if not Assigned(vobj) then begin
|
||||
prefix:=xobj.fValues.Names[j] + ' = ';
|
||||
Writeln(prefix + xobj.fValues.ValueFromIndex[j]+';')
|
||||
end else begin
|
||||
if vobj is TXCodeObject then begin
|
||||
prefix:=xobj.fValues[j] + ' = ';
|
||||
Writeln(prefix + TXCodeObject(vobj).ID+';')
|
||||
end else if vobj is TStringValues then begin
|
||||
st:=TStringValues(vobj);
|
||||
prefix:=xobj.fValues.Names[j]+' = ';
|
||||
Self.Writeln(prefix + ' {');
|
||||
Self.Indent;
|
||||
for k:=0 to st.Count-1 do
|
||||
Self.WritelN(st.Names[k] + ' = ' + st.ValueFromIndex[k] + ';' );
|
||||
Self.Unindent;
|
||||
Self.Writeln('};')
|
||||
end else if vobj is TStringList then begin
|
||||
prefix:=xobj.fValues[j] + ' = ';
|
||||
st:=TStringValues(vobj);
|
||||
Self.Writeln(prefix + ' (');
|
||||
Self.Indent;
|
||||
for k:=0 to st.Count-1 do
|
||||
Self.WritelN(' ' + st[k] + ',' );
|
||||
Self.Unindent;
|
||||
Self.Writeln(');')
|
||||
end else if vobj is TFPObjectList then begin
|
||||
prefix:=xobj.fValues[j] + ' = ';
|
||||
sublist:=TFPObjectList(vobj);
|
||||
Self.Writeln(prefix + '(');
|
||||
Self.Indent;
|
||||
for k:=0 to sublist.Count-1 do
|
||||
Self.WritelN(TXCodeObject(sublist[k]).ID+',');
|
||||
Self.Unindent;
|
||||
Self.Writeln(');')
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
Self.Unindent;
|
||||
Self.WritelN('};');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPBXWriter.Create(Dst: TStream);
|
||||
begin
|
||||
inherited Create;
|
||||
fDst:=Dst;
|
||||
fIndent:=#9;
|
||||
end;
|
||||
|
||||
destructor TPBXWriter.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TPBXWriter.Indent;
|
||||
begin
|
||||
fPrefix:=fPrefix+fIndent;
|
||||
end;
|
||||
|
||||
procedure TPBXWriter.Unindent;
|
||||
begin
|
||||
fPrefix:=Copy(fPrefix,1, length(fPrefix)-length(fIndent));
|
||||
end;
|
||||
|
||||
procedure TPBXWriter.WriteLn(const utf8: AnsiString);
|
||||
const
|
||||
LF : string = #10;
|
||||
begin
|
||||
if utf8='' then Exit;
|
||||
if fPrefix<>'' then fDst.Write(fPrefix[1], length(fPrefix));
|
||||
fDst.Write(utf8[1], length(utf8));
|
||||
fDst.Write(LF[1], length(LF));
|
||||
end;
|
||||
|
||||
procedure WritePBXProjFile(RootObject: TXCodeObject; Dst: TStream);
|
||||
var
|
||||
lists : TFPHashObjectList; // list of TFPList
|
||||
items : TFPList;
|
||||
p : TXCodeObject;
|
||||
stack : TFPList;
|
||||
i : Integer;
|
||||
xobjcount : Integer;
|
||||
wr : TPBXWriter;
|
||||
begin
|
||||
if RootObject=nil then Exit;
|
||||
|
||||
lists:=TFPHashObjectList.Create(True);
|
||||
|
||||
stack:=TFPList.Create;
|
||||
xobjcount:=1;
|
||||
stack.Add(RootObject);
|
||||
while stack.Count > 0 do begin
|
||||
p:= TXCodeObject(stack[0]);
|
||||
items:=TFPList(lists.Find(p.isa));
|
||||
if not Assigned(items) then begin
|
||||
items:=TFPList.Create;
|
||||
lists.Add(p.isa, items);
|
||||
end;
|
||||
items.Add(p);
|
||||
inc(xobjcount, p.ChildCount);
|
||||
for i:=0 to p.ChildCount-1 do stack.Add(p.Child[i]);
|
||||
stack.Delete(0);
|
||||
end;
|
||||
stack.Free;
|
||||
|
||||
wr:=TPBXWriter.Create(Dst);
|
||||
wr.WriteLn(UTF8Mark);
|
||||
wr.WriteLn('{');
|
||||
wr.Indent;
|
||||
wr.WriteLn('archiveVersion = 1;');
|
||||
wr.WriteLn('classes = {};');
|
||||
wr.WriteLn('objectVersion = 45;');
|
||||
wr.WriteLn('objects = { ');
|
||||
wr.Indent;
|
||||
lists.ForEachCall(@wr.WriteItems, nil);
|
||||
wr.Unindent;
|
||||
wr.WriteLn('};');
|
||||
wr.WriteLn('rootObject = '+RootObject.ID+';');
|
||||
wr.Unindent;
|
||||
wr.WriteLn('}');
|
||||
wr.Free;
|
||||
|
||||
lists.Free;
|
||||
end;
|
||||
|
||||
procedure WritePBXProjFile(RootObject: TXCodeObject; const FileName: String);
|
||||
var
|
||||
fs : TFileStream;
|
||||
begin
|
||||
fs:=TFileStream.Create(FileName, fmCreate);
|
||||
WritePBXProjFile(RootOBject, fs);
|
||||
fs.Free;
|
||||
end;
|
||||
|
||||
{ TXCProject }
|
||||
|
||||
function TPBXProject.GetDirPath: string;
|
||||
begin
|
||||
Result:=UnquoteStr(StrValue['projectDirPath']);
|
||||
end;
|
||||
|
||||
function TPBXProject.GetRoot: String;
|
||||
begin
|
||||
Result:=UnquoteStr(StrValue['projectRoot']);
|
||||
end;
|
||||
|
||||
procedure TPBXProject.SetDirPath(const AValue: string);
|
||||
begin
|
||||
StrValue['projectDirPath']:=QuotedStr(AValue);
|
||||
end;
|
||||
|
||||
procedure TPBXProject.SetRoot(const AValue: String);
|
||||
begin
|
||||
StrValue['projectRoot']:=QuotedStr(AValue);
|
||||
end;
|
||||
|
||||
function TPBXProject.GetConfigList: TXCConfigurationList;
|
||||
begin
|
||||
if not Assigned(fConfigList) then begin
|
||||
fConfigList:=TXCConfigurationList.Create;
|
||||
AddObject('buildConfigurationList', fConfigList);
|
||||
end;
|
||||
Result:=fConfigList;
|
||||
end;
|
||||
|
||||
function TPBXProject.GetTargets: TFPObjectList;
|
||||
begin
|
||||
Result:=GetObjectArray('targets');
|
||||
end;
|
||||
|
||||
function TPBXProject.GetVersion: String;
|
||||
begin
|
||||
Result:=GetValue('compatibilityVersion');
|
||||
end;
|
||||
|
||||
procedure TPBXProject.SetVersion(const AVersion: string);
|
||||
begin
|
||||
SetValue('compatibilityVersion', AVersion);
|
||||
end;
|
||||
|
||||
constructor TPBXProject.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Root:='';
|
||||
DirPath:='';
|
||||
end;
|
||||
|
||||
class function TPBXProject.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXProject';
|
||||
end;
|
||||
|
||||
function TPBXProject.AddTarget: TPBXNativeTarget;
|
||||
var
|
||||
list : TFPObjectList;
|
||||
begin
|
||||
// adding a target forces configuration list
|
||||
//if fConfigList=nil then GetConfigList;
|
||||
|
||||
list:=GetObjectArray('targets');
|
||||
Result:=TPBXNativeTarget.Create;
|
||||
AddObject('', Result);
|
||||
list.Add(Result);
|
||||
end;
|
||||
|
||||
function TPBXProject.AddBuildConfig: TXCBuildConfiguration;
|
||||
begin
|
||||
Result:=GetConfigList.AddList;
|
||||
end;
|
||||
|
||||
{ TPBXNativeTarget }
|
||||
|
||||
function TPBXNativeTarget.GetName: String;
|
||||
begin
|
||||
Result:=GetValue('name');
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.GetProductFile: TPBXFileReference;
|
||||
begin
|
||||
if not Assigned(fRef) then begin
|
||||
fRef:=TPBXFileReference.Create;
|
||||
AddObject('productReference', fRef);
|
||||
end;
|
||||
Result:=fRef;
|
||||
end;
|
||||
|
||||
procedure TPBXNativeTarget.SetName(const AValue: String);
|
||||
begin
|
||||
SetValue('name', AValue);
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.GetProductName: String;
|
||||
begin
|
||||
Result:=GetValue('productName');
|
||||
end;
|
||||
|
||||
procedure TPBXNativeTarget.SetProductName(const AValue: String);
|
||||
begin
|
||||
SetValue('productName', AValue);
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.GetProductType: String;
|
||||
begin
|
||||
Result:=GetValue('productType');
|
||||
end;
|
||||
|
||||
procedure TPBXNativeTarget.SetProductType(const AValue: String);
|
||||
begin
|
||||
SetValue('productType', AValue)
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.GetConfigList: TXCConfigurationList;
|
||||
begin
|
||||
if not Assigned(fConfigList) then begin
|
||||
fConfigList:=TXCConfigurationList.Create;
|
||||
AddObject('buildConfigurationList', fConfigList);
|
||||
end;
|
||||
Result:=fConfigList;
|
||||
end;
|
||||
|
||||
constructor TPBXNativeTarget.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
productType := '"com.apple.product-type.application"';
|
||||
GetObjectArray('buildPhases');
|
||||
GetObjectArray('buildRules');
|
||||
GetObjectArray('dependencies');
|
||||
end;
|
||||
|
||||
class function TPBXNativeTarget.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXNativeTarget';
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.AddBuildConfig: TXCBuildConfiguration;
|
||||
begin
|
||||
Result:=GetConfigList.AddList;
|
||||
end;
|
||||
|
||||
function TPBXNativeTarget.AddScriptPhase: TPBXShellScriptBuildPhase;
|
||||
begin
|
||||
Result:=TPBXShellScriptBuildPhase.Create;
|
||||
AddObject('', Result);
|
||||
GetObjectArray('buildPhases').Add(Result);
|
||||
end;
|
||||
|
||||
{ TPBXShellScriptBuildPhase }
|
||||
|
||||
function TPBXShellScriptBuildPhase.GetBuildMask: Integer;
|
||||
begin
|
||||
Result:=StrToIntDef( GetValue('buildActionMask'), 0);
|
||||
end;
|
||||
|
||||
procedure TPBXShellScriptBuildPhase.SetBuildMask(const AValue: Integer);
|
||||
begin
|
||||
SetValue('buildActionMask', IntToStr(AValue));
|
||||
end;
|
||||
|
||||
function TPBXShellScriptBuildPhase.GetShellPath: string;
|
||||
begin
|
||||
Result:=GetValue('shellPath');
|
||||
end;
|
||||
|
||||
procedure TPBXShellScriptBuildPhase.SetShellPath(const AValue: string);
|
||||
begin
|
||||
SetValue('shellPath', AValue);
|
||||
end;
|
||||
|
||||
function TPBXShellScriptBuildPhase.GetShellScript: String;
|
||||
begin
|
||||
Result:=UnquoteStr(GetValue('shellScript'));
|
||||
end;
|
||||
|
||||
procedure TPBXShellScriptBuildPhase.SetShellScript(const AValue: String);
|
||||
begin
|
||||
SetValue('shellScript', QuotedStr(AValue));
|
||||
end;
|
||||
|
||||
constructor TPBXShellScriptBuildPhase.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
ShellPath:='/bin/sh';
|
||||
GetObjectArray('files');
|
||||
GetObjectArray('inputPaths');
|
||||
GetObjectArray('outputPaths');
|
||||
end;
|
||||
|
||||
class function TPBXShellScriptBuildPhase.isa: ShortString;
|
||||
begin
|
||||
Result:='PBXShellScriptBuildPhase';
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
||||
|
287
components/iphonelazext/xcodetemplate.pas
Normal file
287
components/iphonelazext/xcodetemplate.pas
Normal file
@ -0,0 +1,287 @@
|
||||
{
|
||||
*****************************************************************************
|
||||
* *
|
||||
* This file is part of the iPhone Laz Extension *
|
||||
* *
|
||||
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
||||
* for details about the copyright. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* *
|
||||
*****************************************************************************
|
||||
}
|
||||
unit xcodetemplate;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, contnrs;
|
||||
|
||||
procedure PrepareTemplateFile(Src, TemplateValues, BuildSettings: TStrings);
|
||||
|
||||
const
|
||||
XCodeProjectTemplateIconID : AnsiString ='0AE3FFA610F3C9AF00A9B007,';
|
||||
XCodeProjectTemplateIcon : AnsiString =
|
||||
'0AE3FFA610F3C9AF00A9B007 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; };';
|
||||
|
||||
XCodeIconFile : AnsiString = '0A2C67AE10F3CFB800F48811,';
|
||||
XCodeIconFileRef : AnsiString =
|
||||
'0A2C67AE10F3CFB800F48811 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 0AE3FFA610F3C9AF00A9B007 /* Icon.png */; };';
|
||||
|
||||
|
||||
XCodeProjectTemplate : AnsiString =
|
||||
'// !$*UTF8*$!'#10+
|
||||
'{'#10+
|
||||
' archiveVersion = 1;'#10+
|
||||
' classes = {'#10+
|
||||
' };'#10+
|
||||
' objectVersion = 45;'#10+
|
||||
' objects = {'#10+
|
||||
' '#10+
|
||||
' ??iconfileref'#10+
|
||||
' '#10+
|
||||
'/* Begin PBXFileReference section */'#10+
|
||||
' 0A85A8AE10F0D28700AB8400 /* ??bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ??bundle; sourceTree = BUILT_PRODUCTS_DIR; };'#10+
|
||||
' 0A85A8B110F0D28700AB8400 /* ??plist */ = {isa = PBXFileReference; explicitFileType = text.plist.xml; name = ??plist; path = ??plist; sourceTree = SOURCE_ROOT; };'#10+
|
||||
' ??icon'#10+
|
||||
'/* End PBXFileReference section */'#10+
|
||||
''#10+
|
||||
'/* Begin PBXGroup section */'#10+
|
||||
' 0A52AE8110F0D05300478C4F = {'#10+
|
||||
' isa = PBXGroup;'#10+
|
||||
' children = ('#10+
|
||||
' ??iconid'#10+
|
||||
' 0A85A8AF10F0D28700AB8400 /* Products */,'#10+
|
||||
' 0A85A8B110F0D28700AB8400 /* ??plist */,'#10+
|
||||
' );'#10+
|
||||
' sourceTree = "<group>";'#10+
|
||||
' };'#10+
|
||||
' 0A85A8AF10F0D28700AB8400 /* Products */ = {'#10+
|
||||
' isa = PBXGroup;'#10+
|
||||
' children = ('#10+
|
||||
' 0A85A8AE10F0D28700AB8400 /* ??bundle */,'#10+
|
||||
' );'#10+
|
||||
' name = Products;'#10+
|
||||
' sourceTree = "<group>";'#10+
|
||||
' };'#10+
|
||||
'/* End PBXGroup section */'#10+
|
||||
''#10+
|
||||
'/* Begin PBXNativeTarget section */'#10+
|
||||
' 0A85A8AD10F0D28700AB8400 = {'#10+
|
||||
' isa = PBXNativeTarget;'#10+
|
||||
' buildConfigurationList = 0A85A8B410F0D28800AB8400 /* Build configuration list for PBXNativeTarget */;'#10+
|
||||
' buildPhases = ('#10+
|
||||
' 0A85A8B810F0D2D400AB8400 /* ShellScript */,'#10+
|
||||
' 0A2C67A610F3CEFA00F48811 /* Resources */,'#10+
|
||||
' );'#10+
|
||||
' buildRules = ('#10+
|
||||
' );'#10+
|
||||
' dependencies = ('#10+
|
||||
' );'#10+
|
||||
' name = ??targetname;'#10+
|
||||
' productName = ??productname;'#10+
|
||||
' productReference = 0A85A8AE10F0D28700AB8400 /* ??bundle */;'#10+
|
||||
' productType = "com.apple.product-type.application";'#10+
|
||||
' };'#10+
|
||||
'/* End PBXNativeTarget section */'#10+
|
||||
''#10+
|
||||
'/* Begin PBXProject section */'#10+
|
||||
' 0A52AE8310F0D05300478C4F /* Project object */ = {'#10+
|
||||
' isa = PBXProject;'#10+
|
||||
' buildConfigurationList = 0A52AE8610F0D05300478C4F /* Build configuration list for PBXProject "project1" */;'#10+
|
||||
' compatibilityVersion = "Xcode 3.1";'#10+
|
||||
' hasScannedForEncodings = 0;'#10+
|
||||
' mainGroup = 0A52AE8110F0D05300478C4F;'#10+
|
||||
' productRefGroup = 0A85A8AF10F0D28700AB8400 /* Products */;'#10+
|
||||
' projectDirPath = "";'#10+
|
||||
' projectRoot = "";'#10+
|
||||
' targets = ('#10+
|
||||
' 0A85A8AD10F0D28700AB8400,'#10+
|
||||
' );'#10+
|
||||
' };'#10+
|
||||
'/* End PBXProject section */'#10+
|
||||
''#10+
|
||||
'/* Begin PBXResourcesBuildPhase section */'#10+
|
||||
' 0A2C67A610F3CEFA00F48811 /* Resources */ = {'#10+
|
||||
' isa = PBXResourcesBuildPhase;'#10+
|
||||
' buildActionMask = 2147483647;'#10+
|
||||
' files = ('#10+
|
||||
' ??iconfile'#10+
|
||||
' );'#10+
|
||||
' runOnlyForDeploymentPostprocessing = 0;'#10+
|
||||
' };'#10+
|
||||
'/* End PBXResourcesBuildPhase section */'#10+
|
||||
''#10+
|
||||
'/* Begin PBXShellScriptBuildPhase section */'#10+
|
||||
' 0A85A8B810F0D2D400AB8400 /* ShellScript */ = {'#10+
|
||||
' isa = PBXShellScriptBuildPhase;'#10+
|
||||
' buildActionMask = 2147483647;'#10+
|
||||
' files = ('#10+
|
||||
' );'#10+
|
||||
' inputPaths = ('#10+
|
||||
' );'#10+
|
||||
' outputPaths = ('#10+
|
||||
' );'#10+
|
||||
' runOnlyForDeploymentPostprocessing = 0;'#10+
|
||||
' shellPath = /bin/sh;'#10+
|
||||
' shellScript = "if [ x\"$ACTION\" != \"xbuild\" ]; then\n # in case running scripts during cleaning gets fixed\n exit 0\nfi\n\necho $FPC_COMPILER_PATH $FPC_COMPILER_OPTIONS $FPC_MAIN_FILE\n\n$FPC_COMPILER_PATH $FPC_COMPILER_OPTIONS $FPC_MAIN_FILE";'#10+
|
||||
' };'#10+
|
||||
'/* End PBXShellScriptBuildPhase section */'#10+
|
||||
''#10+
|
||||
'/* Begin XCBuildConfiguration section */'#10+
|
||||
' 0A52AE8510F0D05300478C4F /* Release */ = {'#10+
|
||||
' isa = XCBuildConfiguration;'#10+
|
||||
' buildSettings = {'#10+
|
||||
' ARCHS = "$(ARCHS_STANDARD_32_BIT)";'#10+
|
||||
' COPY_PHASE_STRIP = YES;'#10+
|
||||
' FPC_OUTPUT_FILE = $BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH;'#10+
|
||||
' FPC_COMPILER_OPTIONS = "-Parm -o$FPC_OUTPUT_FILE $FPC_CUSTOM_OPTIONS";'#10+
|
||||
' FPC_COMPILER_PATH = ;'#10+
|
||||
' FPC_CUSTOM_OPTIONS = ;'#10+
|
||||
' FPC_MAIN_FILE = ;'#10+
|
||||
' SDKROOT = iphoneos2.0;'#10+
|
||||
' VALID_ARCHS = "armv6 armv7";'#10+
|
||||
' };'#10+
|
||||
' name = Release;'#10+
|
||||
' };'#10+
|
||||
' 0A85A8B310F0D28800AB8400 /* Release */ = {'#10+
|
||||
' isa = XCBuildConfiguration;'#10+
|
||||
' buildSettings = {'#10+
|
||||
' ALWAYS_SEARCH_USER_PATHS = YES;'#10+
|
||||
' COPY_PHASE_STRIP = YES;'#10+
|
||||
' DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";'#10+
|
||||
' GCC_ENABLE_FIX_AND_CONTINUE = NO;'#10+
|
||||
' GCC_PRECOMPILE_PREFIX_HEADER = YES;'#10+
|
||||
' GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/UIKit.framework/Headers/UIKit.h";'#10+
|
||||
' INFOPLIST_FILE = ??plist;'#10+
|
||||
' INSTALL_PATH = "$(HOME)/Applications";'#10+
|
||||
' OTHER_LDFLAGS = ('#10+
|
||||
' "-framework",'#10+
|
||||
' Foundation,'#10+
|
||||
' "-framework",'#10+
|
||||
' UIKit,'#10+
|
||||
' );'#10+
|
||||
' PREBINDING = NO;'#10+
|
||||
' PRODUCT_NAME = ??productname;'#10+
|
||||
' SDKROOT = iphoneos2.0;'#10+
|
||||
' ZERO_LINK = NO;'#10+
|
||||
' };'#10+
|
||||
' name = Release;'#10+
|
||||
' };'#10+
|
||||
'/* End XCBuildConfiguration section */'#10+
|
||||
' '#10+
|
||||
'/* Begin XCConfigurationList section */'#10+
|
||||
' 0A52AE8610F0D05300478C4F /* Build configuration list for PBXProject "project1" */ = {'#10+
|
||||
' isa = XCConfigurationList;'#10+
|
||||
' buildConfigurations = ('#10+
|
||||
' 0A52AE8510F0D05300478C4F /* Release */,'#10+
|
||||
' );'#10+
|
||||
' defaultConfigurationIsVisible = 0;'#10+
|
||||
' defaultConfigurationName = Release;'#10+
|
||||
' };'#10+
|
||||
' 0A85A8B410F0D28800AB8400 /* Build configuration list for PBXNativeTarget */ = {'#10+
|
||||
' isa = XCConfigurationList;'#10+
|
||||
' buildConfigurations = ('#10+
|
||||
' 0A85A8B310F0D28800AB8400 /* Release */,'#10+
|
||||
' );'#10+
|
||||
' defaultConfigurationIsVisible = 0;'#10+
|
||||
' defaultConfigurationName = Release;'#10+
|
||||
' };'#10+
|
||||
'/* End XCConfigurationList section */'#10+
|
||||
' };'#10+
|
||||
' rootObject = 0A52AE8310F0D05300478C4F /* Project object */;'#10+
|
||||
'}'#10;
|
||||
|
||||
implementation
|
||||
|
||||
function GetValueName(const Source: String; idx: Integer): String;
|
||||
var
|
||||
i : integer;
|
||||
const
|
||||
//todo: expand symbols charset
|
||||
Symbols: set of char = [#9, #32, #10,#13,
|
||||
'=',':',';','-','+','*','/','\','!','@','#',
|
||||
'$','%','^','&','(',')','~','`','''','"' ];
|
||||
begin
|
||||
for i:=idx to length(Source) do
|
||||
if Source[i] in Symbols then begin
|
||||
Result:=Copy(Source, idx, i-idx);
|
||||
Exit;
|
||||
end;
|
||||
Result:=Copy(Source, idx, length(Source)-idx+1);
|
||||
end;
|
||||
|
||||
function ChangeValues(const Prefix, Source: String; Values: TStrings): String;
|
||||
var
|
||||
i : integer;
|
||||
nm : string;
|
||||
v : string;
|
||||
begin
|
||||
Result:=Source;
|
||||
i:=Pos(Prefix, Result);
|
||||
while i>0 do begin
|
||||
nm:=GetValueName(Result, i+length(Prefix));
|
||||
Delete(Result, i, length(Prefix)+length(nm));
|
||||
v:=Values.Values[nm];
|
||||
|
||||
if Pos(Prefix, v) <= 0 then // don't allow circular prefix used, to avoid infinite loops
|
||||
Insert(v, Result, i);
|
||||
i:=Pos(Prefix, Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure PrepareTemplateFile(Src, TemplateValues, BuildSettings: TStrings);
|
||||
//todo: Better code to update XCode project file!
|
||||
var
|
||||
i, j : Integer;
|
||||
nm, s, v : String;
|
||||
isSettings : Boolean;
|
||||
buildhash : TFPStringHashTable;
|
||||
|
||||
begin
|
||||
if not Assigned(Src) then Exit;
|
||||
|
||||
if Assigned(TemplateValues) then
|
||||
for i:=0 to Src.Count-1 do
|
||||
Src[i]:=ChangeValues('??', Src[i], TemplateValues);
|
||||
|
||||
isSettings:=false;
|
||||
|
||||
if Assigned(BuildSettings) and (BuildSettings.Count>0) then begin
|
||||
buildhash := TFPStringHashTable.Create;
|
||||
|
||||
for i :=0 to BuildSettings.Count-1 do
|
||||
buildhash.Add(BuildSettings.Names[i], BuildSettings.ValueFromIndex[i]);
|
||||
|
||||
for i:=0 to Src.Count-1 do begin
|
||||
if not isSettings then
|
||||
isSettings:=Pos('buildSettings', Src[i])>0
|
||||
else begin
|
||||
if Trim(Src[i])='};' then
|
||||
isSettings:=false
|
||||
else begin
|
||||
j:=1;
|
||||
s:=Src[i];
|
||||
while (j<=length(s)) and (s[j] in [#9, #32]) do
|
||||
inc(j);
|
||||
|
||||
nm:=GetValueName(s, j);
|
||||
|
||||
if Assigned(buildhash.Find(nm)) then begin
|
||||
v:=buildhash.Items[nm];
|
||||
Src[i]:=Copy(Src[i], 1, j-1)+nm+ ' = ' + v + ';';
|
||||
end;
|
||||
end;
|
||||
end; {of else}
|
||||
end;
|
||||
buildhash.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
Loading…
x
Reference in New Issue
Block a user