Implement a dialog for easier accessing the options for ordered columns.

This has one positive side effect: ViewData no longer re-saves an ORDERCLAUSE to registry after it has been read. At the same time the ORDERCLAUSE is read everytime when grid is filled, not only the first time. Those changes were needed to be able to apply an ORDERCLAUSE which was generated and saved by the new dialog.

Left for later: Moving order-columns up and down. Tested that with a TUpDown which seems to ignore clicks sometimes and then doesn't fire OnClick.
This commit is contained in:
Ansgar Becker
2007-07-12 22:33:59 +00:00
parent 4d12bd3e42
commit cc84963b25
4 changed files with 578 additions and 100 deletions

View File

@ -623,9 +623,9 @@ object MDIChild: TMDIChild
496
31)
object btnColumnSelection: TSpeedButton
Left = 168
Left = 187
Top = 4
Width = 79
Width = 70
Height = 21
AllowAllUp = True
Anchors = [akTop, akRight]
@ -642,12 +642,12 @@ object MDIChild: TMDIChild
FF00F7806300E3805C00C18032008080300000004700}
Layout = blGlyphRight
ParentFont = False
OnClick = btnColumnSelectionClick
OnClick = btnDataClick
end
object lblDataTop: TLabel
Left = 1
Top = 1
Width = 161
Width = 104
Height = 29
Align = alLeft
Anchors = [akLeft, akTop, akRight, akBottom]
@ -656,6 +656,28 @@ object MDIChild: TMDIChild
Layout = tlCenter
WordWrap = True
end
object btnDataSorting: TSpeedButton
Left = 111
Top = 4
Width = 70
Height = 21
AllowAllUp = True
Anchors = [akTop, akRight]
GroupIndex = 10
Caption = 'Sorting'
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Glyph.Data = {
52000000424D52000000000000003E0000002800000009000000050000000100
010000000000140000000000000000000000020000000200000000000000FFFF
FF00F7806300E3805C00C18032008080300000004700}
Layout = blGlyphRight
ParentFont = False
OnClick = btnDataClick
end
object EditDataSearch: TEdit
Left = 317
Top = 4

View File

