mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-26 18:43:50 +02:00
2139 lines
68 KiB
ObjectPascal
2139 lines
68 KiB
ObjectPascal
{ $Id$ }
|
|
{
|
|
/***************************************************************************
|
|
project.pp - project utility class file
|
|
-----------------------------------------
|
|
TProject is responsible for managing a complete project.
|
|
|
|
|
|
Initial Revision : Sun Mar 28 23:15:32 CST 1999
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code 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. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
|
|
}
|
|
unit Project;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
{$ifdef Trace}
|
|
{$ASSERTIONS ON}
|
|
{$endif}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLLinux, LCLType, Laz_XMLCfg, LazConf, CompilerOptions,
|
|
FileCtrl, CodeToolManager, CodeCache, Forms, Controls, EditorOptions, Dialogs,
|
|
IDEProcs, RunParamsOpts, ProjectDefs, EditDefineTree, DefineTemplates;
|
|
|
|
type
|
|
TUnitInfo = class;
|
|
TProject = class;
|
|
|
|
TOnFileBackup = function(const FileToBackup:string;
|
|
IsPartOfProject:boolean):TModalResult of object;
|
|
TOnUnitNameChange = procedure(AnUnitInfo: TUnitInfo;
|
|
const OldUnitName, NewUnitName: string;
|
|
CheckIfAllowed: boolean;
|
|
var Allowed: boolean) of object;
|
|
|
|
//---------------------------------------------------------------------------
|
|
TNewUnitType = (
|
|
nuEmpty, // no code
|
|
nuUnit, // unit
|
|
nuForm, // unit with form
|
|
nuCustomProgram // program
|
|
);
|
|
|
|
|
|
TUnitInfo = class(TObject)
|
|
private
|
|
{ Variables }
|
|
fAutoRevertLockCount: integer;
|
|
fBreakpoints: TProjectBreakPointList;
|
|
fCursorPos: TPoint;
|
|
fCustomHighlighter: boolean; // do not change highlighter on file extension change
|
|
fEditorIndex: integer;
|
|
fFileName: string;
|
|
fForm: TComponent;
|
|
fFormName: string; { classname is always T<FormName>
|
|
this attribute contains the formname even if the unit is not loaded }
|
|
fFormResourceName: string;
|
|
fHasResources: boolean; // source has resource file
|
|
FIgnoreFileDateOnDiskValid: boolean;
|
|
FIgnoreFileDateOnDisk: longint;
|
|
fIsPartOfProject: boolean;
|
|
fLoaded: Boolean; // loaded in the source editor
|
|
fModified: boolean;
|
|
fOnFileBackup: TOnFileBackup;
|
|
fOnLoadSaveFilename: TOnLoadSaveFilename;
|
|
fOnUnitNameChange: TOnUnitNameChange;
|
|
FProject: TProject;
|
|
fReadOnly: Boolean;
|
|
FResourceFilename: string;
|
|
fSource: TCodeBuffer;
|
|
fSyntaxHighlighter: TLazSyntaxHighlighter;
|
|
fTopLine: integer;
|
|
fUnitName: String;
|
|
|
|
function GetFileName: string;
|
|
function GetHasResources:boolean;
|
|
procedure SetEditorIndex(const AValue: integer);
|
|
procedure SetForm(const AValue: TComponent);
|
|
procedure SetLoaded(const AValue: Boolean);
|
|
procedure SetProject(const AValue: TProject);
|
|
procedure SetReadOnly(const NewValue: boolean);
|
|
procedure SetSource(ABuffer: TCodeBuffer);
|
|
procedure SetUnitName(const NewUnitName:string);
|
|
protected
|
|
fNextUnitWithEditorIndex: TUnitInfo;
|
|
fPrevUnitWithEditorIndex: TUnitInfo;
|
|
fNextUnitWithForm: TUnitInfo;
|
|
fPrevUnitWithForm: TUnitInfo;
|
|
fNextLoadedUnit: TUnitInfo;
|
|
fPrevLoadedUnit: TUnitInfo;
|
|
fNextAutoRevertLockedUnit: TUnitInfo;
|
|
fPrevAutoRevertLockedUnit: TUnitInfo;
|
|
procedure UpdateEditorIndexList;
|
|
procedure UpdateFormList;
|
|
procedure UpdateLoadedList;
|
|
procedure UpdateAutoRevertLockedList;
|
|
public
|
|
constructor Create(ACodeBuffer: TCodeBuffer);
|
|
destructor Destroy; override;
|
|
|
|
function ReadUnitSource(ReadUnitName:boolean): TModalResult;
|
|
procedure ReadUnitNameFromSource;
|
|
function WriteUnitSource: TModalResult;
|
|
function WriteUnitSourceToFile(const AFileName: string): TModalResult;
|
|
procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
|
|
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
|
|
procedure Clear;
|
|
procedure CreateStartCode(NewUnitType: TNewUnitType;
|
|
const NewUnitName: string);
|
|
function IsVirtual: boolean;
|
|
function IsMainUnit: boolean;
|
|
procedure IncreaseAutoRevertLock;
|
|
procedure DecreaseAutoRevertLock;
|
|
function IsAutoRevertLocked: boolean;
|
|
function ChangedOnDisk(CompareOnlyLoadSaveTime: boolean): boolean;
|
|
procedure IgnoreCurrentFileDateOnDisk;
|
|
function ShortFilename: string;
|
|
function NeedsSaveToDisk: boolean;
|
|
|
|
{ Properties }
|
|
public
|
|
property NextUnitWithEditorIndex: TUnitInfo read fNextUnitWithEditorIndex;
|
|
property PrevUnitWithEditorIndex: TUnitInfo read fPrevUnitWithEditorIndex;
|
|
property NextUnitWithForm: TUnitInfo read fNextUnitWithForm;
|
|
property PrevUnitWithForm: TUnitInfo read fPrevUnitWithForm;
|
|
property NextLoadedUnit: TUnitInfo read fNextLoadedUnit;
|
|
property PrevLoadedUnit: TUnitInfo read fPrevLoadedUnit;
|
|
property NextAutoRevertLockedUnit: TUnitInfo read fNextAutoRevertLockedUnit;
|
|
property PrevAutoRevertLockedUnit: TUnitInfo read fPrevAutoRevertLockedUnit;
|
|
public
|
|
property Breakpoints: TProjectBreakPointList
|
|
read fBreakpoints write fBreakpoints;
|
|
property CursorPos: TPoint read fCursorPos write fCursorPos;
|
|
property CustomHighlighter: boolean
|
|
read fCustomHighlighter write fCustomHighlighter;
|
|
property EditorIndex:integer read fEditorIndex write SetEditorIndex;
|
|
property Filename: String read GetFilename;
|
|
property Form: TComponent read fForm write SetForm;
|
|
property FormName: string read fFormName write fFormName;
|
|
property FormResourceName: string
|
|
read fFormResourceName write fFormResourceName;
|
|
property HasResources: boolean read GetHasResources write fHasResources;
|
|
property IsPartOfProject: boolean
|
|
read fIsPartOfProject write fIsPartOfProject;
|
|
property Loaded: Boolean read fLoaded write SetLoaded;
|
|
property Modified: boolean read fModified write fModified;
|
|
property OnFileBackup: TOnFileBackup read fOnFileBackup write fOnFileBackup;
|
|
property OnLoadSaveFilename: TOnLoadSaveFilename
|
|
read fOnLoadSaveFilename write fOnLoadSaveFilename;
|
|
property OnUnitNameChange: TOnUnitNameChange
|
|
read fOnUnitNameChange write fOnUnitNameChange;
|
|
property Project: TProject read FProject write SetProject;
|
|
property ReadOnly: Boolean read fReadOnly write SetReadOnly;
|
|
property ResourceFileName: string
|
|
read FResourceFilename write FResourceFilename;
|
|
property Source: TCodeBuffer read fSource write SetSource;
|
|
property SyntaxHighlighter: TLazSyntaxHighlighter
|
|
read fSyntaxHighlighter write fSyntaxHighlighter;
|
|
property TopLine: integer read fTopLine write fTopLine;
|
|
property UnitName: String read fUnitName write SetUnitName;
|
|
end;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
TProjectType = // for a description see ProjectTypeDescriptions below
|
|
(ptApplication, ptProgram, ptCustomProgram);
|
|
TProjectFlag = (pfSaveClosedUnits, pfSaveOnlyProjectUnits);
|
|
TProjectFlags = set of TProjectFlag;
|
|
|
|
TProject = class(TObject)
|
|
private
|
|
FFlags: TProjectFlags;
|
|
xmlconfig: TXMLConfig;
|
|
|
|
{ Variables }
|
|
fActiveEditorIndexAtStart: integer;
|
|
fBookmarks: TProjectBookmarkList;
|
|
fCompilerOptions: TCompilerOptions;
|
|
fFirstAutoRevertLockedUnit: TUnitInfo; // units with IsAutoRevertLocked=true
|
|
fFirstLoadedUnit: TUnitInfo; // units with Loaded=true
|
|
fFirstUnitWithEditorIndex: TUnitInfo;// units with EditorIndex>=0
|
|
fFirstUnitWithForm: TUnitInfo; // units with Form<>nil
|
|
fIconPath: String;
|
|
fJumpHistory: TProjectJumpHistory;
|
|
fMainUnit: Integer; // only for ptApplication
|
|
fModified: boolean;
|
|
fOnFileBackup: TOnFileBackup;
|
|
fOutputDirectory: String;
|
|
fProjectInfoFile: String; // the lpi filename
|
|
fProjectType: TProjectType;
|
|
fSrcPath: string; // source path addition for units in ProjectDir
|
|
fTargetFileExt: String;
|
|
fTitle: String;
|
|
fUnitList: TList; // list of TUnitInfo
|
|
fUnitOutputDirectory: String;
|
|
fRunParameterOptions: TRunParamsOptions;
|
|
|
|
function GetMainFilename: String;
|
|
function GetMainUnitInfo: TUnitInfo;
|
|
function GetProjectInfoFile: string;
|
|
function GetTargetFilename: string;
|
|
function GetUnits(Index: integer): TUnitInfo;
|
|
procedure SetFlags(const AValue: TProjectFlags);
|
|
procedure SetMainUnit(const AValue: Integer);
|
|
procedure SetUnits(Index:integer; AUnitInfo: TUnitInfo);
|
|
procedure SetProjectInfoFile(const NewFilename: string);
|
|
procedure SetTargetFilename(const NewTargetFilename: string);
|
|
procedure OnLoadSaveFilename(var AFilename: string; Load: boolean);
|
|
function OnUnitFileBackup(const Filename: string;
|
|
IsPartOfProject:boolean): TModalResult;
|
|
procedure OnUnitNameChange(AnUnitInfo: TUnitInfo;
|
|
const OldUnitName, NewUnitName: string; CheckIfAllowed: boolean;
|
|
var Allowed: boolean);
|
|
function JumpHistoryCheckPosition(
|
|
APosition:TProjectJumpHistoryPosition): boolean;
|
|
procedure SetSrcPath(const NewSrcPath: string);
|
|
protected
|
|
procedure AddToEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
procedure RemoveFromEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToFormList(AnUnitInfo: TUnitInfo);
|
|
procedure RemoveFromFormList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToLoadedList(AnUnitInfo: TUnitInfo);
|
|
procedure RemoveFromLoadedList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
procedure RemoveFromAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
public
|
|
constructor Create(TheProjectType: TProjectType);
|
|
destructor Destroy; override;
|
|
|
|
function ReadProject(LPIFilename: string): TModalResult;
|
|
function WriteProject: TModalResult;
|
|
|
|
property Units[Index: integer]:TUnitInfo read GetUnits write SetUnits;
|
|
function UnitCount:integer;
|
|
function NewUniqueUnitName(NewUnitType:TNewUnitType): string;
|
|
function NewUniqueFormName(NewUnitType:TNewUnitType): string;
|
|
procedure AddUnit(AUnit: TUnitInfo; AddToProjectFile: boolean);
|
|
procedure RemoveUnit(Index: integer);
|
|
function IndexOf(AUnitInfo: TUnitInfo): integer;
|
|
function IndexOfUnitWithName(const AnUnitName: string;
|
|
OnlyProjectUnits:boolean; IgnoreUnit: TUnitInfo): integer;
|
|
function IndexOfUnitWithForm(AForm: TComponent;
|
|
OnlyProjectUnits:boolean; IgnoreUnit: TUnitInfo): integer;
|
|
function IndexOfUnitWithFormName(const AFormName: string;
|
|
OnlyProjectUnits:boolean; IgnoreUnit: TUnitInfo): integer;
|
|
function IndexOfFilename(const AFilename: string): integer;
|
|
function UnitWithEditorIndex(Index:integer): TUnitInfo;
|
|
Function UnitWithForm(AForm: TComponent): TUnitInfo;
|
|
|
|
procedure CloseEditorIndex(EditorIndex:integer);
|
|
procedure InsertEditorIndex(EditorIndex:integer);
|
|
procedure AddToOrRemoveFromEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToOrRemoveFromFormList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToOrRemoveFromLoadedList(AnUnitInfo: TUnitInfo);
|
|
procedure AddToOrRemoveFromAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
|
|
procedure Clear;
|
|
function SomethingModified: boolean;
|
|
function AddCreateFormToProjectFile(const AClassName,AName:string):boolean;
|
|
function RemoveCreateFormFromProjectFile(const AClassName,AName:string):boolean;
|
|
function FormIsCreatedInProjectFile(const AClassname,AName:string):boolean;
|
|
function UnitIsUsed(const ShortUnitName:string):boolean;
|
|
function GetResourceFile(AnUnitInfo: TUnitInfo; Index:integer):TCodeBuffer;
|
|
function SearchFile(const Filename,SearchPaths,InitialDir:string):string;
|
|
function GetMainResourceFilename(AnUnitInfo: TUnitInfo): string;
|
|
function IsVirtual: boolean;
|
|
function RemoveProjectPathFromFilename(const AFilename: string): string;
|
|
function ProjectDirectory: string;
|
|
function FileIsInProjectDir(const AFilename: string): boolean;
|
|
|
|
procedure GetUnitsChangedOnDisk(var AnUnitList: TList);
|
|
|
|
property ActiveEditorIndexAtStart: integer
|
|
read fActiveEditorIndexAtStart write fActiveEditorIndexAtStart;
|
|
property Bookmarks: TProjectBookmarkList read fBookmarks write fBookmarks;
|
|
property CompilerOptions: TCompilerOptions
|
|
read fCompilerOptions write fCompilerOptions;
|
|
property FirstAutoRevertLockedUnit: TUnitInfo read fFirstAutoRevertLockedUnit;
|
|
property FirstLoadedUnit: TUnitInfo read fFirstLoadedUnit;
|
|
property FirstUnitWithEditorIndex: TUnitInfo read fFirstUnitWithEditorIndex;
|
|
property FirstUnitWithForm: TUnitInfo read fFirstUnitWithForm;
|
|
|
|
property Flags: TProjectFlags read FFlags write SetFlags;
|
|
property IconPath: String read fIconPath write fIconPath;
|
|
property JumpHistory: TProjectJumpHistory
|
|
read fJumpHistory write fJumpHistory;
|
|
property MainUnit: Integer //this is the unit index of the program file
|
|
read fMainUnit write SetMainUnit;
|
|
property MainUnitInfo: TUnitInfo read GetMainUnitInfo;
|
|
property Modified: boolean read fModified write fModified;
|
|
property OnFileBackup: TOnFileBackup read fOnFileBackup write fOnFileBackup;
|
|
property OutputDirectory: String read fOutputDirectory write fOutputDirectory;
|
|
property MainFilename: String read GetMainFilename;
|
|
property ProjectInfoFile: string
|
|
read GetProjectInfoFile write SetProjectInfoFile;
|
|
property ProjectType: TProjectType read fProjectType write fProjectType;
|
|
property RunParameterOptions: TRunParamsOptions read fRunParameterOptions;
|
|
property SrcPath: string read fSrcPath write fSrcPath;
|
|
property TargetFileExt: String read fTargetFileExt write fTargetFileExt;
|
|
property TargetFilename: string read GetTargetFilename write SetTargetFilename;
|
|
property Title: String read fTitle write fTitle;
|
|
property UnitOutputDirectory: String
|
|
read fUnitOutputDirectory write fUnitOutputDirectory;
|
|
end;
|
|
|
|
const
|
|
ResourceFileExt = '.lrs';
|
|
|
|
ProjectTypeNames : array[TProjectType] of string = (
|
|
'Application', 'Program', 'Custom program'
|
|
);
|
|
|
|
ProjectTypeDescriptions : array[TProjectType] of string = (
|
|
// ptApplication
|
|
'Application'#13
|
|
+'A graphical lcl/freepascal program. The program file is '
|
|
+'automatically maintained by lazarus.'#13
|
|
+#13
|
|
+#13
|
|
+'WARNING:'#13
|
|
+'Form editing is under development and should not be used.'
|
|
|
|
// ptProgram
|
|
,'Program:'#13
|
|
+'A freepascal program. The program file is automatically '
|
|
+'maintained by lazarus.'
|
|
|
|
// ptCustomProgram
|
|
,'Custom program:'#13
|
|
+'A freepascal program.'
|
|
);
|
|
|
|
ProjectDefaultExt : array[TProjectType] of string = (
|
|
'.lpr','.pas','.pas'
|
|
);
|
|
|
|
UnitTypeDefaultExt: array[TNewUnitType] of string = (
|
|
'.pas', '.pas', '.pas', '.pas'
|
|
);
|
|
|
|
DefaultTargetFileExt : string = {$IFDEF win32}'.exe'{$ELSE}''{$ENDIF};
|
|
|
|
DefaultProjectFlags = [pfSaveClosedUnits];
|
|
ProjectFlagNames : array[TProjectFlag] of string = (
|
|
'SaveClosedFiles', 'SaveOnlyProjectUnits'
|
|
);
|
|
|
|
function ProjectTypeNameToType(const s:string): TProjectType;
|
|
function ProjectFlagsToStr(Flags: TProjectFlags): string;
|
|
|
|
implementation
|
|
|
|
function ProjectFlagsToStr(Flags: TProjectFlags): string;
|
|
var f: TProjectFlag;
|
|
begin
|
|
Result:='';
|
|
for f:=Low(TProjectFlag) to High(TProjectFlag) do begin
|
|
if f in Flags then begin
|
|
if Result='' then Result:=Result+',';
|
|
Result:=Result+ProjectFlagNames[f];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function ProjectTypeNameToType(const s:string): TProjectType;
|
|
begin
|
|
for Result:=Low(TProjectType) to High(TProjectType) do
|
|
if (lowercase(ProjectTypeNames[Result])=lowercase(s)) then exit;
|
|
Result:=ptCustomProgram;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo Class
|
|
------------------------------------------------------------------------------}
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo Constructor
|
|
------------------------------------------------------------------------------}
|
|
constructor TUnitInfo.Create(ACodeBuffer: TCodeBuffer);
|
|
begin
|
|
inherited Create;
|
|
Assert(False, 'Project Unit Info Class Created');
|
|
fBreakPoints:=TProjectBreakPointList.Create;
|
|
Clear;
|
|
Source := ACodeBuffer;
|
|
if Source=nil then
|
|
FFileName:='';
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo Destructor
|
|
------------------------------------------------------------------------------}
|
|
destructor TUnitInfo.Destroy;
|
|
begin
|
|
Source:=nil;
|
|
fBreakPoints.Free;
|
|
Project:=nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo WriteUnitSource
|
|
------------------------------------------------------------------------------}
|
|
function TUnitInfo.WriteUnitSource: TModalResult;
|
|
var
|
|
ACaption:string;
|
|
AText:string;
|
|
begin
|
|
if fSource=nil then begin
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
if Assigned(fOnFileBackup) then begin
|
|
Result:=fOnFileBackup(fFilename,IsPartOfProject);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
repeat
|
|
if not fSource.Save then begin
|
|
ACaption:='Write error';
|
|
AText:='Unable to write file "'+Filename+'"!';
|
|
Result:=Application.MessageBox(PChar(AText),PChar(ACaption)
|
|
,MB_ABORTRETRYIGNORE);
|
|
if Result=mrAbort then exit;
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
end else begin
|
|
Result:=mrOk;
|
|
FIgnoreFileDateOnDiskValid:=true;
|
|
end;
|
|
until Result<>mrRetry;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TUnitInfo.WriteUnitSourceToFile(const AFileName: string): TModalResult;
|
|
var
|
|
ACaption:string;
|
|
AText:string;
|
|
begin
|
|
if fSource=nil then begin
|
|
Result:=mrOk;
|
|
exit;
|
|
end;
|
|
if Assigned(fOnFileBackup) then begin
|
|
Result:=fOnFileBackup(fFilename,false);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
repeat
|
|
if not fSource.SaveToFile(AFileName) then begin
|
|
ACaption:='Write error';
|
|
AText:='Unable to write file "'+AFilename+'"!';
|
|
Result:=Application.MessageBox(PChar(AText),PChar(ACaption)
|
|
,MB_ABORTRETRYIGNORE);
|
|
if Result=mrAbort then exit;
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
end else
|
|
Result:=mrOk;
|
|
until Result<>mrRetry;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo ReadUnitSource
|
|
------------------------------------------------------------------------------}
|
|
function TUnitInfo.ReadUnitSource(ReadUnitName:boolean): TModalResult;
|
|
var
|
|
ACaption:string;
|
|
AText:string;
|
|
NewSource: TCodeBuffer;
|
|
begin
|
|
repeat
|
|
NewSource:=CodeToolBoss.LoadFile(fFilename,true,false);
|
|
if NewSource=nil then begin
|
|
ACaption:='Read error';
|
|
AText:='Unable to read file "'+fFilename+'"!';
|
|
Result:=Application.MessageBox(PChar(AText),PChar(ACaption)
|
|
,MB_ABORTRETRYIGNORE);
|
|
if Result in [mrAbort,mrIgnore] then
|
|
exit;
|
|
end else begin
|
|
Source:=NewSource;
|
|
FIgnoreFileDateOnDiskValid:=true;
|
|
Result:=mrOk;
|
|
end;
|
|
until Result<>mrRetry;
|
|
if ReadUnitName then
|
|
fUnitName:=CodeToolBoss.GetSourceName(fSource,false);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TUnitInfo.ReadUnitNameFromSource;
|
|
begin
|
|
fUnitName:=CodeToolBoss.GetSourceName(fSource,false);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo Clear
|
|
------------------------------------------------------------------------------}
|
|
procedure TUnitInfo.Clear;
|
|
begin
|
|
fBreakPoints.Clear;
|
|
fCursorPos.X := -1;
|
|
fCursorPos.Y := -1;
|
|
fCustomHighlighter := false;
|
|
fEditorIndex := -1;
|
|
fFilename := '';
|
|
fForm := nil;
|
|
fFormName := '';
|
|
fFormResourceName := '';
|
|
fHasResources := false;
|
|
FIgnoreFileDateOnDiskValid:=false;
|
|
fIsPartOfProject := false;
|
|
Loaded := false;
|
|
fModified := false;
|
|
fReadOnly := false;
|
|
if fSource<>nil then fSource.Clear;
|
|
fSyntaxHighlighter := lshText;
|
|
fTopLine := -1;
|
|
fUnitName := '';
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo SaveToXMLConfig
|
|
------------------------------------------------------------------------------}
|
|
procedure TUnitInfo.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
|
|
var AFilename:string;
|
|
begin
|
|
XMLConfig.SetValue(Path+'CursorPos/X',fCursorPos.X);
|
|
XMLConfig.SetValue(Path+'CursorPos/Y',fCursorPos.Y);
|
|
XMLConfig.SetValue(Path+'EditorIndex/Value',fEditorIndex);
|
|
AFilename:=Filename;
|
|
if Assigned(fOnLoadSaveFilename) then
|
|
fOnLoadSaveFilename(AFilename,false);
|
|
XMLConfig.SetValue(Path+'Filename/Value',AFilename);
|
|
XMLConfig.SetValue(Path+'FormName/Value',fFormName);
|
|
XMLConfig.SetValue(Path+'HasResources/Value',fHasResources);
|
|
XMLConfig.SetValue(Path+'IsPartOfProject/Value',fIsPartOfProject);
|
|
XMLConfig.SetValue(Path+'Loaded/Value',fLoaded);
|
|
XMLConfig.SetValue(Path+'ReadOnly/Value',fReadOnly);
|
|
AFilename:=FResourceFilename;
|
|
if Assigned(fOnLoadSaveFilename) then
|
|
fOnLoadSaveFilename(AFilename,false);
|
|
XMLConfig.SetValue(Path+'ResourceFilename/Value',AFilename);
|
|
XMLConfig.SetValue(Path+'SyntaxHighlighter/Value'
|
|
,LazSyntaxHighlighterNames[fSyntaxHighlighter]);
|
|
XMLConfig.SetValue(Path+'TopLine/Value',fTopLine);
|
|
XMLConfig.SetValue(Path+'UnitName/Value',fUnitName);
|
|
fBreakpoints.SaveToXMLConfig(XMLConfig,Path);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUnitInfo LoadFromXMLConfig
|
|
------------------------------------------------------------------------------}
|
|
procedure TUnitInfo.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
|
|
var AFilename: string;
|
|
begin
|
|
CursorPos.X:=XMLConfig.GetValue(Path+'CursorPos/X',-1);
|
|
CursorPos.Y:=XMLConfig.GetValue(Path+'CursorPos/Y',-1);
|
|
EditorIndex:=XMLConfig.GetValue(Path+'EditorIndex/Value',-1);
|
|
AFilename:=XMLConfig.GetValue(Path+'Filename/Value','');
|
|
if Assigned(fOnLoadSaveFilename) then
|
|
fOnLoadSaveFilename(AFilename,true);
|
|
fFilename:=AFilename;
|
|
fFormName:=XMLConfig.GetValue(Path+'FormName/Value','');
|
|
HasResources:=XMLConfig.GetValue(Path+'HasResources/Value',false);
|
|
fIsPartOfProject:=XMLConfig.GetValue(Path+'IsPartOfProject/Value',false);
|
|
Loaded:=XMLConfig.GetValue(Path+'Loaded/Value',false);
|
|
fReadOnly:=XMLConfig.GetValue(Path+'ReadOnly/Value',false);
|
|
AFilename:=XMLConfig.GetValue(Path+'ResourceFilename/Value','');
|
|
if Assigned(fOnLoadSaveFilename) then
|
|
fOnLoadSaveFilename(AFilename,true);
|
|
FResourceFilename:=AFilename;
|
|
if (FResourceFilename<>'')
|
|
and (FResourceFilename[length(FResourceFilename)]=PathDelim) then
|
|
FResourceFilename:='';
|
|
fSyntaxHighlighter:=StrToLazSyntaxHighlighter(XMLConfig.GetValue(
|
|
Path+'SyntaxHighlighter/Value',''));
|
|
fTopLine:=XMLConfig.GetValue(Path+'TopLine/Value',-1);
|
|
UnitName:=XMLConfig.GetValue(Path+'UnitName/Value','');
|
|
fBreakpoints.LoadFromXMLConfig(XMLConfig,Path);
|
|
end;
|
|
|
|
procedure TUnitInfo.SetUnitName(const NewUnitName:string);
|
|
var Allowed:boolean;
|
|
begin
|
|
if (fUnitName<>NewUnitName) and (NewUnitName<>'') then begin
|
|
Allowed:=true;
|
|
if Assigned(fOnUnitNameChange) then
|
|
fOnUnitNameChange(Self,fUnitName,NewUnitName,false,Allowed);
|
|
// (ignore Allowed)
|
|
if (fSource<>nil) then begin
|
|
CodeToolBoss.RenameSource(fSource,NewUnitName);
|
|
end;
|
|
fUnitName:=NewUnitName;
|
|
fModified:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.UpdateEditorIndexList;
|
|
begin
|
|
if Project<>nil then begin
|
|
Project.AddToOrRemoveFromEditorWithIndexList(Self);
|
|
end else begin
|
|
fNextUnitWithEditorIndex:=nil;
|
|
fPrevUnitWithEditorIndex:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.UpdateFormList;
|
|
begin
|
|
if Project<>nil then begin
|
|
Project.AddToOrRemoveFromFormList(Self);
|
|
end else begin
|
|
fNextUnitWithForm:=nil;
|
|
fPrevUnitWithForm:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.UpdateLoadedList;
|
|
begin
|
|
if Project<>nil then begin
|
|
Project.AddToOrRemoveFromLoadedList(Self);
|
|
end else begin
|
|
fNextLoadedUnit:=nil;
|
|
fPrevLoadedUnit:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.UpdateAutoRevertLockedList;
|
|
begin
|
|
if Project<>nil then begin
|
|
Project.AddToOrRemoveFromAutoRevertLockedList(Self);
|
|
end else begin
|
|
fNextAutoRevertLockedUnit:=nil;
|
|
fPrevAutoRevertLockedUnit:=nil;
|
|
end;
|
|
end;
|
|
|
|
function TUnitInfo.GetFileName: string;
|
|
begin
|
|
if fSource<>nil then Result:=fSource.Filename
|
|
else Result:=fFileName;
|
|
end;
|
|
|
|
function TUnitInfo.IsVirtual: boolean;
|
|
begin
|
|
if fSource<>nil then
|
|
Result:=fSource.IsVirtual
|
|
else
|
|
Result:=(fFileName<>ExpandFileName(fFileName));
|
|
end;
|
|
|
|
function TUnitInfo.IsMainUnit: boolean;
|
|
begin
|
|
Result:=(Project<>nil) and (Project.MainUnitInfo=Self);
|
|
end;
|
|
|
|
procedure TUnitInfo.IncreaseAutoRevertLock;
|
|
begin
|
|
inc(fAutoRevertLockCount);
|
|
if (fAutoRevertLockCount=1) then begin
|
|
// activate lock
|
|
if (Source<>nil) then
|
|
Source.LockAutoDiskRevert;
|
|
if Project<>nil then
|
|
Project.AddToOrRemoveFromAutoRevertLockedList(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.DecreaseAutoRevertLock;
|
|
begin
|
|
dec(fAutoRevertLockCount);
|
|
if (fAutoRevertLockCount=0) then begin
|
|
// deactivate lock
|
|
if (Source<>nil) then
|
|
Source.LockAutoDiskRevert;
|
|
if Project<>nil then
|
|
Project.AddToOrRemoveFromAutoRevertLockedList(Self);
|
|
end;
|
|
end;
|
|
|
|
function TUnitInfo.IsAutoRevertLocked: boolean;
|
|
begin
|
|
Result:=fAutoRevertLockCount>0;
|
|
end;
|
|
|
|
function TUnitInfo.ChangedOnDisk(CompareOnlyLoadSaveTime: boolean): boolean;
|
|
begin
|
|
Result:=(Source<>nil) and (Source.FileOnDiskHasChanged);
|
|
if Result
|
|
and (not CompareOnlyLoadSaveTime)
|
|
and FIgnoreFileDateOnDiskValid
|
|
and (FIgnoreFileDateOnDisk=Source.FileDateOnDisk) then
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TUnitInfo.IgnoreCurrentFileDateOnDisk;
|
|
begin
|
|
if Source<>nil then begin
|
|
FIgnoreFileDateOnDiskValid:=true;
|
|
FIgnoreFileDateOnDisk:=Source.FileDateOnDisk;
|
|
end
|
|
end;
|
|
|
|
function TUnitInfo.ShortFilename: string;
|
|
begin
|
|
if Project<>nil then begin
|
|
Result:=Project.RemoveProjectPathFromFilename(Filename);
|
|
end else begin
|
|
Result:=Filename;
|
|
end;
|
|
end;
|
|
|
|
function TUnitInfo.NeedsSaveToDisk: boolean;
|
|
begin
|
|
Result:=IsVirtual or Modified or ChangedOnDisk(true)
|
|
or (not FileExists(Filename));
|
|
end;
|
|
|
|
procedure TUnitInfo.SetSource(ABuffer: TCodeBuffer);
|
|
begin
|
|
if fSource=ABuffer then exit;
|
|
if (fSource<>nil) and IsAutoRevertLocked then
|
|
fSource.UnlockAutoDiskRevert;
|
|
fSource:=ABuffer;
|
|
FIgnoreFileDateOnDiskValid:=false;
|
|
if (fSource<>nil) then begin
|
|
if IsAutoRevertLocked then
|
|
fSource.LockAutoDiskRevert;
|
|
fFileName:=fSource.FileName;
|
|
end;
|
|
end;
|
|
|
|
procedure TUnitInfo.SetReadOnly(const NewValue: boolean);
|
|
begin
|
|
fReadOnly:=NewValue;
|
|
if fSource<>nil then
|
|
fSource.ReadOnly:=fReadOnly;
|
|
end;
|
|
|
|
procedure TUnitInfo.CreateStartCode(NewUnitType: TNewUnitType;
|
|
const NewUnitName: string);
|
|
var AResourceFilename :string;
|
|
NewSource, LE: string;
|
|
|
|
function Beautified(const s: string): string;
|
|
begin
|
|
Result:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.
|
|
BeautifyStatement(s,0);
|
|
end;
|
|
|
|
begin
|
|
if fSource=nil then exit;
|
|
NewSource:='';
|
|
LE:=EndOfLine;
|
|
if NewUnitType in [nuForm,nuUnit] then begin
|
|
fUnitName:=NewUnitName;
|
|
AResourceFilename:=fUnitName+ResourceFileExt;
|
|
NewSource:=Beautified(
|
|
'unit '+fUnitName+';'+LE
|
|
+LE
|
|
+'{$mode objfpc}{$H+}'+LE
|
|
++LE
|
|
+'interface'+LE
|
|
++LE
|
|
+'uses'+LE);
|
|
case NewUnitType of
|
|
nuUnit:
|
|
begin
|
|
NewSource:=NewSource+Beautified(
|
|
' Classes, SysUtils;'+LE
|
|
+LE
|
|
+'implementation'+LE);
|
|
end;
|
|
nuForm:
|
|
begin
|
|
NewSource:=NewSource+Beautified(
|
|
' Classes, SysUtils, Forms, Controls, Graphics, Dialogs, LResources;'+LE
|
|
+LE
|
|
+'type'+LE
|
|
+' T'+fFormName+' = class(TForm)'+LE
|
|
+' private'+LE);
|
|
NewSource:=NewSource
|
|
+' { private declarations }'+LE;
|
|
NewSource:=NewSource+Beautified(
|
|
+' public'+LE);
|
|
NewSource:=NewSource
|
|
+' { public declarations }'+LE;
|
|
NewSource:=NewSource+Beautified(
|
|
+' end;'+LE
|
|
+LE
|
|
+'var'+LE
|
|
+' '+fFormName+': T'+fFormName+';'+LE
|
|
+LE
|
|
+'implementation'+LE
|
|
+LE
|
|
+'initialization'+LE);
|
|
NewSource:=NewSource
|
|
+' {$I '+AResourceFilename+'}'+LE;
|
|
end;
|
|
end;
|
|
NewSource:=NewSource+Beautified(
|
|
+LE
|
|
+'end.'+LE
|
|
+LE);
|
|
end else if NewUnitType in [nuCustomProgram] then begin
|
|
NewSource:=NewSource+Beautified(
|
|
+'program CustomProgram;'+LE
|
|
+LE
|
|
+'{$mode objfpc}{$H+}'+LE
|
|
+LE
|
|
+'uses'+LE
|
|
+' Classes, SysUtils;'+LE
|
|
+LE
|
|
+'begin'+LE
|
|
+'end.'+LE
|
|
+LE);
|
|
end;
|
|
fSource.Source:=NewSource;
|
|
fModified:=true;
|
|
end;
|
|
|
|
function TUnitInfo.GetHasResources:boolean;
|
|
begin
|
|
Result:=fHasResources or (FormName<>'');
|
|
end;
|
|
|
|
procedure TUnitInfo.SetEditorIndex(const AValue: integer);
|
|
begin
|
|
if fEditorIndex=AValue then exit;
|
|
fEditorIndex:=AValue;
|
|
UpdateEditorIndexList;
|
|
end;
|
|
|
|
procedure TUnitInfo.SetForm(const AValue: TComponent);
|
|
begin
|
|
if fForm=AValue then exit;
|
|
fForm:=AValue;
|
|
UpdateFormList;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure TUnitInfo.SetLoaded(const AValue: Boolean);
|
|
|
|
Loaded is a flag, that is set, when a unit has finished loading into the
|
|
editor. It is saved to the project info file and a loaded unit will be
|
|
reloaded, when the project is opened.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TUnitInfo.SetLoaded(const AValue: Boolean);
|
|
begin
|
|
if fLoaded=AValue then exit;
|
|
fLoaded:=AValue;
|
|
if fLoaded then
|
|
IncreaseAutoRevertLock
|
|
else
|
|
DecreaseAutoRevertLock;
|
|
end;
|
|
|
|
procedure TUnitInfo.SetProject(const AValue: TProject);
|
|
begin
|
|
if FProject=AValue then exit;
|
|
if AValue=nil then begin
|
|
Project.RemoveFromEditorWithIndexList(Self);
|
|
Project.RemoveFromFormList(Self);
|
|
Project.RemoveFromLoadedList(Self);
|
|
Project.RemoveFromAutoRevertLockedList(Self);
|
|
end;
|
|
FProject:=AValue;
|
|
UpdateEditorIndexList;
|
|
UpdateFormList;
|
|
UpdateLoadedList;
|
|
UpdateAutoRevertLockedList;
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject Class
|
|
------------------------------------------------------------------------------}
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject Constructor
|
|
------------------------------------------------------------------------------}
|
|
constructor TProject.Create(TheProjectType: TProjectType);
|
|
var PrgUnitInfo: TUnitInfo;
|
|
NewSource: TStringList;
|
|
NewPrgBuf: TCodeBuffer;
|
|
begin
|
|
inherited Create;
|
|
|
|
Assert(False, 'Trace:Project Class Created');
|
|
xmlconfig := nil;
|
|
|
|
fProjectType:=TheProjectType;
|
|
|
|
fActiveEditorIndexAtStart := -1;
|
|
fBookmarks := TProjectBookmarkList.Create;
|
|
fCompilerOptions := TCompilerOptions.Create;
|
|
FFlags:=DefaultProjectFlags;
|
|
fIconPath := '';
|
|
fJumpHistory:=TProjectJumpHistory.Create;
|
|
fJumpHistory.OnCheckPosition:=@JumpHistoryCheckPosition;
|
|
fJumpHistory.OnLoadSaveFilename:=@OnLoadSaveFilename;
|
|
fMainUnit := -1;
|
|
fModified := false;
|
|
fOutputDirectory := '.';
|
|
fProjectInfoFile := '';
|
|
fRunParameterOptions:=TRunParamsOptions.Create;
|
|
fSrcPath := '';
|
|
fTargetFileExt := DefaultTargetFileExt;
|
|
fTitle := '';
|
|
fUnitList := TList.Create; // list of TUnitInfo
|
|
fUnitOutputDirectory := '.';
|
|
|
|
// create program source
|
|
NewSource:=TStringList.Create;
|
|
case fProjectType of
|
|
ptProgram, ptApplication, ptCustomProgram:
|
|
begin
|
|
NewPrgBuf:=CodeToolBoss.CreateFile(
|
|
'project1'+ProjectDefaultExt[fProjectType]);
|
|
PrgUnitInfo:=TUnitInfo.Create(NewPrgBuf);
|
|
PrgUnitInfo.IsPartOfProject:=true;
|
|
PrgUnitInfo.SyntaxHighlighter:=
|
|
ExtensionToLazSyntaxHighlighter(ProjectDefaultExt[fProjectType]);
|
|
AddUnit(PrgUnitInfo,false);
|
|
MainUnit:=0;
|
|
with NewSource do begin
|
|
Add('program Project1;');
|
|
Add('');
|
|
Add('{$mode objfpc}{$H+}');
|
|
Add('');
|
|
Add('uses');
|
|
case fProjectType of
|
|
ptProgram, ptCustomProgram: Add(' Classes;');
|
|
ptApplication: Add(' Forms;');
|
|
else
|
|
Add(' { add your units here };');
|
|
end;
|
|
Add('');
|
|
Add('begin');
|
|
case fProjectType of
|
|
ptApplication:
|
|
begin
|
|
Add(' Application.Initialize;');
|
|
Add(' Application.Run;');
|
|
end;
|
|
end;
|
|
Add('end.');
|
|
Add('');
|
|
end;
|
|
MainUnitInfo.Source.Assign(NewSource);
|
|
end;
|
|
end;
|
|
NewSource.Free;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject Destructor
|
|
------------------------------------------------------------------------------}
|
|
destructor TProject.Destroy;
|
|
begin
|
|
Clear;
|
|
fBookmarks.Free;
|
|
if (xmlconfig <> nil) then xmlconfig.Free;
|
|
fUnitList.Free;
|
|
fJumpHistory.Free;
|
|
fRunParameterOptions.Free;
|
|
fCompilerOptions.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject WriteProject
|
|
------------------------------------------------------------------------------}
|
|
function TProject.WriteProject: TModalResult;
|
|
|
|
procedure SaveFlags;
|
|
var f: TProjectFlag;
|
|
begin
|
|
for f:=Low(TProjectFlag) to High(TProjectFlag) do begin
|
|
xmlconfig.SetValue('ProjectOptions/General/Flags/'
|
|
+ProjectFlagNames[f]+'/Value', f in Flags);
|
|
end;
|
|
end;
|
|
|
|
function UnitMustBeSaved(i: integer): boolean;
|
|
begin
|
|
Result:=false;
|
|
if (pfSaveOnlyProjectUnits in Flags) and (not Units[i].IsPartOfProject) then
|
|
exit;
|
|
if (not (pfSaveClosedUnits in Flags)) and (not Units[i].IsPartOfProject)
|
|
and (not Units[i].Loaded) then exit;
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure SaveUnits;
|
|
var i, SaveUnitCount: integer;
|
|
begin
|
|
SaveUnitCount:=0;
|
|
for i:=0 to UnitCount-1 do begin
|
|
if UnitMustBeSaved(i) then begin
|
|
Units[i].SaveToXMLConfig(
|
|
xmlconfig,'ProjectOptions/Units/Unit'+IntToStr(SaveUnitCount)+'/');
|
|
inc(SaveUnitCount);
|
|
end;
|
|
end;
|
|
xmlconfig.SetValue('ProjectOptions/Units/Count',SaveUnitCount);
|
|
end;
|
|
|
|
|
|
var
|
|
confPath: String;
|
|
AText, ACaption: string;
|
|
begin
|
|
Result := mrCancel;
|
|
|
|
confPath := ProjectInfoFile;
|
|
if Assigned(fOnFileBackup) then begin
|
|
Result:=fOnFileBackup(confPath,true);
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
xmlconfig := TXMLConfig.Create(SetDirSeparators(confPath));
|
|
|
|
try
|
|
repeat
|
|
try
|
|
xmlconfig.SetValue('ProjectOptions/General/ProjectType/Value',
|
|
ProjectTypeNames[ProjectType]);
|
|
SaveFlags;
|
|
xmlconfig.SetValue('ProjectOptions/General/MainUnit/Value', MainUnit);
|
|
xmlconfig.SetValue('ProjectOptions/General/ActiveEditorIndexAtStart/Value'
|
|
,ActiveEditorIndexAtStart);
|
|
xmlconfig.SetValue('ProjectOptions/General/IconPath/Value', IconPath);
|
|
xmlconfig.SetValue('ProjectOptions/General/TargetFileExt/Value'
|
|
,TargetFileExt);
|
|
xmlconfig.SetValue('ProjectOptions/General/Title/Value', Title);
|
|
xmlconfig.SetValue('ProjectOptions/General/OutputDirectory/Value'
|
|
,OutputDirectory);
|
|
xmlconfig.SetValue('ProjectOptions/General/UnitOutputDirectory/Value'
|
|
,UnitOutputDirectory);
|
|
fBookmarks.SaveToXMLConfig(xmlconfig,'ProjectOptions/');
|
|
fJumpHistory.DeleteInvalidPositions;
|
|
fJumpHistory.SaveToXMLConfig(xmlconfig,'ProjectOptions/');
|
|
xmlconfig.SetValue('ProjectOptions/General/SrcPath/Value',fSrcPath);
|
|
|
|
SaveUnits;
|
|
|
|
// Save the compiler options
|
|
CompilerOptions.XMLConfigFile := xmlconfig;
|
|
CompilerOptions.ProjectFile := confPath;
|
|
CompilerOptions.SaveCompilerOptions(true);
|
|
|
|
// save the Run Parameter Options
|
|
RunParameterOptions.Save(xmlconfig,'ProjectOptions/');
|
|
|
|
xmlconfig.Flush;
|
|
Modified:=false;
|
|
except
|
|
ACaption:='Write error';
|
|
AText:='Unable to write to file "'+confPath+'".';
|
|
Result:=Application.MessageBox(PChar(ACaption),PChar(AText),MB_ABORTRETRYIGNORE);
|
|
if Result=mrIgnore then Result:=mrOk;
|
|
if Result=mrAbort then exit;
|
|
end;
|
|
until Result<>mrRetry;
|
|
finally
|
|
xmlconfig.Free;
|
|
xmlconfig:=nil;
|
|
end;
|
|
Result := mrOk;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject ReadProject
|
|
------------------------------------------------------------------------------}
|
|
function TProject.ReadProject(LPIFilename: string): TModalResult;
|
|
|
|
procedure LoadFlags;
|
|
var f: TProjectFlag;
|
|
begin
|
|
FFlags:=[];
|
|
for f:=Low(TProjectFlag) to High(TProjectFlag) do begin
|
|
if xmlconfig.GetValue('ProjectOptions/General/Flags/'
|
|
+ProjectFlagNames[f]+'/Value', f in DefaultProjectFlags)
|
|
then
|
|
Include(FFlags,f)
|
|
else
|
|
Exclude(FFlags,f);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
NewUnitInfo: TUnitInfo;
|
|
NewUnitCount,i: integer;
|
|
begin
|
|
Result := mrCancel;
|
|
Clear;
|
|
|
|
ProjectInfoFile:=LPIFilename;
|
|
try
|
|
xmlconfig := TXMLConfig.Create(ProjectInfoFile);
|
|
except
|
|
MessageDlg('Unable to read the project info file'#13'"'+ProjectInfoFile+'".'
|
|
,mtError,[mbOk],0);
|
|
Result:=mrCancel;
|
|
exit;
|
|
end;
|
|
|
|
try
|
|
ProjectType := ProjectTypeNameToType(xmlconfig.GetValue(
|
|
'ProjectOptions/General/ProjectType/Value', ''));
|
|
LoadFlags;
|
|
MainUnit := xmlconfig.GetValue('ProjectOptions/General/MainUnit/Value', -1);
|
|
ActiveEditorIndexAtStart := xmlconfig.GetValue(
|
|
'ProjectOptions/General/ActiveEditorIndexAtStart/Value', -1);
|
|
IconPath := xmlconfig.GetValue('ProjectOptions/General/IconPath/Value', './');
|
|
TargetFileExt := xmlconfig.GetValue(
|
|
'ProjectOptions/General/TargetFileExt/Value', DefaultTargetFileExt);
|
|
Title := xmlconfig.GetValue('ProjectOptions/General/Title/Value', '');
|
|
OutputDirectory := xmlconfig.GetValue(
|
|
'ProjectOptions/General/OutputDirectory/Value', '.');
|
|
UnitOutputDirectory := xmlconfig.GetValue(
|
|
'ProjectOptions/General/UnitOutputDirectory/Value', '.');
|
|
fBookmarks.LoadFromXMLConfig(xmlconfig,'ProjectOptions/');
|
|
fJumpHistory.LoadFromXMLConfig(xmlconfig,'ProjectOptions/');
|
|
FSrcPath := xmlconfig.GetValue('ProjectOptions/General/SrcPath/Value','');
|
|
|
|
NewUnitCount:=xmlconfig.GetValue('ProjectOptions/Units/Count',0);
|
|
for i := 0 to NewUnitCount - 1 do begin
|
|
NewUnitInfo:=TUnitInfo.Create(nil);
|
|
AddUnit(NewUnitInfo,false);
|
|
NewUnitInfo.LoadFromXMLConfig(
|
|
xmlconfig,'ProjectOptions/Units/Unit'+IntToStr(i)+'/');
|
|
end;
|
|
|
|
// Load the compiler options
|
|
CompilerOptions.XMLConfigFile := xmlconfig;
|
|
CompilerOptions.ProjectFile := MainFilename;
|
|
CompilerOptions.LoadCompilerOptions(true);
|
|
CreateProjectDefineTemplate(CompilerOptions,FSrcPath);
|
|
|
|
// load the Run Parameter Options
|
|
RunParameterOptions.Load(xmlconfig,'ProjectOptions/');
|
|
|
|
CodeToolBoss.GlobalValues.Variables[ExternalMacroStart+'ProjectDir']:=
|
|
ProjectDirectory;
|
|
CodeToolBoss.DefineTree.ClearCache;
|
|
finally
|
|
xmlconfig.Free;
|
|
xmlconfig:=nil;
|
|
end;
|
|
|
|
Result := mrOk;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject AddUnit
|
|
------------------------------------------------------------------------------}
|
|
procedure TProject.AddUnit(AUnit: TUnitInfo; AddToProjectFile:boolean);
|
|
var
|
|
ShortUnitName:string;
|
|
NewIndex: integer;
|
|
begin
|
|
if (AUnit = nil) then exit;
|
|
NewIndex:=UnitCount;
|
|
fUnitList.Add(AUnit);
|
|
AUnit.Project:=Self;
|
|
AUnit.OnFileBackup:=@OnUnitFileBackup;
|
|
AUnit.OnLoadSaveFilename:=@OnLoadSaveFilename;
|
|
AUnit.OnUnitNameChange:=@OnUnitNameChange;
|
|
|
|
// check if this is the new Main Unit
|
|
if MainUnit=NewIndex then
|
|
MainUnitInfo.IncreaseAutoRevertLock;
|
|
|
|
if AddToProjectFile and (MainUnit>=0) and (MainUnit<>NewIndex) then begin
|
|
// add unit to uses section
|
|
ShortUnitName:=AUnit.UnitName;
|
|
if (ShortUnitName<>'') and (not UnitIsUsed(ShortUnitName)) then
|
|
CodeToolBoss.AddUnitToMainUsesSection(MainUnitInfo.Source,
|
|
ShortUnitName,'');
|
|
end;
|
|
Modified:=true;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject RemoveUnit
|
|
------------------------------------------------------------------------------}
|
|
procedure TProject.RemoveUnit(Index: integer);
|
|
var
|
|
OldUnitInfo: TUnitInfo;
|
|
begin
|
|
if (Index<0) or (Index>=UnitCount) then begin
|
|
raise Exception.Create('ERROR: TProject.RemoveUnit index out of bounds');
|
|
end;
|
|
if (Index=MainUnit) then begin
|
|
raise Exception.Create('ERROR: TProject.RemoveUnit index = MainUnit');
|
|
end;
|
|
OldUnitInfo:=Units[Index];
|
|
Modified:=true;
|
|
|
|
if (MainUnit>=0) then begin
|
|
// remove unit from uses section and from createforms in program file
|
|
if (OldUnitInfo.IsPartOfProject) then begin
|
|
if (OldUnitInfo.UnitName<>'') then
|
|
CodeToolBoss.RemoveUnitFromAllUsesSections(Units[MainUnit].Source,
|
|
OldUnitInfo.UnitName);
|
|
if (OldUnitInfo.FormName<>'') then
|
|
CodeToolBoss.RemoveCreateFormStatement(Units[MainUnit].Source,
|
|
OldUnitInfo.FormName);
|
|
end;
|
|
end;
|
|
|
|
// delete bookmarks of this unit
|
|
if OldUnitInfo.EditorIndex>=0 then
|
|
Bookmarks.DeleteAllWithEditorIndex(OldUnitInfo.EditorIndex);
|
|
|
|
// adjust MainUnit
|
|
if MainUnit>=Index then dec(fMainUnit);
|
|
|
|
// delete unitinfo instance
|
|
OldUnitInfo.Free;
|
|
fUnitList.Delete(Index);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
TProject Clear
|
|
------------------------------------------------------------------------------}
|
|
procedure TProject.Clear;
|
|
var i:integer;
|
|
begin
|
|
if xmlconfig<>nil then xmlconfig.Free;
|
|
xmlconfig:=nil;
|
|
|
|
for i:=0 to UnitCount-1 do Units[i].Free;
|
|
fUnitList.Clear;
|
|
|
|
fRunParameterOptions.Clear;
|
|
|
|
fActiveEditorIndexAtStart := -1;
|
|
fBookmarks.Clear;
|
|
fCompilerOptions.Clear;
|
|
fIconPath := '';
|
|
fJumpHistory.Clear;
|
|
fMainUnit := -1;
|
|
fModified := false;
|
|
fOutputDirectory := '.';
|
|
fProjectInfoFile := '';
|
|
fSrcPath := '';
|
|
fTargetFileExt := {$IFDEF win32}'.exe'{$ELSE}''{$ENDIF};
|
|
fTitle := '';
|
|
fUnitOutputDirectory := '.';
|
|
end;
|
|
|
|
function TProject.GetUnits(Index:integer):TUnitInfo;
|
|
begin
|
|
Result:=TUnitInfo(fUnitList[Index]);
|
|
end;
|
|
|
|
procedure TProject.SetFlags(const AValue: TProjectFlags);
|
|
begin
|
|
FFlags:=AValue;
|
|
end;
|
|
|
|
procedure TProject.SetMainUnit(const AValue: Integer);
|
|
begin
|
|
if fMainUnit=AValue then exit;
|
|
if (fMainUnit>=0) and (fMainUnit<UnitCount) then begin
|
|
MainUnitInfo.DecreaseAutoRevertLock;
|
|
end;
|
|
fMainUnit:=AValue;
|
|
if (fMainUnit>=0) and (fMainUnit<UnitCount) then begin
|
|
MainUnitInfo.IncreaseAutoRevertLock;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.SetUnits(Index:integer; AUnitInfo: TUnitInfo);
|
|
begin
|
|
if AUnitInfo<>TUnitInfo(fUnitList[Index]) then begin
|
|
fUnitList[Index]:=AUnitInfo;
|
|
Modified:=true;
|
|
if AUnitInfo<>nil then AUnitInfo.Project:=Self;
|
|
end;
|
|
end;
|
|
|
|
function TProject.UnitCount:integer;
|
|
begin
|
|
Result:=fUnitList.Count;
|
|
end;
|
|
|
|
function TProject.NewUniqueUnitName(NewUnitType:TNewUnitType):string;
|
|
|
|
function ExpandedUnitname(const AnUnitName:string):string;
|
|
begin
|
|
Result:=uppercase(ExtractFileNameOnly(AnUnitName));
|
|
end;
|
|
|
|
function UnitNameExists(const AnUnitName:string):boolean;
|
|
var i:integer;
|
|
ExpName:string;
|
|
begin
|
|
Result:=true;
|
|
ExpName:=ExpandedUnitName(AnUnitName);
|
|
if ExtractFileNameOnly(fProjectInfoFile)=Expname then exit;
|
|
for i:=0 to UnitCount-1 do
|
|
if (Units[i].IsPartOfProject)
|
|
and (ExpandedUnitName(Units[i].FileName)=ExpName) then
|
|
exit;
|
|
Result:=false;
|
|
end;
|
|
|
|
// NewUniqueUnitName(NewUnitType:TNewUnitType)
|
|
var u:integer;
|
|
Prefix: string;
|
|
begin
|
|
u:=1;
|
|
case NewUnitType of
|
|
nuForm,nuUnit: Prefix:='unit';
|
|
else Prefix:='text'
|
|
end;
|
|
while (UnitNameExists(Prefix+IntToStr(u))) do inc(u);
|
|
Result:=Prefix+IntToStr(u);
|
|
end;
|
|
|
|
function TProject.NewUniqueFormName(NewUnitType:TNewUnitType):string;
|
|
|
|
function FormNameExists(const AFormName: string): boolean;
|
|
var i: integer;
|
|
begin
|
|
Result:=true;
|
|
for i:=0 to UnitCount-1 do begin
|
|
if (Units[i].Form<>nil) then begin
|
|
if AnsiCompareText(Units[i].Form.Name,AFormName)=0 then exit;
|
|
if AnsiCompareText(Units[i].Form.ClassName,'T'+AFormName)=0 then exit;
|
|
end else if (Units[i].FormName<>'')
|
|
and ((Units[i].IsPartOfProject) or (Units[i].Loaded)) then begin
|
|
if AnsiCompareText(Units[i].FormName,AFormName)=0 then exit;
|
|
end;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
// NewUniqueFormName(NewUnitType:TNewUnitType)
|
|
var i: integer;
|
|
Prefix: string;
|
|
begin
|
|
i:=1;
|
|
case NewUnitType of
|
|
nuForm, nuUnit: Prefix:='Form'
|
|
else
|
|
Prefix:='form';
|
|
end;
|
|
while (FormNameExists(Prefix+IntToStr(i))) do inc(i);
|
|
Result:=Prefix+IntToStr(i);
|
|
end;
|
|
|
|
function TProject.AddCreateFormToProjectFile(
|
|
const AClassName,AName:string):boolean;
|
|
begin
|
|
Result:=CodeToolBoss.AddCreateFormStatement(Units[MainUnit].Source,
|
|
AClassName,AName);
|
|
if Result then Modified:=true;
|
|
end;
|
|
|
|
function TProject.RemoveCreateFormFromProjectFile(
|
|
const AClassName,AName:string):boolean;
|
|
begin
|
|
Result:=CodeToolBoss.RemoveCreateFormStatement(Units[MainUnit].Source,
|
|
AName);
|
|
if Result then Modified:=true;
|
|
end;
|
|
|
|
function TProject.FormIsCreatedInProjectFile(
|
|
const AClassname,AName:string):boolean;
|
|
var p: integer;
|
|
begin
|
|
Result:=(CodeToolBoss.FindCreateFormStatement(Units[MainUnit].Source,
|
|
1,AClassName,AName,p)=0);
|
|
end;
|
|
|
|
function TProject.IndexOfUnitWithName(const AnUnitName:string;
|
|
OnlyProjectUnits:boolean; IgnoreUnit: TUnitInfo):integer;
|
|
begin
|
|
Result:=UnitCount-1;
|
|
while (Result>=0) do begin
|
|
if ((OnlyProjectUnits and Units[Result].IsPartOfProject)
|
|
or (not OnlyProjectUnits))
|
|
and (IgnoreUnit<>Units[Result]) then begin
|
|
if (AnsiCompareText(Units[Result].UnitName,AnUnitName)=0) then
|
|
exit;
|
|
end;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
|
|
function TProject.IndexOfUnitWithForm(AForm: TComponent;
|
|
OnlyProjectUnits:boolean; IgnoreUnit: TUnitInfo):integer;
|
|
begin
|
|
Result:=UnitCount-1;
|
|
while (Result>=0) do begin
|
|
if (OnlyProjectUnits and Units[Result].IsPartOfProject)
|
|
or (not OnlyProjectUnits)
|
|
and (IgnoreUnit<>Units[Result]) then begin
|
|
if Units[Result].Form=AForm then
|
|
exit;
|
|
end;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
|
|
function TProject.IndexOfUnitWithFormName(const AFormName: string;
|
|
OnlyProjectUnits: boolean; IgnoreUnit: TUnitInfo): integer;
|
|
begin
|
|
Result:=UnitCount-1;
|
|
while (Result>=0) do begin
|
|
if (OnlyProjectUnits and Units[Result].IsPartOfProject)
|
|
or (not OnlyProjectUnits)
|
|
and (IgnoreUnit<>Units[Result]) then begin
|
|
if (AnsiCompareText(Units[Result].FormName,AFormName)=0)
|
|
or ((Units[Result].Form<>nil)
|
|
and (AnsiCompareText(Units[Result].Form.Name,AFormName)=0))
|
|
then
|
|
exit;
|
|
end;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
|
|
function TProject.UnitWithEditorIndex(Index:integer):TUnitInfo;
|
|
begin
|
|
Result:=fFirstUnitWithEditorIndex;
|
|
while (Result<>nil) and (Result.EditorIndex<>Index) do begin
|
|
Result:=Result.fNextUnitWithEditorIndex;
|
|
end;
|
|
end;
|
|
|
|
function TProject.UnitIsUsed(const ShortUnitName:string):boolean;
|
|
var NamePos, InPos: integer;
|
|
begin
|
|
Result:=CodeToolBoss.FindUnitInAllUsesSections(Units[MainUnit].Source,
|
|
ShortUnitName,NamePos,InPos);
|
|
end;
|
|
|
|
function TProject.GetResourceFile(AnUnitInfo: TUnitInfo;
|
|
Index:integer): TCodeBuffer;
|
|
var i, LinkIndex: integer;
|
|
begin
|
|
LinkIndex:=-1;
|
|
i:=0;
|
|
Result:=nil;
|
|
while (i<Index) do begin
|
|
inc(i);
|
|
Result:=CodeToolBoss.FindNextResourceFile(AnUnitInfo.Source,LinkIndex);
|
|
end;
|
|
end;
|
|
|
|
function TProject.SearchFile(
|
|
const Filename,SearchPaths,InitialDir:string):string;
|
|
var StartPos,EndPos:integer;
|
|
CurPath: string;
|
|
OldDir: string;
|
|
begin
|
|
OldDir:=GetCurrentDir;
|
|
SetCurrentDir(ExtractFilePath(InitialDir));
|
|
try
|
|
StartPos:=1;
|
|
while StartPos<=length(SearchPaths) do begin
|
|
EndPos:=Startpos;
|
|
while (EndPos<=length(SearchPaths)) and (SearchPaths[EndPos]<>';') do
|
|
inc(EndPos);
|
|
CurPath:=copy(SearchPaths,Startpos,EndPos-StartPos);
|
|
if CurPath<>'' then begin
|
|
if CurPath[length(CurPath)]<>PathDelim then
|
|
CurPath:=CurPath+PathDelim;
|
|
Result:=CurPath+Filename;
|
|
if FileExists(Result) then exit;
|
|
end;
|
|
StartPos:=EndPos+1;
|
|
end;
|
|
finally
|
|
SetCurrentDir(OldDir);
|
|
end;
|
|
Result:='';
|
|
end;
|
|
|
|
function TProject.GetMainResourceFilename(AnUnitInfo: TUnitInfo):string;
|
|
var CodeBuf: TCodeBuffer;
|
|
begin
|
|
CodeBuf:=GetResourceFile(AnUnitInfo,1);
|
|
if CodeBuf=nil then begin
|
|
if AnUnitInfo.Filename='' then exit;
|
|
Result:=ChangeFileExt(AnUnitInfo.Filename,ResourceFileExt);
|
|
exit;
|
|
end else
|
|
Result:=CodeBuf.Filename;
|
|
end;
|
|
|
|
function TProject.IsVirtual: boolean;
|
|
begin
|
|
Result:=(MainUnit>=0) and Units[MainUnit].IsVirtual;
|
|
end;
|
|
|
|
function TProject.IndexOf(AUnitInfo: TUnitInfo):integer;
|
|
begin
|
|
Result:=UnitCount-1;
|
|
while (Result>=0) and (Units[Result]<>AUnitInfo) do dec(Result);
|
|
end;
|
|
|
|
procedure TProject.CloseEditorIndex(EditorIndex:integer);
|
|
var i:integer;
|
|
AnUnitInfo, NextUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitInfo:=fFirstUnitWithEditorIndex;
|
|
while AnUnitInfo<>nil do begin
|
|
NextUnitInfo:=AnUnitInfo.fNextUnitWithEditorIndex;
|
|
if AnUnitInfo.EditorIndex=EditorIndex then
|
|
AnUnitInfo.EditorIndex:=-1
|
|
else if AnUnitInfo.EditorIndex>EditorIndex then
|
|
AnUnitInfo.EditorIndex:=AnUnitInfo.EditorIndex-1;
|
|
AnUnitInfo:=NextUnitInfo;
|
|
end;
|
|
i:=Bookmarks.Count-1;
|
|
while (i>=0) do begin
|
|
if (Bookmarks[i].EditorIndex=EditorIndex) then
|
|
Bookmarks.Delete(i)
|
|
else
|
|
Bookmarks[i].EditorIndex:=Bookmarks[i].EditorIndex-1;
|
|
dec(i);
|
|
end;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TProject.InsertEditorIndex(EditorIndex:integer);
|
|
var i:integer;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitInfo:=fFirstUnitWithEditorIndex;
|
|
while AnUnitInfo<>nil do begin
|
|
if AnUnitInfo.EditorIndex>=EditorIndex then
|
|
AnUnitInfo.EditorIndex:=AnUnitInfo.EditorIndex+1;
|
|
AnUnitInfo:=AnUnitInfo.fNextUnitWithEditorIndex;
|
|
end;
|
|
i:=Bookmarks.Count-1;
|
|
while (i>=0) do begin
|
|
if (Bookmarks[i].EditorIndex>=EditorIndex) then
|
|
Bookmarks[i].EditorIndex:=Bookmarks[i].EditorIndex+1;
|
|
dec(i);
|
|
end;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TProject.AddToOrRemoveFromEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
if AnUnitInfo.EditorIndex<0 then begin
|
|
RemoveFromEditorWithIndexList(AnUnitInfo);
|
|
end else begin
|
|
AddToEditorWithIndexList(AnUnitInfo);
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.AddToOrRemoveFromFormList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
if AnUnitInfo.Form=nil then begin
|
|
RemoveFromFormList(AnUnitInfo);
|
|
end else begin
|
|
AddToFormList(AnUnitInfo);
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.AddToOrRemoveFromLoadedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
if not AnUnitInfo.Loaded then begin
|
|
RemoveFromLoadedList(AnUnitInfo);
|
|
end else begin
|
|
AddToLoadedList(AnUnitInfo);
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.AddToOrRemoveFromAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
if not AnUnitInfo.IsAutoRevertLocked then begin
|
|
RemoveFromAutoRevertLockedList(AnUnitInfo);
|
|
end else begin
|
|
AddToAutoRevertLockedList(AnUnitInfo);
|
|
end;
|
|
end;
|
|
|
|
function TProject.GetTargetFilename: string;
|
|
begin
|
|
Result:=fCompilerOptions.TargetFilename;
|
|
end;
|
|
|
|
procedure TProject.SetTargetFilename(const NewTargetFilename: string);
|
|
begin
|
|
fCompilerOptions.TargetFilename:=NewTargetFilename;
|
|
end;
|
|
|
|
function TProject.GetMainFilename: String;
|
|
begin
|
|
if MainUnit>=0 then Result:=Units[MainUnit].Filename
|
|
else Result:='';
|
|
end;
|
|
|
|
function TProject.GetMainUnitInfo: TUnitInfo;
|
|
begin
|
|
if (MainUnit>=0) and (MainUnit<UnitCount) then
|
|
Result:=Units[MainUnit]
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TProject.GetProjectInfoFile:string;
|
|
begin
|
|
Result:=fProjectInfoFile;
|
|
end;
|
|
|
|
procedure TProject.SetProjectInfoFile(const NewFilename:string);
|
|
begin
|
|
if NewFilename='' then exit;
|
|
if (AnsiCompareText(fTitle,ExtractFileNameOnly(fProjectInfoFile))=0)
|
|
or (fProjectInfoFile='') or (fTitle='') then
|
|
fTitle:=ExtractFileNameOnly(NewFilename);
|
|
fProjectInfoFile:=NewFilename;
|
|
|
|
Modified:=true;
|
|
end;
|
|
|
|
function TProject.OnUnitFileBackup(const Filename:string;
|
|
IsPartOfProject:boolean):TModalResult;
|
|
begin
|
|
if Assigned(fOnFileBackup) then
|
|
Result:=fOnFileBackup(Filename,IsPartOfProject)
|
|
else
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
procedure TProject.OnLoadSaveFilename(var AFilename:string; Load:boolean);
|
|
var ProjectPath:string;
|
|
begin
|
|
ProjectPath:=ProjectDirectory;
|
|
if ProjectPath='' then ProjectPath:=GetCurrentDir;
|
|
DoDirSeparators(AFilename);
|
|
AFilename:=TrimFilename(AFilename);
|
|
if Load then begin
|
|
// make filename absolute
|
|
if (AFilename<>'') and (not FilenameIsAbsolute(AFilename)) then
|
|
AFilename:=ProjectPath+AFilename;
|
|
end else begin
|
|
// try making filename relative to project file
|
|
if (AFilename<>'') and FilenameIsAbsolute(AFilename)
|
|
and (CompareFileNames(copy(AFilename,1,length(ProjectPath)),ProjectPath)=0)
|
|
then
|
|
AFilename:=copy(AFilename,length(ProjectPath)+1,
|
|
length(AFilename)-length(ProjectPath));
|
|
end;
|
|
end;
|
|
|
|
function TProject.RemoveProjectPathFromFilename(
|
|
const AFilename: string): string;
|
|
var ProjectPath:string;
|
|
begin
|
|
ProjectPath:=ProjectDirectory;
|
|
if ProjectPath='' then ProjectPath:=GetCurrentDir;
|
|
Result:=AFilename;
|
|
DoDirSeparators(Result);
|
|
// try making filename relative to project file
|
|
if FilenameIsAbsolute(Result)
|
|
and (CompareFileNames(copy(Result,1,length(ProjectPath)),ProjectPath)=0)
|
|
then
|
|
Result:=copy(Result,length(ProjectPath)+1,
|
|
length(Result)-length(ProjectPath));
|
|
end;
|
|
|
|
function TProject.ProjectDirectory: string;
|
|
begin
|
|
Result:=ExtractFilePath(ProjectInfoFile);
|
|
end;
|
|
|
|
function TProject.FileIsInProjectDir(const AFilename: string): boolean;
|
|
var ProjectDir, FilePath: string;
|
|
begin
|
|
if FilenameIsAbsolute(AFilename) then begin
|
|
if (not IsVirtual) then begin
|
|
ProjectDir:=ProjectDirectory;
|
|
FilePath:=LeftStr(AFilename,length(ProjectDir));
|
|
Result:=(CompareFileNames(ProjectDir,FilePath)=0);
|
|
end else
|
|
Result:=false;
|
|
end else
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TProject.GetUnitsChangedOnDisk(var AnUnitList: TList);
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
AnUnitList:=nil;
|
|
AnUnitInfo:=fFirstAutoRevertLockedUnit;
|
|
while (AnUnitInfo<>nil) do begin
|
|
if AnUnitInfo.ChangedOnDisk(false) then begin
|
|
if AnUnitList=nil then
|
|
AnUnitList:=TList.Create;
|
|
AnUnitList.Add(AnUnitInfo);
|
|
end;
|
|
AnUnitInfo:=AnUnitInfo.fNextAutoRevertLockedUnit;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.OnUnitNameChange(AnUnitInfo: TUnitInfo;
|
|
const OldUnitName, NewUnitName: string; CheckIfAllowed: boolean;
|
|
var Allowed: boolean);
|
|
var i:integer;
|
|
begin
|
|
if AnUnitInfo.IsPartOfProject then begin
|
|
if CheckIfAllowed then begin
|
|
// check if no other project unit has this name
|
|
for i:=0 to UnitCount-1 do begin
|
|
if (Units[i].IsPartOfProject)
|
|
and (Units[i]<>AnUnitInfo) and (Units[i].UnitName<>'')
|
|
and (lowercase(Units[i].UnitName)=lowercase(NewUnitName)) then begin
|
|
Allowed:=false;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
if (OldUnitName<>'') and (ProjectType in [ptProgram, ptApplication]) then
|
|
begin
|
|
// rename unit in program uses section
|
|
CodeToolBoss.RenameUsedUnit(Units[MainUnit].Source
|
|
,OldUnitName,NewUnitName,'');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TProject.JumpHistoryCheckPosition(
|
|
APosition:TProjectJumpHistoryPosition): boolean;
|
|
var i: integer;
|
|
begin
|
|
i:=IndexOfFilename(APosition.Filename);
|
|
Result:=(i>=0) and (Units[i].EditorIndex>=0);
|
|
end;
|
|
|
|
function TProject.SomethingModified: boolean;
|
|
var i: integer;
|
|
begin
|
|
Result:=Modified;
|
|
for i:=0 to UnitCount-1 do Result:=Result or Units[i].Modified;
|
|
end;
|
|
|
|
Function TProject.UnitWithForm(AForm : TComponent) : TUnitInfo;
|
|
begin
|
|
Result:=fFirstUnitWithForm;
|
|
while (Result<>nil) and (Result.Form<>AForm) do
|
|
Result:=Result.fNextUnitWithForm;
|
|
end;
|
|
|
|
function TProject.IndexOfFilename(const AFilename: string): integer;
|
|
begin
|
|
Result:=UnitCount-1;
|
|
while (Result>=0) do begin
|
|
if CompareFilenames(AFilename,Units[Result].Filename)=0 then exit;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.SetSrcPath(const NewSrcPath: string);
|
|
begin
|
|
if FSrcPath=NewSrcPath then exit;
|
|
fSrcPath:=NewSrcPath;
|
|
end;
|
|
|
|
procedure TProject.AddToEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// add to list if AnUnitInfo is not in list
|
|
if (fFirstUnitWithEditorIndex<>AnUnitInfo)
|
|
and (AnUnitInfo.fNextUnitWithEditorIndex=nil)
|
|
and (AnUnitInfo.fPrevUnitWithEditorIndex=nil) then begin
|
|
AnUnitInfo.fNextUnitWithEditorIndex:=fFirstUnitWithEditorIndex;
|
|
AnUnitInfo.fPrevUnitWithEditorIndex:=nil;
|
|
fFirstUnitWithEditorIndex:=AnUnitInfo;
|
|
if AnUnitInfo.fNextUnitWithEditorIndex<>nil then
|
|
AnUnitInfo.fNextUnitWithEditorIndex.fPrevUnitWithEditorIndex:=AnUnitInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.RemoveFromEditorWithIndexList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// remove from list if AnUnitInfo is in list
|
|
if fFirstUnitWithEditorIndex=AnUnitInfo then
|
|
fFirstUnitWithEditorIndex:=AnUnitInfo.fNextUnitWithEditorIndex;
|
|
if AnUnitInfo.fNextUnitWithEditorIndex<>nil then
|
|
AnUnitInfo.fNextUnitWithEditorIndex.fPrevUnitWithEditorIndex:=
|
|
AnUnitInfo.fPrevUnitWithEditorIndex;
|
|
if AnUnitInfo.fPrevUnitWithEditorIndex<>nil then
|
|
AnUnitInfo.fPrevUnitWithEditorIndex.fNextUnitWithEditorIndex:=
|
|
AnUnitInfo.fNextUnitWithEditorIndex;
|
|
AnUnitInfo.fNextUnitWithEditorIndex:=nil;
|
|
AnUnitInfo.fPrevUnitWithEditorIndex:=nil;
|
|
end;
|
|
|
|
procedure TProject.AddToFormList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// add to list if AnUnitInfo is not in list
|
|
if (fFirstUnitWithForm<>AnUnitInfo)
|
|
and (AnUnitInfo.fNextUnitWithForm=nil)
|
|
and (AnUnitInfo.fPrevUnitWithForm=nil) then begin
|
|
AnUnitInfo.fNextUnitWithForm:=fFirstUnitWithForm;
|
|
AnUnitInfo.fPrevUnitWithForm:=nil;
|
|
fFirstUnitWithForm:=AnUnitInfo;
|
|
if AnUnitInfo.fNextUnitWithForm<>nil then
|
|
AnUnitInfo.fNextUnitWithForm.fPrevUnitWithForm:=AnUnitInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.RemoveFromFormList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// remove from list if AnUnitInfo is in list
|
|
if fFirstUnitWithForm=AnUnitInfo then
|
|
fFirstUnitWithForm:=AnUnitInfo.fNextUnitWithForm;
|
|
if AnUnitInfo.fNextUnitWithForm<>nil then
|
|
AnUnitInfo.fNextUnitWithForm.fPrevUnitWithForm:=
|
|
AnUnitInfo.fPrevUnitWithForm;
|
|
if AnUnitInfo.fPrevUnitWithForm<>nil then
|
|
AnUnitInfo.fPrevUnitWithForm.fNextUnitWithForm:=
|
|
AnUnitInfo.fNextUnitWithForm;
|
|
AnUnitInfo.fNextUnitWithForm:=nil;
|
|
AnUnitInfo.fPrevUnitWithForm:=nil;
|
|
end;
|
|
|
|
procedure TProject.AddToLoadedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// add to list if AnUnitInfo is not in list
|
|
if (fFirstLoadedUnit<>AnUnitInfo)
|
|
and (AnUnitInfo.fNextLoadedUnit=nil)
|
|
and (AnUnitInfo.fPrevLoadedUnit=nil) then begin
|
|
AnUnitInfo.fNextLoadedUnit:=fFirstLoadedUnit;
|
|
AnUnitInfo.fPrevLoadedUnit:=nil;
|
|
fFirstLoadedUnit:=AnUnitInfo;
|
|
if AnUnitInfo.fNextLoadedUnit<>nil then
|
|
AnUnitInfo.fNextLoadedUnit.fPrevLoadedUnit:=AnUnitInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.RemoveFromLoadedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// remove from list if AnUnitInfo is in list
|
|
if fFirstLoadedUnit=AnUnitInfo then
|
|
fFirstLoadedUnit:=AnUnitInfo.fNextUnitWithForm;
|
|
if AnUnitInfo.fNextLoadedUnit<>nil then
|
|
AnUnitInfo.fNextLoadedUnit.fPrevLoadedUnit:=
|
|
AnUnitInfo.fPrevLoadedUnit;
|
|
if AnUnitInfo.fPrevLoadedUnit<>nil then
|
|
AnUnitInfo.fPrevLoadedUnit.fNextLoadedUnit:=
|
|
AnUnitInfo.fNextLoadedUnit;
|
|
AnUnitInfo.fNextLoadedUnit:=nil;
|
|
AnUnitInfo.fPrevLoadedUnit:=nil;
|
|
end;
|
|
|
|
procedure TProject.AddToAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// add to list if AnUnitInfo is not in list
|
|
if (fFirstAutoRevertLockedUnit<>AnUnitInfo)
|
|
and (AnUnitInfo.fNextAutoRevertLockedUnit=nil)
|
|
and (AnUnitInfo.fPrevAutoRevertLockedUnit=nil) then begin
|
|
AnUnitInfo.fNextAutoRevertLockedUnit:=fFirstAutoRevertLockedUnit;
|
|
AnUnitInfo.fPrevAutoRevertLockedUnit:=nil;
|
|
fFirstAutoRevertLockedUnit:=AnUnitInfo;
|
|
if AnUnitInfo.fNextAutoRevertLockedUnit<>nil then
|
|
AnUnitInfo.fNextAutoRevertLockedUnit.fPrevAutoRevertLockedUnit:=AnUnitInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TProject.RemoveFromAutoRevertLockedList(AnUnitInfo: TUnitInfo);
|
|
begin
|
|
// remove from list if AnUnitInfo is in list
|
|
if fFirstAutoRevertLockedUnit=AnUnitInfo then
|
|
fFirstAutoRevertLockedUnit:=AnUnitInfo.fNextAutoRevertLockedUnit;
|
|
if AnUnitInfo.fNextAutoRevertLockedUnit<>nil then
|
|
AnUnitInfo.fNextAutoRevertLockedUnit.fPrevAutoRevertLockedUnit:=
|
|
AnUnitInfo.fPrevAutoRevertLockedUnit;
|
|
if AnUnitInfo.fPrevAutoRevertLockedUnit<>nil then
|
|
AnUnitInfo.fPrevAutoRevertLockedUnit.fNextAutoRevertLockedUnit:=
|
|
AnUnitInfo.fNextAutoRevertLockedUnit;
|
|
AnUnitInfo.fNextAutoRevertLockedUnit:=nil;
|
|
AnUnitInfo.fPrevAutoRevertLockedUnit:=nil;
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
{
|
|
$Log$
|
|
Revision 1.74 2002/09/05 19:03:36 lazarus
|
|
MG: improved handling of ambigious source files
|
|
|
|
Revision 1.73 2002/08/23 07:05:15 lazarus
|
|
MG: started form renaming
|
|
|
|
Revision 1.72 2002/08/21 07:16:59 lazarus
|
|
MG: reduced mem leak of clipping stuff, still not fixed
|
|
|
|
Revision 1.71 2002/08/07 09:55:28 lazarus
|
|
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
|
|
|
|
Revision 1.70 2002/08/01 14:10:30 lazarus
|
|
MG: started file access monitoring for loaded files
|
|
|
|
Revision 1.69 2002/08/01 08:03:03 lazarus
|
|
MG: accelerated searches in project
|
|
|
|
Revision 1.68 2002/07/31 06:52:17 lazarus
|
|
MG: started File Access Monitoring for hidden files
|
|
|
|
Revision 1.67 2002/07/30 06:24:04 lazarus
|
|
MG: added a faster version of TXMLConfig
|
|
|
|
Revision 1.66 2002/07/06 06:37:06 lazarus
|
|
MG: added Revert
|
|
|
|
Revision 1.65 2002/05/16 13:00:57 lazarus
|
|
MG: fixed changing syntax highlighter on save as
|
|
|
|
Revision 1.64 2002/05/10 06:57:45 lazarus
|
|
MG: updated licenses
|
|
|
|
Revision 1.63 2002/04/28 14:10:29 lazarus
|
|
MG: fixes for saving resource files
|
|
|
|
Revision 1.62 2002/04/21 13:24:06 lazarus
|
|
MG: small updates and fixes
|
|
|
|
Revision 1.61 2002/04/15 12:45:57 lazarus
|
|
MG: added save projectunit flags
|
|
|
|
Revision 1.60 2002/04/05 16:34:16 lazarus
|
|
MG: fixed autocreate form editing in project opts
|
|
|
|
Revision 1.59 2002/04/04 17:21:18 lazarus
|
|
MG: fixed outputfilter for linker errors
|
|
|
|
Revision 1.58 2002/04/02 17:18:25 lazarus
|
|
MG: fixed save project as, renaming source name
|
|
|
|
Revision 1.57 2002/03/28 00:11:06 lazarus
|
|
MG: removed unused
|
|
|
|
Revision 1.56 2002/03/25 16:48:26 lazarus
|
|
MG: clean ups for main.pp, many minor fixes
|
|
|
|
Revision 1.55 2002/03/25 07:29:23 lazarus
|
|
MG: added TOpen/SaveFlags and splittet some methods
|
|
|
|
Revision 1.54 2002/03/22 12:36:45 lazarus
|
|
MG: many fixes, to make it short: events
|
|
|
|
Revision 1.53 2002/03/21 23:59:59 lazarus
|
|
MG: code creation options applied to new unit source
|
|
|
|
Revision 1.52 2002/03/21 22:44:08 lazarus
|
|
MG: fixes for save-as and form streaming exceptions
|
|
|
|
Revision 1.51 2002/03/05 08:14:59 lazarus
|
|
MG: updates for codetools defines editor
|
|
|
|
Revision 1.50 2002/02/25 23:18:54 lazarus
|
|
MG: jump history will now try to save relative filenames
|
|
|
|
Revision 1.49 2002/02/08 21:08:00 lazarus
|
|
MG: saving of virtual project files will now save the whole project
|
|
|
|
Revision 1.48 2002/02/03 00:23:55 lazarus
|
|
TPanel implemented.
|
|
Basic graphic primitives split into GraphType package, so that we can
|
|
reference it from interface (GTK, Win32) units.
|
|
New Frame3d canvas method that uses native (themed) drawing (GTK only).
|
|
New overloaded Canvas.TextRect method.
|
|
LCLLinux and Graphics was split, so a bunch of files had to be modified.
|
|
|
|
Revision 1.47 2001/12/19 22:09:14 lazarus
|
|
MG: added GUID and alias parsing, added DoJumpToCodeToolBossError
|
|
|
|
Revision 1.46 2001/12/16 22:24:54 lazarus
|
|
MG: changes for new compiler 20011216
|
|
|
|
Revision 1.45 2001/12/13 23:09:58 lazarus
|
|
MG: enhanced code caching, fixed CursorToCleanPos and beautify statement
|
|
|
|
Revision 1.44 2001/12/02 11:03:36 lazarus
|
|
MG: added default pascal file extension option
|
|
|
|
Revision 1.43 2001/12/01 22:17:26 lazarus
|
|
MG: added jump-history
|
|
|
|
Revision 1.42 2001/11/17 09:48:56 lazarus
|
|
MG: changing project filename will now also change the title
|
|
|
|
Revision 1.41 2001/11/15 13:49:50 lazarus
|
|
MG: fixed open non existing file and unitname in save project as
|
|
|
|
Revision 1.40 2001/11/14 17:46:57 lazarus
|
|
Changes to make toggling between form and unit work.
|
|
Added BringWindowToTop
|
|
Shane
|
|
|
|
Revision 1.39 2001/11/06 22:20:30 lazarus
|
|
MG: started breakpoint and watch frontend
|
|
|
|
Revision 1.38 2001/11/06 16:42:23 lazarus
|
|
MG: added facade for find in files
|
|
|
|
Revision 1.36 2001/11/06 15:47:32 lazarus
|
|
MG: added build all
|
|
|
|
Revision 1.35 2001/11/06 12:20:33 lazarus
|
|
MG: added Run Parameter Options - not enabled yet
|
|
|
|
Revision 1.34 2001/11/05 18:18:18 lazarus
|
|
added popupmenu+arrows to notebooks, added target filename
|
|
|
|
Revision 1.33 2001/11/03 08:37:35 lazarus
|
|
MG: fixed errorline showing, resource adding and published var editing and added make cleanall
|
|
|
|
Revision 1.32 2001/10/23 09:13:52 lazarus
|
|
MG: fixed TestProject
|
|
|
|
Revision 1.31 2001/10/18 13:01:31 lazarus
|
|
MG: fixed speedbuttons numglyphs>1 and started IDE debugging
|
|
|
|
Revision 1.30 2001/10/15 13:11:27 lazarus
|
|
MG: added complete code
|
|
|
|
Revision 1.27 2001/10/09 09:46:50 lazarus
|
|
MG: added codetools, fixed synedit unindent, fixed MCatureHandle
|
|
|
|
Revision 1.26 2001/07/08 22:33:56 lazarus
|
|
MG: added rapid testing project
|
|
|
|
Revision 1.25 2001/06/27 21:43:23 lazarus
|
|
MG: added project bookmark support
|
|
|
|
Revision 1.24 2001/06/04 09:32:17 lazarus
|
|
MG: fixed bugs and cleaned up messages
|
|
|
|
Revision 1.23 2001/05/27 11:52:00 lazarus
|
|
MG: added --primary-config-path=<filename> cmd line option
|
|
|
|
Revision 1.20 2001/04/04 13:55:35 lazarus
|
|
MG: finished TComponentPropertyEditor, added OnModified to oi, cfe and designer
|
|
|
|
Revision 1.19 2001/04/04 12:20:34 lazarus
|
|
MG: added add to/remove from project, small bugfixes
|
|
|
|
Revision 1.18 2001/03/29 12:38:59 lazarus
|
|
MG: new environment opts, ptApplication bugfixes
|
|
|
|
Revision 1.17 2001/03/26 14:52:30 lazarus
|
|
MG: TSourceLog + compiling bugfixes
|
|
|
|
Revision 1.16 2001/03/19 14:00:47 lazarus
|
|
MG: fixed many unreleased DC and GDIObj bugs
|
|
|
|
Revision 1.15 2001/03/09 17:54:45 lazarus
|
|
|
|
Fixed error in Windows section of OnLoadSaveFilename - missing ')'
|
|
|
|
Revision 1.14 2001/03/09 11:38:20 lazarus
|
|
auto load last project
|
|
|
|
Revision 1.10 2001/03/03 11:06:15 lazarus
|
|
added project support, codetools
|
|
|
|
Revision 1.8 2001/02/22 17:04:57 lazarus
|
|
added environment options + killed ide unit circles
|
|
|
|
Revision 1.7 2001/02/08 06:08:13 lazarus
|
|
Began adding code to save project to the output directory. Added TODO
|
|
comments and cleaned up some of the code. CAW
|
|
|
|
Revision 1.6 2001/01/31 13:03:33 lazarus
|
|
Commitng source with new editor.
|
|
Shane
|
|
|
|
Revision 1.5 2001/01/31 06:28:41 lazarus
|
|
Removed global unit.
|
|
Renamed TProjectUnitInfo to TUnitInfo.
|
|
Added Source property to both TUnitInfo and TProject to hold source code
|
|
for units and project.
|
|
Added functions to load and save units to TUnitInfo.
|
|
Added code to save and load units when a project is saved and loaded. CAW
|
|
|
|
Revision 1.4 2001/01/29 05:42:41 lazarus
|
|
Created new TProjectUnitInfo class.
|
|
Created new TProject class. Saves to XML config file.
|
|
Moved compiler options to write to the project file. CAW
|
|
|
|
Revision 1.3 2001/01/04 20:33:53 lazarus
|
|
Moved lresources.
|
|
Moved CreateLFM to Main.pp
|
|
Changed Form1 and TFOrm1 to MainIDE and TMainIDE
|
|
Shane
|
|
|
|
Revision 1.2 2000/12/19 18:43:13 lazarus
|
|
Removed IDEEDITOR. This causes the PROJECT class to not function.
|
|
Saving projects no longer works.
|
|
|
|
I added TSourceNotebook and TSourceEditor. They do all the work for saving/closing/opening units. Somethings work but they are in early development.
|
|
Shane
|
|
|
|
Revision 1.1 2000/07/13 10:27:48 michael
|
|
+ Initial import
|
|
|
|
}
|