iphonelazext: implemented creating/deleting xib files from inside of project options

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1214 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2010-05-02 22:57:55 +00:00
parent 7a69f33b79
commit 058d550ef9
11 changed files with 652 additions and 164 deletions

View File

@ -50,7 +50,7 @@ type
public public
//isiPhoneMenu :TIDEMenuCommand; //isiPhoneMenu :TIDEMenuCommand;
constructor Create; constructor Create;
procedure UpdateXCode(Sender: TObject); procedure UpdateXcode(Sender: TObject);
procedure SimRun(Sender: TObject); procedure SimRun(Sender: TObject);
//procedure isProjectClicked(Sender: TObject); //procedure isProjectClicked(Sender: TObject);
end; end;
@ -339,7 +339,7 @@ begin
//isiPhoneMenu.Checked:=ProjOptions.isIPhoneApp; //isiPhoneMenu.Checked:=ProjOptions.isIPhoneApp;
end; end;
procedure TiPhoneExtension.UpdateXCode(Sender: TObject); procedure TiPhoneExtension.UpdateXcode(Sender: TObject);
var var
templates : TStringList; templates : TStringList;
build : TStringList; build : TStringList;

View File

@ -20,7 +20,8 @@ unit iPhoneExtOptions;
interface interface
uses uses
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, iPhoneBundle, DOM, XMLRead, XMLConf, PlistFile; Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf,
iPhoneBundle, DOM, XMLRead, XMLConf, XcodeUtils;
const const
DefaultResourceDir = 'Resources'; DefaultResourceDir = 'Resources';
@ -112,12 +113,6 @@ function EnvOptions: TiPhoneEnvironmentOptions;
function ProjOptions: TiPhoneProjectOptions; function ProjOptions: TiPhoneProjectOptions;
type
TSDKFoundEvent = procedure (const Version: String;
const DeviceSDKName, DeviceSDKPath, SimSDKName, SimSDKPath: String) of object;
function ScanForSDK(const PlatformDir: String; FoundProc: TSDKFoundEvent): Boolean;
var var
iPhoneEnvGroup : Integer; iPhoneEnvGroup : Integer;
iPhonePrjGroup : Integer; iPhonePrjGroup : Integer;
@ -409,101 +404,6 @@ begin
end; end;
end; end;
type
TSDKDescription = record
FullPath : String; {full SDK path}
Name : String;
Alternate : String; {alternate SDK -> iphonesimulator for iphoneos}
Version : String;
isSim : Boolean; {true for real iPhoneOS, false for iPhoneSimulator}
end;
// todo: implement reading .plist via OSX functions! (in case a .plist format changes)
function ReadSDKSettings(const FileName: String; var Descr: TSDKDescription): Boolean;
var
plist : TPListFile;
begin
Result:=False;
plist:=TPListFile.Create(FileName);
Descr.Name:=plist.GetStrValue('CanonicalName');
Descr.Alternate:=plist.GetStrValue('AlternateSDK');
Descr.Version:=plist.GetStrValue('Version');
plist.Free;
end;
function isSDKDir(const SDKDir: String; var d: TSDKDescription): Boolean;
var
plist : String;
begin
plist := IncludeTrailingPathDelimiter(SDKDir)+'SDKSettings.plist';
Result:=FileExists(plist);
if not Result then Exit;
ReadSDKSettings(plist, d);
d.FullPath:=SDKDir;
end;
function ScanForSDK(const PlatformDir: String; FoundProc: TSDKFoundEvent): Boolean;
const
PlatformName: array [Boolean] of String = ('iPhoneOS.platform','iPhoneSimulator.platform');
SDKSubDir = PathDelim+'Developer'+PathDelim+'SDKs'+PathDelim;
var
isSim : Boolean;
dir : String;
sr : TSearchRec;
sdks : array of TSDKDescription;
descr : TSDKDescription;
cnt : Integer;
simname : String;
simpath : String;
i,j : Integer;
procedure AddDescription(const d: TSDKDescription);
begin
if cnt = length(sdks) then begin
if cnt = 0 then SetLength(sdks, 16)
else SetLength(sdks, cnt*2);
end;
sdks[cnt]:=d;
inc(cnt);
end;
begin
Result:=Assigned(FoundProc);
if not Result then Exit;
cnt:=0;
for isSim:=false to true do begin
dir := IncludeTrailingPathDelimiter(PlatformDir) + PlatformName[isSim] + SDKSubDir;
if FindFirst(dir+'*', faAnyFile, sr)=0 then begin
repeat
if (sr.Attr and faDirectory>0) and (ExtractFileExt(sr.Name) = '.sdk') then
if isSDKDir( dir + sr.Name, descr) then begin
descr.isSim:=isSim;
AddDescription(descr);
end;
until FindNext(sr)<>0;
FindClose(sr);
end;
end;
for i:=0 to cnt-1 do
if not sdks[i].isSim then begin
simname:='';
simpath:='';
for j:=0 to cnt-1 do
if (sdks[j].isSim) and (sdks[i].Alternate=sdks[j].Name) then begin
simname:=sdks[j].Name;
simpath:=sdks[j].FullPath;
end;
FoundProc(sdks[i].Version, sdks[i].Name, sdks[i].FullPath, simname, simpath);
end;
Result:=True;
end;
initialization initialization
InitOptions; InitOptions;

