| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 | 
							- unit NortonLikeListView;
 
- interface
 
- uses
 
-   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 
-   ComCtrls, ListViewColProperties, CommCtrl, Menus;
 
- type
 
-   TCustomNortonLikeListView = class;
 
-   TSelectMode = (smAll, smNone, smInvert);
 
-   TNortonLikeMode = (nlOn, nlOff, nlKeyboard);
 
-   TSelectMethod = (smNoneYet, smMouse, smKeyboard);
 
-   TCustomNortonLikeListView = class(TCustomListView)
 
-   private
 
-     { Private declarations }
 
-     FColProperties: TCustomListViewColProperties;
 
-     FDontSelectItem: Boolean;
 
-     FDontUnSelectItem: Boolean;
 
-     FSelCount: Integer;
 
-     FNortonLike: TNortonLikeMode;
 
-     FLastDeletedItem: TListItem; // aby sme nepocitali smazany item 2x
 
-     FFocusingItem: Boolean;
 
-     FManageSelection: Boolean;
 
-     FForceUpdateOnItemUnfocus: Boolean;
 
-     FFirstSelected: Integer;
 
-     FLastSelected: Integer;
 
-     FFocused: TDateTime;
 
-     FIgnoreSetFocusFrom: THandle;
 
-     FSelectingImplicitly: Boolean;
 
-     FAnyAndAllSelectedImplicitly: Boolean;
 
-     FLButtonDownShiftState: TShiftState;
 
-     FLButtonDownPos: TPoint;
 
-     FLastSelectMethod: TSelectMethod;
 
-     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
 
-     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
 
-     procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
 
-     procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
 
-     procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
 
-     procedure WMChar(var Message: TWMChar); message WM_CHAR;
 
-     procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
 
-     procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
 
-     procedure LVMEditLabel(var Message: TMessage); message LVM_EDITLABEL;
 
-     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
 
