unit FormList;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  ActnList, Menus, ItemList, FormEx;

type
  { TFormList }

  TFormList = class(TFormEx)
    AAdd: TAction;
    ASelectAll: TAction;
    AModify: TAction;
    ARemove: TAction;
    AClone: TAction;
    ActionList1: TActionList;
    ListView1: TListView;
    MenuItem1: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    MenuItem4: TMenuItem;
    MenuItem5: TMenuItem;
    PopupMenu1: TPopupMenu;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    procedure AAddExecute(Sender: TObject);
    procedure ACloneExecute(Sender: TObject);
    procedure AModifyExecute(Sender: TObject);
    procedure ARemoveExecute(Sender: TObject);
    procedure ASelectAllExecute(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ListView1CustomDrawSubItem(Sender: TCustomListView;
      Item: TListItem; SubItem: Integer; State: TCustomDrawState;
      var DefaultDraw: Boolean);
    procedure ListView1Data(Sender: TObject; Item: TListItem);
    procedure ListView1KeyPress(Sender: TObject; var Key: char);
    procedure ListView1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
      );
    procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
  private
    FImages: TImageList;
    FList: TBaseItemList;
    procedure SetImages(AValue: TImageList);
    procedure SetList(AValue: TBaseItemList);
    procedure UpdateListViewColumns;
  public
    MinItemCount: Integer;
    MaxItemCount: Integer;
    procedure UpdateInterface;
    procedure UpdateList;
    property List: TBaseItemList read FList write SetList;
    property Images: TImageList read FImages write SetImages;
  end;


implementation

{$R *.lfm}

uses
  FormItem;

resourcestring
  SRemoveItems = 'Remove items';
  SRemoveItemsQuery = 'Do you want to remove selected items?';

{ TFormList }

procedure TFormList.ARemoveExecute(Sender: TObject);
var
  I: Integer;
begin
  if Assigned(ListView1.Selected) then begin
    if MessageDlg(SRemoveItems, SRemoveItemsQuery,
    TMsgDlgType.mtConfirmation, [mbCancel, mbOk], 0) = mrOk then begin
      for I := ListView1.Items.Count - 1 downto 0 do
        if ListView1.Items[I].Selected then begin
          if List.Count <= MinItemCount then Break;
          ListView1.Items[I].Selected := False;
          FList.Remove(TItem(ListView1.Items[I].Data));
        end;
      UpdateList;
      UpdateInterface;
    end;
  end;
end;

procedure TFormList.AModifyExecute(Sender: TObject);
var
  TempEntry: TItem;
  FormItem: TFormItem;
begin
  if Assigned(ListView1.Selected) then
  with TItem(ListView1.Selected.Data) do begin
    TempEntry := FList.CreateItem;
    TempEntry.Assign(TItem(ListView1.Selected.Data));
    FormItem := TFormItem.Create(Self);
    try
      FormItem.Item := TempEntry;
      if FormItem.ShowModal = mrOk then begin
        TItem(ListView1.Selected.Data).Assign(TempEntry);
        UpdateList;
        UpdateInterface;
      end;
    finally
      FreeAndNil(FormItem);
      FreeAndNil(TempEntry);
    end;
  end;
end;

procedure TFormList.AAddExecute(Sender: TObject);
var
  TempEntry: TItem;
  FormItem: TFormItem;
begin
  if (MaxItemCount <> -1) and (FList.Count >= MaxItemCount) then Exit;

  TempEntry := FList.CreateItem;
  FormItem := TFormItem.Create(Self);
  try
    TempEntry.Name := FList.GetNextAvailableName(List.GetName);
    FormItem.Item := TempEntry;
    if FormItem.ShowModal = mrOk then begin
      FList.Add(TempEntry);
      TempEntry := nil;
      UpdateList;
      UpdateInterface;
    end;
  finally
    FreeAndNil(FormItem);
  end;
  TempEntry.Free;
end;

procedure TFormList.ACloneExecute(Sender: TObject);
var
  TempEntry: TItem;
  FormItem: TFormItem;
begin
  if (MaxItemCount <> -1) and (FList.Count >= MaxItemCount) then Exit;

  TempEntry := FList.CreateItem;
  TempEntry.Assign(TItem(ListView1.Selected.Data));
  FormItem := TFormItem.Create(Self);
  try
    TempEntry.Name := List.GetNextAvailableName(TempEntry.Name);
    FormItem.Item := TempEntry;
    if FormItem.ShowModal = mrOk then begin
      FList.Add(TempEntry);
      TempEntry := nil;
      UpdateList;
      UpdateInterface;
    end;
  finally
    FreeAndNil(FormItem);
  end;
  TempEntry.Free;
end;