View File

@ -18,7 +18,7 @@
<Description Value="iPhone Development Lazarus extension"/> <Description Value="iPhone Development Lazarus extension"/>
<License Value="LGPL"/> <License Value="LGPL"/>
<Version Minor="6"/> <Version Minor="6"/>
<Files Count="11"> <Files Count="13">
<Item1> <Item1>
<Filename Value="ideext.pas"/> <Filename Value="ideext.pas"/>
<HasRegisterProc Value="True"/> <HasRegisterProc Value="True"/>
@ -64,6 +64,14 @@
<Filename Value="lazfilesutils.pas"/> <Filename Value="lazfilesutils.pas"/>
<UnitName Value="lazfilesutils"/> <UnitName Value="lazfilesutils"/>
</Item11> </Item11>
<Item12>
<Filename Value="xcodeutils.pas"/>
<UnitName Value="xcodeutils"/>
</Item12>
<Item13>
<Filename Value="newxibdialog.pas"/>
<UnitName Value="newxibdialog"/>
</Item13>
</Files> </Files>
<Type Value="RunAndDesignTime"/> <Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="3"> <RequiredPkgs Count="3">

View File

@ -1,23 +1,23 @@
{ This file was automatically created by Lazarus. do not edit! { This file was automatically created by Lazarus. Do not edit!
This source is only used to compile and install the package. This source is only used to compile and install the package.
} }
unit iphonelazext; unit iphonelazext;
interface interface
uses uses
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject, ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
environment_iphone_options, project_iphone_options, iPhoneExtOptions, environment_iphone_options, project_iphone_options, iPhoneExtOptions,
xcodetemplate, lazfilesutils, LazarusPackageIntf; xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, LazarusPackageIntf;
implementation implementation
procedure Register; procedure Register;
begin begin
RegisterUnit('ideext', @ideext.Register); RegisterUnit('ideext',@ideext.Register);
end; end;
initialization initialization
RegisterPackage('iphonelazext', @Register); RegisterPackage('iphonelazext',@Register);
end. end.

View File

@ -12,7 +12,7 @@
* * * *
***************************************************************************** *****************************************************************************
} }
unit lazfilesutils; unit LazFilesUtils;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
@ -21,8 +21,7 @@ interface
uses uses
{$ifdef Unix}BaseUnix,{$endif} {$ifdef Unix}BaseUnix,{$endif}
Classes, SysUtils, FileUtil, Masks, Classes, SysUtils, FileUtil, Masks,
LazIDEIntf,ProjectIntf; LazIDEIntf, ProjectIntf, process;
function ResolveProjectPath(const path: string; project: TLazProject = nil): string; function ResolveProjectPath(const path: string; project: TLazProject = nil): string;
@ -33,6 +32,10 @@ function NeedQuotes(const path: string): Boolean;
function CopySymLinks(const SrcDir, DstDir, FilterMask: string): Boolean; function CopySymLinks(const SrcDir, DstDir, FilterMask: string): Boolean;
procedure EnumFilesAtDir(const PathUtf8 : AnsiString; Dst: TStrings);
procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings);
procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString);
implementation implementation
{$ifdef Unix} {$ifdef Unix}
@ -177,5 +180,47 @@ begin
end; end;
end; end;
procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings);
var
mask : TMask;
sr : TSearchRec;
path : AnsiString;
begin
if (AMask='') or (trim(AMask)='*') then mask:=nil else mask:=TMask.Create(AMask);
try
path:=IncludeTrailingPathDelimiter(PathUtf8);
if FindFirstUTF8(path+AllFilesMask, faAnyFile, sr) = 0 then begin
repeat
if (sr.Name<>'.') and (sr.Name<>'..') then
if not Assigned(mask) or mask.Matches(sr.Name) then
Dst.Add(path+sr.Name);
until FindNextUTF8(sr)<>0;
FindCloseUTF8(sr);
end;
finally
mask.Free;
end;
end;
procedure EnumFilesAtDir(const PathUtf8 : AnsiString; Dst: TStrings);
begin
EnumFilesAtDir(PathUTF8, AllFilesMask, Dst);
end;
procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString);
var
proc : TProcess;
begin
proc:=TProcess.Create(nil);
try
proc.CommandLine:=CmdLineUtf8;
//proc.WaitOnExit:=WaitExit;
proc.Execute;
finally
proc.Free;
end;
end;
end. end.

