~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to converter/convertdelphi.pas

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
uses
35
35
  // LCL+FCL
36
 
  Classes, SysUtils, LCLProc, Forms, Controls, Dialogs, LResources,
 
36
  Classes, SysUtils, LCLProc, Forms, Controls, Dialogs, LResources, LConvEncoding,
37
37
  FileUtil, contnrs, IniFiles, AVL_Tree,
38
38
  // codetools
39
39
  CodeToolManager, DefineTemplates, CodeAtom, CodeCache, LinkScanner,
98
98
    fSettings: TConvertSettings;
99
99
    function GetDfmFileName: string;
100
100
    function CopyAndLoadFile: TModalResult;
101
 
    function FixLfmFilename(ADfmFilename: string): TModalResult;
 
101
    function FixLfmFilenameAndLoad(ADfmFilename: string): TModalResult;
102
102
    function ConvertUnitFile: TModalResult;
103
103
    function ConvertFormFile: TModalResult;
104
104
    function AskUnitPathFromUser: TModalResult;
146
146
    // Units that are found and will be added to project and converted.
147
147
    fUnitsToAddToProject: TStringList;
148
148
    fSettings: TConvertSettings;
 
149
    fUseThreads: boolean;              // The project/package uses TThread.
149
150
    function ConvertSub: TModalResult;
150
151
    procedure CleanUpCompilerOptionsSearchPaths(Options: TBaseCompilerOptions);
151
152
    procedure SetCompilerModeForDefineTempl(DefTempl: TDefineTemplate);
161
162
  protected
162
163
    function CreateInstance: TModalResult; virtual; abstract;
163
164
    function CreateMainSourceFile: TModalResult; virtual;
164
 
    function ScanMainSourceFile: TModalResult; virtual;
165
165
    function ConvertMainSourceFile: TModalResult; virtual;
166
166
    function FindAllUnits: TModalResult; virtual; abstract;
167
167
    function ConvertAllUnits: TModalResult; virtual; abstract;
168
168
    function ExtractOptionsFromDelphiSource: TModalResult; virtual; abstract;
169
 
    // The following protected funcs are needed only because Project and LazPackage
170
 
    //  don't inherit from the same class.
 
169
    // The following protected funcs are needed only because
 
170
    //  Project and LazPackage don't inherit from the same class.
171
171
    function GetCompOpts: TBaseCompilerOptions; virtual; abstract;
172
172
    function GetCustomDefines: TDefineTemplate; virtual; abstract;
173
173
    procedure CustomDefinesChanged; virtual; abstract;
180
180
    constructor Create(const AFilename, ADescription: string);
181
181
    destructor Destroy; override;
182
182
    function Convert: TModalResult;
 
183
    function CheckPackageDependency(AUnitName: string): Boolean;
183
184
  public
184
185
    property CompOpts: TBaseCompilerOptions read GetCompOpts;
185
186
    property CustomDefines: TDefineTemplate read GetCustomDefines;
194
195
  private
195
196
    // Resource code
196
197
    fMainUnitConverter: TConvertDelphiUnit;
197
 
    function AddUnit(AUnitName: string; out OutUnitInfo: TUnitInfo): TModalResult;
 
198
    function AddUnit(AFileName: string; out OutUnitInfo: TUnitInfo): TModalResult;
198
199
    function GetLazProject: TProject;
199
200
    procedure SetLazProject(const AValue: TProject);
200
201
  protected
201
202
    function CreateInstance: TModalResult; override;
202
203
    function CreateMainSourceFile: TModalResult; override;
203
 
    function ScanMainSourceFile: TModalResult; override;
204
204
    function ConvertMainSourceFile: TModalResult; override;
205
205
    function FindAllUnits: TModalResult; override;
206
206
    function ConvertAllUnits: TModalResult; override;
269
269
  end;
270
270
}
271
271
  // Some global functions from delphiunit2laz are not (yet) converted to class methods.
272
 
 
273
 
  function CheckDelphiFileExt(const Filename: string): TModalResult;
274
 
  function CheckFilenameForLCLPaths(const Filename: string): TModalResult;
275
 
 
276
 
  // projects
277
 
  function CheckDelphiProjectExt(const Filename: string): TModalResult;
278
 
 
279
 
  // file names / search paths
280
272
  function ConvertDelphiAbsoluteToRelativeFile(const Filename: string;
281
273
                                               AProject: TProject): string;
282
274
  function ExpandDelphiFilename(const Filename: string; AProject: TProject): string;
286
278
 
287
279
implementation
288
280
 
289
 
function CheckDelphiFileExt(const Filename: string): TModalResult;
290
 
begin
291
 
  Result:=mrOk;
292
 
  if CompareFileExt(Filename,'.pas',false)<>0 then
293
 
    Result:=QuestionDlg(lisNotADelphiUnit,
294
 
        Format(lisTheFileIsNotADelphiUnit, ['"', Filename, '"']),
295
 
        mtError, [mrCancel,lisConvDelphiSkipThisFile,mbAbort,lisInfoBuildMakeAbort], 0);
296
 
end;
297
 
 
298
 
function CheckFilenameForLCLPaths(const Filename: string): TModalResult;
299
 
// check if the unitpath of the directory of filename contains the path to the LCL
300
 
var
301
 
  Directory: String;
302
 
  UnitPath: String;
303
 
  LazarusSrcDir: string;
304
 
  LCLPath: String;
305
 
  NextStartPos: Integer;
306
 
begin
307
 
  // get directory of filename
308
 
  Directory:=ExtractFilePath(Filename);
309
 
  // get unitpath definition of directory
310
 
  UnitPath:=CodeToolBoss.GetUnitPathForDirectory(Directory);
311
 
  // get lazarus source directory
312
 
  LazarusSrcDir:=CodeToolBoss.GlobalValues.Variables[ExternalMacroStart+'LazarusDir'];
