fcdbtreeview.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:131k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. begin
  2.   Down:= True;
  3.   InvalidateRow(MouseRow); { Invalidate button icon }
  4.   SetCapture(Handle);
  5.   try
  6.     while GetCapture = Handle do
  7.     begin
  8.       GetCursorPos(ACursor);
  9.       case Integer(GetMessage(Msg, 0, 0, 0)) of
  10.         -1: Break;
  11.         0: begin
  12.           PostQuitMessage(Msg.WParam);
  13.           Break;
  14.         end;
  15.       end;
  16.       case Msg.Message of
  17.         WM_LBUTTONDOWN, WM_LBUTTONDBLCLK: ;
  18.         WM_MOUSEMOVE: MouseLoop_MouseMove(X, Y, ACursor);
  19.         WM_LBUTTONUP: begin
  20.           MouseLoop_MouseUp(X, Y, ACursor);
  21.           TranslateMessage(Msg);   // So OnMouseUp fires
  22.           DispatchMessage(Msg);
  23.           if GetCapture = Handle then ReleaseCapture;
  24.         end;
  25.         else begin
  26.           TranslateMessage(Msg);   // So OnMouseUp fires
  27.           DispatchMessage(Msg);
  28.         end;
  29.       end;
  30.     end;
  31.   finally
  32.     if GetCapture = Handle then ReleaseCapture;
  33.     if Dragging then EndDrag(False);
  34.   end;
  35. end;
  36. Function TfcDBCustomTreeView.TextRect(Node: TfcDBTreeNode; Row: integer): TRect;
  37. var R: TRect;
  38. begin
  39.    R:= Rect(FixedOffset + (Node.Level+1)*LevelIndent, row*RowHeight, Width,
  40.        (row+1)*RowHeight-1);
  41.    if Images<>nil then r.Left:= r.Left + TImageList(Images).Width;
  42.    if UseStateImages(Node) then r.Left:= r.Left + GetStateImageWidth;
  43.    if (Images<>nil) and (UseStateImages(Node)) then
  44.       r.Left:= r.Left + 1;
  45.    if Header<>nil then
  46.    begin
  47.       R.Right:= R.Left + ClientWidth + HorzScrollBar.position;
  48.    end
  49.    else begin
  50.       R.Right:= R.Left + FPaintCanvas.TextWidth(Node.Text) + 3;
  51.    end;
  52.    if not (dtvoShowRoot in Options) then begin
  53.       r.Left:= r.Left - LevelIndent;
  54.       r.Right:= r.Right - LevelIndent;
  55.    end;
  56.    result:= R;
  57. end;
  58. Function TfcDBCustomTreeView.LevelRect(Node: TfcDBTreeNode): TRect;
  59. var r: TRect;
  60.     row: Integer;
  61. begin
  62.    r:= Rect(0,0,0,0);
  63.    r.Left:= Node.Level * LevelIndent + FixedOffset;
  64. //   if Images<>nil then
  65.      r.Right:= r.Left + LevelIndent - 1;
  66. //   else r.Right:= r.Left + LevelIndent - 4;
  67.    if NodeToRow(Node, Row) then begin
  68.       r.Top:= Row * RowHeight;
  69.       r.Bottom:= (Row+1) * RowHeight -1;
  70.    end
  71.    else begin
  72.       r.Top:= 0;
  73.       r.Bottom:= RowHeight-1;
  74.    end;
  75.    if not (dtvoShowRoot in Options) then begin
  76.       if Node.Level=0 then
  77.       begin
  78.          r.Left:= 0;
  79.          r.Right:= 0;
  80.       end
  81.       else begin
  82.          r.Left:= r.Left - LevelIndent;
  83.          r.Right:= r.Right - LevelIndent;
  84.       end
  85.    end;
  86.    result:= r;
  87. end;
  88. Function TfcDBCustomTreeView.GetCenterPoint(ARect: TRect): TPoint;
  89. var r: TRect;
  90. begin
  91.    r:= ARect;
  92.    if odd(fcRectHeight(r) div 2) then
  93.       result.y:= r.Top + (fcRectHeight(r)+2) div 2
  94.    else
  95.       result.y:= r.Top + (fcRectHeight(r)) div 2;
  96.    result.x:= r.Left + (fcRectWidth(r)) div 2
  97. end;
  98. procedure TfcDBCustomTreeView.PaintImage(Node: TfcDBTreeNode);
  99. const ItemChecked: array[Boolean] of Integer = (0, DFCS_CHECKED);
  100.       CheckBoxFlat: array[Boolean] of Integer = (0, DFCS_FLAT);
  101.       DrawSelected: array[Boolean] of Integer = (ILD_NORMAL, ILD_SELECTED);
  102. var r: TRect;
  103.     x: Integer;
  104.     Index: Integer;
  105.     cp: TPoint;
  106.     offset: integer;
  107.     ARect: TRect;
  108.     {$ifdef fcUseThemeManager}
  109.     Details: TThemedElementDetails;
  110.     CheckboxStyle: TThemedButton;
  111.     PaintRect: TRect;
  112.     {$endif}
  113. begin
  114.   r := LevelRect(Node);
  115.   if not((Images = nil) or (Node.ImageIndex < 0) or
  116.     (Node.ImageIndex >= Images.Count)) then
  117.   begin
  118.     x := r.Right -2;
  119.     if UseStateImages(Node) then
  120.     begin
  121.        inc(x, GetStateImageWidth+1);
  122.     end;
  123.     Index := Node.ImageIndex;
  124.     ImageList_DrawEx(Images.Handle, Index, FPaintCanvas.Handle,
  125.       x, r.Top + (r.Bottom - r.Top - TImageList(Images).Height) div 2, 0, 0,
  126.       CLR_NONE, ColorToRGB(TImageList(Images).BlendColor),
  127.       DrawSelected[Node.Selected and (TImageList(Images).BlendColor <> clNone)
  128.       and not (dtvoRowSelect in Options)]);
  129.   end;
  130.   if UseStateImages(Node) then
  131.   begin
  132.      if MultiSelectCheckboxNeeded(Node) then begin
  133.          cp:= GetCenterPoint(r);
  134.          Offset:= 6;
  135.          ARect:= Rect(r.right+1, cp.y-offset, r.Right + 2*offset + 2, cp.y+offset+1);
  136.          if fcUseThemes(self) then
  137.          begin
  138.            {$ifdef fcUseThemeManager}
  139.            if Node.multiselected then CheckboxStyle:= tbCheckboxCheckedNormal
  140.            else CheckboxStyle:= tbCheckboxUnCheckedNormal;
  141.            Details := ThemeServices.GetElementDetails(CheckboxStyle);
  142.            PaintRect := ARect;
  143.            ThemeServices.DrawElement(Canvas.Handle, Details, PaintRect);
  144.            PaintRect := ThemeServices.ContentRect(Canvas.Handle, Details, PaintRect);
  145.            {$endif}
  146.          end
  147.          else begin
  148.             DrawFrameControl(FPaintCanvas.Handle, ARect,
  149.                  DFC_BUTTON, DFCS_BUTTONCHECK or CheckBoxFlat[dtvoFlatCheckBoxes in Options] or ItemChecked[Node.MultiSelected])
  150.          end
  151.      end
  152.      else
  153.         StateImages.Draw(FPaintCanvas, r.right-2, r.Top + (r.Bottom-r.Top-TImageList(StateImages).Height) div 2, Node.StateIndex)
  154. //        StateImages.Draw(FPaintCanvas, r.Right, r.Top, Node.StateIndex)
  155.   end;
  156. end;
  157. Function TfcDBCustomTreeView.GetStartX(Node: TfcDBTreeNode): integer;
  158. var Offset : integer;
  159.     r: TRect;
  160. begin
  161.    r := LevelRect(Node);
  162.    Offset:= (((r.Bottom - r.Top) div 2) div 2)+2;
  163.    Offset:= fcMin(Offset, 7);
  164.    result:= r.Left + offset + 1; //r.Right + Offset + 1;
  165. end;
  166. procedure TfcDBCustomTreeView.PaintLines(Node: TfcDBTreeNode);
  167. var LevelNode: TfcDBTreeNode;
  168.     LineStartX:integer;
  169.     LineTop, LineBottom: TPoint;
  170.     y:integer;
  171.     size: integer;
  172.     r, OrigRect: TRect;
  173. begin
  174.   if (dtvoShowLines in Options) and
  175.      ((dtvoShowRoot in Options) or (Node.Level<>0)) then
  176.   begin
  177. //    FPaintCanvas.Pen.Color := clBtnShadow;
  178.     LevelNode := Node;
  179.     OrigRect := LevelRect(Node);
  180.     while (LevelNode <> nil) and ((LevelNode.Level = 0) or (LevelNode.Parent <> nil)) do
  181.     begin
  182.       if (LevelNode.Level=0) and (not (dtvoShowRoot in Options)) then break;
  183.       r := LevelRect(LevelNode);
  184.       r.Top := OrigRect.Top;
  185.       r.Bottom := OrigRect.Bottom;
  186.       LineStartX:= GetStartX(LevelNode);
  187.       if (dtvoExpandButtons3D in Options) then
  188.       begin
  189.          LineTop:= Point(LineStartX, r.Top);
  190.          LineBottom:= Point(LineStartX, r.Bottom);
  191.       end
  192.       else begin
  193.          LineTop:= Point(LineStartX, r.Top);
  194.          LineBottom:= Point(LineStartX, r.Bottom);
  195.       end;
  196.       if LevelNode.Level = Node.Level then
  197.       begin
  198.         if (not Node.HasPrevSibling) and (Node.Parent = nil) then
  199.         begin
  200.            inc(LineTop.y, GetCenterPoint(r).y);
  201.         end;
  202.         if (not Node.HasNextSibling) then
  203.            dec(LineBottom.y, (r.bottom-r.top) div 2)
  204.         else if (PaintingRow >= CacheSize-1) then
  205.            LineBottom.y:= LineBottom.y+2;
  206.       end;
  207.       if (LevelNode.HasNextSibling) or (LevelNode.Level = Node.Level) then
  208.         FPaintCanvas.DottedLine(LineTop, LineBottom);
  209.       LevelNode := LevelNode.Parent;
  210.     end;
  211.     r := LevelRect(Node);
  212.     if (dtvoShowRoot in Options) or (Node.Level <> 0) then
  213.     begin
  214.       y:= GetCenterPoint(r).y;
  215.       if (Node.MultiSelected or (Node.Selected and Focused)) and
  216.          UseStateImages(Node) and MultiSelectCheckboxNeeded(Node) and
  217.          (dtvoRowSelect in Options) then
  218.          r.right:= r.right - 4;
  219.       if dtvoExpandButtons3D in Options then
  220.          FPaintCanvas.DottedLine(Point(GetStartX(Node), y), Point(r.Right, y))
  221.       else
  222.          FPaintCanvas.DottedLine(Point(GetStartX(Node), y), Point(r.Right, y));
  223.     end
  224.   end;
  225.   if (Node.HasChildren) then begin
  226.      // 06/17/2000 - PYW - Correct painting bug when dtvoShowRoot is not in options and paintbutton is called on the root node
  227.      if (not (dtvoShowRoot in Options)) and (Node.Level = 0) then exit;
  228.      size:= ((r.bottom-r.top) div 2);
  229.      size:= fcMax(size, 8);
  230.      PaintButton(Node,
  231.         Point(GetStartX(Node), GetCenterPoint(r).y), size, Node.Expanded)
  232.   end
  233. end;
  234. procedure TfcDBCustomTreeView.PaintButton(Node: TfcDBTreeNode;
  235.     pt: TPoint; Size: integer; Expanded: Boolean);
  236. var offset: integer;
  237.     drawRect: TRect;
  238.     OrigColor: TColor;
  239.     StateFlags: Word;
  240.     {$ifdef fcUseThemeManager}
  241.     Details: TThemedElementDetails;
  242.     {$endif}
  243. begin
  244.    OrigColor:= FPaintCanvas.Brush.Color;
  245.    if not (dtvoShowButtons in Options) then Exit;
  246.    offset:= Size;
  247.    Offset:= Offset div 2;
  248.    DrawRect.Left:= pt.x - offset;
  249.    DrawRect.Right:= pt.x + offset+1;
  250.    DrawRect.Top:= pt.y-offset;
  251.    DrawRect.Bottom:= pt.y+offset+1;
  252.    if dtvoExpandButtons3D in Options then
  253.    begin
  254.       FPaintCanvas.Brush.Color := clBtnFace;
  255.       FPaintCanvas.FillRect(DrawRect);
  256.       FPaintCanvas.Brush.Color := clBtnShadow;
  257.       StateFlags:= DFCS_BUTTONPUSH;
  258.       if Down and (MouseRow=PaintingRow) then
  259.          StateFlags := StateFlags or DFCS_PUSHED;
  260.       with DrawRect do
  261.          DrawFrameControl(FPaintCanvas.Handle, Rect(Left, Top, Right+1, Bottom+1),
  262.               DFC_BUTTON, StateFlags);
  263.       if ColorToRGB(Color)=clWhite then
  264.       begin
  265.          with DrawRect, FPaintCanvas do begin
  266.            Pen.Color := clBtnFace;
  267.            Polyline([Point(Left-1, Bottom), Point(Left-1, Top-1), Point(Right+1, Top-1)]);
  268.          end;
  269.       end;
  270.       if Down and (MouseRow = PaintingRow) then
  271.       begin
  272.          pt.x:= pt.x+1;
  273.          pt.y:= pt.y+1;
  274.          DrawRect.Left:= DrawRect.Left + 1;
  275.          DrawRect.Top:= DrawRect.Top + 1;
  276.          DrawRect.Right:= DrawRect.Right + 1;
  277.          DrawRect.Bottom:= DrawRect.Bottom + 1;
  278.       end;
  279.       FPaintCanvas.Brush.Color := Color;
  280.       FPaintCanvas.Pen.Color := clBlack;
  281.       if not Expanded then
  282.          FPaintCanvas.Polyline([Point(pt.x, DrawRect.Top+Offset div 2), Point(pt.x, DrawRect.Bottom-Offset div 2)]);
  283.       FPaintCanvas.Polyline([Point(DrawRect.Left+Offset div 2, pt.y), Point(DrawRect.Right-Offset div 2, pt.y)]);
  284.       FPaintCanvas.Brush.Color:= OrigColor;
  285.    end
  286.    else begin
  287.       if fcUseThemes(self) then
  288.       begin
  289.         {$ifdef fcUseThemeManager}
  290.         if expanded then
  291.           Details := ThemeServices.GetElementDetails(ttGlyphOpened)
  292.         else
  293.           Details := ThemeServices.GetElementDetails(ttGlyphClosed);
  294.         ThemeServices.DrawElement(FPaintCanvas.Handle, Details, DrawRect);
  295.         {$endif}
  296.       end
  297.       else begin
  298.          FPaintCanvas.Brush.Color := clWhite;
  299.          FPaintCanvas.FillRect(DrawRect);
  300.          FPaintCanvas.Brush.Color := clBtnShadow;
  301.          FPaintCanvas.FrameRect(DrawRect);
  302.          FPaintCanvas.Brush.Color := Color;
  303.          FPaintCanvas.Pen.Color := clBlack;
  304.          if not Expanded then
  305.             FPaintCanvas.Polyline([Point(pt.x, DrawRect.Top+Offset div 2), Point(pt.x, DrawRect.Bottom-Offset div 2)]);
  306.          FPaintCanvas.Polyline([Point(DrawRect.Left+Offset div 2, pt.y), Point(DrawRect.Right-Offset div 2, pt.y)]);
  307.          FPaintCanvas.Brush.Color:= OrigColor;
  308.       end
  309.    end
  310. end;
  311. procedure TfcDBCustomTreeView.SetBorderStyle(Value: TBorderStyle);
  312. begin
  313.   if FBorderStyle <> Value then
  314.   begin
  315.     FBorderStyle := Value;
  316.     RecreateWnd;
  317.   end;
  318. end;
  319. procedure TfcDBCustomTreeView.SetLineColor(Value: TColor);
  320. begin
  321.   if FLineColor <> Value then
  322.   begin
  323.     FLineColor:= Value;
  324.     InvalidateClient;
  325.   end;
  326. end;
  327. procedure TfcDBCustomTreeView.SetInactiveFocusColor(Value: TColor);
  328. begin
  329.   if FInactiveFocusColor <> Value then
  330.   begin
  331.     FInactiveFocusColor:= Value;
  332.     InvalidateClient;
  333.   end;
  334. end;
  335. procedure TfcDBCustomTreeView.SetOptions(Value: TfcDBTreeViewOptions);
  336. const
  337.   LayoutOptions = [dtvoShowHorzScrollBar, dtvoShowVertScrollBar];
  338. var ChangedOptions: TfcDBTreeViewOptions;
  339. begin
  340.    if Value<>FOptions then
  341.    begin
  342.       ChangedOptions := (FOptions + Value) - (FOptions * Value);
  343.       FOptions:= Value;
  344.       if ChangedOptions * LayoutOptions <> [] then begin
  345.          { 1/20/2000 - Support dtvoShowVertScrollBar }
  346.          if dtvoShowVertScrollBar in ChangedOptions then
  347.          begin
  348.             if HandleAllocated then begin
  349.               if (dtvoShowVertScrollBar in Options) then
  350.               begin
  351.                  VertScrollBar.visible:= true;
  352.                  if not HideUpDownButtons then
  353.                  begin
  354.                     UpTreeButton.visible:= true;
  355.                     DownTreeButton.visible:= true;
  356.                  end
  357.                  else begin
  358.                     UpTreeButton.visible:= false;
  359.                     DownTreeButton.visible:= false;
  360.                  end
  361.               end
  362.               else begin
  363.                  VertScrollBar.visible:= false;
  364.                  UpTreeButton.visible:= false;
  365.                  DownTreeButton.visible:= false;
  366.               end;
  367.               UpdateScrollBarPosition;
  368.             end
  369.          end;
  370.          LayoutChanged;
  371.       end
  372.       else begin
  373.          invalidate;
  374.       end
  375.    end
  376. end;
  377. procedure TfcDBCustomTreeView.SetLastVisibleDataSet(DataSet: TDataSet);
  378. begin
  379.   if FLastVisibleDataSet<>DataSet then
  380.   begin
  381. //     DoChangeLastExpandedDataSet;
  382.      FLastVisibleDataSet:= DataSet;
  383.   end;
  384. end;
  385. procedure TfcDBCustomTreeView.SetActiveDataSet(DataSet: TDataSet);
  386. var DataLinkChild, DataLinkParent: TfcTreeDataLink;
  387. begin
  388.     if ActiveDataSet=DataSet then exit;
  389.     if DataSet<>nil then
  390.     begin
  391.        DataLinkChild:= GetChildDataLink(ActiveDataSet);
  392.        DataLinkParent:= GetParentDataLink(ActiveDataSet);
  393.        if (DataLinkChild<>nil) and (DataLinkChild.DataSet = DataSet) then begin
  394.           { Expanding }
  395.           FreeHintWindow;
  396.        end
  397.        else if (DataLinkParent<>nil) and (DataLinkParent.dataset = DataSet) then begin
  398.           { Collapsing }
  399.           FreeHintWindow;
  400.        end
  401.     end;
  402.     { 1/17/2000 - If insert state then allow changing to this dataset }
  403.     if (not (DataSet.Bof and DataSet.eof)) or (dataset.state=dsinsert) then
  404.     begin
  405.        FActiveDataSet:= DataSet;
  406.        ActiveDataSetChanged:= True; { Next paint event will trigger Change event }
  407. //       if GetDataLink(LastVisibleDataSet)<>Nil then LastVisibleDataSet:= DataSet; { 5/15/99 - Commented out this line }
  408. //       if LastVisibleDataSet=nil then LastVisibleDataSet:= DataSet;
  409.     end;
  410.     if FScrollWithinLevel then UpdateScrollBar;
  411. end;
  412. procedure TfcDBCustomTreeView.ScrollLeft;
  413. var scrollpos: integer;
  414. begin
  415.    scrollpos:= HorzScrollBar.position;
  416.    if scrollpos>0 then
  417.    begin
  418.       scrollpos:= fcmax(0, scrollpos - 10);
  419.       HorzScrollBar.position:= scrollpos;
  420.       invalidateClient;
  421.    end
  422. end;
  423. procedure TfcDBCustomTreeView.ScrollRight;
  424. var scrollpos: integer;
  425. begin
  426.    scrollpos:= HorzScrollBar.position;
  427.    if scrollpos + (ClientRect.right - ClientRect.Left) <MaxTextWidth then
  428.    begin
  429.       scrollpos:= fcmin(MaxTextWidth, scrollpos + 10);
  430.       HorzScrollBar.position:= scrollpos;
  431.       invalidateClient;
  432.    end
  433. end;
  434. procedure TfcDBCustomTreeView.KeyDown(var Key: Word; Shift: TShiftState);
  435. var DataLink: TfcTreeDataLink;
  436. begin
  437.    DataLink:= GetDataLink(ActiveDataSet);
  438.    case key of
  439.       vk_down: begin
  440.           NextRow(dtvoKeysScrollLevelOnly in Options);
  441.        end;
  442.       vk_up: begin
  443.           PriorRow(dtvoKeysScrollLevelOnly in Options);
  444.        end;
  445.       vk_multiply, vk_add, vk_right:
  446.        begin
  447.           if ssCtrl in Shift then
  448.              ScrollRight
  449.           else Expand(ActiveNode);
  450.        end;
  451.       vk_subtract, vk_left:
  452.        begin
  453.           if ssCtrl in Shift then
  454.           begin
  455.              ScrollLeft;
  456.           end
  457.           else begin
  458.              if (ActiveNode<>nil) then
  459.              begin
  460.                 if (ActiveNode.Parent<>nil) then
  461.                     Collapse(ActiveNode.Parent)
  462.                 else
  463.                     Collapse(ActiveNode);
  464.              end
  465.           end;
  466.        end;
  467.       vk_home:
  468.          if (ssCtrl in Shift)then
  469.          begin
  470.             ActiveDataSet:= TfcTreeDataLink(FDataLinks[0]).DataSet;
  471.             LastVisibleDataSet := ActiveDataSet;
  472.             ResetStartOffsets(ActiveDataSet);
  473.             TfcTreeDataLink(FDataLinks[0]).dataset.first;
  474.          end
  475.          else
  476.             DataLink.dataset.first;
  477.       vk_end:
  478.          if (ssCtrl in Shift)then
  479.          begin
  480.             ActiveDataSet:= TfcTreeDataLink(FDataLinks[0]).DataSet;
  481.             LastVisibleDataSet := ActiveDataSet;
  482.             ResetStartOffsets(ActiveDataSet);
  483.             TfcTreeDataLink(FDataLinks[0]).dataset.last;
  484.          end
  485.          else
  486.             DataLink.dataset.last;
  487.       vk_next:
  488.           NextPage(dtvoKeysScrollLevelOnly in Options);
  489.       vk_prior:
  490.           PriorPage(dtvoKeysScrollLevelOnly in Options);
  491.       vk_space: ToggleMultiSelection(not MultiSelectAttributes.MultiSelectCheckbox, Shift);
  492.    end;
  493.    if key in [vk_right, vk_left, vk_down, vk_up, vk_next, vk_prior, vk_space] then key:= 0;
  494.    if Assigned(OnKeyDown) then OnKeyDown(self, Key, Shift); { 7/4/99 - Fire OnKeyDown event }
  495. end;
  496. function TfcDBCustomTreeView.IsChildDataSetOfActive(DataSet: TDataSet): boolean;
  497. var DataLinkParent: TfcTreeDataLink;
  498. begin
  499.     result:= False;
  500.     DataLinkParent:= GetDataLink(DataSet);
  501.     if DataLinkParent=nil then exit;
  502.     repeat
  503.        DataLinkParent:= GetParentDataLink(DataLinkParent.DataSet);
  504.     until (DataLinkParent=nil) or (DataLinkParent.DataSet = ActiveDataSet);
  505.     if (DataLinkParent<>nil) then result:= True;
  506. end;
  507. function TfcDBCustomTreeView.IsMasterDataSetOfActive(DataSet: TDataSet): boolean;
  508. var DataLinkChild: TfcTreeDataLink;
  509. begin
  510.     result:= False;
  511.     if DataSet=nil then
  512.     begin
  513.        result:= True;
  514.        exit;
  515.     end;
  516.     DataLinkChild:= GetDataLink(DataSet);
  517.     if DataLinkChild=nil then exit;
  518.     repeat
  519.        DataLinkChild:= GetChildDataLink(DataLinkChild.DataSet);
  520.     until (DataLinkChild=nil) or (DataLinkChild.DataSet = ActiveDataSet);
  521.     if (DataLinkChild<>nil) then result:= True;
  522. end;
  523. procedure TfcDBCustomTreeView.WMGetDlgCode(var Message: TWMGetDlgCode);
  524. begin
  525.    inherited;
  526.    message.result:= DLGC_WANTARROWS;
  527. end;
  528. function TfcDBCustomTreeView.GetHitTestInfoAt(X, Y: Integer): TfcTreeHitTests;
  529. var
  530.   cbPoint: TPoint;
  531.   Node: TfcDBTreeNode;
  532.   Row: integer;
  533.   r: TRect;
  534.   StateImageOffset: integer;
  535. begin
  536.   X:= X + HorzScrollBar.position;
  537.   Result := [];
  538.   MouseToRow(X, Y, Row);
  539.   if not RowToNode(Row, Node) then exit;
  540.   r:= LevelRect(Node);
  541.   if Node=ActiveNode then
  542.      result:= result + [fchtdOnActiveNode];
  543.   if dtvoShowButtons in Options then
  544.   begin
  545.      if (r.Left<>r.right) and (r.Top<>r.Bottom) then begin
  546.         cbPoint:= GetCenterPoint(r);
  547.         if (abs(GetStartX(Node)-x) <7) and (abs(cbPoint.y-y)<7) then
  548.         begin
  549.            result:= result + [fchtdOnButton];
  550.            exit;
  551.         end
  552.      end;
  553.   end;
  554.   StateImageOffset:= 0;
  555.   if UseStateImages(Node) then begin
  556.      StateImageOffset:= GetStateImageWidth;
  557.      if (x>r.Right) and (x<r.Right + StateImageOffset) then
  558.      begin
  559.         result:= result + [fchtdOnStateIcon];
  560.         exit;
  561.      end
  562.   end;
  563.   if (Images<>nil) and (x>r.Right + StateImageOffset) and
  564.      (x<r.Right + StateImageOffset + TImageList(Images).Width) then
  565.   begin
  566.      result:= result + [fchtdOnImageIcon];
  567.      exit;
  568.   end;
  569.   R:= TextRect(Node, Row);
  570.   if (x>=R.Left) and (x<=R.Right) then
  571.   begin
  572.      result:= result + [fchtdOnText];
  573.      exit;
  574.   end;
  575. //  THitTest = (htAbove, htBelow, htNowhere, htOnItem, htOnButton, htOnIcon,
  576. //    htOnIndent, htOnLabel, htOnRight, htOnStateIcon, htToLeft, htToRight);
  577. end;
  578. procedure TfcDBCustomTreeView.ResetStartOffsets(ActiveDataSet: TDataSet);
  579. var i: integer;
  580.     clear: boolean;
  581. begin
  582.    Clear:= False;
  583.    for i:= 0 to FDataLinks.Count-1 do begin
  584.       if ActiveDataSet = TfcTreeDataLink(FDataLinks[i]).dataset then
  585.          Clear:= True;
  586.       if Clear then StartOffsets[i]:= 0;
  587.    end;
  588. end;
  589. Procedure TfcDBCustomTreeView.SetStartOffset(ActiveDataSet: TDataSet; val: integer);
  590. var i: integer;
  591. begin
  592.    for i:= 0 to FDataLinks.Count-1 do
  593.       if ActiveDataSet = TfcTreeDataLink(FDataLinks[i]).DataSet then
  594.          StartOffsets[i]:= val;
  595. end;
  596. Function TfcDBCustomTreeView.GetStartOffset: integer;
  597. var StartOffset: integer;
  598.    Function GetOffset(Dataset: TDataSet): integer;
  599.    var i: integer;
  600.    begin
  601.       result:= 0;
  602.       for i:= 0 to FDataLinks.Count-1 do
  603.       begin
  604.          result:= fcmax(result, StartOffsets[i]);
  605.          if DataSet = TfcTreeDataLink(FDataLinks[i]).DataSet then
  606.          begin
  607.             break;
  608.          end
  609.       end;
  610.    end;
  611. begin
  612.    StartOffset:= GetOffset(LastVisibleDataSet);
  613.    if ActiveNodeIndex<StartOffset then StartOffset:= GetOffset(ActiveDataSet);
  614.    result:= StartOffset;
  615. end;
  616. procedure TfcDBCustomTreeView.SetImages(Value: TCustomImageList);
  617. begin
  618.   FImages := Value;
  619.   invalidateClient;
  620. end;
  621. procedure TfcDBCustomTreeView.SetStateImages(Value: TCustomImageList);
  622. begin
  623.   FStateImages := Value;
  624.   invalidateClient;
  625. end;
  626. function TfcDBCustomTreeView.UseStateImages(Node: TfcDBTreeNode): Boolean;
  627. begin
  628.   result := ((StateImages <> nil) and (Node.StateIndex >= 0) and
  629.     (Node.StateIndex < StateImages.Count));
  630.   if not Result then
  631.      if MultiSelectCheckBoxNeeded(Node) then result:= True
  632. end;
  633. procedure TfcDBCustomTreeView.WMSetFocus(var Message: TWMSetFocus);
  634. begin
  635.    inherited;
  636.    invalidateClient;
  637. end;
  638. procedure TfcDBCustomTreeView.CMExit(var Message: TMessage);
  639. begin
  640.    inherited;
  641.    invalidateClient;
  642. end;
  643. procedure TfcDBCustomTreeView.UpdateScrollBar;
  644. var
  645.   recCount: longint;
  646.   DataLink: TfcTreeDataLink;
  647.   OldMax, OldPosition: integer;
  648. begin
  649. //  if not FShowVertScrollBar then exit;
  650.   if FDataLinks.count<=0 then exit;
  651.   if FScrollWithinLevel then
  652.      DataLink:= GetDataLink(ActiveDataSet)
  653.   else DataLink:= nil;
  654.   if DataLink=Nil then DataLink:= TfcTreeDataLink(FDataLinks[0]);
  655.   if Datalink.Active and HandleAllocated then
  656.   begin
  657. //    recNum:= 0;
  658. //    recCount:= 0;
  659.     { Set scroll bar precisely }
  660.     if datalink.dataset.active and { 3/21/00 - Check for active }
  661.        DataLink.DataSet.isSequenced then with DataLink.DataSet do
  662.     begin
  663.        DataLink.DataSet.UpdateCursorPos;
  664.        recCount:= DataLink.DataSet.RecordCount;
  665. //       recNum:= DataLink.DataSet.RecNo;
  666.        with VertScrollBar do begin
  667.           FixedThumbSize:= False;
  668.           OldMax:= Max;
  669.           OldPosition:= Position;
  670.           PageSize:= CacheSize;
  671.           Min:=1;
  672.           Max:= fcMax(recCount + PageSize-1, PageSize+1);
  673.           if State in [dsInactive, dsBrowse, dsEdit] then
  674.           begin
  675.              if BOF then position := 0
  676.              else if EOF then position := fcMax(recCount, 2)
  677.              else position:= recNo;
  678.           end
  679.           else Position := RecNo;  // else keep old pos
  680.           if (OldPosition<>Position) or (Max<>OldMax) then
  681.           begin
  682.              VertScrollBar.invalidate;
  683.           end;
  684.        end;
  685.     end
  686.     else with Datalink.DataSet do
  687.     begin
  688.        with VertScrollBar do begin
  689.           OldPosition:= Position;
  690.           PageSize:= 1;
  691.           Min:=0;
  692.           Max:= 40;
  693.           if BOF then Position := 0
  694.           else if EOF then Position := 40
  695.           else Position := 20;
  696.           if (not FixedThumbSize) or (OldPosition<>Position) then
  697.           begin
  698.              FixedThumbSize:= True;
  699.              VertScrollBar.invalidate;
  700.           end;
  701.        end
  702.     end
  703.   end
  704. end;
  705. procedure TfcDBCustomTreeView.CreateWnd;
  706. begin
  707.   inherited CreateWnd;
  708.   UpdateScrollBarPosition;
  709.   LayoutChanged;
  710.   UpdateScrollBar;
  711. end;
  712. procedure TfcDBCustomTreeView.HScroll(ScrollCode: integer; Position: integer);
  713. begin
  714.    if Position<>HorzScrollBar.PriorPosition then
  715.    begin
  716.       if Header<>nil then
  717.       begin
  718.          Header.HeaderControl.Width:= Width+HorzScrollBar.position;
  719.          Header.HeaderControl.Left:= -HorzScrollBar.position;
  720.       end;
  721.       invalidateClient;
  722.    end;
  723. end;
  724.   procedure TfcDBCustomTreeView.NextRow(WithinLevel: boolean);
  725.   var ActiveDataLink: TfcTreeDataLink;
  726.   begin
  727.     ActiveDataLink:= GetDataLink(ActiveDataSet);
  728.     if ActiveDataLink=Nil then ActiveDataLink:= TfcTreeDataLink(FDataLinks[0]);
  729.     if WithinLevel then
  730.     begin
  731.        if ActiveDataLink.ActiveRecord>=ActiveDataLink.RecordCount-1 then
  732.        begin
  733.           ActiveDataLink.DataSet.MoveBy(1);
  734.        end
  735.        else begin
  736.           ActiveDataLink.DataSet.Next;
  737.        end;
  738.        exit;
  739.     end;
  740.     with ActiveDatalink.Dataset do
  741.     begin
  742.        if Eof and (ActiveDataLink.ActiveRecord>=0) and
  743.          (ActiveDataLink.ActiveRecord<ActiveDataLink.RecordCount-1) and not (State=dsInsert) then
  744.        begin
  745.           ActiveDataLink.ActiveRecord:= ActiveDataLink.ActiveRecord + 1
  746.        end
  747.        else begin
  748.           Next;
  749.           if Eof then begin
  750.              if GetParentDataLink(ActiveDataSet)<>nil then
  751.              begin
  752.                 ActiveDataSet:= GetParentDataLink(ActiveDataSet).DataSet;
  753.                 LastVisibleDataSet:= ActiveDataSet; { 12/7/98 }
  754.                 NextRow(False);
  755.              end
  756.           end
  757.        end
  758.     end;
  759.   end;
  760.   { Move to next node for activedataset }
  761.   procedure TfcDBCustomTreeView.NextPage(WithinLevel: boolean);
  762.   var ActiveDataLink: TfcTreeDataLink;
  763.   begin
  764.     ActiveDataLink:= GetDataLink(ActiveDataSet);
  765.     if ActiveDataLink=Nil then ActiveDataLink:= TfcTreeDataLink(FDataLinks[0]);
  766.     if WithinLevel then begin
  767.        ActiveDataLink.DataSet.MoveBy(CacheSize);
  768.        exit;
  769.     end;
  770.     with ActiveDatalink.Dataset do
  771.     begin
  772.        ActiveDataLink.DataSet.MoveBy(CacheSize);
  773.        if Eof then begin
  774.           if GetParentDataLink(ActiveDataSet)<>nil then
  775.           begin
  776.              ActiveDataSet:= GetParentDataLink(ActiveDataSet).DataSet;
  777.              LastVisibleDataSet:= ActiveDataSet; { 12/7/98 }
  778.              NextRow(False);
  779.           end
  780.        end
  781.     end;
  782.   end;
  783.   procedure TfcDBCustomTreeView.PriorRow(WithinLevel: boolean);
  784.   var ActiveDataLink: TfcTreeDataLink;
  785.   begin
  786.      ActiveDataLink:= GetDataLink(ActiveDataSet);
  787.      if ActiveDataLink=Nil then ActiveDataLink:= TfcTreeDataLink(FDataLinks[0]);
  788.      if WithinLevel then
  789.      begin
  790.         if ActiveDataLink.ActiveRecord<=0 then
  791.         begin
  792.            ActiveDataLink.DataSet.MoveBy(-1);
  793.            if ActiveDataLink.DataSet.Bof then
  794.            begin
  795.               StartOffsets[GetDataLinkIndex(ActiveDataLink.DataSet)]:= 0;
  796.               InvalidateClient; { 4/9/99 }
  797.            end
  798.         end
  799.         else begin
  800.            ActiveDataLink.DataSet.Prior;
  801.         end;
  802.         exit;
  803.      end;
  804.      with ActiveDatalink.Dataset do
  805. if BOF and (ActiveDataLink.ActiveRecord>0) then
  806.    ActiveDataLink.ActiveRecord:= ActiveDataLink.ActiveRecord - 1
  807. else begin
  808.            Prior;
  809.            if bof then begin
  810.              if GetParentDataLink(ActiveDataSet)<>nil then
  811.              begin
  812.                 ActiveDataSet:= GetParentDataLink(ActiveDataSet).DataSet;
  813.                 LastVisibleDataSet:= ActiveDataSet; { 12/7/98 }
  814.                 invalidateClient;
  815.              end
  816.            end
  817.         end;
  818.   end;
  819.   procedure TfcDBCustomTreeView.PriorPage(WithinLevel: boolean);
  820.   var ActiveDataLink: TfcTreeDataLink;
  821.   begin
  822.      ActiveDataLink:= GetDataLink(ActiveDataSet);
  823.      if ActiveDataLink=Nil then ActiveDataLink:= TfcTreeDataLink(FDataLinks[0]);
  824.      if WithinLevel then
  825.      begin
  826.         ActiveDataLink.DataSet.MoveBy(-CacheSize);
  827.         if ActiveDataLink.DataSet.Bof then begin
  828.            StartOffsets[GetDataLinkIndex(ActiveDataLink.DataSet)]:= 0;
  829.            InvalidateClient; { 4/9/99 }
  830.         end;
  831.         exit;
  832.      end;
  833.      with ActiveDatalink.Dataset do begin
  834.        ActiveDataLink.DataSet.MoveBy(-CacheSize);
  835.        if BOF then begin
  836.           if GetParentDataLink(ActiveDataSet)<>nil then
  837.           begin
  838.              ActiveDataSet:= GetParentDataLink(ActiveDataSet).DataSet;
  839.              LastVisibleDataSet:= ActiveDataSet; { 12/7/98 }
  840.              InvalidateClient;
  841.           end
  842.        end
  843.      end
  844.   end;
  845. procedure TfcDBCustomTreeView.VScroll(ScrollCode: integer; Position: integer);
  846. var DataLink: TfcTreeDataLink;
  847.   Function Sequencable: boolean;
  848.   begin
  849.      result:= DataLink.DataSet.isSequenced;
  850.   end;
  851.   procedure ParadoxPosition;
  852.   var recNum : Longint;
  853.   begin
  854.      with DataLink.DataSet do begin
  855.         recNum:= position;
  856.         checkBrowseMode;
  857.         RecNo:= recNum;
  858.         resync([]);
  859.      end;
  860.   end;
  861.   procedure MoveToFirst;
  862.   var ActiveDataLink: TfcTreeDataLink;
  863.   begin
  864.     ActiveDataLink:= GetDataLink(ActiveDataSet);
  865.     if ActiveDataLink=Nil then ActiveDataLink:= TfcTreeDataLink(FDataLinks[0]);
  866.     StartOffsets[GetDataLinkIndex(ActiveDataLink.DataSet)]:= 0;
  867.     InvalidateClient;
  868.   end;
  869. begin
  870.   if not CanFocus then Exit;
  871.   if not HaveValidDataLinks then exit;
  872.   SetFocus;
  873.   if FScrollWithinLevel then
  874.      DataLink:= GetDataLink(ActiveDataSet)
  875.   else DataLink:= nil;
  876.   if DataLink=Nil then DataLink:= TfcTreeDataLink(FDataLinks[0]);
  877.   if Datalink.Active then
  878.     with DataLink.DataSet, Datalink do begin
  879.       case ScrollCode of
  880. SB_LINEUP: PriorRow(FScrollWithinLevel);
  881. SB_LINEDOWN: NextRow(FScrollWithinLevel);
  882. SB_PAGEUP: PriorPage(FScrollWithinLevel);
  883. SB_PAGEDOWN: NextPage(FScrollWithinLevel);
  884. SB_THUMBPOSITION:
  885.   begin
  886.     if Sequencable then begin
  887.                LastVisibleDataSet:= DataLink.DataSet;
  888.        if position<=1 then
  889.                begin
  890.                   First;
  891.                   MoveToFirst;
  892.                end
  893.        else if position>=DataLink.DataSet.recordCount then
  894.                   Last
  895.        else ParadoxPosition;
  896.     end
  897.     else begin
  898.                if position=0 then begin
  899.                   LastVisibleDataSet:= DataLink.DataSet;
  900.                   First;
  901.                   MoveToFirst;
  902.                end
  903.                else if position=40 then begin
  904.                   LastVisibleDataSet:= DataLink.DataSet;
  905.                   Last;
  906.                end
  907.                else if Bof then begin
  908.                   MoveBy(CacheSize);
  909.                end
  910.                else if Eof then begin
  911.                   MoveBy(-CacheSize);
  912.                end
  913.                else if position<20 then begin
  914.                   MoveBy(-CacheSize);
  915.                end
  916.                else if position>20 then begin
  917.                   MoveBy(CacheSize);
  918.                end
  919.                else if position<20 then begin
  920.                   MoveBy(-CacheSize);
  921.                end;
  922. {        case Position of
  923.  0: begin
  924.                        LastVisibleDataSet:= DataLink.DataSet;
  925.                        First;
  926.                     end;
  927.  1: MoveBy(-CacheSize);
  928.  2: exit;
  929.  3: MoveBy(CacheSize);
  930.  4: begin
  931.                        LastVisibleDataSet:= DataLink.DataSet;
  932.                        Last;
  933.                     end;
  934.        end;}
  935.     end
  936.   end;
  937. SB_BOTTOM: begin
  938.            LastVisibleDataSet:= DataLink.DataSet;
  939.            Last;
  940.         end;
  941. SB_TOP: begin
  942.            LastVisibleDataSet:= DataLink.DataSet;
  943.            First;
  944.         end;
  945.       end;
  946.    end;
  947. end;
  948. (*
  949. procedure TfcDBCustomTreeView.WMVScroll(var Message: TWMVScroll);
  950. var DataLink: TfcTreeDataLink;
  951.   Function Sequencable: boolean;
  952.   begin
  953.      result:= DataLink.DataSet.isSequenced;
  954.   end;
  955.   procedure ParadoxPosition;
  956.   var recNum : Longint;
  957.       {$ifndef wwDelphi3Up}
  958.       recCount: Longint;
  959.       {$endif}
  960.   begin
  961.      with DataLink.DataSet do begin
  962.         recNum:= Message.Pos; // * recordCount) div GridScrollSize;
  963.         checkBrowseMode;
  964.         RecNo:= recNum;
  965.         LastVisibleDataSet:= DataLink.DataSet;
  966.         resync([]);
  967.      end;
  968.   end;
  969. begin
  970.   if not CanFocus then Exit;
  971.   if not HaveValidDataLinks then exit;
  972.   SetFocus;
  973.   DataLink:= TfcTreeDataLink(FDAtaLinks[0]);
  974.   if Datalink.Active then
  975.     with Message, DataLink.DataSet, Datalink do
  976.       case ScrollCode of
  977. SB_LINEUP: PriorRow(FScrollWithinLevel);
  978. SB_LINEDOWN: NextRow(FScrollWithinLevel);
  979. SB_PAGEUP: PriorPage(FScrollWithinLevel);
  980. SB_PAGEDOWN: NextPage(FScrollWithinLevel);
  981. SB_THUMBPOSITION:
  982.   begin
  983.     if Sequencable then begin
  984.        if pos<=1 then
  985.                   First
  986.        else if pos>=DataLink.DataSet.recordCount then
  987.                   Last
  988.        else ParadoxPosition;
  989.     end
  990.     else begin
  991.        case Pos of
  992.  0: First;
  993.  1: MoveBy(-CacheSize);
  994.  2: exit;
  995.  3: MoveBy(CacheSize);
  996.  4: Last;
  997.        end;
  998.     end
  999.   end;
  1000. SB_BOTTOM: Last;
  1001. SB_TOP: First;
  1002.       end;
  1003. end;
  1004. *)
  1005. Function TfcDBCustomTreeView.MultiSelectCheckboxNeeded(Node: TfcDBTreeNode): boolean;
  1006. begin
  1007.    with FMultiSelectAttributes do
  1008.       result:= Enabled and MultiSelectCheckbox and (ValidMultiSelectLevel(Node.Level))
  1009. end;
  1010. function TfcDBCustomTreeView.ValidMultiSelectLevel(ALevel: Integer): Boolean;
  1011. begin
  1012.   result := (FMultiSelectAttributes.MultiSelectLevel = ALevel) or
  1013.             (FMultiSelectAttributes.MultiSelectLevel = -1);
  1014. end;
  1015. constructor TfcDBMultiSelectAttributes.Create(Owner: TComponent);
  1016. begin
  1017.    TreeView:= Owner as TfcDBCustomTreeView;
  1018.    FAutoUnselect:= False;
  1019.    FMultiSelectCheckbox:= True;
  1020. end;
  1021. procedure TfcDBMultiSelectAttributes.Assign(Source: TPersistent);
  1022. var tsa: TfcDBMultiSelectAttributes;
  1023. begin
  1024.    If Source is TfcDBMultiSelectAttributes then
  1025.    begin
  1026.       tsa:= TfcDBMultiSelectAttributes(Source);
  1027.       Enabled:= tsa.Enabled;
  1028.       MultiSelectCheckbox:= tsa.MultiSelectCheckbox;
  1029.       MultiSelectLevel:= tsa.MultiSelectLevel;
  1030.    end
  1031.    else inherited Assign(Source);
  1032. end;
  1033. procedure TfcDBMultiSelectAttributes.SetEnabled(val: boolean);
  1034. //var Node: TfcDBTreeNode;
  1035. begin
  1036.    if val<>FEnabled then
  1037.    begin
  1038.       FEnabled:= val;
  1039.       TreeView.invalidateClient;
  1040.    end
  1041. end;
  1042. procedure TfcDBMultiSelectAttributes.SetMultiSelectCheckBox(val: boolean);
  1043. begin
  1044.    if val<>FMultiSelectCheckbox then
  1045.    begin
  1046.       FMultiSelectCheckbox:= val;
  1047.       TreeView.invalidateClient;
  1048.    end
  1049. end;
  1050. procedure TfcDBMultiSelectAttributes.SetMultiSelectLevel(val: integer);
  1051. begin
  1052.    if val<>FMultiSelectLevel then
  1053.    begin
  1054.       FMultiSelectLevel:= val;
  1055.       (TreeView as TfcDBCustomTreeView).UnselectAll;
  1056.       TreeView.InvalidateClient;
  1057.    end
  1058. end;
  1059. {$ifdef fcDelphi4Up}
  1060. procedure TfcDBCustomTreeView.SelectAll(ADataSet: TDataSet);
  1061. var saveBK : TBookmark;
  1062.     MultiSelectItem: TfcMultiSelectItem;
  1063. begin
  1064.    UnselectAll;
  1065.    with ADataset do
  1066.    begin
  1067.       saveBK := GetBookmark;  { Save current record position }
  1068.       CheckBrowseMode;  { bookmarks don't work in edit mode }
  1069.       DisableControls;
  1070.       First;
  1071.       while (not Eof) do begin
  1072.          MultiSelectItem:= TfcMultiSelectItem.create;
  1073.          with MultiSelectItem do
  1074.          begin
  1075.             Bookmark:= GetBookmark;
  1076.             DataSet:= ADataSet;
  1077.          end;
  1078.          FMultiSelectList.Add(MultiSelectItem);
  1079.          Next;
  1080.       end;
  1081.       GotoBookmark(saveBK);  { Restore original record position}
  1082.       Freebookmark(saveBK);
  1083.       EnableControls;
  1084.    end
  1085. end;
  1086. {$endif}
  1087. procedure TfcDBCustomTreeView.UnselectAll;
  1088. var i: integer;
  1089. begin
  1090.    for i:= 0 to FMultiSelectList.Count-1 do
  1091.    begin
  1092.       FreeMem(MultiSelectList[i].Bookmark); { 5/20/00 - Don't reference dataset in case its already been destroyed }
  1093. //      MultiSelectList[i].DataSet.Freebookmark(MultiSelectList[i].Bookmark);
  1094.       MultiSelectList[i].Free;
  1095.    end;
  1096.    FMultiSelectList.Clear;
  1097.    if not (csDestroying in ComponentState) then InvalidateClient; { 2/14/2000 }
  1098. end;
  1099. procedure TfcDBCustomTreeView.SelectRecord;
  1100. var MultiSelectItem: TfcMultiSelectItem;
  1101. begin
  1102.   MultiSelectItem:= TfcMultiSelectItem.create;
  1103.   with MultiSelectItem do
  1104.   begin
  1105.      ActiveDataSet.CheckBrowseMode;  { bookmarks don't work in edit mode }
  1106.      if IsSelectedRecord then exit;
  1107.      Bookmark:= ActiveDataSet.GetBookmark;
  1108.      DataSet:= ActiveDataSet;
  1109.   end;
  1110.   FMultiSelectList.Add(MultiSelectItem);
  1111.   InvalidateClient;
  1112. end;
  1113. Procedure TfcDBCustomTreeView.UnselectRecord;
  1114. var MultiSelectItem: TfcMultiSelectItem;
  1115.     MultiSelectItemIndex: integer;
  1116. begin
  1117.     MultiSelectItemIndex:= FindCurrentMultiSelectIndex(ActiveDataSet);
  1118.     if MultiSelectItemIndex<0 then exit; { Can't unselect since its not selected }
  1119.     MultiSelectItem:= MultiSelectList[MultiSelectItemIndex];
  1120.     MultiSelectItem.DataSet.Freebookmark(MultiSelectItem.Bookmark);
  1121.     MultiSelectItem.Free;
  1122.     FMultiSelectList.Delete(MultiSelectItemIndex);
  1123.     InvalidateClient;
  1124. end;
  1125. Function TfcDBCustomTreeView.IsSelectedRecord: boolean;
  1126. begin
  1127.    result:= FindCurrentMultiSelectIndex(ActiveDataSet)>=0;
  1128. end;
  1129. Function TfcDBCustomTreeView.FindCurrentMultiSelectIndex(DataSet: TDataSet): integer;
  1130. var i: integer;
  1131.     curBookmark: Tbookmark;
  1132.     thisTable: TDataset;
  1133.     res: CmpBkmkRslt;
  1134. begin
  1135.    thisTable:= DataSet;
  1136.    if (thisTable.state=dsEdit) or (thisTable.state=dsInsert) then begin
  1137.       result:= -1;
  1138.       exit;
  1139.    end;
  1140.    curBookmark:= thisTable.getBookmark;
  1141.    result:= -1;
  1142.    if curBookmark=Nil then exit;
  1143.    for i:= 0 to FMultiSelectList.count-1 do begin
  1144.       if thisTable<>MultiSelectList[i].DataSet then continue;
  1145.       if MultiSelectList[i]=nil then continue;
  1146.       res:= thisTable.CompareBookmarks(MultiSelectList[i].Bookmark, curBookmark);
  1147.       if (res=CMPKeyEql) or (res=CMPEql) then begin
  1148.          result:= i;
  1149.          break;
  1150.       end
  1151.    end;
  1152.    thisTable.freebookmark(curBookmark);
  1153. end;
  1154. function TfcDBCustomTreeView.GetMultiSelectItem(Index: integer): TfcMultiSelectItem;
  1155. begin
  1156.    result:= TfcMultiSelectItem(FMultiSelectList[Index]);
  1157. end;
  1158. procedure TfcDBCustomTreeView.CMFontChanged(var Message: TMessage);
  1159. begin
  1160.   inherited;
  1161.   LayoutChanged;
  1162. end;
  1163. procedure TfcDBCustomTreeView.LayoutChanged;
  1164. var i: Integer;
  1165.     DataLink: TfcTreeDataLink;
  1166. //    SINew: TScrollInfo;
  1167.     NewCacheSize: integer;
  1168. begin
  1169.   Canvas.Font := Font;
  1170.   RowHeight:= Canvas.Textheight('W') + 2;
  1171.   RowHeight:= fcmax(RowHeight, 16);
  1172.   if StateImages<>nil then
  1173.      RowHeight:= fcmax(RowHeight, TImageList(StateImages).Height);
  1174.   if Images<>nil then
  1175.      RowHeight:= fcmax(RowHeight, TImageList(Images).Height);
  1176.   RowHeight:= ((RowHeight+1) div 2) * 2; { Row height must be even }
  1177.   if BorderStyle=bsNone then  { 5/25/99 }
  1178.      NewCacheSize:= Height div RowHeight
  1179.   else
  1180.      NewCacheSize:= (Height-4) div RowHeight;
  1181.   if (dtvoShowHorzScrollBar in Options) and HandleAllocated then begin
  1182.      if HorzScrollBar.PageSize<HorzScrollBar.Max then
  1183.      begin
  1184.         if BorderStyle=bsNone then  { 5/25/99 }
  1185.            NewCacheSize:= (Height-GetSystemMetrics(SM_CYHSCROLL)) div RowHeight
  1186.         else
  1187.            NewCacheSize:= (Height-GetSystemMetrics(SM_CYHSCROLL) - 4) div RowHeight
  1188.      end
  1189.   end;
  1190.   if NewCacheSize<>CacheSize then begin
  1191.      CacheSize:= NewCacheSize;
  1192.      for i:= 0 to FDataLinks.Count-1 do
  1193.      begin
  1194.         DataLink:= TfcTreeDataLink(FDataLinks[i]);
  1195. //        if DataLink.Active then  { 3/31/99- Still set BufferCount so that its accurate}
  1196.         begin
  1197.            DataLink.BufferCount:= CacheSize;
  1198.         end
  1199.      end;
  1200.   end;
  1201.   if InPaint then
  1202.      CheckMaxWidthGrow:= True { 3/10/99 }
  1203.   else
  1204.      CheckMaxWidth:= True;
  1205.   InvalidateClient;
  1206. end;
  1207. procedure TfcDBCustomTreeView.Loaded;
  1208. begin
  1209.   inherited Loaded;
  1210.   if DataSources<>'' then
  1211.      RefreshDataLinks(FFirstDataLink.DataSource, FLastDataLink.DataSource);
  1212.   LayoutChanged;
  1213. end;
  1214. procedure TfcDBCustomTreeView.FreeHintWindow;
  1215. begin
  1216.    HintTimerCount:= 0;
  1217.    SkipErase:= True;
  1218.    HintWindow.Free;
  1219.    SkipErase:= False;
  1220.    HintWindow:= nil;
  1221.    if HintTimer<>nil then
  1222.       HintTimer.enabled:= False;
  1223. //   LastHintRow:= -1;
  1224. end;
  1225. procedure TfcDBCustomTreeView.HintTimerEvent(Sender: TObject);
  1226. var
  1227.     sp, cp: TPoint;
  1228.     OutsideClient: boolean;
  1229. begin
  1230.    if (dtvoHotTracking in Options) or (HintWindow<>nil) then
  1231.    begin
  1232.       GetCursorPos(cp);
  1233.       sp:= self.ClientToScreen(Point(0, 0));
  1234.       if (cp.x<sp.x) or (cp.x>sp.x+ClientRect.Right-ClientRect.Left) or
  1235.          (cp.y<sp.y) or (cp.y>sp.y+ClientRect.Bottom-ClientRect.Top) then
  1236.       begin
  1237.          OutsideClient:= True;
  1238.       end
  1239.       else OutsideClient:= False;
  1240.    end
  1241.    else exit;
  1242.    if (dtvoHotTracking in Options) then
  1243.    begin
  1244.       if Outsideclient and (HotTrackRow>=0) then
  1245.          InvalidateClient;
  1246.       exit; { Don't display hint window if hot-tracking }
  1247.    end;
  1248.    { Process Hint Timer clean-up}
  1249.    if OutsideClient then
  1250.    begin
  1251.       FreeHintWindow;
  1252.       LastHintRow:= -1;
  1253.       exit;
  1254.    end;
  1255.    inc(HintTimerCount);
  1256.    if HintTimerCount>16 then
  1257.    begin
  1258.       FreeHintWindow;
  1259.       exit;
  1260.    end;
  1261. end;
  1262. procedure TfcDBCustomTreeView.MouseMove(Shift: TShiftState; X, Y: Integer);
  1263. var Row: integer;
  1264.     Node: TfcDBTreeNode;
  1265.     R: TRect;
  1266.     SP: TPoint;
  1267.     HintText: string;
  1268.     DoDefault: boolean;
  1269.     ValidNode: boolean;
  1270. begin
  1271.    inherited MouseMove(Shift, X, Y);
  1272.    if not (Assigned(FOnMouseMove) or (dtvoShowNodeHint in Options)) then exit;
  1273.    sp:= self.ClientToScreen(Point(0, 0));
  1274.    MouseToRow(X, Y, Row);
  1275.    ValidNode:= RowToNode(Row, Node);
  1276.    if (dtvoHotTracking in Options) and ValidNode then begin
  1277.       if (Row<>HotTrackRow) then
  1278.       begin
  1279.          InvalidateClient;
  1280.          HotTrackRow:= Row;
  1281.       end
  1282.       else begin
  1283.          InvalidateClient;
  1284.       end;
  1285.       FreeHintWindow;
  1286.       HintTimer.Free;
  1287.       HintTimer:= nil;
  1288.       HintTimer:= TTimer.create(self);
  1289.       HintTimer.OnTimer:=HintTimerEvent;
  1290.       HintTimer.Interval:=250;
  1291.       HintTimer.Enabled:= True;
  1292.       if Assigned(FOnMouseMove) then FOnMouseMove(self, Node, Shift, X, Y);
  1293.       exit;
  1294.    end;
  1295.    if Assigned(FOnMouseMove) then FOnMouseMove(self, Node, Shift, X, Y);
  1296.    if not ValidNode then exit;
  1297.    if not (dtvoShowNodeHint in Options) then exit;
  1298.    if Header<>nil then exit; // Currently do not support hints when have header control
  1299.    { Show hint window on node that mouse is over}
  1300.    sp:= self.ClientToScreen(Point(0, 0));
  1301.    MouseToRow(X, Y, Row);
  1302.    if not RowToNode(Row, Node) then exit;
  1303.    if (x < LevelRect(Node).Right) then exit;
  1304.    if (Row<>LastHintRow) and (Row>=0) then begin
  1305.       FreeHintWindow;
  1306.       HintTimer.Free;
  1307.       HintTimer:= nil;
  1308.       if TextRect(Node, Row).Left+Canvas.TextWidth(Node.Text)>
  1309.          Width-GetSystemMetrics(SM_CXHThumb)-6 then
  1310.       begin
  1311.          HintWindow:= CreateHintWindow;
  1312.          HintTimer:= TTimer.create(self);
  1313.          HintTimer.OnTimer:=HintTimerEvent;
  1314.          HintTimer.Interval:=250;
  1315.          HintTimer.Enabled:= True;
  1316.          with HintWindow do
  1317.          begin
  1318.             R:= TextRect(Node, Row);
  1319. //            R.Left:= r.left + sp.x - 2 - GetScrollPos(self.Handle, SB_HORZ);
  1320.             R.Left:= r.left + sp.x - 2 - HorzScrollBar.position; //GetScrollPos(self.Handle, SB_HORZ);
  1321.             R.Right:= r.Right + sp.x + 2;
  1322.             if not odd(fcRectHeight(R) div 2) then
  1323.             begin
  1324.                R.Top:= R.Top + sp.y - 3;
  1325.                R.Bottom:= R.Bottom + sp.y - 3;
  1326.             end
  1327.             else begin
  1328.                R.Top:= R.Top + sp.y - 2;
  1329.                R.Bottom:= R.Bottom + sp.y - 2;
  1330.             end;
  1331.             HintText:= Node.Text;
  1332.             DoDefault:= True;
  1333. //            DoActivateHint(HintWindow, Node, HintText, DoDefault);
  1334.             if DoDefault then begin
  1335.               R.Right:= R.Left + FPaintCanvas.TextWidth(HintText) + 6;
  1336.               ActivateHint(R, HintText);
  1337.             end;
  1338.          end;
  1339.       end;
  1340.       LastHintRow:= Row;
  1341.    end
  1342. end;
  1343. procedure TfcDBCustomTreeView.InvalidateRow(Row: integer);
  1344. var r: TRect;
  1345. begin
  1346.    r.Top:= Row * RowHeight;
  1347.    r.Bottom:= (Row+1) * RowHeight -1;
  1348.    r.Left:= 0;
  1349.    r.Right:= GetClientRect.Right; //Width;
  1350.    InvalidateRect(Handle, @r, True);
  1351. end;
  1352. procedure TfcDBCustomTreeView.InvalidateNode(Node: TfcDBTreeNode);
  1353. var r: TRect;
  1354. begin
  1355.    r:= LevelRect(Node);
  1356.    r.Left:= 0;
  1357.    r.Right:= Width;
  1358.    InvalidateRect(Handle, @r, True);
  1359. end;
  1360. function TfcDBCustomTreeView.GetMultiSelectListCount: integer;
  1361. begin
  1362.   result:= FMultiSelectList.Count;
  1363. end;
  1364. procedure TfcDBCustomTreeView.Change(FSelected: TfcDBTreeNode);
  1365. begin
  1366.    if Assigned(FOnChange) then
  1367.       FOnChange(Self, FSelected);
  1368. end;
  1369. procedure TfcDBCustomTreeView.DoUserExpand(Node: TfcDBTreeNode);
  1370. begin
  1371.    if Assigned(FOnUserExpand) then
  1372.       FOnUserExpand(Self, Node);
  1373. end;
  1374. procedure TfcDBCustomTreeView.DoUserCollapse(Node: TfcDBTreeNode);
  1375. begin
  1376.    if Assigned(FOnUserCollapse) then
  1377.       FOnUserCollapse(Self, Node);
  1378. end;
  1379. {procedure TfcDBCustomTreeView.DoActivateHint(
  1380.    HintWindow: THintWindow; FSelected: TfcDBTreeNode;
  1381.    var HintText: string; var DoDefault: boolean);
  1382. begin
  1383.    if Assigned(FOnActivateHint) then
  1384.    begin
  1385.       DoDefault:= True;
  1386.       FOnActivateHint(Self, HintWindow, FSelected, HintText, DoDefault);
  1387.    end
  1388. end;
  1389. }
  1390. type
  1391.   TfcDBTreeHintWindow=class(THintWindow)
  1392.   protected
  1393.      procedure Paint; override;
  1394. //  public
  1395. //     Node: TfcTreeNode;
  1396.   end;
  1397. procedure TfcDBTreeHintWindow.Paint;
  1398. var
  1399.   R: TRect;
  1400. begin
  1401.   R := ClientRect;
  1402.   Inc(R.Left, 2);
  1403.   Inc(R.Top, 2);
  1404.   Canvas.Font.Color := clInfoText;
  1405.   SetBkMode(Canvas.Handle, TRANSPARENT);
  1406.   DrawText(Canvas.Handle, PChar(Caption), -1, R, DT_LEFT or DT_NOPREFIX or
  1407.     DT_WORDBREAK);
  1408. end;
  1409. Function TfcDBCustomTreeView.CreateHintWindow: THintWindow;
  1410. begin
  1411.    HintWindow:= TfcDBTreeHintWindow.create(self);
  1412.    HintWindow.Color:= GetSysColor(COLOR_INFOBK);
  1413.    HintWindow.Canvas.Brush.Color:= GetSysColor(COLOR_INFOBK);
  1414.    HintWindow.Canvas.Font:= self.Font;
  1415.    HintWindow.Canvas.Font.Color:= GetSysColor(COLOR_INFOTEXT);
  1416.    HintWindow.Canvas.Pen.Color:= clBlack;
  1417.    result:= HintWindow;
  1418. end;
  1419. Function TfcDBCustomTreeView.GetStateImageWidth: integer;
  1420. begin
  1421.    if StateImages<>nil then result:= TImageList(StateImages).Width
  1422.    else result:= 16;
  1423. end;
  1424. Function TfcDBCustomTreeView.HaveValidDataLinks: boolean;
  1425. var i: Integer;
  1426. begin
  1427.    result:= FDataLinks.Count>0;
  1428.    for i:= 0 to FDataLinks.count-1 do
  1429.    begin
  1430.       if TfcTreeDataLink(FDataLinks[i]).DataSet=nil then result:= False;
  1431.       if not TfcTreeDataLink(FDataLinks[i]).Active then result:= False;
  1432.    end;
  1433. {
  1434.    result:= false;
  1435.    if FDataLinks.count<=0 then exit;
  1436.    DataLink:= TfcTreeDataLink(FDataLinks[0]);
  1437.    if datalink.dataset = nil then exit;
  1438.    if not datalink.active then exit;
  1439.    result:= true;}
  1440. end;
  1441. Procedure TfcDBCustomTreeView.ToggleMultiSelection(
  1442.        RequireControlKey: boolean; Shift: TShiftState);
  1443. begin
  1444.    if (ActiveNode<>nil) then begin
  1445.        if MultiSelectAttributes.Enabled and
  1446.           (ValidMultiSelectLevel(ActiveNode.Level)) then
  1447.        begin
  1448.           if RequireControlKey then
  1449.           begin
  1450.              if (ssCtrl in Shift) then
  1451.              begin
  1452.                 if IsSelectedRecord then UnselectRecord
  1453.                 else SelectRecord;
  1454.              end;
  1455.           end
  1456.           else begin
  1457.              if IsSelectedRecord then UnselectRecord
  1458.              else SelectRecord;
  1459.           end
  1460.        end;
  1461.     end;
  1462. end;
  1463. procedure TfcDBCustomTreeView.WMSize(var Message: TWMSize);
  1464. begin
  1465.   inherited;
  1466.   ResetScroll:= True;
  1467.   UpdateScrollBarPosition;
  1468.   LayoutChanged;
  1469. end;
  1470. {$ifdef fcDelphi4Up}
  1471. procedure TfcDBCustomTreeView.SetHideUpDownButtons(val: boolean);
  1472. begin
  1473.    if val<>FHideUpDownButtons then
  1474.    begin
  1475.       FHideUpDownButtons:=val;
  1476.       UpTreeButton.visible:= not val;
  1477.       DownTreeButton.visible:= not val;
  1478.       UpdateScrollBarPosition;
  1479.    end
  1480. end;
  1481. {$endif}
  1482. procedure TfcDBCustomTreeView.UpdateScrollBarPosition;
  1483. var
  1484.    VertHeight: integer;
  1485. //   curBottom: integer;
  1486.    ButtonHeight: integer;
  1487. begin
  1488.   { 5/25/99 - Fix BorderStyle=bsNone bug where horizontal scrollbar and
  1489.     buttons drawn in wrong position }
  1490.   ButtonHeight := GetSystemMetrics(SM_CXVSCROLL) + 1;
  1491.   if (VertScrollBar<>nil) then
  1492.   begin
  1493.      if BorderStyle=bsNone then
  1494.         VertHeight:= Height
  1495.      else
  1496.         VertHeight:= Height - 4;
  1497.      {$ifdef fcDelphi4Up}
  1498.      if UpTreeButton.visible and (not FHideUpDownButtons) then
  1499.      {$else}
  1500.      if UpTreeButton.visible then
  1501.      {$endif}
  1502.         VertHeight:= VertHeight - ButtonHeight + 1;
  1503.      VertScrollBar.Height:= VertHeight;
  1504.      VertScrollBar.Width:= ButtonHeight - 1;
  1505.      VertScrollBar.Left:= GetClientRect.Right;
  1506.   end;
  1507.   if (HorzScrollBar<>nil) then with HorzScrollBar do
  1508.   begin
  1509.      Left:=  0;
  1510.      if VertScrollBar.visible then
  1511.      begin
  1512.        if BorderStyle=bsNone then
  1513.           Width:= fcMax(0, self.Width - VertScrollBar.Width)
  1514.        else
  1515.           Width:= fcMax(0, self.Width - 4 - VertScrollBar.Width);
  1516.      end
  1517.      else begin
  1518.        if BorderStyle=bsNone then
  1519.           Width:= fcMax(0, self.Width)
  1520.        else
  1521.           Width:= fcMax(0, self.Width - 4);
  1522.      end;
  1523.      Height:=
  1524.         GetSystemMetrics(SM_CYHSCROLL);
  1525.      if BorderStyle=bsNone then
  1526.        Top:= self.Height - Height
  1527.      else
  1528.        Top:= self.Height - Height - 4;
  1529.   end;
  1530.   with UpTreeButton do
  1531.   begin
  1532.      Height:= ButtonHeight;
  1533.      Width:= ButtonHeight;
  1534.      Top:= VertScrollBar.height;
  1535.      Left:= VertScrollBar.Left;
  1536.   end;
  1537.   with DownTreeButton do
  1538.   begin
  1539.      Height:= ButtonHeight;
  1540.      Width:= ButtonHeight;
  1541.      Top:= VertScrollBar.height;
  1542.      Left:= VertScrollBar.Left;
  1543.   end;
  1544. end;
  1545. procedure TfcDBCustomTreeView.SetLevelIndent(val: integer);
  1546. begin
  1547.    if FLevelIndent<>val then
  1548.    begin
  1549.       FLevelIndent:= val;
  1550.       InvalidateClient;
  1551.    end
  1552. end;
  1553. procedure TfcDBCustomTreeView.SetDisplayFields(Value: TStrings);
  1554. begin
  1555.    FDisplayFields.Assign(Value);
  1556.    InvalidateClient;
  1557. end;
  1558. procedure TfcDBCustomTreeView.MakeActiveDataSet(DataSet: TDataSet; Collapse: boolean);
  1559. begin
  1560. //   self.Update;  { Finish painting operations }
  1561.    ActiveDataSet:= DataSet;
  1562.    if Collapse then LastVisibleDataSet:= DataSet
  1563.    else begin
  1564.       if IsMasterDataSetOfActive(LastVisibleDataSet) then
  1565.          LastVisibleDataSet:= DataSet;
  1566.    end;
  1567.    invalidateClient;
  1568. end;
  1569. { Make room for scroll bar if its shown }
  1570. function TfcDBCustomTreeView.GetClientRect: TRect;
  1571. begin
  1572.    result:= inherited GetClientRect;
  1573.    if (VertScrollBar<>nil) and (VertScrollBar.visible) then
  1574.    begin
  1575.       result.Right:= result.Right - VertScrollBar.Width;
  1576.    end;
  1577.    if InComputeHorzWidthOnly then exit;
  1578.    if (HorzScrollBar<>nil) and
  1579.       (HorzScrollBar.Max-HorzScrollBar.Min>HorzScrollBar.PageSize) then
  1580.    begin
  1581.       result.Bottom:= result.Bottom - HorzScrollBar.Height;
  1582.       if not HorzScrollBar.visible then begin
  1583.          HorzScrollBar.visible:= True;
  1584.          LayoutChanged;
  1585.          HorzScrollBar.invalidate;
  1586.       end
  1587.    end
  1588.    else begin
  1589.       if HorzScrollBar.visible then begin
  1590.          HorzScrollBar.visible:= False;
  1591.          HorzScrollBar.Max:= 5;
  1592.          HorzScrollBar.PageSize:= 10;
  1593.          LayoutChanged;
  1594.       end
  1595.    end;
  1596. end;
  1597. procedure TfcDBCustomTreeView.InvalidateClient;
  1598. var r: TRect;
  1599. begin
  1600.    if not HandleAllocated then exit;
  1601.    r:= GetClientRect;
  1602.    InvalidateRect(Handle, @r, False);
  1603. end;
  1604. procedure TfcDBCustomTreeView.TreeUpClick(Sender : TObject);
  1605. begin
  1606.    if ActiveNode=nil then exit;
  1607.    
  1608.    if (ActiveNode.Parent<>nil) then
  1609.       Collapse(ActiveNode.Parent)
  1610.    else
  1611.       Collapse(ActiveNode);
  1612. end;
  1613. procedure TfcDBCustomTreeView.TreeDownClick(Sender : TObject);
  1614. begin
  1615.    Expand(ActiveNode);
  1616. end;
  1617. procedure TfcTreeVertScrollBar.Scroll(ScrollCode: integer; Position: integer);
  1618. begin
  1619.    inherited;
  1620.    (Parent as TfcDBCustomTreeView).VScroll(ScrollCode, Position);
  1621. end;
  1622. procedure TfcTreeHorzScrollBar.Scroll(ScrollCode: integer; Position: integer);
  1623. begin
  1624.    inherited;
  1625.    (Parent as TfcDBCustomTreeView).HScroll(ScrollCode, Position);
  1626. end;
  1627. function TfcDBCustomTreeView.CreateUpTreeButton: TfcShapeBtn;
  1628. var bm: TBitmap;
  1629.     resName: string;
  1630. begin
  1631.    UpTreeButton:= TfcShapeBtn.create(self);
  1632.    with UpTreeButton do begin
  1633.      Width := 17;
  1634.      Height := 17;
  1635.      Color := clBtnFace;
  1636.      Orientation := soUp;
  1637.      PointList.Add('0,0');
  1638.      PointList.Add('Width,0');
  1639.      PointList.Add('0,Height');
  1640.      PointList.Add('0,0');
  1641.      ShadeColors.Btn3DLight := clWhite;
  1642.      ShadeColors.BtnHighlight := clBtnFace;
  1643.      ShadeColors.BtnBlack := clBlack;
  1644.      Shape := bsCustom;
  1645.      TabStop:= False;
  1646.      offsets.glyphx:= 1;
  1647.      offsets.glyphy:= 1;
  1648.      bm := TBitmap.Create;
  1649.      bm.Transparent := True;
  1650.      resName:= 'FCTREEUP';
  1651.      bm.LoadFromResourceName(HINSTANCE, resName);
  1652.      glyph.assign(bm);
  1653.      bm.Free;
  1654.      parent:= self;
  1655.      OnClick:= TreeUpClick;
  1656.    end;
  1657.    result:= UpTreeButton;
  1658. end;
  1659. function TfcDBCustomTreeView.CreateDownTreeButton: TfcShapeBtn;
  1660. var bm: TBitmap;
  1661.     resName: string;
  1662. begin
  1663.    DownTreeButton:= TfcShapeBtn.create(self);
  1664.    with DownTreeButton do begin
  1665.      Width := 17;
  1666.      Height := 17;
  1667.      Color := clBtnFace;
  1668.      Orientation := soDown;
  1669.      PointList.Add('0,0');
  1670.      PointList.Add('Width,0');
  1671.      PointList.Add('0,Height');
  1672.      PointList.Add('0,0');
  1673.      Shape := bsCustom;
  1674.      TabStop:= False;
  1675.      offsets.glyphx:= 6;
  1676.      offsets.glyphy:= 6;
  1677.      bm := TBitmap.Create;
  1678.      bm.Transparent := True;
  1679.      resName:= 'FCTREEDOWN';
  1680.      bm.LoadFromResourceName(HINSTANCE, resName);
  1681.      glyph.assign(bm);
  1682.      bm.Free;
  1683.      parent:= self;
  1684.      OnClick:= TreeDownClick;
  1685.    end;
  1686.    result:= DownTreeButton;
  1687. end;
  1688. procedure TfcDBCustomTreeView.DrawColumnText(
  1689.          Node: TfcDBTreeNode; ARect: TRect);
  1690. const
  1691.   AlignFlags : array [TAlignment] of Integer =
  1692.     ( DT_LEFT or DT_END_ELLIPSIS,
  1693.       DT_RIGHT or DT_END_ELLIPSIS,
  1694.       DT_CENTER or DT_END_ELLIPSIS);
  1695. var i,DrawFlags: integer;
  1696.     s:String;
  1697.     TempRect:TRect;
  1698. //    l, r: integer;
  1699.     RootDataSet: TDataSet;
  1700.     curField: TField;
  1701.     OrigColor: TColor;
  1702.     OrigFontColor: TColor;
  1703.     DoDefault: boolean;
  1704. begin
  1705.   TempRect:=ARect;
  1706.   TempRect.Right := ClientWidth + HorzScrollBar.position;
  1707.   TempRect.Top := TempRect.Top-1;
  1708.   TempRect.Bottom := TempRect.Bottom+1;
  1709. //  Canvas.FillRect(TempRect);  // Comment as it does not work with imager, and
  1710.                                 // seems uncessary otherwise.  If there is a problem
  1711.                                 // with commenting out, then check if imager assigned.
  1712.   OrigColor:= Canvas.Brush.Color;
  1713.   OrigFontColor:= Canvas.Font.Color;
  1714.   RootDataSet:= TfcTreeDataLink(FDataLinks[0]).DataSet;
  1715.   if (RootDataSet=nil) then exit;
  1716. //  ARect.Right := Header.Sections[0].Width-5;
  1717.   for i:=0 to Header.Sections.count-1 do begin
  1718.      curField:= RootDataSet.FindField(Header.Sections[i].FieldName);
  1719.      if curField<>nil then
  1720.         DrawFlags:= AlignFlags[curField.Alignment]
  1721.      else
  1722.         DrawFlags:= AlignFlags[taLeftJustify];
  1723.      ARect.Right:= Header.Sections[i].right;
  1724.      if i>0 then ARect.Left:= Header.Sections[i].Left;
  1725.      s:= fcGetToken(Node.Text, #9, i);
  1726.      ARect.Top:= ARect.Top-1;
  1727.      ARect.Bottom:= ARect.Bottom+1;
  1728.      Canvas.Font.Color:= OrigFontColor;
  1729.      Canvas.Brush.Color:= OrigColor;
  1730.      DoCalcSectionAttributes(Node, Header.Sections[i], S);
  1731.      if OrigColor<>Canvas.Brush.Color then
  1732.         FPaintCanvas.FillRect(ARect);
  1733.      ARect.Right:= ARect.Right-2;
  1734.      ARect.Left:= ARect.Left+2;
  1735.      ARect.Top:= ARect.Top+1;
  1736.      ARect.Bottom:= ARect.Bottom-1;
  1737.      DoDefault:= True;
  1738.      DoDrawSection(Node, Header.Sections[i], ARect, S, DoDefault);
  1739.      if DoDefault then
  1740.         DrawText(Canvas.Handle,PChar(s), length(s), ARect, DrawFlags);
  1741. {     ARect.Left := ARect.Right+8;
  1742.      if I<> Header.Sections.Count-1 then
  1743.        ARect.Right := ARect.Left+Header.Sections[i+1].Width-5;}
  1744.   end;
  1745. end;
  1746. procedure TfcDBCustomTreeView.DoDrawText(TreeView: TfcDBCustomTreeView;
  1747.          Node: TfcDBTreeNode; ARect: TRect;
  1748.          var DefaultDrawing: boolean);
  1749. begin
  1750.    DefaultDrawing:= True;
  1751.    if Assigned(FOnDrawText) then FOnDrawText(Self, Node, ARect, defaultDrawing);
  1752. end;
  1753. procedure TfcDBCustomTreeView.WMNCHitTest(var Message: TWMNCHitTest);
  1754. begin
  1755.   DefaultHandler(Message);
  1756. end;
  1757. //procedure TfcdbCustomTreeView.CMDesignHitTest(var Message: TCMDesignHitTest);
  1758. //begin
  1759. //   message.result:= 1;
  1760. //   inherited;
  1761. //end;
  1762. procedure TfcDBCustomTreeView.WndProc(var Message: TMessage);
  1763. begin
  1764. {   if (csDesigning in ComponentState) then
  1765.    begin
  1766.       if (Message.Msg = wm_lbuttondown) then
  1767.       begin
  1768.          ControlState := ControlState + [csLButtonDown];
  1769.          Dispatch(Message);
  1770.          exit;
  1771.       end;
  1772.    end;
  1773. }
  1774.   inherited WndProc(Message);
  1775. end;
  1776. Function TfcDBCustomTreeView.GetNodeAt(X,Y: integer): TfcDBTreeNode;
  1777. var Row: integer;
  1778. begin
  1779.    MouseToRow(X, Y, Row);
  1780.    if not RowToNode(Row, Result) then Result:= nil;
  1781. end;
  1782. Function TfcDBTreeNode.GetFieldValue(FieldName: string): Variant;
  1783. var PrevActiveRecord: integer;
  1784.     curField: TField;
  1785. begin
  1786.    PrevActiveRecord:= DataLink.ActiveRecord;
  1787.    DataLink.ActiveRecord:= ActiveRecord;
  1788.    curField:= DataSet.FindField(FieldName);
  1789.    if curField=nil then result:= NULL
  1790.    else result:= curField.Value;
  1791.    DataLink.ActiveRecord:= PrevActiveRecord;
  1792. end;
  1793. procedure TfcDBCustomTreeView.Notification(AComponent: TComponent;
  1794.   Operation: TOperation);
  1795. begin
  1796.   inherited Notification(AComponent, Operation);
  1797.   if (Operation = opRemove) then
  1798.   begin
  1799.      if AComponent = Header then Header:= nil;
  1800.      if AComponent = Images then Images := nil;
  1801.      if AComponent = StateImages then StateImages := nil;
  1802.      if (AComponent = FImager) then FImager := nil
  1803.   end;
  1804. end;
  1805. { Sorts by level, and then by bookmark order }
  1806. procedure TfcDBCustomTreeView.SortMultiSelectList;
  1807. var res: CmpBkmkRslt;
  1808.    Function LessThan(item1, item2: TfcMultiSelectItem): boolean;
  1809.    begin
  1810.       if item1.DataSet = item2.DataSet then begin
  1811.          res:= (item1.DataSet as TDataSet).CompareBookmarks(item1.bookmark, item2.bookmark);
  1812.          result:= integer(res)=CmpLESS;
  1813.       end
  1814.       else begin
  1815.          result:= GetDataLinkIndex(item1.dataset)<GetDataLinkIndex(item2.dataset)
  1816.       end
  1817.    end;
  1818.    Function GreaterThan(item1, item2: TfcMultiSelectItem): boolean;
  1819.    begin
  1820.       if item1.DataSet = item2.DataSet then begin
  1821.          res:= (item1.DataSet as TDataSet).CompareBookmarks(item1.bookmark, item2.bookmark);
  1822.          result:= integer(res)=CmpGtr;
  1823.       end
  1824.       else begin
  1825.          result:= GetDataLinkIndex(item1.dataset)>GetDataLinkIndex(item2.dataset)
  1826.       end
  1827.    end;
  1828.    procedure Partition(var i, j: integer);
  1829.    var Pivot, Temp: TfcMultiSelectItem;
  1830.    begin
  1831.       Pivot:= MultiSelectList[(i+j) div 2];
  1832.       repeat
  1833.          while LessThan(MultiSelectList[i], Pivot) do i:= i + 1;
  1834.          while GreaterThan(MultiSelectList[j], Pivot) do j:= j - 1;
  1835.          if (i<=j) then begin
  1836.             Temp:= FMultiSelectList[i];
  1837.             FMultiSelectList[i]:= FMultiSelectList[j];
  1838.             FMultiSelectList[j]:= Temp;
  1839.             i:= i +1;
  1840.             j:= j-1;
  1841.          end
  1842.       until (i>j);
  1843.    end;
  1844.    procedure QuickSort(m, n: integer);
  1845.    var i,j: integer;
  1846.    begin
  1847.       if (m<n) then begin
  1848.          i:= m; j:= n;
  1849.          Partition(i, j);
  1850.          QuickSort(m,j);
  1851.          QuickSort(i,n);
  1852.       end
  1853.    end;
  1854. begin
  1855.     QuickSort(0, MultiSelectListCount-1);
  1856. end;
  1857. procedure TfcDBCustomTreeview.SetImager(Value: TfcCustomImager);
  1858. begin
  1859.   if FImager <> nil then FImager.UnRegisterChanges(FChangeLink);
  1860.   if Value <> nil then
  1861.   begin
  1862.     Value.FreeNotification(self);
  1863.     Value.RegisterChanges(FChangeLink);
  1864.     Value.Parent := self;
  1865.     if Value.DrawStyle <> dsStretch then
  1866.        Value.DrawStyle := dsTile;
  1867. //    Value.Align := alClient;
  1868.     Value.Visible := False;
  1869.     Value.Left:= 0;
  1870.     Value.Top:= 0;
  1871.     Value.Width:= 25;
  1872.     Value.Height:= 25;
  1873.   end;
  1874.   if Value<>FImager then InvalidateClient;
  1875.   FImager := Value;
  1876. end;
  1877. procedure TfcDBCustomTreeView.ImagerChange(Sender: TObject);
  1878. begin
  1879.   invalidate;
  1880. end;
  1881. {$ifdef fcDelphi4Up}
  1882. function TfcDBCustomTreeView.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
  1883. begin
  1884.   NextRow(dtvoKeysScrollLevelOnly in Options);
  1885.   result := True;
  1886. end;
  1887. function TfcDBCustomTreeView.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
  1888. begin
  1889.   PriorRow(dtvoKeysScrollLevelOnly in Options);
  1890.   result := True;
  1891. end;
  1892. {$endif}
  1893. procedure TfcDBCustomTreeView.SetHeader(Value: TFcTreeHeader);
  1894. begin
  1895.    if FHeader<>nil then
  1896.    begin
  1897.       TfcTreeHeader(Header).HeaderControl.Tree:=nil;
  1898.    end;
  1899.    FHeader:= Value;
  1900.    if Value<>nil then
  1901.       TfcTreeHeader(Value).HeaderControl.Tree:=self;
  1902. end;
  1903. function TfcDBCustomTreeView.ComputeHeaderWidth: integer;
  1904. var i: integer;
  1905.     NewMaxTextWidth: integer;
  1906. begin
  1907.    NewMaxTextWidth:= 0;
  1908.    with TfcTreeHeader(Header) do begin
  1909.       for i:= 0 to Sections.count-1 do
  1910.          NewMaxTextWidth:= NewMaxTextWidth + Sections[i].width;
  1911.    end;
  1912.    result:= NewMaxTextWidth;
  1913. end;
  1914. {procedure TfcDBCustomTreeView.WMHScroll(var Message: TWMHScroll);
  1915. begin
  1916.   inherited;
  1917.   exit;
  1918. end;
  1919. }
  1920. end.