unit IEListView;
{==================================================================
 Component TIEListView / Version 1.0, September 1999
 ==================================================================


    Description:
    ============
    Basic component for TDirView.

    Author:
    =======
    (c) Ingo Eckel 1999
    Sodener Weg 38
    65812 Bad Soden
    Germany
    (c) Martin Prikryl 2001 - 2003

    For detailed documentation see the documentation of TDirView.

 ==================================================================}

{Required compiler options for TIEListView:}
{$A+,B-,X+,H+,P+}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, ActiveX, CommCtrl, Extctrls, ImgList, BaseUtils,
  ComCtrls, NortonLikeListView;

type
  TDateTimeDisplay = (dtdDateTimeSec, dtdDateTime, dtdDate);

type
  TIEListView = class(TCustomNortonLikeListView)
  private
    FSortColumn: Integer;
    FSortAscending: Boolean;
    FColumnIconPainted: Boolean;
    FShowColumnIcon: Boolean;
    FHeaderHandle: HWND;
    FParentForm: TCustomForm;
    FMask: string;

    FOnHeaderEndDrag: TNotifyEvent;
    FOnHeaderEndTrack: TNotifyEvent;

    FDateTimeFormatStr: string;
    FDateFormatStr: string;
    FDateTimeDisplay: TDateTimeDisplay;
    FDragImageList: TDragImageList;
    FHeaderImages: TImageList;
  protected
    procedure ColPropertiesChange(Sender: TObject); virtual;

    procedure SetShowColumnIcon(Value: Boolean); virtual;
    procedure SetSortColumn(Value: Integer); virtual;
    procedure SetSortAscending(Value: Boolean); virtual;
    procedure SortItems; virtual;
    procedure SetViewStyle(Value: TViewStyle); override; // CLEAN virtual
    procedure SetDateTimeDisplay(Value: TDateTimeDisplay); virtual;
    procedure SetDateTimeFormatString; virtual;
    procedure HeaderEndDrag(Sender: TObject); virtual;
    procedure SetMask(Value: string); virtual;
    procedure SetHeaderImages(Value: TImageList); virtual;

    procedure CreateWnd; override;
    procedure ColClick(Column: TListColumn); override;
    procedure Loaded; override;
    procedure WMPaint(var Msg: TWMPaint); message WM_PAINT;
    procedure WMNotify(var Msg: TWMNotify); message WM_NOTIFY;

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetColumnImages; virtual;
    function NormalizeMask(Mask: string): string; dynamic;

    property HeaderImages: TImageList read FHeaderImages write SetHeaderImages;
    property DragImageList: TDragImageList read FDragImageList;
    property ColumnIconPainted: Boolean
      read FColumnIconPainted write FColumnIconPainted stored False;
    property HeaderHandle: HWND read FHeaderHandle;
    property ParentForm: TCustomForm read FParentForm;
    property DateTimeFormatStr: string
      read FDateTimeFormatStr write FDateTimeFormatStr stored False;
    property DateFormatStr: string read FDateFormatStr;
    {filemask, multiple filters are possible: '*.pas;*.dfm'}
    property Mask: string read FMask write SetMask;
    {Set the sort column of the listview}
    property SortColumn: Integer read FSortColumn write SetSortColumn;
    {Show the sorting symbol in the listview's header:}
    property ShowColumnIcon: Boolean
      read FShowColumnIcon write SetShowColumnIcon default True;
    {Sortorder of actual sort column}
    property SortAscending: Boolean
      read FSortAscending write SetSortAscending default True;

  published
    {Display format of the date/time of the files:}
    property DateTimeDisplay: TDateTimeDisplay
      read FDateTimeDisplay write SetDateTimeDisplay default dtdDateTimeSec;
    property OnHeaderEndDrag: TNotifyEvent
      read  FOnHeaderEndDrag write FOnHeaderEndDrag;
    property OnHeaderEndTrack: TNotifyEvent
      read  FOnHeaderEndTrack write FOnHeaderEndTrack;

    property Align;
    property AllocBy;
    property Anchors;
    property BiDiMode;
    property BorderStyle;
    property BorderWidth;
    property Checkboxes;
    property Color;
    property ColumnClick default True;
    property Constraints;
    property Ctl3D;
    property Enabled;
    property Font;
    property FlatScrollBars;
    property FullDrag;
    property GridLines;
    property HideSelection;
    property HotTrack;
    property HotTrackStyles;
    property IconOptions;
    property ReadOnly default False;
    Property RowSelect;
    property ParentBiDiMode;
    property ParentColor default False;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowColumnHeaders;
    property ShowHint;
    property TabOrder;
    property TabStop default True;
    property ViewStyle {CLEAN write SetViewStyle};
    property Visible;
    property OnChange;
    property OnChanging;
    property OnClick;
    property OnColumnClick;
    property OnColumnRightClick;
    property OnCustomDraw;
    property OwnerDraw;
    {Used for internal purposes:}
    property OnCustomDrawItem;
    property OnCustomDrawSubItem;
    property OnDblClick;
    property OnDeletion;
    property OnDrawItem;
    property OnEdited;
    property OnEditing;
    property OnEndDock;
    property OnEnter;
    property OnExit;
    property OnInsert;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnStartDock;

    property NortonLike;
    property OnSelectByMask;
  end; {Type TIEListView}

var
  GlobalDragImageList: TDragImageList;

implementation

{ TIEListView }

constructor TIEListView.Create(AOwner: TComponent);
begin
  inherited;

  ColProperties.OnChange := ColPropertiesChange;
  FHeaderImages := nil;
  FShowColumnIcon := True;
  FSortColumn := 0;
  FSortAscending := True;
  FMask := '*.*';
  SetDateTimeFormatString;
end; {Create}

procedure TIEListView.SetSortColumn(Value: Integer);
begin
  if Value <> SortColumn then
  begin
    FSortColumn := Value;
    FSortAscending := True;
    if Items.Count > 0 then
      SortItems;
    SetColumnImages;
  end;
end; {SetSortColumn}

procedure TIEListView.SetViewStyle(Value: TViewStyle);
begin
  if Value <> ViewStyle then
  begin
    inherited SetViewStyle(Value);
    if ViewStyle = vsReport then
      SetColumnImages;
  end;
end; {SetViewStyle}

procedure TIEListView.SetSortAscending(Value: Boolean);
begin
  if SortAscending <> Value then
  begin
    FSortAscending := Value;
    if Items.Count > 0 then
      SortItems;
    SetColumnImages;
  end;
end; {SetSortAscending}

procedure TIEListView.SetHeaderImages(Value: TImageList);
begin
  if FHeaderImages <> Value then
  begin
    FHeaderImages := Value;
    if FHeaderHandle <> 0 then
      Header_SetImageList(FHeaderHandle, FHeaderImages.Handle);
  end;
end;

procedure TIEListView.SetColumnImages;
var
  HdItem: THdItem;
  Index: Integer;
begin
  if ShowColumnHeaders and HandleAllocated then
  begin
    for Index := 0 to Columns.Count-1 do
    begin
      HdItem.Mask := HDI_FORMAT;
      Header_GetItem(GetDlgItem(Self.Handle,0), Index, HdItem);

      if (HeaderImages <> nil) and FShowColumnIcon and (Index = SortColumn) then
      begin
        HdItem.Mask := HDI_FORMAT or HDI_IMAGE;
        HdItem.fmt := Hditem.fmt or HDF_IMAGE;
        if SortAscending then HdItem.iImage := 0
          else HdItem.iImage := 1;
        if Columns[Index].Alignment = taLeftJustify then
          HdItem.fmt := HdItem.fmt or HDF_BITMAP_ON_RIGHT;
      end
        else HdItem.fmt := HdItem.fmt and (not HDF_IMAGE);

      Header_SetItem(GetDlgItem(Self.Handle, 0), Index, HDItem);
    end;
    FColumnIconPainted := True;
  end;
end; {SetColumnImage}

procedure TIEListView.SetShowColumnIcon(Value: Boolean);
begin
  if Value <> ShowColumnIcon then
  begin
    FShowColumnIcon := Value;
    SetColumnImages;
  end;
end; {SetShowColumnIcon}

procedure TIEListView.ColClick(Column: TListColumn);
begin
  if Column.Index = SortColumn then FSortAscending := not FSortAscending
    else
  begin
    FSortColumn := Column.Index;
    FSortAscending := True;
  end;

  if Items.Count > 0 then SortItems;

  SetColumnImages;

  inherited;
end; {ColClick}

procedure TIEListView.WMPaint(var Msg: TWMPaint);
begin
  Inherited;
  if (ViewStyle = vsReport) and not ColumnIconPainted and
     ShowColumnHeaders then SetColumnImages;
end; {WMPaint}

procedure TIEListView.WMNotify(var Msg: TWMNotify);
{Repaint header icons, if columns are resized:}
begin
  if (FHeaderHandle <> 0) and (Msg.NMHdr^.hWndFrom = FHeaderHandle) then
    case Msg.NMHdr.code of
      HDN_BEGINDRAG:
        {Due to a bug in D4 (until Update Pack 3) we should eat this message!};
      HDN_ENDDRAG:
        begin
          {Due to a bug in D4 (until Update Pack 3) we should eat this message!}
          HeaderEndDrag(Self);
          Invalidate;
          Exit;
        end;
       HDN_ENDTRACK, HDN_ENDTRACKW:
         begin
           SetColumnImages;
           FColumnIconPainted := False;
           Invalidate;
           inherited;
           if Assigned(FOnHeaderEndTrack) then
             FOnHeaderEndTrack(Self);
           Exit;
         end;
       HDN_DIVIDERDBLCLICK, HDN_DIVIDERDBLCLICKW:
         {Due to a bug in D4 (until Update Pack 3) the column property is
          not updated by this message:}
         begin
           inherited;
           with PHDNotify(Pointer(Msg.NMHdr))^ do
             if Columns.Count > Item then
               Columns[Item].Width := ListView_GetColumnWidth(Self.Handle, Item);
           if Assigned(FOnHeaderEndTrack) then
             FOnHeaderEndTrack(Self);
           SetColumnImages;
           FColumnIconPainted := False;
           Exit;
         end;
    end; {Case}

  inherited;
end; { TIElistView.WMNotify }

procedure TIEListView.HeaderEndDrag(Sender : TObject);
begin
  if Assigned(FOnHeaderEndDrag) then
    FOnHeaderEndDrag(Self);
end; {HeaderEndDrag}

procedure TIEListView.Loaded;
begin
  inherited;
  FHeaderHandle := ListView_GetHeader(Self.Handle);
  if (FHeaderImages <> nil) and (FHeaderHandle <> 0) then
    Header_SetImageList(FHeaderHandle, FHeaderImages.Handle);
end; {Loaded}

procedure TIEListView.ColPropertiesChange(Sender: TObject);
begin
  SetColumnImages;
end;

procedure TIEListView.CreateWnd;
begin
  inherited;

  FParentForm := GetParentForm(Self);
  if not (csDesigning in ComponentState) then
    FDragImageList := TDragImageList.Create(Self);
  if not Assigned(GlobalDragImageList) then
    GlobalDragImageList := DragImageList;
end; {CreateWnd}

destructor TIEListView.Destroy;
begin
  if Assigned(FDragImageList) then
  begin
    if GlobalDragImageList = FDragImageList then
      GlobalDragImageList := nil;
    FDragImageList.Free;
  end;

  inherited;
end; {Destroy}

procedure TIEListView.SetDateTimeDisplay(Value: TDateTimeDisplay);
begin
  if Value <> FDateTimeDisplay then
  begin
    FDateTimeDisplay := Value;
    SetDateTimeFormatString;
    Invalidate;
  end;
end; {SetDateTimeDisplay}

procedure TIEListView.SetDateTimeFormatString;
var
  ShortDate: string;
begin
  ShortDate := UpperCase(ShortDateFormat);
  {Create DateTime format string:}
  if Pos('YYYY', UpperCase(ShortDate)) = 0 then
  begin
    if Copy(UpperCase(ShortDate), Length(ShortDate) - 1, 2) = 'YY' then
        FDateTimeFormatStr := ShortDateFormat + 'yy'
      else
    if Copy(UpperCase(ShortDate), 1, 2) = 'YY' then
      FDateTimeFormatStr := 'yy' + ShortDateFormat;
  end
    else FDateTimeFormatStr := ShortDateFormat;

  FDateFormatStr := FDateTimeFormatStr;

  if FDateTimeDisplay = dtdDateTimeSec then
      FDateTimeFormatStr := FDateTimeFormatStr + '  ' + LongTimeFormat
    else
  if fDateTimeDisplay = dtdDateTime then
    FDateTimeFormatStr := FDateTimeFormatStr + '  ' + ShortTimeFormat;
end; {SetDateTimeFormatString}

procedure TIEListView.SetMask(Value: string);
begin
  Value := NormalizeMask(Value);
  FMask := Value;
end;{SetMask}

function TIEListView.NormalizeMask(Mask: string): string;
begin
  Mask := Trim(Mask);
  if Length(Mask) = 0 then Mask := '*.*';

  StrTranslate(Mask, ' ;,;');

  while Pos(';;', Mask) <> 0 do
    System.Delete(Mask, Pos(';;', Mask), 1);

  Result := LowerCase(Mask);
end; {NormalizeMask}

procedure TIEListView.SortItems;
begin
end;

end.