313
 
  // create base path to LCL compiled units <LazarusSrcDir>/lcl/units/
314
 
  LCLPath:=TrimFilename(LazarusSrcDir+SetDirSeparators('/lcl/units/'));
315
 
  NextStartPos:=1;
316
 
  if GetNextUsedDirectoryInSearchPath(UnitPath,LCLPath,NextStartPos)='' then
317
 
  begin
318
 
    LCLPath:=LCLPath+'$(TargetCPU)-$(TargetOS)';
319
 
    Result:=QuestionDlg(lisLCLUnitPathMissing,
320
 
      Format(lisTheCurrentUnitPathForTheFileIsThePathToTheLCLUnits,
321
 
            [sLineBreak,'"',Filename,'"',sLineBreak,'"',UnitPath,'"',sLineBreak,
322
 
             sLineBreak,'"',LCLPath,'"',sLineBreak,sLineBreak,sLineBreak]),
323
 
      mtError, [mrOK, lisContinue, mrAbort, lisInfoBuildMakeAbort], 0);
324
 
    exit;
325
 
  end;
326
 
  Result:=mrOk;
327
 
end;
328
 
 
329
 
function CheckDelphiProjectExt(const Filename: string): TModalResult;
330
 
begin
331
 
  if CompareFileExt(Filename,'.dpr',false)<>0 then begin
332
 
    Result:=QuestionDlg(lisNotADelphiProject,
333
 
      Format(lisTheFileIsNotADelphiProjectDpr, ['"', Filename, '"']),
334
 
      mtError, [mrCancel, lisConvDelphiSkipThisStep, mbAbort], 0);
335
 
    exit;
336
 
  end;
337
 
  Result:=mrOk;
338
 
end;
339
 
 
340
281
function ConvertDelphiAbsoluteToRelativeFile(const Filename: string; AProject: TProject): string;
341
282
// often projects use paths near to their project directory. For example:
342
283
//   A project /somewhere/MyProjects/project1.dpr
424
365
constructor TCacheUnitsThread.Create(aConverter: TConvertDelphiPBase; aBasePath: string);
425
366
begin
426
367
  inherited Create(True);
427
 
  fConverter:=aConverter;
428
 
  fPath:=TrimFilename(aBasePath+'../'); // Will scan one level up from base path.
 
368
  fConverter:=aConverter;    // Will scan one level up from base path.
 
369
  fPath:=TrimFilename(aBasePath+'..'+DirectorySeparator);
429
370
end;
430
371
 
431
372
destructor TCacheUnitsThread.Destroy;
459
400
  if not LazarusIDE.BeginCodeTools then
460
401
    IDEMessagesWindow.AddMsg(lisConvDelphiBeginCodeToolsFailed, '', -1);
461
402
  fCTLink:=Nil;                     // Will be created later.
 
403
  fUsedUnitsTool:=Nil;
462
404
end;
463
405
 
464
406
destructor TConvertDelphiUnit.Destroy;
465
407
begin
 
408
  fUsedUnitsTool.Free;
466
409
  fCTLink.Free;
467
410
  if fOwnerConverter=nil then
468
411
    fSettings.Free;
490
433
    end;
491
434
  end;
492
435
  if Result=mrOk then
493
 
    IDEMessagesWindow.AddMsg(lisConvDelphiReady, '', -1)
 
436
    IDEMessagesWindow.AddMsg(lisConvDelphiConversionReady, '', -1)
494
437
  else
495
 
    IDEMessagesWindow.AddMsg(lisConvDelphiAborted, '', -1)
 
438
    IDEMessagesWindow.AddMsg(lisConvDelphiConversionAborted, '', -1)
496
439
end;
497
440
 
498
441
function TConvertDelphiUnit.GetDfmFileName: string;
510
453
 
511
454
function TConvertDelphiUnit.CopyAndLoadFile: TModalResult;
512
455
begin
 
456
  IDEMessagesWindow.AddMsg(Format(lisConvDelphiConvertingFile,
 
457
                                  [fOrigUnitFilename]), '', -1);
 
458
  Application.ProcessMessages;
513
459
  // Convert in place. File must be writable.
514
460
  Result:=CheckFileIsWritable(fOrigUnitFilename,[mbAbort]);
515
461
  if Result<>mrOk then exit;
524
470
  fPascalBuffer:=nil;
525
471
  Result:=LoadCodeBuffer(fPascalBuffer,fLazUnitFilename,
526
472
                         [lbfCheckIfText,lbfUpdateFromDisk],true);
 
473
  if Result<>mrOk then exit;
 
474
  // Change encoding to UTF-8
 
475
  if fPascalBuffer.DiskEncoding<>EncodingUTF8 then begin
 
476
    IDEMessagesWindow.AddMsg(Format(lisConvDelphiChangedEncodingToUTF8,
 
477
                                    [fPascalBuffer.DiskEncoding]), '', -1);
 
478
    fPascalBuffer.DiskEncoding:=EncodingUTF8; // Takes effect when buffer is saved.
 
479
  end;
527
480
  // Create a shared link for codetools.
528
481
  Assert(fCTLink=Nil, 'fCTLink should be Nil in CopyAndLoadFile');
529
482
  fCTLink:=TCodeToolLink.Create(fPascalBuffer);
530
483
  fCTLink.Settings:=fSettings;
 
484
  fCTLink.AskAboutError:=Assigned(fOwnerConverter);
 
485
  // Create a toold for missing units.
 
486
  fUsedUnitsTool:=TUsedUnitsTool.Create(fCTLink, fOrigUnitFilename);
 
487
  if Assigned(fOwnerConverter) then begin
 
488
    fUsedUnitsTool.CheckPackDepEvent:=@fOwnerConverter.CheckPackageDependency;
 
