From 51365b3a3552f6d946a6e5d8c60bf3d4f3b961e4 Mon Sep 17 00:00:00 2001 From: mattias Date: Sun, 13 Apr 2003 13:45:04 +0000 Subject: [PATCH] implemented broken dependencies dialog git-svn-id: trunk@4052 - --- ide/idecomp.pp | 4 + ide/mainbar.pas | 57 +++++++++++++ ide/project.pp | 19 ++++- lcl/comctrls.pp | 17 +++- lcl/dialogs.pp | 33 ++++--- lcl/include/messagedialogs.inc | 6 +- packager/basepkgmanager.pas | 6 +- packager/packagedefs.pas | 28 ++++-- packager/packageeditor.pas | 29 ++++--- packager/packagesystem.pas | 92 +++++++++++++++++++- packager/pkggraphexporer.pas | 17 +--- packager/pkgmanager.pas | 152 +++++++++++++++++++++++++++------ packager/pkgoptionsdlg.pas | 112 ++++++++++++++++++++++-- 13 files changed, 486 insertions(+), 86 deletions(-) diff --git a/ide/idecomp.pp b/ide/idecomp.pp index c2d1a392a1..996056fafb 100644 --- a/ide/idecomp.pp +++ b/ide/idecomp.pp @@ -35,6 +35,10 @@ unit IDEComp; { $DEFINE INTERBASE} +{$IFDEF INTERBASE} + {$linklib crypt} +{$ENDIF} + interface uses diff --git a/ide/mainbar.pas b/ide/mainbar.pas index 45711b89ff..eb89cc7281 100644 --- a/ide/mainbar.pas +++ b/ide/mainbar.pas @@ -354,6 +354,8 @@ type function DoInitProjectRun: TModalResult; virtual; abstract; function DoOpenMacroFile(Sender: TObject; const AFilename: string): TModalResult; virtual; + function DoCheckCreatingFile(const AFilename: string; + CheckReadable: boolean): TModalResult; virtual; function DoCheckFilesOnDisk: TModalResult; virtual; abstract; function DoCheckAmbigiousSources(const AFilename: string; @@ -1351,6 +1353,61 @@ begin [ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofConvertMacros]); end; +{------------------------------------------------------------------------------- + function TMainIDEBar.DoCheckCreatingFile(const AFilename: string; + CheckReadable: boolean): TModalResult; +-------------------------------------------------------------------------------} +function TMainIDEBar.DoCheckCreatingFile(const AFilename: string; + CheckReadable: boolean): TModalResult; +var + fs: TFileStream; + c: char; +begin + // create if not yet done + if not FileExists(AFilename) then begin + try + fs:=TFileStream.Create(AFilename,fmCreate); + fs.Free; + except + Result:=MessageDlg('Unable to create file', + 'Unable to create file "'+AFilename+'".',mtError,[mbCancel,mbAbort],0); + exit; + end; + end; + // check writable + try + if CheckReadable then + fs:=TFileStream.Create(AFilename,fmOpenWrite) + else + fs:=TFileStream.Create(AFilename,fmOpenReadWrite); + try + fs.Seek(0,soEnd); + fs.Write(' ',1); + finally + fs.Free; + end; + except + Result:=MessageDlg('Unable to write file', + 'Unable to write file "'+AFilename+'".',mtError,[mbCancel,mbAbort],0); + exit; + end; + // check readable + try + fs:=TFileStream.Create(AFilename,fmOpenReadWrite); + try + fs.Seek(-1,soEnd); + fs.Read(c,1); + finally + fs.Free; + end; + except + Result:=MessageDlg('Unable to read file', + 'Unable to read file "'+AFilename+'".',mtError,[mbCancel,mbAbort],0); + exit; + end; + Result:=mrOk; +end; + {------------------------------------------------------------------------------- function TMainIDEBar.DoCheckAmbigiousSources(const AFilename: string ): TModalResult; diff --git a/ide/project.pp b/ide/project.pp index 820e3402b5..69fc63f31d 100644 --- a/ide/project.pp +++ b/ide/project.pp @@ -1207,7 +1207,21 @@ begin if Result=mrAbort then exit; end; confPath:=SetDirSeparators(confPath); - xmlconfig := TXMLConfig.Create(confPath); + try + ClearFile(confPath,true); + xmlconfig := TXMLConfig.Create(confPath); + except + on E: Exception do begin + writeln('ERROR: ',E.Message); + MessageDlg('Write error', + 'Unable to write the project info file'#13 + +'"'+ProjectInfoFile+'".'#13 + +'Error: '+E.Message + ,mtError,[mbOk],0); + Result:=mrCancel; + exit; + end; + end; UpdateUsageCounts; repeat @@ -2282,6 +2296,9 @@ end. { $Log$ + Revision 1.103 2003/04/13 13:45:04 mattias + implemented broken dependencies dialog + Revision 1.102 2003/04/07 23:49:03 mattias implemented adding units to packages diff --git a/lcl/comctrls.pp b/lcl/comctrls.pp index ee9d74d976..234b2d5e8c 100644 --- a/lcl/comctrls.pp +++ b/lcl/comctrls.pp @@ -215,6 +215,9 @@ type property Item[const AIndex: Integer]: TListItem read GetItem write SetItem; default; property Owner : TCustomListView read FOwner; end; + + + { TListColumn } TWidth = 0..MaxInt; @@ -254,6 +257,9 @@ type property Visible : Boolean read FVisible write SetVisible; property Width: TWidth read GetWidth write SetWidth; end; + + + { TListColumns } TListColumns = class(TCollection) private @@ -270,6 +276,9 @@ type read GetItem write SetItem; default; procedure Assign(Source: TPersistent); override; end; + + + { TCustomListView } TItemChange = (ctText, ctImage, ctState); TViewStyle = (vsList,vsReport); @@ -374,8 +383,11 @@ type procedure EndUpdate; property Selected: TListItem read GetSelection write SetSelection; end; + + + { TListView } - TListView = class(TCustomListView) + TListView = class(TCustomListView) published property Align; property Anchors; @@ -1742,6 +1754,9 @@ end. { ============================================================================= $Log$ + Revision 1.71 2003/04/13 13:45:04 mattias + implemented broken dependencies dialog + Revision 1.70 2003/04/08 16:56:55 mattias implemented saving package diff --git a/lcl/dialogs.pp b/lcl/dialogs.pp index fd7a5de4b2..f63f1ebbef 100644 --- a/lcl/dialogs.pp +++ b/lcl/dialogs.pp @@ -41,22 +41,28 @@ uses LMessages, Forms, Controls, GraphType, Graphics, Buttons, StdCtrls; -//type -// TDialogButtons = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, -// mbIgnore, mbAll, mbNoToAll, mbYesToAll, mbHelp); -// TDialogButtonsSet = set of TDialogButtons; type - TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, - mtCustom); - TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, - mbAll, mbNoToAll, mbYesToAll, mbHelp); - TMsgDlgButtons = set of TMsgDlgBtn; + TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, + mtCustom); + TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, + mbAll, mbNoToAll, mbYesToAll, mbHelp, mbClose); + TMsgDlgButtons = set of TMsgDlgBtn; const - mbYesNoCancel = [mbYes, mbNo, mbCancel]; - mbOKCancel = [mbOK, mbCancel]; - mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore]; + mbYesNoCancel = [mbYes, mbNo, mbCancel]; + mbOKCancel = [mbOK, mbCancel]; + mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore]; + + MsgDlgBtnToBitBtnKind: array[TMsgDlgBtn] of TBitBtnKind = ( + bkYes, bkNo, bkOK, bkCancel, bkAbort, bkRetry, bkIgnore, + bkAll, bkNoToAll, bkYesToAll, bkHelp, bkClose + ); + + BitBtnKindToMsgDlgBtn: array[TBitBtnKind] of TMsgDlgBtn = ( + mbOk, mbOK, mbCancel, mbHelp, mbYes, mbNo, + mbClose, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToALl, mbYesToAll + ); type @@ -340,6 +346,9 @@ end. { ============================================================================= $Log$ + Revision 1.30 2003/04/13 13:45:04 mattias + implemented broken dependencies dialog + Revision 1.29 2003/04/08 09:04:07 mattias fixed registration for fpc 1.0.x diff --git a/lcl/include/messagedialogs.inc b/lcl/include/messagedialogs.inc index 5b8116ba7a..2611a0f9a0 100644 --- a/lcl/include/messagedialogs.inc +++ b/lcl/include/messagedialogs.inc @@ -102,7 +102,8 @@ const ButtonIds : Array[TMsgDlgbtn] of Longint = (idButtonYes, idButtonNo, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry, idButtonIgnore, - idButtonAll, idButtonNoToAll, idButtonYesToAll, idButtonHelp); + idButtonAll, idButtonNoToAll, idButtonYesToAll, idButtonHelp, + idButtonClose); DialogResults : Array[idButtonOK..idButtonNoToAll] of TModalResult = ( mrOk, mrCancel, mrOk{CLOSE!!}, mrYes, mrNo, -1{HELP!!}, mrAbort, mrRetry, @@ -232,6 +233,9 @@ end; { $Log$ + Revision 1.22 2003/04/13 13:45:04 mattias + implemented broken dependencies dialog + Revision 1.21 2002/10/25 14:59:11 lazarus AJ: MessageDlgs -> PromptUser, better Cancel/Default order diff --git a/packager/basepkgmanager.pas b/packager/basepkgmanager.pas index 43de589597..e839d56780 100644 --- a/packager/basepkgmanager.pas +++ b/packager/basepkgmanager.pas @@ -48,7 +48,8 @@ uses type TPkgSaveFlag = ( - psfSaveAs + psfSaveAs, + pfAskBeforeSaving ); TPkgSaveFlags = set of TPkgSaveFlag; @@ -74,6 +75,9 @@ type Flags: TPkgOpenFlags): TModalResult; virtual; abstract; function DoSavePackage(APackage: TLazPackage; Flags: TPkgSaveFlags): TModalResult; virtual; abstract; + function DoSaveAllPackages(Flags: TPkgSaveFlags): TModalResult; virtual; abstract; + function DoClosePackageEditor(APackage: TLazPackage): TModalResult; virtual; abstract; + function DoCloseAllPackageEditors: TModalResult; virtual; abstract; end; var diff --git a/packager/packagedefs.pas b/packager/packagedefs.pas index f4d96610f4..fda5e1bf4a 100644 --- a/packager/packagedefs.pas +++ b/packager/packagedefs.pas @@ -216,6 +216,7 @@ type procedure Assign(Source: TPkgDependency); procedure ConsistencyCheck; function IsCompatible(Pkg: TLazPackageID): boolean; + procedure MakeCompatible(const PkgName: string; const Version: TPkgVersion); function AsString: string; function NextUsedByDependency: TPkgDependency; function PrevUsedByDependency: TPkgDependency; @@ -290,7 +291,8 @@ type // (for example because it is Installed or an Installed // package requires this package) lpfVisited, // Used by the PackageGraph to avoid double checking - lpfDestroying // set during destruction + lpfDestroying, // set during destruction + lpfSkipSaving ); TLazPackageFlags = set of TLazPackageFlag; @@ -326,7 +328,6 @@ type FIconFile: string; FInstalled: TPackageInstallType; FModifiedLock: integer; - FOnChangeName: TPkgChangeNameEvent; FPackageEditor: TBasePackageEditor; FPackageType: TLazPackageType; FReadOnly: boolean; @@ -402,6 +403,7 @@ type function Requires(APackage: TLazPackage): boolean; procedure AddUsedByDependency(Dependency: TPkgDependency); procedure RemoveUsedByDependency(Dependency: TPkgDependency); + procedure ChangeID(const NewName: string; NewVersion: TPkgVersion); public property AddDependCompilerOptions: TAdditionalCompilerOptions read FAddDependCompilerOptions; @@ -430,7 +432,6 @@ type property Installed: TPackageInstallType read FInstalled write SetInstalled; property Registered: boolean read FRegistered write SetRegistered; property Modified: boolean read GetModified write SetModified; - property OnChangeName: TPkgChangeNameEvent read FOnChangeName write FOnChangeName; property PackageType: TLazPackageType read FPackageType write SetPackageType; property ReadOnly: boolean read FReadOnly write SetReadOnly; @@ -467,7 +468,7 @@ const 'RunTime', 'DesignTime', 'RunAndDesignTime'); LazPackageFlagNames: array[TLazPackageFlag] of string = ( 'lpfAutoIncrementVersionOnBuild', 'lpfModified', 'lpfAutoUpdate', - 'lpfNeeded', 'lpfVisited', 'lpfDestroying'); + 'lpfNeeded', 'lpfVisited', 'lpfDestroying', 'lpfSkipSaving'); var // All TPkgDependency are added to this AVL tree (sorted for names, not version!) @@ -1002,6 +1003,14 @@ begin Result:=IsCompatible(Pkg.Name,Pkg.Version); end; +procedure TPkgDependency.MakeCompatible(const PkgName: string; + const Version: TPkgVersion); +begin + PackageName:=PkgName; + if MinVersion.Compare(Version)>0 then MinVersion.Assign(Version); + if MaxVersion.Compare(Version)<0 then MaxVersion.Assign(Version); +end; + function TPkgDependency.AsString: string; begin Result:=FPackageName; @@ -1309,16 +1318,13 @@ begin Include(FFlags,lpfModified) else Exclude(FFlags,lpfModified); + Exclude(FFlags,lpfSkipSaving); end; procedure TLazPackage.SetName(const AValue: string); -var - OldName: String; begin if FName=AValue then exit; - OldName:=FName; FName:=AValue; - if Assigned(OnChangeName) then OnChangeName(Self,OldName); Modified:=true; end; @@ -1836,6 +1842,12 @@ begin Dependency.RemoveFromList(FFirstUsedByDependency,pdlUsedBy); end; +procedure TLazPackage.ChangeID(const NewName: string; NewVersion: TPkgVersion); +begin + Version.Assign(NewVersion); + Name:=NewName; +end; + { TPkgComponent } procedure TPkgComponent.SetPkgFile(const AValue: TPkgFile); diff --git a/packager/packageeditor.pas b/packager/packageeditor.pas index 3f491d3bf8..b64c3bbecf 100644 --- a/packager/packageeditor.pas +++ b/packager/packageeditor.pas @@ -49,7 +49,8 @@ type TOnOpenPackage = function(Sender: TObject; APackage: TLazPackage): TModalResult of object; TOnSavePackage = - function(Sender: TObject; APackage: TLazPackage): TModalResult of object; + function(Sender: TObject; APackage: TLazPackage; + SaveAs: boolean): TModalResult of object; TOnCreateNewPkgFile = function(Sender: TObject; const Params: TAddToPkgResult): TModalResult of object; @@ -109,6 +110,7 @@ type ARect: TRect; State: TOwnerDrawState); procedure RemoveBitBtnClick(Sender: TObject); procedure SaveBitBtnClick(Sender: TObject); + procedure SaveAsClick(Sender: TObject); procedure UseMaxVersionCheckBoxClick(Sender: TObject); procedure UseMinVersionCheckBoxClick(Sender: TObject); private @@ -133,7 +135,7 @@ type public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; - procedure DoSave; + procedure DoSave(SaveAs: boolean); public property LazPackage: TLazPackage read FLazPackage write SetLazPackage; end; @@ -167,7 +169,7 @@ type procedure DoFreeEditor(Pkg: TLazPackage); function CreateNewFile(Sender: TObject; const Params: TAddToPkgResult): TModalResult; - function SavePackage(APackage: TLazPackage): TModalResult; + function SavePackage(APackage: TLazPackage; SaveAs: boolean): TModalResult; public property Editors[Index: integer]: TPackageEditorForm read GetEditors; property OnCreateNewFile: TOnCreateNewPkgFile read FOnCreateNewFile @@ -321,6 +323,7 @@ begin AddPopupMenuItem('-',nil,true); AddPopupMenuItem('Save',@SaveBitBtnClick,SaveBitBtn.Enabled); + AddPopupMenuItem('Save As',@SaveAsClick,not LazPackage.AutoCreated); AddPopupMenuItem('Compile',@CompileBitBtnClick,CompileBitBtn.Enabled); AddPopupMenuItem('Add',@AddBitBtnClick,AddBitBtn.Enabled); AddPopupMenuItem('Remove',@RemoveBitBtnClick,RemoveBitBtn.Enabled); @@ -410,7 +413,7 @@ begin +'Save package?', mtConfirmation,[mbYes,mbNo,mbAbort],0); if MsgResult=mrYes then begin - MsgResult:=PackageEditors.SavePackage(LazPackage); + MsgResult:=PackageEditors.SavePackage(LazPackage,false); end; if MsgResult=mrAbort then CanClose:=false; end; @@ -505,7 +508,12 @@ end; procedure TPackageEditorForm.SaveBitBtnClick(Sender: TObject); begin - DoSave; + DoSave(false); +end; + +procedure TPackageEditorForm.SaveAsClick(Sender: TObject); +begin + DoSave(true); end; procedure TPackageEditorForm.UseMaxVersionCheckBoxClick(Sender: TObject); @@ -830,7 +838,7 @@ begin with CompilerOptionsBitBtn do begin Name:='CompilerOptionsBitBtn'; Parent:=Self; - Caption:='Compiler Options'; + Caption:='Comp. Opts.'; OnClick:=@CompilerOptionsBitBtnClick; Hint:='Edit Options to compile package'; ShowHint:=true; @@ -1283,9 +1291,9 @@ begin end; end; -procedure TPackageEditorForm.DoSave; +procedure TPackageEditorForm.DoSave(SaveAs: boolean); begin - PackageEditors.SavePackage(LazPackage); + PackageEditors.SavePackage(LazPackage,SaveAs); UpdateButtons; UpdateTitle; UpdateStatusBar; @@ -1404,9 +1412,10 @@ begin Result:=OnCreateNewFile(Sender,Params); end; -function TPackageEditors.SavePackage(APackage: TLazPackage): TModalResult; +function TPackageEditors.SavePackage(APackage: TLazPackage; + SaveAs: boolean): TModalResult; begin - if Assigned(OnSavePackage) then Result:=OnSavePackage(Self,APackage); + if Assigned(OnSavePackage) then Result:=OnSavePackage(Self,APackage,SaveAs); end; initialization diff --git a/packager/packagesystem.pas b/packager/packagesystem.pas index 5a0ef39763..e04b137fb0 100644 --- a/packager/packagesystem.pas +++ b/packager/packagesystem.pas @@ -67,6 +67,7 @@ const type TPkgAddedEvent = procedure(APackage: TLazPackage) of object; TPkgDeleteEvent = procedure(APackage: TLazPackage) of object; + TDependencyModifiedEvent = procedure(ADependency: TPkgDependency) of object; TLazPackageGraph = class private @@ -79,6 +80,7 @@ type FOnBeginUpdate: TNotifyEvent; FOnChangePackageName: TPkgChangeNameEvent; FOnDeletePackage: TPkgDeleteEvent; + FOnDependencyModified: TDependencyModifiedEvent; FOnEndUpdate: TNotifyEvent; FRegistrationFile: TPkgFile; FRegistrationPackage: TLazPackage; @@ -134,6 +136,11 @@ type procedure ClosePackage(APackage: TLazPackage); procedure MarkNeededPackages; procedure CloseUnneededPackages; + procedure ChangePackageID(APackage: TLazPackage; + const NewName: string; NewVersion: TPkgVersion; + RenameDependencies: boolean); + function GetBrokenDependenciesWhenChangingPkgID(APackage: TLazPackage; + const NewName: string; NewVersion: TPkgVersion): TList; function CheckIfPackageCanBeClosed(APackage: TLazPackage): boolean; function PackageIsNeeded(APackage: TLazPackage): boolean; procedure RegisterStaticPackages; @@ -157,7 +164,10 @@ type property OnBeginUpdate: TNotifyEvent read FOnBeginUpdate write FOnBeginUpdate; property OnChangePackageName: TPkgChangeNameEvent read FOnChangePackageName write FOnChangePackageName; - property OnDeletePackage: TPkgDeleteEvent read FOnDeletePackage write FOnDeletePackage; + property OnDependencyModified: TDependencyModifiedEvent + read FOnDependencyModified write FOnDependencyModified; + property OnDeletePackage: TPkgDeleteEvent read FOnDeletePackage + write FOnDeletePackage; property OnEndUpdate: TNotifyEvent read FOnEndUpdate write FOnEndUpdate; property Packages[Index: integer]: TLazPackage read GetPackages; default; property RegistrationFile: TPkgFile read FRegistrationFile; @@ -724,8 +734,7 @@ begin BeginUpdate; FTree.Add(APackage); FItems.Add(APackage); - APackage.OnChangeName:=@PackageChangedName; - + // open all dependencies Dependency:=APackage.FirstRequiredDependency; while Dependency<>nil do begin @@ -829,6 +838,83 @@ begin EndUpdate; end; +procedure TLazPackageGraph.ChangePackageID(APackage: TLazPackage; + const NewName: string; NewVersion: TPkgVersion; RenameDependencies: boolean); +var + Dependency, FirstUpdateDependency: TPkgDependency; + RequiredPackage: TLazPackage; + ANode: TAVLTreeNode; + NextDependency: TPkgDependency; + OldPkgName: String; +begin + OldPkgName:=APackage.Name; + if (AnsiCompareText(OldPkgName,NewName)=0) + and (APackage.Version.Compare(NewVersion)=0) then begin + // ID does not change + // -> just rename + APackage.Name:=NewName; + exit; + end; + + // ID changed + + // break or change all dependencies, that became incompatible + Dependency:=APackage.FirstUsedByDependency; + FirstUpdateDependency:=nil; + while Dependency<>nil do begin + NextDependency:=Dependency.NextUsedByDependency; + if not Dependency.IsCompatible(NewName,NewVersion) then begin + if RenameDependencies then begin + Dependency.MakeCompatible(NewName,NewVersion); + if Assigned(OnDependencyModified) then OnDependencyModified(Dependency); + end else begin + Dependency.RequiredPackage:=nil; + Dependency.AddToList(FirstUpdateDependency,pdlUsedBy); + end; + end; + Dependency:=NextDependency; + end; + + // change ID + FTree.Remove(APackage); + APackage.ChangeID(NewName,NewVersion); + FTree.Add(APackage); + + // update new broken dependencies + while FirstUpdateDependency<>nil do begin + Dependency.RemoveFromList(FirstUpdateDependency,pdlUsedBy); + OpenDependency(Dependency,RequiredPackage); + end; + // update old broken dependencies + ANode:=FindLowestPkgDependencyNodeWithName(NewName); + while ANode<>nil do begin + Dependency:=TPkgDependency(ANode.Data); + if (Dependency.LoadPackageResult<>lprSuccess) + and Dependency.IsCompatible(APackage) then + OpenDependency(Dependency,RequiredPackage); + ANode:=FindNextPkgDependecyNodeWithSameName(ANode); + end; + + if Assigned(OnChangePackageName) then + OnChangePackageName(APackage,OldPkgName); +end; + +function TLazPackageGraph.GetBrokenDependenciesWhenChangingPkgID( + APackage: TLazPackage; const NewName: string; NewVersion: TPkgVersion + ): TList; +var + Dependency: TPkgDependency; +begin + Result:=TList.Create; + // find all dependencies, that will become incompatible + Dependency:=APackage.FirstUsedByDependency; + while Dependency<>nil do begin + if not Dependency.IsCompatible(NewName,NewVersion) then + Result.Add(Dependency); + Dependency:=Dependency.NextUsedByDependency; + end; +end; + function TLazPackageGraph.CheckIfPackageCanBeClosed(APackage: TLazPackage ): boolean; begin diff --git a/packager/pkggraphexporer.pas b/packager/pkggraphexporer.pas index 3f385dcf9c..b1b9841ab6 100644 --- a/packager/pkggraphexporer.pas +++ b/packager/pkggraphexporer.pas @@ -41,7 +41,7 @@ uses Classes, SysUtils, LCLProc, LResources, Forms, Controls, Buttons, ComCtrls, StdCtrls, ExtCtrls, Menus, Dialogs, Graphics, FileCtrl, AVL_Tree, LazarusIDEStrConsts, IDEProcs, IDEOptionDefs, EnvironmentOpts, - Project, PackageDefs, PackageSystem, PackageEditor; + Project, BrokenDependenciesDlg, PackageDefs, PackageSystem, PackageEditor; type TPkgGraphExplorer = class(TForm) @@ -488,7 +488,6 @@ var Dependency: TPkgDependency; UsedByDep: TPkgDependency; sl: TStringList; - DepOwner: TObject; NewItem: String; begin GetDependency(PkgTreeView.Selected,Pkg,Dependency); @@ -498,19 +497,7 @@ begin UsedByDep:=Pkg.FirstUsedByDependency; sl:=TStringList.Create; while UsedByDep<>nil do begin - DepOwner:=UsedByDep.Owner; - if (DepOwner<>nil) then begin - if DepOwner is TLazPackage then begin - NewItem:='Package: '+TLazPackage(DepOwner).IDAsString; - end else if DepOwner is TProject then begin - NewItem:='Project: ' - +ExtractFileNameOnly(TProject(DepOwner).ProjectInfoFile); - end else begin - NewItem:=DepOwner.ClassName - end; - end else begin - NewItem:='Dependency without Owner: '+UsedByDep.AsString; - end; + NewItem:=GetDependencyOwnerAsString(UsedByDep); sl.Add(NewItem); UsedByDep:=UsedByDep.NextUsedByDependency; end; diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas index c745002bd2..2be1f58686 100644 --- a/packager/pkgmanager.pas +++ b/packager/pkgmanager.pas @@ -47,9 +47,9 @@ uses Classes, SysUtils, LCLProc, Forms, Controls, FileCtrl, Dialogs, Menus, CodeToolManager, CodeCache, Laz_XMLCfg, AVL_Tree, LazarusIDEStrConsts, KeyMapping, EnvironmentOpts, IDEProcs, ProjectDefs, - InputHistory, IDEDefs, UComponentManMain, PackageEditor, AddToPackageDlg, - PackageDefs, PackageLinks, PackageSystem, ComponentReg, OpenInstalledPkgDlg, - PkgGraphExporer, + InputHistory, IDEDefs, UComponentManMain, Project, ComponentReg, + PackageEditor, AddToPackageDlg, PackageDefs, PackageLinks, PackageSystem, + OpenInstalledPkgDlg, PkgGraphExporer, BrokenDependenciesDlg, BasePkgManager, MainBar; type @@ -64,11 +64,12 @@ type var HasRegisterProc: boolean); function OnPackageEditorOpenPackage(Sender: TObject; APackage: TLazPackage ): TModalResult; - function OnPackageEditorSavePackage(Sender: TObject; - APackage: TLazPackage): TModalResult; + function OnPackageEditorSavePackage(Sender: TObject; APackage: TLazPackage; + SaveAs: boolean): TModalResult; procedure PackageGraphChangePackageName(APackage: TLazPackage; const OldName: string); procedure PackageGraphDeletePackage(APackage: TLazPackage); + procedure PackageGraphDependencyModified(ADependency: TPkgDependency); function PackageGraphExplorerOpenPackage(Sender: TObject; APackage: TLazPackage): TModalResult; procedure PkgManagerAddPackage(Pkg: TLazPackage); @@ -99,7 +100,10 @@ type Flags: TPkgOpenFlags): TModalResult; override; function DoSavePackage(APackage: TLazPackage; Flags: TPkgSaveFlags): TModalResult; override; + function DoSaveAllPackages(Flags: TPkgSaveFlags): TModalResult; override; function DoShowPackageGraph: TModalResult; + function DoClosePackageEditor(APackage: TLazPackage): TModalResult; override; + function DoCloseAllPackageEditors: TModalResult; override; end; implementation @@ -223,9 +227,12 @@ begin end; function TPkgManager.OnPackageEditorSavePackage(Sender: TObject; - APackage: TLazPackage): TModalResult; + APackage: TLazPackage; SaveAs: boolean): TModalResult; begin - Result:=DoSavePackage(APackage,[]); + if SaveAs then + Result:=DoSavePackage(APackage,[psfSaveAs]) + else + Result:=DoSavePackage(APackage,[]); end; procedure TPkgManager.PackageGraphChangePackageName(APackage: TLazPackage; @@ -243,6 +250,18 @@ begin end; end; +procedure TPkgManager.PackageGraphDependencyModified(ADependency: TPkgDependency + ); +var + DepOwner: TObject; +begin + DepOwner:=ADependency.Owner; + if DepOwner is TLazPackage then + TLazPackage(DepOwner).Modified:=true + else if DepOwner is TProject then + TProject(DepOwner).Modified:=true; +end; + function TPkgManager.PackageGraphExplorerOpenPackage(Sender: TObject; APackage: TLazPackage): TModalResult; begin @@ -304,6 +323,8 @@ var ConflictPkg: TLazPackage; PkgFile: TPkgFile; LowerFilename: String; + BrokenDependencies: TList; + RenameDependencies: Boolean; begin OldPkgFilename:=APackage.Filename; @@ -402,6 +423,22 @@ begin continue; // try again end; + // check for broken dependencies + BrokenDependencies:=PackageGraph.GetBrokenDependenciesWhenChangingPkgID( + APackage,NewPkgName,APackage.Version); + RenameDependencies:=false; + try + if BrokenDependencies.Count>0 then begin + Result:=ShowBrokenDependencies(BrokenDependencies, + DefaultBrokenDepButtons); + if Result=mrAbort then exit; + if Result=mrRetry then continue; + if Result=mrYes then RenameDependencies:=true; + end; + finally + BrokenDependencies.Free; + end; + // check existing file if (CompareFilenames(NewFileName,OldPkgFilename)<>0) and FileExists(NewFileName) then begin @@ -411,6 +448,10 @@ begin if Result<>mrOk then exit; end; + // check if new file is read/writable + Result:=MainIDE.DoCheckCreatingFile(NewFileName,true); + if Result=mrAbort then exit; + until Result<>mrRetry; finally InputHistories.StoreFileDialogSettings(SaveDialog); @@ -421,17 +462,9 @@ begin APackage.Filename:=NewFilename; // rename package - if NewPkgName<>APackage.Name then begin - if AnsiCompareText(NewPkgName,APackage.Name)=0 then begin - // just change the case - APackage.Name:=NewPkgName; - end else begin - // name change -> update package graph - APackage.Name:=NewPkgName; - // ToDo: update package graph - end; - end; - + PackageGraph.ChangePackageID(APackage,NewPkgName,APackage.Version, + RenameDependencies); + // clean up old package file to reduce ambigiousities if FileExists(OldPkgFilename) and (CompareFilenames(OldPkgFilename,NewFilename)<>0) then begin @@ -444,8 +477,7 @@ begin EnvironmentOptions.RecentPackageFiles); end else begin MessageDlg('Delete failed', - 'Deleting of file "'+OldPkgFilename+'"' - +' failed.',mtError,[mbOk],0); + 'Unable to delete file "'+OldPkgFilename+'".',mtError,[mbOk],0); end; end; end; @@ -465,6 +497,7 @@ begin PackageGraph.OnChangePackageName:=@PackageGraphChangePackageName; PackageGraph.OnAddPackage:=@PkgManagerAddPackage; PackageGraph.OnDeletePackage:=@PackageGraphDeletePackage; + PackageGraph.OnDependencyModified:=@PackageGraphDependencyModified; PackageEditors:=TPackageEditors.Create; PackageEditors.OnOpenFile:=@MainIDE.DoOpenMacroFile; @@ -579,6 +612,7 @@ begin NewPackage:=PackageGraph.NewPackage('NewPackage'); NewPackage.AddRequiredDependency( PackageGraph.FCLPackage.CreateDependencyForThisPkg); + NewPackage.Modified:=false; // open a package editor CurEditor:=PackageEditors.OpenEditor(NewPackage); @@ -670,18 +704,29 @@ begin Result:=mrAbort; exit; end; - MainIDE.SaveSourceEditorChangesToCodeCache(-1); - + if APackage.IsVirtual then Include(Flags,psfSaveAs); // check if package needs saving - if (not (psfSaveAs in Flags)) and (not APackage.ReadOnly) - and (not APackage.Modified) + if (not (psfSaveAs in Flags)) + and (not APackage.ReadOnly) and (not APackage.Modified) and FileExists(APackage.Filename) then begin Result:=mrOk; exit; end; + // ask user if package should be saved + if pfAskBeforeSaving in Flags then begin + Result:=MessageDlg('Save package?', + 'Package "'+APackage.IDAsString+'" changed. Save?', + mtConfirmation,[mbYes,mbNo,mbAbort],0); + if (Result=mrNo) then Result:=mrIgnore; + if Result<>mrOk then exit; + end; + + // save editor files to codetools + MainIDE.SaveSourceEditorChangesToCodeCache(-1); + // save package if (psfSaveAs in Flags) then begin Result:=DoShowSavePackageAsDialog(APackage); @@ -697,6 +742,7 @@ begin // save try + ClearFile(APackage.Filename,true); XMLConfig:=TXMLConfig.Create(APackage.Filename); try XMLConfig.Clear; @@ -709,12 +755,13 @@ begin on E: Exception do begin Result:=MessageDlg('Error Writing Package', 'Unable to write package "'+APackage.IDAsString+'"'#13 - +'to file "'+APackage.Filename+'".', + +'to file "'+APackage.Filename+'".'#13 + +'Error: '+E.Message, mtError,[mbAbort,mbCancel],0); exit; end; end; - + // success APackage.Modified:=false; // add to recent @@ -735,5 +782,58 @@ begin Result:=mrOk; end; +function TPkgManager.DoCloseAllPackageEditors: TModalResult; +var + APackage: TLazPackage; +begin + while PackageEditors.Count>0 do begin + APackage:=PackageEditors.Editors[PackageEditors.Count-1].LazPackage; + Result:=DoClosePackageEditor(APackage); + if Result<>mrOk then exit; + end; + Result:=mrOk; +end; + +function TPkgManager.DoClosePackageEditor(APackage: TLazPackage): TModalResult; +begin + if APackage.Editor<>nil then begin + APackage.Editor.Free; + end; + Result:=mrOk; +end; + +function TPkgManager.DoSaveAllPackages(Flags: TPkgSaveFlags): TModalResult; +var + AllSaved: Boolean; + i: Integer; + CurPackage: TLazPackage; +begin + try + repeat + AllSaved:=true; + i:=0; + while imrOk then exit; + AllSaved:=false; + end; + inc(i); + end; + until AllSaved; + finally + // clear all lpfSkipSaving flags + for i:=0 to PackageGraph.Count-1 do begin + CurPackage:=PackageGraph[i]; + CurPackage.Flags:=CurPackage.Flags-[lpfSkipSaving]; + end; + end; + Result:=mrOk; +end; + end. diff --git a/packager/pkgoptionsdlg.pas b/packager/pkgoptionsdlg.pas index 69164130c4..0350c4b3dc 100644 --- a/packager/pkgoptionsdlg.pas +++ b/packager/pkgoptionsdlg.pas @@ -39,8 +39,8 @@ interface uses Classes, SysUtils, Forms, Controls, Buttons, LResources, ExtCtrls, StdCtrls, - Spin, Dialogs, PathEditorDlg, IDEProcs, IDEOptionDefs, - PackageDefs, PackageSystem; + Spin, Dialogs, PathEditorDlg, IDEProcs, IDEOptionDefs, LazarusIDEStrConsts, + BrokenDependenciesDlg, PackageDefs, PackageSystem; type TPackageOptionsDialog = class(TForm) @@ -89,6 +89,9 @@ type procedure AddOptionsGroupBoxResize(Sender: TObject); procedure AddPathsGroupBoxResize(Sender: TObject); procedure DescriptionPageResize(Sender: TObject); + procedure OkButtonClick(Sender: TObject); + procedure PackageOptionsDialogClose(Sender: TObject; + var Action: TCloseAction); procedure PackageOptionsDialogResize(Sender: TObject); procedure PathEditBtnClick(Sender: TObject); procedure PathEditBtnExecuted(Sender: TObject); @@ -104,6 +107,7 @@ type procedure ReadOptionsFromPackage; procedure ReadPkgTypeFromPackage; function GetEditForPathButton(AButton: TPathEditorButton): TEdit; + procedure ShowMsgPackageTypeMustBeDesign; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; @@ -196,12 +200,7 @@ begin then begin // user sets to runtime only if (LazPackage.AutoInstall<>pitNope) then begin - MessageDlg('Invalid package type', - 'The package "'+LazPackage.IDAsString+'" has the auto install flag.'#13 - +'This means it will be installed in the IDE. Installation packages'#13 - +'must be designtime Packages.', - mtError,[mbCancel],0); - ReadPkgTypeFromPackage; + ShowMsgPackageTypeMustBeDesign; end; end; end; @@ -296,6 +295,89 @@ begin SetBounds(x,y,w,90); end; +procedure TPackageOptionsDialog.OkButtonClick(Sender: TObject); +var + NewPackageType: TLazPackageType; + NewVersion: TPkgVersion; + BrokenDependencies: TList; + RenameDependencies: Boolean; + MsgResult: TModalResult; +begin + if LazPackage.ReadOnly then exit; + + // check changes + + // package type + case PkgTypeRadioGroup.ItemIndex of + 0: NewPackageType:=lptDesignTime; + 1: NewPackageType:=lptRunTime; + else NewPackageType:=lptRunAndDesignTime; + end; + if NewPackageType<>LazPackage.PackageType then begin + if (NewPackageType=lptRunTime) and (LazPackage.AutoInstall<>pitNope) then + begin + ShowMsgPackageTypeMustBeDesign; + exit; + end; + end; + + // version + NewVersion:=TPkgVersion.Create; + try + NewVersion.Major:=round(VersionMajorSpinEdit.Value); + NewVersion.Minor:=round(VersionMinorSpinEdit.Value); + NewVersion.Release:=round(VersionReleaseSpinEdit.Value); + NewVersion.Build:=round(VersionBuildSpinEdit.Value); + + // check for broken dependencies + BrokenDependencies:=PackageGraph.GetBrokenDependenciesWhenChangingPkgID( + LazPackage,LazPackage.Name,NewVersion); + RenameDependencies:=false; + try + if BrokenDependencies.Count>0 then begin + MsgResult:=ShowBrokenDependencies(BrokenDependencies, + DefaultBrokenDepButtons); + if MsgResult=mrYes then + RenameDependencies:=true + else if MsgResult=mrNo then + RenameDependencies:=false + else + exit; + end; + finally + BrokenDependencies.Free; + end; + + PackageGraph.ChangePackageID(LazPackage,LazPackage.Name,NewVersion, + RenameDependencies); + finally + NewVersion.Free; + end; + + // Description page + LazPackage.Description:=DescriptionMemo.Text; + LazPackage.Author:=AuthorEdit.Text; + LazPackage.AutoIncrementVersionOnBuild:=AutoIncrementOnBuildCheckBox.Checked; + + // Usage page + LazPackage.PackageType:=NewPackageType; + LazPackage.AutoUpdate:=(UpdateRadioGroup.ItemIndex=0); + with LazPackage.AddDependCompilerOptions do begin + UnitPath:=UnitPathEdit.Text; + IncludePath:=IncludePathEdit.Text; + ObjectPath:=ObjectPathEdit.Text; + LibraryPath:=LibraryPathEdit.Text; + LinkerOptions:=LinkerOptionsMemo.Text; + CustomOptions:=CustomOptionsMemo.Text; + end; +end; + +procedure TPackageOptionsDialog.PackageOptionsDialogClose(Sender: TObject; + var Action: TCloseAction); +begin + IDEDialogLayoutList.SaveLayout(Self); +end; + procedure TPackageOptionsDialog.AddPathsGroupBoxResize(Sender: TObject); var LabelLeft: Integer; @@ -385,6 +467,7 @@ begin Name:='OkButton'; Caption:='Ok'; Parent:=Self; + OnClick:=@OkButtonClick; end; CancelButton:=TButton.Create(Self); @@ -688,6 +771,8 @@ end; procedure TPackageOptionsDialog.ReadOptionsFromPackage; begin if LazPackage=nil then exit; + + OkButton.Enabled:=not LazPackage.ReadOnly; // Description page DescriptionMemo.Text:=LazPackage.Description; @@ -739,6 +824,16 @@ begin Result:=nil; end; +procedure TPackageOptionsDialog.ShowMsgPackageTypeMustBeDesign; +begin + MessageDlg('Invalid package type', + 'The package "'+LazPackage.IDAsString+'" has the auto install flag.'#13 + +'This means it will be installed in the IDE. Installation packages'#13 + +'must be designtime Packages.', + mtError,[mbCancel],0); + ReadPkgTypeFromPackage; +end; + constructor TPackageOptionsDialog.Create(TheOwner: TComponent); begin inherited Create(TheOwner); @@ -749,6 +844,7 @@ begin Position:=poScreenCenter; IDEDialogLayoutList.ApplyLayout(Self,450,400); OnResize(Self); + OnClose:=@PackageOptionsDialogClose; end; destructor TPackageOptionsDialog.Destroy;