diff --git a/heidisql.lpi b/heidisql.lpi
index 9da7e5e6..ffada3ad 100644
--- a/heidisql.lpi
+++ b/heidisql.lpi
@@ -229,6 +229,13 @@
+
+
+
+
+
+
+
diff --git a/heidisql.lpr b/heidisql.lpr
index af1a20e4..853a372f 100644
--- a/heidisql.lpr
+++ b/heidisql.lpr
@@ -19,7 +19,7 @@ uses
dbstructures.sqlite, change_password, loginform, data_sorting, extra_controls,
column_selection, loaddata, csv_detector, createdatabase, editvar, copytable,
exportgrid, usermanager, selectdbobject, reformatter, searchreplace,
- connections, jsonregistry {, printlist (EnablePrint not defined) }
+ connections, jsonregistry, sqlhelp {, printlist (EnablePrint not defined) }
;
{$R *.res}
diff --git a/source/main.pas b/source/main.pas
index 90659dbd..2affa0e6 100644
--- a/source/main.pas
+++ b/source/main.pas
@@ -1415,7 +1415,7 @@ implementation
uses
FileInfo, winpeimagereader, elfreader, machoreader, About, data_sorting, column_selection, loaddata, editvar,
- copytable, csv_detector, exportgrid, usermanager, selectdbobject, reformatter, connections;
+ copytable, csv_detector, exportgrid, usermanager, selectdbobject, reformatter, connections, sqlhelp;
{$R *.lfm}
@@ -4903,10 +4903,10 @@ end;
procedure TMainform.CallSQLHelpWithKeyword( keyword: String );
begin
if FActiveDbObj.Connection.Has(frHelpKeyword) then begin
- {if not Assigned(SqlHelpDialog) then
+ if not Assigned(SqlHelpDialog) then
SqlHelpDialog := TfrmSQLhelp.Create(Self);
SqlHelpDialog.Show;
- SqlHelpDialog.Keyword := keyword;}
+ SqlHelpDialog.Keyword := keyword;
end else
ErrorDialog(_('SQL help not available.'), f_('HELP requires %s or newer.', ['MySQL 4.1']));
end;
@@ -13273,10 +13273,10 @@ begin
Editors.Add(frmPreferences.SynMemoSQLSample);}
if Assigned(FCreateDatabaseDialog) then
Editors.Add(FCreateDatabaseDialog.SynMemoCreateCode);
- {if SqlHelpDialog <> nil then begin
+ if SqlHelpDialog <> nil then begin
Editors.Add(SqlHelpDialog.memoDescription);
Editors.Add(SqlHelpDialog.MemoExample);
- end;}
+ end;
{if Assigned(FTableToolsDialog) then
Editors.Add(FTableToolsDialog.SynMemoFindText);}
if Assigned(frmCsvDetector) then
diff --git a/source/sqlhelp.lfm b/source/sqlhelp.lfm
new file mode 100644
index 00000000..c2dfeea9
--- /dev/null
+++ b/source/sqlhelp.lfm
@@ -0,0 +1,339 @@
+object frmSQLhelp: TfrmSQLhelp
+ Left = 0
+ Height = 444
+ Top = 0
+ Width = 728
+ BorderWidth = 10
+ Caption = 'Integrated SQL-help'
+ ClientHeight = 444
+ ClientWidth = 728
+ Color = clBtnFace
+ DesignTimePPI = 120
+ FormStyle = fsStayOnTop
+ OnClose = FormClose
+ OnCreate = FormCreate
+ OnShow = FormShow
+ object pnlMain: TPanel
+ Left = 10
+ Height = 382
+ Top = 10
+ Width = 708
+ Align = alClient
+ BevelOuter = bvNone
+ ClientHeight = 382
+ ClientWidth = 708
+ ParentBackground = False
+ TabOrder = 0
+ object Splitter1: TSplitter
+ Cursor = crSizeWE
+ Left = 191
+ Height = 382
+ Top = 0
+ Width = 10
+ end
+ object pnlLeft: TPanel
+ Left = 0
+ Height = 382
+ Top = 0
+ Width = 191
+ Align = alLeft
+ BevelOuter = bvNone
+ ClientHeight = 382
+ ClientWidth = 191
+ ParentBackground = False
+ TabOrder = 0
+ object editFilter: TEditButton
+ Left = 0
+ Height = 28
+ Top = 0
+ Width = 191
+ Align = alTop
+ ButtonWidth = 29
+ Images = MainForm.ImageListIcons8
+ ImageIndex = 193
+ MaxLength = 0
+ NumGlyphs = 1
+ OnButtonClick = editFilterRightButtonClick
+ OnChange = editFilterChange
+ PasswordChar = #0
+ TabOrder = 0
+ TextHint = 'Filter'
+ end
+ object treeTopics: TLazVirtualStringTree
+ Left = 0
+ Height = 354
+ Top = 28
+ Width = 191
+ Align = alClient
+ Constraints.MinWidth = 38
+ Header.AutoSizeIndex = 0
+ Header.Columns = <>
+ Header.MainColumn = -1
+ Images = MainForm.ImageListIcons8
+ TabOrder = 1
+ TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed]
+ OnFocusChanged = treeTopicsFocusChanged
+ OnFreeNode = treeTopicsFreeNode
+ OnGetText = treeTopicsGetText
+ OnGetImageIndex = treeTopicsGetImageIndex
+ OnGetNodeDataSize = treeTopicsGetNodeDataSize
+ OnInitChildren = treeTopicsInitChildren
+ OnInitNode = treeTopicsInitNode
+ end
+ end
+ object pnlRight: TPanel
+ Left = 201
+ Height = 382
+ Top = 0
+ Width = 507
+ Align = alClient
+ BevelOuter = bvNone
+ ClientHeight = 382
+ ClientWidth = 507
+ ParentBackground = False
+ TabOrder = 1
+ object Splitter2: TSplitter
+ Cursor = crVSplit
+ Left = 0
+ Height = 10
+ Top = 212
+ Width = 507
+ Align = alTop
+ ResizeAnchor = akTop
+ end
+ object lblDescription: TLabel
+ Left = 0
+ Height = 20
+ Top = 1
+ Width = 507
+ Align = alTop
+ Caption = 'Description:'
+ end
+ object lblKeyword: TLabel
+ Left = 0
+ Height = 1
+ Top = 0
+ Width = 507
+ Align = alTop
+ ShowAccelChar = False
+ end
+ object lblExample: TLabel
+ Left = 0
+ Height = 20
+ Top = 222
+ Width = 507
+ Align = alTop
+ Caption = 'Example:'
+ end
+ inline memoDescription: TSynEdit
+ Left = 0
+ Height = 191
+ Top = 21
+ Width = 507
+ Align = alTop
+ Constraints.MinHeight = 38
+ Font.Height = -16
+ Font.Name = 'Courier New'
+ Font.Pitch = fpFixed
+ Font.Quality = fqNonAntialiased
+ ParentColor = False
+ ParentFont = False
+ TabOrder = 0
+ OnKeyDown = memosKeyDown
+ Gutter.Visible = False
+ Gutter.Width = 72
+ Gutter.MouseActions = <>
+ RightGutter.Width = 0
+ RightGutter.MouseActions = <>
+ Keystrokes = <>
+ MouseActions = <>
+ MouseTextActions = <>
+ MouseSelActions = <>
+ Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing]
+ MouseOptions = [emDragDropEditing]
+ VisibleSpecialChars = [vscSpace, vscTabAtLast]
+ ReadOnly = True
+ RightEdge = 0
+ SelectedColor.BackPriority = 50
+ SelectedColor.ForePriority = 50
+ SelectedColor.FramePriority = 50
+ SelectedColor.BoldPriority = 50
+ SelectedColor.ItalicPriority = 50
+ SelectedColor.UnderlinePriority = 50
+ SelectedColor.StrikeOutPriority = 50
+ BracketHighlightStyle = sbhsBoth
+ BracketMatchColor.Background = clNone
+ BracketMatchColor.Foreground = clNone
+ BracketMatchColor.Style = [fsBold]
+ FoldedCodeColor.Background = clNone
+ FoldedCodeColor.Foreground = clGray
+ FoldedCodeColor.FrameColor = clGray
+ MouseLinkColor.Background = clNone
+ MouseLinkColor.Foreground = clBlue
+ LineHighlightColor.Background = clNone
+ LineHighlightColor.Foreground = clNone
+ inline SynLeftGutterPartList1: TSynGutterPartList
+ object SynGutterMarks1: TSynGutterMarks
+ Width = 30
+ MouseActions = <>
+ end
+ object SynGutterLineNumber1: TSynGutterLineNumber
+ Width = 21
+ MouseActions = <>
+ MarkupInfo.Background = clBtnFace
+ MarkupInfo.Foreground = clNone
+ DigitCount = 2
+ ShowOnlyLineNumbersMultiplesOf = 1
+ ZeroStart = False
+ LeadingZeros = False
+ end
+ object SynGutterChanges1: TSynGutterChanges
+ Width = 5
+ MouseActions = <>
+ ModifiedColor = 59900
+ SavedColor = clGreen
+ end
+ object SynGutterSeparator1: TSynGutterSeparator
+ Width = 3
+ MouseActions = <>
+ MarkupInfo.Background = clWhite
+ MarkupInfo.Foreground = clGray
+ end
+ object SynGutterCodeFolding1: TSynGutterCodeFolding
+ Width = 13
+ MouseActions = <>
+ MarkupInfo.Background = clNone
+ MarkupInfo.Foreground = clGray
+ MouseActionsExpanded = <>
+ MouseActionsCollapsed = <>
+ end
+ end
+ end
+ inline MemoExample: TSynEdit
+ Left = 0
+ Height = 140
+ Top = 242
+ Width = 507
+ Align = alClient
+ Constraints.MinHeight = 38
+ Font.Height = -16
+ Font.Name = 'Courier New'
+ Font.Pitch = fpFixed
+ Font.Quality = fqNonAntialiased
+ ParentColor = False
+ ParentFont = False
+ TabOrder = 1
+ OnKeyDown = memosKeyDown
+ Gutter.Visible = False
+ Gutter.Width = 72
+ Gutter.MouseActions = <>
+ RightGutter.Width = 0
+ RightGutter.MouseActions = <>
+ Keystrokes = <>
+ MouseActions = <>
+ MouseTextActions = <>
+ MouseSelActions = <>
+ Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing]
+ MouseOptions = [emDragDropEditing]
+ VisibleSpecialChars = [vscSpace, vscTabAtLast]
+ ReadOnly = True
+ RightEdge = 0
+ SelectedColor.BackPriority = 50
+ SelectedColor.ForePriority = 50
+ SelectedColor.FramePriority = 50
+ SelectedColor.BoldPriority = 50
+ SelectedColor.ItalicPriority = 50
+ SelectedColor.UnderlinePriority = 50
+ SelectedColor.StrikeOutPriority = 50
+ BracketHighlightStyle = sbhsBoth
+ BracketMatchColor.Background = clNone
+ BracketMatchColor.Foreground = clNone
+ BracketMatchColor.Style = [fsBold]
+ FoldedCodeColor.Background = clNone
+ FoldedCodeColor.Foreground = clGray
+ FoldedCodeColor.FrameColor = clGray
+ MouseLinkColor.Background = clNone
+ MouseLinkColor.Foreground = clBlue
+ LineHighlightColor.Background = clNone
+ LineHighlightColor.Foreground = clNone
+ inline SynLeftGutterPartList1: TSynGutterPartList
+ object SynGutterMarks1: TSynGutterMarks
+ Width = 30
+ MouseActions = <>
+ end
+ object SynGutterLineNumber1: TSynGutterLineNumber
+ Width = 21
+ MouseActions = <>
+ MarkupInfo.Background = clBtnFace
+ MarkupInfo.Foreground = clNone
+ DigitCount = 2
+ ShowOnlyLineNumbersMultiplesOf = 1
+ ZeroStart = False
+ LeadingZeros = False
+ end
+ object SynGutterChanges1: TSynGutterChanges
+ Width = 5
+ MouseActions = <>
+ ModifiedColor = 59900
+ SavedColor = clGreen
+ end
+ object SynGutterSeparator1: TSynGutterSeparator
+ Width = 3
+ MouseActions = <>
+ MarkupInfo.Background = clWhite
+ MarkupInfo.Foreground = clGray
+ end
+ object SynGutterCodeFolding1: TSynGutterCodeFolding
+ Width = 13
+ MouseActions = <>
+ MarkupInfo.Background = clNone
+ MarkupInfo.Foreground = clGray
+ MouseActionsExpanded = <>
+ MouseActionsCollapsed = <>
+ end
+ end
+ end
+ end
+ end
+ object pnlBottom: TPanel
+ Left = 10
+ Height = 42
+ Top = 392
+ Width = 708
+ Align = alBottom
+ BevelOuter = bvNone
+ ClientHeight = 42
+ ClientWidth = 708
+ ParentBackground = False
+ TabOrder = 1
+ object btnSearchOnline: TSpeedButton
+ Left = 444
+ Height = 31
+ Top = 8
+ Width = 129
+ Anchors = [akTop, akRight]
+ Caption = 'Search online'
+ Images = MainForm.ImageListIcons8
+ ImageIndex = 69
+ OnClick = ButtonOnlinehelpClick
+ end
+ object ButtonClose: TButton
+ Left = 580
+ Height = 31
+ Top = 8
+ Width = 128
+ Anchors = [akTop, akRight]
+ Cancel = True
+ Caption = 'Close'
+ Default = True
+ TabOrder = 0
+ OnClick = ButtonCloseClick
+ end
+ end
+ object timerSearch: TTimer
+ Interval = 500
+ OnTimer = DoSearch
+ Left = 10
+ Top = 400
+ end
+end
diff --git a/source/sqlhelp.pas b/source/sqlhelp.pas
new file mode 100644
index 00000000..c5c3ea94
--- /dev/null
+++ b/source/sqlhelp.pas
@@ -0,0 +1,427 @@
+unit sqlhelp;
+
+{$mode delphi}{$H+}
+
+interface
+
+uses
+ SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls,
+ Buttons, SynEdit, SynEditHighlighter, extra_controls,
+ laz.VirtualTrees, Graphics, EditBtn,
+ dbconnection;
+
+type
+
+ { TfrmSQLhelp }
+
+ TfrmSQLhelp = class(TExtForm)
+ //URIOpenerDescription: TSynURIOpener;
+ //URIHighlighter: TSynURISyn;
+ //URIOpenerExample: TSynURIOpener;
+ btnSearchOnline: TSpeedButton;
+ ButtonClose: TButton;
+ pnlBottom: TPanel;
+ pnlMain: TPanel;
+ pnlLeft: TPanel;
+ treeTopics: TLazVirtualStringTree;
+ editFilter: TEditButton;
+ pnlRight: TPanel;
+ Splitter2: TSplitter;
+ Splitter1: TSplitter;
+ lblDescription: TLabel;
+ lblKeyword: TLabel;
+ memoDescription: TSynEdit;
+ lblExample: TLabel;
+ MemoExample: TSynEdit;
+ timerSearch: TTimer;
+ procedure FormCreate(Sender: TObject);
+ procedure memosKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+ procedure ButtonOnlinehelpClick(Sender: TObject);
+ procedure ButtonCloseClick(Sender: TObject);
+ procedure DoSearch(Sender: TObject);
+ procedure treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+ procedure treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ var ChildCount: Cardinal);
+ procedure treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
+ procedure treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+ procedure treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex);
+ procedure editFilterChange(Sender: TObject);
+ procedure editFilterRightButtonClick(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure FormShow(Sender: TObject);
+
+ private
+ { Private declarations }
+ FConnection: TDBConnection;
+ FKeyword: String;
+ FRootTopics: TDBQuery;
+ function GetHelpResult(Node: PVirtualNode): TDBQuery;
+ procedure SetKeyword(Value: String);
+ public
+ { Public declarations }
+ property Keyword: String read FKeyword write SetKeyword;
+ end;
+
+ var
+ SqlHelpDialog: TfrmSQLhelp; // global var, so we can apply settings via SetupSynEditors
+
+ const
+ DEFAULT_WINDOW_CAPTION : String = 'Integrated SQL-help' ;
+ ICONINDEX_CATEGORY_CLOSED : Integer = 66;
+ ICONINDEX_CATEGORY_OPENED : Integer = 67;
+ ICONINDEX_HELPITEM : Integer = 68;
+
+implementation
+
+uses apphelpers, main;
+
+{$I const.inc}
+
+{$R *.lfm}
+
+
+procedure TfrmSQLhelp.FormCreate(Sender: TObject);
+begin
+ // Set window-layout
+ lblKeyword.Font.Style := [fsBold];
+ Caption := DEFAULT_WINDOW_CAPTION;
+ FixVT(treeTopics);
+ HasSizeGrip := True;
+
+ treeTopics.Clear;
+ FreeAndNil(FRootTopics);
+ FConnection := MainForm.ActiveConnection;
+ FRootTopics := FConnection.GetResults('HELP '+FConnection.EscapeString('CONTENTS'));
+ treeTopics.RootNodeCount := FRootTopics.RecordCount;
+end;
+
+
+procedure TfrmSQLhelp.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ AppSettings.WriteInt(asSQLHelpWindowLeft, Left );
+ AppSettings.WriteInt(asSQLHelpWindowTop, Top );
+ AppSettings.WriteIntDpiAware(asSQLHelpWindowWidth, Self, Width);
+ AppSettings.WriteIntDpiAware(asSQLHelpWindowHeight, Self, Height);
+ AppSettings.WriteIntDpiAware(asSQLHelpPnlLeftWidth, Self, pnlLeft.Width);
+ AppSettings.WriteIntDpiAware(asSQLHelpPnlRightTopHeight, Self, memoDescription.Height);
+ Action := caFree;
+ SqlHelpDialog := nil;
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex);
+var
+ Results: TDBQuery;
+ VT: TVirtualStringTree;
+begin
+ // Topic selected
+ VT := Sender as TVirtualStringTree;
+ if not Assigned(VT.FocusedNode) then
+ Exit;
+ if VT.HasChildren[VT.FocusedNode] then
+ Exit;
+ FKeyword := VT.Text[VT.FocusedNode, VT.FocusedColumn];
+ lblKeyword.Caption := Copy(FKeyword, 0, 100);
+ MemoDescription.Lines.Clear;
+ MemoExample.Lines.Clear;
+ Caption := DEFAULT_WINDOW_CAPTION;
+
+ if FKeyword <> '' then try
+ Screen.Cursor := crHourglass;
+ Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword));
+ Caption := Caption + ' - ' + FKeyword;
+ MemoDescription.Text := fixNewlines(Results.Col('description', True));
+ MemoExample.Text := fixNewlines(Results.Col('example', True));
+ finally
+ FreeAndNil(Results);
+ Screen.Cursor := crDefault;
+ end;
+
+ // Show the user if topic is (not) available
+ if memoDescription.GetTextLen = 0 then
+ memoDescription.Text := _('No help available for this keyword or no keyword was selected.');
+ if memoExample.GetTextLen = 0 then
+ memoExample.Text := _('No example available or no keyword was selected.');
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+var
+ Results: PDBQuery;
+begin
+ // Node gets destroyed - free memory used for bound SQL result
+ Results := Sender.GetNodeData(Node);
+ if Assigned(Results^) then
+ Results^.Free;
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex);
+begin
+ // Return open or closed book icon for folders, or document icon for topics
+ if not (Kind in [ikNormal, ikSelected]) then
+ Exit;
+ if Sender.HasChildren[Node] then begin
+ if Sender.Expanded[Node] then
+ ImageIndex := ICONINDEX_CATEGORY_OPENED
+ else
+ ImageIndex := ICONINDEX_CATEGORY_CLOSED;
+ end else
+ ImageIndex := ICONINDEX_HELPITEM;
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree;
+ var NodeDataSize: Integer);
+begin
+ // We bind one TDBQuery to a node
+ NodeDataSize := SizeOf(TDBQuery);
+end;
+
+
+function TfrmSQLhelp.GetHelpResult(Node: PVirtualNode): TDBQuery;
+var
+ P: PDBQuery;
+begin
+ // Find right result set for given node
+ if treeTopics.GetNodeLevel(Node) = 0 then
+ Result := FRootTopics
+ else begin
+ P := treeTopics.GetNodeData(Node.Parent);
+ Result := P^;
+ end;
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+var
+ Results: TDBQuery;
+begin
+ // Ask result set for node text
+ Results := GetHelpResult(Node);
+ Results.RecNo := Node.Index;
+ CellText := Results.Col('name');
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ var ChildCount: Cardinal);
+var
+ Results: PDBQuery;
+ VT: TVirtualStringTree;
+begin
+ // Return number of children for folder
+ VT := Sender as TVirtualStringTree;
+ Results := VT.GetNodeData(Node);
+ Results^ := FConnection.GetResults('HELP '+FConnection.EscapeString(VT.Text[Node, VT.Header.MainColumn]));
+ ChildCount := Results.RecordCount;
+end;
+
+
+procedure TfrmSQLhelp.treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode,
+ Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
+var
+ Results: TDBQuery;
+ ThisFolder, PrevFolder: String;
+ N: PVirtualNode;
+ VT: TVirtualStringTree;
+ RecursionAlarm: Boolean;
+begin
+ // Display plus button for nodes which are folders
+ VT := Sender as TVirtualStringTree;
+ Results := GetHelpResult(Node);
+ Results.RecNo := Node.Index;
+ if Results.Col('is_it_category', True) = 'Y' then begin
+ // Some random server versions have duplicated category names in help tables, which would cause
+ // infinite tree recursion, e.g. for "Polygon properties" > "Contents". Do not display these
+ // duplicates as folder
+ RecursionAlarm := False;
+ ThisFolder := Results.Col('name');
+ N := VT.GetPreviousInitialized(Node);
+ while Assigned(N) do begin
+ PrevFolder := VT.Text[N, VT.Header.MainColumn];
+ if VT.HasChildren[N] and ((ThisFolder=PrevFolder) or (ThisFolder='Contents')) then begin
+ RecursionAlarm := True;
+ break;
+ end;
+ N := VT.GetPreviousInitialized(N);
+ end;
+ if not RecursionAlarm then
+ Include(InitialStates, ivsHasChildren);
+ end;
+end;
+
+
+procedure TfrmSQLhelp.ButtonCloseClick(Sender: TObject);
+begin
+ Close;
+end;
+
+
+procedure TfrmSQLhelp.FormShow(Sender: TObject);
+begin
+ Top := AppSettings.ReadInt(asSQLHelpWindowTop);
+ Left := AppSettings.ReadInt(asSQLHelpWindowLeft);
+ Width := AppSettings.ReadIntDpiAware(asSQLHelpWindowWidth, Self);
+ Height := AppSettings.ReadIntDpiAware(asSQLHelpWindowHeight, Self);
+ MakeFullyVisible;
+
+ pnlLeft.Width := AppSettings.ReadIntDpiAware(asSQLHelpPnlLeftWidth, Self);
+ memoDescription.Height := AppSettings.ReadIntDpiAware(asSQLHelpPnlRightTopHeight, Self);
+ // Apply themed colors in OnShow, not OnCreate, as a check with <> nil returns false otherwise
+ MainForm.SetupSynEditors(Self);
+ // These SynMemo's don't have any (SQL) highligher, so we have to assign correct colors for basic text
+ memoDescription.Font.Color := GetThemeColor(clWindowText);
+ MemoExample.Font.Color := GetThemeColor(clWindowText);
+ editFilter.SetFocus;
+end;
+
+
+procedure TfrmSQLhelp.ButtonOnlinehelpClick(Sender: TObject);
+begin
+ // Link/redirect to mysql.com for further help
+ ShellExec(APPDOMAIN + 'sqlhelp.php?mysqlversion='+inttostr(FConnection.ServerVersionInt)+
+ '&keyword='+EncodeURLParam(keyword));
+end;
+
+
+procedure TfrmSQLhelp.memosKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ // Esc pressed - close form.
+ // Seems that if we're in a memo, the ButtonClose.Cancel=True doesn't have an effect
+ //if Key = VK_ESCAPE then
+ // Close;
+end;
+
+
+procedure TfrmSQLhelp.SetKeyword(Value: string);
+var
+ VT: TVirtualStringTree;
+ Node: PVirtualNode;
+ Results: TDBQuery;
+ SearchNoInit: Boolean;
+begin
+ // Find keyword in tree
+ FKeyword := Value;
+ if FKeyword = '' then
+ Exit;
+ Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword));
+ while not Results.Eof do begin
+ if Results.Col('is_it_category', true) = 'N' then begin
+ FKeyword := Results.Col('name');
+ break;
+ end;
+ Results.Next;
+ end;
+ FreeAndNil(Results);
+
+ VT := treeTopics;
+ if (not Assigned(VT.FocusedNode)) // No node selected
+ or VT.HasChildren[VT.FocusedNode] // Selected node is a folder, not a document
+ or (VT.Text[VT.FocusedNode, VT.Header.MainColumn] <> FKeyword) // Node is not the right one
+ then begin
+ // Start searching in initialized nodes, to minimize number of "HELP xyz" queries in certain cases
+ Node := VT.GetFirst;
+ SearchNoInit := False;
+ while Assigned(Node) do begin
+ if (not VT.HasChildren[Node]) and (UpperCase(VT.Text[Node, VT.Header.MainColumn]) = UpperCase(FKeyword)) then begin
+ SelectNode(VT, Node);
+ break;
+ end;
+ if not SearchNoInit then begin
+ Node := VT.GetNextInitialized(Node);
+ if not Assigned(Node) then begin
+ SearchNoInit := True;
+ Node := VT.GetFirst;
+ end;
+ end;
+ if SearchNoInit then
+ Node := VT.GetNext(Node);
+ end;
+ end;
+end;
+
+
+procedure TfrmSQLhelp.editFilterChange(Sender: TObject);
+begin
+ timerSearch.Enabled := False;
+ timerSearch.Enabled := True;
+ editFilter.Button.Enabled := Trim(editFilter.Text) <> '';
+end;
+
+
+procedure TfrmSQLhelp.editFilterRightButtonClick(Sender: TObject);
+begin
+ editFilter.Clear;
+end;
+
+
+procedure TfrmSQLhelp.DoSearch(Sender: TObject);
+var
+ Node: PVirtualNode;
+ Search: String;
+ Vis: Boolean;
+
+ function HasVisibleChildItems(Node: PVirtualNode): Boolean;
+ var
+ N: PVirtualNode;
+ begin
+ N := treeTopics.GetFirstChild(Node);
+ Result := False;
+ while Assigned(N) do begin
+ if treeTopics.HasChildren[N] then
+ Result := HasVisibleChildItems(N)
+ else
+ Result := treeTopics.IsVisible[N];
+ if Result then
+ Exit;
+ N := treeTopics.GetNextSibling(N);
+ end;
+ end;
+begin
+ // Apply filter text
+ Screen.Cursor := crHourglass;
+ treeTopics.BeginUpdate;
+ timerSearch.Enabled := False;
+ Search := Trim(editFilter.Text);
+ if Search = '' then begin
+ // Show all items
+ Node := treeTopics.GetFirstInitialized;
+ while Assigned(Node) do begin
+ treeTopics.IsVisible[Node] := True;
+ Node := treeTopics.GetNextInitialized(Node);
+ end;
+ end else begin
+ // Hide non matching child items
+ Node := treeTopics.GetFirst;
+ while Assigned(Node) do begin
+ if not treeTopics.HasChildren[Node] then
+ treeTopics.IsVisible[Node] := Pos(UpperCase(Search), UpperCase(treeTopics.Text[Node, treeTopics.Header.MainColumn])) > 0;
+ Node := treeTopics.GetNext(Node);
+ end;
+ // Hide empty folders
+ Node := treeTopics.GetFirst;
+ while Assigned(Node) do begin
+ if treeTopics.HasChildren[Node] then begin
+ Vis := HasVisibleChildItems(Node);
+ treeTopics.Expanded[Node] := Vis;
+ treeTopics.IsVisible[Node] := Vis;
+ end;
+ Node := treeTopics.GetNext(Node);
+ end;
+ end;
+ treeTopics.EndUpdate;
+ Screen.Cursor := crDefault;
+end;
+
+end.