aboutsummaryrefslogtreecommitdiffstats
path: root/src/qtvstools/QtHelpMenu.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/qtvstools/QtHelpMenu.cs')
-rw-r--r--src/qtvstools/QtHelpMenu.cs289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/qtvstools/QtHelpMenu.cs b/src/qtvstools/QtHelpMenu.cs
new file mode 100644
index 00000000..50a68e62
--- /dev/null
+++ b/src/qtvstools/QtHelpMenu.cs
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using EnvDTE;
+using Microsoft.VisualStudio.Settings;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Shell.Settings;
+using QtProjectLib;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Design;
+using System.Data.Common;
+using System.Data.SQLite;
+using System.IO;
+using System.Linq;
+
+namespace QtVsTools
+{
+ internal sealed class QtHelpMenu
+ {
+ public static QtHelpMenu Instance
+ {
+ get;
+ private set;
+ }
+
+ public static void Initialize(Package package)
+ {
+ Instance = new QtHelpMenu(package);
+ }
+
+ const int F1QtHelpId = 0x0100;
+ const int ViewQtHelpId = 0x0101;
+ const int OnlineDocumentationId = 0x0102;
+ const int OfflineDocumentationId = 0x0103;
+
+ readonly Package package;
+ const string QtVsToolsHelpPreferencePath = @"QtVsTools\Help\Preference";
+ static readonly Guid HelpMenuGroupGuid = new Guid("fc6244f9-ec84-4370-a59c-b009b2eafd1b");
+
+ QtHelpMenu(Package pkg)
+ {
+ if (pkg == null)
+ throw new ArgumentNullException("package");
+ package = pkg;
+
+ var commandService = ServiceProvider.GetService(typeof(IMenuCommandService))
+ as OleMenuCommandService;
+
+ if (commandService == null)
+ return;
+
+ var menuCommandID = new CommandID(HelpMenuGroupGuid, F1QtHelpId);
+ commandService.AddCommand(new MenuCommand(F1QtHelpCallback, menuCommandID));
+
+ menuCommandID = new CommandID(HelpMenuGroupGuid, ViewQtHelpId);
+ commandService.AddCommand(new MenuCommand(ViewQtHelpCallback, menuCommandID));
+
+ var command = new OleMenuCommand(ExecHandler, new CommandID(HelpMenuGroupGuid,
+ OfflineDocumentationId));
+ command.BeforeQueryStatus += BeforeQueryStatus;
+ commandService.AddCommand(command);
+
+ command = new OleMenuCommand(ExecHandler, new CommandID(HelpMenuGroupGuid,
+ OnlineDocumentationId));
+ command.BeforeQueryStatus += BeforeQueryStatus;
+ commandService.AddCommand(command);
+ }
+
+ IServiceProvider ServiceProvider
+ {
+ get { return package; }
+ }
+
+ static bool IsSuperfluousCharacter(string text)
+ {
+ switch (text) {
+ case " ": case ";": case ".": case "<": case ">": case "{": case "}":
+ case "(": case ")": case ":": case ",": case "/": case "\\": case "^":
+ case "%": case "+": case "-": case "*": case "\t": case "&": case "\"":
+ case "!": case "[": case "]": case "|": case "'": case "~": case "#": case "=":
+ return true; // nothing we are interested in
+ }
+ return false;
+ }
+
+ static string GetString(DbDataReader reader, int index)
+ {
+ if (!reader.IsDBNull(index))
+ return reader.GetString(index);
+ return string.Empty;
+ }
+
+ void ViewQtHelpCallback(object sender, EventArgs args)
+ {
+ VsShellUtilities.OpenSystemBrowser("https://www.qt.io/developers");
+ }
+
+ async void F1QtHelpCallback(object sender, EventArgs args)
+ {
+ try {
+ var dte = ServiceProvider.GetService(typeof(SDTE)) as DTE;
+ var objTextDocument = dte.ActiveDocument.Object() as TextDocument;
+
+ var keyword = string.Empty;
+ var selection = objTextDocument.Selection as TextSelection;
+ if (selection.IsEmpty) { // no selection inside the document
+ var line = selection.ActivePoint.Line; // current line
+ var offset = selection.ActivePoint.LineCharOffset; // current char offset
+
+ selection.CharLeft(true); // try the character before the cursor
+ if (!selection.IsEmpty) {
+ keyword = selection.Text; // something in front of the cursor
+ selection.CharRight(true); // reset to origin
+ if (!IsSuperfluousCharacter(keyword)) {
+ // move the selection to the start of the word
+ selection.WordLeft(true);
+ selection.MoveToPoint(selection.TopPoint);
+ }
+ }
+ selection.WordRight(true); // select the word
+ keyword = selection.Text; // get the selected text
+ selection.MoveToLineAndOffset(line, offset); // reset
+ } else {
+ keyword = selection.Text;
+ }
+
+ keyword = keyword.Trim();
+ if (keyword.Length <= 1 || IsSuperfluousCharacter(keyword))
+ return; // suppress single character, operators etc...
+
+ var qtVersion = "$(DefaultQtVersion)";
+ var project = HelperFunctions.GetSelectedQtProject(dte);
+ if (project == null) {
+ project = HelperFunctions.GetSelectedProject(dte);
+ if (project != null && HelperFunctions.IsQMakeProject(project)) {
+ var qmakeQtDir = HelperFunctions.GetQtDirFromQMakeProject(project);
+ qtVersion = QtVersionManager.The().GetQtVersionFromInstallDir(qmakeQtDir);
+ }
+ } else {
+ qtVersion = QtVersionManager.The().GetProjectQtVersion(project);
+ }
+
+ var docPath = QtVersionManager.The().GetVersionInfo(qtVersion).QtInstallDocs;
+ if (string.IsNullOrEmpty(docPath) || !Directory.Exists(docPath))
+ return;
+
+ var qchFiles = Directory.GetFiles(docPath, "*?.qch");
+ if (qchFiles.Length == 0)
+ return;
+
+ var settingsManager = new ShellSettingsManager(QtHelpMenu.Instance.ServiceProvider);
+ var store = settingsManager.GetReadOnlySettingsStore(SettingsScope.UserSettings);
+ var offline = store.GetBoolean(QtVsToolsHelpPreferencePath, "Offline", true);
+
+ var linksForKeyword = string.Format("SELECT d.Title, f.Name, e.Name, "
+ + "d.Name, a.Anchor FROM IndexTable a, FileNameTable d, FolderTable e, "
+ + "NamespaceTable f WHERE a.FileId=d.FileId AND d.FolderId=e.Id AND "
+ + "a.NamespaceId=f.Id AND a.Name='{0}'", keyword);
+
+ var links = new Dictionary<string, string>();
+ var builder = new SQLiteConnectionStringBuilder
+ {
+ ReadOnly = true
+ };
+ foreach (var file in qchFiles) {
+ builder.DataSource = file;
+ using (var connection = new SQLiteConnection(builder.ToString())) {
+ connection.Open();
+ using (var command = new SQLiteCommand(linksForKeyword, connection)) {
+ using (var reader = await command.ExecuteReaderAsync()) {
+ while (reader.Read()) {
+ var title = GetString(reader, 0);
+ if (string.IsNullOrWhiteSpace(title))
+ title = keyword + ':' + GetString(reader, 3);
+ var path = string.Empty;
+ if (offline) {
+ path = "file:///" + Path.Combine(docPath,
+ GetString(reader, 2), GetString(reader, 3));
+ } else {
+ path = "https://" + Path.Combine("doc.qt.io", "qt-5",
+ GetString(reader, 3));
+ }
+ if (!string.IsNullOrWhiteSpace(GetString(reader, 4)))
+ path += "#" + GetString(reader, 4);
+ links.Add(title, path);
+ }
+ }
+ }
+ }
+ }
+
+ var uri = string.Empty;
+ switch (links.Values.Count) {
+ case 0:
+ if (!offline) {
+ uri = new UriBuilder("http://doc.qt.io/qt-5/search-results.html")
+ {
+ Query = "q=" + keyword
+ }.ToString();
+ }
+ break;
+ case 1:
+ uri = links.First().Value;
+ break;
+ default:
+ var dialog = new QtHelpLinkChooser
+ {
+ Links = links,
+ Keyword = keyword,
+ ShowInTaskbar = false
+ };
+ if (!dialog.ShowModal().GetValueOrDefault())
+ return;
+ uri = dialog.Link;
+ break;
+ }
+
+ if (string.IsNullOrEmpty(uri)) { // offline mode without a single search hit
+ VsShellUtilities.ShowMessageBox(QtHelpMenu.Instance.ServiceProvider,
+ "Your search - " + keyword + " - did not match any documents.",
+ string.Empty, OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK,
+ OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
+ } else {
+ VsShellUtilities.OpenSystemBrowser(HelperFunctions.ChangePathFormat(uri));
+ }
+ } catch { }
+ }
+
+ void ExecHandler(object sender, EventArgs e)
+ {
+ var command = sender as OleMenuCommand;
+ if (command == null)
+ return;
+
+ var settingsManager = new ShellSettingsManager(ServiceProvider);
+ var store = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
+ store.CreateCollection(QtVsToolsHelpPreferencePath);
+
+ var value = command.CommandID.ID == OfflineDocumentationId;
+ store.SetBoolean(QtVsToolsHelpPreferencePath, "Offline", value);
+ }
+
+ void BeforeQueryStatus(object sender, EventArgs e)
+ {
+ var command = sender as OleMenuCommand;
+ if (command == null)
+ return;
+
+ var settingsManager = new ShellSettingsManager(ServiceProvider);
+ var store = settingsManager.GetReadOnlySettingsStore(SettingsScope.UserSettings);
+
+ switch (command.CommandID.ID) {
+ case OnlineDocumentationId:
+ command.Checked = !store.GetBoolean(QtVsToolsHelpPreferencePath, "Offline", true);
+ break;
+ case OfflineDocumentationId:
+ command.Checked = store.GetBoolean(QtVsToolsHelpPreferencePath, "Offline", true);
+ break;
+ }
+ }
+ }
+}