View File

@ -0,0 +1,81 @@
object newXibForm: TnewXibForm
Left = 583
Height = 447
Top = 195
Width = 477
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'Choose a template'
ClientHeight = 447
ClientWidth = 477
OnCreate = FormCreate
OnDestroy = FormDestroy
LCLVersion = '0.9.29'
object Edit1: TEdit
Left = 94
Height = 22
Top = 24
Width = 370
OnKeyPress = Edit1KeyPress
TabOrder = 0
Text = 'Edit1'
end
object Label1: TLabel
Left = 16
Height = 18
Top = 24
Width = 61
Caption = 'FileName:'
ParentColor = False
end
object DrawGrid1: TDrawGrid
Left = 16
Height = 200
Top = 64
Width = 448
ColCount = 1
DefaultColWidth = 80
DefaultDrawing = False
DefaultRowHeight = 96
ExtendedSelect = False
FixedCols = 0
FixedRows = 0
GridLineWidth = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goSmoothScroll]
ScrollBars = ssVertical
TabOrder = 1
OnDrawCell = DrawGrid1DrawCell
OnSelection = DrawGrid1Selection
OnSelectCell = DrawGrid1SelectCell
end
object Button1: TButton
Left = 160
Height = 20
Top = 400
Width = 70
AutoSize = True
Caption = 'Cancel'
ModalResult = 2
TabOrder = 2
end
object Button2: TButton
Left = 248
Height = 20
Top = 400
Width = 71
AutoSize = True
Caption = 'Choose'
ModalResult = 1
OnClick = Button2Click
TabOrder = 3
end
object Memo1: TMemo
Left = 16
Height = 112
Top = 272
Width = 448
ReadOnly = True
ScrollBars = ssAutoVertical
TabOrder = 4
end
end

View File

