mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-26 11:17:57 +08:00
Implement query history in helpers tree. See http://www.heidisql.com/forum.php?t=8927 .
This commit is contained in:
@ -171,7 +171,6 @@ type
|
|||||||
function GetRegValue( valueName: String; defaultValue: Boolean; Session: String = '' ) : Boolean; Overload;
|
function GetRegValue( valueName: String; defaultValue: Boolean; Session: String = '' ) : Boolean; Overload;
|
||||||
function GetRegValue( valueName: String; defaultValue: String; Session: String = '' ) : String; Overload;
|
function GetRegValue( valueName: String; defaultValue: String; Session: String = '' ) : String; Overload;
|
||||||
procedure DeInitializeVTNodes(Sender: TBaseVirtualTree);
|
procedure DeInitializeVTNodes(Sender: TBaseVirtualTree);
|
||||||
function CompareNumbers(List: TStringList; Index1, Index2: Integer): Integer;
|
|
||||||
function ListIndexByRegExpr(List: TStrings; Expression: String): Integer;
|
function ListIndexByRegExpr(List: TStrings; Expression: String): Integer;
|
||||||
function FindNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode): PVirtualNode;
|
function FindNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode): PVirtualNode;
|
||||||
procedure SelectNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode=nil); overload;
|
procedure SelectNode(VT: TVirtualStringTree; idx: Cardinal; ParentNode: PVirtualNode=nil); overload;
|
||||||
@ -195,6 +194,8 @@ type
|
|||||||
function LoadConnectionParams(Session: String): TConnectionParameters;
|
function LoadConnectionParams(Session: String): TConnectionParameters;
|
||||||
function CharAtPos(Str: String; Pos: Integer): Char;
|
function CharAtPos(Str: String; Pos: Integer): Char;
|
||||||
function CompareAnyNode(Text1, Text2: String): Integer;
|
function CompareAnyNode(Text1, Text2: String): Integer;
|
||||||
|
function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer;
|
||||||
|
function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer;
|
||||||
function GetColumnDefaultType(var Text: String): TColumnDefaultType;
|
function GetColumnDefaultType(var Text: String): TColumnDefaultType;
|
||||||
function GetColumnDefaultClause(DefaultType: TColumnDefaultType; Text: String): String;
|
function GetColumnDefaultClause(DefaultType: TColumnDefaultType; Text: String): String;
|
||||||
function GetImageLinkTimeStamp(const FileName: string): TDateTime;
|
function GetImageLinkTimeStamp(const FileName: string): TDateTime;
|
||||||
@ -1572,22 +1573,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function CompareNumbers(List: TStringList; Index1, Index2: Integer): Integer;
|
|
||||||
var
|
|
||||||
Number1, Number2 : Extended;
|
|
||||||
begin
|
|
||||||
// Custom sort method for TStringLists
|
|
||||||
Number1 := MakeFloat( List[Index1] );
|
|
||||||
Number2 := MakeFloat( List[Index2] );
|
|
||||||
if Number1 > Number2 then
|
|
||||||
Result := 1
|
|
||||||
else if Number1 = Number2 then
|
|
||||||
Result := 0
|
|
||||||
else
|
|
||||||
Result := -1;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function ListIndexByRegExpr(List: TStrings; Expression: String): Integer;
|
function ListIndexByRegExpr(List: TStrings; Expression: String): Integer;
|
||||||
var
|
var
|
||||||
rx: TRegExpr;
|
rx: TRegExpr;
|
||||||
@ -2407,6 +2392,20 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer;
|
||||||
|
begin
|
||||||
|
// Sort TStringList items, containing numbers or strings, ascending
|
||||||
|
Result := CompareAnyNode(List[Index1], List[Index2]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer;
|
||||||
|
begin
|
||||||
|
// Sort TStringList items, containing numbers or strings, descending
|
||||||
|
Result := CompareAnyNode(List[Index2], List[Index1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function GetColumnDefaultType(var Text: String): TColumnDefaultType;
|
function GetColumnDefaultType(var Text: String): TColumnDefaultType;
|
||||||
begin
|
begin
|
||||||
Result := TColumnDefaultType(MakeInt(Copy(Text, 1, 1)));
|
Result := TColumnDefaultType(MakeInt(Copy(Text, 1, 1)));
|
||||||
|
@ -1537,7 +1537,7 @@ object MainForm: TMainForm
|
|||||||
Images = ImageListMain
|
Images = ImageListMain
|
||||||
IncrementalSearch = isAll
|
IncrementalSearch = isAll
|
||||||
PopupMenu = popupQueryHelpers
|
PopupMenu = popupQueryHelpers
|
||||||
RootNodeCount = 5
|
RootNodeCount = 6
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
TextMargin = 0
|
TextMargin = 0
|
||||||
TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSpanColumns, toAutoTristateTracking, toAutoDeleteMovedNodes]
|
TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSpanColumns, toAutoTristateTracking, toAutoDeleteMovedNodes]
|
||||||
@ -1548,6 +1548,7 @@ object MainForm: TMainForm
|
|||||||
OnContextPopup = treeQueryHelpersContextPopup
|
OnContextPopup = treeQueryHelpersContextPopup
|
||||||
OnDblClick = treeQueryHelpersDblClick
|
OnDblClick = treeQueryHelpersDblClick
|
||||||
OnFocusChanging = treeQueryHelpersFocusChanging
|
OnFocusChanging = treeQueryHelpersFocusChanging
|
||||||
|
OnFreeNode = treeQueryHelpersFreeNode
|
||||||
OnGetText = treeQueryHelpersGetText
|
OnGetText = treeQueryHelpersGetText
|
||||||
OnPaintText = treeQueryHelpersPaintText
|
OnPaintText = treeQueryHelpersPaintText
|
||||||
OnGetImageIndex = treeQueryHelpersGetImageIndex
|
OnGetImageIndex = treeQueryHelpersGetImageIndex
|
||||||
|
379
source/main.pas
379
source/main.pas
@ -15,7 +15,7 @@ uses
|
|||||||
SynEdit, SynEditTypes, SynEditKeyCmds, VirtualTrees, DateUtils, SyncObjs,
|
SynEdit, SynEditTypes, SynEditKeyCmds, VirtualTrees, DateUtils, SyncObjs,
|
||||||
ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter,
|
ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter,
|
||||||
SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, ExtActns, IOUtils, Types, Themes, ComObj,
|
SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, ExtActns, IOUtils, Types, Themes, ComObj,
|
||||||
CommCtrl, Contnrs, Generics.Collections, SynEditExport, SynExportHTML, Math, ExtDlgs, Registry, AppEvnts,
|
CommCtrl, Contnrs, Generics.Collections, Generics.Defaults, SynEditExport, SynExportHTML, Math, ExtDlgs, Registry, AppEvnts,
|
||||||
routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor,
|
routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor,
|
||||||
TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection,
|
TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection,
|
||||||
insertfiles, searchreplace, loaddata, copytable, VTHeaderPopup, Cromis.DirectoryWatch, SyncDB;
|
insertfiles, searchreplace, loaddata, copytable, VTHeaderPopup, Cromis.DirectoryWatch, SyncDB;
|
||||||
@ -59,6 +59,7 @@ type
|
|||||||
QueryProfile: TDBQuery;
|
QueryProfile: TDBQuery;
|
||||||
ProfileTime, MaxProfileTime: Extended;
|
ProfileTime, MaxProfileTime: Extended;
|
||||||
LeftOffsetInMemo: Integer;
|
LeftOffsetInMemo: Integer;
|
||||||
|
HistoryDays: TStringList;
|
||||||
function GetActiveResultTab: TResultTab;
|
function GetActiveResultTab: TResultTab;
|
||||||
procedure DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string);
|
procedure DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string);
|
||||||
procedure MemofileModifiedTimerNotify(Sender: TObject);
|
procedure MemofileModifiedTimerNotify(Sender: TObject);
|
||||||
@ -70,6 +71,24 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TQueryHistoryItem = class(TObject)
|
||||||
|
Time: TDateTime;
|
||||||
|
Database: String;
|
||||||
|
SQL: String;
|
||||||
|
Duration: Cardinal;
|
||||||
|
RegValue: Integer;
|
||||||
|
end;
|
||||||
|
TQueryHistory = class(TObjectList<TQueryHistoryItem>)
|
||||||
|
private
|
||||||
|
FMaxDuration: Cardinal;
|
||||||
|
public
|
||||||
|
property MaxDuration: Cardinal read FMaxDuration;
|
||||||
|
function ReadItem(RegValue: Integer): TQueryHistoryItem;
|
||||||
|
end;
|
||||||
|
TQueryHistoryItemComparer = class(TComparer<TQueryHistoryItem>)
|
||||||
|
function Compare(const Left, Right: TQueryHistoryItem): Integer; override;
|
||||||
|
end;
|
||||||
|
|
||||||
ITaskbarList = interface(IUnknown)
|
ITaskbarList = interface(IUnknown)
|
||||||
[SID_ITaskbarList]
|
[SID_ITaskbarList]
|
||||||
function HrInit: HRESULT; stdcall;
|
function HrInit: HRESULT; stdcall;
|
||||||
@ -742,6 +761,7 @@ type
|
|||||||
function ActiveQueryTab: TQueryTab;
|
function ActiveQueryTab: TQueryTab;
|
||||||
function ActiveOrEmptyQueryTab(ConsiderActiveTab: Boolean): TQueryTab;
|
function ActiveOrEmptyQueryTab(ConsiderActiveTab: Boolean): TQueryTab;
|
||||||
function GetQueryTabByNumber(Number: Integer): TQueryTab;
|
function GetQueryTabByNumber(Number: Integer): TQueryTab;
|
||||||
|
function GetQueryTabByHelpers(FindTree: TBaseVirtualTree): TQueryTab;
|
||||||
function ActiveQueryMemo: TSynMemo;
|
function ActiveQueryMemo: TSynMemo;
|
||||||
function ActiveQueryHelpers: TVirtualStringTree;
|
function ActiveQueryHelpers: TVirtualStringTree;
|
||||||
function ActiveSynMemo: TSynMemo;
|
function ActiveSynMemo: TSynMemo;
|
||||||
@ -825,6 +845,7 @@ type
|
|||||||
var ContentRect: TRect);
|
var ContentRect: TRect);
|
||||||
procedure treeQueryHelpersDblClick(Sender: TObject);
|
procedure treeQueryHelpersDblClick(Sender: TObject);
|
||||||
procedure treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
|
procedure treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
|
||||||
|
procedure treeQueryHelpersFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||||||
procedure treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
procedure treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
||||||
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
||||||
procedure treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode,
|
procedure treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode,
|
||||||
@ -2320,11 +2341,16 @@ end;
|
|||||||
procedure TMainForm.FinishedQueryExecution(Thread: TQueryThread);
|
procedure TMainForm.FinishedQueryExecution(Thread: TQueryThread);
|
||||||
var
|
var
|
||||||
Tab, WarningsTab: TQueryTab;
|
Tab, WarningsTab: TQueryTab;
|
||||||
MetaInfo, ErroneousSQL, MsgTitle, MsgText: String;
|
MetaInfo, ErroneousSQL, RegName, RegItem, MsgTitle, MsgText: String;
|
||||||
ProfileAllTime: Extended;
|
ProfileAllTime: Extended;
|
||||||
ProfileNode: PVirtualNode;
|
ProfileNode: PVirtualNode;
|
||||||
|
AllRegItems: TStringList;
|
||||||
|
History: TQueryHistory;
|
||||||
|
HistoryItem: TQueryHistoryItem;
|
||||||
Warnings: TDBQuery;
|
Warnings: TDBQuery;
|
||||||
MaxWarnings: Integer;
|
HistoryNum, MaxWarnings, RegItemsSize: Integer;
|
||||||
|
DoDelete: Boolean;
|
||||||
|
MinDate: TDateTime;
|
||||||
|
|
||||||
procedure GoToErrorPos(Err: String);
|
procedure GoToErrorPos(Err: String);
|
||||||
var
|
var
|
||||||
@ -2430,6 +2456,59 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
// Store successful query packet in history if it's not a batch.
|
||||||
|
// Assume that a bunch of up to 5 queries is not a batch.
|
||||||
|
if IsEmpty(Thread.ErrorMessage) and (Thread.Batch.Count <= 5) and (Thread.Batch.Size <= SIZE_MB) then begin
|
||||||
|
ShowStatusMsg('Updating query history ...');
|
||||||
|
OpenRegistry(Thread.Connection.Parameters.SessionName);
|
||||||
|
MainReg.OpenKey(REGKEY_QUERYHISTORY, true);
|
||||||
|
|
||||||
|
// Load all items so we can clean up
|
||||||
|
AllRegItems := TStringList.Create;
|
||||||
|
MainReg.GetValueNames(AllRegItems);
|
||||||
|
History := TQueryHistory.Create;
|
||||||
|
for RegItem in AllRegItems do begin
|
||||||
|
History.ReadItem(StrToInt(RegItem));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Find lowest unused item number
|
||||||
|
HistoryNum := 0;
|
||||||
|
while True do begin
|
||||||
|
Inc(HistoryNum);
|
||||||
|
RegName := IntToStr(HistoryNum);
|
||||||
|
if AllRegItems.IndexOf(RegName) = -1 then
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Sort by date
|
||||||
|
History.Sort(TQueryHistoryItemComparer.Create);
|
||||||
|
|
||||||
|
// Delete identical history items to avoid spam
|
||||||
|
// Delete old items
|
||||||
|
// Delete items which exceed a max datasize barrier
|
||||||
|
MinDate := IncDay(Now, -30);
|
||||||
|
RegItemsSize := Thread.Batch.Size;
|
||||||
|
for HistoryItem in History do begin
|
||||||
|
Inc(RegItemsSize, Length(HistoryItem.SQL));
|
||||||
|
DoDelete := (HistoryItem.SQL = Thread.Batch.SQL)
|
||||||
|
or (HistoryItem.Time < MinDate)
|
||||||
|
or (RegItemsSize > SIZE_MB);
|
||||||
|
if DoDelete then
|
||||||
|
MainReg.DeleteValue(IntToStr(HistoryItem.RegValue));
|
||||||
|
end;
|
||||||
|
History.Free;
|
||||||
|
|
||||||
|
// Store history item and closing registry key to ensure writing has finished
|
||||||
|
MainReg.WriteString(RegName, DateTimeToStr(Now) + DELIM +
|
||||||
|
Thread.Connection.Database + DELIM +
|
||||||
|
IntToStr(Thread.QueryTime+Thread.QueryNetTime) + DELIM +
|
||||||
|
Thread.Batch.SQL);
|
||||||
|
MainReg.CloseKey;
|
||||||
|
|
||||||
|
RefreshHelperNode(HELPERNODE_HISTORY);
|
||||||
|
end;
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
DisableProgress;
|
DisableProgress;
|
||||||
Tab.QueryRunning := False;
|
Tab.QueryRunning := False;
|
||||||
@ -3823,7 +3902,7 @@ begin
|
|||||||
Filters.Add(Trim(SynMemoFilter.Text));
|
Filters.Add(Trim(SynMemoFilter.Text));
|
||||||
MainReg.OpenKey(GetRegKeyTable+'\'+REGNAME_FILTERS, True);
|
MainReg.OpenKey(GetRegKeyTable+'\'+REGNAME_FILTERS, True);
|
||||||
MainReg.GetValueNames(OldNumbers);
|
MainReg.GetValueNames(OldNumbers);
|
||||||
OldNumbers.CustomSort(CompareNumbers);
|
OldNumbers.CustomSort(StringListCompareAnythingAsc);
|
||||||
// Add old filters
|
// Add old filters
|
||||||
for i := 0 to OldNumbers.Count - 1 do begin
|
for i := 0 to OldNumbers.Count - 1 do begin
|
||||||
nr := MakeInt(OldNumbers[i]);
|
nr := MakeInt(OldNumbers[i]);
|
||||||
@ -5304,7 +5383,7 @@ begin
|
|||||||
src := Source as TControl;
|
src := Source as TControl;
|
||||||
// Accepting drag's from DBTree and QueryHelpers
|
// Accepting drag's from DBTree and QueryHelpers
|
||||||
H := ActiveQueryHelpers;
|
H := ActiveQueryHelpers;
|
||||||
Accept := (src = DBtree) or ((src = H) and Assigned(H.FocusedNode) and (H.GetNodeLevel(H.FocusedNode)=1));
|
Accept := (src = DBtree) or ((src = H) and Assigned(H.FocusedNode) and (H.GetNodeLevel(H.FocusedNode) in [1,2]));
|
||||||
// set x-position of cursor
|
// set x-position of cursor
|
||||||
Memo.CaretX := (x - Memo.Gutter.Width) div Memo.CharWidth - 1 + Memo.LeftChar;
|
Memo.CaretX := (x - Memo.Gutter.Width) div Memo.CharWidth - 1 + Memo.LeftChar;
|
||||||
// set y-position of cursor
|
// set y-position of cursor
|
||||||
@ -5322,6 +5401,7 @@ var
|
|||||||
ShiftPressed: Boolean;
|
ShiftPressed: Boolean;
|
||||||
Tree: TVirtualStringTree;
|
Tree: TVirtualStringTree;
|
||||||
Node: PVirtualNode;
|
Node: PVirtualNode;
|
||||||
|
History: TQueryHistory;
|
||||||
begin
|
begin
|
||||||
// dropping a tree node or listbox item into the query-memo
|
// dropping a tree node or listbox item into the query-memo
|
||||||
ActiveQueryMemo.UndoList.AddGroupBreak;
|
ActiveQueryMemo.UndoList.AddGroupBreak;
|
||||||
@ -5342,27 +5422,37 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end else if src = Tree then begin
|
end else if src = Tree then begin
|
||||||
if (Tree.GetNodeLevel(Tree.FocusedNode) = 1) and Assigned(Tree.FocusedNode) then begin
|
case Tree.GetNodeLevel(Tree.FocusedNode) of
|
||||||
case Tree.FocusedNode.Parent.Index of
|
1:
|
||||||
HELPERNODE_SNIPPETS:
|
case Tree.FocusedNode.Parent.Index of
|
||||||
Text := ReadTextFile(FDirnameSnippets + Tree.Text[Tree.FocusedNode, 0] + '.sql', nil);
|
HELPERNODE_SNIPPETS:
|
||||||
else begin
|
Text := ReadTextFile(FDirnameSnippets + Tree.Text[Tree.FocusedNode, 0] + '.sql', nil);
|
||||||
Node := Tree.GetFirstChild(Tree.FocusedNode.Parent);
|
HELPERNODE_HISTORY:
|
||||||
while Assigned(Node) do begin
|
Text := '';
|
||||||
if Tree.Selected[Node] then begin
|
else begin
|
||||||
ItemText := Tree.Text[Node, 0];
|
Node := Tree.GetFirstChild(Tree.FocusedNode.Parent);
|
||||||
if Node.Parent.Index = HELPERNODE_COLUMNS then
|
while Assigned(Node) do begin
|
||||||
ItemText := ActiveConnection.QuoteIdent(ItemText, False); // Quote column names
|
if Tree.Selected[Node] then begin
|
||||||
if ShiftPressed then
|
ItemText := Tree.Text[Node, 0];
|
||||||
Text := Text + ItemText + ',' + CRLF
|
if Node.Parent.Index = HELPERNODE_COLUMNS then
|
||||||
else
|
ItemText := ActiveConnection.QuoteIdent(ItemText, False); // Quote column names
|
||||||
Text := Text + ItemText + ', ';
|
if ShiftPressed then
|
||||||
|
Text := Text + ItemText + ',' + CRLF
|
||||||
|
else
|
||||||
|
Text := Text + ItemText + ', ';
|
||||||
|
end;
|
||||||
|
Node := Tree.GetNextSibling(Node);
|
||||||
end;
|
end;
|
||||||
Node := Tree.GetNextSibling(Node);
|
Delete(Text, Length(Text)-1, 2);
|
||||||
end;
|
end;
|
||||||
Delete(Text, Length(Text)-1, 2);
|
|
||||||
end;
|
end;
|
||||||
end;
|
2:
|
||||||
|
case Tree.FocusedNode.Parent.Parent.Index of
|
||||||
|
HELPERNODE_HISTORY: begin
|
||||||
|
History := ActiveQueryTab.HistoryDays.Objects[Tree.FocusedNode.Parent.Index] as TQueryHistory;
|
||||||
|
Text := History[Tree.FocusedNode.Index].SQL;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end else
|
end else
|
||||||
raise Exception.Create('Unspecified source control in drag''n drop operation!');
|
raise Exception.Create('Unspecified source control in drag''n drop operation!');
|
||||||
@ -7042,6 +7132,7 @@ begin
|
|||||||
if (PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection) then begin
|
if (PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection) then begin
|
||||||
LogSQL('Entering session "'+FActiveDbObj.Connection.Parameters.SessionName+'"', lcInfo);
|
LogSQL('Entering session "'+FActiveDbObj.Connection.Parameters.SessionName+'"', lcInfo);
|
||||||
DBTree.Color := GetRegValue(REGNAME_TREEBACKGROUND, clWindow, FActiveDbObj.Connection.Parameters.SessionName);
|
DBTree.Color := GetRegValue(REGNAME_TREEBACKGROUND, clWindow, FActiveDbObj.Connection.Parameters.SessionName);
|
||||||
|
RefreshHelperNode(HELPERNODE_HISTORY);
|
||||||
case FActiveDbObj.Connection.Parameters.NetTypeGroup of
|
case FActiveDbObj.Connection.Parameters.NetTypeGroup of
|
||||||
ngMySQL:
|
ngMySQL:
|
||||||
SynSQLSyn1.SQLDialect := sqlMySQL;
|
SynSQLSyn1.SQLDialect := sqlMySQL;
|
||||||
@ -7188,6 +7279,8 @@ procedure TMainForm.DatabaseChanged(Connection: TDBConnection; Database: String)
|
|||||||
begin
|
begin
|
||||||
// Immediately force db icons to repaint, so the user sees the active db state
|
// Immediately force db icons to repaint, so the user sees the active db state
|
||||||
DBtree.Repaint;
|
DBtree.Repaint;
|
||||||
|
if ActiveQueryHelpers <> nil then
|
||||||
|
ActiveQueryHelpers.Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -8770,6 +8863,7 @@ begin
|
|||||||
QueryTab.treeHelpers.OnBeforeCellPaint := treeQueryHelpers.OnBeforeCellPaint;
|
QueryTab.treeHelpers.OnBeforeCellPaint := treeQueryHelpers.OnBeforeCellPaint;
|
||||||
QueryTab.treeHelpers.OnContextPopup := treeQueryHelpers.OnContextPopup;
|
QueryTab.treeHelpers.OnContextPopup := treeQueryHelpers.OnContextPopup;
|
||||||
QueryTab.treeHelpers.OnDblClick := treeQueryHelpers.OnDblClick;
|
QueryTab.treeHelpers.OnDblClick := treeQueryHelpers.OnDblClick;
|
||||||
|
QueryTab.treeHelpers.OnFreeNode := treeQueryHelpers.OnFreeNode;
|
||||||
QueryTab.treeHelpers.OnGetImageIndex := treeQueryHelpers.OnGetImageIndex;
|
QueryTab.treeHelpers.OnGetImageIndex := treeQueryHelpers.OnGetImageIndex;
|
||||||
QueryTab.treeHelpers.OnGetText := treeQueryHelpers.OnGetText;
|
QueryTab.treeHelpers.OnGetText := treeQueryHelpers.OnGetText;
|
||||||
QueryTab.treeHelpers.OnInitChildren := treeQueryHelpers.OnInitChildren;
|
QueryTab.treeHelpers.OnInitChildren := treeQueryHelpers.OnInitChildren;
|
||||||
@ -9154,6 +9248,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TMainForm.GetQueryTabByHelpers(FindTree: TBaseVirtualTree): TQueryTab;
|
||||||
|
var
|
||||||
|
Tab: TQueryTab;
|
||||||
|
begin
|
||||||
|
// Find query tab where passed treeHelpers resides
|
||||||
|
Result := nil;
|
||||||
|
for Tab in QueryTabs do begin
|
||||||
|
if Tab.treeHelpers = FindTree then begin
|
||||||
|
Result := Tab;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TMainForm.ActiveQueryMemo: TSynMemo;
|
function TMainForm.ActiveQueryMemo: TSynMemo;
|
||||||
var
|
var
|
||||||
Tab: TQueryTab;
|
Tab: TQueryTab;
|
||||||
@ -9973,21 +10082,36 @@ procedure TMainForm.treeQueryHelpersBeforeCellPaint(Sender: TBaseVirtualTree; Ta
|
|||||||
var ContentRect: TRect);
|
var ContentRect: TRect);
|
||||||
var
|
var
|
||||||
Tab: TQueryTab;
|
Tab: TQueryTab;
|
||||||
|
History: TQueryHistory;
|
||||||
begin
|
begin
|
||||||
// Paint green value bar in cell
|
// Paint green value bar in cell
|
||||||
if (Node.Parent.Index=HELPERNODE_PROFILE)
|
if (Node.Parent.Index=HELPERNODE_PROFILE)
|
||||||
and (Column=1)
|
and (Column=1)
|
||||||
and (Sender.GetNodeLevel(Node)=1)
|
and (Sender.GetNodeLevel(Node)=1)
|
||||||
then begin
|
then begin
|
||||||
Tab := ActiveQueryTab;
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
Tab.QueryProfile.RecNo := Node.Index;
|
if Tab <> nil then begin
|
||||||
PaintColorBar(MakeFloat(Tab.QueryProfile.Col(Column)), Tab.MaxProfileTime, TargetCanvas, CellRect);
|
Tab.QueryProfile.RecNo := Node.Index;
|
||||||
|
PaintColorBar(MakeFloat(Tab.QueryProfile.Col(Column)), Tab.MaxProfileTime, TargetCanvas, CellRect);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if (Sender.GetNodeLevel(Node)=2)
|
||||||
|
and (Column=1)
|
||||||
|
and (Node.Parent.Parent.Index=HELPERNODE_HISTORY) then begin
|
||||||
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
|
if Tab <> nil then begin
|
||||||
|
History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory;
|
||||||
|
PaintColorBar(History[Node.Index].Duration, History.MaxDuration, TargetCanvas, CellRect);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
procedure TMainForm.treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
|
||||||
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
|
||||||
|
var
|
||||||
|
History: TQueryHistory;
|
||||||
|
Tab: TQueryTab;
|
||||||
begin
|
begin
|
||||||
// Paint text in datatype's color
|
// Paint text in datatype's color
|
||||||
if (Node.Parent.Index=HELPERNODE_COLUMNS)
|
if (Node.Parent.Index=HELPERNODE_COLUMNS)
|
||||||
@ -9997,6 +10121,15 @@ begin
|
|||||||
then begin
|
then begin
|
||||||
TargetCanvas.Font.Color := DatatypeCategories[SelectedTableColumns[Node.Index].DataType.Category].Color;
|
TargetCanvas.Font.Color := DatatypeCategories[SelectedTableColumns[Node.Index].DataType.Category].Color;
|
||||||
end;
|
end;
|
||||||
|
if (Sender.GetNodeLevel(Node)=2)
|
||||||
|
and (Node.Parent.Parent.Index=HELPERNODE_HISTORY) then begin
|
||||||
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
|
if Tab <> nil then begin
|
||||||
|
History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory;
|
||||||
|
if ActiveConnection.Database <> History[Node.Index].Database then
|
||||||
|
TargetCanvas.Font.Color := clGrayText;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -10037,6 +10170,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.treeQueryHelpersFreeNode(Sender: TBaseVirtualTree;
|
||||||
|
Node: PVirtualNode);
|
||||||
|
var
|
||||||
|
Values: TQueryHistory;
|
||||||
|
Tab: TQueryTab;
|
||||||
|
begin
|
||||||
|
// Free some memory, taken by probably big SQL query history items
|
||||||
|
if (Sender.GetNodeLevel(Node)=1)
|
||||||
|
and (Node.Parent.Index = HELPERNODE_HISTORY) then begin
|
||||||
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
|
if Tab <> nil then begin
|
||||||
|
Tab.HistoryDays.Objects[Node.Index].Free;
|
||||||
|
Tab.HistoryDays.Delete(Node.Index);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
procedure TMainForm.treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||||||
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
|
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
|
||||||
begin
|
begin
|
||||||
@ -10054,6 +10205,7 @@ begin
|
|||||||
HELPERNODE_FUNCTIONS: ImageIndex := 13;
|
HELPERNODE_FUNCTIONS: ImageIndex := 13;
|
||||||
HELPERNODE_KEYWORDS: ImageIndex := 25;
|
HELPERNODE_KEYWORDS: ImageIndex := 25;
|
||||||
HELPERNODE_SNIPPETS: ImageIndex := 51;
|
HELPERNODE_SNIPPETS: ImageIndex := 51;
|
||||||
|
HELPERNODE_HISTORY: ImageIndex := 149;
|
||||||
HELPERNODE_PROFILE: ImageIndex := 145;
|
HELPERNODE_PROFILE: ImageIndex := 145;
|
||||||
end;
|
end;
|
||||||
1: case Node.Parent.Index of
|
1: case Node.Parent.Index of
|
||||||
@ -10061,6 +10213,7 @@ begin
|
|||||||
HELPERNODE_FUNCTIONS: ImageIndex := 13;
|
HELPERNODE_FUNCTIONS: ImageIndex := 13;
|
||||||
HELPERNODE_KEYWORDS: ImageIndex := 25;
|
HELPERNODE_KEYWORDS: ImageIndex := 25;
|
||||||
HELPERNODE_SNIPPETS: ImageIndex := 68;
|
HELPERNODE_SNIPPETS: ImageIndex := 68;
|
||||||
|
HELPERNODE_HISTORY: ImageIndex := 80;
|
||||||
HELPERNODE_PROFILE: ImageIndex := 145;
|
HELPERNODE_PROFILE: ImageIndex := 145;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -10069,9 +10222,13 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
procedure TMainForm.treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||||||
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
|
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
|
||||||
|
var
|
||||||
|
History: TQueryHistory;
|
||||||
|
Tab: TQueryTab;
|
||||||
begin
|
begin
|
||||||
// Query helpers tree fetching node text
|
// Query helpers tree fetching node text
|
||||||
CellText := '';
|
CellText := '';
|
||||||
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
case Column of
|
case Column of
|
||||||
0: case Sender.GetNodeLevel(Node) of
|
0: case Sender.GetNodeLevel(Node) of
|
||||||
0: case Node.Index of
|
0: case Node.Index of
|
||||||
@ -10085,10 +10242,11 @@ begin
|
|||||||
HELPERNODE_FUNCTIONS: CellText := 'SQL Functions';
|
HELPERNODE_FUNCTIONS: CellText := 'SQL Functions';
|
||||||
HELPERNODE_KEYWORDS: CellText := 'SQL Keywords';
|
HELPERNODE_KEYWORDS: CellText := 'SQL Keywords';
|
||||||
HELPERNODE_SNIPPETS: CellText := 'Snippets';
|
HELPERNODE_SNIPPETS: CellText := 'Snippets';
|
||||||
|
HELPERNODE_HISTORY: CellText := 'Query history';
|
||||||
HELPERNODE_PROFILE: begin
|
HELPERNODE_PROFILE: begin
|
||||||
CellText := 'Query profile';
|
CellText := 'Query profile';
|
||||||
if Assigned(ActiveQueryTab.QueryProfile) then
|
if Assigned(Tab.QueryProfile) then
|
||||||
CellText := CellText + ' ('+FormatNumber(ActiveQueryTab.ProfileTime, 6)+'s)';
|
CellText := CellText + ' ('+FormatNumber(Tab.ProfileTime, 6)+'s)';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
1: case Node.Parent.Index of
|
1: case Node.Parent.Index of
|
||||||
@ -10103,13 +10261,27 @@ begin
|
|||||||
HELPERNODE_FUNCTIONS: CellText := MySQLFunctions[Node.Index].Name;
|
HELPERNODE_FUNCTIONS: CellText := MySQLFunctions[Node.Index].Name;
|
||||||
HELPERNODE_KEYWORDS: CellText := MySQLKeywords[Node.Index];
|
HELPERNODE_KEYWORDS: CellText := MySQLKeywords[Node.Index];
|
||||||
HELPERNODE_SNIPPETS: CellText := FSnippetFilenames[Node.Index];
|
HELPERNODE_SNIPPETS: CellText := FSnippetFilenames[Node.Index];
|
||||||
|
HELPERNODE_HISTORY: begin
|
||||||
|
CellText := Tab.HistoryDays[Node.Index];
|
||||||
|
if CellText = DateToStr(Today) then
|
||||||
|
CellText := CellText + ', today'
|
||||||
|
else if CellText = DateToStr(Yesterday) then
|
||||||
|
CellText := CellText + ', yesterday';
|
||||||
|
end;
|
||||||
HELPERNODE_PROFILE: begin
|
HELPERNODE_PROFILE: begin
|
||||||
if Assigned(ActiveQueryTab.QueryProfile) then begin
|
if Assigned(Tab.QueryProfile) then begin
|
||||||
ActiveQueryTab.QueryProfile.RecNo := Node.Index;
|
Tab.QueryProfile.RecNo := Node.Index;
|
||||||
CellText := ActiveQueryTab.QueryProfile.Col(Column);
|
CellText := Tab.QueryProfile.Col(Column);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
2: case Node.Parent.Parent.Index of
|
||||||
|
HELPERNODE_HISTORY: begin
|
||||||
|
History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory;
|
||||||
|
CellText := Copy(TimeToStr(History[Node.Index].Time), 1, 5)+': '+History[Node.Index].SQL;
|
||||||
|
end
|
||||||
|
else CellText := ''; // unused
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
1: case Sender.GetNodeLevel(Node) of
|
1: case Sender.GetNodeLevel(Node) of
|
||||||
0: CellText := '';
|
0: CellText := '';
|
||||||
@ -10119,13 +10291,19 @@ begin
|
|||||||
CellText := SelectedTableColumns[Node.Index].DataType.Name;
|
CellText := SelectedTableColumns[Node.Index].DataType.Name;
|
||||||
HELPERNODE_FUNCTIONS: CellText := MySQLFunctions[Node.Index].Declaration;
|
HELPERNODE_FUNCTIONS: CellText := MySQLFunctions[Node.Index].Declaration;
|
||||||
HELPERNODE_PROFILE: begin
|
HELPERNODE_PROFILE: begin
|
||||||
if Assigned(ActiveQueryTab.QueryProfile) then begin
|
if Assigned(Tab.QueryProfile) then begin
|
||||||
ActiveQueryTab.QueryProfile.RecNo := Node.Index;
|
Tab.QueryProfile.RecNo := Node.Index;
|
||||||
CellText := FormatNumber(ActiveQueryTab.QueryProfile.Col(Column))+'s';
|
CellText := FormatNumber(Tab.QueryProfile.Col(Column))+'s';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
else CellText := '';
|
else CellText := '';
|
||||||
end;
|
end;
|
||||||
|
2: case Node.Parent.Parent.Index of
|
||||||
|
HELPERNODE_HISTORY: begin
|
||||||
|
History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory;
|
||||||
|
CellText := FormatNumber(History[Node.Index].Duration / 1000, 3)+'s';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -10135,17 +10313,30 @@ procedure TMainForm.treeQueryHelpersInitNode(Sender: TBaseVirtualTree; ParentNod
|
|||||||
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
|
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
|
||||||
begin
|
begin
|
||||||
// Query helpers tree asking if plus/minus button should be displayed
|
// Query helpers tree asking if plus/minus button should be displayed
|
||||||
if Sender.GetNodeLevel(Node) = 0 then begin
|
case Sender.GetNodeLevel(Node) of
|
||||||
Include(InitialStates, ivsHasChildren);
|
0: begin
|
||||||
if Node.Index = HELPERNODE_PROFILE then
|
Include(InitialStates, ivsHasChildren);
|
||||||
Node.CheckType := ctCheckbox;
|
if Node.Index = HELPERNODE_PROFILE then
|
||||||
|
Node.CheckType := ctCheckbox;
|
||||||
|
end;
|
||||||
|
1: begin
|
||||||
|
if Node.Parent.Index = HELPERNODE_HISTORY then
|
||||||
|
Include(InitialStates, ivsHasChildren);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
procedure TMainForm.treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
||||||
var ChildCount: Cardinal);
|
var ChildCount: Cardinal);
|
||||||
|
var
|
||||||
|
Values: TStringList;
|
||||||
|
v, QueryDay: String;
|
||||||
|
History: TQueryHistory;
|
||||||
|
Item: TQueryHistoryItem;
|
||||||
|
Tab: TQueryTab;
|
||||||
begin
|
begin
|
||||||
|
Tab := GetQueryTabByHelpers(Sender);
|
||||||
case Sender.GetNodeLevel(Node) of
|
case Sender.GetNodeLevel(Node) of
|
||||||
0: case Node.Index of
|
0: case Node.Index of
|
||||||
HELPERNODE_COLUMNS: begin
|
HELPERNODE_COLUMNS: begin
|
||||||
@ -10163,10 +10354,50 @@ begin
|
|||||||
HELPERNODE_FUNCTIONS: ChildCount := Length(MySQLFunctions);
|
HELPERNODE_FUNCTIONS: ChildCount := Length(MySQLFunctions);
|
||||||
HELPERNODE_KEYWORDS: ChildCount := MySQLKeywords.Count;
|
HELPERNODE_KEYWORDS: ChildCount := MySQLKeywords.Count;
|
||||||
HELPERNODE_SNIPPETS: ChildCount := FSnippetFilenames.Count;
|
HELPERNODE_SNIPPETS: ChildCount := FSnippetFilenames.Count;
|
||||||
HELPERNODE_PROFILE: if not Assigned(ActiveQueryTab.QueryProfile) then ChildCount := 0
|
HELPERNODE_HISTORY: begin
|
||||||
else ChildCount := ActiveQueryTab.QueryProfile.RecordCount;
|
// Find all unique days in history
|
||||||
|
if not Assigned(Tab.HistoryDays) then
|
||||||
|
Tab.HistoryDays := TStringList.Create;
|
||||||
|
Tab.HistoryDays.Clear;
|
||||||
|
OpenRegistry(ActiveConnection.Parameters.SessionName);
|
||||||
|
MainReg.OpenKey(REGKEY_QUERYHISTORY, true);
|
||||||
|
Values := TStringList.Create;
|
||||||
|
MainReg.GetValueNames(Values);
|
||||||
|
History := TQueryHistory.Create;
|
||||||
|
for v in Values do begin
|
||||||
|
Item := History.ReadItem(StrToInt(v));
|
||||||
|
QueryDay := DateToStr(Item.Time);
|
||||||
|
if Tab.HistoryDays.IndexOf(QueryDay) = -1 then
|
||||||
|
Tab.HistoryDays.Add(QueryDay);
|
||||||
|
end;
|
||||||
|
History.Free;
|
||||||
|
Values.Free;
|
||||||
|
Tab.HistoryDays.CustomSort(StringListCompareAnythingDesc);
|
||||||
|
ChildCount := Tab.HistoryDays.Count;
|
||||||
|
end;
|
||||||
|
HELPERNODE_PROFILE: if not Assigned(Tab.QueryProfile) then ChildCount := 0
|
||||||
|
else ChildCount := Tab.QueryProfile.RecordCount;
|
||||||
end;
|
end;
|
||||||
1: ChildCount := 0;
|
1: case Node.Parent.Index of
|
||||||
|
HELPERNODE_HISTORY: begin
|
||||||
|
History := TQueryHistory.Create;
|
||||||
|
Tab.HistoryDays.Objects[Node.Index] := History;
|
||||||
|
OpenRegistry(ActiveConnection.Parameters.SessionName);
|
||||||
|
MainReg.OpenKey(REGKEY_QUERYHISTORY, true);
|
||||||
|
Values := TStringList.Create;
|
||||||
|
MainReg.GetValueNames(Values);
|
||||||
|
for v in Values do begin
|
||||||
|
Item := History.ReadItem(StrToInt(v));
|
||||||
|
QueryDay := DateToStr(Item.Time);
|
||||||
|
if QueryDay <> Tab.HistoryDays[Node.Index] then
|
||||||
|
History.Remove(Item);
|
||||||
|
end;
|
||||||
|
History.Sort(TQueryHistoryItemComparer.Create);
|
||||||
|
ChildCount := History.Count;
|
||||||
|
Values.Free;
|
||||||
|
end;
|
||||||
|
else ChildCount := 0;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -10240,16 +10471,39 @@ end;
|
|||||||
procedure TMainForm.RefreshHelperNode(NodeIndex: Cardinal);
|
procedure TMainForm.RefreshHelperNode(NodeIndex: Cardinal);
|
||||||
var
|
var
|
||||||
Tab: TQueryTab;
|
Tab: TQueryTab;
|
||||||
Node: PVirtualNode;
|
Node, Child: PVirtualNode;
|
||||||
|
OldStates: TVirtualNodeStates;
|
||||||
|
OldCheckState: TCheckState;
|
||||||
|
ExpandedChildren: TStringList;
|
||||||
begin
|
begin
|
||||||
if not Assigned(QueryTabs) then
|
if not Assigned(QueryTabs) then
|
||||||
Exit;
|
Exit;
|
||||||
for Tab in QueryTabs do begin
|
for Tab in QueryTabs do begin
|
||||||
Node := FindNode(Tab.treeHelpers, NodeIndex, nil);
|
Node := FindNode(Tab.treeHelpers, NodeIndex, nil);
|
||||||
if vsInitialized in Node.States then begin
|
// Store node + children states
|
||||||
Node.States := Node.States - [vsInitialized];
|
OldStates := Node.States;
|
||||||
Tab.treeHelpers.InvalidateNode(Node);
|
OldCheckState := Node.CheckState;
|
||||||
|
ExpandedChildren := TStringList.Create;
|
||||||
|
Child := Tab.treeHelpers.GetFirstChild(Node);
|
||||||
|
while Assigned(Child) do begin
|
||||||
|
if vsExpanded in Child.States then
|
||||||
|
ExpandedChildren.Add(IntToStr(Child.Index));
|
||||||
|
Child := Tab.treeHelpers.GetNextSibling(Child);
|
||||||
end;
|
end;
|
||||||
|
// Keep scroll offset
|
||||||
|
Tab.treeHelpers.BeginUpdate;
|
||||||
|
// Remove children and grandchildren
|
||||||
|
Tab.treeHelpers.ResetNode(Node);
|
||||||
|
// Restore old node + children states
|
||||||
|
Tab.treeHelpers.CheckState[Node] := OldCheckState;
|
||||||
|
Tab.treeHelpers.Expanded[Node] := vsExpanded in OldStates;
|
||||||
|
Child := Tab.treeHelpers.GetFirstChild(Node);
|
||||||
|
while Assigned(Child) do begin
|
||||||
|
Tab.treeHelpers.Expanded[Child] := ExpandedChildren.IndexOf(IntToStr(Child.Index)) > -1;
|
||||||
|
Child := Tab.treeHelpers.GetNextSibling(Child);
|
||||||
|
end;
|
||||||
|
ExpandedChildren.Free;
|
||||||
|
Tab.treeHelpers.EndUpdate;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -10601,6 +10855,41 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TQueryHistory }
|
||||||
|
|
||||||
|
function TQueryHistory.ReadItem(RegValue: Integer): TQueryHistoryItem;
|
||||||
|
var
|
||||||
|
p: Integer;
|
||||||
|
Raw: String;
|
||||||
|
begin
|
||||||
|
Result := TQueryHistoryItem.Create;
|
||||||
|
Result.RegValue := RegValue;
|
||||||
|
Raw := MainReg.ReadString(IntToStr(RegValue));
|
||||||
|
p := Pos(DELIM, Raw);
|
||||||
|
Result.Time := StrToDateTime(Copy(Raw, 1, p-1));
|
||||||
|
System.Delete(Raw, 1, p);
|
||||||
|
p := Pos(DELIM, Raw);
|
||||||
|
Result.Database := Copy(Raw, 1, p-1);
|
||||||
|
System.Delete(Raw, 1, p);
|
||||||
|
p := Pos(DELIM, Raw);
|
||||||
|
Result.Duration := StrToIntDef(Copy(Raw, 1, p-1), 0);
|
||||||
|
FMaxDuration := Max(FMaxDuration, Result.Duration);
|
||||||
|
Result.SQL := Copy(Raw, p+1, Length(Raw));
|
||||||
|
Add(Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TQueryHistoryItemComparer.Compare(const Left, Right: TQueryHistoryItem): Integer;
|
||||||
|
begin
|
||||||
|
// Simple sort method for a TDBObjectList
|
||||||
|
if Left.Time > Right.Time then
|
||||||
|
Result := -1
|
||||||
|
else if Left.Time = Right.Time then
|
||||||
|
Result := 0
|
||||||
|
else
|
||||||
|
Result := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user