489
    fUsedUnitsTool.IsConsoleApp:=fOwnerConverter.fIsConsoleApp;
 
490
  end;
531
491
end;
532
492
 
533
 
function TConvertDelphiUnit.FixLfmFilename(ADfmFilename: string): TModalResult;
 
493
function TConvertDelphiUnit.FixLfmFilenameAndLoad(ADfmFilename: string): TModalResult;
534
494
var
535
495
  LfmFilename: string;     // Lazarus .LFM file name.
 
496
  DFMConverter: TDFMConverter;
 
497
  TempLFMBuffer: TCodeBuffer;
536
498
begin
537
499
  Result:=mrOK;
538
500
  fLFMBuffer:=nil;
540
502
    Result:=LazarusIDE.DoCloseEditorFile(ADfmFilename,[cfSaveFirst]);
541
503
    if Result<>mrOk then exit;
542
504
  end;
543
 
  if fSettings.Target=ctLazarusDelphiSameDfm then
 
505
  if fSettings.SameDfmFile then
544
506
    LfmFilename:=ADfmFilename
545
507
  else begin
546
508
    // Create a form file name based on the unit file name.
552
514
          DeleteFileUTF8(LfmFilename); // .lfm is older than .dfm -> remove .lfm
553
515
      if not FileExistsUTF8(LfmFilename) then begin
554
516
        // TODO: update project
555
 
        if fSettings.Target=ctLazarusDelphi then
 
517
        if fSettings.SupportDelphi and not fSettings.SameDfmFile then
556
518
          Result:=CopyFileWithErrorDialogs(ADfmFilename,LfmFilename,[mbAbort])
557
519
        else
558
520
          Result:=fSettings.RenameFile(ADfmFilename,LfmFilename);
562
524
  end;
563
525
  // convert .dfm file to .lfm file (without context type checking)
564
526
  if FileExistsUTF8(LfmFilename) then begin
565
 
    Result:=ConvertDfmToLfm(LfmFilename);
566
 
    if Result<>mrOk then exit;
 
527
    DFMConverter:=TDFMConverter.Create(IDEMessagesWindow);
 
528
    try
 
529
      Result:=DFMConverter.ConvertDfmToLfm(LfmFilename);
 
530
      if Result<>mrOk then exit;
 
531
    finally
 
532
      DFMConverter.Free;
 
533
    end;
 
534
    // Change encoding to UTF-8
 
535
    Result:=LoadCodeBuffer(TempLFMBuffer,LfmFilename,
 
536
                           [lbfCheckIfText,lbfUpdateFromDisk],true);
 
537
    if TempLFMBuffer.DiskEncoding<>EncodingUTF8 then begin
 
538
      IDEMessagesWindow.AddMsg(Format(lisConvDelphiChangedEncodingToUTF8,
 
539
                                      [TempLFMBuffer.DiskEncoding]), '', -1);
 
540
      TempLFMBuffer.DiskEncoding:=EncodingUTF8;
 
541
      TempLFMBuffer.Save;
 
542
    end;
567
543
    // Read form file code in.
568
 
    if fSettings.Target<>ctLazarusDelphiSameDfm then begin
 
544
    if not fSettings.SameDfmFile then begin
569
545
      Result:=LoadCodeBuffer(fLFMBuffer,LfmFilename,
570
546
                             [lbfCheckIfText,lbfUpdateFromDisk],true);
571
547
    end;
594
570
  DfmFilename: string;     // Delphi .DFM file name.
595
571
  ConvTool: TConvDelphiCodeTool;
596
572
begin
597
 
  IDEMessagesWindow.AddMsg(Format(lisConvDelphiConvertingUnitFile,
598
 
                                  [fOrigUnitFilename]), '', -1);
599
 
  Application.ProcessMessages;
600
573
  // Get DFM file name and close it in editor.
601
574
  DfmFilename:=GetDfmFileName;
602
 
  Result:=FixLfmFilename(DfmFilename);
 
575
  Result:=FixLfmFilenameAndLoad(DfmFilename);
603
576
  if Result<>mrOk then exit;
604
 
  // Check LCL path for single files. They are correct when converting projects.
605
 
{  if not Assigned(fOwnerConverter) then begin
606
 
    Result:=CheckFilenameForLCLPaths(fLazUnitFilename);
607
 
    if Result<>mrOk then exit;
608
 
  end;  }
609
577
  // Fix include file names.
610
578
  Result:=FixIncludeFiles;
611
579
  if Result<>mrOk then exit;
612
 
  fCTLink.IsConsoleApp:=False;
613
 
  fCTLink.IsMainFile:=False;
614
 
  fCTLink.AskAboutError:=False;
615
 
  if Assigned(fOwnerConverter) then begin
616
 
    fCTLink.IsConsoleApp:= fOwnerConverter.fIsConsoleApp;
617
 
    fCTLink.IsMainFile:=fOwnerConverter.MainName=fLazUnitFilename;
618
 
    fCTLink.AskAboutError:=True;
 
580
  if fSettings.UnitsReplaceMode<>rlDisabled then begin
 
581
    // Find and prepare the missing units. Don't replace yet.
 
582
    Result:=fUsedUnitsTool.Prepare;
 
583
    if Result<>mrOk then exit;
 
584
    if fUsedUnitsTool.MissingUnitCount>0 then begin
 
585
      Result:=ReduceMissingUnits;
 
586
      if Result<>mrOk then exit;
 
587
    end;
619
588
  end;
620
 
  // Take care of missing units in uses sections.
621
 
  fUsedUnitsTool:=Nil;
 
589
  // Do the actual code conversion.
 
590
  ConvTool:=TConvDelphiCodeTool.Create(fCTLink);
622
591
  try
623
 
    if fSettings.UnitsReplaceMode<>rlDisabled then begin
