home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / EnhListView.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  81KB  |  2,573 lines

  1. {$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }
  2.  
  3. // Delphi 2 and C++B 1 have incorrectly declared InsertItem as private.
  4. {$IFDEF DFS_COMPILER_3_UP}
  5.   {$DEFINE DFS_FIXED_LIST_VIEW}
  6. {$ENDIF}
  7.  
  8. {.$DEFINE DFS_DEBUG}
  9.  
  10.  
  11. {------------------------------------------------------------------------------}
  12. { TdfsEnhListView v3.72                                                        }
  13. {------------------------------------------------------------------------------}
  14. { A list view control that provides enhanced functionality beyond the          }
  15. { standard list view.  For example, automatic sorting of simple data types,    }
  16. { owner draw event for vsReport mode, and more.  This does NOT require any     }
  17. { special version of COMCTL32.DLL.                                             }
  18. {                                                                              }
  19. { Copyright 1998-2001, Brad Stowers.  All Rights Reserved.                     }
  20. {                                                                              }
  21. { Copyright:                                                                   }
  22. { All Delphi Free Stuff (hereafter "DFS") source code is copyrighted by        }
  23. { Bradley D. Stowers (hereafter "author"), and shall remain the exclusive      }
  24. { property of the author.                                                      }
  25. {                                                                              }
  26. { Distribution Rights:                                                         }
  27. { You are granted a non-exlusive, royalty-free right to produce and distribute }
  28. { compiled binary files (executables, DLLs, etc.) that are built with any of   }
  29. { the DFS source code unless specifically stated otherwise.                    }
  30. { You are further granted permission to redistribute any of the DFS source     }
  31. { code in source code form, provided that the original archive as found on the }
  32. { DFS web site (http://www.delphifreestuff.com) is distributed unmodified. For }
  33. { example, if you create a descendant of TDFSColorButton, you must include in  }
  34. { the distribution package the colorbtn.zip file in the exact form that you    }
  35. { downloaded it from http://www.delphifreestuff.com/mine/files/colorbtn.zip.   }
  36. {                                                                              }
  37. { Restrictions:                                                                }
  38. { Without the express written consent of the author, you may not:              }
  39. {   * Distribute modified versions of any DFS source code by itself. You must  }
  40. {     include the original archive as you found it at the DFS site.            }
  41. {   * Sell or lease any portion of DFS source code. You are, of course, free   }
  42. {     to sell any of your own original code that works with, enhances, etc.    }
  43. {     DFS source code.                                                         }
  44. {   * Distribute DFS source code for profit.                                   }
  45. {                                                                              }
  46. { Warranty:                                                                    }
  47. { There is absolutely no warranty of any kind whatsoever with any of the DFS   }
  48. { source code (hereafter "software"). The software is provided to you "AS-IS", }
  49. { and all risks and losses associated with it's use are assumed by you. In no  }
  50. { event shall the author of the softare, Bradley D. Stowers, be held           }
  51. { accountable for any damages or losses that may occur from use or misuse of   }
  52. { the software.                                                                }
  53. {                                                                              }
  54. { Support:                                                                     }
  55. { Support is provided via the DFS Support Forum, which is a web-based message  }
  56. { system.  You can find it at http://www.delphifreestuff.com/discus/           }
  57. { All DFS source code is provided free of charge. As such, I can not guarantee }
  58. { any support whatsoever. While I do try to answer all questions that I        }
  59. { receive, and address all problems that are reported to me, you must          }
  60. { understand that I simply can not guarantee that this will always be so.      }
  61. {                                                                              }
  62. { Clarifications:                                                              }
  63. { If you need any further information, please feel free to contact me directly.}
  64. { This agreement can be found online at my site in the "Miscellaneous" section.}
  65. {------------------------------------------------------------------------------}
  66. { The lateset version of my components are always available on the web at:     }
  67. {   http://www.delphifreestuff.com/                                            }
  68. { See ELV.txt for notes, known issues, and revision history.                   }
  69. {------------------------------------------------------------------------------}
  70. { Date last modified:  June 28, 2001                                           }
  71. {------------------------------------------------------------------------------}
  72.  
  73.  
  74. unit EnhListView;
  75.  
  76. interface
  77.  
  78. {$IFNDEF DFS_WIN32}
  79.   ERROR!  This unit only available for Delphi 2.0 or higher!!!
  80. {$ENDIF}
  81.  
  82. uses
  83.   Forms, Windows, Messages, Classes, Controls, ComCtrls, CommCtrl, SysUtils,
  84.   {$IFDEF DFS_COMPILER_4_UP} ImgList, {$ENDIF} Graphics, StdCtrls, Menus;
  85.  
  86.  
  87. const
  88.   { This shuts up C++Builder 3 about the redefiniton being different. There
  89.     seems to be no equivalent in C1.  Sorry. }
  90.   {$IFDEF DFS_CPPB_3_UP}
  91.   {$EXTERNALSYM DFS_COMPONENT_VERSION}
  92.   {$ENDIF}
  93.   DFS_COMPONENT_VERSION = 'TdfsEnhListView v3.72';
  94.  
  95.   DRAWTEXTEX_FLAGS = DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER or
  96.      DT_END_ELLIPSIS;
  97.   DRAWTEXTEX_ALIGNMENT: array[TAlignment] of UINT = (DT_LEFT, DT_RIGHT,
  98.      DT_CENTER);
  99.   WM_OWNERDRAWCOLUMNS = WM_USER + 143;
  100.  
  101. type
  102.   TIntArray = array[0..(MaxInt div SizeOf(Integer)-1)] of Integer;
  103.   PIntArray = ^TIntArray;
  104.  
  105.   TResizeMethod = (rmFitText, rmFitHeader);
  106.   TAutoColumnSort = (acsNoSort, acsSort, acsSortToggle);
  107.   TAutoSortStyle = (assSmart, assDefault);
  108.   TSortAs = (saNone, saString, saNumeric, saDateTime);
  109.   TLVStyle = (lvStandard, lvOwnerDrawFixed);
  110.   TLVHDrawItemEvent = procedure(Control: TWinControl; var ACanvas: TCanvas;
  111.      Index: Integer; var ARect: TRect; Selected: boolean;
  112.      var DefaultDrawing: boolean) of object;
  113.   TLVMeasureItemEvent = procedure(Control: TWinControl;
  114.      var AHeight: UINT) of object;
  115.   TLVDrawItemEvent = procedure(Control: TWinControl; var ACanvas: TCanvas;
  116.      Index: Integer; ARect: TRect; State: TOwnerDrawState;
  117.      var DefaultDrawing, FullRowSelect: boolean) of object;
  118.   TLVDrawSubItemEvent = procedure(Control: TWinControl; var ACanvas: TCanvas;
  119.      Index, SubItem: Integer; ARect: TRect; State: TOwnerDrawState;
  120.      var DefaultDrawing: boolean) of object;
  121.   TLVAfterDrawItemEvent = procedure(Control: TWinControl; var ACanvas: TCanvas;
  122.      Index: Integer; ARect: TRect; State: TOwnerDrawState) of object;
  123.   TLVSortItemsEvent = procedure(Sender: TObject; Item1, Item2: TListItem;
  124.      SortColumn: integer; var SortAs: TSortAs; var CompResult: integer) of object;
  125.   TLVSortStatusEvent = procedure(Sender: TObject; SortColumn: integer;
  126.      Ascending: boolean) of object;
  127.   TLVEditCanceled = procedure(Sender: TObject; Item: TListItem) of object;
  128.   {$IFNDEF DFS_COMPILER_4_UP}
  129.   TLVNotifyEvent = procedure(Sender: TObject; Item: TListItem) of object;
  130.   {$ENDIF}
  131.  
  132.   // Class for saved settings
  133.   TdfsEnhLVSaveSettings = class(TPersistent)
  134.   private
  135.     FAutoSave: boolean;
  136.     FRegistryKey: string;
  137.     FSaveColumnSizes: boolean;
  138.     FSaveCurrentSort: boolean;
  139.     FSaveViewStyle: boolean;
  140.   public
  141.     constructor Create; virtual;
  142.     procedure StoreColumnSizes(ColCount: integer;
  143.        const IntArray: array of integer);
  144.     procedure ReadColumnSizes(ColCount: integer;
  145.        var IntArray: array of integer);
  146.     procedure StoreCurrentSort(Ascending: boolean; SortCol: integer);
  147.     procedure ReadCurrentSort(var Ascending: boolean; var SortCol: integer);
  148.     procedure StoreViewStyle(Style: TViewStyle);
  149.     function ReadViewStyle(Default: TViewStyle): TViewStyle;
  150.   published
  151.     property AutoSave: boolean read FAutoSave write FAutoSave default FALSE;
  152.     property RegistryKey: string read FRegistryKey write FRegistryKey;
  153.     property SaveColumnSizes: boolean
  154.        read FSaveColumnSizes
  155.        write FSaveColumnSizes
  156.        default TRUE;
  157.     property SaveCurrentSort: boolean
  158.        read FSaveCurrentSort
  159.        write FSaveCurrentSort
  160.        default TRUE;
  161.     property SaveViewStyle: boolean
  162.        read FSaveViewStyle
  163.        write FSaveViewStyle
  164.        default TRUE;
  165.   end;
  166.  
  167.   { The new class }
  168.   TCustomEnhListView = class(TCustomListView)
  169.   private
  170.     FSortDirty: boolean;
  171.     FUpdateCount: integer;
  172.     FStyle: TLVStyle;
  173.     FAutoColumnSort: TAutoColumnSort;
  174.     FAutoSortStyle: TAutoSortStyle;
  175.     FAutoResort: boolean;
  176.     FAutoSortAscending: boolean;
  177.     FTmpAutoSortAscending: boolean;
  178.     FLastColumnClicked: Integer;
  179.     FSaveSettings: TdfsEnhLVSaveSettings;
  180.     FShowSortArrows: boolean;
  181.     FReverseSortArrows: boolean;
  182.     FSortUpBmp,
  183.     FSortDownBmp: TBitmap;
  184.     FCreatingWindowHandle: boolean;
  185. {$IFDEF BACKGROUND_FIXED}
  186.     FBackgroundImage: TBitmap;
  187. {$ENDIF}
  188.     FNoColumnResize: boolean;
  189.     FOldHeaderWndProc: pointer;
  190.     FHeaderInstance: pointer;
  191.     FSearchStr: string;
  192.     FSearchTickCount: Double;
  193.     FColumnSearch: boolean;
  194.  
  195.     FOnSortBegin: TLVSortStatusEvent;
  196.     FOnSortFinished: TLVSortStatusEvent;
  197.     FOnMeasureItem: TLVMeasureItemEvent;
  198.     FOnDrawItem: TLVDrawItemEvent;
  199.     FOnDrawSubItem: TLVDrawSubItemEvent;
  200.     FOnAfterDefaultDrawItem: TLVAfterDrawItemEvent;
  201.     FOnDrawHeader: TLVHDrawItemEvent;
  202.     FOnSortItems: TLVSortItemsEvent;
  203.     FOnEditCanceled: TLVEditCanceled;
  204. {$IFNDEF DFS_COMPILER_4_UP}
  205.     FOnGetImageIndex: TLVNotifyEvent;
  206. {$ENDIF}
  207.  
  208.     procedure HeaderWndProc(var Message: TMessage);
  209.     { Message handlers }
  210.     procedure CMSysColorChange(var Message: TWMSysColorChange);
  211.        message CM_SYSCOLORCHANGE;
  212.     procedure CMFontChanged(var Messsage: TMessage); message CM_FONTCHANGED;
  213.     procedure CNMeasureItem(var Message: TWMMeasureItem); message CN_MEASUREITEM;
  214.     procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
  215.     procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
  216.     procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
  217.     procedure WMDrawHeader(var Message: TWMDrawItem); message WM_DRAWITEM;
  218.     procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
  219.     procedure WMOwnerDrawColumns(var Message: TMessage);
  220.        message WM_OWNERDRAWCOLUMNS;
  221.     procedure WMParentNotify(var Message: TWMParentNotify); message WM_PARENTNOTIFY;
  222.   protected
  223.     { USE WITH CARE.  This can be NIL }
  224.     FCanvas: TCanvas;
  225.     FHeaderHandle: HWND;
  226.     procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  227.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  228. {$IFNDEF DFS_COMPILER_4_UP}
  229.     function GetItem(Value: TLVItem): TListItem;
  230. {$ENDIF}
  231.     procedure ResetOwnerDrawHeight;
  232.     procedure InvalidateColumnHeader(Index: integer); virtual;
  233.     procedure DoSort(ColumnIndex:integer; Descending: boolean); virtual;
  234.     procedure SortBegin(ColumnIndex: integer; Ascending: boolean); virtual;
  235.     procedure SortFinished(ColumnIndex: integer; Ascending: boolean); virtual;
  236.     procedure SortItems(const Item1, Item2: TListItem; SortColumn: integer;
  237.        var CompResult: integer); virtual;
  238.     procedure MeasureItem(var Height: UINT); virtual;
  239.     procedure DefaultDrawItem(Index: Integer; Rect: TRect;
  240.        State: TOwnerDrawState; FullRowSelect: boolean); virtual;
  241.     procedure DefaultDrawSubItem(Index, SubItem: integer; Rect: TRect;
  242.        State: TOwnerDrawState); virtual;
  243.     procedure ProcessDrawItemMsg(Index: Integer;
  244.        Rect: TRect; State: TOwnerDrawState; var DefaultDrawing,
  245.        FullRowSelect: boolean); virtual;
  246.     function ActualColumnIndex(Index: integer): integer; virtual;
  247.     function GetActualColumn(Index: integer): TListColumn; virtual;
  248.     function GetSubItemText(Index, SubItem: integer): string; virtual;
  249.     procedure DrawSubItem(Index, SubItem: Integer; Rect: TRect;
  250.        State: TOwnerDrawState; var DefaultDrawing: boolean); virtual;
  251.     procedure DrawItem(var Canvas: TCanvas; Index: Integer; Rect: TRect;
  252.        State: TOwnerDrawState; var DefaultDrawing,
  253.        FullRowSelect: boolean);
  254.        {$IFDEF DFS_COMPILER_4_UP} reintroduce; overload; {$ENDIF} virtual;
  255.     procedure AfterDrawItem(var Canvas: TCanvas; Index: Integer;
  256.        Rect: TRect; State: TOwnerDrawState); virtual;
  257.     procedure Edit(const Item: TLVItem); override;
  258.     procedure EditCanceled(const Item: TLVItem); virtual;
  259.     { Overriden ancestor methods }
  260.     procedure ColClick(Column: TListColumn); override;
  261. {$IFDEF DFS_FIXED_LIST_VIEW}
  262.     procedure InsertItem(Item: TListItem); override;
  263. {$ENDIF}
  264.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  265.     procedure CreateWnd; override;
  266.     procedure DestroyWnd; override;
  267.     procedure ProcessDrawHeaderMsg(Index: Integer; Rect: TRect;
  268.        State: TOwnerDrawState; var DefaultDrawing: boolean); virtual;
  269.     procedure DrawHeader(var Canvas: TCanvas; Index: Integer; var Rect: TRect;
  270.        Selected: boolean; var DefaultDrawing: boolean); virtual;
  271.     procedure DefaultDrawHeader(var Canvas: TCanvas; Index: Integer;
  272.        var Rect: TRect; Selected: boolean); virtual;
  273.     procedure SetOnDrawHeader(Value: TLVHDrawItemEvent); virtual;
  274.     procedure SetColumnsOwnerDrawFlag(OwnerDrawn: boolean); virtual;
  275.     procedure CreateSortBmps(var UpBmp, DownBmp: TBitmap); virtual;
  276. {$IFNDEF DFS_COMPILER_4_UP}
  277.     procedure GetImageIndex(Item: TListItem); virtual;
  278. {$ENDIF}
  279. {$IFDEF BACKGROUND_FIXED}
  280.     procedure BackgroundImageChanged(Sender: TObject); virtual;
  281. {$ENDIF}
  282.  
  283.     { Property methods }
  284.     procedure SetAutoColumnSort(Value: TAutoColumnSort);
  285.     procedure SetAutoSortStyle(Value: TAutoSortStyle);
  286.     procedure SetCurrentSortAscending(Value: boolean);
  287.     procedure SetAutoSortAscending(Value: boolean);
  288.     procedure SetStyle(Value: TLVStyle);
  289.     procedure SetShowSortArrows(Value: boolean);
  290.     procedure SetReverseSortArrows(Value: boolean);
  291.     procedure SetLastColumnClicked(Value: integer);
  292.     procedure SetAutoResort(Value: boolean);
  293. {$IFDEF BACKGROUND_FIXED}
  294.     procedure SetBackgroundImage(const Value: TBitmap);
  295. {$ENDIF}
  296.     function GetSmallImages: {$IFDEF DFS_COMPILER_4_UP} TCustomImageList {$ELSE}
  297.        TImageList {$ENDIF};
  298.     procedure SetSmallImages(Val: {$IFDEF DFS_COMPILER_4_UP} TCustomImageList
  299.        {$ELSE} TImageList {$ENDIF});
  300.     function GetVersion: string; virtual;
  301.     procedure SetVersion(const Val: string);
  302.     function GetCurrentColumnWidth(Index: integer): integer;
  303.  
  304.     procedure CreateParams(var Params: TCreateParams); override;
  305.     procedure Loaded; override;
  306.  
  307.     { Should probably remain protected }
  308.     property SortUpBmp: TBitmap
  309.       read FSortUpBmp;
  310.     property SortDownBmp: TBitmap
  311.       read FSortDownBmp;
  312.  
  313.     { Should be made public by descendants as needed }
  314.     property LastColumnClicked: Integer
  315.       read FLastColumnClicked
  316.       write SetLastColumnClicked;
  317.  
  318.     { Should be published by descendants as needed }
  319.     property HeaderHandle: HWnd
  320.        read FHeaderHandle;
  321.     property AutoColumnSort: TAutoColumnSort
  322.        read FAutoColumnSort
  323.        write SetAutoColumnSort
  324.        default acsNoSort;
  325.     property AutoSortStyle: TAutoSortStyle
  326.        read FAutoSortStyle
  327.        write SetAutoSortStyle
  328.        default assSmart;
  329.     property AutoResort: boolean
  330.        read FAutoResort
  331.        write SetAutoResort
  332.        default TRUE;
  333.     property AutoSortAscending: boolean
  334.        read FAutoSortAscending
  335.        write SetAutoSortAscending
  336.        default TRUE;
  337.     property ColumnSearch: boolean
  338.        read FColumnSearch
  339.        write FColumnSearch
  340.        default FALSE;
  341.     property ShowSortArrows: boolean
  342.        read FShowSortArrows
  343.        write SetShowSortArrows
  344.        default FALSE;
  345.     property ReverseSortArrows: boolean
  346.        read FReverseSortArrows
  347.        write SetReverseSortArrows
  348.        default FALSE;
  349.     property CurrentSortAscending: boolean
  350.        read FTmpAutoSortAscending
  351.        write SetCurrentSortAscending;
  352.     property SaveSettings: TdfsEnhLVSaveSettings
  353.        read FSaveSettings
  354.        write FSaveSettings;
  355.     property Style: TLVStyle
  356.        read FStyle
  357.        write SetStyle
  358.        default lvStandard;
  359.     property CurrentColumnWidth[Index: integer]: integer
  360.        read GetCurrentColumnWidth;
  361. {$IFDEF BACKGROUND_FIXED}
  362.     property BackgroundImage: TBitmap
  363.        read FBackgroundImage
  364.        write SetBackgroundImage;
  365. {$ENDIF}       
  366.     property NoColumnResize: boolean
  367.        read FNoColumnResize
  368.        write FNoColumnResize;
  369.     // We have to redeclare this so we can hook into the read/write methods.
  370.     property SmallImages:
  371.        {$IFDEF DFS_COMPILER_4_UP} TCustomImageList {$ELSE} TImageList {$ENDIF}
  372.        read GetSmallImages
  373.        write SetSmallImages;
  374.  
  375.     { Events }
  376.     property OnDrawHeader: TLVHDrawItemEvent
  377.        read FOnDrawHeader
  378.        write SetOnDrawHeader;
  379.     property OnMeasureItem: TLVMeasureItemEvent
  380.        read FOnMeasureItem
  381.        write FOnMeasureItem;
  382.     property OnDrawItem: TLVDrawItemEvent
  383.        read FOnDrawItem
  384.        write FOnDrawItem;
  385.     property OnDrawSubItem: TLVDrawSubItemEvent
  386.        read FOnDrawSubItem
  387.        write FOnDrawSubItem;
  388.     property OnAfterDefaultDrawItem: TLVAfterDrawItemEvent
  389.        read FOnAfterDefaultDrawItem
  390.        write FOnAfterDefaultDrawItem;
  391.     property OnSortItems: TLVSortItemsEvent
  392.        read FOnSortItems
  393.        write FOnSortItems;
  394.     property OnSortBegin: TLVSortStatusEvent
  395.        read FOnSortBegin
  396.        write FOnSortBegin;
  397.     property OnSortFinished: TLVSortStatusEvent
  398.        read FOnSortFinished
  399.        write FOnSortFinished;
  400.     property OnEditCanceled: TLVEditCanceled
  401.        read FOnEditCanceled
  402.        write FOnEditCanceled;
  403. {$IFNDEF DFS_COMPILER_4_UP}
  404.     property OnGetImageIndex: TLVNotifyEvent
  405.        read FOnGetImageIndex
  406.        write FOnGetImageIndex;
  407. {$ENDIF}
  408.   public
  409.     constructor Create(AOwner: TComponent); override;
  410.     destructor Destroy; override;
  411.  
  412.     function StoreSettings: boolean; virtual;
  413.     function WriteSettings: boolean; virtual;
  414.     function LoadSettings: boolean; virtual;
  415.     function ReadSettings: boolean; virtual;
  416.     procedure DefaultSort(ColumnIndex:integer; Descending: boolean); virtual;
  417.     procedure Resort; virtual;
  418.     // Use these as replacements for Items.BeginUpdate and EndUpdate.  They
  419.     // call those methods, but they also inhibit autosorting until after the
  420.     // last EndUpdate.
  421.     procedure BeginUpdate; virtual;
  422.     procedure EndUpdate; virtual;
  423.  
  424.     // Resize all columns.
  425.     procedure ResizeColumns(ResizeMethod: TResizeMethod); virtual;
  426.  
  427.     // Move list item to new position.
  428.     procedure MoveItem(OriginalIndex, NewIndex: Integer); virtual;
  429.  
  430.     function StringSelect(FindStr: string; ColumnIndex: Integer): boolean; virtual;
  431.     function SubStringSelect(FindStr: string; ColumnIndex: Integer): boolean; virtual;
  432.  
  433.     // Accounts for re-ordered columns
  434.     property ActualColumn[Index: integer]: TListColumn
  435.        read GetActualColumn;
  436.   published
  437.     property Version: string
  438.        read GetVersion
  439.        write SetVersion
  440.        stored FALSE;
  441.   end;
  442.  
  443.  
  444.   TdfsEnhListView = class(TCustomEnhListView)
  445.   public
  446.     property HeaderHandle;
  447.     property CurrentSortAscending;
  448.     property LastColumnClicked;
  449.     property CurrentColumnWidth;
  450.   published
  451.     property AutoColumnSort;
  452.     property AutoSortStyle;
  453.     property AutoResort;
  454.     property AutoSortAscending;
  455. {$IFDEF BACKGROUND_FIXED}
  456.     property BackgroundImage;
  457. {$ENDIF}
  458.     property ColumnSearch;
  459.     property NoColumnResize;
  460.     property ReverseSortArrows;
  461.     property ShowSortArrows;
  462.     property SaveSettings;
  463.     property Style;
  464.  
  465.     property OnMeasureItem;
  466.     property OnDrawItem;
  467.     property OnDrawSubItem;
  468.     property OnAfterDefaultDrawItem;
  469.     property OnDrawHeader;
  470.     property OnSortItems;
  471.     property OnSortBegin;
  472.     property OnSortFinished;
  473.     property OnEditCanceled;
  474.  
  475.     { Publish TCustomListView inherited protected properties }
  476.     property Align;
  477. {$IFDEF DFS_COMPILER_4_UP}
  478.     property Anchors;
  479.     property BiDiMode;
  480. {$ENDIF}
  481.     property BorderStyle;
  482. {$IFDEF DFS_COMPILER_4_UP}
  483.     property BorderWidth;
  484. {$ENDIF}
  485.     property Color;
  486.     property ColumnClick;
  487.     property OnClick;
  488.     property OnDblClick;
  489.     property Columns;
  490. {$IFDEF DFS_COMPILER_4_UP}
  491.     property Constraints;
  492. {$ENDIF}
  493.     property Ctl3D;
  494. {$IFDEF DFS_COMPILER_4_UP}
  495.     property DragKind;
  496. {$ENDIF}
  497.     property DragMode;
  498.     property ReadOnly
  499.        default False;
  500.     property Enabled;
  501.     property Font;
  502.     property HideSelection;
  503.     property IconOptions;
  504.     property Items;
  505.     property AllocBy;
  506.     property MultiSelect;
  507.     property OnChange;
  508.     property OnChanging;
  509.     property OnColumnClick;
  510.     property OnDeletion;
  511.     property OnEdited;
  512.     property OnEditing;
  513. {$IFDEF DFS_COMPILER_4_UP}
  514.     property OnEndDock;
  515. {$ENDIF}
  516.     property OnEnter;
  517.     property OnExit;
  518.     property OnInsert;
  519.     property OnDragDrop;
  520.     property OnDragOver;
  521.     property DragCursor;
  522.     property OnStartDrag;
  523.     property OnEndDrag;
  524.     property OnGetImageIndex;
  525.     property OnMouseDown;
  526.     property OnMouseMove;
  527.     property OnMouseUp;
  528. {$IFDEF DFS_COMPILER_4_UP}
  529.     property OnResize;
  530.     property OnSelectItem;
  531.     property OnStartDock;
  532. {$ENDIF}
  533.     property ParentColor
  534.        default False;
  535.     property ParentFont;
  536.     property ParentShowHint;
  537. {$IFDEF DFS_COMPILER_4_UP}
  538.     property ParentBiDiMode;
  539. {$ENDIF}
  540.     property ShowHint;
  541.     property PopupMenu;
  542.     property ShowColumnHeaders;
  543.     property TabOrder;
  544.     property TabStop
  545.        default True;
  546.     property ViewStyle;
  547.     property Visible;
  548.     property OnKeyDown;
  549.     property OnKeyPress;
  550.     property OnKeyUp;
  551.     property LargeImages;
  552.     property SmallImages;
  553.     property StateImages;
  554.   end;
  555.  
  556. var
  557.   { Default drawing variables }
  558.   DefDraw_TextOffset: integer; // Offset for the text -- 5
  559.   DefDraw_ImageOffset: integer; // Offset for image -- 2
  560.  
  561.  
  562. implementation
  563.  
  564. uses
  565.   Registry, ExtListView;
  566.  
  567.  
  568. var
  569.   FDirection,
  570.   FSortColNum: integer;
  571.  
  572. {$IFNDEF DFS_COMPILER_4_UP}
  573. type
  574.   TReplaceFlags = set of (rfReplaceAll, rfIgnoreCase);
  575.  
  576. function StringReplace(const S, OldPattern, NewPattern: string;
  577.   Flags: TReplaceFlags): string;
  578. var
  579.   SearchStr, Patt, NewStr: string;
  580.   Offset: Integer;
  581. begin
  582.   if rfIgnoreCase in Flags then
  583.   begin
  584.     SearchStr := AnsiUpperCase(S);
  585.     Patt := AnsiUpperCase(OldPattern);
  586.   end else
  587.   begin
  588.     SearchStr := S;
  589.     Patt := OldPattern;
  590.   end;
  591.   NewStr := S;
  592.   Result := '';
  593.   while SearchStr <> '' do
  594.   begin
  595.     Offset := {$IFDEF DFS_COMPILER_2} Pos( {$ELSE} AnsiPos( {$ENDIF} Patt, SearchStr);
  596.     if Offset = 0 then
  597.     begin
  598.       Result := Result + NewStr;
  599.       Break;
  600.     end;
  601.     Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
  602.     NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
  603.     if not (rfReplaceAll in Flags) then
  604.     begin
  605.       Result := Result + NewStr;
  606.       Break;
  607.     end;
  608.     SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
  609.   end;
  610. end;
  611. {$ENDIF}
  612.  
  613. function IsValidNumber(S: string; var V: extended): boolean;
  614. var
  615.   NumCode: integer;
  616.   FirstSpace: integer;
  617. begin
  618.   FirstSpace := Pos(' ', S);
  619.   if FirstSpace > 0 then
  620.     S := Copy(S, 1, FirstSpace - 1);
  621.   Val(S, V, NumCode);
  622.   Result := (NumCode = 0);
  623.   if not Result then
  624.   begin
  625.     // Remove all thousands seperators
  626.     S := StringReplace(S, ThousandSeparator, '', [rfReplaceAll]);
  627.     // change DecimalSeperator to '.' because Val only recognizes that, not
  628.     // the locale specific decimal char.  Stupid Val.
  629.     S := StringReplace(S, DecimalSeparator, '.', [rfReplaceAll]);
  630.     // and try again
  631.     Val(S, V, NumCode);
  632.     Result := (NumCode = 0);
  633.   End;
  634. end;
  635.  
  636. // date conversion will fail if using long format, e.g. '1 January 1994'
  637. function IsValidDateTime(const S: string; var D: TDateTime): boolean;
  638. var
  639.   i: integer;
  640.   HasDate: boolean;
  641.   HasTime: boolean;
  642. begin
  643.   // Check for two date seperators.  This is because some regions use a "-"
  644.   //  to seperate dates, so if we just checked for one we would flag negative
  645.   //  numbers as being dates.
  646.   i := Pos(DateSeparator, S);
  647.   HasDate := i > 0;
  648.   if HasDate and (i <> Length(S)) then
  649.     HasDate := Pos(DateSeparator, Copy(S, i+1, Length(S)-i)) > 0;
  650.   HasTime := Pos(TimeSeparator, S) > 0;
  651.   Result := HasDate or HasTime;
  652.   if Result then
  653.   begin
  654.     try
  655.       if HasDate and HasTime then
  656.         D := StrToDateTime(S)
  657.       else if HasDate then
  658.         D := StrToDate(S)
  659.       else if HasTime then
  660.         D := StrToTime(S);
  661.     except
  662.       // Something failed to convert...
  663.       D := 0;
  664.       Result := FALSE;
  665.     end;
  666.   end;
  667. end; { IsValidDateTime }
  668.  
  669. function __CustomSortProc1__(Item1, Item2: TListItem; Data: integer): integer;
  670.    stdcall;
  671. var
  672.   Str1, Str2: string;
  673.   Val1, Val2: extended;
  674.   Date1, Date2: TDateTime;
  675.   Diff: TDateTime;
  676. begin
  677.   if (Item1 = NIL) or (Item2 = NIL) then
  678.   begin
  679.     // something bad happening, I'm outta here
  680.     Result := 0;
  681.     exit;
  682.   end;
  683.  
  684.   try
  685.     if FSortColNum = -1 then
  686.     begin
  687.       Str1 := Item1.Caption;
  688.       Str2 := Item2.Caption;
  689.     end else begin
  690.       if FSortColNum < Item1.SubItems.Count then
  691.         Str1 := Item1.SubItems[FSortColNum]
  692.       else
  693.         Str1 := '';
  694.       if FSortColNum < Item2.SubItems.Count then
  695.         Str2 := Item2.SubItems[FSortColNum]
  696.       else
  697.         Str2 := '';
  698.     end;
  699.  
  700.     if TCustomEnhListView(Data).AutoSortStyle = assSmart then
  701.     begin
  702.       if IsValidDateTime(Str1, Date1) and IsValidDateTime(Str2, Date2) then
  703.       begin
  704.         Diff := Date1 - Date2;
  705.         if Diff < 0.0 then Result := -1
  706.         else if Diff > 0.0 then Result := 1
  707.         else Result := 0
  708.       end else if IsValidNumber(Str1, Val1) and IsValidNumber(Str2, Val2) then
  709.       begin
  710.         if Val1 < Val2 then Result := -1
  711.         else if Val1 > Val2 then Result := 1
  712.         else Result := 0
  713.       end else
  714.         Result := AnsiCompareStr(Str1, Str2);
  715.     end else
  716.       Result := AnsiCompareStr(Str1, Str2);
  717.  
  718.     Result := FDirection * Result; // Set direction flag.
  719.   except
  720.     Result := 0;  // Something went bad in the comparison.  Say they are equal.
  721.   end;
  722. end;
  723.  
  724. function __CustomSortProc2__(Item1, Item2: TListItem; Data: integer): integer;
  725.    stdcall;
  726. var
  727.   EvRes: integer;
  728. begin
  729.   EvRes := 0;
  730.   TCustomEnhListView(Data).SortItems(Item1, Item2, FSortColNum, EvRes);
  731.   Result := EvRes * FDirection;
  732. end;
  733.  
  734.  
  735.  
  736. { TdfsEnhLVSaveSettings }
  737.  
  738. constructor TdfsEnhLVSaveSettings.Create;
  739. begin
  740.   inherited Create;
  741.  
  742.   FAutoSave := FALSE;
  743.   FRegistryKey := '';
  744.   FSaveViewStyle := TRUE;
  745.   FSaveColumnSizes := TRUE;
  746.   SaveCurrentSort := TRUE;
  747. end;
  748.  
  749. procedure TdfsEnhLVSaveSettings.StoreColumnSizes(ColCount: integer;
  750.    const IntArray: array of integer);
  751. var
  752.   Reg: TRegIniFile;
  753.   x: integer;
  754.   s: string;
  755. begin
  756.   if ColCount < 1 then exit;
  757.   s := '';
  758.   for x := 0 to ColCount-1 do
  759.     s := s + IntToStr(IntArray[x]) + ',';
  760.   SetLength(s, Length(s)-1);
  761.   Reg := TRegIniFile.Create(FRegistryKey);
  762.   try
  763.     Reg.WriteString('Columns', 'Sizes', s);
  764.   finally
  765.     Reg.Free;
  766.   end;
  767. end;
  768.  
  769. procedure TdfsEnhLVSaveSettings.ReadColumnSizes(ColCount: integer;
  770.    var IntArray: array of integer);
  771. var
  772.   Reg: TRegIniFile;
  773.   x,y: integer;
  774.   s: string;
  775. begin
  776.   if ColCount < 1 then exit;
  777.   s := '';
  778.   Reg := TRegIniFile.Create(FRegistryKey);
  779.   try
  780.     s := Reg.ReadString('Columns', 'Sizes', '');
  781.   finally
  782.     Reg.Free;
  783.   end;
  784.   if s = '' then
  785.   begin
  786.     IntArray[0] := -1;
  787.     exit;
  788.   end;
  789.   y := 0;
  790.   for x := 0 to ColCount-1 do
  791.   begin
  792.     try
  793.       y := Pos(',', s);
  794.       if y = 0 then
  795.         y := Length(s)+1;
  796.       IntArray[x] := StrToInt(Copy(s, 1, y-1));
  797.     except
  798.       { Nothing, just eat the exception };
  799.     end;
  800.     s := copy(s, y+1, length(s));
  801.     if s = '' then break;
  802.   end;
  803. end;
  804.  
  805. procedure TdfsEnhLVSaveSettings.StoreCurrentSort(Ascending: boolean;
  806.    SortCol: integer);
  807. var
  808.   Reg: TRegIniFile;
  809. begin
  810.   Reg := TRegIniFile.Create(FRegistryKey);
  811.   try
  812.     Reg.WriteBool('Sort', 'Ascending', Ascending);
  813.     Reg.WriteInteger('Sort', 'SortCol', SortCol);
  814.   finally
  815.     Reg.Free;
  816.   end;
  817. end;
  818.  
  819. procedure TdfsEnhLVSaveSettings.ReadCurrentSort(var Ascending: boolean;
  820.    var SortCol: integer);
  821. var
  822.   Reg: TRegIniFile;
  823. begin
  824.   Reg := TRegIniFile.Create(FRegistryKey);
  825.   try
  826.     Ascending := Reg.ReadBool('Sort', 'Ascending', TRUE);
  827.     SortCol := Reg.ReadInteger('Sort', 'SortCol', 0);
  828.   finally
  829.     Reg.Free;
  830.   end;
  831. end;
  832.  
  833. procedure TdfsEnhLVSaveSettings.StoreViewStyle(Style: TViewStyle);
  834. const
  835.   STYLE_VAL: array[TViewStyle] of integer = (0, 1, 2, 3);
  836. var
  837.   Reg: TRegIniFile;
  838. begin
  839.   Reg := TRegIniFile.Create(FRegistryKey);
  840.   try
  841.     Reg.WriteInteger('ViewStyle', 'ViewStyle', STYLE_VAL[Style]);
  842.   finally
  843.     Reg.Free;
  844.   end;
  845. end;
  846.  
  847. function TdfsEnhLVSaveSettings.ReadViewStyle(Default: TViewStyle): TViewStyle;
  848. const
  849.   STYLES: array[0..3] of TViewStyle = (vsIcon, vsSmallIcon, vsList, vsReport);
  850. var
  851.   Reg: TRegIniFile;
  852.   i: integer;
  853. begin
  854.   Reg := TRegIniFile.Create(FRegistryKey);
  855.   try
  856.     i := Reg.ReadInteger('ViewStyle', 'ViewStyle', -1);
  857.     if (i >= Low(STYLES)) and (i <= High(STYLES)) then
  858.       Result := STYLES[i]
  859.     else
  860.       Result := Default;
  861.   finally
  862.     Reg.Free;
  863.   end;
  864. end;
  865.  
  866.  
  867. // Override constructor to "zero out" our internal variable.
  868. constructor TCustomEnhListView.Create(AOwner: TComponent);
  869. begin
  870.   inherited Create(AOwner);
  871.  
  872.   FSearchStr := '';
  873.   FSearchTickCount := 0;
  874.   FHeaderHandle := 0;
  875.   FSortDirty := FALSE;
  876.   FUpdateCount := 1; // inhibit sorting until finished creating.
  877.   FSaveSettings := TdfsEnhLVSaveSettings.Create;
  878.   FAutoColumnSort := acsNoSort;
  879.   FAutoResort := TRUE;
  880.   FAutoSortStyle := assSmart;
  881.   FAutoSortAscending := TRUE;
  882.   FTmpAutoSortAscending := FAutoSortAscending;
  883.   FLastColumnClicked := -1;
  884.   FCanvas := NIL;
  885.   FStyle  := lvStandard;
  886.   FSortUpBmp := NIL;
  887.   FSortDownBmp := NIL;
  888.   FShowSortArrows := FALSE;
  889.   FReverseSortArrows := FALSE;
  890. {$IFDEF BACKGROUND_FIXED}
  891.   FBackgroundImage := TBitmap.Create;
  892. {$ENDIF}
  893.   FHeaderInstance := MakeObjectInstance(HeaderWndProc);
  894. end;
  895.  
  896. destructor TCustomEnhListView.Destroy;
  897. begin
  898. {$IFDEF BACKGROUND_FIXED}
  899.   FBackgroundImage.Free;
  900. {$ENDIF}
  901.   FSortUpBmp.Free;
  902.   FSortDownBmp.Free;
  903.   FCanvas.Free;
  904.   if FHeaderHandle <> 0 then
  905.     SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FOldHeaderWndProc));
  906.   FreeObjectInstance(FHeaderInstance);
  907.  
  908.   inherited Destroy;
  909.  
  910.   FSaveSettings.Free;
  911. end;
  912.  
  913. procedure TCustomEnhListView.CreateParams(var Params: TCreateParams);
  914. begin
  915.   inherited CreateParams(Params);
  916.  
  917.   if (FStyle = lvOwnerDrawFixed) then
  918.   begin
  919.     Params.Style := Params.Style or LVS_OWNERDRAWFIXED;
  920.     if FCanvas = NIL then
  921.       FCanvas := TCanvas.Create;
  922.   end else begin
  923.     if (not assigned(FOnDrawHeader)) and (not FShowSortArrows) then
  924.     begin
  925.       FCanvas.Free;
  926.       FCanvas := NIL;
  927.     end;
  928.   end;
  929. end;
  930.  
  931. procedure TCustomEnhListView.CreateWnd;
  932. begin
  933. //  if FCreatingWindowHandle then exit;
  934.  
  935.   FCreatingWindowHandle := TRUE;
  936.   try
  937.     inherited CreateWnd;
  938.     // If we are loading object from stream (form file), we have to wait until
  939.     // everything is loaded before populating the list.  If we are not loading,
  940.     // i.e. the component was created dynamically or was just dropped on a form,
  941.     // we need to reset the flag now.
  942.     if not (csLoading in ComponentState) then
  943.       FUpdateCount := 0;
  944.  
  945.     // Something very bizarre happens in either TCustomListView or in the
  946.     // list view code itself in COMCTL32.DLL:  The first WM_MEASUREITEM value
  947.     // is not honored if the listview has small images assigned to it.  Instead
  948.     // the value is ignored and the height of the images are used.  I found that
  949.     // by forcing Windows to ask for the item height a second time, it would
  950.     // honor the value then.
  951.     if Style = lvOwnerDrawFixed then
  952.       ResetOwnerDrawHeight;
  953.   finally
  954.     FCreatingWindowHandle := FALSE;
  955.   end;
  956. end;
  957.  
  958. procedure TCustomEnhListView.Loaded;
  959. begin
  960.   inherited Loaded;
  961.  
  962. {$IFDEF BACKGROUND_FIXED}
  963.   BackgroundImageChanged(Self);
  964. {$ENDIF}
  965.  
  966.   if not FCreatingWindowHandle then
  967.     HandleNeeded;
  968.  
  969.   FUpdateCount := 0;
  970.  
  971.   if (not LoadSettings) or (not SaveSettings.SaveCurrentSort) then
  972.   begin
  973.     if Columns.Count > 0 then
  974.       FLastColumnClicked := 0;
  975.     Resort;
  976.   end;
  977.  
  978.   // Something flaky going on.  Hard to explain, but this clears it up.
  979.   PostMessage(Handle, WM_OWNERDRAWCOLUMNS, 0, 0);
  980. end;
  981.  
  982. procedure TCustomEnhListView.WMDestroy(var Message: TWMDestroy);
  983. begin
  984.   StoreSettings;
  985.  
  986.   inherited;
  987. end;
  988.  
  989.  
  990. function TCustomEnhListView.StoreSettings: boolean;
  991. begin
  992.   if FSaveSettings.AutoSave and
  993.      (([csDesigning, csLoading, csReading] * ComponentState) = []) then
  994.     Result := WriteSettings
  995.   else
  996.     Result := FALSE;
  997. end;
  998.  
  999. function TCustomEnhListView.WriteSettings: boolean;
  1000. var
  1001.   ColCount: integer;
  1002.   ColArray: PIntArray;
  1003.   x: integer;
  1004. begin
  1005.   Result := TRUE;
  1006.   ColCount := Columns.Count;
  1007.   if ColCount > 0 then
  1008.   begin
  1009.     GetMem(ColArray, SizeOf(Integer)*ColCount);
  1010.     try
  1011.       if FSaveSettings.SaveColumnSizes then
  1012.       begin
  1013.         for x := 0 to ColCount-1 do
  1014.           ColArray[x] := ActualColumn[x].Width;
  1015.         FSaveSettings.StoreColumnSizes(ColCount, ColArray^);
  1016.       end;
  1017.       if FSaveSettings.SaveCurrentSort then
  1018.         FSaveSettings.StoreCurrentSort(CurrentSortAscending, LastColumnClicked);
  1019.       if FSaveSettings.SaveViewStyle then
  1020.         FSaveSettings.StoreViewStyle(ViewStyle);
  1021.     finally
  1022.       FreeMem(ColArray);
  1023.     end;
  1024.   end;
  1025. end;
  1026.  
  1027. function TCustomEnhListView.LoadSettings: boolean;
  1028. begin
  1029.   if FSaveSettings.AutoSave and (not(csDesigning in ComponentState)) then
  1030.     Result := ReadSettings
  1031.   else
  1032.     Result := FALSE;
  1033. end;
  1034.  
  1035. function TCustomEnhListView.ReadSettings: boolean;
  1036. var
  1037.   ColCount: integer;
  1038.   ColArray: PIntArray;
  1039.   x: integer;
  1040.   SortCol: integer;
  1041.   SortAscending: boolean;
  1042. begin
  1043.   Result := TRUE;
  1044.   ColCount := Columns.Count;
  1045.   if ColCount > 0 then
  1046.   begin
  1047.     GetMem(ColArray, SizeOf(Integer)*ColCount);
  1048.     try
  1049.       if FSaveSettings.SaveColumnSizes then
  1050.       begin
  1051.         for x := 0 to ColCount-1 do
  1052.           ColArray[x] := ActualColumn[x].Width;
  1053.         FSaveSettings.ReadColumnSizes(ColCount, ColArray^);
  1054.         if ColArray[0] <> -1 then
  1055.           for x := 0 to ColCount-1 do
  1056.             ActualColumn[x].Width := ColArray[x];
  1057.       end;
  1058.     finally
  1059.       FreeMem(ColArray);
  1060.     end;
  1061.   end;
  1062.  
  1063.   if FSaveSettings.SaveCurrentSort then
  1064.   begin
  1065.     FSaveSettings.ReadCurrentSort(SortAscending, SortCol);
  1066.     if SortCol >= Columns.Count then
  1067.       SortCol := Columns.Count-1;
  1068.     if SortCol < 0 then
  1069.       SortCol := 0;
  1070.     BeginUpdate;
  1071.     try
  1072.       CurrentSortAscending := SortAscending;
  1073.       LastColumnClicked := SortCol;
  1074.       Resort;
  1075.     finally
  1076.       EndUpdate;
  1077.     end;
  1078.   end;
  1079.  
  1080.   if FSaveSettings.SaveViewStyle then
  1081.     ViewStyle := FSaveSettings.ReadViewStyle(ViewStyle);
  1082. end;
  1083.  
  1084. procedure TCustomEnhListView.DoSort(ColumnIndex:integer; Descending: boolean);
  1085. begin
  1086.   FSortDirty := FALSE;
  1087.   LastColumnClicked := ColumnIndex;
  1088.   SortBegin(ColumnIndex, not Descending);
  1089.   if Descending then
  1090.     FDirection := 1
  1091.   else
  1092.     FDirection := -1;
  1093.   FSortColNum := ColumnIndex - 1;
  1094.   if assigned(FOnSortItems) then
  1095.     CustomSort(@__CustomSortProc2__, integer(Self))
  1096.   else
  1097.     CustomSort(@__CustomSortProc1__, integer(Self));
  1098.   SortFinished(ColumnIndex, not Descending);
  1099. end;
  1100.  
  1101. procedure TCustomEnhListView.DefaultSort(ColumnIndex: integer;
  1102.    Descending: boolean);
  1103. begin
  1104.   // Check if the sort order should be toggled
  1105.   if FAutoColumnSort = acsSortToggle then
  1106.     if LastColumnClicked = ColumnIndex then
  1107.       FTmpAutoSortAscending := not Descending
  1108.     else
  1109.       FTmpAutoSortAscending := Descending;
  1110.  
  1111.   InvalidateColumnHeader(ColumnIndex);
  1112.   DoSort(ColumnIndex, Descending);
  1113. end;
  1114.  
  1115. procedure TCustomEnhListView.SortItems(const Item1, Item2: TListItem;
  1116.    SortColumn: integer; var CompResult: integer);
  1117. var
  1118.   SortAs: TSortAs;
  1119.   Str1, Str2: string;
  1120.   F1, F2: extended;
  1121.   Date1, Date2, Diff: TDateTime;
  1122. begin
  1123.   // The only way to get in here is if FOnSortItems is assigned, so don't bother
  1124.   //  checking for NIL
  1125.   SortAs := saNone;
  1126.   FonSortItems(Self, Item1, Item2, SortColumn, SortAs, CompResult);
  1127.   // Do they want us to sort it?
  1128.   if SortAs <> saNone then
  1129.   begin
  1130.     if SortColumn = -1 then
  1131.     begin
  1132.       Str1 := Item1.Caption;
  1133.       Str2 := Item2.Caption;
  1134.     end else begin
  1135.       if SortColumn < Item1.SubItems.Count then
  1136.         Str1 := Item1.SubItems[SortColumn]
  1137.       else
  1138.         Str1 := '';
  1139.       if SortColumn < Item2.SubItems.Count then
  1140.         Str2 := Item2.SubItems[SortColumn]
  1141.       else
  1142.         Str2 := '';
  1143.     end;
  1144.  
  1145.     case SortAs of
  1146.       saString: CompResult := AnsiCompareStr(Str1, Str2);
  1147.       saNumeric:
  1148.         begin
  1149.           if not IsValidNumber(Str1, F1) then
  1150.             F1 := 0;
  1151.           if not IsValidNumber(Str2, F2) then
  1152.             F2 := 0;
  1153.           if F1 < F2 then CompResult := -1
  1154.           else if F1 > F2 then CompResult := 1
  1155.           else CompResult := 0;
  1156.         end;
  1157.       saDateTime:
  1158.         begin
  1159.           if not IsValidDateTime(Str1, Date1) then
  1160.             Date1 := 0;
  1161.           if not IsValidDateTime(Str2, Date2) then
  1162.             Date1 := 0;
  1163.           Diff := Date1 - Date2;
  1164.           if Diff < 0.0 then CompResult := -1
  1165.           else if Diff > 0.0 then CompResult := 1
  1166.           else CompResult := 0
  1167.         end;
  1168.     end;
  1169.   end;
  1170. end;
  1171.  
  1172. procedure TCustomEnhListView.SortBegin(ColumnIndex: integer;
  1173.    Ascending: boolean);
  1174. begin
  1175.   if assigned(FOnSortBegin) then
  1176.     FOnSortBegin(Self, ColumnIndex, Ascending);
  1177. end;
  1178.  
  1179. procedure TCustomEnhListView.SortFinished(ColumnIndex: integer;
  1180.    Ascending: boolean);
  1181. begin
  1182.   if assigned(FOnSortFinished) then
  1183.     FOnSortFinished(Self, ColumnIndex, Ascending);
  1184. end;
  1185.  
  1186. procedure TCustomEnhListView.ColClick(Column: TListColumn);
  1187. begin
  1188.   // Check if the sort order should be toggled
  1189.   if FAutoColumnSort = acsSortToggle then
  1190.     if LastColumnClicked = Column.Index then
  1191.       FTmpAutoSortAscending := not FTmpAutoSortAscending
  1192.     else
  1193.       FTmpAutoSortAscending := FAutoSortAscending;
  1194.  
  1195.   inherited ColClick(Column);
  1196.  
  1197.   if (FAutoColumnSort <> acsNoSort) and (Column.Index < Columns.Count) then
  1198.     DoSort(Column.Index, FTmpAutoSortAscending);
  1199.  
  1200.   LastColumnClicked := Column.Index;
  1201. end;
  1202.  
  1203. {$IFDEF DFS_FIXED_LIST_VIEW}
  1204. procedure TCustomEnhListView.InsertItem(Item: TListItem);
  1205. begin
  1206.   inherited InsertItem(Item);
  1207.   if FAutoResort then
  1208.     Resort;
  1209. end;
  1210. {$ENDIF}
  1211.  
  1212.  
  1213. procedure TCustomEnhListView.Edit(const Item: TLVItem);
  1214. begin
  1215.   inherited Edit(Item);
  1216.   if FAutoResort then
  1217.     Resort;
  1218. end;
  1219.  
  1220. type
  1221.   THackListItems = class(TListItems)
  1222.   end;
  1223.  
  1224. procedure TCustomEnhListView.EditCanceled(const Item: TLVItem);
  1225. begin
  1226.   if assigned(FOnEditCanceled) then
  1227.     with Item do
  1228.       FOnEditCanceled(Self, THackListItems(Items).GetItem(iItem));
  1229. end;
  1230.  
  1231. {$IFNDEF DFS_COMPILER_4_UP}
  1232. function TCustomEnhListView.GetItem(Value: TLVItem): TListItem;
  1233. begin
  1234.   with Value do
  1235.     if (mask and LVIF_PARAM) <> 0 then Result := TListItem(lParam)
  1236.     else Result := Items[IItem];
  1237. end;
  1238. {$ENDIF}
  1239.  
  1240.  
  1241. {$IFNDEF DFS_COMPILER_4_UP}
  1242. type
  1243.   THackdfsExtListView = class(TdfsExtListView);
  1244. {$ENDIF}
  1245. procedure TCustomEnhListView.CNNotify(var Message: TWMNotify);
  1246. {$IFNDEF DFS_COMPILER_4_UP}
  1247. var
  1248.   Item: TListItem;
  1249. {$ENDIF}
  1250. begin
  1251.   inherited;
  1252.  
  1253.   with Message.NMHdr^ do
  1254.     case code of
  1255. {$IFNDEF DFS_FIXED_LIST_VIEW}
  1256.       LVN_INSERTITEM:
  1257.         if FAutoResort then
  1258.           Resort;
  1259. {$ENDIF}
  1260.       LVN_ENDLABELEDIT:
  1261.         with PLVDispInfo(Pointer(Message.NMHdr))^ do
  1262.           if (item.pszText = NIL) and (item.IItem <> -1) then
  1263.             EditCanceled(item);
  1264. {$IFNDEF DFS_COMPILER_4_UP}
  1265.       LVN_GETDISPINFO:
  1266.         begin
  1267.           Item := GetItem(PLVDispInfo(Message.NMHdr)^.item);
  1268.           if Item <> NIL then
  1269.             with PLVDispInfo(Message.NMHdr)^.item do
  1270.             begin
  1271.               if (mask and LVIF_IMAGE) <> 0 then
  1272.               begin
  1273.                 if iSubItem = 0 then
  1274.                 begin
  1275.                   GetImageIndex(Item);
  1276.                   iImage := Item.ImageIndex;
  1277.                   if Assigned(StateImages) then
  1278.                   begin
  1279.                     state := IndexToStateImageMask(Item.StateIndex + 1);
  1280.                     stateMask := $F000;
  1281.                     mask := mask or LVIF_STATE;
  1282.                   end;
  1283.                 end;
  1284.               end;
  1285.             end;
  1286.         end;
  1287. {$ENDIF}
  1288.     end;
  1289. end;
  1290.  
  1291. procedure TCustomEnhListView.SetAutoColumnSort(Value: TAutoColumnSort);
  1292. begin
  1293.   if FAutoColumnSort <> Value then
  1294.   begin
  1295.     FAutoColumnSort := Value;
  1296.     if FAutoColumnSort <> acsNoSort then
  1297.       Resort;
  1298.   end;
  1299. end;
  1300.  
  1301. procedure TCustomEnhListView.SetAutoSortStyle(Value: TAutoSortStyle);
  1302. begin
  1303.   if FAutoSortStyle <> Value then
  1304.   begin
  1305.     FAutoSortStyle := Value;
  1306.     Resort;
  1307.   end;
  1308. end;
  1309.  
  1310. procedure TCustomEnhListView.SetAutoResort(Value: boolean);
  1311. begin
  1312.   if FAutoResort <> Value then
  1313.     FAutoResort := Value;
  1314. end;
  1315.  
  1316. procedure TCustomEnhListView.SetCurrentSortAscending(Value: boolean);
  1317. begin
  1318.   if FTmpAutoSortAscending <> Value then
  1319.   begin
  1320.     FTmpAutoSortAscending := Value;
  1321.     InvalidateColumnHeader(FLastColumnClicked);
  1322.   end;
  1323. end;
  1324.  
  1325. procedure TCustomEnhListView.SetAutoSortAscending(Value: Boolean);
  1326. begin
  1327.   if FAutoSortAscending <> Value then
  1328.   begin
  1329.     FAutoSortAscending := Value;
  1330.     FTmpAutoSortAscending := Value;
  1331.   end;
  1332. end;
  1333.  
  1334. procedure TCustomEnhListView.Resort;
  1335. begin
  1336.   FSortDirty := TRUE;
  1337.   if ((FAutoColumnSort <> acsNoSort) and (LastColumnClicked >= 0) and
  1338.      (LastColumnClicked < Columns.Count)) or (assigned(FOnSortItems)) then
  1339.   begin
  1340.     if FUpdateCount < 1 then
  1341.       DoSort(LastColumnClicked, FTmpAutoSortAscending);
  1342.   end;
  1343. end;
  1344.  
  1345. procedure TCustomEnhListView.BeginUpdate;
  1346. begin
  1347.   Items.BeginUpdate;
  1348.   inc(FUpdateCount);
  1349. end;
  1350.  
  1351.  
  1352. procedure TCustomEnhListView.EndUpdate;
  1353. begin
  1354.   dec(FUpdateCount);
  1355.   if FUpdateCount < 0 then
  1356.     FUpdateCount := 0; // In case someone gets overly happy with EndUpdate calls
  1357.   if FUpdateCount = 0 then
  1358.   begin
  1359.     // Need to resort?
  1360.     if FSortDirty then
  1361.       Resort;
  1362.   end;
  1363.  
  1364.   // Call this last so resort happens before screen redraw is re-enabled.
  1365.   Items.EndUpdate;
  1366. end;
  1367.  
  1368.  
  1369. procedure TCustomEnhListView.DrawItem(var Canvas: TCanvas; Index: Integer;
  1370.    Rect: TRect; State: TOwnerDrawState; var DefaultDrawing,
  1371.    FullRowSelect: boolean);
  1372. begin
  1373.   DefaultDrawing := not assigned(FOnDrawItem);
  1374.   if assigned(FOnDrawItem) then
  1375.     FOnDrawItem(Self, Canvas, Index, Rect, State, DefaultDrawing,FullRowSelect);
  1376. end;
  1377.  
  1378. procedure TCustomEnhListView.AfterDrawItem(var Canvas: TCanvas; Index: Integer;
  1379.    Rect: TRect; State: TOwnerDrawState);
  1380. begin
  1381.   if assigned(FOnAfterDefaultDrawItem) then
  1382.     FOnAfterDefaultDrawItem(Self, Canvas, Index, Rect, State);
  1383. end;
  1384.  
  1385. procedure TCustomEnhListView.CMSysColorChange(var Message: TWMSysColorChange);
  1386. begin
  1387.   // Need to recreate the sort arrow bmps to use the new system colors
  1388.   if ShowSortArrows then
  1389.     CreateSortBmps(FSortUpBmp, FSortDownBmp);
  1390.   inherited;
  1391. end;
  1392.  
  1393. procedure TCustomEnhListView.CMFontChanged(var Messsage: TMessage);
  1394. begin
  1395.   if HandleAllocated and (Style = lvOwnerDrawFixed) then
  1396.     RecreateWnd
  1397.   else
  1398.     inherited;
  1399. end;
  1400.  
  1401. procedure TCustomEnhListView.CNMeasureItem(var Message: TWMMeasureItem);
  1402. var
  1403.   DC: HDC;
  1404.   OldFont: HFONT;
  1405.   Size: TSize;
  1406. begin
  1407.   inherited;
  1408.  
  1409.   DC := CreateCompatibleDC(0);
  1410.   OldFont := SelectObject(DC, Font.Handle);
  1411.   try
  1412.     GetTextExtentPoint32(DC, 'Wy', 2, Size);
  1413.     // Owner drawing only happens in vsReport mode, so no need to check anything
  1414.     // besides that.
  1415.     // I'm checking SmallImages.Height here, but I don't think it'll do any
  1416.     // good.  From what I can tell, if you have SmallImages assigned, this
  1417.     // handler will get called but the value you give it is ignored and the
  1418.     // list uses it's normal item height.  Strange....
  1419.     if assigned(SmallImages) and (SmallImages.Height > Size.cy) then
  1420.       Message.MeasureItemStruct.itemHeight := SmallImages.Height
  1421.     else
  1422.       Message.MeasureItemStruct.itemHeight := Size.cy + 1;
  1423.   finally
  1424.     SelectObject(DC, OldFont);
  1425.     DeleteDC(DC);
  1426.   end;
  1427.   MeasureItem(Message.MeasureItemStruct.itemHeight);
  1428.   Message.Result := 1;
  1429. end;
  1430.  
  1431. procedure TCustomEnhListView.MeasureItem(var Height: UINT);
  1432. begin
  1433.   if assigned(FOnMeasureItem) then
  1434.     FOnMeasureItem(Self, Height);
  1435. end;
  1436.  
  1437.  
  1438. procedure TCustomEnhListView.CNDrawItem(var Message: TWMDrawItem);
  1439. var
  1440.   State: TOwnerDrawState;
  1441.   DoDefaultDrawing: boolean;
  1442.   FullRowSelect: boolean;
  1443.   SavedDC: integer;
  1444. begin { CNDrawItem }
  1445.   if FCanvas = NIL then exit;
  1446.  
  1447.   with Message.DrawItemStruct^ do
  1448.   begin
  1449.     {$IFDEF DFS_COMPILER_5_UP}
  1450.     State := TOwnerDrawState(LongRec(itemState).Lo);
  1451.     {$ELSE}
  1452.     State := TOwnerDrawState(WordRec(LongRec(itemState).Lo).Lo);
  1453.     {$ENDIF}
  1454.     SavedDC := SaveDC(hDC);
  1455.     FCanvas.Handle := hDC;
  1456.     try
  1457.       FCanvas.Font := Font;
  1458.       FCanvas.Brush := Brush;
  1459.       DoDefaultDrawing := FALSE;
  1460.       FullRowSelect := FALSE;
  1461.       ProcessDrawItemMsg(itemID, rcItem, State, DoDefaultDrawing, FullRowSelect);
  1462.     finally
  1463.       FCanvas.Handle := 0;
  1464.       RestoreDC(hDC, SavedDC);
  1465.     end;
  1466.   end;
  1467.  
  1468.   Message.Result := 1;
  1469. end;
  1470.  
  1471. function TCustomEnhListView.GetActualColumn(Index: integer): TListColumn;
  1472. begin
  1473.   // Delphi 2 and C++B 1 have a bug in TListColumn.GetWidth.  It returns zero
  1474.   // for the width if the handle hasn't been allocated yet instead of returning
  1475.   // the value of the internal storage variable like Delphi 3 does.  I've also
  1476.   // had some problems similar under Delphi 3, so I'm just always requiring the
  1477.   // handle to be valid.
  1478.   HandleNeeded;
  1479.  
  1480.   if Index >= Columns.Count then
  1481.     Result := NIL
  1482.   else
  1483.     Result := Columns[Index];
  1484. end;
  1485.  
  1486. function TCustomEnhListView.GetSubItemText(Index, SubItem: integer): string;
  1487. begin
  1488.   if SubItem < 0 then
  1489.     Result := Items[Index].Caption
  1490.   else
  1491.     Result := Items[Index].SubItems[SubItem];
  1492. end;
  1493.  
  1494. // SubItem is -1 for Caption item
  1495. procedure TCustomEnhListView.DrawSubItem(Index, SubItem: Integer; Rect: TRect;
  1496.    State: TOwnerDrawState; var DefaultDrawing: boolean);
  1497. begin
  1498.   DefaultDrawing := not assigned(FOnDrawSubItem);
  1499.   if assigned(FOnDrawSubItem) then
  1500.     FOnDrawSubItem(Self, FCanvas, Index, SubItem, Rect, State, DefaultDrawing);
  1501. end;
  1502.  
  1503. procedure TCustomEnhListView.DefaultDrawSubItem(Index, SubItem: Integer;
  1504.    Rect: TRect; State: TOwnerDrawState);
  1505. var
  1506.   DoDefaultDrawing: boolean;
  1507.   SavedDC: integer;
  1508. begin
  1509.   DoDefaultDrawing := csDesigning in ComponentState;
  1510.   SavedDC := SaveDC(FCanvas.Handle);
  1511.   try
  1512.     if not (csDesigning in ComponentState) then
  1513.       DrawSubItem(Index, SubItem, Rect, State, DoDefaultDrawing);
  1514.  
  1515.     if DoDefaultDrawing then
  1516.     begin
  1517.       if SubItem >= 0 then
  1518.         InflateRect(Rect, -4, 0);
  1519.       if ActualColumn[SubItem+1].Alignment = taLeftJustify then
  1520.         Inc(Rect.Left, DefDraw_TextOffset);
  1521.       DrawTextEx(FCanvas.Handle, PChar(GetSubItemText(Index, SubItem)), -1, Rect,
  1522.          DRAWTEXTEX_FLAGS or
  1523.          DRAWTEXTEX_ALIGNMENT[ActualColumn[SubItem+1].Alignment], NIL);
  1524.     end;
  1525.   finally
  1526.     RestoreDC(FCanvas.Handle, SavedDC);
  1527.   end;
  1528. end;
  1529.  
  1530. {$IFDEF DFS_COMPILER_4_UP}
  1531. type
  1532.   THackImageList = class(TCustomImageList);
  1533. {$ENDIF}
  1534.  
  1535. procedure TCustomEnhListView.DefaultDrawItem(Index: Integer; Rect: TRect;
  1536.    State: TOwnerDrawState; FullRowSelect: boolean);
  1537. {$IFDEF DFS_COMPILER_4_UP}
  1538. const
  1539.   DrawingStyles: array[TDrawingStyle] of Longint = (ILD_FOCUS, ILD_SELECTED,
  1540.     ILD_NORMAL, ILD_TRANSPARENT);
  1541.   Images: array[TImageType] of Longint = (0, ILD_MASK);
  1542. {$ENDIF}
  1543. var
  1544. {$IFDEF DFS_COMPILER_4_UP}
  1545.   DS: TDrawingStyle;
  1546.   x: integer;
  1547. {$ELSE}
  1548.   OldStyle: TDrawingStyle;
  1549. {$ENDIF}
  1550.   OldBlend: TColor;
  1551.   Count: Integer;
  1552.   SubRect: TRect;
  1553.   ImgTop: integer;
  1554. begin
  1555.   if Items[Index] = NIL then
  1556.     // something bad happening, I'm outta here
  1557.     exit;
  1558.  
  1559.   if Columns.Count > 0 then
  1560.   begin
  1561.     if (odSelected in State) then
  1562.     begin
  1563.       if Focused then
  1564.       begin
  1565.         FCanvas.Brush.Color := clHighlight;
  1566.         FCanvas.Font.Color := clHighlightText;
  1567.       end else begin
  1568.         if not HideSelection then
  1569.         begin
  1570.           FCanvas.Brush.Color := clBtnFace;
  1571.           FCanvas.Font.Color := clBtnText;
  1572.         end;
  1573.       end;
  1574.     end;
  1575.     SubRect := Rect;
  1576.     SubRect.Right := Rect.Left + CurrentColumnWidth[0]{ - 2};
  1577.  
  1578.     if assigned(StateImages) then
  1579.     begin
  1580.       StateImages.Draw(FCanvas, SubRect.Left + DefDraw_ImageOffSet,
  1581.          SubRect.Top + (SubRect.Bottom - SubRect.Top - StateImages.Height) div 2,
  1582.          Items[Index].StateIndex);
  1583.       Inc(SubRect.Left, StateImages.Width);
  1584.     end;
  1585.  
  1586.     if assigned(SmallImages) then
  1587.     begin
  1588.       OldBlend := SmallImages.BlendColor;
  1589.       SmallImages.BlendColor := clHighlight;
  1590.       ImgTop := SubRect.Top + (SubRect.Bottom - SubRect.Top -
  1591.         SmallImages.Height) div 2;
  1592.       {$IFDEF DFS_COMPILER_4_UP}
  1593.       { Changing DrawStyle causes an invalidate, which is very nasty since we
  1594.         are in the process of repainting here.  Continuous flickering.... }
  1595.       if Focused and ((odSelected in State) or Items[Index].Focused) then
  1596.         DS := dsSelected
  1597.       else
  1598.         DS := dsTransparent;
  1599.       // Draw OverlayImage
  1600.       if (Items[Index].OverlayIndex >= 0) and
  1601.          (Items[Index].OverlayIndex <= 3) then // vadid overlay index?
  1602.       begin
  1603.         x := IndexToOverlayMask(Items[Index].OverlayIndex+1);
  1604.         THackImageList(SmallImages).DoDraw(Items[Index].ImageIndex, FCanvas,
  1605.            SubRect.Left + DefDraw_ImageOffSet, ImgTop, DrawingStyles[DS] or
  1606.            Images[SmallImages.ImageType] or ILD_OVERLAYMASK and x, Enabled);
  1607.       end else
  1608.         THackImageList(SmallImages).DoDraw(Items[Index].ImageIndex, FCanvas,
  1609.            SubRect.Left + DefDraw_ImageOffSet, ImgTop,
  1610.            DrawingStyles[DS] or Images[SmallImages.ImageType], Enabled);
  1611.  
  1612.  
  1613.       {$ELSE}
  1614.       OldStyle := SmallImages.DrawingStyle;
  1615.       if Focused and ((odSelected in State) or Items[Index].Focused) then
  1616.         SmallImages.DrawingStyle := dsSelected
  1617.       else
  1618.         SmallImages.DrawingStyle := dsTransparent;
  1619.  
  1620.       SmallImages.Draw(FCanvas, SubRect.Left + DefDraw_ImageOffSet, ImgTop,
  1621.          Items[Index].ImageIndex);
  1622.  
  1623.       // Draw OverlayImage
  1624.       if (Items[Index].OverlayIndex >= 0) and
  1625.          (Items[Index].OverlayIndex <= 3) then // vadid overlay index?
  1626.         SmallImages.DrawOverlay(FCanvas, SubRect.Left + DefDraw_ImageOffSet,
  1627.            ImgTop, Items[Index].ImageIndex, Items[Index].OverlayIndex);
  1628.  
  1629.       SmallImages.DrawingStyle := OldStyle;
  1630.       {$ENDIF}
  1631.  
  1632.       SmallImages.BlendColor := OldBlend;
  1633.       if ActualColumn[0].Alignment = taLeftJustify then
  1634.         Inc(SubRect.Left, {DefDraw_TextOffset + }SmallImages.Width);
  1635. {    end else begin
  1636.       if ActualColumn[0].Alignment = taLeftJustify then
  1637.         Inc(SubRect.Left, DefDraw_TextOffset);}
  1638.     end;
  1639.  
  1640.     DefaultDrawSubItem(Index, -1, SubRect, State);
  1641.  
  1642.     // Already done column 0, start at 1.
  1643.     for Count := 1 to Columns.Count-1 do
  1644.     begin
  1645.       { Restore this through each iteration since they may screw with it in
  1646.         the OnDrawSubItem event. }
  1647.       if not FullRowSelect then
  1648.       begin
  1649.         FCanvas.Brush.Color := clWindow;
  1650.         FCanvas.Font.Color := clWindowText;
  1651.       end;
  1652.  
  1653.       if Count > Items[Index].SubItems.Count then
  1654.         continue; // Hidden item
  1655.       if ActualColumn[Count].Alignment = taLeftJustify then
  1656.       begin
  1657.         SubRect.Left := SubRect.Right;
  1658.         SubRect.Right := SubRect.Left + CurrentColumnWidth[Count];
  1659. //        Inc(SubRect.Left, DefDraw_TextOffset)
  1660.       end else begin
  1661.         SubRect.Left := SubRect.Right;// + DefDraw_TextOffset;
  1662.         SubRect.Right := SubRect.Left + CurrentColumnWidth[Count];
  1663. //        Dec(SubRect.Right, DefDraw_TextOffset);
  1664.       end;
  1665.       DefaultDrawSubItem(Index, Count-1, SubRect, State);
  1666.     end;
  1667.   end;
  1668. end;
  1669.  
  1670.  
  1671. procedure TCustomEnhListView.ProcessDrawItemMsg(Index: Integer; Rect: TRect;
  1672.    State: TOwnerDrawState; var DefaultDrawing, FullRowSelect: boolean);
  1673. var
  1674.   SubRect: TRect;
  1675. begin
  1676.   DefaultDrawing := csDesigning in ComponentState;
  1677.   if not (csDesigning in ComponentState) then
  1678.     DrawItem(FCanvas, Index, Rect, State, DefaultDrawing, FullRowSelect);
  1679.  
  1680.   if DefaultDrawing then
  1681.   begin
  1682.     FCanvas.FillRect(Rect);
  1683.  
  1684.     if (Index >= 0) then
  1685.     begin
  1686.       if (odSelected in State) then
  1687.       begin
  1688.         if (not HideSelection) or Focused then
  1689.         begin
  1690.           if Focused then
  1691.             FCanvas.Brush.Color := clHighlight
  1692.           else
  1693.             FCanvas.Brush.Color := clBtnFace;
  1694.  
  1695.           SubRect := Rect;
  1696. //          Inc(SubRect.Left, DefDraw_TextOffset - 2);
  1697. //          Dec(SubRect.Left, 2);
  1698.           if (not FullRowSelect) then
  1699.           begin
  1700.             if assigned(Items[Index]) then
  1701.               SubRect.Right := SubRect.Left +
  1702.                  FCanvas.TextWidth(Items[Index].Caption) + 8;
  1703.             if assigned(StateImages) then
  1704.               OffsetRect(SubRect, StateImages.Width, 0);
  1705.             if assigned(SmallImages) then
  1706.               OffsetRect(SubRect, SmallImages.Width, 0);
  1707.             // Don't let it go past first column width
  1708.             if (Columns.Count > 0) and
  1709.                (CurrentColumnWidth[0] < SubRect.Right) then
  1710.               SubRect.Right := CurrentColumnWidth[0];
  1711.           end else begin
  1712.             if assigned(StateImages) then
  1713.               Inc(SubRect.Left, StateImages.Width);
  1714.             if assigned(SmallImages) then
  1715.               Inc(SubRect.Left, SmallImages.Width);
  1716.           end;
  1717.           FCanvas.FillRect(SubRect);
  1718.         end;
  1719.       end;
  1720.       DefaultDrawItem(Index, Rect, State, FullRowSelect);
  1721.       if (odFocused in State) and Focused then
  1722.       begin
  1723.         SubRect := Rect;
  1724. //        Inc(SubRect.Left, DefDraw_TextOffset - 2);
  1725. //        Dec(SubRect.Left, 2);
  1726.         if (not FullRowSelect) then
  1727.         begin
  1728.           if assigned(Items[Index]) then
  1729.             SubRect.Right := SubRect.Left +
  1730.                FCanvas.TextWidth(Items[Index].Caption) + 8;
  1731.             if assigned(SmallImages) then
  1732.               OffsetRect(SubRect, SmallImages.Width, 0);
  1733.             if assigned(StateImages) then
  1734.               OffsetRect(SubRect, StateImages.Width, 0);
  1735.             // Don't let it go past first column width
  1736.             if (Columns.Count > 0) and
  1737.                (CurrentColumnWidth[0] < SubRect.Right) then
  1738.               SubRect.Right := CurrentColumnWidth[0];
  1739.         end else begin
  1740.           if assigned(StateImages) then
  1741.             Inc(SubRect.Left, StateImages.Width);
  1742.           if assigned(SmallImages) then
  1743.             Inc(SubRect.Left, SmallImages.Width);
  1744.         end;
  1745.         FCanvas.DrawFocusRect(SubRect);
  1746.       end;
  1747.     end else
  1748.       FCanvas.FillRect(Rect);
  1749.  
  1750.     if (not (csDesigning in ComponentState)) then
  1751.       AfterDrawItem(FCanvas, Index, Rect, State);
  1752.   end;
  1753. end;
  1754.  
  1755.  
  1756. procedure TCustomEnhListView.SetStyle(Value: TLVStyle);
  1757. begin
  1758.   if FStyle <> Value then
  1759.   begin
  1760.     FStyle := Value;
  1761.     if HandleAllocated then
  1762.       RecreateWnd;
  1763.   end;
  1764. end;
  1765.  
  1766. procedure TCustomEnhListView.SetReverseSortArrows(Value: boolean);
  1767. begin
  1768.   if Value <> FReverseSortArrows then
  1769.   begin
  1770.     FReverseSortArrows := Value;
  1771.     if ShowSortArrows then
  1772.     begin
  1773.       CreateSortBmps(FSortUpBmp, FSortDownBmp);
  1774.       InvalidateColumnHeader(FLastColumnClicked);
  1775.     end;
  1776.   end;
  1777. end;
  1778.  
  1779. procedure TCustomEnhListView.SetShowSortArrows(Value: boolean);
  1780. begin
  1781.   if Value <> FShowSortArrows then
  1782.     FShowSortArrows := Value;
  1783.   FSortUpBmp.Free;
  1784.   FSortDownBmp.Free;
  1785.   if FShowSortArrows then
  1786.   begin
  1787.     FSortUpBmp := TBitmap.Create;
  1788.     FSortDownBmp := TBitmap.Create;
  1789.     CreateSortBmps(FSortUpBmp, FSortDownBmp);
  1790.     if not (csReading in ComponentState) then
  1791.       SetColumnsOwnerDrawFlag(TRUE);
  1792.   end else begin
  1793.     FSortUpBmp := NIL;
  1794.     FSortDownBmp := NIL;
  1795.  
  1796.     if not (csReading in ComponentState) then
  1797.       SetColumnsOwnerDrawFlag(assigned(FOnDrawHeader))
  1798.   end;
  1799.   if HandleAllocated then
  1800.     Invalidate;
  1801. end;
  1802.  
  1803. procedure TCustomEnhListView.CreateSortBmps(var UpBmp, DownBmp: TBitmap);
  1804. var
  1805.   HeaderHeight: integer;
  1806.   MidPoint: integer;
  1807.   Bmp: TBitmap;
  1808. begin
  1809.   if UpBmp = NIL then
  1810.     UpBmp := TBitmap.Create;
  1811.   if DownBmp = NIL then
  1812.     DownBmp := TBitmap.Create;
  1813.  
  1814.   UpBmp.Canvas.Font.Assign(Font);
  1815.   HeaderHeight := UpBmp.Canvas.TextHeight('Wy') - 6;
  1816.   if HeaderHeight > 0 then
  1817.   begin
  1818.     if Odd(HeaderHeight) then
  1819.       Inc(HeaderHeight);
  1820.     UpBmp.Width := HeaderHeight;
  1821.     UpBmp.Height := HeaderHeight;
  1822.     DownBmp.Width := HeaderHeight;
  1823.     DownBmp.Height := HeaderHeight;
  1824.     MidPoint := HeaderHeight div 2;
  1825.  
  1826.     { Don't ask about the drawing.  I just fooled around until I got
  1827.       something I liked. }
  1828.     if FReverseSortArrows then
  1829.       Bmp := UpBmp
  1830.     else
  1831.       Bmp := DownBmp;
  1832.     with Bmp.Canvas do
  1833.     begin
  1834.       Brush.Color := clBtnFace;
  1835.       FillRect(Rect(0, 0, HeaderHeight, HeaderHeight));
  1836.       Pen.Color := clBtnShadow;
  1837.       MoveTo(MidPoint, HeaderHeight-2);
  1838.       LineTo(HeaderHeight-1, 0);
  1839.       Pixels[HeaderHeight-1, 0] := Pen.Color;
  1840.       Pen.Color := clBtnHighlight;
  1841.       MoveTo(HeaderHeight-2, 0);
  1842.       LineTo(0, 0);
  1843.       LineTo(MidPoint-1, HeaderHeight-2);
  1844.       Pixels[MidPoint-1, HeaderHeight-2] := Pen.Color;
  1845.     end;
  1846.  
  1847.     if FReverseSortArrows then
  1848.       Bmp := DownBmp
  1849.     else
  1850.       Bmp := UpBmp;
  1851.     with Bmp.Canvas do
  1852.     begin
  1853.       Brush.Color := clBtnFace;
  1854.       FillRect(Rect(0, 0, HeaderHeight, HeaderHeight));
  1855.       Pen.Color := clBtnHighlight;
  1856.       MoveTo(0, HeaderHeight-1);
  1857.       LineTo(MidPoint-1, 0);
  1858.       Pen.Color := clBtnShadow;
  1859.       MoveTo(MidPoint, 0);
  1860.       LineTo(HeaderHeight-1, HeaderHeight-1);
  1861.       LineTo(-1, HeaderHeight-1);
  1862.       Pixels[MidPoint, 0] := clBtnFace;
  1863.     end;
  1864.   end;
  1865. end;
  1866.  
  1867. procedure TCustomEnhListView.DestroyWnd;
  1868. begin
  1869.   if not FCreatingWindowHandle then
  1870.   begin
  1871.     inherited DestroyWnd;
  1872.  
  1873.     FHeaderHandle := 0;
  1874.   end;
  1875. end;
  1876.  
  1877. procedure TCustomEnhListView.DrawHeader(var Canvas: TCanvas; Index: Integer;
  1878.    var Rect: TRect; Selected: boolean; var DefaultDrawing: boolean);
  1879. begin
  1880.   DefaultDrawing := not assigned(FOnDrawHeader);
  1881.   if assigned(FOnDrawHeader) then
  1882.     FOnDrawHeader(Self, Canvas, Index, Rect, Selected, DefaultDrawing);
  1883. end;
  1884.  
  1885. procedure TCustomEnhListView.WMNotify(var Message: TWMNotify);
  1886. const
  1887.   RECURSE_FLAG: boolean = FALSE;
  1888. begin
  1889.   if NoColumnResize then
  1890.     case Message.NMHdr.code of
  1891.       HDN_BEGINTRACK, HDN_TRACK, HDN_BEGINTRACKW, HDN_TRACKW:
  1892.       begin
  1893.         Message.Result := 1;
  1894.         exit;
  1895.       end;
  1896.     end;
  1897.  
  1898.   inherited;
  1899.   // Note the recursion flag.  This is needed since the SetColumnsOwnerDrawFlag
  1900.   // call below will cause some HDN_xxx notification messages.
  1901.   if RECURSE_FLAG then
  1902.     exit;
  1903.  
  1904.   // For some reason, the SECOND time you drag a header width, it toasts the
  1905.   // column index in the draw item message.  Also seems to reset owner draw
  1906.   // info at times, too.  Anyway, the best fix I could come up with was to
  1907.   // always reset the owner draw flag.
  1908.   case Message.NMHdr.code of
  1909.     HDN_BEGINTRACK, HDN_ITEMCHANGED, HDN_BEGINTRACKW, HDN_ITEMCHANGEDW:
  1910.       begin
  1911.         if Message.NMHdr.code <> HDN_TRACK then
  1912.         begin
  1913.           RECURSE_FLAG := TRUE;
  1914.           try
  1915.             SetColumnsOwnerDrawFlag(assigned(FOnDrawHeader) or FShowSortArrows);
  1916.           finally
  1917.             RECURSE_FLAG := FALSE;
  1918.           end;
  1919.         end;
  1920.       end;
  1921.     HDN_DIVIDERDBLCLICK, HDN_DIVIDERDBLCLICKW:
  1922.       { D4 (and others probably) don't update column width when this happens. }
  1923.       begin
  1924.         with PHDNotify(Pointer(Message.NMHdr))^ do
  1925.           if Item < Columns.Count then
  1926.             {$IFDEF DFS_COMPILER_4_UP}
  1927.             Column[Item].Width :=
  1928.             {$ELSE}
  1929.             ActualColumn[Item].Width :=
  1930.             {$ENDIF}
  1931.               ListView_GetColumnWidth(Handle, Item);
  1932.       end;
  1933.   end;
  1934.  
  1935. (*  old way.  had some performance problems when used in conjunction with
  1936.     TToolbar97 component.  No idea why that would cause it, though.
  1937.   // For some reason, the SECOND time you drag a header width, it toasts the
  1938.   // column index in the draw item message.  Also seems to reset owner draw
  1939.   // info at times, too.  Anyway, the best fix I could come up with was to
  1940.   // always watch for a change in the header handle, and always reset the owner
  1941.   // draw flag.  Note the recursion flag.  This is needed since the
  1942.   // SetColumnsOwnerDrawFlag will cause some HDN_xxx notification messages.
  1943.  
  1944.   // Best way that I can find to snag the real header handle.  Kludgy at best,
  1945.   // but what else are you gonna do?
  1946.   case Message.NMHdr.code of
  1947.     HDN_LAST..HDN_FIRST:
  1948.       begin
  1949.         if Message.NMHdr.hwndFrom <> FHeaderHandle then
  1950.           FHeaderHandle := Message.NMHdr^.hwndFrom;
  1951.  
  1952.         if RECURSE_FLAG or (FUpdateCount > 0) then exit;
  1953.  
  1954.         RECURSE_FLAG := TRUE;
  1955.         try
  1956.           SetColumnsOwnerDrawFlag(assigned(FOnDrawHeader) or FShowSortArrows);
  1957.         finally
  1958.           RECURSE_FLAG := FALSE;
  1959.         end;
  1960.       end;
  1961.   end;
  1962. *)
  1963. end;
  1964.  
  1965. procedure TCustomEnhListView.WMDrawHeader(var Message: TWMDrawItem);
  1966. var
  1967.   State: TOwnerDrawState;
  1968.   DoDefaultDrawing: boolean;
  1969.   SavedDC: integer;
  1970. begin { CNDrawItem }
  1971.   if FCanvas = NIL then exit;
  1972.  
  1973.   with Message.DrawItemStruct^ do
  1974.   begin
  1975.     Message.Result := 1;
  1976.     {$IFDEF DFS_COMPILER_5_UP}
  1977.     State := TOwnerDrawState(LongRec(itemState).Lo);
  1978.     {$ELSE}
  1979.     State := TOwnerDrawState(WordRec(LongRec(itemState).Lo).Lo);
  1980.     {$ENDIF}
  1981.     SavedDC := SaveDC(hDC);
  1982.     FCanvas.Handle := hDC;
  1983.     try
  1984.       FCanvas.Font := Font;
  1985.       FCanvas.Brush := Brush;
  1986.       DoDefaultDrawing := FALSE;
  1987.       ProcessDrawHeaderMsg(itemID, rcItem, State, DoDefaultDrawing);
  1988.     finally
  1989.       FCanvas.Handle := 0;
  1990.       RestoreDC(hDC, SavedDC);
  1991.     end;
  1992.   end;
  1993. end;
  1994.  
  1995. procedure TCustomEnhListView.ProcessDrawHeaderMsg(Index: Integer; Rect: TRect;
  1996.    State: TOwnerDrawState; var DefaultDrawing: boolean);
  1997. begin
  1998.   FCanvas.Font.Assign(Font);
  1999.   FCanvas.Brush.Assign(Brush);
  2000.   FCanvas.Brush.Style := bsClear;
  2001.   FCanvas.Brush.Color := clBtnFace;
  2002.  
  2003.   DefaultDrawing := csDesigning in ComponentState;
  2004.   if not (csDesigning in ComponentState) then
  2005.     DrawHeader(FCanvas, Index, Rect, odSelected in State, DefaultDrawing);
  2006.  
  2007.   if DefaultDrawing then
  2008.     DefaultDrawHeader(FCanvas, Index, Rect, odSelected in State);
  2009. end;
  2010.  
  2011. procedure TCustomEnhListView.DefaultDrawHeader(var Canvas: TCanvas;
  2012.    Index: Integer; var Rect: TRect; Selected: boolean);
  2013. var
  2014.   TheColumn: TListColumn;
  2015.   Offset: integer;
  2016.   R, CR: TRect;
  2017.   Bmp: TBitmap;
  2018. begin
  2019.  
  2020. (******************************************************************************)
  2021. (* NOTE:  This method is overriden and replaced in TExtListView.  That means  *)
  2022. (*   that if changes are made here, they will also need to be made in         *)
  2023. (*   ExtListView.pas' DefaultDrawHeader method.                               *)
  2024. (******************************************************************************)
  2025.  
  2026.   if not Selected then
  2027.     InflateRect(Rect, -2, -2);
  2028.   Canvas.FillRect(Rect);
  2029.   if Selected then
  2030.     InflateRect(Rect, -2, -2);
  2031.  
  2032.   if (Index >= 0) and (Index < Columns.Count) then
  2033.   begin
  2034.     // Don't use ActualColumn[] here!  That's for SubItem foolery, not header.
  2035.     TheColumn := Columns[Index];
  2036.  
  2037.     if Selected then
  2038.     begin
  2039.       inc(Rect.Top);
  2040.       inc(Rect.Left);
  2041.     end;
  2042.  
  2043.     R := Rect;
  2044.  
  2045.     case TheColumn.Alignment of
  2046.       taRightJustify:
  2047.         Dec(R.Right, 4);
  2048.       taLeftJustify:
  2049.         Inc(R.Left, 4);
  2050.       // taCenter needs no modification
  2051.     end;
  2052.  
  2053.     if FShowSortArrows and (LastColumnClicked = Index) and
  2054.        (AutoColumnSort <> acsNoSort) then
  2055.     begin
  2056.       if CurrentSortAscending then
  2057.         Bmp := FSortUpBmp
  2058.       else
  2059.         Bmp := FSortDownBmp;
  2060.  
  2061.       if TheColumn.Alignment = taRightJustify then
  2062.         Inc(R.Left, Bmp.Width + 8)
  2063.       else
  2064.         Dec(R.Right, Bmp.Width + 8);
  2065.  
  2066.       { How big of a rectangle do we have to work with for the text? }
  2067.       CR := R;
  2068.       DrawTextEx(FCanvas.Handle, PChar(TheColumn.Caption), -1, CR,
  2069.          DRAWTEXTEX_FLAGS or DT_CALCRECT or
  2070.          DRAWTEXTEX_ALIGNMENT[TheColumn.Alignment], NIL);
  2071.       { Note that DT_CALCRECT does not adjust for alignment. We must do that }
  2072.       case TheColumn.Alignment of
  2073.         taRightJustify:
  2074.           R.Left := R.Right - (CR.Right - CR.Left);
  2075.         taCenter:
  2076.           begin
  2077.             R.Left := R.Left + (((R.Right - R.Left) - (CR.Right - CR.Left)) div
  2078.                2);
  2079.             R.Right := R.Left + (CR.Right - CR.Left);
  2080.           end;
  2081.       else // taLeftJustify: doesn't matter, that is what DT_CALCRECT returns
  2082.         R := CR;
  2083.       end;
  2084.       if R.Left < Rect.Left then
  2085.         R.Left := Rect.Left;
  2086.       if R.Right > Rect.Right then
  2087.         R.Right := Rect.Right;
  2088.  
  2089.       if Selected then
  2090.         OffsetRect(R, 1, 1);
  2091.       // Draw the caption in the rect available
  2092.       DrawTextEx(FCanvas.Handle, PChar(TheColumn.Caption), -1, R,
  2093.          DRAWTEXTEX_FLAGS or DRAWTEXTEX_ALIGNMENT[TheColumn.Alignment], NIL);
  2094.  
  2095.       // Draw the sort arrow bitmap
  2096.       Offset := (Rect.Bottom - Rect.Top - Bmp.Height) div 2;
  2097.       case TheColumn.Alignment of
  2098.         taRightJustify:
  2099.           // Only draw if we have enough room
  2100.           if (R.Left - Bmp.Width - 8) >= Rect.Left then
  2101.             Canvas.Draw(R.Left - Bmp.Width - 8, R.Top + Offset, Bmp);
  2102.       else // taLeftJustify, taCenter
  2103.         // Only draw if we have enough room
  2104.         if (R.Right + Bmp.Width + 8) <= Rect.Right then
  2105.           Canvas.Draw(R.Right + 8, R.Top + Offset, Bmp);
  2106.       end;
  2107.     end else begin
  2108.       if Selected then
  2109.         OffsetRect(R, 1, 1);
  2110.       DrawTextEx(FCanvas.Handle, PChar(TheColumn.Caption), -1, R,
  2111.          DRAWTEXTEX_FLAGS or DRAWTEXTEX_ALIGNMENT[TheColumn.Alignment], NIL);
  2112.     end;
  2113.   end;
  2114. end;
  2115.  
  2116. procedure TCustomEnhListView.SetOnDrawHeader(Value: TLVHDrawItemEvent);
  2117. begin
  2118.   FOnDrawHeader := Value;
  2119.   SetColumnsOwnerDrawFlag(assigned(FOnDrawHeader) or FShowSortArrows);
  2120. end;
  2121.  
  2122. procedure TCustomEnhListView.SetColumnsOwnerDrawFlag(OwnerDrawn: boolean);
  2123. var
  2124.   Item: THDItem;
  2125.   x: integer;
  2126. begin
  2127.   if not HandleAllocated then exit;
  2128.  
  2129.   for x := 0 to Columns.Count-1 do
  2130.   begin
  2131.     Item.Mask := HDI_FORMAT;
  2132.     if Header_GetItem(HeaderHandle, x, Item) then
  2133.     begin
  2134.       if OwnerDrawn then
  2135.         Item.Fmt := Item.Fmt or HDF_OWNERDRAW
  2136.       else
  2137.         Item.Fmt := Item.Fmt and not HDF_OWNERDRAW;
  2138.       Header_SetItem(HeaderHandle, x, Item);
  2139.     end;
  2140.   end;
  2141.  
  2142.   if OwnerDrawn then
  2143.   begin
  2144.     if (FCanvas = NIL) then
  2145.       FCanvas := TCanvas.Create;
  2146.   end else begin
  2147.     if (Style = lvStandard) and (FCanvas <> NIL) then
  2148.     begin
  2149.       FCanvas.Free;
  2150.       FCanvas := NIL;
  2151.     end;
  2152.   end;
  2153. end;
  2154.  
  2155. procedure TCustomEnhListView.SetLastColumnClicked(Value: integer);
  2156. var
  2157.   OldValue: integer;
  2158. begin
  2159.   if Value <> FLastColumnClicked then
  2160.   begin
  2161.     OldValue := FLastColumnClicked;
  2162.     FLastColumnClicked := Value;
  2163.     // If showing arrows and clicked column changes, we have to get rid of the
  2164.     // old sorting arrow by causing the header to be repainted.
  2165.     if FShowSortArrows then
  2166.       // Can't do this above because FLastColumnClicked is used to paint the
  2167.       // arrow
  2168.       InvalidateColumnHeader(OldValue);
  2169.   end;
  2170. end;
  2171.  
  2172. function TCustomEnhListView.ActualColumnIndex(Index: integer): integer;
  2173. begin
  2174.   Result := Index;
  2175. end;
  2176.  
  2177. procedure TCustomEnhListView.InvalidateColumnHeader(Index: integer);
  2178.   function RealColWidth(i: integer): integer;
  2179.   {$IFDEF DFS_COMPILER_4_UP}
  2180.   var
  2181.     Column: TLVColumn;
  2182.   {$ENDIF}
  2183.   begin
  2184.     {$IFDEF DFS_COMPILER_4_UP}
  2185.     Column.mask := LVCF_WIDTH;
  2186.     ListView_GetColumn(Handle, i, Column);
  2187.     Result := Column.cx;
  2188.     {$ELSE}
  2189.     Result := Columns[i].Width;
  2190.     {$ENDIF}
  2191.   end;
  2192. var
  2193.   R: TRect;
  2194.   x: integer;
  2195.   w: integer;
  2196. begin
  2197.   if (Index < 0) or (Index >= Columns.Count) or (HeaderHandle = 0) then
  2198.     exit;
  2199.  
  2200.   w := RealColWidth(Index);
  2201.   // We have to turn this into the actual column index if drag-drop headers have
  2202.   // re-arranged stuff in the TExtListView descendant component.
  2203.   Index := ActualColumnIndex(Index);
  2204.  
  2205.   Windows.GetClientRect(HeaderHandle, R);
  2206.   for x := 0 to Columns.Count - 1 do
  2207.     if ActualColumnIndex(x) < Index then
  2208.       inc(R.Left, RealColWidth(x));
  2209.   R.Right := R.Left + w;
  2210.  
  2211.   // Adjust for shadow
  2212.   InflateRect(R, -2, -2);
  2213.   InvalidateRect(HeaderHandle, @R, FALSE);
  2214. end;
  2215.  
  2216. procedure TCustomEnhListView.WMOwnerDrawColumns(var Message: TMessage);
  2217. begin
  2218.   SetColumnsOwnerDrawFlag(assigned(FOnDrawHeader) or FShowSortArrows);
  2219.   Update;
  2220. end;
  2221.  
  2222. function TCustomEnhListView.GetVersion: string;
  2223. begin
  2224.   Result := DFS_COMPONENT_VERSION;
  2225. end;
  2226.  
  2227. procedure TCustomEnhListView.SetVersion(const Val: string);
  2228. begin
  2229.   { empty write method, just needed to get it to show up in Object Inspector }
  2230. end;
  2231.  
  2232. procedure TCustomEnhListView.ResizeColumns(ResizeMethod: TResizeMethod);
  2233. var
  2234.   i: integer;
  2235. begin
  2236.   BeginUpdate;
  2237.   Columns.BeginUpdate;
  2238.   try
  2239.     for i := 0 to Columns.Count - 1 do
  2240.       if ResizeMethod = rmFitText then
  2241.         Columns[i].Width := -1
  2242.       else
  2243.         Columns[i].Width := -2;
  2244.   finally
  2245.     EndUpdate;
  2246.     Columns.EndUpdate;
  2247.   end;
  2248. end;
  2249.  
  2250.  
  2251. function TCustomEnhListView.GetCurrentColumnWidth(Index: integer): integer;
  2252. {$IFDEF DFS_COMPILER_4_UP}
  2253. var
  2254.   Column: TLVColumn;
  2255. {$ENDIF}
  2256. begin
  2257. {$IFDEF DFS_COMPILER_4_UP}
  2258.   if HandleAllocated then
  2259.   begin
  2260.     Column.mask := LVCF_WIDTH;
  2261.     ListView_GetColumn(Handle, ActualColumnIndex(Index), Column);
  2262.     Result := Column.cx;
  2263.   end else
  2264.     Result := ActualColumn[Index].Width;
  2265. {$ELSE}
  2266.   Result := ActualColumn[Index].Width;
  2267. {$ENDIF}
  2268. end;
  2269.  
  2270.  
  2271. {$IFDEF BACKGROUND_FIXED}
  2272. procedure TCustomEnhListView.SetBackgroundImage(
  2273.    const Value: TBitmap);
  2274. begin
  2275.   FBackgroundImage.Assign(Value);
  2276.   BackgroundImageChanged(Self);
  2277. end;
  2278. {$ENDIF}
  2279.  
  2280. {$IFDEF BACKGROUND_FIXED}
  2281. procedure TCustomEnhListView.BackgroundImageChanged(Sender: TObject);
  2282. begin
  2283.   Brush.Bitmap := NIL;
  2284.   if (FBackgroundImage <> NIL) and (not FBackgroundImage.Empty) then
  2285.   begin
  2286.     // Transparent text
  2287.     ListView_SetTextBkColor(Handle, $FFFFFFFF);
  2288.     Brush.Bitmap := FBackgroundImage;
  2289.   end else begin
  2290.     ListView_SetTextBkColor(Handle, ColorToRGB(Color));
  2291.     Brush.Color := Color;
  2292.   end;
  2293.   Invalidate;
  2294. end;
  2295. {$ENDIF}
  2296.  
  2297. function TCustomEnhListView.GetSmallImages:
  2298.    {$IFDEF DFS_COMPILER_4_UP} TCustomImageList {$ELSE} TImageList {$ENDIF};
  2299. begin
  2300.   Result := inherited SmallImages;
  2301. end;
  2302.  
  2303. procedure TCustomEnhListView.SetSmallImages(Val:
  2304.    {$IFDEF DFS_COMPILER_4_UP} TCustomImageList {$ELSE} TImageList {$ENDIF});
  2305. begin
  2306.   inherited SmallImages := Val;
  2307.  
  2308.   // If owner drawn, we have to recreate the window so that the WM_MEASUREITEM
  2309.   // will get sent to us again, and we can handle it to account for image list
  2310.   // size.
  2311.   if HandleAllocated and (Style = lvOwnerDrawFixed) and (not (csLoading in
  2312.     ComponentState)) then
  2313.     ResetOwnerDrawHeight;
  2314. end;
  2315.  
  2316. procedure TCustomEnhListView.HeaderWndProc(var Message: TMessage);
  2317.   function DisallowColumnResize: boolean;
  2318.   var
  2319.     HTI: THDHitTestInfo;
  2320.     pt: TPoint;
  2321.   begin
  2322.     Result := NoColumnResize;
  2323.     if (not Result) and (Self is TCustomExtListView) then
  2324.     begin
  2325.       // get cursor position
  2326.       GetCursorPos(pt);
  2327.       // convert to coordinates on header control of the listview
  2328.       Windows.ScreentoClient(HeaderHandle, pt);
  2329.       // fill in hittest structure
  2330.       HTI.flags := HHT_ONHEADER Or HHT_ONDIVIDER;
  2331.       HTI.point.x := pt.x;
  2332.       HTI.point.y := pt.y;
  2333.       //  get the header's hit-test info
  2334.       SendMessage(HeaderHandle, HDM_HITTEST, LongInt(0),LongInt(@HTI));
  2335.       if (HTI.Item >=0) and (HTI.Item <
  2336.         TdfsExtListView(Self).ColumnsFormat.Count) then
  2337.         Result := not TdfsExtListView(Self).ColumnsFormat[HTI.Item].AllowResize;
  2338.     end;
  2339.   end;
  2340. var
  2341.   HTI: THDHitTestInfo;
  2342.   Icon: HICON;
  2343. begin
  2344.   try
  2345.     with Message do
  2346.     begin
  2347.       case Msg of
  2348.         WM_SETCURSOR:
  2349.           begin
  2350.             if DisallowColumnResize then
  2351. //            if NoColumnResize then
  2352.             begin
  2353.               Icon := GetClassLong(FHeaderHandle, GCL_HICON);
  2354.               if Icon = 0 then
  2355.                 Icon := LoadCursor(0, IDC_ARROW);
  2356.               SetCursor(Icon);
  2357.               exit;
  2358.             end;
  2359.           end;
  2360.         WM_NCHITTEST:
  2361.           begin
  2362.             with TWMNCHitTest(Message) do
  2363.               if csDesigning in ComponentState then
  2364.               begin
  2365.                 Result := Windows.HTTRANSPARENT;
  2366.                 exit;
  2367.               end
  2368.               else if DisallowColumnResize then
  2369.               begin
  2370.                 HTI.Point := Point(LoWord(Message.LParam), HiWord(Message.LParam));
  2371.                 Windows.ScreenToClient(FHeaderHandle, HTI.Point);
  2372.                 SendMessage(FHeaderHandle, HDM_HITTEST, 0, integer(@HTI));
  2373.                 if ((HTI.Flags and HHT_ONHeader) = 0) then
  2374.                 begin
  2375.                   Result := Windows.HTNOWHERE;
  2376.                   exit;
  2377.                 end;
  2378.               end;
  2379.           end;
  2380.         WM_NCDESTROY:
  2381.           begin
  2382.             Result := CallWindowProc(FOldHeaderWndProc, FHeaderHandle, Msg, WParam, LParam);
  2383.             FHeaderHandle := 0;
  2384.             FOldHeaderWndProc := nil;
  2385.             Exit;
  2386.           end;
  2387.       end;
  2388.       Result := CallWindowProc(FOldHeaderWndProc, FHeaderHandle, Msg, WParam, LParam);
  2389.     end;
  2390.   except
  2391.     Application.HandleException(Self);
  2392.   end;
  2393. end;
  2394.  
  2395. procedure TCustomEnhListView.WMParentNotify(var Message: TWMParentNotify);
  2396. begin
  2397.   with Message do
  2398.     if (Event = WM_CREATE) and (FHeaderHandle = 0) then
  2399.     begin
  2400.       FHeaderHandle := ChildWnd;
  2401.       FOldHeaderWndProc := Pointer(GetWindowLong(FHeaderHandle, GWL_WNDPROC));
  2402.       SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FHeaderInstance));
  2403.     end;
  2404.   inherited;
  2405. end;
  2406.  
  2407. procedure TCustomEnhListView.KeyDown(var Key: Word; Shift: TShiftState);
  2408. begin
  2409.   inherited;
  2410.   // Ctrl + causes all columns to change size as if their dividers had been
  2411.   // double-clicked.  Can't have that.
  2412.   if NoColumnResize and (Key = VK_ADD) and (Shift = [ssCtrl]) then
  2413.     Key := VK_SUBTRACT;
  2414. end;
  2415.  
  2416. procedure TCustomEnhListView.ResetOwnerDrawHeight;
  2417. var
  2418.   r: TRect;
  2419.   wp: TWindowPos;
  2420. begin
  2421.   // Found this code on www.codeguru.com in an article talking about how to get
  2422.   // an owner draw listview to ask for the item height (WM_MEASUREITEM) again.  
  2423.     GetWindowRect(Handle, r);
  2424.     wp.hwnd := Handle;
  2425.     wp.cx := Width;
  2426.     wp.cy := Height;
  2427.     wp.flags := SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOZORDER;
  2428.     SendMessage(Handle, WM_WINDOWPOSCHANGED, 0, LPARAM(@wp));
  2429. end;
  2430.  
  2431. procedure TCustomEnhListView.MoveItem(OriginalIndex, NewIndex: Integer);
  2432. var
  2433.   Selected, Focused: boolean;
  2434.   ListItem:  TListItem;
  2435. begin
  2436.   if ((OriginalIndex < 0) or (OriginalIndex > Items.Count)) or
  2437.     ((NewIndex < 0) or (NewIndex > Items.Count)) then
  2438.     Exit;
  2439.     
  2440.   BeginUpdate;
  2441.   try
  2442.     Selected := Items[OriginalIndex].Selected;
  2443.     Focused := Items[OriginalIndex].Focused;
  2444.     if NewIndex < OriginalIndex then
  2445.       inc(OriginalIndex);
  2446.     if (NewIndex > OriginalIndex) then
  2447.       ListItem := Items.Insert(NewIndex + 1)
  2448.     else
  2449.       ListItem := Items.Insert(NewIndex);
  2450.     ListItem.Assign(Items[OriginalIndex]);
  2451.     Items.Delete(OriginalIndex);
  2452.     ListItem.Selected := Selected;
  2453.     ListItem.Focused := Focused;
  2454.   finally
  2455.     EndUpdate;
  2456.   end;
  2457. end;
  2458.  
  2459. procedure TCustomEnhListView.KeyUp(var Key: Word; Shift: TShiftState);
  2460. var
  2461.   PrevSearch: string;
  2462.   Ascii: array[0..1] of char;
  2463.   KBState: TKeyboardState;
  2464. begin
  2465.   inherited;
  2466.   if ColumnSearch then
  2467.   begin
  2468.     GetKeyboardState(KBState);
  2469.     if (ToAscii(Key, 0, KBState, Ascii, 0) = 1) and (Ascii[0] in [#32..#127]) then
  2470.     begin
  2471.       PrevSearch := FSearchStr;                      // remember searchstring
  2472.       if GetTickCount > FSearchTickCount + 1000 then // last search over one second ago?
  2473.         PrevSearch := '';                            // reset searchstring
  2474.       FSearchStr := PrevSearch + Ascii[0];           // Append searchstring
  2475.       FSearchTickCount := GetTickCount;              // remember last search time
  2476.       Key := 0;                                      // prevent automatic search on first column
  2477.       if not StringSelect(FSearchStr, LastColumnClicked) then
  2478.       begin
  2479.         MessageBeep(MB_ICONSTOP);
  2480.         FSearchStr := PrevSearch;
  2481.       end;
  2482.     end;
  2483.   end;
  2484. end;
  2485.  
  2486. function TCustomEnhListView.StringSelect(FindStr: string; ColumnIndex: Integer): boolean;
  2487. var
  2488.   SearchLen,
  2489.   SearchIndex,
  2490.   SearchStart: Integer;
  2491. begin
  2492.   Result := FALSE;
  2493.   SearchLen := Length(FindStr);
  2494.   if Assigned(Selected) then   // determine starting item
  2495.     SearchStart := Selected.Index + 1
  2496.   else
  2497.     SearchStart := 1;
  2498.  
  2499.   // Searches from currently selected item to last item
  2500.   // and from first item to currently selected item until result(found)
  2501.  
  2502.   SearchIndex := 0;
  2503.   while (SearchIndex < Items.Count) and not Result do
  2504.   begin
  2505.     if ColumnIndex = 0 then                                // find main or subitem?
  2506.       Result := AnsiCompareText(Copy(Items[(SearchStart + SearchIndex) mod
  2507.         Items.Count].Caption, 0, SearchLen), FindStr) = 0
  2508.     else
  2509.       Result := AnsiCompareText(Copy(Items[(SearchStart + SearchIndex) mod
  2510.         Items.Count].SubItems[ColumnIndex - 1], 0, SearchLen), FindStr) = 0;
  2511.     Inc(SearchIndex);
  2512.   end;
  2513.   if Result then
  2514.   begin
  2515.     Selected := Items[(SearchStart + SearchIndex - 1) mod Items.Count];
  2516.     ItemFocused := Selected;
  2517.   end;
  2518. end;
  2519.  
  2520. function TCustomEnhListView.SubStringSelect(FindStr: string;
  2521.   ColumnIndex: Integer): boolean;
  2522. var
  2523.   SearchIndex,
  2524.   SearchStart: Integer;
  2525. begin
  2526.   Result := FALSE;
  2527.   if Assigned(Selected) then  // determine starting item
  2528.     SearchStart := Selected.Index + 1
  2529.   else
  2530.     SearchStart := 1;
  2531.  
  2532.   // Searches from currently selected item to last item
  2533.   // and from first item to currently selected item until result(found)
  2534.  
  2535.   SearchIndex := 0;
  2536.   while (SearchIndex < Items.Count) and not Result do
  2537.   begin
  2538.     if ColumnIndex = 0 then                                // find main or subitem?
  2539.       Result := Pos(FindStr, Items[(SearchStart + SearchIndex) mod
  2540.         Items.Count].Caption) > 0
  2541.     else
  2542.       Result := Pos(FindStr, Items[(SearchStart + SearchIndex) mod
  2543.         Items.Count].SubItems[ColumnIndex - 1]) > 0;
  2544.     Inc(SearchIndex);
  2545.   end;
  2546.   if Result then
  2547.   begin
  2548.     Selected := Items[(SearchStart + SearchIndex - 1) mod Items.Count];
  2549.     ItemFocused := Selected;
  2550.   end;
  2551. end;
  2552.  
  2553. {$IFNDEF DFS_COMPILER_4_UP}
  2554. procedure TCustomEnhListView.GetImageIndex(Item: TListItem);
  2555. begin
  2556.   if Assigned(FOnGetImageIndex) then
  2557.     FOnGetImageIndex(Self, Item);
  2558. end;
  2559. {$ENDIF}
  2560.  
  2561. procedure TCustomEnhListView.Notification(AComponent: TComponent; Operation: TOperation);
  2562. begin
  2563.   if (Operation = opRemove) and (AComponent = SmallImages) then
  2564.     SmallImages := NIL;
  2565.   inherited Notification(AComponent, Operation);
  2566. end;
  2567.  
  2568. initialization
  2569.   DefDraw_TextOffset := 4;
  2570.   DefDraw_ImageOffset := 2;
  2571. end.
  2572.  
  2573.