@ -0,0 +1,228 @@
unit newXibDialog;
{$mode objfpc}{$H+}
interface
uses
MacOSAll,
Types,Classes,SysUtils,FileUtil,LResources,Forms,Controls,Graphics,Dialogs,StdCtrls,LCLProc,
Grids,
//todo: use LCL file loading and drawing, instead of OSX
CarbonGDIObjects, CarbonProc;
type
{ TnewXibForm }
TnewXibForm = class(TForm)
Button1:TButton;
Button2:TButton;
DrawGrid1:TDrawGrid;
Edit1:TEdit;
Label1:TLabel;
Memo1:TMemo;
procedure Button2Click(Sender:TObject);
procedure DrawGrid1DrawCell(Sender:TObject;aCol,aRow:Integer;aRect:TRect;
aState:TGridDrawState);
procedure DrawGrid1SelectCell(Sender:TObject;aCol,aRow:Integer;var CanSelect
:Boolean);
procedure DrawGrid1Selection(Sender:TObject;aCol,aRow:Integer);
procedure Edit1KeyPress(Sender:TObject;var Key:char);
procedure FormCreate(Sender:TObject);
procedure FormDestroy(Sender:TObject);
private
{ private declarations }
SelectedXib : String;
Items : TList;
CustomName : Boolean;
public
{ public declarations }
procedure AddTemplate(const AName, SourceXibFile, ADescr, IconFile: AnsiString);
function Execute(var FileName, SourceXibFile: AnsiString): Boolean;
end;
var
newXibForm: TnewXibForm;
implementation
{$R *.lfm}
type
{ TXibItem }
TXibItem = class(TObject)
image : TBitmap;
sourcefile : AnsiString;
descr : AnsiString;
name : AnsiString;
constructor Create(const AName, ASourceFile, ADescr, IconFileName: AnsiString);
destructor Destroy; override;
end;
{ TXibItem }
constructor TXibItem.Create(const AName,ASourceFile,ADescr, IconFileName:AnsiString);
var
url : CFURLRef;
data : CGImageSourceRef;
cf : CFStringRef;
img : CGImageRef;
ctx : CGContextRef;
space : CGColorSpaceRef;
r : CGRect;
w : WideString;
begin
inherited Create;
w:=UTF8Decode(AName);
if w<>'' then w[1]:=WideUpperCase(w[1])[1];
name:=UTF8Encode(w);
sourcefile:=ASourceFile;
descr:=ADescr;
if IconFileName<>'' then begin
CreateCFString(IconFileName, cf);
url:=CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault , cf,
kCFURLPOSIXPathStyle, false, nil);
data:=CGImageSourceCreateWithURL(url, nil);
img:=CGImageSourceCreateImageAtIndex(data, 0, nil);
image:=TBitmap.Create;
image.PixelFormat:=pf32bit;
image.SetSize( 64, 64);
image.BeginUpdate;
space:=CGColorSpaceCreateDeviceRGB;
ctx:=CGBitmapContextCreate(image.RawImage.Data, image.Width, image.Height, 8,
image.Width*4, space, kCGImageAlphaPremultipliedFirst);
r.origin.x:=0; r.origin.y:=0;
r.size.width:=image.Width; r.size.height:=image.Height;
CGColorSpaceRelease(space);
CGContextDrawImage(ctx, r, img);
CGContextRelease(ctx);
image.EndUpdate;
CFRelease(img);
CFRelease(data);
CFRelease(url);
end;
end;
destructor TXibItem.Destroy;
begin
image.Free;
inherited Destroy;
end;
{ TnewXibForm }
procedure TnewXibForm.FormCreate(Sender:TObject);
begin
Items:=TList.Create;
end;
procedure TnewXibForm.DrawGrid1DrawCell(Sender:TObject;aCol,aRow:Integer;aRect:
TRect;aState:TGridDrawState);
var
info : TXibItem;
sz : TSize;
x,y : Integer;
idx : integer;
begin
idx:=DrawGrid1.ColCount*aRow+aCol;
if (idx>=0) and (idx<Items.Count) then
info:=TXibItem(Items[idx])
else
info:=nil;
if not Assigned(info) then Exit;
if gdSelected in aState then begin
DrawGrid1.Canvas.Brush.Color:=clHighlight;
DrawGrid1.Canvas.Font.Color:=clHighlightText;
end else begin
DrawGrid1.Canvas.Brush.Color:=clWindow;
DrawGrid1.Canvas.Font.Color:=clWindowText;
end;
DrawGrid1.Canvas.FillRect(aRect);
if Assigned(info.image) then
DrawGrid1.Canvas.Draw(aRect.Left+4, aRect.Top, info.image);
sz:=DrawGrid1.Canvas.TextExtent(info.name);
x:=aRect.Left+ ((aRect.Right-aRect.Left) - sz.cx) div 2;
y:=aRect.Top + info.image.Height+4;
DrawGrid1.Canvas.TextOut(x, y, info.name);
end;
procedure TnewXibForm.Button2Click(Sender:TObject);
begin
end;
procedure TnewXibForm.DrawGrid1SelectCell(Sender:TObject;aCol,aRow:Integer;var
CanSelect:Boolean);
var
idx : integer;
begin
idx:=DrawGrid1.ColCount*aRow+aCol;
CanSelect:=(idx>=0) and (idx<Items.Count);
if CanSelect then begin
Memo1.Text:=TXibItem(Items[idx]).descr;
if not CustomName then
Edit1.Text:=TXibItem(Items[idx]).name;
SelectedXib:=TXibItem(Items[idx]).sourcefile;
end else begin
Memo1.Text:='';
SelectedXib:='';
end;
Button2.Enabled:=CanSelect;
end;
procedure TnewXibForm.DrawGrid1Selection(Sender:TObject;aCol,aRow:Integer);
begin
end;
procedure TnewXibForm.Edit1KeyPress(Sender:TObject;var Key:char);
begin
CustomName:=True;
end;
procedure TnewXibForm.FormDestroy(Sender:TObject);
var
i : Integer;
begin
for i:=0 to Items.Count-1 do TObject(Items[i]).Free;
end;
procedure TnewXibForm.AddTemplate(const AName,SourceXibFile,ADescr, IconFile:AnsiString);
begin
Items.Add( TXibItem.Create(AName, SourceXibFile, ADescr, IconFile));
end;
function TnewXibForm.Execute(var FileName,SourceXibFile:AnsiString):Boolean;
var
w : integer;
begin
if Items.Count=0 then begin
Result:=False;
Exit;
end;
w:=DrawGrid1.ClientWidth div DrawGrid1.DefaultColWidth;
if w=0 then w:=1;
DrawGrid1.ColCount:=w;
DrawGrid1.RowCount:=Items.Count div w;
CustomName:=False;
Result:=ShowModal = mrOK;
if Result then begin
FileName:=Edit1.Text;
SourceXibFile:=SelectedXib;
end;
end;
end.