624
 
      fUsedUnitsTool:=TUsedUnitsTool.Create(fCTLink, fOrigUnitFilename);
625
 
      // Find and prepare the missing units. Don't replace yet.
626
 
      Result:=fUsedUnitsTool.Prepare;
627
 
      if Result<>mrOk then exit;
628
 
      if fUsedUnitsTool.MissingUnitCount>0 then begin
629
 
        Result:=ReduceMissingUnits;
630
 
        if Result<>mrOk then exit;
631
 
      end;
632
 
    end;
633
 
    // Do the actual code conversion.
634
 
    ConvTool:=TConvDelphiCodeTool.Create(fCTLink);
635
 
    try
636
 
      ConvTool.LowerCaseRes:=FileExistsUTF8(ChangeFileExt(fLazUnitFilename, '.res'));
637
 
      ConvTool.HasFormFile:=DfmFilename<>'';
638
 
      Result:=ConvTool.Convert;
639
 
      if Result<>mrOk then exit;
640
 
    finally
641
 
      ConvTool.Free;
642
 
    end;
643
 
    // Fix or comment missing units, show error messages.
644
 
    if fSettings.UnitsReplaceMode<>rlDisabled then
645
 
      Result:=fUsedUnitsTool.Convert;
 
592
    if Assigned(fOwnerConverter) then
 
593
      ConvTool.IsConsoleApp:=fOwnerConverter.fIsConsoleApp;
 
594
    ConvTool.LowerCaseRes:=FileExistsUTF8(ChangeFileExt(fLazUnitFilename, '.res'));
 
595
    ConvTool.HasFormFile:=DfmFilename<>'';
 
596
    ConvTool.AddUnitEvent:=@fUsedUnitsTool.AddUnitIfNeeded;
 
597
    Result:=ConvTool.Convert;
646
598
  finally
647
 
    FreeAndNil(fUsedUnitsTool);
 
599
    ConvTool.Free;
648
600
  end;
649
601
end;
650
602
 
660
612
    LfmFixer:=TLFMFixer.Create(fCTLink,fLFMBuffer,@IDEMessagesWindow.AddMsg);
661
613
    try
662
614
      LfmFixer.Settings:=fSettings;
 
615
      LfmFixer.UsedUnitsTool:=fUsedUnitsTool;
663
616
      LfmFixer.RootMustBeClassInUnit:=true;
664
617
      LfmFixer.RootMustBeClassInIntf:=true;
665
 
      LfmFixer.ObjectsMustExists:=true;
 
618
      LfmFixer.ObjectsMustExist:=true;
666
619
      if LfmFixer.Repair<>mrOk then begin
667
620
        LazarusIDE.DoJumpToCompilerMessage(-1,true);
668
621
        exit(mrAbort);
674
627
    Result:=SaveCodeBufferToFile(fLFMBuffer,fLFMBuffer.Filename);
675
628
    if Result<>mrOk then exit;
676
629
  end;
 
630
  // After other changes: add, remove, fix and comment out units in uses sections.
 
631
  IDEMessagesWindow.AddMsg(Format(lisConvDelphiFixingUsedUnits,
 
632
                                  [fOrigUnitFilename]), '', -1);
 
633
  Result:=fUsedUnitsTool.Convert;
 
634
  if Result<>mrOk then exit;
677
635
  Result:=mrOk;
678
636
end;
679
637
 
687
645
  repeat
688
646
    TryAgain:=False;
689
647
    Result:=AskMissingUnits(MainUsedUnits.MissingUnits, ImplUsedUnits.MissingUnits,
690
 
                            ExtractFileName(fLazUnitFilename),
691
 
                    fSettings.Target in [ctLazarusDelphi, ctLazarusDelphiSameDfm]);
 
648
                            ExtractFileName(fLazUnitFilename), fSettings.SupportDelphi);
692
649
    case Result of
693
650
      // mrOK means: comment out.
694
651
      mrOK: begin
702
659
        UnitDirDialog:=TSelectDirectoryDialog.Create(nil);
703
660
        try
704
661
          UnitDirDialog.InitialDir:=fOwnerConverter.fPrevSelectedPath;
705
 
          UnitDirDialog.Title:=
706
 
            lisConvDelphiAllSubDirectoriesWillBeScannedForUnitFiles;
 
662
          UnitDirDialog.Title:=lisConvDelphiAllSubDirsScanned;
707
663
          if UnitDirDialog.Execute then begin
708
664
            if Assigned(fOwnerConverter) then begin
709
665
              fOwnerConverter.fPrevSelectedPath:=ExtractFilePath(UnitDirDialog.Filename);
719
675
        end;
720
676
        Result:=mrOK;        // Caller will check for Result<>mrOK
721
677
      end;
722
 
      // User wants to abort.
 
678
      // Skip this unit.
 
679
      mrIgnore: Exit;
 
680
      // Abort the whole conversion.
723
681
      mrAbort: Exit;
724
682
    end;
725
683
  until not TryAgain;
779
737
begin
780
738
  fOrigPFilename:=AFilename;
781
739
  fIsConsoleApp:=False;                      // Default = GUI app.
 
740
  fUseThreads:=False;
782
741
  fUnitSearchPaths:=TStringList.Create;
783
742
  fUnitSearchPaths.Delimiter:=';';
784
743
  fUnitSearchPaths.StrictDelimiter:=True;
809
768
  // The initial unit name cache is done in a thread so that GUI shows at once.
810
769
  CacheUnitsThread: TCacheUnitsThread;
811
770
begin
 
771
  if CompareFileExt(fOrigPFilename,'.dproj',false)=0 then begin
 
772
    ShowMessage('.dproj file is not supported yet. The file is used by Delphi 2007 and newer.'+
 
773
                ' Please select a .dpr file for projects or .dpk file for packages.');
 
