From 3f0b70c409b08c2a9a27cc79c0649353ced6a041 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Mon, 27 Aug 2007 00:01:53 +0000 Subject: [PATCH] Switch ListColumns from TSortListView to TVirtualStringTree Additionally/Sideeffects: - Fix vstFreeNode to delete the item from the array, not only free the item itself - Change/Rename GetSelectedNodesFromVT to GetVTCaptions and give it the ability to return all captions, not only the selected. This function is very useful now and saves writing much redundant code. A table with 500 columns needed 3 seconds to display in the TSortListView, now that takes less than a half second. --- source/childwin.dfm | 69 +++++++---- source/childwin.pas | 239 +++++++++++++++++++----------------- source/column_selection.pas | 11 +- source/data_sorting.pas | 8 +- source/exportsql.pas | 2 +- source/fieldeditor.pas | 48 ++++---- source/helpers.pas | 30 +++-- source/main.pas | 2 +- source/printlist.pas | 7 +- source/tbl_properties.pas | 2 +- 10 files changed, 233 insertions(+), 185 deletions(-) diff --git a/source/childwin.dfm b/source/childwin.dfm index d4272b81..aee60295 100644 --- a/source/childwin.dfm +++ b/source/childwin.dfm @@ -641,49 +641,70 @@ object MDIChild: TMDIChild end end end - object ListColumns: TSortListView - Tag = -1 + object ListColumns: TVirtualStringTree Left = 28 Top = 17 Width = 468 Height = 203 Align = alClient + EditDelay = 500 + Header.AutoSizeIndex = 0 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.Height = 20 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoHotTrack, hoShowSortGlyphs, hoVisible] + Images = MainForm.ImageList1 + IncrementalSearch = isInitializedOnly + PopupMenu = popupTableGrid + TabOrder = 2 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] + OnChange = ListColumnsChange + OnCompareNodes = vstCompareNodes + OnDblClick = UpdateField + OnFreeNode = vstFreeNode + OnGetText = vstGetText + OnGetImageIndex = vstGetImageIndex + OnGetNodeDataSize = vstGetNodeDataSize + OnHeaderClick = vstHeaderClick + OnInitNode = vstInitNode + OnKeyUp = controlsKeyUp + OnNewText = ListColumnsNewText Columns = < item - Caption = 'Name' - Width = -1 - WidthType = ( - -1) + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 0 + Width = 94 + WideText = 'Name' end item - Caption = 'Type' + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 1 Width = 100 + WideText = 'Type' end item - Caption = 'Null' + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 2 Width = 40 + WideText = 'Null' end item - Caption = 'Default' + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 3 Width = 115 + WideText = 'Default' end item - Caption = 'Extra' - Width = 200 + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 4 + Width = 100 + WideText = 'Extra' end> - GridLines = True - MultiSelect = True - RowSelect = True - PopupMenu = popupTableGrid - SmallImages = MainForm.ImageList1 - TabOrder = 2 - ViewStyle = vsReport - OnDblClick = UpdateField - OnEdited = ListColumnsEdited - OnKeyUp = controlsKeyUp - OnSelectItem = ListColumnsSelectItem - ImageIndexSortAsc = 0 - ImageIndexSortDesc = 0 end end object tabData: TTabSheet diff --git a/source/childwin.pas b/source/childwin.pas index 5d173077..4be9ff5b 100644 --- a/source/childwin.pas +++ b/source/childwin.pas @@ -110,7 +110,7 @@ type PopupMenuDropTable: TMenuItem; N17: TMenuItem; pnlTableToolbar: TPanel; - ListColumns: TSortListView; + ListColumns: TVirtualStringTree; CopycontentsasHTML1: TMenuItem; CopycontentsasHTML2: TMenuItem; Copy3: TMenuItem; @@ -307,8 +307,8 @@ type tlbTableLeft2: TToolBar; btnTableInsertRecord: TToolButton; procedure menuRenameColumnClick(Sender: TObject); - procedure ListColumnsEdited(Sender: TObject; Item: TListItem; - var S: string); + procedure ListColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; NewText: WideString); procedure menuclearClick(Sender: TObject); procedure popupQueryPopup(Sender: TObject); procedure lboxQueryHelpersClick(Sender: TObject); @@ -321,8 +321,7 @@ type procedure DBtreeExpanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); procedure ListTablesClick(Sender: TObject); - procedure ListColumnsSelectItem(Sender: TObject; Item: TListItem; - Selected: Boolean); + procedure ListColumnsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure DBMemo1Exit(Sender: TObject); procedure btnUnsafeEditClick(Sender: TObject); procedure gridMouseDown(Sender: TObject; Button: TMouseButton; @@ -545,7 +544,8 @@ type VTRowDataListVariables, VTRowDataListProcesses, VTRowDataListCommandStats, - VTRowDataListTables : Array of TVTreeData; + VTRowDataListTables, + VTRowDataListColumns : TVTreeDataArray; FProgressForm : TFrmQueryProgress; procedure Init(AConn : POpenConnProf; AMysqlConn : TMysqlConn); @@ -1280,8 +1280,6 @@ begin tabTable.TabVisible := false; tabData.TabVisible := false; - ListTables.Clear; - ListColumns.Items.Clear(); pnlTableTop.Caption := 'Table-Properties'; Caption := Description + ' - /' + ActualDatabase; ActualDatabase := db; @@ -1381,7 +1379,7 @@ var DropDown : TStringList; i : Integer; j : Integer; - Columns : TStringList; + ValidColumns : TStringList; PrimaryKeyColumns : TStringList; reg : TRegistry; reg_value : String; @@ -1473,20 +1471,12 @@ begin begin orderclauses := explode( ',', reg.ReadString( reg_value ) ); RewriteOrderClause := False; + ValidColumns := GetVTCaptions( ListColumns ); for i := 0 to ( orderclauses.Count - 1 ) do begin columnname := Trim( Copy( orderclauses[i], 0, LastPos( ' ', 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; + columnexists := ValidColumns.IndexOf(columnname) > -1; if ( not columnexists ) then begin @@ -1533,7 +1523,6 @@ begin end; MenuLimit.Checked := Mainform.CheckBoxLimit.Checked; - Columns := TStringList.Create(); PrimaryKeyColumns := TStringList.Create(); if ( ( ActualTable <> '' ) and ( ActualDatabase <> '' ) ) then @@ -1645,14 +1634,13 @@ begin MainForm.ShowStatus( STATUS_MSG_READY, 2 ); - for i := 0 to ( ListColumns.Items.Count - 1 ) do + for i := 0 to Length(VTRowDataListColumns) - 1 do begin - Columns.Add( ListColumns.Items[i].Caption ); // give all enum-fields a PickList with its Items - if ( StrCmpBegin( 'enum', ListColumns.Items[i].SubItems[0]) ) then + if ( StrCmpBegin( 'enum', VTRowDataListColumns[i].Captions[1]) ) then begin - DropDown := explode( ''',''', getEnumValues( ListColumns.Items[i].SubItems[0] ) ); + DropDown := explode( ''',''', getEnumValues( VTRowDataListColumns[i].Captions[1] ) ); for j := 0 to ( DropDown.Count - 1 ) do begin DropDown[j] := trimc( DropDown[j], '''' ); @@ -1660,7 +1648,7 @@ begin for j := 0 to ( gridData.Columns.Count - 1 ) do begin - if ( gridData.Columns[j].FieldName = ListColumns.Items[i].Caption ) then + if ( gridData.Columns[j].FieldName = VTRowDataListColumns[i].Captions[0] ) then begin gridData.Columns[j].PickList := DropDown; end; @@ -1671,11 +1659,11 @@ begin for j := 0 to ( gridData.Columns.Count - 1 ) do begin if ( - ( gridData.Columns[j].FieldName = ListColumns.Items[i].Caption ) and - ( ListColumns.Items[i].ImageIndex = 26 ) + ( gridData.Columns[j].FieldName = VTRowDataListColumns[i].Captions[0] ) and + ( VTRowDataListColumns[i].ImageIndex = 26 ) ) then begin - PrimaryKeyColumns.Add( ListColumns.Items[i].Caption ); + PrimaryKeyColumns.Add( VTRowDataListColumns[i].Captions[0] ); end; end; end; @@ -2145,7 +2133,6 @@ end; procedure TMDIChild.ShowTableProperties(Sender: TObject); var i,j : Integer; - n : TListItem; tn, tndb : TTreeNode; isFulltext : Boolean; ds : TDataSet; @@ -2185,26 +2172,28 @@ begin end; MainForm.ShowStatus( 'Reading table properties...', 2, true ); - ListColumns.Items.BeginUpdate; - ListColumns.Items.Clear; + ListColumns.BeginUpdate; + ListColumns.Clear; Try ds := GetResults( 'SHOW COLUMNS FROM ' + mask(ActualTable), false ); + SetLength(VTRowDataListColumns, ds.RecordCount); for i:=1 to ds.RecordCount do begin - n := ListColumns.Items.Add; - n.ImageIndex := ICONINDEX_FIELD; - - n.Caption := ds.FieldByName('Field').AsString; - n.Subitems.Add( ds.FieldByName('Type').AsString ); + VTRowDataListColumns[i-1].ImageIndex := ICONINDEX_FIELD; + VTRowDataListColumns[i-1].Captions := TStringList.Create; + VTRowDataListColumns[i-1].Captions.Add( ds.FieldByName('Field').AsString ); + VTRowDataListColumns[i-1].Captions.Add( ds.FieldByName('Type').AsString ); if lowercase( ds.FieldByName('Null').AsString ) = 'yes' then - n.Subitems.Add('Yes') - else n.Subitems.Add('No'); - n.Subitems.Add( ds.FieldByName('Default').AsString ); - n.Subitems.Add( ds.FieldByName('Extra').AsString ); + VTRowDataListColumns[i-1].Captions.Add('Yes') + else VTRowDataListColumns[i-1].Captions.Add('No'); + VTRowDataListColumns[i-1].Captions.Add( ds.FieldByName('Default').AsString ); + VTRowDataListColumns[i-1].Captions.Add( ds.FieldByName('Extra').AsString ); ds.Next; end; + ListColumns.RootNodeCount := Length(VTRowDataListColumns); + // Manually invoke OnChange event of tabset to fill helper list with data if tabsetQueryHelpers.TabIndex = 0 then tabsetQueryHelpers.OnChange( Sender, tabsetQueryHelpers.TabIndex, dummy); @@ -2232,12 +2221,12 @@ begin for i:=1 to ds.RecordCount do begin // Search for the column name in listColumns - for j:=0 to ListColumns.Items.Count-1 do + for j:=0 to Length(VTRowDataListColumns)-1 do begin - if ds.FieldByName('Column_name').AsString = ListColumns.Items[j].Caption then + if ds.FieldByName('Column_name').AsString = VTRowDataListColumns[j].Captions[0] then begin // Only apply a new icon if it was not already changed - if ListColumns.Items[j].ImageIndex <> ICONINDEX_FIELD then + if VTRowDataListColumns[j].ImageIndex <> ICONINDEX_FIELD then break; // Check if column is part of a fulltext key @@ -2248,16 +2237,16 @@ begin // Primary key if ds.FieldByName('Key_name').AsString = 'PRIMARY' then - ListColumns.Items[j].ImageIndex := ICONINDEX_PRIMARYKEY + VTRowDataListColumns[j].ImageIndex := ICONINDEX_PRIMARYKEY // Fulltext index else if isFullText then - ListColumns.Items[j].ImageIndex := ICONINDEX_FULLTEXTKEY + VTRowDataListColumns[j].ImageIndex := ICONINDEX_FULLTEXTKEY // Unique index else if ds.FieldByName('Non_unique').AsString = '0' then - ListColumns.Items[j].ImageIndex := ICONINDEX_UNIQUEKEY + VTRowDataListColumns[j].ImageIndex := ICONINDEX_UNIQUEKEY // Normal index else - ListColumns.Items[j].ImageIndex := ICONINDEX_INDEXKEY; + VTRowDataListColumns[j].ImageIndex := ICONINDEX_INDEXKEY; // Column was found and processed break; @@ -2265,17 +2254,28 @@ begin end; ds.Next; end; + { + ** note, ansgarbecker, 2007-08-26 + VT has a pretty autosorting feature, which keeps the sorting even after having + filled it with new data. + But: Don't use this auto-sorting here, neither automatically nor manual + because that would cause big confusion to the user if a just clicked + table displays its fields not in the natural order. + + @todo Detect if the list was just refreshed (and then keep sorting) + or if another table get displayed (then don't sort, as below) + } + ListColumns.Header.SortColumn := -1; + ListColumns.Header.SortDirection := sdAscending; finally - ListColumns.Items.EndUpdate; - // Remove existing column-sort-images - // (TODO: auomatically invoke this method in TSortListView itself) - ListColumns.ClearSortColumnImages; + + ListColumns.EndUpdate; Screen.Cursor := crDefault; end; MainForm.ShowStatus( STATUS_MSG_READY, 2, false ); - MainForm.showstatus(ActualDatabase + ': '+ ActualTable + ': ' + IntToStr(ListColumns.Items.count) +' field(s)'); + MainForm.showstatus(ActualDatabase + ': '+ ActualTable + ': ' + IntToStr(ListColumns.RootNodeCount) +' field(s)'); Screen.Cursor := crDefault; end; @@ -2478,7 +2478,7 @@ begin exit; // Add selected items/tables to helper list - t := GetSelectedNodesFromVT(ListTables); + t := GetVTCaptions(ListTables, True); if MessageDlg('Empty ' + IntToStr(t.count) + ' Table(s) ?' + crlf + '(' + implodestr(', ', t) + ')', mtConfirmation, [mbok,mbcancel], 0) <> mrok then exit; @@ -2932,44 +2932,41 @@ begin end; -procedure TMDIChild.ListColumnsSelectItem(Sender: TObject; Item: TListItem; - Selected: Boolean); +{** + Clicked somewhere in the field-list of the "Table"-tabsheet +} +procedure TMDIChild.ListColumnsChange(Sender: TBaseVirtualTree; Node: + PVirtualNode); var - SomeSelected: Boolean; + SomeSelected, OneFocused: Boolean; begin - // Clicked somewhere in the field-list of the "Table"-tabsheet - // some columns selected ? - SomeSelected := ListColumns.Selected <> nil; + OneFocused := Assigned(Sender.FocusedNode); + SomeSelected := Length(Sender.GetSortedSelection(False))>0; // Toggle state of menuitems and buttons btnTableDropField.Enabled := SomeSelected; DropField1.Enabled := SomeSelected; - MenuEditField.Enabled := SomeSelected; - btnTableEditField.enabled := SomeSelected; - menuRenameColumn.Enabled := SomeSelected; + MenuEditField.Enabled := OneFocused; + btnTableEditField.enabled := OneFocused; + menuRenameColumn.Enabled := OneFocused; end; procedure TMDIChild.DropField(Sender: TObject); var tn : TTreeNode; - i, j: Integer; + i : Integer; dropCmd : String; dropList : TStringList; begin // Drop Columns // We allow the user to select and delete multiple listItems - dropList := TStringList.Create; - for i := 0 to ListColumns.Items.Count - 1 do - begin - if ListColumns.Items[i].Selected then - dropList.Add(ListColumns.Items[i].Caption); - end; + dropList := GetVTCaptions( ListColumns, True ); // In case all listItems are selected: - if dropList.Count = ListColumns.Items.Count then + if dropList.Count = Length(VTRowDataListColumns) then begin if MessageDlg('Can''t drop all or the last Field - drop Table '+ActualTable+'?', mtConfirmation, [mbok,mbcancel], 0) = mrok then begin @@ -2999,20 +2996,12 @@ begin // Rely on the server respective ExecUpdateQuery has raised an exception so the // following code will be skipped on any error - for i := ListColumns.Items.Count - 1 downto 0 do - begin - for j := 0 to dropList.Count - 1 do - begin - if dropList[j] = ListColumns.Items[i].Caption then - begin - ListColumns.Items[i].Delete; - break; - end; - end; - end; + ListColumns.BeginUpdate; + ListColumns.DeleteSelectedNodes; + ListColumns.EndUpdate; - // Set focus on automatically focused item - ListColumns.Selected := ListColumns.ItemFocused; + // Set focus on first item + ListColumns.FocusedNode := ListColumns.GetFirstVisible; except On E : Exception do begin @@ -3307,8 +3296,8 @@ begin fn := ''; fem := femFieldAdd; - if ListColumns.Selected<>nil then - fn := ListColumns.Selected.Caption; + if Assigned(ListColumns.FocusedNode) then + fn := ListColumns.Text[ListColumns.FocusedNode, 0]; if fn<>'' then fem := femFieldUpdate; @@ -3484,7 +3473,7 @@ var begin // Optimize tables Screen.Cursor := crHourGlass; - Selected := GetSelectedNodesFromVT( ListTables ); + Selected := GetVTCaptions( ListTables, True ); try for i:=0 to Selected.Count-1 do begin @@ -3506,7 +3495,7 @@ begin // Check tables Screen.Cursor := crHourGlass; tables := ''; - Selected := GetSelectedNodesFromVT( ListTables ); + Selected := GetVTCaptions( ListTables, True ); try for i:=0 to Selected.Count-1 do begin @@ -3550,7 +3539,7 @@ begin // Analyze tables Screen.Cursor := crHourGlass; tables := ''; - Selected := GetSelectedNodesFromVT( ListTables ); + Selected := GetVTCaptions( ListTables, True ); try for i:=0 to Selected.Count-1 do begin @@ -3575,7 +3564,7 @@ begin // Repair tables Screen.Cursor := crHourGlass; tables := ''; - Selected := GetSelectedNodesFromVT( ListTables ); + Selected := GetVTCaptions( ListTables, True ); try for i:=0 to Selected.Count - 1 do begin @@ -4192,7 +4181,7 @@ var begin tabletype := (Sender as TMenuItem).Caption; tabletype := StringReplace( tabletype, '&', '', [rfReplaceAll] ); // Remove Auto-Hotkey - Selected := GetSelectedNodesFromVT(ListTables); + Selected := GetVTCaptions(ListTables, True); for i:=0 to Selected.Count - 1 do ExecUpdateQuery( 'ALTER TABLE ' + mask(Selected[i]) + ' TYPE = ' + tabletype); Selected.Free; @@ -4207,7 +4196,7 @@ var begin // change table-type: if inputquery('Change table-type...','New table-type:', strtype) then begin - Selected := GetSelectedNodesFromVT(ListTables); + Selected := GetVTCaptions(ListTables, True); for i:=0 to Selected.Count - 1 do ExecUpdateQuery( 'ALTER TABLE ' + mask(Selected[i]) + ' TYPE = ' + strtype ); Selected.Free; @@ -4537,14 +4526,14 @@ begin // Data-Tab else if (PageControlMain.ActivePage = tabData) and (-1 < gridData.Col) - and (gridData.Col <= ListColumns.Items.Count) then + and (gridData.Col <= Length(VTRowDataListColumns)) then begin - keyword := ListColumns.Items[gridData.Col-1].SubItems[0]; + keyword := VTRowDataListColumns[gridData.Col-1].Captions[1]; end // Table-Tab - else if ListColumns.Focused and (ListColumns.Selected <> nil) then + else if ListColumns.Focused and Assigned(ListColumns.FocusedNode) then begin - keyword := ListColumns.Selected.SubItems[0]; + keyword := ListColumns.Text[ListColumns.FocusedNode, 1]; end else if lboxQueryHelpers.Focused then begin @@ -5682,9 +5671,9 @@ begin begin // Keep native order of columns lboxQueryHelpers.Sorted := False; - for i := 0 to ListColumns.Items.Count - 1 do + for i := 0 to High(VTRowDataListColumns) do begin - lboxQueryHelpers.Items.Add(ListColumns.Items[i].Caption); + lboxQueryHelpers.Items.Add(VTRowDataListColumns[i].Captions[0]); end; end; @@ -5793,25 +5782,29 @@ end; } procedure TMDIChild.menuRenameColumnClick(Sender: TObject); begin - listColumns.Selected.EditCaption; + ListColumns.EditNode(ListColumns.FocusedNode, 0); end; {** Rename a column name from within listColumns } -procedure TMDIChild.ListColumnsEdited(Sender: TObject; Item: TListItem; - var S: string); +procedure TMDIChild.ListColumnsNewText(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; NewText: WideString); var def : TDataSet; sql_update, sql_null, sql_default, sql_extra, DefaultValue : String; + NodeData : PVTreeData; begin // Try to rename, on any error abort and don't rename ListItem try - ensureValidIdentifier( S ); + ensureValidIdentifier( NewText ); + + // Fetch data from listitem + NodeData := ListColumns.GetNodeData(Node); // Fetch column definition - def := GetResults( 'SHOW COLUMNS FROM ' + mask(ActualTable) + ' LIKE ' + esc(Item.Caption), False, False ); + def := GetResults( 'SHOW COLUMNS FROM ' + mask(ActualTable) + ' LIKE ' + esc(NodeData.Captions[0]), False, False ); // Check NOT NULL sql_null := 'NULL '; @@ -5835,8 +5828,8 @@ begin // Concat column definition sql_update := 'ALTER TABLE ' + mask(ActualTable) + - ' CHANGE ' + mask(Item.Caption) + - ' ' + mask(S) + ' ' + + ' CHANGE ' + mask(NodeData.Captions[0]) + + ' ' + mask(NewText) + ' ' + def.FieldByName('Type').AsString + ' ' + sql_null + sql_default + @@ -5844,11 +5837,13 @@ begin // Fire ALTER query ExecUpdateQuery( sql_update, False, False ); + + // Update listitem + NodeData.Captions[0] := NewText; except On E : Exception do begin MessageDlg( E.Message, mtError, [mbOK], 0 ); - abort; end; end; end; @@ -5968,6 +5963,11 @@ begin begin NodeData.Captions := VTRowDataListTables[Node.Index].Captions; NodeData.ImageIndex := VTRowDataListTables[Node.Index].ImageIndex; + end + else if Sender = ListColumns then + begin + NodeData.Captions := VTRowDataListColumns[Node.Index].Captions; + NodeData.ImageIndex := VTRowDataListColumns[Node.Index].ImageIndex; end; end; @@ -5978,13 +5978,30 @@ end; procedure TMDIChild.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var - NodeData : PVTreeData; + a : TVTreeDataArray; begin - // Get the pointer to the node data - NodeData := Sender.GetNodeData(Node); - // Free data - NodeData.Captions.Free; - NodeData.ImageIndex := -1; + // Detect which global array should be processed + if Sender = ListVariables then + a := VTRowDataListVariables + else if Sender = ListCommandStats then + a := VTRowDataListCommandStats + else if Sender = ListProcesses then + a := VTRowDataListProcesses + else if Sender = ListTables then + a := VTRowDataListTables + else if Sender = ListColumns then + a := VTRowDataListColumns; + + if Node.Index < Cardinal(High(a)-1) then + begin + // Delete node somewhere in the middle of the array + // Taken from http://delphi.about.com/cs/adptips2004/a/bltip0204_2.htm + System.Move( a[Node.Index +1], + a[Node.Index], + (Cardinal(Length(a)) - Node.Index -1) * SizeOf(TVTreeData) + 1 + ); + end; + SetLength(a, Length(a) - 1) end; diff --git a/source/column_selection.pas b/source/column_selection.pas index 85be6a76..1147cb02 100644 --- a/source/column_selection.pas +++ b/source/column_selection.pas @@ -46,11 +46,7 @@ var reg_columns : TStringList; begin // Take column names from listColumns and add here - chklistColumns.Items.Clear; - for i := 0 to Mainform.Childwin.listColumns.Items.Count-1 do - begin - chklistColumns.Items.Add( Mainform.Childwin.listColumns.Items[i].Caption ); - end; + chklistColumns.Items := GetVTCaptions(Mainform.Childwin.ListColumns); // Set global reg_name (also used in btnOKClick) reg_name := REGNAME_DISPLAYEDCOLUMNS + '_' + Mainform.Childwin.ActualDatabase + '.' + Mainform.Childwin.ActualTable; @@ -218,10 +214,9 @@ begin // Add all fieldnames again and check those which are in the checkedfields list chklistColumns.Items.BeginUpdate; - chklistColumns.Items.Clear; - for i := 0 to Mainform.Childwin.listColumns.Items.Count-1 do + chklistColumns.Items := GetVTCaptions(Mainform.Childwin.ListColumns); + for i := 0 to chklistColumns.Items.Count-1 do begin - chklistColumns.Items.Add( Mainform.Childwin.listColumns.Items[i].Caption ); if checkedfields.IndexOf( chklistColumns.Items[i] ) > -1 then chklistColumns.Checked[i] := True; end; diff --git a/source/data_sorting.pas b/source/data_sorting.pas index a03b1ee2..24f5c685 100644 --- a/source/data_sorting.pas +++ b/source/data_sorting.pas @@ -49,7 +49,7 @@ const implementation -uses main; +uses main, helpers; {$R *.dfm} @@ -64,11 +64,7 @@ var reg : TRegistry; 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; + ColumnNames := GetVTCaptions( Mainform.Childwin.ListColumns ); // Read original ORDER clause from registry reg := TRegistry.Create(); diff --git a/source/exportsql.pas b/source/exportsql.pas index 1d5dce9e..d8dafb0b 100644 --- a/source/exportsql.pas +++ b/source/exportsql.pas @@ -358,7 +358,7 @@ begin checkListTables.Items := Mainform.ChildWin.GetCol( 'SHOW TABLES FROM ' + MainForm.mask(comboSelectDatabase.Text) ); // Fetch selected tables in list - Selected := GetSelectedNodesFromVT( Mainform.ChildWin.ListTables ); + Selected := GetVTCaptions( Mainform.ChildWin.ListTables, True ); // select all/some: for i:=0 to checkListTables.Items.Count-1 do diff --git a/source/fieldeditor.pas b/source/fieldeditor.pas index 6724e6fc..bdef8b78 100644 --- a/source/fieldeditor.pas +++ b/source/fieldeditor.pas @@ -10,7 +10,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ComCtrls, ImgList, ToolWin, ExtCtrls, Buttons; + StdCtrls, ComCtrls, ImgList, ToolWin, ExtCtrls, Buttons, VirtualTrees; type TFieldEditorMode = (femFieldAdd,femFieldUpdate,femIndexEditor); @@ -130,7 +130,8 @@ procedure TFieldEditForm.InitFieldEditor(Sender: TObject); var strtype : String; i : Integer; - ListColumns : TListView; + ListColumns : TVirtualStringTree; + NodeData : PVTreeData; begin // Initiate "Position"-combobox @@ -143,9 +144,9 @@ begin // get fieldlist // add fieldnames - for i:=0 to ListColumns.Items.Count-1 do + for i:=0 to High(Mainform.Childwin.VTRowDataListColumns) do begin - ComboBoxPosition.Items.Add('AFTER ' + mainform.mask(ListColumns.Items[i].Caption)); + ComboBoxPosition.Items.Add('AFTER ' + mainform.mask(Mainform.Childwin.VTRowDataListColumns[i].Captions[0])); end; // re-fill datatypes-combobox @@ -168,8 +169,8 @@ begin EditDefault.Text := ''; CheckBoxUnsigned.Checked := true; - if ListColumns.Selected <> nil then - ComboBoxPosition.ItemIndex := ListColumns.Selected.Index+2 + if Assigned(ListColumns.FocusedNode) then + ComboBoxPosition.ItemIndex := ListColumns.FocusedNode.Index+2 else ComboBoxPosition.ItemIndex := 0; end; @@ -177,12 +178,13 @@ begin // "Field" tab in Update-mode femFieldUpdate: begin - EditFieldname.Text := ListColumns.Selected.Caption; - EditLength.Text := getEnumValues( ListColumns.Selected.Subitems[0] ); - EditDefault.Text := ListColumns.Selected.Subitems[2]; + NodeData := ListColumns.GetNodeData(ListColumns.FocusedNode); + EditFieldname.Text := FFieldName; + EditLength.Text := getEnumValues( NodeData.Captions[1] ); + EditDefault.Text := NodeData.Captions[3]; // extract field type - strtype := UpperCase( ListColumns.Selected.Subitems[0] ); + strtype := UpperCase( NodeData.Captions[1] ); if Pos ('(',strtype) > 0 then strtype := Trim(copy (strtype,0,Pos ('(',strtype)-1)); @@ -202,12 +204,12 @@ begin end; // set attributes: - strtype := LowerCase( ListColumns.Selected.Subitems[0] ); + strtype := LowerCase( NodeData.Captions[1] ); CheckBoxBinary.Checked := pos('binary', strtype) > 0; CheckBoxZerofill.Checked := pos('zerofill', strtype) > 0; CheckBoxUnsigned.Checked := pos('unsigned', strtype) > 0; - CheckBoxNotNull.Checked := lowercase(ListColumns.Selected.Subitems[1]) <> 'yes'; - CheckBoxAutoIncrement.Checked := lowercase(ListColumns.Selected.Subitems[3]) = 'auto_increment'; + CheckBoxNotNull.Checked := lowercase(NodeData.Captions[2]) <> 'yes'; + CheckBoxAutoIncrement.Checked := lowercase(NodeData.Captions[4]) = 'auto_increment'; // TODO: Disable 'auto increment' checkbox if field is not part of index or primary key. end; @@ -252,10 +254,7 @@ begin ds.Next; end; - for i:=0 to cwin.ListColumns.Items.Count-1 do begin - if cwin.ListColumns.Items[i] <> nil then - self.listColumnsAvailable.Items.Add(cwin.ListColumns.Items[i].Caption); - end; + listColumnsAvailable.Items := GetVTCaptions(cwin.ListColumns); showkeys(); end; @@ -431,7 +430,7 @@ begin end else if (FMode = femFieldUpdate) then begin cwin.ExecUpdateQuery( 'ALTER TABLE ' + mainform.mask(cwin.ActualTable) + ' ' + // table - 'CHANGE ' + mainform.mask(cwin.ListColumns.Selected.Caption) + ' ' + // old name + 'CHANGE ' + mainform.mask(FFieldName) + ' ' + // old name mainform.mask(EditFieldName.Text) + ' ' + // new name fielddef ); @@ -532,13 +531,16 @@ end; @todo code cleanup, get rid of WITH statement } procedure TFieldEditForm.ComboBoxKeysChange(Sender: TObject); -var i : Integer; +var i, j : Integer; begin if ComboBoxKeys.ItemIndex > -1 then begin - listColumnsAvailable.Items.Clear; - for i:=0 to Mainform.ChildWin.ListColumns.Items.Count-1 do - if (Mainform.ChildWin.ListColumns.Items[i] <> nil) and (klist[ComboBoxKeys.ItemIndex].columns.Indexof(Mainform.ChildWin.ListColumns.Items[i].Caption)=-1) then - listColumnsAvailable.Items.Add(Mainform.ChildWin.ListColumns.Items[i].Caption); + listColumnsAvailable.Items := GetVTCaptions(Mainform.ChildWin.ListColumns); + for i:=0 to klist[ComboBoxKeys.ItemIndex].columns.Count-1 do + begin + j := listColumnsAvailable.Items.IndexOf(klist[ComboBoxKeys.ItemIndex].columns[i]); + if j > -1 then + listColumnsAvailable.Items.Delete( j ); + end; with klist[ComboBoxKeys.ItemIndex] do begin listColumnsUsed.Items := Columns; CheckBoxUnique.OnClick := nil; diff --git a/source/helpers.pas b/source/helpers.pas index 6cd63c04..2462c8cf 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -21,6 +21,9 @@ type end; PVTreedata = ^TVTreeData; + // Standardize the list with node-data-records to be able to + // use this type as variables in functions/procedures (fx VT.OnFreeNode) + TVTreeDataArray = Array of TVTreeData; {$I const.inc} @@ -81,7 +84,7 @@ type function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; function FormatTimeNumber( Seconds: Cardinal ): String; function TColorToHex( Color : TColor ): string; - function GetSelectedNodesFromVT( VT: TVirtualStringTree; Column: Integer = 0 ): TStringList; + function GetVTCaptions( VT: TVirtualStringTree; OnlySelected: Boolean = False; Column: Integer = 0 ): TStringList; var MYSQL_KEYWORDS : TStringList; @@ -1996,18 +1999,31 @@ end; Return a TStringList with captions from all selected nodes in a VirtualTree Especially helpful when toMultiSelect is True } -function GetSelectedNodesFromVT( VT: TVirtualStringTree; Column: Integer = 0 ): TStringList; +function GetVTCaptions( VT: TVirtualStringTree; OnlySelected: Boolean = False; Column: Integer = 0 ): TStringList; var SelectedNodes : TNodeArray; - NodeData : PVTreeData; + Node : PVirtualNode; i: Integer; begin Result := TStringList.Create; - SelectedNodes := VT.GetSortedSelection(False); - for i := 0 to Length(SelectedNodes) - 1 do + if OnlySelected then begin - NodeData := VT.GetNodeData(SelectedNodes[i]); - Result.Add(NodeData.Captions[Column]); + // Fetch only selected nodes + SelectedNodes := VT.GetSortedSelection(False); + for i := 0 to Length(SelectedNodes) - 1 do + begin + Node := SelectedNodes[i]; + Result.Add( VT.Text[ Node, Column ] ); + end; + end + else begin + // Fetch all nodes + Node := VT.GetFirst; + for i := 0 to VT.RootNodeCount - 1 do + begin + Result.Add( VT.Text[ Node, Column ] ); + Node := VT.GetNext(Node); + end; end; end; diff --git a/source/main.pas b/source/main.pas index 99607980..b11cb5f4 100644 --- a/source/main.pas +++ b/source/main.pas @@ -994,7 +994,7 @@ begin t.add(mask(DBRightClickSelectedItem.Parent.text) + '.' + mask(DBRightClickSelectedItem.text)); end else if PageControlMain.ActivePage = tabDatabase then begin // Invoked from one of the various buttons, SheetDatabase is the active page, drop highlighted table(s). - t := GetSelectedNodesFromVT(ListTables); + t := GetVTCaptions(ListTables, True); for i:=0 to t.count-1 do begin t[i] := mask(t[i]); diff --git a/source/printlist.pas b/source/printlist.pas index 54238209..d1885296 100644 --- a/source/printlist.pas +++ b/source/printlist.pas @@ -72,15 +72,16 @@ begin cwin := Mainform.ChildWin; // which ListView to print? - case cwin.PageControlMain.ActivePageIndex of + // TODO: Reactivate after switching to VirtualTree! +// case cwin.PageControlMain.ActivePageIndex of // 0 : case cwin.PageControlHost.ActivePageIndex of // 0 : begin list := cwin.ListVariables; title := 'Server-Variables for ' + cwin.Conn.MysqlParams.Host; end; // 1 : begin list := cwin.ListProcesses; title := 'Processlist for ' + cwin.Conn.MysqlParams.Host; end; // 2 : begin list := cwin.ListCommandStats; title := 'Command-statistics for ' + cwin.Conn.MysqlParams.Host; end; // end; // 1 : begin list := cwin.ListTables; title := 'Tables-List for Database ' + cwin.ActualDatabase; end; - 2 : begin list := cwin.ListColumns; title := 'Field-List for ' + cwin.ActualDatabase + '/' + cwin.ActualTable; end; - end; +// 2 : begin list := cwin.ListColumns; title := 'Field-List for ' + cwin.ActualDatabase + '/' + cwin.ActualTable; end; +// end; caption := 'Print ' + title + '...'; // delete all CheckBoxes diff --git a/source/tbl_properties.pas b/source/tbl_properties.pas index d208e934..d163a386 100644 --- a/source/tbl_properties.pas +++ b/source/tbl_properties.pas @@ -95,7 +95,7 @@ begin end; // Fetch selected nodes - Selected := GetSelectedNodesFromVT(ListTables); + Selected := GetVTCaptions(ListTables, True); // for tables found for t := 0 to (query.RecordCount - 1) do