View File

@ -4,8 +4,8 @@ inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
ClientHeight = 474 ClientHeight = 474
ClientWidth = 620 ClientWidth = 620
OnClick = FrameClick OnClick = FrameClick
DesignLeft = 611 DesignLeft = 463
DesignTop = 128 DesignTop = 306
object chkisPhone: TCheckBox[0] object chkisPhone: TCheckBox[0]
Left = 16 Left = 16
Height = 18 Height = 18
@ -154,7 +154,31 @@ inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
OnClick = btnShowInFinderClick OnClick = btnShowInFinderClick
TabOrder = 6 TabOrder = 6
end end
object nibsPopup: TPopupMenu[15] object btnAddXib: TButton[15]
AnchorSideLeft.Control = btnRemoveXib
AnchorSideRight.Control = btnRemoveXib
AnchorSideRight.Side = asrBottom
Left = 40
Height = 20
Top = 283
Width = 74
Anchors = [akTop, akLeft, akRight]
AutoSize = True
Caption = 'Add'
OnClick = btnAddXibClick
TabOrder = 7
end
object btnRemoveXib: TButton[16]
Left = 40
Height = 20
Top = 312
Width = 74
AutoSize = True
Caption = 'Remove'
OnClick = btnRemoveXibClick
TabOrder = 8
end
object nibsPopup: TPopupMenu[17]
OnPopup = nibsPopupPopup OnPopup = nibsPopupPopup
left = 256 left = 256
top = 288 top = 288

View File