774
    Exit(mrCancel);
 
775
  end;
812
776
  IDEMessagesWindow.Clear;
813
777
  // Start scanning unit files one level above project path. The GUI will appear
814
778
  // without delay but then we must wait for the thread before continuing.
815
779
  CacheUnitsThread:=TCacheUnitsThread.Create(Self, fSettings.MainPath);
816
780
  try
817
 
    CacheUnitsThread.Resume;
 
781
    CacheUnitsThread.Start;
818
782
    Result:=fSettings.RunForm;      // Get settings from user.
819
783
    Screen.Cursor:=crHourGlass;
820
784
    try
861
825
 
862
826
  RemoveNonExistingFiles(false);
863
827
  CleanUpCompilerOptionsSearchPaths(CompOpts);
864
 
  // Scan LPR file for directives. Sets fIsConsoleApp flag.
865
 
  Result:=ScanMainSourceFile;
866
 
  if Result<>mrOK then exit;
867
828
  // LCL dependency is added automatically later for GUI applications.
868
829
//  AddPackageDependency('LCL');
869
830
  // ToDo: make an option to add NoGUI to Project.CompilerOptions.LCLWidgetType.
870
831
  if fProjPack is TProject then
871
 
    PkgBoss.AddDefaultDependencies(fProjPack as TProject);
 
832
    PkgBoss.OpenProjectDependencies(fProjPack as TProject,true);
872
833
  CustomDefinesChanged;
873
834
 
874
835
  SetCompilerModeForDefineTempl(CustomDefines);
875
836
  try
876
 
    Result:=ConvertMainSourceFile;     // Convert project's LPR file.
877
837
    if Result<>mrOK then exit;
878
838
    // get all options from the .dpr or .dpk file
879
839
    Result:=ExtractOptionsFromDelphiSource;
880
840
    if Result<>mrOK then exit;
881
841
    Result:=FindAllUnits;              // find all files and save the project.
882
842
    if Result<>mrOK then exit;
 
843
    Result:=ConvertMainSourceFile;     // Convert project's LPR file.
 
844
    if Result<>mrOK then exit;
883
845
    Result:=ConvertAllUnits;           // convert all files.
884
846
  finally
885
847
    UnsetCompilerModeForDefineTempl(CustomDefines);
954
916
  begin
955
917
    if DelphiPkgName='' then exit;
956
918
    if System.Pos(';'+lowercase(DelphiPkgName)+';',
957
 
                  ';'+lowercase(DelphiPkgNames)+';')>0 then
 
919
                  ';'+lowercase(DelphiPkgNames)+';')>0 then begin
958
920
      AddPackageDependency(LazarusPkgName);
 
921
      IDEMessagesWindow.AddMsg(
 
922
          Format(lisConvDelphiAddedPackageRequirement, [LazarusPkgName]), '', -1);
 
923
    end;
959
924
  end;
960
925
 
961
926
  procedure ReadDelphiPackages;
1097
1062
  Options.SrcPath:=CleanProjectSearchPath(Options.SrcPath);
1098
1063
end;
1099
1064
 
 
1065
function TConvertDelphiPBase.CheckPackageDependency(AUnitName: string): Boolean;
 
1066
var
 
1067
  Pack: TPkgFile;
 
1068
  Dep: TPkgDependency;
 
1069
  s: String;
 
1070
begin
 
1071
  Result:=False;
 
1072
  Pack:=PackageGraph.FindUnitInAllPackages(AUnitName, True);
 
1073
  if Assigned(Pack) then begin
 
1074
    // Found from package: add package to project dependencies and open it.
 
1075
    s:=Pack.LazPackage.Name;
 
1076
    if s='LCLBase' then
 
1077
      s:='LCL';
 
1078
    AddPackageDependency(s);
 
1079
    IDEMessagesWindow.AddMsg(Format(lisConvDelphiAddedPackageRequirement, [s]), '', -1);
 
1080
    Dep:=FindDependencyByName(s);
 
1081
    if Assigned(Dep) then
 
1082
      PackageGraph.OpenDependency(Dep,false);
 
1083
    Result:=True;
 
1084
  end else begin;
 
1085
    // ToDo: Install the required package automatically from a repository...
 
1086
  end;
 
1087
end;
 
1088
 
1100
1089
function TConvertDelphiPBase.DoMissingUnits(AUsedUnitsTool: TUsedUnitsTool): integer;
1101
1090
// Locate unit names from earlier cached list or from packages.
1102
1091
// Return the number of units still missing.
1103
1092
 
1104
1093
  procedure DoMissingSub(AUsedUnits: TUsedUnits);
1105
1094
  var
1106
 
    Pack: TPkgFile;
1107
 
    Dep: TPkgDependency;
1108
1095
    mUnit, sUnitPath, RealFileName, RealUnitName: string;
1109
1096
    i: Integer;
1110
1097
  begin
1121
1108
        RealFileName:=fCachedRealFileNames[UpperCase(mUnit)];
1122
1109
        RealUnitName:=ExtractFileNameOnly(RealFileName);
1123
1110
        if (RealUnitName<>'') and (RealUnitName<>mUnit) then
1124
 
          AUsedUnits.UnitsToRename[mUnit]:=RealUnitName;
 
1111
          AUsedUnits.UnitsToFixCase[mUnit]:=RealUnitName;
1125
1112
        // Will be added later to project.
1126
1113
        fUnitsToAddToProject.Add(sUnitPath+RealFileName);
1127
1114
        AUsedUnits.MissingUnits.Delete(i);      // No more missing, delete from list.
1128
1115
      end
1129
 
      else begin
1130
 
        Pack:=PackageGraph.FindUnitInAllPackages(mUnit, True);
1131
 
        if Assigned(Pack) then begin
1132
 
          // Found from package: add package to project dependencies and open it.
