LCL/ListView: implement incremental search in virtual mode for Windows. Issue #39748.

This commit is contained in:
wp_xyz 2022-05-13 11:06:11 +02:00
parent 78ff1c894f
commit 0883c8c524
3 changed files with 67 additions and 11 deletions

View File

@ -1545,6 +1545,9 @@ type
function DoOwnerDataHint(AStartIndex, AEndIndex: Integer): Boolean; virtual;
function DoOwnerDataStateChange(AStartIndex, AEndIndex: Integer; AOldState,
ANewState: TListItemStates): Boolean; virtual;
function DoOwnerDataFind(AFind: TItemFind; const AFindString: string;
const AFindPosition: TPoint; AFindData: Pointer; AStartIndex: Integer;
ADirection: TSearchDirection; AWrap: Boolean): Integer; virtual;
protected
// Multiselection

View File

@ -294,7 +294,7 @@ begin
end;
// LVN_GETDISPINFO:
// LVN_ODCACHEHINT:
// LVN_ODFINDITEM:
// LVN_ODFINDITEM: implemented in win32 widgetset
// LVN_ODSTATECHANGED:
// LVN_BEGINLABELEDIT: implemented via TCustomListViewEditor
// LVN_ENDLABELEDIT: implemented via TCustomListViewEditor
@ -883,6 +883,16 @@ begin
FOnDataStateChange(Self, AStartIndex, AEndIndex, AOldState, ANewState);
end;
function TCustomListView.DoOwnerDataFind(AFind: TItemFind; const AFindString: string;
const AFindPosition: TPoint; AFindData: Pointer; AStartIndex: Integer;
ADirection: TSearchDirection; AWrap: Boolean): Integer;
begin
Result := -1;
if Assigned(FOnDataFind) then
FOnDataFind(Self, AFind, AFindString, AFindPosition, AFindData, AStartIndex,
ADirection, AWrap, Result);
end;
procedure TCustomListView.QueuedShowEditor(Data: PtrInt);
begin
if fShowEditorQueued and IsVisible then

View File

@ -232,22 +232,65 @@ var
MsgResult := MsgResult or CDRFRESULT[ResultFlag];
end;
end;
{ Workaround for issue #39715 to prevent the selection jumping to the first
item in virtual mode when a normal key is pressed (the listview probably
tries to perform an incremental search in this case which has not been
implemented, yet (handler for OnDataFind). }
{ Implements incremental search for TCustomListView in virtual mode.
See:
- https://docs.microsoft.com/de-DE/windows/win32/api/commctrl/ns-commctrl-nmlvfinditema
- https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-lvfindinfoa }
procedure HandleListViewFindItem(ALV: TCustomlistViewAccess);
var
FindInfo: PNMLVFindItem;
listitem: TListItem;
findItem: PNMLVFindItem;
itemFind: TItemFind;
findStr: String = '';
findStrLen: Integer = 0;
findData: Pointer = nil;
findPt: TPoint = (X: 0; Y: 0);
findDir: TSearchDirection = sdAll;
findStart: Integer;
findWrap: Boolean;
begin
if ALV.OwnerData then
begin
FindInfo := PNMLVFindItem(NMHdr);
if Assigned(FindInfo) then
findItem := PNMLVFindItem(NMHdr);
if Assigned(findItem) then
begin
MsgResult := -1;
if findItem^.lvfi.flags and LVFI_PARAM <> 0 then
itemFind := ifData
else if findItem^.lvfi.flags and LVFI_PARTIAL <> 0 then
itemFind := ifPartialString
else if findItem^.lvfi.flags and LVFI_STRING <> 0 then
itemFind := ifExactString
else if findItem^.lvfi.flags and LVFI_NEARESTXY <> 0 then
itemFind := ifNearest
else
itemFind := ifData;
case itemFind of
ifPartialString, ifExactString:
begin
findStrLen := SendMessage(ALV.Handle, LVM_GETISEARCHSTRING, 0, 0);
if findStrLen > 0 then
begin
SetLength(findStr, findStrLen);
ListView_GetISearchString(ALV.Handle, PChar(findStr));
end;
end;
ifData:
findData := Pointer(PtrUInt(findItem^.lvfi.lParam));
ifNearest:
begin
findPt := findItem^.lvfi.pt;
case findItem^.lvfi.vkDirection of
VK_LEFT: findDir := sdLeft;
VK_UP: findDir := sdAbove;
VK_RIGHT: findDir := sdRight;
VK_DOWN: findDir := sdBelow;
end;
end;
end;
findstart := findItem^.iStart;
findWrap := findItem^.lvfi.flags and LVFI_WRAP <> 0;
MsgResult := ALV.DoOwnerDataFind(itemFind, findStr, findPt, findData, findStart, findDir, findWrap);
WinProcess := false;
end;
end;