@ -3,7 +3,7 @@
LazarusResources.Add('TiPhoneProjectOptionsEditor','FORMDATA',[ LazarusResources.Add('TiPhoneProjectOptionsEditor','FORMDATA',[
'TPF0'#241#27'TiPhoneProjectOptionsEditor'#26'iPhoneProjectOptionsEditor'#6'H' 'TPF0'#241#27'TiPhoneProjectOptionsEditor'#26'iPhoneProjectOptionsEditor'#6'H'
+'eight'#3#218#1#5'Width'#3'l'#2#12'ClientHeight'#3#218#1#11'ClientWidth'#3'l' +'eight'#3#218#1#5'Width'#3'l'#2#12'ClientHeight'#3#218#1#11'ClientWidth'#3'l'
+#2#7'OnClick'#7#10'FrameClick'#10'DesignLeft'#3'c'#2#9'DesignTop'#3#128#0#0 +#2#7'OnClick'#7#10'FrameClick'#10'DesignLeft'#3#207#1#9'DesignTop'#3'2'#1#0
+#242#2#0#9'TCheckBox'#10'chkisPhone'#4'Left'#2#16#6'Height'#2#18#3'Top'#2#16 +#242#2#0#9'TCheckBox'#10'chkisPhone'#4'Left'#2#16#6'Height'#2#18#3'Top'#2#16
+#5'Width'#3#199#0#7'Caption'#6#29'is iPhone application project'#8'OnChange' +#5'Width'#3#199#0#7'Caption'#6#29'is iPhone application project'#8'OnChange'
+#7#16'chkisPhoneChange'#8'TabOrder'#2#0#0#0#242#2#1#6'TLabel'#8'lblAppID'#4 +#7#16'chkisPhoneChange'#8'TabOrder'#2#0#0#0#242#2#1#6'TLabel'#8'lblAppID'#4
@ -46,8 +46,15 @@ LazarusResources.Add('TiPhoneProjectOptionsEditor','FORMDATA',[
+'t'#2#246#11'ParentColor'#8#10'ParentFont'#8#0#0#242#2#14#7'TButton'#15'btnS' +'t'#2#246#11'ParentColor'#8#10'ParentFont'#8#0#0#242#2#14#7'TButton'#15'btnS'
+'howInFinder'#4'Left'#3#229#1#6'Height'#2#20#3'Top'#3#176#0#5'Width'#2'u'#7 +'howInFinder'#4'Left'#3#229#1#6'Height'#2#20#3'Top'#3#176#0#5'Width'#2'u'#7
+'Anchors'#11#5'akTop'#7'akRight'#0#8'AutoSize'#9#7'Caption'#6#14'Show in Fin' +'Anchors'#11#5'akTop'#7'akRight'#0#8'AutoSize'#9#7'Caption'#6#14'Show in Fin'
+'der'#7'OnClick'#7#20'btnShowInFinderClick'#8'TabOrder'#2#6#0#0#242#2#15#10 +'der'#7'OnClick'#7#20'btnShowInFinderClick'#8'TabOrder'#2#6#0#0#242#2#15#7'T'
+'TPopupMenu'#9'nibsPopup'#7'OnPopup'#7#14'nibsPopupPopup'#4'left'#3#0#1#3'to' +'Button'#9'btnAddXib'#22'AnchorSideLeft.Control'#7#12'btnRemoveXib'#23'Ancho'
+'p'#3' '#1#0#9'TMenuItem'#9'mnuOpenIB'#7'Caption'#6#22'Open Interface Builde' +'rSideRight.Control'#7#12'btnRemoveXib'#20'AnchorSideRight.Side'#7#9'asrBott'
+'r'#7'OnClick'#7#14'mnuOpenIBClick'#0#0#0#0 +'om'#4'Left'#2'('#6'Height'#2#20#3'Top'#3#27#1#5'Width'#2'J'#7'Anchors'#11#5
+'akTop'#6'akLeft'#7'akRight'#0#8'AutoSize'#9#7'Caption'#6#3'Add'#7'OnClick'#7
+#14'btnAddXibClick'#8'TabOrder'#2#7#0#0#242#2#16#7'TButton'#12'btnRemoveXib'
+#4'Left'#2'('#6'Height'#2#20#3'Top'#3'8'#1#5'Width'#2'J'#8'AutoSize'#9#7'Cap'
+'tion'#6#6'Remove'#7'OnClick'#7#17'btnRemoveXibClick'#8'TabOrder'#2#8#0#0#242
+#2#17#10'TPopupMenu'#9'nibsPopup'#7'OnPopup'#7#14'nibsPopupPopup'#4'left'#3#0
+#1#3'top'#3' '#1#0#9'TMenuItem'#9'mnuOpenIB'#7'Caption'#6#22'Open Interface '
+'Builder'#7'OnClick'#7#14'mnuOpenIBClick'#0#0#0#0
]); ]);

View File

@ -19,9 +19,9 @@ unit project_iphone_options;
interface interface
uses uses
Classes,SysUtils,FileUtil,LResources,Forms,StdCtrls,Masks,CheckLst,Buttons, Classes,SysUtils,FileUtil,LResources,Forms,StdCtrls,CheckLst,Buttons, Dialogs,
Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr, Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr,
iPhoneExtOptions, process, Controls; iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog;
type type
@ -29,6 +29,8 @@ type
TiPhoneProjectOptionsEditor = class(TAbstractIDEOptionsEditor) TiPhoneProjectOptionsEditor = class(TAbstractIDEOptionsEditor)
btnShowInFinder:TButton; btnShowInFinder:TButton;
btnAddXib:TButton;
btnRemoveXib:TButton;
Label5:TLabel; Label5:TLabel;
mnuOpenIB:TMenuItem; mnuOpenIB:TMenuItem;
nibFilesBox:TCheckListBox; nibFilesBox:TCheckListBox;
@ -45,7 +47,10 @@ type
lblAppIDHint: TLabel; lblAppIDHint: TLabel;
lblSDKVer: TLabel; lblSDKVer: TLabel;
nibsPopup:TPopupMenu; nibsPopup:TPopupMenu;
procedure btnAddXibClick(Sender:TObject);
procedure btnRemoveXibClick(Sender:TObject);
procedure btnShowInFinderClick(Sender:TObject); procedure btnShowInFinderClick(Sender:TObject);
procedure Button1Click(Sender:TObject);
procedure chkisPhoneChange(Sender:TObject); procedure chkisPhoneChange(Sender:TObject);
procedure cmbSDKsChange(Sender: TObject); procedure cmbSDKsChange(Sender: TObject);
procedure edtExcludeChange(Sender: TObject); procedure edtExcludeChange(Sender: TObject);
@ -81,47 +86,8 @@ type
property OnChanged: TNotifyEvent read fOnChanged write fOnChanged; property OnChanged: TNotifyEvent read fOnChanged write fOnChanged;
end; end;
procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings);
procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString);
implementation implementation
procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings);
var
mask : TMask;
sr : TSearchRec;
path : AnsiString;
begin
if (AMask='') or (trim(AMask)='*') then mask:=nil else mask:=TMask.Create(AMask);
try
path:=IncludeTrailingPathDelimiter(PathUtf8);
if FindFirstUTF8(path+AllFilesMask, faAnyFile, sr) = 0 then begin
repeat
if (sr.Name<>'.') and (sr.Name<>'..') then
if not Assigned(mask) or mask.Matches(sr.Name) then
Dst.Add(path+sr.Name);
until FindNextUTF8(sr)<>0;
FindCloseUTF8(sr);
end;
finally
mask.Free;
end;
end;
procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString);
var
proc : TProcess;
begin
proc:=TProcess.Create(nil);
try
proc.CommandLine:=CmdLineUtf8;
//proc.WaitOnExit:=WaitExit;
proc.Execute;
finally
proc.Free;
end;
end;
{ TiPhoneProjectOptionsEditor } { TiPhoneProjectOptionsEditor }
procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject); procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject);
@ -148,6 +114,49 @@ begin
if DirectoryExistsUTF8(path) then ExecCmdLineNoWait('open "'+path +'"'); if DirectoryExistsUTF8(path) then ExecCmdLineNoWait('open "'+path +'"');
end; end;
procedure TiPhoneProjectOptionsEditor.btnAddXibClick(Sender:TObject);
var
FileName : AnsiString;
SrcXib : AnsiString;
ResDir : AnsiString;
begin
newXibForm:=TnewXibForm.Create(Self);
ScanForXibTemplates(
XibTemplateDir( IncludeTrailingPathDelimiter(EnvOptions.PlatformsBaseDir)+iPhoneOSplatform),
@newXibForm.AddTemplate);
if (newXibForm.Execute(FileName, SrcXib)) and (SrcXib<>'')then begin
ResDir:=edtResDir.Text;
LazarusIDE.ActiveProject.LongenFilename(ResDir);
ForceDirectoriesUTF8(ResDir);
if not CopyFile(SrcXib, ChangeFileExt(IncludeTrailingPathDelimiter(ResDir)+FileName,'.xib')) then
ShowMessage('Failed to create Nib file');
RefreshXIBList;
end;
newXibForm.Free;
newXibForm:=nil;
end;
procedure TiPhoneProjectOptionsEditor.btnRemoveXibClick(Sender:TObject);
var
XibName : AnsiString;
begin
if nibFilesBox.ItemIndex<0 then Exit;
XibName:=edtResDir.Text;
LazarusIDE.ActiveProject.LongenFilename(XibName);
XibName:=ChangeFileExt(IncludeTrailingPathDelimiter(XibName)+nibFilesBox.Items[nibFilesBox.ItemIndex],'.xib');
if FileExistsUTF8(XibName) then DeleteFileUTF8(XibName);
RefreshXIBList;
end;
procedure TiPhoneProjectOptionsEditor.Button1Click(Sender:TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.chkisPhoneChange(Sender:TObject); procedure TiPhoneProjectOptionsEditor.chkisPhoneChange(Sender:TObject);
begin begin
SetControlsEnabled(chkisPhone.Checked); SetControlsEnabled(chkisPhone.Checked);

View File

@ -0,0 +1,186 @@
unit XcodeUtils;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, PlistFile, LazFilesUtils;
const
iPhoneOSplatform = 'iPhoneOS.platform';
// file names should utf8 encoded
// Scanning Xcode platform for available SDKs
type
TSDKFoundEvent = procedure (const Version: String;
const DeviceSDKName, DeviceSDKPath, SimSDKName, SimSDKPath: String) of object;
function ScanForSDK(const PlatformDir: String; FoundProc: TSDKFoundEvent): Boolean;
// Scanning for Templates
function XibTemplateDir(const PlatformDir: AnsiString): AnsiString;
type
TScanTemplateProc = procedure ( const TemplateName, XibFileName,
Description, IconFileName: AnsiString) of object;
procedure ScanForXibTemplates(const TemplateDir: AnsiString; Callback: TScanTemplateProc);
implementation
type
TSDKDescription = record
FullPath : String; {full SDK path}
Name : String;
Alternate : String; {alternate SDK -> iphonesimulator for iphoneos}
Version : String;
isSim : Boolean; {true for real iPhoneOS, false for iPhoneSimulator}
end;
function ReadSDKSettings(const FileName: String; var Descr: TSDKDescription): Boolean;
var
plist : TPListFile;
begin
Result:=False;
plist:=TPListFile.Create(FileName);
Descr.Name:=plist.GetStrValue('CanonicalName');
Descr.Alternate:=plist.GetStrValue('AlternateSDK');
Descr.Version:=plist.GetStrValue('Version');
plist.Free;
end;
function isSDKDir(const SDKDir: String; var d: TSDKDescription): Boolean;
var
plist : String;
begin
plist := IncludeTrailingPathDelimiter(SDKDir)+'SDKSettings.plist';
Result:=FileExists(plist);
if not Result then Exit;
ReadSDKSettings(plist, d);
d.FullPath:=SDKDir;
end;
function ScanForSDK(const PlatformDir: String; FoundProc: TSDKFoundEvent): Boolean;
const
PlatformName: array [Boolean] of String = ('iPhoneOS.platform','iPhoneSimulator.platform');
SDKSubDir = PathDelim+'Developer'+PathDelim+'SDKs'+PathDelim;
var
isSim : Boolean;
dir : String;
sr : TSearchRec;
sdks : array of TSDKDescription;
descr : TSDKDescription;
cnt : Integer;
simname : String;
simpath : String;
i,j : Integer;
procedure AddDescription(const d: TSDKDescription);
begin
if cnt = length(sdks) then begin
if cnt = 0 then SetLength(sdks, 16)
else SetLength(sdks, cnt*2);
end;
sdks[cnt]:=d;
inc(cnt);
end;
begin
Result:=Assigned(FoundProc);
if not Result then Exit;
cnt:=0;
for isSim:=false to true do begin
dir := IncludeTrailingPathDelimiter(PlatformDir) + PlatformName[isSim] + SDKSubDir;
if FindFirst(dir+'*', faAnyFile, sr)=0 then begin
repeat
if (sr.Attr and faDirectory>0) and (ExtractFileExt(sr.Name) = '.sdk') then
if isSDKDir( dir + sr.Name, descr) then begin
descr.isSim:=isSim;
AddDescription(descr);
end;
until FindNext(sr)<>0;
FindClose(sr);
end;
end;
for i:=0 to cnt-1 do
if not sdks[i].isSim then begin
simname:='';
simpath:='';
for j:=0 to cnt-1 do
if (sdks[j].isSim) and (sdks[i].Alternate=sdks[j].Name) then begin
simname:=sdks[j].Name;
simpath:=sdks[j].FullPath;
end;
FoundProc(sdks[i].Version, sdks[i].Name, sdks[i].FullPath, simname, simpath);
end;
Result:=True;
end;
function XibTemplateDir(const PlatformDir: AnsiString): AnsiString;
const
TemplatePath = 'Developer/Library/Xcode/File Templates/User Interface';
begin
Result:=IncludeTrailingPathDelimiter(PlatformDir)+TemplatePath;
end;
procedure ScanForXibTemplates(const TemplateDir: AnsiString; Callback: TScanTemplateProc);
var
dirs : TStringList;
files : TStringList;
i,j : Integer;
plist : TPListFile;
xib : AnsiString;
name : AnsiString;
descr : AnsiString;
const
XibTemplateMask = '*.pbfiletemplate';
IconFile = 'TemplateIcon.tiff';
begin
if not Assigned(Callback) or not DirectoryExists(TemplateDir) then Exit;
dirs:=TStringList.Create;
files:=TStringList.Create;
try
EnumFilesAtDir( TemplateDir, XibTemplateMask, dirs );
for i:=0 to dirs.Count-1 do begin
if DirectoryExists(dirs[i]) then begin
files.Clear;
EnumFilesAtDir(dirs[i], files);
xib:='';
for j:=0 to files.Count-1 do
if AnsiLowerCase(ExtractFileExt(files[j]))='.plist' then begin
plist:=TPListFile.Create(files[j]);
xib:=plist.GetStrValue('MainTemplateFile');
descr:=plist.GetStrValue('Description');
name:=ChangeFileExt(xib, '');
Break;
end;
if xib<>'' then begin
xib:=IncludeTrailingPathDelimiter(dirs[i])+xib;
Callback(name, xib, descr, IncludeTrailingPathDelimiter(dirs[i])+IconFile);
end;
end;
end;
finally
dirs.Free;
files.Free;
end;
end;
end.