procedure TFormList.ASelectAllExecute(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to ListView1.Items.Count - 1 do
    ListView1.Items[I].Selected := True;
end;

procedure TFormList.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to ToolBar1.ButtonCount - 1 do
    ToolBar1.Buttons[I].Hint := ToolBar1.Buttons[I].Caption;
  MinItemCount := 0;
  MaxItemCount := -1;
end;

procedure TFormList.FormDestroy(Sender: TObject);
begin
  List := nil;
end;

procedure TFormList.FormShow(Sender: TObject);
begin
  UpdateListViewColumns;
  UpdateList;
  UpdateInterface;
end;

procedure TFormList.ListView1CustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  ItemFields: TItemFields;
  ItemField: TItemField;
  DrawRect: TRect;
begin
  ItemFields := TItem(Item.Data).GetFields;
  try
    ItemField := ItemFields[SubItem];
    with ListView1.Canvas do
    if ItemField.DataType = dtColor then begin
      Brush.Color := TItem(Item.Data).GetValueColor(ItemField.Index);
      Brush.Style := bsSolid;
      DrawRect := Item.DisplayRectSubItem(SubItem, drBounds);
      {$IFDEF LCLQT5}
      // TODO: Wrong rectangle width on Qt5
      if DrawRect.Width > ListView1.Columns[SubItem].Width then
        DrawRect.Width := ListView1.Columns[SubItem].Width;
      {$ENDIF}
      FillRect(DrawRect);
      end;
  finally
    ItemFields.Free;
  end;
end;

procedure TFormList.ListView1Data(Sender: TObject; Item: TListItem);
var
  I: Integer;
  Fields: TItemFields;
begin
  if Item.Index < ListView1.Items.Count then
  with FList[Item.Index] do begin
    //Item.Caption := GetName;
    Item.Data := FList[Item.Index];
    Fields := FList.GetItemFields;
    try
      for I := 0 to Fields.Count - 1 do begin
        if I = 0 then Item.Caption := GetValueAsText(Fields[I].Index)
          else Item.SubItems.Add(GetValueAsText(Fields[I].Index));
      end;
    finally
      Fields.Free;
    end;
  end;
end;

procedure TFormList.ListView1KeyPress(Sender: TObject; var Key: char);
begin
  if Key = #13 then AModify.Execute;
  if Key = #27 then Close;
end;

procedure TFormList.ListView1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = 45 then AAdd.Execute;
  if Key = 46 then ARemove.Execute;
end;

procedure TFormList.ListView1SelectItem(Sender: TObject;
  Item: TListItem; Selected: Boolean);
begin
  UpdateInterface;
end;

procedure TFormList.SetList(AValue: TBaseItemList);
begin
  if FList = AValue then Exit;
  FList := AValue;
  UpdateInterface;
  UpdateList;
end;

procedure TFormList.SetImages(AValue: TImageList);
begin
  if FImages = AValue then Exit;
  FImages := AValue;
  ToolBar1.Images := FImages;
  PopupMenu1.Images := FImages;
end;

procedure TFormList.UpdateListViewColumns;
var
  I: Integer;
  Fields: TItemFields;
begin
  if not Assigned(FList) then begin
    while ListView1.Columns.Count > 0 do
      ListView1.Columns.Delete(ListView1.Columns.Count - 1);
    Exit;
  end;
  Fields := List.GetItemFields;
  ListView1.Columns.BeginUpdate;
  try
    while ListView1.Columns.Count < Fields.Count do
      ListView1.Columns.Add;
    while ListView1.Columns.Count > Fields.Count do
      ListView1.Columns.Delete(ListView1.Columns.Count - 1);
    for I := 0 to ListView1.Columns.Count - 1 do begin
      ListView1.Columns[I].Caption := Fields[I].Name;
      ListView1.Columns[I].Width := Scale96ToScreen(100);
    end;
  finally
    ListView1.Columns.EndUpdate;
  end;
  Fields.Free;
end;

procedure TFormList.UpdateInterface;
begin
  ARemove.Enabled := Assigned(FList) and Assigned(ListView1.Selected) and ((List.Count - ListView1.SelCount) >= MinItemCount);
  AModify.Enabled := Assigned(FList) and Assigned(ListView1.Selected);
  AAdd.Enabled := Assigned(FList) and ((MaxItemCount = -1) or ((MaxItemCount <> -1) and (List.Count < MaxItemCount)));
  AClone.Enabled := Assigned(FList) and ((MaxItemCount = -1) or ((MaxItemCount <> -1) and (List.Count < MaxItemCount)));
  ASelectAll.Enabled := ListView1.Items.Count > 0;
end;

procedure TFormList.UpdateList;
begin
  if Assigned(FList) then ListView1.Items.Count := FList.Count
    else ListView1.Items.Count := 0;
  ListView1.Refresh;
end;

end.