1133
 
          AddPackageDependency(Pack.LazPackage.Name);
1134
 
          Dep:=FindDependencyByName(Pack.LazPackage.Name);
1135
 
          if Assigned(Dep) then
1136
 
            PackageGraph.OpenDependency(Dep,false);
1137
 
          AUsedUnits.MissingUnits.Delete(i);
1138
 
        end;
1139
 
      end;
 
1116
      else if CheckPackageDependency(mUnit) then
 
1117
        AUsedUnits.MissingUnits.Delete(i);
1140
1118
    end;
1141
1119
  end;
1142
1120
 
1190
1168
  Result:=mrOK; // Do nothing. Overridden in project.
1191
1169
end;
1192
1170
 
1193
 
function TConvertDelphiPBase.ScanMainSourceFile: TModalResult;
1194
 
begin
1195
 
  Result:=mrOK; // Do nothing. Overridden in project.
1196
 
end;
1197
 
 
1198
1171
function TConvertDelphiPBase.ConvertMainSourceFile: TModalResult;
1199
1172
begin
1200
1173
  Result:=mrOK; // Do nothing. Overridden in project.
1256
1229
// adds the .lpr as main unit to the project, if not already done
1257
1230
var
1258
1231
  MainUnitInfo: TUnitInfo;
 
1232
  ConvTool: TConvDelphiCodeTool;
1259
1233
begin
1260
1234
  // Converter for main LPR file.
1261
1235
  fMainUnitConverter:=TConvertDelphiUnit.Create(Self,fOrigPFilename,[]);
1262
 
  if fSettings.Target in [ctLazarusDelphi, ctLazarusDelphiSameDfm] then
 
1236
  if fSettings.SupportDelphi then
1263
1237
    fMainUnitConverter.LazFileExt:=ExtractFileExt(fOrigPFilename)
1264
1238
  else
1265
1239
    fMainUnitConverter.LazFileExt:='.lpr';
1266
 
  fMainUnitConverter.CopyAndLoadFile;
 
1240
  Result:=fMainUnitConverter.CopyAndLoadFile;
 
1241
  if Result<>mrOk then exit;
1267
1242
  if LazProject.MainUnitInfo=nil then begin
1268
1243
    // add .lpr file to project as main unit
1269
1244
    MainUnitInfo:=TUnitInfo.Create(fMainUnitConverter.fPascalBuffer);
1276
1251
    // replace main unit in project
1277
1252
    LazProject.MainUnitInfo.Source:=fMainUnitConverter.fPascalBuffer;
1278
1253
  end;
1279
 
  Result:=LazarusIDE.DoOpenEditorFile(fMainUnitConverter.fLazUnitFilename,0,0,[ofQuiet]);
1280
 
  if Result<>mrOK then exit;
1281
 
  Result:=mrOk;
1282
 
end;
1283
 
 
1284
 
function TConvertDelphiProject.ScanMainSourceFile: TModalResult;
1285
 
var
1286
 
  CTLink: TCodeToolLink;
1287
 
  ConvTool: TConvDelphiCodeTool;
1288
 
begin
1289
 
  Result:=mrOK;
1290
 
  CTLink:=TCodeToolLink.Create(fMainUnitConverter.fPascalBuffer);
1291
 
  ConvTool:=TConvDelphiCodeTool.Create(CTLink);
 
1254
  // Scan LPR file for directives. Sets fIsConsoleApp flag.
 
1255
  ConvTool:=TConvDelphiCodeTool.Create(fMainUnitConverter.fCTLink);
1292
1256
  try
1293
1257
    fIsConsoleApp:=ConvTool.FindApptypeConsole;
1294
1258
  finally
1295
1259
    ConvTool.Free;
1296
 
    CTLink.Free;
1297
 
  end;
 
1260
  end;
 
1261
  CompOpts.Win32GraphicApp := not fIsConsoleApp;
 
1262
  with fMainUnitConverter do begin
 
1263
    fUsedUnitsTool.IsMainFile:=True;
 
1264
    fUsedUnitsTool.IsConsoleApp:=fIsConsoleApp;
 
1265
    Result:=LazarusIDE.DoOpenEditorFile(fLazUnitFilename,0,0,[ofQuiet]);
 
1266
    if Result<>mrOK then exit;
 
1267
  end;
 
1268
  Result:=mrOk;
1298
1269
end;
1299
1270
 
1300
1271
function TConvertDelphiProject.ConvertMainSourceFile: TModalResult;
1305
1276
  Result:=fMainUnitConverter.ConvertFormFile;
1306
1277
end;
1307
1278
 
1308
 
