From 058d550ef9c91b23c1de9d33354cfacc02c4597f Mon Sep 17 00:00:00 2001 From: skalogryz Date: Sun, 2 May 2010 22:57:55 +0000 Subject: [PATCH] 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 --- components/iphonelazext/ideext.pas | 4 +- components/iphonelazext/iphoneextoptions.pas | 104 +------- components/iphonelazext/iphonelazext.lpk | 10 +- components/iphonelazext/iphonelazext.pas | 14 +- components/iphonelazext/lazfilesutils.pas | 51 +++- components/iphonelazext/newxibdialog.lfm | 81 +++++++ components/iphonelazext/newxibdialog.pas | 228 ++++++++++++++++++ .../iphonelazext/project_iphone_options.lfm | 30 ++- .../iphonelazext/project_iphone_options.lrs | 17 +- .../iphonelazext/project_iphone_options.pas | 91 +++---- components/iphonelazext/xcodeutils.pas | 186 ++++++++++++++ 11 files changed, 652 insertions(+), 164 deletions(-) create mode 100644 components/iphonelazext/newxibdialog.lfm create mode 100644 components/iphonelazext/newxibdialog.pas create mode 100644 components/iphonelazext/xcodeutils.pas diff --git a/components/iphonelazext/ideext.pas b/components/iphonelazext/ideext.pas index d014f37aa..30fab00b0 100644 --- a/components/iphonelazext/ideext.pas +++ b/components/iphonelazext/ideext.pas @@ -50,7 +50,7 @@ type public //isiPhoneMenu :TIDEMenuCommand; constructor Create; - procedure UpdateXCode(Sender: TObject); + procedure UpdateXcode(Sender: TObject); procedure SimRun(Sender: TObject); //procedure isProjectClicked(Sender: TObject); end; @@ -339,7 +339,7 @@ begin //isiPhoneMenu.Checked:=ProjOptions.isIPhoneApp; end; -procedure TiPhoneExtension.UpdateXCode(Sender: TObject); +procedure TiPhoneExtension.UpdateXcode(Sender: TObject); var templates : TStringList; build : TStringList; diff --git a/components/iphonelazext/iphoneextoptions.pas b/components/iphonelazext/iphoneextoptions.pas index b980b0c68..64d5d9d8d 100644 --- a/components/iphonelazext/iphoneextoptions.pas +++ b/components/iphonelazext/iphoneextoptions.pas @@ -20,7 +20,8 @@ unit iPhoneExtOptions; interface uses - Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, iPhoneBundle, DOM, XMLRead, XMLConf, PlistFile; + Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, + iPhoneBundle, DOM, XMLRead, XMLConf, XcodeUtils; const DefaultResourceDir = 'Resources'; @@ -112,12 +113,6 @@ function EnvOptions: TiPhoneEnvironmentOptions; 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 iPhoneEnvGroup : Integer; iPhonePrjGroup : Integer; @@ -409,101 +404,6 @@ begin 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 InitOptions; diff --git a/components/iphonelazext/iphonelazext.lpk b/components/iphonelazext/iphonelazext.lpk index 4439f395e..80bf3eccc 100644 --- a/components/iphonelazext/iphonelazext.lpk +++ b/components/iphonelazext/iphonelazext.lpk @@ -18,7 +18,7 @@ - + @@ -64,6 +64,14 @@ + + + + + + + + diff --git a/components/iphonelazext/iphonelazext.pas b/components/iphonelazext/iphonelazext.pas index aa84b986c..923e0c897 100644 --- a/components/iphonelazext/iphonelazext.pas +++ b/components/iphonelazext/iphonelazext.pas @@ -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. } -unit iphonelazext; +unit iphonelazext; interface uses ideext, iPhoneExtStr, iPhoneBundle, XCodeProject, environment_iphone_options, project_iphone_options, iPhoneExtOptions, - xcodetemplate, lazfilesutils, LazarusPackageIntf; + xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, LazarusPackageIntf; implementation -procedure Register; +procedure Register; begin - RegisterUnit('ideext', @ideext.Register); -end; + RegisterUnit('ideext',@ideext.Register); +end; initialization - RegisterPackage('iphonelazext', @Register); + RegisterPackage('iphonelazext',@Register); end. diff --git a/components/iphonelazext/lazfilesutils.pas b/components/iphonelazext/lazfilesutils.pas index 116633cb0..ac91216c4 100644 --- a/components/iphonelazext/lazfilesutils.pas +++ b/components/iphonelazext/lazfilesutils.pas @@ -12,7 +12,7 @@ * * ***************************************************************************** } -unit lazfilesutils; +unit LazFilesUtils; {$mode objfpc}{$H+} @@ -21,8 +21,7 @@ interface uses {$ifdef Unix}BaseUnix,{$endif} Classes, SysUtils, FileUtil, Masks, - LazIDEIntf,ProjectIntf; - + LazIDEIntf, ProjectIntf, process; 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; +procedure EnumFilesAtDir(const PathUtf8 : AnsiString; Dst: TStrings); +procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings); +procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString); + implementation {$ifdef Unix} @@ -177,5 +180,47 @@ begin 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. diff --git a/components/iphonelazext/newxibdialog.lfm b/components/iphonelazext/newxibdialog.lfm new file mode 100644 index 000000000..28dc2e79f --- /dev/null +++ b/components/iphonelazext/newxibdialog.lfm @@ -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 diff --git a/components/iphonelazext/newxibdialog.pas b/components/iphonelazext/newxibdialog.pas new file mode 100644 index 000000000..246f35b7b --- /dev/null +++ b/components/iphonelazext/newxibdialog.pas @@ -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=0) and (idx'.') 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 } procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject); @@ -148,6 +114,49 @@ begin if DirectoryExistsUTF8(path) then ExecCmdLineNoWait('open "'+path +'"'); 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); begin SetControlsEnabled(chkisPhone.Checked); diff --git a/components/iphonelazext/xcodeutils.pas b/components/iphonelazext/xcodeutils.pas new file mode 100644 index 000000000..69fbe182b --- /dev/null +++ b/components/iphonelazext/xcodeutils.pas @@ -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. +