-     procedure CMWantSpecialKey(var Message: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
 
-     function GetMarkedCount: Integer;
 
-     function GetMarkedFile: TListItem;
 
-     procedure ItemSelected(Item: TListItem; Index: Integer);
 
-     procedure ItemUnselected(Item: TListItem; Index: Integer);
 
-     procedure SelectAll(Mode: TSelectMode; Exclude: TListItem); reintroduce; overload;
 
-   protected
 
-     { Protected declarations }
 
-     FClearingItems: Boolean;
 
-     FUpdatingSelection: Integer;
 
-     FNextCharToIgnore: Word;
 
-     FHeaderHandle: HWND;
 
-     procedure CreateWnd; override;
 
-     procedure DestroyWnd; override;
 
-     procedure BeginSelectionUpdate; virtual;
 
-     procedure EndSelectionUpdate; virtual;
 
-     function CanChangeSelection(Item: TListItem; Select: Boolean): Boolean; virtual;
 
-     procedure ClearItems; virtual;
 
-     procedure ItemsReordered;
 
-     procedure Delete(Item: TListItem); override;
 
-     function ExCanChange(Item: TListItem; Change: Integer;
 
-       NewState, OldState: Word): Boolean; dynamic;
 
-     procedure InsertItem(Item: TListItem); override;
 
-     function NewColProperties: TCustomListViewColProperties; virtual; abstract;
 
-     procedure FocusSomething; virtual;
 
-     function EnableDragOnClick: Boolean; virtual;
 
-     function GetItemFromHItem(const Item: TLVItem): TListItem;
 
-     function GetValid: Boolean; virtual;
 
-     function GetSelCount: Integer; override;
 
-     procedure DDBeforeDrag;
 
-     function CanEdit(Item: TListItem): Boolean; override;
 
-     function GetPopupMenu: TPopupMenu; override;
 
-     procedure ChangeScale(M, D: Integer); override;
 
-   public
 
-     { Public declarations }
 
-     constructor Create(AOwner: TComponent); override;
 
-     destructor Destroy; override;
 
-     function ClosestUnselected(Item: TListItem): TListItem;
 
-     procedure SelectAll(Mode: TSelectMode); reintroduce; overload;
 
-     procedure SelectCurrentItem(FocusNext: Boolean);
 
-     function GetNextItem(StartItem: TListItem; Direction: TSearchDirection;
 
-       States: TItemStates): TListItem;
 
-     procedure MakeProgressVisible(Item: TListItem);
 
-     procedure FocusItem(Item: TListItem);
 
-     property ColProperties: TCustomListViewColProperties read FColProperties write FColProperties stored False;
 
-     property MultiSelect default True;
 
-     property NortonLike: TNortonLikeMode read FNortonLike write FNortonLike default nlOn;
 
-     property MarkedCount: Integer read GetMarkedCount;
 
-     property MarkedFile: TListItem read GetMarkedFile;
 
-     property Valid: Boolean read GetValid;
 
-     property LastSelectMethod: TSelectMethod read FLastSelectMethod;
 
-   end;
 
- implementation
 
- uses
 
-   PasTools, Types;
 
-   { TCustomNortonLikeListView }
 
- constructor TCustomNortonLikeListView.Create(AOwner: TComponent);
 
- begin
 
-   inherited Create(AOwner);
 
-   FSelCount := 0;
 
-   FFirstSelected := -1;
 
-   FLastSelected := -1;
 
-   FClearingItems := False;
 
-   MultiSelect := True;
 
-   FDontSelectItem := False;
 
-   FDontUnSelectItem := False;
 
-   FNortonLike := nlOn;
 
-   FColProperties := NewColProperties;
 
-   FLastDeletedItem := nil;
 
-   FUpdatingSelection := 0;
 
-   FFocusingItem := False;
 
-   FLastSelectMethod := smNoneYet;
 
-   // On Windows Vista, native GetNextItem for selection stops working once we
 
-   // disallow deselecting any item (see ExCanChange).
 
-   // So we need to manage selection state ourselves
 
-   // cannot use Win32MajorVersion as it is affected by compatibility mode and
 
-   // the bug is present even in compatibility mode
 
-   FManageSelection := IsVistaHard;
 
-   FFocused := 0;
 
-   FIgnoreSetFocusFrom := INVALID_HANDLE_VALUE;
 
-   // On Windows 7 we have to force item update when it looses focus,
 
-   // otherwise some remnants of focus rectangle remain
 
-   // Doing the same on WinXP makes list view down from the item flicker,
 
-   // so we avoid this there.
 
-   // Not sure about Vista
 
-   FForceUpdateOnItemUnfocus := IsWin7;
 
-   FNextCharToIgnore := 0;
 
- end;
 
- destructor TCustomNortonLikeListView.Destroy;
 
- begin
 
-   FColProperties.Free;
 
-   inherited;
 
- end;
 
- procedure TCustomNortonLikeListView.ItemSelected(Item: TListItem; Index: Integer);
 
- begin
 
-   Inc(FSelCount);
 
-   if FSelectingImplicitly and (FSelCount = 1) then
 
-   begin
 
-     FAnyAndAllSelectedImplicitly := True;
 
-   end
 
-     else
 
-   if not FSelectingImplicitly then
 
-   begin
 
-     FAnyAndAllSelectedImplicitly := False;
 
-   end;
 
-   if FManageSelection then
 
-   begin
 
-     if Index < 0 then
 
-       Index := Item.Index;
 
-     if FSelCount = 1 then
 
-     begin
 
-       Assert(FFirstSelected < 0);
 
-       FFirstSelected := Index;
 
-       Assert(FLastSelected < 0);
 
-       FLastSelected := Index;
 
-     end
 
-       else
 
-     begin
 
-       // if reference is not assigned, do not assign it as we
 
-       // cannot be sure that the item is actually first/last
 
-       if (FFirstSelected >= 0) and (Index < FFirstSelected) then
 
-         FFirstSelected := Index;
 
-       if (FLastSelected >= 0) and (Index > FLastSelected) then
 
-         FLastSelected := Index;
 
-     end;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.ItemUnselected(Item: TListItem; Index: Integer);
 
- begin
 
-   Dec(FSelCount);
 
-   if (FSelCount = 0) or (not FSelectingImplicitly) then
 
-   begin
 
-     FAnyAndAllSelectedImplicitly := False;
 
-   end;
 
-   if FManageSelection then
 
-   begin
 
-     if Index < 0 then
 
-       Index := Item.Index;
 
-     if FFirstSelected = Index then
 
-     begin
 
-       if FSelCount = 1 then
 
-         FFirstSelected := FLastSelected // may be -1
 
-       else
 
-         FFirstSelected := -1;
 
-     end;
 
-     if FLastSelected = Index then
 
-     begin
 
-       if FSelCount = 1 then
 
-         FLastSelected := FFirstSelected // may be -1
 
-       else
 
-         FLastSelected := -1;
 
-     end;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.Delete(Item: TListItem);
 
- var
 
-   Index: Integer;
 
- begin
 
-   if (FLastDeletedItem <> Item) and (not FClearingItems) then
 
-   begin
 
-     Index := Item.Index;
 
-     if Item.Selected then
 
-       ItemUnselected(Item, Index);
 
-     if FManageSelection then
 
-     begin
 
-       if (FLastSelected >= 0) and (Index <= FLastSelected) then
 
-         Dec(FLastSelected);
 
-       if (FFirstSelected >= 0) and (Index <= FFirstSelected) then
 
-         Dec(FFirstSelected);
 
-     end;
 
-   end;
 
-   FLastDeletedItem := Item;
 
-   inherited;
 
-   FLastDeletedItem := nil;
 
- end;
 
- function TCustomNortonLikeListView.ExCanChange(Item: TListItem; Change: Integer;
 
-   NewState, OldState: Word): Boolean;
 
- begin
 
-   Assert(Assigned(Item));
 
-   Result := True;
 
-   if (Change = LVIF_STATE) and
 
-      ((((OldState and LVIS_SELECTED) < (NewState and LVIS_SELECTED)) and
 
-        (FDontSelectItem or (not CanChangeSelection(Item, True)))) or
 
-       (((OldState and LVIS_SELECTED) > (NewState and LVIS_SELECTED)) and
 
-        (FDontUnSelectItem or (not CanChangeSelection(Item, False))))) then
 
-   begin
 
-     if (OldState or LVIS_SELECTED) <> (NewState or LVIS_SELECTED) then
 
-     begin
 
-       ListView_SetItemState(Handle, Item.Index, NewState,
 
-         (NewState or OldState) - LVIS_SELECTED);
 
-     end;
 
-     Result := False;
 
-   end;
 
- end;
 
- function TCustomNortonLikeListView.CanChangeSelection(Item: TListItem;
 
-   Select: Boolean): Boolean;
 
- begin
 
-   Result := True;
 
- end;
 
- procedure TCustomNortonLikeListView.ClearItems;
 
- begin
 
-   Items.BeginUpdate;
 
-   try
 
-     FClearingItems := True;
 
-     Items.Clear;
 
-   finally
 
-     FSelCount := 0;
 
-     if FManageSelection then
 
-     begin
 
-       FFirstSelected := -1;
 
-       FLastSelected := -1;
 
-     end;
 
-     FClearingItems := False;
 
-     Items.EndUpdate;
 
-   end;
 
- end; { ClearItems }
 
- procedure TCustomNortonLikeListView.ItemsReordered;
 
- begin
 
-   if FManageSelection then
 
-   begin
 
-     FFirstSelected := -1;
 
-     FLastSelected := -1;
 
-   end;
 
- end;
 
- function TCustomNortonLikeListView.ClosestUnselected(Item: TListItem): TListItem;
 
- var
 
-   Index: Integer;
 
- begin
 
-   if Assigned(Item) and (Item.Selected or ((NortonLike <> nlOff) and (SelCount = 0))) then
 
-   begin
 
-     Index := Item.Index + 1;
 
-     while (Index < Items.Count) and Items[Index].Selected do Inc(Index);
 
-     if (Index >= Items.Count) or Items[Index].Selected then
 
-     begin
 
-       Index := Item.Index - 1;
 
-       while (Index >= 0) and Items[Index].Selected do Dec(Index);
 
-     end;
 
-     if (Index >= 0) and (Index < Items.Count) and (not Items[Index].Selected) then
 
-       Result := Items[Index]
 
-     else
 
-       Result := nil;
 
-   end
 
-     else Result := Item;
 
- end;
 
- function TCustomNortonLikeListView.GetPopupMenu: TPopupMenu;
 
- begin
 
-   // While editing pretend that we do not have a popup menu.
 
-   // Otherwise Ctrl+V is swallowed by the TWinControl.CNKeyDown,
 
-   // when it finds out (TWinControl.IsMenuKey) that there's a command with Ctrl+V shortcut in the list view context menu
 
-   // (the "paste" file action)
 
-   if IsEditing then
 
-   begin
 
-     Result := nil;
 
-   end
 
-     else
 
-   begin
 
-     Result := inherited;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.WMNotify(var Message: TWMNotify);
 
- var
 
-   HDNotify: PHDNotify;
 
- begin
 
-   if (FHeaderHandle <> 0) and (Message.NMHdr^.hWndFrom = FHeaderHandle) then
 
-   begin
 
-     HDNotify := PHDNotify(Message.NMHdr);
 
-     // Disallow resizing of "invisible" (width=0) columns.
 
-     // (We probably get only Unicode versions of the messages here as
 
-     // controls are created as Unicode by VCL)
 
-     case HDNotify.Hdr.code of
 
-       HDN_BEGINTRACKA, HDN_TRACKA, HDN_BEGINTRACKW, HDN_TRACKW:
 
-         if not ColProperties.Visible[HDNotify.Item] then
 
-         begin
 
-           Message.Result := 1;
 
-           Exit;
 
-         end;
 
-       // We won't get here when user tries to resize the column by mouse,
 
-       // as that's prevented above.
 
-       // But we get here when other methods are used
 
-       // (the only we know about atm is Ctrl-+ shortcut)
 
-       // We are getting this notification also when control is being setup,
 
-       // with mask including also other fields, not just HDI_WIDTH.
 
-       // While it does not seem to hurt to swallow even those messages,
 
-       // not sure it's good thing to do, so we swallow width-only messages only.
 
-       // That's why there's "= HDI_WIDTH" not "and HDI_WIDTH <> 0".
 
-       HDN_ITEMCHANGINGA, HDN_ITEMCHANGINGW:
 
-         if (HDNotify.PItem.Mask = HDI_WIDTH) and
 
-            (HDNotify.PItem.cxy <> 0) and
 
-            (not ColProperties.Visible[HDNotify.Item]) then
 
-         begin
 
-           Message.Result := 1;
 
-           Exit;
 
-         end;
 
-     end;
 
-   end;
 
-   inherited;
 
- end;
 
- procedure TCustomNortonLikeListView.DDBeforeDrag;
 
- begin
 
-   FDontSelectItem := False;
 
-   FDontUnSelectItem := False;
 
- end;
 
- procedure TCustomNortonLikeListView.CNNotify(var Message: TWMNotify);
 
- var
 
-   Item: TListItem;
 
- begin
 
-   with Message do
 
-     case NMHdr^.code of
 
-       LVN_ITEMCHANGING:
 
-         with PNMListView(NMHdr)^ do
 
-         begin
 
-           Item := Items[iItem];
 
-           if Valid and (not FClearingItems) and (Item <> FLastDeletedItem) and
 
-              ((not CanChange(Item, uChanged)) or
 
-               (not ExCanChange(Item, uChanged, uNewState, uOldState)))
 
-               then
 
-           begin
 
-             Result := 1;
 
-           end;
 
-         end;
 
-       LVN_ITEMCHANGED:
 
-         begin
 
-           with PNMListView(NMHdr)^ do
 
-           begin
 
-             Item := Items[iItem];
 
-             if Valid and (not FClearingItems) and
 
-                (uChanged = LVIF_STATE) and (Item <> FLastDeletedItem) then
 
-             begin
 
-               if FForceUpdateOnItemUnfocus and
 
-                  (NortonLike <> nlOff) and
 
-                  ((uOldState and LVIS_FOCUSED) > (uNewState and LVIS_FOCUSED)) then
 
-               begin
 
-                 // force update, otherwise some remnants of focus rectangle remain
 
-                 Item.Update;
 
-               end;
 
-               if (uOldState and LVIS_SELECTED) <> (uNewState and LVIS_SELECTED) then
 
-               begin
 
-                 if (uOldState and LVIS_SELECTED) <> 0 then
 
-                 begin
 
-                   ItemUnselected(Item, iItem);
 
-                 end
 
-                   else
 
-                 begin
 
-                   ItemSelected(Item, iItem);
 
-                 end;
 
-               end;
 
-             end;
 
-           end;
 
-           inherited;
 
-         end;
 
-       LVN_ENDLABELEDIT:
 
-         begin
 
-           FIgnoreSetFocusFrom := ListView_GetEditControl(Handle);
 
-           inherited;
 
-         end;
 
-       else
 
-         begin
 
-           inherited;
 
-         end;
 
-     end;
 
- end;
 
- procedure TCustomNortonLikeListView.SelectCurrentItem(FocusNext: Boolean);
 
- var
 
-   Item: TListItem;
 
- begin
 
-   Item := ItemFocused;
 
-   if Item = nil then Item := Items[0];
 
-   Item.Selected := not Item.Selected;
 
-   if FocusNext then
 
-   begin
 
-     SendMessage(Handle, WM_KEYDOWN, VK_DOWN, LongInt(0));
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.WMKeyDown(var Message: TWMKeyDown);
 
- var
 
-   PLastSelectMethod: TSelectMethod;
 
-   PDontUnSelectItem: Boolean;
 
-   PDontSelectItem: Boolean;
 
- begin
 
-   FNextCharToIgnore := 0;
 
-   if (NortonLike <> nlOff) and (Message.CharCode = VK_INSERT) then
 
-   begin
 
-     if Items.Count > 0 then
 
-     begin
 
-       PLastSelectMethod := FLastSelectMethod;
 
-       FLastSelectMethod := smKeyboard;
 
-       try
 
-         SelectCurrentItem(True);
 
-       finally
 
-         FLastSelectMethod := PLastSelectMethod;
 
-       end;
 
-       Message.Result := 1;
 
-     end;
 
-   end
 
-     else
 
-   if Message.CharCode = VK_ADD then
 
-   begin
 
-     FNextCharToIgnore := Word('+');
 
-     inherited;
 
-   end
 
-     else
 
-   if Message.CharCode = VK_SUBTRACT then
 
-   begin
 
-     FNextCharToIgnore := Word('-');
 
-     inherited;
 
-   end
 
-     else
 
-   if Message.CharCode = VK_MULTIPLY then
 
-   begin
 
-     FNextCharToIgnore := Word('*');
 
-     inherited;
 
-   end
 
-     else
 
-   if (NortonLike <> nlOff) and (Message.CharCode in [VK_LEFT, VK_RIGHT]) and
 
-      (ViewStyle = vsReport) and
 
-      ((GetWindowLong(Handle, GWL_STYLE) and WS_HSCROLL) = 0) then
 
-   begin
 
-     if Items.Count > 0 then
 
-     begin
 
-       // do not focus item directly to make later selecting work
 
-       if Message.CharCode = VK_LEFT then
 
-         SendMessage(Handle, WM_KEYDOWN, VK_HOME, LongInt(0))
 
-       else
 
-         SendMessage(Handle, WM_KEYDOWN, VK_END, LongInt(0));
 
-     end;
 
-     Message.Result := 1;
 
-   end
 
-     else
 
-   if (NortonLike <> nlOff) and (Message.CharCode = VK_SPACE) and
 
-      ((KeyDataToShiftState(Message.KeyData) * [ssCtrl]) <> []) then
 
-   begin
 
-     // prevent Ctrl+Space landing in else branch below,
 
-     // this can safely get processed by default handler as Ctrl+Space
 
-     // toggles only focused item, not affecting others
 
-     PLastSelectMethod := FLastSelectMethod;
 
-     FLastSelectMethod := smKeyboard;
 
-     try
 
-       inherited;
 
-     finally
 
-       FLastSelectMethod := PLastSelectMethod;
 
-     end;
 
-   end
 
-     else
 
-   if (Message.CharCode in [VK_SPACE, VK_PRIOR, VK_NEXT, VK_END, VK_HOME, VK_LEFT,
 
-     VK_UP, VK_RIGHT, VK_DOWN, VK_SELECT]) then
 
-   begin
 
-     PLastSelectMethod := FLastSelectMethod;
 
-     PDontSelectItem := FDontSelectItem;
 
-     PDontUnSelectItem := FDontUnSelectItem;
 
-     FLastSelectMethod := smKeyboard;
 
-     FDontSelectItem := FDontSelectItem or
 
-       ((NortonLike <> nlOff) and
 
-        ((KeyDataToShiftState(Message.KeyData) * [ssShift]) = []));
 
-     // Note that Space (selecting toggling) is processed by default handler for WM_CHAR,
 
-     // otherwise the below condition would prevent unselection
 
-     FDontUnSelectItem :=
 
-       FDontUnSelectItem or
 
-       (NortonLike = nlOn) or
 
-       ((NortonLike = nlKeyboard) and (not FAnyAndAllSelectedImplicitly));
 
-     try
 
-       inherited;
 
-     finally
 
-       FDontSelectItem := PDontSelectItem;
 
-       FDontUnSelectItem := PDontUnSelectItem;
 
-       FLastSelectMethod := PLastSelectMethod;
 
-     end;
 
-   end
 
-     else inherited;
 
- end;
 
- procedure TCustomNortonLikeListView.WMSysCommand(var Message: TWMSysCommand);
 
- begin
 
-   // Ugly workaround to avoid Windows beeping when Alt+Grey +/- are pressed
 
-   // (for (Us)Select File with Same Ext commands)
 
-   // The same for Alt+Enter (for Properties)
 
-   if (Message.CmdType = SC_KEYMENU) and
 
-      ((Message.Key = Word('+')) or (Message.Key = Word('-')) or (Message.Key = VK_RETURN)) then
 
-   begin
 
-     Message.Result := 1;
 
-   end
 
-     else inherited;
 
- end;
 
- procedure TCustomNortonLikeListView.WMChar(var Message: TWMChar);
 
- var
 
-   PLastSelectMethod: TSelectMethod;
 
-   PDontUnSelectItem: Boolean;
 
-   PDontSelectItem: Boolean;
 
- begin
 
-   if Message.CharCode = FNextCharToIgnore then
 
-   begin
 
-     // ugly fix to avoid Windows beeping when these keys are processed by
 
-     // WMKeyDown instead of here (WMChar)
 
-     Message.Result := 1;
 
-   end
 
-     else
 
-   if (NortonLike <> nlOff) and (Message.CharCode = Byte(' ')) then
 
-   begin
 
-     if (GetKeyState(VK_CONTROL) >= 0) then
 
-     begin
 
-       // If not handled in TCustomScpExplorerForm::DirViewKeyPress
 
-       if not DoKeyPress(Message) then
 
-       begin
 
-         if Assigned(ItemFocused) then
 
-           ItemFocused.Selected := not ItemFocused.Selected;
 
-       end;
 
-     end
 
-       else inherited;
 
-   end
 
-     else
 
-   begin
 
-     PLastSelectMethod := FLastSelectMethod;
 
-     PDontSelectItem := FDontSelectItem;
 
-     PDontUnSelectItem := FDontUnSelectItem;
 
-     FDontSelectItem := FDontSelectItem or (NortonLike <> nlOff);
 
-     FLastSelectMethod := smKeyboard;
 
-     FDontUnSelectItem :=
 
-       FDontUnSelectItem or
 
-       (NortonLike = nlOn) or
 
-       ((NortonLike = nlKeyboard) and (not FAnyAndAllSelectedImplicitly));
 
-     try
 
-       inherited;
 
-     finally
 
-       FLastSelectMethod := PLastSelectMethod;
 
-       FDontSelectItem := PDontSelectItem;
 
-       FDontUnSelectItem := PDontUnSelectItem;
 
-     end;
 
-   end;
 
-   FNextCharToIgnore := 0;
 
- end;
 
- procedure TCustomNortonLikeListView.FocusSomething;
 
- begin
 
-   if Valid and (Items.Count > 0) and not Assigned(ItemFocused) then
 
-   begin
 
-     if (NortonLike <> nlOff) then
 
-     begin
 
-       SendMessage(Handle, WM_KEYDOWN, VK_DOWN, LongInt(0));
 
-     end;
 
-     if not Assigned(ItemFocused) then
 
-     begin
 
-       ItemFocused := Items[0];
 
-     end;
 
-   end;
 
-   if Assigned(ItemFocused) then
 
-   begin
 
-     ItemFocused.MakeVisible(False);
 
-   end;
 
- end;
 
- function TCustomNortonLikeListView.EnableDragOnClick: Boolean;
 
- begin
 
-   Result := (not FFocusingItem);
 
- end;
 
- procedure TCustomNortonLikeListView.FocusItem(Item: TListItem);
 
- var
 
-   P: TPoint;
 
-   PLastSelectMethod: TSelectMethod;
 
-   PDontUnSelectItem: Boolean;
 
-   PDontSelectItem: Boolean;
 
-   WParam: UINT_PTR;
 
-   LParam: INT_PTR;
 
- begin
 
-   // This whole is replacement for mere ItemFocused := Item
 
-   // because that does not reset some internal focused pointer,
 
-   // causing subsequent Shift-Click selects range from the first item,
 
-   // not from focused item.
 
-   Item.MakeVisible(False);
 
-   Assert(Focused);
 
-   if Focused then
 
-   begin
 
-     P := Item.GetPosition;
 
-     PLastSelectMethod := FLastSelectMethod;
 
-     PDontSelectItem := FDontSelectItem;
 
-     PDontUnSelectItem := FDontUnSelectItem;
 
-     FLastSelectMethod := smNoneYet;
 
-     FDontSelectItem := True;
 
-     FDontUnSelectItem := True;
 
-     FFocusingItem := True;
 
-     try
 
-       // HACK
 
-       // WM_LBUTTONDOWN enters loop, waiting for WM_LBUTTONUP,
 
-       // so we have to post it in advance to break the loop immediately
 
-       // Without MK_CONTROL, if there are more items selected,
 
-       // they won't get unselected on subsequent focus change
 
-       // (with explorer-style selection).
 
-       // And it also makes the click the least obtrusive, affecting the focused
 
-       // file only.
 
-       WParam := MK_LBUTTON or MK_CONTROL;
 
-       LParam := MAKELPARAM(P.X, P.Y);
 
-       PostMessage(Handle, WM_LBUTTONUP, WParam, LParam);
 
-       SendMessage(Handle, WM_LBUTTONDOWN, WParam, LParam);
 
-     finally
 
-       FFocusingItem := False;
 
-       FLastSelectMethod := PLastSelectMethod;
 
-       FDontSelectItem := PDontSelectItem;
 
-       FDontUnSelectItem := PDontUnSelectItem;
 
-     end;
 
-   end;
 
-   if ItemFocused <> Item then
 
-     ItemFocused := Item;
 
- end;
 
- procedure TCustomNortonLikeListView.SelectAll(Mode: TSelectMode; Exclude: TListItem);
 
- var
 
-   Index: Integer;
 
-   Item: TListItem;
 
- begin
 
-   BeginSelectionUpdate;
 
-   try
 
-     for Index := 0 to Items.Count - 1 do
 
-     begin
 
-       Item := Items[Index];
 
-       if Item <> Exclude then
 
-       begin
 
-         case Mode of
 
-           smAll: Item.Selected := True;
 
-           smNone: Item.Selected := False;
 
-           smInvert: Item.Selected := not Item.Selected;
 
-         end;
 
-       end;
 
-     end;
 
-   finally
 
-     EndSelectionUpdate;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.SelectAll(Mode: TSelectMode);
 
- begin
 
-   SelectAll(Mode, nil);
 
- end;
 
- procedure TCustomNortonLikeListView.WMLButtonDown(var Message: TWMLButtonDown);
 
- var
 
-   PLastSelectMethod: TSelectMethod;
 
-   PDontUnSelectItem: Boolean;
 
-   PDontSelectItem: Boolean;
 
-   PSelectingImplicitly: Boolean;
 
-   SelectingImplicitly: Boolean;
 
-   Shift: TShiftState;
 
-   Item: TListItem;
 
- begin
 
-   Shift := KeysToShiftState(Message.Keys);
 
-   PLastSelectMethod := FLastSelectMethod;
 
-   PDontSelectItem := FDontSelectItem;
 
-   PDontUnSelectItem := FDontUnSelectItem;
 
-   PSelectingImplicitly := FSelectingImplicitly;
 
-   FLastSelectMethod := smMouse;
 
-   FDontSelectItem := FDontSelectItem or ((NortonLike = nlOn) and ((Shift * [ssCtrl, ssShift]) = []));
 
-   FDontUnSelectItem := FDontUnSelectItem or ((NortonLike = nlOn) and ((Shift * [ssCtrl]) = []));
 
-   SelectingImplicitly := ((Shift * [ssCtrl, ssShift]) = []);
 
-   if SelectingImplicitly and (NortonLike = nlKeyboard) then
 
-   begin
 
-     // in general, when clicking, we clear selection only after mouse button is released,
 
-     // from within WMLButtonUp, so we know we are not starting dragging,
 
-     // so we do not want to clear the selection.
 
-     // on the other hand, when clicking outside of the selection,
 
-     // we want to explicitly clear the selection, no matter what
 
-     Item := GetItemAt(Message.XPos, Message.YPos);
 
-     if (Item = nil) or (not Item.Selected) then
 
-       SelectAll(smNone);
 
-   end;
 
-   FSelectingImplicitly := FSelectingImplicitly or SelectingImplicitly;
 
-   FLButtonDownShiftState := Shift;
 
-   FLButtonDownPos := Point(Message.XPos, Message.YPos);
 
-   try
 
-     inherited;
 
-   finally
 
-     FLastSelectMethod := PLastSelectMethod;
 
-     FDontSelectItem := PDontSelectItem;
 
-     FDontUnSelectItem := PDontUnSelectItem;
 
-     FSelectingImplicitly := PSelectingImplicitly;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.WMRButtonDown(var Message: TWMRButtonDown);
 
- var
 
-   PLastSelectMethod: TSelectMethod;
 
-   PDontUnSelectItem: Boolean;
 
-   PDontSelectItem: Boolean;
 
-   PSelectingImplicitly: Boolean;
 
-   SelectingImplicitly: Boolean;
 
-   Shift: TShiftState;
 
- begin
 
-   Shift := KeysToShiftState(Message.Keys);
 
-   PLastSelectMethod := FLastSelectMethod;
 
-   PDontSelectItem := FDontSelectItem;
 
-   PDontUnSelectItem := FDontUnSelectItem;
 
-   PSelectingImplicitly := FSelectingImplicitly;
 
-   FLastSelectMethod := smMouse;
 
-   FDontSelectItem := FDontSelectItem or (NortonLike = nlOn);
 
-   FDontUnSelectItem := FDontUnSelectItem or (NortonLike = nlOn);
 
-   SelectingImplicitly := ((Shift * [ssCtrl, ssShift]) = []);
 
-   // TODO unselect all when clicking outside of selection
 
-   // (is not done automatically when focused item is not selected)
 
-   FSelectingImplicitly := FSelectingImplicitly or SelectingImplicitly;
 
-   try
 
-     inherited;
 
-   finally
 
-     FLastSelectMethod := PLastSelectMethod;
 
-     FDontSelectItem := PDontSelectItem;
 
-     FDontUnSelectItem := PDontUnSelectItem;
 
-     FSelectingImplicitly := PSelectingImplicitly;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.WMLButtonUp(var Message: TWMLButtonUp);
 
- var
 
-   SelectingImplicitly: Boolean;
 
-   Shift: TShiftState;
 
- begin
 
-   // Workaround
 
-   // For some reason Message.Keys is always 0 here,
 
-   // so we use shift state from the LButtonDown as a workaround
 
-   Shift := KeysToShiftState(Message.Keys);
 
-   SelectingImplicitly :=
 
-     ((Shift * [ssCtrl, ssShift]) = []) and
 
-     ((FLButtonDownShiftState * [ssCtrl, ssShift]) = []);
 
-   if SelectingImplicitly and (csClicked in ControlState) and
 
-      (Abs(FLButtonDownPos.X - Message.XPos) <= 4) and
 
-      (Abs(FLButtonDownPos.Y - Message.YPos) <= 4) then
 
-   begin
 
-     SelectAll(smNone, ItemFocused);
 
-     // Because condition in ItemSelected is not triggered as we first select
 
-     // the new item and then unselect the previous.
 
-     // This probably means that we can get rid of the code in ItemSelected.
 
-     FAnyAndAllSelectedImplicitly := True;
 
-   end;
 
-   inherited;
 
- end;
 
- function TCustomNortonLikeListView.GetMarkedFile: TListItem;
 
- begin
 
-   if Assigned(Selected) then Result := Selected
 
-     else
 
-   if Assigned(ItemFocused) and (NortonLike <> nlOff) then Result := ItemFocused
 
-     else Result := nil;
 
- end;
 
- function TCustomNortonLikeListView.GetNextItem(StartItem: TListItem;
 
-   Direction: TSearchDirection; States: TItemStates): TListItem;
 
- var
 
-   Start, Index, First, Last: Integer;
 
- begin
 
-   if not FManageSelection then
 
-   begin
 
-     Result := inherited GetNextItem(StartItem, Direction, States);
 
-   end
 
-     else
 
-   begin
 
-     Assert(Direction = sdAll);
 
-     if States = [isSelected] then
 
-     begin
 
-       if FSelCount = 0 then
 
-       begin
 
-         Result := nil
 
-       end
 
-         else
 
-       if (not Assigned(StartItem)) and (FFirstSelected >= 0) then
 
-       begin
 
-         Result := Items[FFirstSelected]
 
-       end
 
-         else
 
-       begin
 
-         if Assigned(StartItem) then
 
-           Start := StartItem.Index
 
-         else
 
-           Start := -1;
 
-         if (FFirstSelected >= 0) and (Start < FFirstSelected) then
 
-           First := FFirstSelected
 
-         else
 
-           First := Start + 1;
 
-         if FLastSelected >= 0 then
 
-           Last := FLastSelected
 
-         else
 
-           Last := Items.Count - 1;
 
-         if Start > Last then
 
-         begin
 
-           Result := nil;
 
-         end
 
-           else
 
-         begin
 
-           Index := First;
 
-           while (Index <= Last) and (not (Items[Index].Selected)) do
 
-           begin
 
-             Inc(Index);
 
-           end;
 
-           if Index > Last then
 
-           begin
 
-             Result := nil;
 
-             if Assigned(StartItem) and StartItem.Selected then
 
-             begin
 
-               Assert((FLastSelected < 0) or (FLastSelected = Start));
 
-               FLastSelected := Start;
 
-             end;
 
-           end
 
-             else
 
-           begin
 
-             Result := Items[Index];
 
-             Assert(Result.Selected);
 
-             if not Assigned(StartItem) then
 
-             begin
 
-               Assert((FFirstSelected < 0) or (FFirstSelected = Index));
 
-               FFirstSelected := Index;
 
-             end;
 
-           end;
 
-         end;
 
-       end;
 
-     end
 
-       else
 
-     if States = [isCut] then
 
-     begin
 
-       Result := inherited GetNextItem(StartItem, Direction, States);
 
-     end
 
-       else
 
-     if States = [] then
 
-     begin
 
-       if Assigned(StartItem) then
 
-         Start := StartItem.Index
 
-       else
 
-         Start := -1;
 
-       Inc(Start);
 
-       if Start < Items.Count then
 
-         Result := Items[Start]
 
-       else
 
-         Result := nil;
 
-     end
 
-       else
 
-     begin
 
-       Assert(False);
 
-       Result := nil;
 
-     end;
 
-   end;
 
- end;
 
- function TCustomNortonLikeListView.GetSelCount: Integer;
 
- begin
 
-   Result := FSelCount;
 
- end;
 
- procedure TCustomNortonLikeListView.InsertItem(Item: TListItem);
 
- begin
 
-   inherited;
 
-   if Item.Selected then
 
-     ItemSelected(Item, -1);
 
- end;
 
- function TCustomNortonLikeListView.GetItemFromHItem(const Item: TLVItem): TListItem;
 
- begin
 
-   with Item do
 
-     if (state and LVIF_PARAM) <> 0 then Result := Pointer(lParam)
 
-       else Result := Items[iItem];
 
- end;
 
- function TCustomNortonLikeListView.GetMarkedCount: Integer;
 
- begin
 
-   if (SelCount > 0) or (NortonLike = nlOff) then Result := SelCount
 
-     else
 
-   if Assigned(ItemFocused) then Result := 1
 
-     else Result := 0;
 
- end;
 
- function TCustomNortonLikeListView.GetValid: Boolean;
 
- begin
 
-   // Note that TCustomDirView::GetValid don't inherit
 
-   // this method because of optimalization
 
-   Result := (not (csDestroying in ComponentState)) and (not FClearingItems);
 
- end;
 
- procedure TCustomNortonLikeListView.BeginSelectionUpdate;
 
- begin
 
-   // Higher value is probably some nesting error
 
-   Assert(FUpdatingSelection in [0..4]);
 
-   Inc(FUpdatingSelection);
 
- end; { BeginUpdatingSelection }
 
- procedure TCustomNortonLikeListView.EndSelectionUpdate;
 
- begin
 
-   Assert(FUpdatingSelection > 0);
 
-   Dec(FUpdatingSelection);
 
- end; { EndUpdatingSelection }
 
- procedure TCustomNortonLikeListView.CreateWnd;
 
- begin
 
-   try
 
-     Assert(ColProperties <> nil);
 
-     inherited;
 
-     FHeaderHandle := ListView_GetHeader(Handle);
 
-     ColProperties.ListViewWndCreated;
 
-   finally
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.DestroyWnd;
 
- begin
 
-   ColProperties.ListViewWndDestroying;
 
-   try
 
-     inherited;
 
-   finally
 
-     ColProperties.ListViewWndDestroyed;
 
-   end;
 
- end;
 
- procedure TCustomNortonLikeListView.LVMEditLabel(var Message: TMessage);
 
- begin
 
-   // explicitly requesting editing (e.g. F2),
 
-   // so we do not care anymore when the view was focused
 
-   FFocused := 0;
 
-   inherited;
 
- end;
 
- function TCustomNortonLikeListView.CanEdit(Item: TListItem): Boolean;
 
- var
 
-   N: TDateTime;
 
-   Delta: Double;
 
- begin
 
-   N := Now;
 
-   Result := inherited CanEdit(Item);
 
-   if Result and (FFocused > 0) then
 
-   begin
 
-     Delta := N - FFocused;
 
-     // it takes little more than 500ms to trigger editing after click
 
-     Result := Delta > (750.0/MSecsPerDay);
 
-   end;
 
-   FFocused := 0;
 
- end;
 
- procedure TCustomNortonLikeListView.WMSetFocus(var Message: TWMSetFocus);
 
- begin
 
-   inherited;
 
-   if Message.FocusedWnd <> FIgnoreSetFocusFrom then
 
-     FFocused := Now;
 
- end;
 
- procedure TCustomNortonLikeListView.CMWantSpecialKey(var Message: TCMWantSpecialKey);
 
- begin
 
-   inherited;
 
-   if IsEditing and (Message.CharCode = VK_TAB) then
 
-     Message.Result := 1;
 
- end;
 
- procedure TCustomNortonLikeListView.MakeProgressVisible(Item: TListItem);
 
- var
 
-   DisplayRect: TRect;
 
- begin
 
-   if ViewStyle = vsReport then
 
-   begin
 
-     DisplayRect := Item.DisplayRect(drBounds);
 
-     if DisplayRect.Bottom > ClientHeight then
 
-     begin
 
-       Scroll(0, Item.Top - TopItem.Top);
 
-     end;
 
-   end;
 
-   Item.MakeVisible(False);
 
- end;
 
- procedure TCustomNortonLikeListView.ChangeScale(M, D: Integer);
 
- begin
 
-   if M <> D then
 
-   begin
 
-     // When font is scaled, while the control is being re-created, previous font is restored once
 
-     // read from the persistence data in TCustomListView.CreateWnd.
 
-     // Requiring handle, makes sure the re-create phase is closed.
 
-     // We could limit impact by checking ControlHasRecreationPersistenceData,
 
-     // but for now, we actually prefer larger impact to test this change better.
 
-     HandleNeeded;
 
-   end;
 
-   inherited;
 
- end;
 
- end.
 
 
  |