
{                                                                              }
{  IB_DatasetBar                                                               }
{                                                                              }

{***************************************************************}
{                                                               }
{          IB Objects Components and Resources Library          }
{                                                               }
{          Copyright (C) 1996-2007 Jason Wharton                }
{          and Computer Programming Solutions, Mesa, AZ         }
{                                                               }
{  This source code unit is released under the terms of the     }
{  CPS Trustware License.                                       }
{  It may be distributed or deployed as source code or in       }
{  compiled form only in compliance with the terms and          }
{  conditions of the CPS Trustware License which may be         )
{  examined at http://www.ibobjects.com/ibo_trustware.html      )
{                                                               }
{***************************************************************}

{******************************************************************************}
{  CONTRIBUTED MODIFICATIONS                                                   }
{  Additions or modifications listed below using format:                       }
{                                                                              }
{  Joe Citizen <joe@joecitizen.com>                                            }
{  mm/dd/yyyy                                                                  }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{            Copyright (C) 2001 Joe Citizen                                    }
{                                                                              }
{------------------------------------------------------------------------------}
{  Place your credits and information in the top of the section                }
{  below with any other descriptions or explanations desired.                  }
{------------------------------------------------------------------------------}
{  Salvatore Besso <s.besso@mclink.it>                                         }
{  21-Jul-2006                                                                 }
{     Normalized procedure ResetButtonState so that it is the same in all      }
{     IB....bar.pas files. Made this change because not all bars worked with   }
{     custom glyphs                                                            }
{------------------------------------------------------------------------------}
{  Rade Vojvodic <rvojvodic@rsdef.org>                                         }
{  12/14/2005                                                                  }
{     Added propery ShowCaptions to enable Captions on the Bar                 }
{     Captions are to be read from IB_Constants.pas                            }
{            Copyright (C) 2005 Rade Vojvodic                                  }
{------------------------------------------------------------------------------}
{  Rade Vojvodic <rvojvodic@rsdef.org>                                         }
{  12/14/2005                                                                  }
{     Added protected CalcMinSize procedure and Changed AdjSize                }
{     procedure to work like in TDbNavigator. Buttons are placed               }
{     correctly in the bar                                                     }
{            Copyright (C) 2005 Rade Vojvodic                                  }
{------------------------------------------------------------------------------}
{                                                                              }
{  Marco Menardi <mmenaz@lycosmail.com>                                        }
{  14-apr-2002                                                                 }
{     Reduced resouce usage, critical in Win98 but important also in Win2K     }
{                                                                              }
{******************************************************************************}

{$INCLUDE IB_Directives.inc}

{: This unit contains the TIB_DatasetBar component. }
unit
  IB_DatasetBar;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Controls, StdCtrls,
  Forms, Graphics, ExtCtrls, Menus, Buttons, Dialogs, Math,

  IB_Constants,
  IB_Components,
  IB_FieldDataLink;

type
{: These are the different button types available to this button bar.
<br><br>
<br>dbPrepare prepares the current statement in the SQL property.
<br>dbUnprepare unprepares the current statement in the SQL property.
<br>dbOpen Opens a cursor on the server to process the fetches.
<br>dbClose Closes the cursor opened on the server.}
TIB_DatasetBar_ButtonType = ( dbPrepare,
                              dbUnprepare,
                              dbOpen,
                              dbClose );

{: Set of button types for this button bar.}
TIB_DatasetBar_ButtonSet = set of TIB_DatasetBar_ButtonType;

{: This is the button class definition that is used internally.}  
TIB_DatasetBar_Button = class;

{: This enables the order of the buttons on the toolbar to be customized.}  
TIB_DatasetBar_ButtonsOrder = array[0..3] of TIB_DatasetBar_ButtonType;

//------------------------------------------------------------------------------
// Here's where the customized stuff begins
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// Here's where the customized stuff ends
//------------------------------------------------------------------------------

{: Button bar that gives access and control of statements and cursors.}
TIB_DatasetBar = class (TCustomPanel)
{$I IB_Bars.INT}
{$I IB_InterfaceDataLink.INT}
private
  FVisibleButtons: TIB_DatasetBar_ButtonSet;
  FCustomGlyphsSupplied: TIB_DatasetBar_ButtonSet;
  FFocusedButton: TIB_DatasetBar_ButtonType;
  FButtonsOrder: TIB_DatasetBar_ButtonsOrder;
  procedure SetVisibleButtons(Value: TIB_DatasetBar_ButtonSet);
  procedure SetCustomGlyphsSupplied(Value: TIB_DatasetBar_ButtonSet);
  function GetButtonsOrder(Index: Integer): TIB_DatasetBar_ButtonType;

public

{: Storage array for the different buttons on this button bar. }
  Buttons: array[TIB_DatasetBar_ButtonType] of TIB_DatasetBar_Button;

{: Method used to pass the click of a single button to the owning parent.}
  procedure BtnClick(Index: TIB_DatasetBar_ButtonType);
  
{: The currently selected button of the button set.
<br><br>
Use this property in the xxxxAction events to know which button was clicked.}
  property FocusedButton: TIB_DatasetBar_ButtonType read FFocusedButton;

{: Allows for customizing the order of the buttons on the button bar.}
  property ButtonsOrder[Index: Integer]: TIB_DatasetBar_ButtonType
      read GetButtonsOrder;

published

{: Set this property to indicate which glyphs have been supplied in the
CustomGlyphs property.}
  property CustomGlyphsSupplied: TIB_DatasetBar_ButtonSet
      read FCustomGlyphsSupplied
     write SetCustomGlyphsSupplied;
     
{: Set which button are visible to the user.}
  property VisibleButtons: TIB_DatasetBar_ButtonSet
      read FVisibleButtons
     write SetVisibleButtons
   default [ dbOpen, dbClose ];

// -----------------------------------------------------------------------------
// This is the beginning of the area for the non-template stuff.
// -----------------------------------------------------------------------------

private
  FTogglePrepare: boolean;
  FToggleOpen: boolean;

published

{: When Prepared the Unprepare button will be shown. When unprepared the
Prepare button will show.
<br><br>
Must also have only one of these buttons in the VisibleButtons property.}
  property TogglePrepare: boolean read FTogglePrepare
                                  write FTogglePrepare
                                  default false;
{: When Opened the Close button will be shown. When Closed the
Open button will show.
<br><br>
Must also have only one of these buttons in the VisibleButtons property.}
  property ToggleOpen: boolean read FToggleOpen
                               write FToggleOpen
                               default false;

// -----------------------------------------------------------------------------
// This is the ending of the area for the non-template stuff.
// -----------------------------------------------------------------------------

end;

TIB_DatasetBar_Button = class(TSpeedButton)
private
  FIndex: TIB_DatasetBar_ButtonType;
protected
  procedure Paint; override;
public
  property Index: TIB_DatasetBar_ButtonType read FIndex write FIndex;
end;

var
  DatasetBar_Images: TStringList;
  IB_DatasetBar_ButtonsOrder: TIB_DatasetBar_ButtonsOrder;

implementation

{$R IB_DatasetBar.RES}

function StandardBitmap( S: String ):tBitmap;
var
  x: integer;
begin
  if DatasetBar_Images.Find( S, x ) then
    Result := TBitmap( DatasetBar_Images.Objects[ x ] )
  else
    Result := nil;
end;

procedure FillImages;
var
  i: integer;
  b: TBitmap;
const
  a: array[0..4] of pchar = ( 'DSET_BAR_PREPARE', 'DSET_BAR_UNPREPARE',
                              'DSET_BAR_OPEN',    'DSET_BAR_CLOSE',
                              'DSET_BAR_EXECUTE'      );
begin
  for i := low(a) to high(a) do
  begin
    B := TBitmap.Create;
    B.LoadFromResourceName( hinstance, strPas(a[i] ));
    B.Dormant;
{$IFDEF IBO_VCL70_OR_GREATER}
    B.FreeImage;
{$ENDIF}
    DatasetBar_Images.AddObject( strPas( a[i] ), B );
  end;
end;

constructor TIB_DatasetBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle - [csAcceptsControls, csSetCaption] + [csOpaque];
  if not NewStyleControls then
    ControlStyle := ControlStyle + [csFramed];
  FIB_DataLink := TIB_InterfaceDataLink.Create( Self );
  with FIB_DataLink do 
  begin
    Control := Self;
    AfterAssignment := IB_DatasetStateChanged;
    OnStateChanged := IB_DatasetStateChanged;
  end;
  InitButtonsOrder;
  FVisibleButtons := [dbOpen, dbClose];
  InitButtons;
  BevelOuter := bvNone;
  BevelInner := bvNone;
  Ctl3D := false;
  ParentCtl3D := false;
  Width := 121;
  Height := 25;
  ButtonWidth := 0;
  FFocusedButton := dbOpen;
{$IFDEF IBO_VCL30_OR_GREATER}
  Flat := true; // Hit the property.
{$ENDIF}
end;

destructor TIB_DatasetBar.Destroy;
begin
  if Assigned( FCustomGlyphs ) then
    FCustomGlyphs.OnChange := nil;
  with DataLink do
  begin
    AfterAssignment := nil;
    OnStateChanged := nil;
  end;
  inherited Destroy;
end;

procedure TIB_DatasetBar.Notification( AComponent: TComponent;
                                       Operation: TOperation );
begin
  inherited Notification( AComponent, Operation );
  if ( Operation = opRemove ) and ( CustomGlyphs <> nil ) and
     ( AComponent = CustomGlyphs ) then
    CustomGlyphs := nil;
end;

{$IFDEF IBO_VCL30_OR_GREATER}
procedure TIB_DatasetBar.SetFlat( AValue: boolean );
begin
  if Flat <> AValue then begin
    FFlat := AValue;
    Buttons[ dbPrepare   ].Flat := Flat;
    Buttons[ dbUnprepare ].Flat := Flat;
    Buttons[ dbOpen      ].Flat := Flat;
    Buttons[ dbClose     ].Flat := Flat;
    Buttons[ dbOpen      ].Flat := Flat;
  end;
end;
{$ENDIF}

procedure TIB_DatasetBar.SetShowCaptions(AValue: Boolean);
var
  W, H: Integer;
  I: TIB_DatasetBar_ButtonType;
begin
  FShowCaptions := AValue;
  for I := Low(Buttons) to High(Buttons) do
  begin
    Buttons[i].Caption := '';
    if FShowCaptions then
    begin
      Buttons[i].Layout := blGlyphTop;
      case I of
        dbPrepare:   Buttons[i].Caption := C_ST_PREPARE;
        dbUnprepare: Buttons[i].Caption := C_ST_UNPREPARE;
        dbopen:      Buttons[i].Caption := C_ST_OPEN;
        dbClose:     Buttons[i].Caption := C_ST_CLOSE;
      end;
    end;
  end;
  W := Width;
  H := Height;
  AdjSize(W,H);
end;

procedure TIB_DatasetBar.InitButtons;
var
  I: Integer;
  Btn: TIB_DatasetBar_Button;
  X: Integer;
begin
  MinBtnSize := Point(20, 18);
  X := 0;
  for I := Low(TIB_DatasetBar_ButtonsOrder) to
           High(TIB_DatasetBar_ButtonsOrder) do 
  begin
    Btn := TIB_DatasetBar_Button.Create (Self);
    Btn.Index := FButtonsOrder[I];
    Btn.Visible := Btn.Index in FVisibleButtons;
    Btn.Enabled := True;
    Btn.SetBounds (X, 0, MinBtnSize.X, MinBtnSize.Y);
    Btn.Enabled := False;
    Btn.Enabled := True;
    Btn.OnClick := BarClick;
    Btn.OnMouseDown := BtnMouseDown;
    Btn.Parent := Self;
    Buttons[Btn.Index] := Btn;
    X := X + MinBtnSize.X;
  end;
  ResetButtonState;
end;


procedure TIB_DatasetBar.InitHints;
var
  I: TIB_DatasetBar_ButtonType;
  Btn: TIB_DatasetBar_Button;
begin
  for I := Low(Buttons) to High(Buttons) do
  begin
    Btn := Buttons[ I ];
    case I of
      dbPrepare:   Btn.Hint := H_DS_Prepare_Dataset;
      dbUnprepare: Btn.Hint := H_DS_Unprepare_Dataset;
      dbOpen:
      begin
        if ( not Assigned( DataSource )) or
           ( not Assigned( DataSource.Dataset )) or
           ( not DataSource.Dataset.Prepared ) or
           ( DataSource.Dataset.StatementType = stSelect ) or
           ( DataSource.Dataset.StatementType = stSelectForUpdate ) then
          Btn.Hint := H_DS_Open_Dataset
        else
          Btn.Hint := H_DS_Execute_Statement;
      end;
      dbClose: Btn.Hint := H_DS_Close_Dataset;
    end;
  end;
end;

procedure TIB_DatasetBar.BtnMouseDown (Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  OldFocus: TIB_DatasetBar_ButtonType;
begin
  OldFocus := FocusedButton;
  FFocusedButton := TIB_DatasetBar_Button(Sender).Index;
  if TabStop and (GetFocus <> Handle) and CanFocus then
  begin
    SetFocus;
    if (GetFocus <> Handle) then
      Exit;
  end
  else
  if TabStop and (GetFocus = Handle) and (OldFocus <> FocusedButton) then
  begin
    Buttons[OldFocus].Invalidate;
    Buttons[FocusedButton].Invalidate;
  end;
end;

procedure TIB_DatasetBar.SetVisibleButtons(Value: TIB_DatasetBar_ButtonSet);
var
  I: TIB_DatasetBar_ButtonType;
  W, H: Integer;
begin
  W := Width;
  H := Height;
  FVisibleButtons := Value;
  for I := Low(Buttons) to High(Buttons) do
    Buttons[I].Visible := I in FVisibleButtons;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds (Left, Top, W, H);
  Invalidate;
end;

procedure TIB_DatasetBar.CalcMinSize(var W, H: Integer);
var
  Count: Integer;
  I: TIB_DatasetBar_ButtonType;
  t: integer;
begin
  if (csLoading in ComponentState) then Exit;
  if Buttons[dbOpen] = nil then Exit;

  Count := 0;
  for I := Low(Buttons) to High(Buttons) do
    if Buttons[I].Visible then
      Inc(Count);
  if Count = 0 then
    Inc(Count);
  t := Count * MinBtnSize.X;
  if t > W then W := t;
  t := MinBtnSize.Y;
  if t > H then H := t;
  if Align = alNone then W := (W div Count) * Count;
end;

procedure TIB_DatasetBar.AdjSize (var W: Integer; var H: Integer);
var
  Count: Integer;
  I: TIB_DatasetBar_ButtonType;
  Space, Temp, Remain: Integer;
  X: Integer;
begin
  if (csLoading in ComponentState) then Exit;
  if Buttons[dbOpen] = nil then Exit;

  CalcMinSize(W, H);

  Count := 0;
  for I := Low(Buttons) to High(Buttons) do
  begin
    if Buttons[I].Visible then
      Inc(Count);
  end;
  if Count = 0 then Inc(Count);

  ButtonWidth := W div Count;
  Temp := Count * ButtonWidth;
  if Align = alNone then W := Temp;

  X := 0;
  Remain := W - Temp;
  Temp := Count div 2;
  for I := Low(Buttons) to High(Buttons) do
  begin
    if Buttons[I].Visible then
    begin
      Space := 0;
      if Remain <> 0 then
      begin
        Dec (Temp, Remain);
        if Temp < 0 then
        begin
          Inc (Temp, Count);
          Space := 1;
        end;
      end;
      Buttons[I].SetBounds (X, 0, ButtonWidth + Space, Height);
      Inc (X, ButtonWidth + Space);
    end
    else
      Buttons[I].SetBounds (Width + 1, 0, ButtonWidth, Height);
  end;
end;

procedure TIB_DatasetBar.WMSize(var Message: TWMSize);
var
  W, H: Integer;
begin
  inherited;
  { check for minimum size }
  W := Width;
  H := Height;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds(Left, Top, W, H);
  Message.Result := 0;
end;

procedure TIB_DatasetBar.WMSetFocus(var Message: TWMSetFocus);
begin
  Buttons[FocusedButton].Invalidate;
end;

procedure TIB_DatasetBar.WMKillFocus(var Message: TWMKillFocus);
begin
  Buttons[FocusedButton].Invalidate;
end;

procedure TIB_DatasetBar.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  Message.Result := DLGC_WANTARROWS;
end;

procedure TIB_DatasetBar.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  if not (csLoading in ComponentState) then
    SysStateChanged;
end;

procedure TIB_DatasetBar.SysStateChanged;
var
  NewVisibleButtons: TIB_DatasetBar_ButtonSet;
begin
  with FIB_DataLink do
  begin
    NewVisibleButtons := VisibleButtons;
    if TogglePrepare then
    begin
      if Prepared then
      begin
        if     ( dbPrepare in VisibleButtons ) and
           not ( dbUnprepare in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ dbUnPrepare ] -
                                                   [ dbPrepare   ];
        end;
      end
      else
      begin
        if not ( dbPrepare in VisibleButtons ) and
               ( dbUnprepare in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ dbPrepare   ] -
                                                   [ dbUnprepare ];
        end;
      end;
    end;
    if ToggleOpen then
    begin
      if Active then
      begin
        if     ( dbOpen in VisibleButtons ) and
           not ( dbClose in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ dbClose ] -
                                                   [ dbOpen  ];
        end;
      end
      else
      begin
        if not ( dbOpen in VisibleButtons ) and
               ( dbClose in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ dbOpen  ] -
                                                   [ dbClose ];
        end;
      end;
    end;
    VisibleButtons := NewVisibleButtons;
    if Assigned( Dataset ) and Enabled then
    begin
      Buttons[ dbPrepare   ].Enabled := not Dataset.Prepared;
      Buttons[ dbUnprepare ].Enabled :=     Dataset.Prepared;
      Buttons[ dbOpen      ].Enabled := not Dataset.Active;
      Buttons[ dbClose     ].Enabled :=     Dataset.Active;
      if not Dataset.Prepared or
         ( Dataset.StatementType = stSelect ) or
         ( Dataset.StatementType = stSelectForUpdate ) then
      begin
        if (CustomGlyphs = nil) or ( not (dbOpen in CustomGlyphsSupplied )) then
        begin
          Buttons[ dbOpen ].Glyph.Assign( StandardBitmap( 'DSET_BAR_OPEN' ));
          Buttons[ dbOpen ].Glyph.Dormant;
          Buttons[ dbOpen ].Glyph.FreeImage;
        end;
      end
      else
      begin
        if (CustomGlyphs = nil) or ( not (dbOpen in CustomGlyphsSupplied )) then
        begin
          Buttons[ dbOpen ].Glyph.Assign( StandardBitmap( 'DSET_BAR_EXECUTE' ));
          Buttons[ dbOpen ].Glyph.Dormant;
          Buttons[ dbOpen ].Glyph.FreeImage;
        end;
        Buttons[ dbClose ].Enabled := false;
      end;
    end
    else
    begin
      Buttons[ dbPrepare   ].Enabled := false;
      Buttons[ dbUnprepare ].Enabled := false;
      Buttons[ dbOpen      ].Enabled := false;
      Buttons[ dbClose     ].Enabled := false;
      if (CustomGlyphs = nil) or ( not (dbOpen in CustomGlyphsSupplied )) then
      begin
        Buttons[ dbOpen ].Glyph.Assign( StandardBitmap( 'DSET_BAR_OPEN' ));
        Buttons[ dbOpen ].Glyph.Dormant;
        Buttons[ dbOpen ].Glyph.FreeImage;
      end;
    end;
  end;
  InitHints;
  if ( not ( csDestroying in ComponentState )) and
     Assigned( FOnButtonsStateChanged ) then
    FOnButtonsStateChanged( Self );
end;

procedure TIB_DatasetBar.Loaded;
var
  W, H: Integer;
begin
  inherited Loaded;
  W := Width;
  H := Height;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds (Left, Top, W, H);
  SysStateChanged;
end;

procedure TIB_DatasetBar.KeyDown(var Key: Word; Shift: TShiftState);
var
  NewFocus: TIB_DatasetBar_ButtonType;
  OldFocus: TIB_DatasetBar_ButtonType;
begin
  OldFocus := FocusedButton;
  case Key of
    VK_RIGHT:
      begin
        NewFocus := FocusedButton;
        repeat
          if NewFocus < High(Buttons) then
            NewFocus := Succ(NewFocus);
        until (NewFocus = High(Buttons)) or (Buttons[NewFocus].Visible);
        if NewFocus <> FocusedButton then
        begin
          FFocusedButton := NewFocus;
          Buttons[OldFocus].Invalidate;
          Buttons[FocusedButton].Invalidate;
        end;
      end;
    VK_LEFT:
      begin
        NewFocus := FocusedButton;
        repeat
          if NewFocus > Low(Buttons) then
            NewFocus := Pred(NewFocus);
        until (NewFocus = Low(Buttons)) or (Buttons[NewFocus].Visible);
        if NewFocus <> FocusedButton then
        begin
          FFocusedButton := NewFocus;
          Buttons[OldFocus].Invalidate;
          Buttons[FocusedButton].Invalidate;
        end;
      end;
    VK_SPACE:
      begin
        if Buttons[FocusedButton].Enabled then
          Buttons[FocusedButton].Click;
      end;
  end;
end;

procedure TIB_DatasetBar.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  W, H: Integer;
begin
  W := AWidth;
  H := AHeight;
  AdjSize (W, H);
  inherited SetBounds (ALeft, ATop, W, H);
end;

procedure TIB_DatasetBar.BtnClick(Index: TIB_DatasetBar_ButtonType);
begin
  FFocusedButton := Index;
  if ( not (csDesigning in ComponentState)) and
     Assigned( FBeforeAction ) then
    FBeforeAction( Self );
  if (DataSource <> nil) then
  begin
    with DataSource do
    begin
      if Dataset <> nil then
        with Dataset do
        begin
          case Index of
            dbPrepare: Prepare;
            dbUnprepare: Unprepare;
            dbOpen:
            begin
              if not Prepared then
                Prepare;
              if ( StatementType = stSelect ) or
                 ( StatementType = stSelectForUpdate ) then
                Open
              else
                Execute;
            end;
            dbClose: Close;
          end;
      end;
    end;
  end;
  if ( not (csDesigning in ComponentState)) and
     Assigned( FAfterAction ) then
    FAfterAction( Self );
end;

procedure TIB_DatasetBar.BarClick( Sender: TObject );
begin
  BtnClick( TIB_DatasetBar_Button(Sender).Index );
end;

procedure TIB_DatasetBar_Button.Paint;
var
  R: TRect;
begin
  inherited Paint;
  if ( GetFocus = Parent.Handle ) and
     ( FIndex = TIB_DatasetBar(Parent).FocusedButton ) then
  begin
    R := Bounds( 0, 0, Width, Height );
    InflateRect( R, -3, -3 );
    if FState = bsDown then
      OffsetRect( R, 1, 1 );
    DrawFocusRect( Canvas.Handle, R );
  end;
end;

procedure TIB_DatasetBar.SetCustomGlyphs(Value: TImageList);
begin
  if Assigned( FCustomGlyphs ) then
    FCustomGlyphs.OnChange := nil;
  FCustomGlyphs := Value;
  if Assigned( FCustomGlyphs ) then
    FCustomGlyphs.OnChange := CustomGlyphsChange;
  ResetButtonState;
end;

procedure TIB_DatasetBar.CustomGlyphsChange(Sender: TObject);
begin
  if not (csDestroying in ComponentState) then
    ResetButtonState;
end;

procedure TIB_DatasetBar.SetCustomGlyphsSupplied(
                                              Value: TIB_DatasetBar_ButtonSet );
begin
  if FCustomGlyphsSupplied <> Value then
  begin
    FCustomGlyphsSupplied := Value;
    ResetButtonState;
  end;
end;

procedure TIB_DatasetBar.ResetButtonState;
var
  j: Integer;
  i: TIB_DatasetBar_ButtonType;
  TmpGlyph: TBitmap;
begin
  j := 0;
  for i:= low(Buttons) to high(Buttons) do
  begin
    if Assigned( FCustomGlyphs ) and
       ( i in CustomGlyphsSupplied ) and
       ( j < FCustomGlyphs.Count ) then
    begin
      TmpGlyph := TBitmap.Create;
      try
        FCustomGlyphs.GetBitmap(j, TmpGlyph);
        Buttons[i].Glyph.Assign(TmpGlyph);
        Buttons[i].Glyph.Dormant;
        Buttons[i].Glyph.FreeImage;
        if ((( TmpGlyph.Width +
               ( TmpGlyph.Width div 3 )) div 2 ) > TmpGlyph.Height ) then
          Buttons[i].NumGlyphs := 2
        else
          Buttons[i].NumGlyphs := 1;
        Buttons[i].Caption := '';
      finally
        TmpGlyph.Free;
      end;
      inc(j);
    end
    else
    begin
      Buttons[i].NumGlyphs := 2;
      with Buttons[i].Glyph do
      begin
        case I of
          dbPrepare:    Assign( StandardBitmap( 'DSET_BAR_PREPARE'   ));
          dbUnprepare:  Assign( StandardBitmap( 'DSET_BAR_UNPREPARE' ));
          dbOpen:
          begin
            if ( not Assigned( DataSource )) or
               ( not Assigned( DataSource.Dataset )) or
               ( DataSource.Dataset.Prepared ) or
               ( DataSource.Dataset.StatementType = stSelect ) or
               ( DataSource.Dataset.StatementType = stSelectForUpdate ) then
              Assign( StandardBitmap( 'DSET_BAR_OPEN' ))
            else
              Assign( StandardBitmap( 'DSET_BAR_EXECUTE' ))
          end;
          dbClose:      Assign( StandardBitmap( 'DSET_BAR_CLOSE' ));
        end;
        Dormant;
        FreeImage;
      end;
    end;
  end;
end;

procedure TIB_DatasetBar.InitButtonsOrder;

  function GlobalOrderAssigned : boolean;
  var
    Flags : Array [TIB_DatasetBar_ButtonType] of boolean;
    i : TIB_DatasetBar_ButtonType;
    ii : byte;
  begin
    Result := False;
    for i := Low(TIB_DatasetBar_ButtonType) to 
             High(TIB_DatasetBar_ButtonType) do
      Flags[i] := False;
    for ii := 0 to 7 do
    begin
      if not Flags[IB_DatasetBar_ButtonsOrder[ii]] then
        Flags[IB_DatasetBar_ButtonsOrder[ii]] := True
      else
        Exit; // the flag can't be updated twice
    end;
    // All items must be true
    for i := Low(TIB_DatasetBar_ButtonType) to
             High(TIB_DatasetBar_ButtonType) do
      if not Flags[i] then
        Exit;
    Result := True;
  end;

begin
  if GlobalOrderAssigned then
    FButtonsOrder := IB_DatasetBar_ButtonsOrder
  else
  begin
    FButtonsOrder[0] := dbPrepare;
    FButtonsOrder[1] := dbUnprepare;
    FButtonsOrder[2] := dbOpen;
    FButtonsOrder[3] := dbClose;
  end;
end;

function TIB_DatasetBar.GetButtonsOrder( Index: Integer ):
                                                      TIB_DatasetBar_ButtonType;
begin
  Result := FButtonsOrder[Index];
end;

procedure TIB_DatasetBar.IB_DatasetStateChanged( Sender: TIB_DataLink;
                                                 DataSource: TIB_DataSource );
begin
  SysStateChanged;
end;

procedure TIB_DatasetBar.IB_DatasetDataChange( Sender: TIB_DataLink;
                                               DataSource: TIB_DataSource;
                                               IB_Field: TIB_Column );
begin
  SysStateChanged;
end;

function TIB_DatasetBar.GetDataSource: TIB_DataSource;
begin
  if FIB_DataLink <> nil then
    Result := FIB_DataLink.DataSource
  else
    Result := nil;
end;

procedure TIB_DatasetBar.SetDataSource(AValue: TIB_DataSource);
begin
  if FIB_DataLink <> nil then
  begin
    if DataLink.DataSource <> AValue then
    begin
      DataLink.DataSource := AValue;
      SysStateChanged;
    end;
  end;
end;

function TIB_DatasetBar.GetReceiveFocus: boolean;
begin
  if FIB_DataLink <> nil then
    Result := DataLink.ReceiveFocus
  else
    Result := false;
end;

procedure TIB_DatasetBar.SetReceiveFocus(AValue: boolean);
begin
  if FIB_DataLink <> nil then
    DataLink.ReceiveFocus := AValue;
end;

function TIB_DatasetBar.GetOnReceiveFocus: TIB_DataLinkEvent;
begin
  Result := DataLink.OnReceiveFocus;
end;

procedure TIB_DatasetBar.SetOnReceiveFocus( AValue: TIB_DataLinkEvent );
begin
  DataLink.OnReceiveFocus := AValue;
end;

//------------------------------------------------------------------------------
// Here's where the customized stuff begins
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Here's where the customized stuff ends
//------------------------------------------------------------------------------

initialization
  DatasetBar_Images := TIB_StringList.Create;
  DatasetBar_Images.Sorted := true;
  FillImages;

finalization
  while DatasetBar_Images.Count > 0 do
  begin
    TBitmap( DatasetBar_Images.Objects[0] ).Free;
    DatasetBar_Images.Delete( 0 );
  end;
  DatasetBar_Images.Free;

end.
