Files
lazarus-ccr/components/jvcllaz/run/JvStdCtrls/jvlinkedcontrols.pas
2018-09-28 11:09:45 +00:00

284 lines
8.4 KiB
ObjectPascal

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvLinkedControls.PAS, released on 2004-01-26.
The Initial Developer of the Original Code is Peter Thörnqvist
Portions created by Peter Thörnqvist are Copyright (C) 2004 Peter Thörnqvist.
All Rights Reserved.
Contributor(s):
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.delphi-jedi.org
Known Issues:
-----------------------------------------------------------------------------}
// $Id$
unit JvLinkedControls;
{$mode objfpc}{$H+}
interface
uses
SysUtils, Controls, Classes;
type
TJvLinkedControlsOption = (loLinkChecked, loLinkEnabled, loInvertChecked, loInvertEnabled, loForceFocus);
TJvLinkedControlsOptions = set of TJvLinkedControlsOption;
TJvLinkedControl = class(TCollectionItem)
private
FOwnerControl, FControl: TControl;
FOptions: TJvLinkedControlsOptions;
FOriginalEnabled: Boolean;
procedure SetControl(const Value: TControl);
procedure SetOptions(const Value: TJvLinkedControlsOptions);
protected
function GetDisplayName: string; override;
public
constructor Create(ACollection: TCollection); override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
published
property Control: TControl read FControl write SetControl;
property Options: TJvLinkedControlsOptions read FOptions write SetOptions default [loLinkChecked, loLinkEnabled];
end;
TJvLinkedControls = class(TOwnedCollection)
private
FControl: TControl;
FOnChange: TNotifyEvent;
FRestoreEnabled: Boolean;
function GetItems(Index: Integer): TJvLinkedControl;
procedure SetItems(Index: Integer; const Value: TJvLinkedControl);
protected
procedure Update(Item: TCollectionItem); override;
public
// You must call Notification in the Owning controls overridden Notification
// or hell will break loose when linked controls are removed!!!
procedure Notification(AComponent: TComponent; Operation: TOperation); virtual;
constructor Create(AControl: TControl);
function Add: TJvLinkedControl;
procedure Assign(Source: TPersistent); override;
// If RestoreEnabled is True, TJvLinkedControls will try to restore the Enabled state
// of linked controls when an item is changed or removed
property Items[Index: Integer]: TJvLinkedControl read GetItems write SetItems; default;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
published
property RestoreEnabled: Boolean read FRestoreEnabled write FRestoreEnabled default True;
end;
function CheckLinkControlEnabled(Enabled, Checked: Boolean; Options: TJvLinkedControlsOptions): Boolean;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL$';
Revision: '$Revision$';
Date: '$Date$';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
JvResources;
function CheckLinkControlEnabled(Enabled, Checked: Boolean; Options: TJvLinkedControlsOptions): Boolean;
var
IsChecked, IsEnabled: Boolean;
begin
if loInvertChecked in Options then
IsChecked := not Checked
else
IsChecked := Checked;
if loInvertEnabled in Options then
IsEnabled := not Enabled
else
IsEnabled := Enabled;
if (loLinkChecked in Options) and (loLinkEnabled in Options) then
Result := IsChecked and IsEnabled
else
Result := ((loLinkChecked in Options) and IsChecked) or ((loLinkEnabled in Options) and IsEnabled);
// Result := ((loLinkChecked in Options) and ((not Checked and (loInvertChecked in Options) or (Checked and not (loInvertChecked in Options))))) or
// ((loLinkEnabled in Options) and (not Enabled and (loInvertEnabled in Options)) or (Enabled and not (loInvertEnabled in Options)));
end;
//=== { TJvLinkedControl } ===================================================
constructor TJvLinkedControl.Create(ACollection: TCollection);
begin
inherited Create(ACollection);
if (ACollection is TJvLinkedControls) then
FOwnerControl := TJvLinkedControls(ACollection).FControl;
FOptions := [loLinkChecked, loLinkEnabled];
end;
destructor TJvLinkedControl.Destroy;
begin
if (FControl <> nil) and not (csDestroying in FControl.ComponentState) and
(Collection is TJvLinkedControls) and TJvLinkedControls(Collection).RestoreEnabled then
FControl.Enabled := FOriginalEnabled;
inherited Destroy;
end;
procedure TJvLinkedControl.Assign(Source: TPersistent);
begin
if Source is TJvLinkedControl then
begin
if Source <> Self then
begin
Control := TJvLinkedControl(Source).Control;
Options := TJvLinkedControl(Source).Options;
Changed(False);
end;
end
else
inherited Assign(Source);
end;
function TJvLinkedControl.GetDisplayName: string;
begin
if Control <> nil then
Result := Control.Name
else
Result := inherited GetDisplayName;
end;
procedure TJvLinkedControl.SetControl(const Value: TControl);
begin
if FControl <> Value then
begin
if (FOwnerControl = nil) and (Collection is TJvLinkedControls) then
FOwnerControl := TJvLinkedControls(Collection).FControl;
if (Value = FOwnerControl) and (FOwnerControl <> nil) then
raise Exception.CreateRes(@RsEOwnerLinkError);
if Assigned(FControl) then
begin
if Assigned(FOwnerControl) then
FControl.RemoveFreeNotification(FOwnerControl);
if (Collection is TJvLinkedControls) and TJvLinkedControls(Collection).RestoreEnabled and
not (csDestroying in FControl.ComponentState) then
FControl.Enabled := FOriginalEnabled;
end;
if (FOwnerControl <> nil) and (csDestroying in FOwnerControl.ComponentState) then
FControl := nil
else
FControl := Value;
if Assigned(FControl) then
begin
FOriginalEnabled := FControl.Enabled;
if Assigned(FOwnerControl) then
FControl.FreeNotification(FOwnerControl);
end;
Changed(False);
end;
end;
procedure TJvLinkedControl.SetOptions(const Value: TJvLinkedControlsOptions);
begin
if FOptions <> Value then
begin
FOptions := Value;
Changed(False);
end;
end;
//=== { TJvLinkedControls } ==================================================
constructor TJvLinkedControls.Create(AControl: TControl);
begin
inherited Create(AControl, TJvLinkedControl);
FControl := AControl;
FRestoreEnabled := True;
end;
function TJvLinkedControls.Add: TJvLinkedControl;
begin
Result := TJvLinkedControl(inherited Add);
Result.FOwnerControl := FControl;
end;
procedure TJvLinkedControls.Assign(Source: TPersistent);
var
I: Integer;
begin
if Source is TJvLinkedControls then
begin
if Source <> Self then
begin
BeginUpdate;
try
Clear;
for I := 0 to TJvLinkedControls(Source).Count - 1 do
Add.Assign(TJvLinkedControls(Source)[I]);
RestoreEnabled := TJvLinkedControls(Source).RestoreEnabled;
finally
EndUpdate;
end;
end;
end
else
inherited Assign(Source);
end;
function TJvLinkedControls.GetItems(Index: Integer): TJvLinkedControl;
begin
Result := TJvLinkedControl(inherited Items[Index]);
end;
procedure TJvLinkedControls.Notification(AComponent: TComponent; Operation: TOperation);
var
I: Integer;
begin
if (Operation = opRemove) and (AComponent is TControl) then
begin
BeginUpdate;
try
for I := 0 to Count - 1 do
if Items[I].Control = AComponent then
Items[I].Control := nil;
finally
EndUpdate;
end;
end;
end;
procedure TJvLinkedControls.SetItems(Index: Integer; const Value: TJvLinkedControl);
begin
inherited Items[Index] := Value;
end;
procedure TJvLinkedControls.Update(Item: TCollectionItem);
begin
inherited Update(Item);
if Item <> nil then
TJvLinkedControl(Item).FOwnerControl := FControl;
if Assigned(FOnChange) then
FOnChange(Self);
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.