Files
HeidiSQL/source/data_sorting.pas
Ansgar Becker be645ac79b Unify code for refreshing Virtual Trees in a new helper method InvalidateVT. Fixes issue #1789 and issue #1790.
* Don't try to access a passed tree if it has been destroyed by some earlier event.
* Don't try to access registry in DoDisconnect after key has been closed.
* Now that DoDisconnect lives in FormDestroy it is save to call it slightly earlier, before registry has been closed. There should be no later paint events which will trigger random database queries.
2010-03-21 10:43:16 +00:00

356 lines
9.4 KiB
ObjectPascal

unit data_sorting;
interface
uses
Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, ComCtrls, Buttons,
Contnrs,
helpers;
type
TDataSortingForm = class(TForm)
pnlBevel: TPanel;
btnOK: TButton;
btnCancel: TButton;
btnAddCol: TButton;
btnReset: TButton;
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);
private
{ Private declarations }
ColumnNames : TStringList;
OrderColumns : TOrderColArray;
OldOrderClause : String;
procedure DisplaySortingControls;
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);
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;
end;
{**
Create controls for order columns
}
procedure TDataSortingForm.DisplaySortingControls;
var
labelNumber: TLabel;
buttonDelete: TButton;
dropdownCols: TComboBox;
buttonOrder: TSpeedButton;
i, xPosition, topPosition, btnWidth : Integer;
begin
// 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.Top := Height - pnlBevel.BorderWidth - MARGIN - btnOK.Height;
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;
// 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;
// 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.