unit Unit2;

interface

{$I ..\..\..\Source\Compilers.inc}

uses
  SysUtils,
  Classes,
  Contnrs,
  {$IFDEF COMPILER_6_UP}
  Variants,
  {$ENDIF COMPILER_6_UP}
  StrUtils,
  EasyListview;

type
  TEmployee = class(TObject, // you could use any base class here
                    IInterface, // the list item can only be associated with an IInterface
                    IEasyCaptions, // implement only those interfaces you want to return data for
                    IEasyImages,
                    IEasyDetails,
                    IEasyNotifier,
                    IEasyCaptionsEditable,
                    IEasyCompare)
  private
    FFirstname: WideString;
    FImageIndex: Integer;
    FLastname: WideString;
    FNotifier: IEasyNotificationSink;
  protected
    // IUnknown: in this case we don't use reference counting (although we could)
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    // IEasyCaptions: provide captions for all columns and details for the tiled view
    function GetCaption(Column: Integer): Variant;
    // IEasyImages: provide imagelist indexes for normal, state and overlay images
    function GetImageIndex(Column: Integer; ImageKind: TEasyImageKind): Integer;
    // IEasyDetails: provide a few captions (columns) for the tiled view
    function GetDetail(Line: Integer): Integer;
    function GetDetailCount: Integer;
    // IEasyNotifier: report data changes back to the listitem
    procedure OnRegisterNotify(const ANotifier: IEasyNotificationSink);
    procedure OnUnRegisterNotify(const ANotifier: IEasyNotificationSink);
    // IEasyCaptionsEditable: accept edits from the listitem
    function SetCaption(Column: Integer; const Value: Variant): Boolean;
    // IEasyCompareData: compare data to allow listitem sorting
    function Compare(const Data: IUnknown; Column: TEasyColumn): Integer;
  public
    constructor Create(Lastname, Firstname: WideString; ImageIndex: Integer);
    destructor Destroy; override;
    procedure ToggleFunnyName;
    property Firstname: WideString read FFirstname;
    property Lastname: WideString read FLastname;
  end;

  TEmployees = class
  private
    FList: TObjectList;
    function GetCount: Integer;
    function GetEmployee(Index: Integer): TEmployee;
  public
    constructor Create;
    destructor Destroy; override;
    procedure BeSilly;
    procedure Load;
    property Count: Integer read GetCount;
    property Employees[Index: Integer]: TEmployee read GetEmployee; default;
  end;

implementation

{ TEmployee }

function TEmployee.Compare(const Data: IUnknown; Column: TEasyColumn): Integer;
begin
  Result := 0; // TODO
end;

constructor TEmployee.Create(Lastname, Firstname: WideString;
  ImageIndex: Integer);
begin
  inherited Create;
  FFirstname := Firstname;
  FLastname := Lastname;
  FImageIndex := ImageIndex;
end;

destructor TEmployee.Destroy;
begin
  inherited;
end;

function TEmployee.GetCaption(Column: Integer): Variant;
begin
  case Column of
    0: Result := Lastname;
    1: Result := Firstname;
  else
    Result := Null;
  end;
end;

function TEmployee.GetDetail(Line: Integer): Integer;
begin
  Result := Line;
end;

function TEmployee.GetDetailCount: Integer;
begin
  Result := 2;
end;

function TEmployee.GetImageIndex(Column: Integer;
  ImageKind: TEasyImageKind): Integer;
begin
  if (Column = 0) and (ImageKind = eikNormal) then
    Result := FImageIndex
  else
    Result := -1;
end;

procedure TEmployee.OnRegisterNotify(const ANotifier: IEasyNotificationSink);
begin
  // Remember this notifier because we will use it later to talk back to the
  // list item.
  FNotifier := ANotifier;
end;

procedure TEmployee.OnUnRegisterNotify(const ANotifier: IEasyNotificationSink);
begin
  // The list item will not be available anymore and we must forget its
  // then useless notifier.
  FNotifier := nil;
end;

function TEmployee.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TEmployee.SetCaption(Column: Integer; const Value: Variant): Boolean;
var
  NewName: WideString;
begin
  // The caption of the given column has been edited. For this demo we
  // allow editing column 0 only.
  // You may check the input and reject it, e.g. if it does not have a suitable
  // format. Let's require a minimum length of 3 characters.
  NewName := Value;
  Result := (Column = 0) and (Length(NewName) >= 3);
  if Result then
    FLastname := NewName // will be invalidated automatically via IEasyCaptions
//  else
//    raise Exception.Create('name must have at least 3 characters');
end;

procedure TEmployee.ToggleFunnyName;
begin
  FLastname := ReverseString(FLastname);
  if FNotifier <> nil then
    FNotifier.InvalidateItem(True);
end;

function TEmployee._AddRef: Integer;
begin
  Result := -1;
end;

function TEmployee._Release: Integer;
begin
  Result := -1;
end;

{ TEmployees }

procedure TEmployees.BeSilly;
begin
  if Count > 0 then
    Employees[Random(Count)].ToggleFunnyName;
end;

constructor TEmployees.Create;
begin
  inherited Create;
  FList := TObjectList.Create;
end;

destructor TEmployees.Destroy;
begin
  FList.Free;
  inherited;
end;

function TEmployees.GetCount: Integer;
begin
  Result := FList.Count;
end;

function TEmployees.GetEmployee(Index: Integer): TEmployee;
begin
  Result := TEmployee(FList[Index]);
end;

procedure TEmployees.Load;
begin
  // We could load data from disk but for this demo it may suffice to have
  // some static data.
  FList.Clear;
  FList.Add(TEmployee.Create('Aniston', 'Jennifer', 0));
  FList.Add(TEmployee.Create('Carrey', 'Jim', 1));
  FList.Add(TEmployee.Create('Knightley', 'Keira', 2));
  FList.Add(TEmployee.Create('Lester', 'Adrian', 3));
  FList.Add(TEmployee.Create('Marceau', 'Sophie', 4));
  FList.Add(TEmployee.Create('Reno', 'Jean', 5));
end;

end.

