unit data_sorting;

interface

uses
  Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, ComCtrls, Buttons,

  helpers, gnugettext;


type
  TDataSortingForm = class(TForm)
    pnlBevel: TPanel;
    btnOK: TButton;
    btnCancel: TButton;
    btnAddCol: TButton;
    btnReset: TButton;
    timerRefresh: TTimer;
    procedure btnAddColClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
    procedure btnOKClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDeactivate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure DisplaySortingControls(Sender: TObject);
  private
    { Private declarations }
    ColumnNames : TStringList;
    OrderColumns : TOrderColArray;
    OldOrderClause : String;
    procedure dropdownColsChange( Sender: TObject );
    procedure buttonOrderClick( Sender: TObject );
    procedure buttonDeleteClick( Sender: TObject );
    procedure Modified;
  public
    { Public declarations }
  end;


const
  LINE_HEIGHT = 20;         // Height of automatically created controls
  MARGIN = 2;               // Space between controls
  MARGIN_BIG = 3 * MARGIN;  // Space above the very first and last controls, used to separate stuff

implementation

uses main;

{$R *.dfm}


procedure TDataSortingForm.FormCreate(Sender: TObject);
begin
  InheritFont(Font);
  TranslateComponent(Self);
  ColumnNames := TStringList.Create;
end;


{**
  Initialization
}
procedure TDataSortingForm.FormShow(Sender: TObject);
var
  i: Integer;
begin
  // Take column names from listColumns and add here
  ColumnNames.Clear;
  for i:=0 to Mainform.SelectedTableColumns.Count-1 do
    ColumnNames.Add(Mainform.SelectedTableColumns[i].Name);

  OrderColumns := Mainform.DataGridSortColumns;
  OldOrderClause := ComposeOrderClause(OrderColumns);

  // First creation of controls
  DisplaySortingControls(Sender);

end;


{**
  Create controls for order columns
}
procedure TDataSortingForm.DisplaySortingControls(Sender: TObject);
var
  labelNumber: TLabel;
  buttonDelete: TButton;
  dropdownCols: TComboBox;
  buttonOrder: TSpeedButton;
  i, xPosition, topPosition, btnWidth : Integer;
begin
  if not timerRefresh.Enabled then begin
    timerRefresh.Enabled := True;
    Exit;
  end;

  timerRefresh.Enabled := False;

  // Remove previously created components
  for i := ComponentCount - 1 downto 0 do
  begin
    if Components[i].Tag > 0 then
      Components[i].Free;
  end;

  // Set initial width to avoid resizing form to 0
  xPosition := pnlBevel.Width;


  // Create line with controls for each order column
  for i:=0 to Length(OrderColumns)-1 do
  begin
    xPosition := pnlBevel.BorderWidth;
    topPosition := pnlBevel.BorderWidth + MARGIN_BIG + (i * (LINE_HEIGHT + MARGIN));

    // 1. Label with number
    labelNumber := TLabel.Create(self);
    labelNumber.Parent := pnlBevel;
    labelNumber.AutoSize := False; // Avoids automatic changes to width + height
    labelNumber.Left := xPosition;
    labelNumber.Top := topPosition;
    labelNumber.Width := 15;
    labelNumber.Height := LINE_HEIGHT;
    labelNumber.Alignment := taRightJustify;
    labelNumber.Layout := tlCenter;
    labelNumber.Caption := IntToStr(i+1) + '.';
    labelNumber.Tag := i+1;
    Inc( xPosition, labelNumber.Width + MARGIN );

    // 2. Dropdown with columnnames
    dropdownCols := TComboBox.Create(self);
    dropdownCols.Parent := pnlBevel;
    dropdownCols.Width := 120;
    dropdownCols.Height := LINE_HEIGHT;
    dropdownCols.Left := xPosition;
    dropdownCols.Top := topPosition;
    dropdownCols.Items.Text := ColumnNames.Text;
    dropdownCols.Style := csDropDownList; // Not editable
    dropdownCols.ItemIndex := ColumnNames.IndexOf(OrderColumns[i].ColumnName);
    dropdownCols.Tag := i+1;
    dropdownCols.OnChange := dropdownColsChange;
    Inc( xPosition, dropdownCols.Width + MARGIN );

    // 3. A button for selecting ASC/DESC
    buttonOrder := TSpeedButton.Create(self);
    buttonOrder.Parent := pnlBevel;
    buttonOrder.Width := 35;
    buttonOrder.Height := LINE_HEIGHT;
    buttonOrder.Left := xPosition;
    buttonOrder.Top := topPosition;
    buttonOrder.AllowAllUp := True; // Enables Down = False
    buttonOrder.GroupIndex := i+1; // if > 0 enables Down = True
    buttonOrder.Caption := TXT_ASC;
    if OrderColumns[i].SortDirection = ORDER_DESC then
    begin
      buttonOrder.Caption := TXT_DESC;
      buttonOrder.Down := True;
    end;
    buttonOrder.Hint := _('Toggle the sort direction for this column.');
    buttonOrder.Tag := i+1;
    buttonOrder.OnClick := buttonOrderClick;
    Inc( xPosition, buttonOrder.Width + MARGIN );

    // 4. Button for deleting
    buttonDelete := TButton.Create(self);
    buttonDelete.Parent := pnlBevel;
    buttonDelete.Width := 20;
    buttonDelete.Height := LINE_HEIGHT;
    buttonDelete.Left := xPosition;
    buttonDelete.Top := topPosition;
    buttonDelete.Caption := 'X';
    buttonDelete.Hint := _('Drops sorting by this column.');
    buttonDelete.Tag := i+1;
    buttonDelete.OnClick := buttonDeleteClick;
    Inc( xPosition, buttonDelete.Width + MARGIN );

  end;

  // Auto-adjust size of form
  Height := (pnlBevel.BorderWidth * 2) + // Top + Bottom border
    (MARGIN_BIG * 2) + // Separator spaces
    (Length(OrderColumns) * (LINE_HEIGHT + MARGIN)) + // Height of created controls
    (btnOK.Height + MARGIN + btnReset.Height + Margin); // Height of buttons
  Width := xPosition + pnlBevel.BorderWidth;

  // Auto-adjust width and position of main buttons at bottom
  btnWidth := (pnlBevel.Width -pnlBevel.BorderWidth*2 - MARGIN) DIV 3 - MARGIN;
  btnOK.Width := btnWidth;
  btnOK.Left := pnlBevel.BorderWidth + MARGIN;
  btnCancel.Width := btnWidth;
  btnCancel.Left := btnOK.Left + btnWidth + MARGIN;
  btnAddCol.Width := btnWidth;
  btnAddCol.Left := btnCancel.Left + btnWidth + MARGIN;
  btnReset.Left := btnCancel.Left;
  btnReset.Width := 2*btnWidth + MARGIN;
  btnReset.Enabled := Mainform.actDataResetSorting.Enabled;