function TConvertDelphiProject.AddUnit(AUnitName: string;
 
1279
function TConvertDelphiProject.AddUnit(AFileName: string;
1309
1280
                                       out OutUnitInfo: TUnitInfo): TModalResult;
1310
1281
// add new unit to project
1311
1282
var
1312
1283
  CurUnitInfo: TUnitInfo;
1313
 
  RP: String;
 
1284
  RP, PureUnitName: String;
 
1285
  x: Integer;
1314
1286
begin
1315
1287
  Result:=mrOK;
1316
1288
  OutUnitInfo:=nil;
1317
 
  if not FilenameIsAbsolute(AUnitName) then
1318
 
    AUnitName:=AppendPathDelim(LazProject.ProjectDirectory)+AUnitName;
1319
 
  AUnitName:=TrimFilename(AUnitName);
1320
 
  if not FileExistsUTF8(AUnitName) then
 
1289
  if not FilenameIsAbsolute(AFileName) then
 
1290
    AFileName:=AppendPathDelim(LazProject.ProjectDirectory)+AFileName;
 
1291
  AFileName:=TrimFilename(AFileName);
 
1292
  if not FileExistsUTF8(AFileName) then
1321
1293
    exit(mrNo);
1322
1294
  // Create relative search path for project settings.
1323
 
  RP:=ExtractFilePath(CreateRelativePath(AUnitName, LazProject.ProjectDirectory));
 
1295
  RP:=ExtractFilePath(CreateRelativePath(AFileName, LazProject.ProjectDirectory));
1324
1296
  if (RP<>'') and (fUnitSearchPaths.IndexOf(RP)<0) then
1325
1297
    fUnitSearchPaths.Add(RP);
1326
 
  // Check unitname and create UnitInfo.
1327
 
  CurUnitInfo:=LazProject.UnitInfoWithFilename(AUnitName);
1328
 
  if CurUnitInfo=nil then begin
1329
 
    if FilenameIsPascalUnit(AUnitName) then begin
1330
 
      CurUnitInfo:=LazProject.UnitWithUnitname(ExtractFileNameOnly(AUnitName));
1331
 
      if CurUnitInfo<>nil then begin
1332
 
        Result:=QuestionDlg(lisConvDelphiUnitnameExistsTwice,
1333
 
          Format(lisConvDelphiThereAreTwoUnitsWithTheSameUnitname,
1334
 
                 [#13, CurUnitInfo.Filename, #13, AUnitName, #13]),
1335
 
          mtWarning, [mrYes, lisConvDelphiRemoveFirst, mrNo,
1336
 
            lisConvDelphiRemoveSecond,
1337
 
                     mrIgnore, lisConvDelphiKeepBoth, mrAbort], 0);
1338
 
        case Result of
1339
 
          mrYes: CurUnitInfo.IsPartOfProject:=false;
1340
 
          mrNo:  exit(mrNo);
1341
 
          mrIgnore: ;
1342
 
        else
1343
 
          exit(mrAbort);
 
1298
  PureUnitName:=ExtractFileNameOnly(AFileName);
 
1299
  if not fSettings.OmitProjUnits.Find(PureUnitName, x) then begin
 
1300
    // Check unitname and create UnitInfo.
 
1301
    CurUnitInfo:=LazProject.UnitInfoWithFilename(AFileName);
 
1302
    if CurUnitInfo=nil then begin
 
1303
      if FilenameIsPascalUnit(AFileName) then begin
 
1304
        CurUnitInfo:=LazProject.UnitWithUnitname(PureUnitName);
 
1305
        if CurUnitInfo<>nil then begin
 
1306
          Result:=QuestionDlg(lisConvDelphiUnitnameExistsTwice,
 
1307
            Format(lisConvDelphiThereAreTwoUnitsWithTheSameUnitname,
 
1308
                   [#13, CurUnitInfo.Filename, #13, AFileName, #13]),
 
1309
            mtWarning, [mrYes, lisConvDelphiRemoveFirst, mrNo,
 
1310
              lisConvDelphiRemoveSecond,
 
1311
                       mrIgnore, lisConvDelphiKeepBoth, mrAbort], 0);
 
1312
          case Result of
 
1313
            mrYes: CurUnitInfo.IsPartOfProject:=false;
 
1314
            mrNo:  exit(mrNo);
 
1315
            mrIgnore: ;
 
1316
          else
 
1317
            exit(mrAbort);
 
1318
          end;
1344
1319
        end;
1345
1320
      end;
 
1321
      CurUnitInfo:=TUnitInfo.Create(nil);
 
1322
      CurUnitInfo.Filename:=AFileName;
 
1323
      LazProject.AddFile(CurUnitInfo,false);
1346
1324
    end;
1347
 
    CurUnitInfo:=TUnitInfo.Create(nil);
1348
 
    CurUnitInfo.Filename:=AUnitName;
1349
 
    LazProject.AddFile(CurUnitInfo,false);
 
1325
    CurUnitInfo.IsPartOfProject:=true;
 
1326
    OutUnitInfo:=CurUnitInfo;
 
1327
  end
 
1328
  else begin
 
1329
    fMainUnitConverter.fUsedUnitsTool.Remove(PureUnitName);
 
1330
    IDEMessagesWindow.AddMsg(Format(lisConvDelphiProjOmittedUnit,[PureUnitName]), '', -1);
1350
1331
  end;
1351
 
  CurUnitInfo.IsPartOfProject:=true;
1352
 
  OutUnitInfo:=CurUnitInfo;
1353
1332
end;
1354
1333
 
1355
1334
function TConvertDelphiProject.FindAllUnits: TModalResult;
1375
1354
      Result:=mrCancel;
1376
1355
      exit;
1377
1356
    end;
1378
 
    try
1379
 
      // add all units to the project
 
1357
    try        // add all units to the project
1380
1358
      for i:=0 to FoundUnits.Count-1 do begin
1381
1359
        CurFilename:=FoundUnits[i];
1382
1360
        p:=System.Pos(' in ',CurFilename);
1388
1366
      end;
1389
1367
    finally
1390
1368
      AllPath:=fUnitSearchPaths.DelimitedText;
1391
 
      // set unit paths to find all project units
1392
 
      LazProject.CompilerOptions.OtherUnitFiles:=
1393
 
          MergeSearchPaths(LazProject.CompilerOptions.OtherUnitFiles,AllPath);
1394
 
      // set include path
1395
 
      LazProject.CompilerOptions.IncludePath:=
1396
 
          MergeSearchPaths(LazProject.CompilerOptions.IncludePath,AllPath);
 
1369
      // set unit and include paths for project
 
1370
      with LazProject.CompilerOptions do begin
 
1371
        OtherUnitFiles:=MergeSearchPaths(OtherUnitFiles,AllPath);
 
1372
        IncludePath:=MergeSearchPaths(IncludePath,AllPath);
 
1373
      end;
1397
1374
      // clear caches
1398
1375
      LazProject.DefineTemplates.SourceDirectoriesChanged;
1399
1376
    end;
1421
1398
    Converter.fUnitInfo:=AUnitInfo;
1422
1399
    ConvUnits.Add(Converter);
1423
1400
    Result:=Converter.CopyAndLoadFile;
 
1401
    if Result<>mrOK then exit;
1424
1402
    Result:=Converter.CheckFailed(Result);
1425
1403
    if Result<>mrOK then exit;
1426
1404
    Result:=Converter.ConvertUnitFile;
1441
1419
      // Main LPR file was converted earlier.
1442
1420
      if CurUnitInfo.IsPartOfProject and (CurUnitInfo<>LazProject.MainUnitInfo) then begin
1443
1421
        Result:=ConvertOne(CurUnitInfo);
1444
 
        if Result<>mrOK then Break;
 
1422
        if Result=mrIgnore then Continue;
 
1423
        if Result=mrAbort then Exit;
 
1424
//        if Result<>mrOK then Break;
1445
1425
      end;
1446
1426
    end;
1447
1427
    // During conversion there were more units added to be converted.
1448
1428
    for i:=0 to fUnitsToAddToProject.Count-1 do begin
1449
1429
      Result:=AddUnit(fUnitsToAddToProject[i], CurUnitInfo);
1450
 
      if Result=mrNo then continue;
1451
 
      if Result=mrAbort then Break;
 
1430
      if Result=mrNo then Continue;
 
1431
      if Result=mrAbort then Exit;
1452
1432
      Result:=ConvertOne(CurUnitInfo);
1453
 
      if Result<>mrOK then Break;
 
1433
      if Result=mrIgnore then Continue;
 
1434
      if Result=mrAbort then Exit;
1454
1435
    end;
1455
 
    if Result=mrOK then
 
1436
    if Result=mrOK then begin
 
1437
      if fUseThreads then begin
 
1438
        Result:=fMainUnitConverter.fUsedUnitsTool.AddThreadSupport;
 
1439
        if Result<>mrOK then exit;
 
1440
      end;
1456
1441
      Result:=ConvertAllFormFiles(ConvUnits);
 
1442
    end;
1457
1443
  finally
1458
1444
    ConvUnits.Free;  // Owns and frees converter objects.
1459
1445
  end;
1565
1551
  end;
1566
1552
  // search package in graph
1567
1553
  PkgName:=ExtractFileNameOnly(fLazPFilename);
1568
 
  LazPackage:=PackageGraph.FindAPackageWithName(PkgName,nil);
 
1554
  LazPackage:=PackageGraph.FindPackageWithName(PkgName,nil);
1569
1555
  if LazPackage<>nil then begin
1570
1556
    // there is already a package loaded with this name ...
1571
1557
    if CompareFilenames(LazPackage.Filename,fLazPFilename)<>0 then begin
1614
1600
      Converter:=TConvertDelphiUnit.Create(Self, PkgFile.Filename,[]);
1615
1601
      ConvUnits.Add(Converter);
1616
1602
      Result:=Converter.CopyAndLoadFile;
 
1603
      if Result<>mrOK then exit;
1617
1604
      Result:=Converter.CheckFailed(Result);
1618
1605
      if Result<>mrOK then Break;
1619
1606
      Result:=Converter.ConvertUnitFile;
 
1607
      if Result<>mrOK then exit;
1620
1608
      Result:=Converter.CheckFailed(Result);
1621
1609
      if Result<>mrOK then Break;
1622
1610
    end;
1630
1618
function TConvertDelphiPackage.FindAllUnits: TModalResult;
1631
1619
var
1632
1620
  FoundInUnits, MissingInUnits, NormalUnits: TStrings;
1633
 
  NotFoundUnits: String;
1634
1621
  i: Integer;
1635
1622
  NewSearchPath, AllPath, UselessPath: String;
1636
1623
  CurFilename: string;
1652
1639
      Result:=mrCancel;
1653
1640
      exit;
1654
1641
    end;
1655
 
    // warn about missing units
1656
 
    if (MissingInUnits<>nil) and (MissingInUnits.Count>0) then begin
1657
 
      NotFoundUnits:=MissingInUnits.Text;
1658
 
      Result:=QuestionDlg(lisConvDelphiUnitsNotFound,
1659
 
        Format(lisConvDelphiSomeUnitsOfTheDelphiPackageAreMissing,
1660
 
               [#13, NotFoundUnits]), mtWarning, [mrIgnore, mrAbort], 0);
1661
 
      if Result<>mrIgnore then exit;
1662
 
    end;
1663
 
 
1664
1642
    try
1665
1643
      // add all units to the package
1666
1644
      for i:=0 to FoundInUnits.Count-1 do begin
1669
1647
        if p>0 then
1670
1648
          CurFilename:=copy(CurFilename,p+4,length(CurFilename));
1671
1649
        if CurFilename='' then continue;
 
1650
        CurFilename:=SwitchPathDelims(CurFilename, True);
1672
1651
        if not FilenameIsAbsolute(CurFilename) then
1673
1652
          CurFilename:=AppendPathDelim(LazPackage.Directory)+CurFilename;
1674
1653
        CurFilename:=TrimFilename(CurFilename);
1694
1673
              end;
1695
1674
            end;
1696
1675
          end;
1697
 
 
1698
1676
          // add new unit to package
1699
1677
          LazPackage.AddFile(CurFilename,ExtractFileNameOnly(CurFilename),
1700
1678
                           pftUnit,[pffAddToPkgUsesSection],cpNormal);
1701
1679
        end;
1702
1680
      end;
1703
 
 
1704
1681
    finally
1705
1682
      AllPath:=LazPackage.SourceDirectories.CreateSearchPathFromAllFiles;
1706
1683
      UselessPath:='.;'+VirtualDirectory+';'+VirtualTempDir+';'+LazPackage.Directory;