@ -285,6 +285,7 @@ type
MenuReplace: TMenuItem;
MenuItem2: TMenuItem;
lblDataTop: TLabel;
btnDataSorting: TSpeedButton;
procedure menuclearClick(Sender: TObject);
procedure popupQueryPopup(Sender: TObject);
procedure lboxQueryHelpersClick(Sender: TObject);
@ -293,7 +294,7 @@ type
var AllowChange: Boolean);
procedure btnTableViewDataClick(Sender: TObject);
procedure btnDbViewDataClick(Sender: TObject);
procedure btnColumnSelectionClick(Sender: TObject);
procedure btnDataClick(Sender: TObject);
procedure DBtreeExpanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
procedure ListTablesSelectItem(Sender: TObject; Item: TListItem;
@ -546,7 +547,7 @@ implementation
uses
Main, createtable, fieldeditor, tbl_properties, tblcomment,
optimizetables, copytable, sqlhelp, printlist,
column_selection, mysql;
column_selection, data_sorting, mysql;
{$I const.inc}
@ -1356,6 +1357,7 @@ var
manualLimitEnd : integer;
DisplayedColumnsList : TStringList;
tmp : TDataSet;
RewriteOrderClause : Boolean;
begin
viewingdata := true;
try
@ -1411,7 +1413,6 @@ begin
if ( not dataselected ) then
begin
SynMemoFilter.Text := '';
gridData.SortColumns.Clear();
// Read cached WHERE-clause and set filter
reg_value := 'WHERECLAUSE_' + ActualDatabase + '.' + ActualTable;
if ( reg.ValueExists( reg_value ) ) then
@ -1422,87 +1423,73 @@ begin
tabFilter.tabVisible := true;
PageControlBottom.ActivePage := tabFilter;
end;
// Read cached ORDER-clause and set Grid.Sortcolumns
reg_value := 'ORDERCLAUSE_' + ActualDatabase + '.' + ActualTable;
if ( reg.ValueExists( reg_value ) ) then
begin
orderclauses := explode( ',', reg.ReadString( reg_value ) );
for i := 0 to ( orderclauses.Count - 1 ) do
begin
columnname := Trim( Copy( orderclauses[i], 0, Pos( ' ', orderclauses[i] ) ) );
columnname := trimc( columnname, '`' );
columnexists := false;
for j := 0 to ( ListColumns.Items.Count - 1 ) do
begin
if ( ListColumns.Items[j].Caption = columnname ) then
begin
columnexists := true;
Break;
end;
end;
if ( not columnexists ) then
begin
LogSQL( 'Notice: A stored ORDER-BY clause could not be applied, '+
'because the column "' + columnname + '" does not exist!');
Continue;
end;
with ( gridData.SortColumns.Add() ) do
begin
Fieldname := columnname;
if ( Copy( orderclauses[i], ( Length( orderclauses[i] ) - 3 ), 4 ) = 'DESC' ) then
begin
SortType := stAscending;
end
else
begin
SortType := stDescending;
end;
end;
end;
end;
end;
sorting := '';
for i := 0 to ( gridData.SortColumns.Count - 1 ) do
begin
with ( gridData.SortColumns[i] ) do
begin
if ( SortType <> stNone ) then
begin
if ( sorting <> '' ) then
begin
sorting := sorting + ', ';
end;
sorting := sorting + mask( FieldName );
end;
case SortType of
// stNone: ;
stAscending :
begin
sorting := sorting + ' DESC';
end;
stDescending:
begin
sorting := sorting + ' ASC';
end;
end;
end;
end;
// Read cached ORDER-clause and set Grid.Sortcolumns
reg_value := 'ORDERCLAUSE_' + ActualDatabase + '.' + ActualTable;
if ( sorting <> '' ) then
begin
reg.WriteString( reg_value, sorting );
sorting := 'ORDER BY ' + sorting;
end
else
sorting := '';
gridData.SortColumns.Clear();
if ( reg.ValueExists( reg_value ) ) then
begin
reg.DeleteValue( reg_value );
orderclauses := explode( ',', reg.ReadString( reg_value ) );
RewriteOrderClause := False;
for i := 0 to ( orderclauses.Count - 1 ) do
begin
columnname := Trim( Copy( orderclauses[i], 0, Pos( ' ', orderclauses[i] ) ) );
columnname := trimc( columnname, '`' );
columnexists := false;
for j := 0 to ( ListColumns.Items.Count - 1 ) do
begin
if ( ListColumns.Items[j].Caption = columnname ) then
begin
columnexists := true;
Break;
end;
end;
if ( not columnexists ) then
begin
LogSQL( 'Notice: A stored ORDER-BY clause could not be applied, '+
'because the column "' + columnname + '" does not exist!');
RewriteOrderClause := True;
Continue;
end;
// Add column to order clause
if sorting <> '' then
sorting := sorting + ', ';
sorting := sorting + orderclauses[i];
with ( gridData.SortColumns.Add() ) do
begin
Fieldname := columnname;
if ( Copy( orderclauses[i], ( Length( orderclauses[i] ) - 3 ), 4 ) = 'DESC' ) then
begin
SortType := stAscending;
end
else
begin
SortType := stDescending;
end;
end;
end;
// Old orderclause contained a no longer existing column, so overwrite it
if RewriteOrderClause then
begin
reg.WriteString( reg_value, sorting );
end;
end;
if ( sorting <> '' ) then
begin
sorting := 'ORDER BY ' + sorting;
// Signal for the user that we applied an ORDER-clause
btnDataSorting.Font.Color := clRed;
end
else
begin
btnDataSorting.Font.Color := clWindowText;
end;
MenuLimit.Checked := Mainform.CheckBoxLimit.Checked;
@ -3590,6 +3577,9 @@ var
Grid : TSMDBGrid;
i : Integer;
existed : Boolean;
sortcol : TSMSortColumn;
sorting, reg_value : String;
reg : TRegistry;
begin
// column-title clicked -> generate "ORDER BY"
@ -3599,28 +3589,72 @@ begin
for i:=Grid.SortColumns.Count-1 downto 0 do
begin
with Grid.SortColumns[i] do
begin
if FieldName <> column.FieldName then
continue;
existed := true;
case SortType of
stDescending : SortType := stAscending;
stAscending : Grid.SortColumns.Delete(i);
stNone : SortType := stDescending;
end;
sortcol := Grid.SortColumns[i];
if sortcol.FieldName <> Column.FieldName then
continue;
existed := true;
case sortcol.SortType of
stDescending : sortcol.SortType := stAscending;
stAscending : Grid.SortColumns.Delete(i);
stNone : sortcol.SortType := stDescending;
end;
end;
{add a new sorted column in list - ascending order}
if not existed then with Grid.SortColumns.Add do
if not existed then
begin
FieldName := column.FieldName;
SortType := stDescending
sortcol := Grid.SortColumns.Add;
sortcol.FieldName := column.FieldName;
sortcol.SortType := stDescending;
end;
Grid.DataSource.DataSet.EnableControls;
viewdata(self);
// Concat orderclause
sorting := '';
for i := 0 to ( gridData.SortColumns.Count - 1 ) do
begin
sortcol := gridData.SortColumns[i];
if ( sortcol.SortType <> stNone ) then
begin
if ( sorting <> '' ) then
begin
sorting := sorting + ', ';
end;
sorting := sorting + mask( sortcol.FieldName );
end;
case sortcol.SortType of
// stNone: ;
stAscending :
begin
sorting := sorting + ' DESC';
end;
stDescending:
begin
sorting := sorting + ' ASC';
end;
end;
end;
// Write orderclause to registry
reg := TRegistry.Create();
reg.OpenKey( REGPATH + '\Servers\' + FConn.Description, true );
reg_value := 'ORDERCLAUSE_' + ActualDatabase + '.' + ActualTable;
if ( sorting <> '' ) then
begin
reg.WriteString( reg_value, sorting );
end
else
begin
if ( reg.ValueExists( reg_value ) ) then
reg.DeleteValue( reg_value );
end;
reg.CloseKey;
ViewData(self);
end;
@ -5489,16 +5523,22 @@ end;
{**
Column selection for datagrid
}
procedure TMDIChild.btnColumnSelectionClick(Sender: TObject);
procedure TMDIChild.btnDataClick(Sender: TObject);
var
btn : TSpeedButton;
frm : TColumnSelectionForm;
frm : TForm;
begin
btn := (Sender as TSpeedButton);
if btn.Down then
begin
frm := TColumnSelectionForm.Create(self);
// Create the desired form
if btn = btnColumnSelection then
frm := TColumnSelectionForm.Create(self)
else if btn = btnDataSorting then
frm := TDataSortingForm.Create(self)
else
frm := TForm.Create(self); // Dummy fallback, should never get created
// Position new form relative to btn's position
frm.Top := btn.ClientOrigin.Y + btn.Height;
@ -5506,6 +5546,8 @@ begin
// Display form
frm.ShowModal;
btn.Down := False;
end;
end;

64
source/data_sorting.dfm Normal file
View File

@ -0,0 +1,64 @@
object DataSortingForm: TDataSortingForm
Left = 0
Top = 0
BorderStyle = bsNone
Caption = 'DataSortingForm'
ClientHeight = 63
ClientWidth = 204
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object pnlBevel: TPanel
Left = 0
Top = 0
Width = 204
Height = 63
Align = alClient
BorderWidth = 3
TabOrder = 0
DesignSize = (
204
63)
object btnOK: TButton
Left = 3
Top = 34
Width = 60
Height = 25
Anchors = [akLeft, akBottom]
Caption = 'OK'
Default = True
Enabled = False
ModalResult = 1
TabOrder = 0
OnClick = btnOKClick
end
object btnCancel: TButton
Left = 68
Top = 34
Width = 60
Height = 25
Anchors = [akLeft, akBottom]
Cancel = True
Caption = 'Cancel'
ModalResult = 2
TabOrder = 1
end
object btnAddCol: TButton
Left = 134
Top = 34
Width = 60
Height = 25
Anchors = [akLeft, akBottom]
Caption = 'Add Col'
TabOrder = 2
OnClick = btnAddColClick
end
end
end

350
source/data_sorting.pas Normal file
View File

@ -0,0 +1,350 @@
unit data_sorting;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, Buttons, Registry, smdbgrid;
type
TOrderCol = record
ColumnName: String;
SortDirection: Byte;
end;
type
TDataSortingForm = class(TForm)
pnlBevel: TPanel;
btnOK: TButton;
btnCancel: TButton;
btnAddCol: TButton;
procedure btnAddColClick(Sender: TObject);
procedure btnOKClick(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
ColumnNames : TStringList;
OrderColumns : Array of TOrderCol;
procedure DisplaySortingControls;
procedure dropdownColsChange( Sender: TObject );
procedure buttonOrderClick( Sender: TObject );
procedure buttonDeleteClick( Sender: TObject );
procedure Modified;
public
{ Public declarations }
end;
const
ORDER_ASC = 0; // Used for tag-value of "Direction"-button
ORDER_DESC = 1; // dito
TXT_ASC = 'ASC'; // Used for caption of "Direction"-button
TXT_DESC = 'DESC'; // dito
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}
{**
Initialization
}
procedure TDataSortingForm.FormShow(Sender: TObject);
var
i : Cardinal;
grid: TSMDBGrid;
begin
// Take column names from listColumns and add here
ColumnNames := TStringList.Create;
for i := 0 to Mainform.Childwin.listColumns.Items.Count-1 do
begin
ColumnNames.Add( Mainform.Childwin.listColumns.Items[i].Caption );
end;
// Create one OrderColumns record for each grid.SortColumn
grid := Mainform.Childwin.gridData;
if grid.SortColumns.Count > 0 then // Avoids AV when accessing SortColumn[0] ... ??
begin
for i := 0 to grid.SortColumns.Count - 1 do
begin
SetLength( OrderColumns, i+1 );
OrderColumns[i].ColumnName := grid.SortColumns[i].FieldName;
if grid.SortColumns[i].SortType = stDescending then
OrderColumns[i].SortDirection := ORDER_ASC
else
OrderColumns[i].SortDirection := ORDER_DESC; // Also applies for SortType = stNone
end;
end;
// 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 := ColumnNames;
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); // 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;
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;
// 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.
}
procedure TDataSortingForm.Modified;
begin
btnOk.Enabled := True;
end;
{**
OK clicked
}
procedure TDataSortingForm.btnOKClick(Sender: TObject);
var
reg : TRegistry;
reg_name, reg_value, sort : String;
i : Integer;
begin
// Concat all sort options to a ORDER clause
reg_value := '';
for i := 0 to Length(OrderColumns) - 1 do
begin
if reg_value <> '' then
reg_value := reg_value + ', ';
if OrderColumns[i].SortDirection = ORDER_ASC then
sort := TXT_ASC
else
sort := TXT_DESC;
reg_value := reg_value + Mainform.Mask( OrderColumns[i].ColumnName ) + ' ' + sort;
end;
// Write ORDER clause to registry
reg := TRegistry.Create();
reg.OpenKey( REGPATH + '\Servers\' + Mainform.Childwin.Description, true );
reg_name := 'ORDERCLAUSE_' + Mainform.Childwin.ActualDatabase + '.' + Mainform.Childwin.ActualTable;
reg.WriteString( reg_name, reg_value );
reg.CloseKey;
// Refresh data
Mainform.Childwin.viewdata(self);
end;
end.