QGIS API Documentation  3.15.0-Master (c0197371fe)
qgshelp.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgshelp.cpp
3  --------------------------------------
4  Date : December 2016
5  Copyright : (C) 2016 by Alexander Bruy
6  Email : alexander dot bruy at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgshelp.h"
17 
18 #include "qgis.h"
19 #include "qgssettings.h"
20 #include "qgsapplication.h"
21 #include "qgsexpressioncontext.h"
22 #include "qgsmessagelog.h"
24 
25 #include <QUrl>
26 #include <QFileInfo>
27 #include <QTcpSocket>
28 #include <QDesktopServices>
29 #include <QRegularExpression>
30 #include <QNetworkProxy>
31 #include <QNetworkProxyFactory>
32 
33 #include <memory>
34 
35 
36 void QgsHelp::openHelp( const QString &key )
37 {
38  QDesktopServices::openUrl( QgsHelp::helpUrl( key ) );
39 }
40 
41 QUrl QgsHelp::helpUrl( const QString &key )
42 {
43  QUrl helpNotFound = QUrl::fromLocalFile( QgsApplication::pkgDataPath() + "/doc/nohelp.html" );
44 
45  QgsSettings settings;
46  QStringList paths = settings.value( QStringLiteral( "help/helpSearchPath" ) ).toStringList();
47  if ( paths.isEmpty() )
48  {
49  QgsMessageLog::logMessage( QObject::tr( "Help location is not configured!" ), QObject::tr( "QGIS Help" ) );
50  return helpNotFound;
51  }
52 
53  std::unique_ptr<QgsExpressionContextScope> scope( QgsExpressionContextUtils::globalScope() );
54 
55  QUrl helpUrl;
56  QString helpPath, fullPath;
57  bool helpFound = false;
58 
59  const auto constPaths = paths;
60  for ( const QString &path : constPaths )
61  {
62  if ( path.endsWith( QLatin1String( "\\" ) ) || path.endsWith( QLatin1String( "/" ) ) )
63  {
64  fullPath = path.left( path.size() - 1 );
65  }
66  else
67  {
68  fullPath = path;
69  }
70 
71  const auto constVariableNames = scope->variableNames();
72  for ( const QString &var : constVariableNames )
73  {
74  QRegularExpression rx( QStringLiteral( "(<!\\$\\$)*(\\$%1)" ).arg( var ) );
75  fullPath.replace( rx, scope->variable( var ).toString() );
76  }
77  fullPath.replace( QRegularExpression( QStringLiteral( "(\\$\\$)" ) ), QStringLiteral( "$" ) );
78 
79  helpPath = QStringLiteral( "%1/%2" ).arg( fullPath, key );
80 
81  QgsMessageLog::logMessage( QObject::tr( "Trying to open help using key '%1'. Full URI is '%2'…" ).arg( key ).arg( helpPath ), QObject::tr( "QGIS Help" ), Qgis::Info );
82 
83  if ( helpPath.startsWith( QLatin1String( "http" ) ) )
84  {
85  if ( !QgsHelp::urlExists( helpPath ) )
86  {
87  continue;
88  }
89  helpUrl = QUrl( helpPath );
90  }
91  else
92  {
93  QString filePath = helpPath.mid( 0, helpPath.lastIndexOf( QLatin1String( "#" ) ) );
94  if ( !QFileInfo::exists( filePath ) )
95  {
96  continue;
97  }
98  helpUrl = QUrl::fromLocalFile( filePath );
99  int pos = helpPath.lastIndexOf( QLatin1String( "#" ) );
100  if ( pos != -1 )
101  {
102  helpUrl.setFragment( helpPath.mid( helpPath.lastIndexOf( QLatin1String( "#" ) ) + 1, -1 ) );
103  }
104  }
105 
106  helpFound = true;
107  break;
108  }
109 
110  return helpFound ? helpUrl : helpNotFound;
111 }
112 
113 bool QgsHelp::urlExists( const QString &url )
114 {
115  QUrl helpUrl( url );
116  QTcpSocket socket;
117 
118  QgsSettings settings;
119  bool proxyEnabled = settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool();
120  if ( proxyEnabled )
121  {
122  QNetworkProxy proxy;
123  QString proxyHost = settings.value( QStringLiteral( "proxy/proxyHost" ), QString() ).toString();
124  int proxyPort = settings.value( QStringLiteral( "proxy/proxyPort" ), QString() ).toString().toInt();
125  QString proxyUser = settings.value( QStringLiteral( "proxy/proxyUser" ), QString() ).toString();
126  QString proxyPassword = settings.value( QStringLiteral( "proxy/proxyPassword" ), QString() ).toString();
127 
128  QString proxyTypeString = settings.value( QStringLiteral( "proxy/proxyType" ), QString() ).toString();
129 
130  if ( proxyTypeString == QLatin1String( "DefaultProxy" ) )
131  {
132  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
133  if ( !proxies.isEmpty() )
134  {
135  proxy = proxies.first();
136  }
137  }
138  else
139  {
140  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
141  if ( proxyTypeString == QLatin1String( "Socks5Proxy" ) )
142  {
143  proxyType = QNetworkProxy::Socks5Proxy;
144  }
145  else if ( proxyTypeString == QLatin1String( "HttpProxy" ) )
146  {
147  proxyType = QNetworkProxy::HttpProxy;
148  }
149  else if ( proxyTypeString == QLatin1String( "HttpCachingProxy" ) )
150  {
151  proxyType = QNetworkProxy::HttpCachingProxy;
152  }
153  else if ( proxyTypeString == QLatin1String( "FtpCachingProxy" ) )
154  {
155  proxyType = QNetworkProxy::FtpCachingProxy;
156  }
157  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
158  }
159  socket.setProxy( proxy );
160  }
161 
162  socket.connectToHost( helpUrl.host(), 80 );
163  if ( socket.waitForConnected() )
164  {
165  socket.write( "HEAD " + helpUrl.path().toUtf8() + " HTTP/1.1\r\n"
166  "Host: " + helpUrl.host().toUtf8() + "\r\n\r\n" );
167  if ( socket.waitForReadyRead() )
168  {
169  QByteArray bytes = socket.readAll();
170  if ( bytes.contains( "200 OK" ) || bytes.contains( "302 Found" ) || bytes.contains( "301 Moved" ) )
171  {
172  return true;
173  }
174  }
175  }
176 
177  return false;
178 }
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
Definition: qgshelp.cpp:41
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QString pkgDataPath()
Returns the common root path of all application data directories.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36