end;


{**
  Dropdown for column selection was changed
}
procedure TDataSortingForm.dropdownColsChange( Sender: TObject );
var
  combo : TComboBox;
begin
  combo := Sender as TComboBox;
  OrderColumns[combo.Tag-1].ColumnName := combo.Text;

  // Enables OK button
  Modified;
end;


{**
  Button for selecting sort-direction was clicked
}
procedure TDataSortingForm.buttonOrderClick( Sender: TObject );
var
  btn : TSpeedButton;
begin
  btn := Sender as TSpeedButton;
  if btn.Down then
  begin
    btn.Caption := TXT_DESC;
    OrderColumns[btn.Tag-1].SortDirection := ORDER_DESC;
  end
  else
  begin
    btn.Caption := TXT_ASC;
    OrderColumns[btn.Tag-1].SortDirection := ORDER_ASC;
  end;

  // Enables OK button
  Modified;
end;


{**
  Delete order column
}
procedure TDataSortingForm.buttonDeleteClick( Sender: TObject );
var
  btn : TButton;
  i : Integer;
begin
  btn := Sender as TButton;

  if Length(OrderColumns)>1 then
  begin
    // Move remaining items one up
    for i := btn.Tag-1 to Length(OrderColumns) - 2 do
    begin
      OrderColumns[i] := OrderColumns[i+1];
    end;
  end;
  // Delete last item
  SetLength(OrderColumns, Length(OrderColumns)-1);

  // Refresh controls
  DisplaySortingControls(Sender);

  // Enables OK button
  Modified;
end;


{**
  Add a new order column
}
procedure TDataSortingForm.btnAddColClick(Sender: TObject);
var
  i, new : Integer;
  UnusedColumns : TStringList;
begin
  SetLength( OrderColumns, Length(OrderColumns)+1 );
  new := Length(OrderColumns)-1;
  OrderColumns[new] := TOrderCol.Create;

  // Take first unused column as default for new sort column
  UnusedColumns := TStringList.Create;
  UnusedColumns.AddStrings( ColumnNames );
  for i := 0 to Length(OrderColumns) - 1 do
  begin
    if UnusedColumns.IndexOf(OrderColumns[i].ColumnName) > -1 then
    begin
      UnusedColumns.Delete( UnusedColumns.IndexOf(OrderColumns[i].ColumnName) );
    end;
  end;
  if UnusedColumns.Count > 0 then
    OrderColumns[new].ColumnName := UnusedColumns[0]
  else
    OrderColumns[new].ColumnName := ColumnNames[0];

  // Sort ASC by default
  OrderColumns[new].SortDirection := ORDER_ASC;

  // Refresh controls
  DisplaySortingControls(Sender);

  // Enables OK button
  Modified;
end;


{**
  Gets called when any option has changed.
  Enables the OK button if ORDER options have changed
}
procedure TDataSortingForm.Modified;
begin
  btnOk.Enabled := ComposeOrderClause(OrderColumns) <> OldOrderClause;
end;


{**
  OK clicked: Write ORDER clause to registry
}
procedure TDataSortingForm.btnOKClick(Sender: TObject);
begin
  // TODO: apply ordering
  Mainform.DataGridSortColumns := OrderColumns;
  InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
  btnCancel.OnClick(Sender);
end;


procedure TDataSortingForm.btnCancelClick(Sender: TObject);
begin
  Mainform.tbtnDataSorting.Down := False;
  Close;
end;


{**
  Be sure the form is destroyed after closing.
}
procedure TDataSortingForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;


{**
  Cancel this dialog if the user clicks elsewhere on mainform
}
procedure TDataSortingForm.FormDeactivate(Sender: TObject);
begin
  btnCancel.OnClick(Sender);
end;


procedure TDataSortingForm.btnResetClick(Sender: TObject);
begin
  Mainform.actDataResetSortingExecute(Sender);
  btnCancel.OnClick(Sender);
end;


end.
