-
-
Notifications
You must be signed in to change notification settings - Fork 240
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a QField documentation help locator for the search bar
- Loading branch information
Showing
5 changed files
with
229 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/*************************************************************************** | ||
helplocatorfilter.cpp | ||
--------------------- | ||
begin : 02.07.2024 | ||
copyright : (C) 2024 by Mathieu Pellerin | ||
email : mathieu at opengis dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "helplocatorfilter.h" | ||
#include "locatormodelsuperbridge.h" | ||
|
||
#include <QDesktopServices> | ||
#include <QNetworkRequest> | ||
#include <QTextDocument> | ||
#include <qgsblockingnetworkrequest.h> | ||
#include <qgsfeedback.h> | ||
#include <qgsstringutils.h> | ||
|
||
HelpLocatorFilter::HelpLocatorFilter( LocatorModelSuperBridge *locatorBridge, QObject *parent ) | ||
: QgsLocatorFilter( parent ) | ||
, mLocatorBridge( locatorBridge ) | ||
{ | ||
setFetchResultsDelay( 1000 ); | ||
setUseWithoutPrefix( false ); | ||
} | ||
|
||
HelpLocatorFilter *HelpLocatorFilter::clone() const | ||
{ | ||
return new HelpLocatorFilter( mLocatorBridge ); | ||
} | ||
|
||
void HelpLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback ) | ||
{ | ||
Q_UNUSED( feedback ) | ||
|
||
if ( string.length() < 3 ) | ||
{ | ||
return; | ||
} | ||
|
||
const QString searchString = string.trimmed().toLower(); | ||
const QStringList words = searchString.split( ' ', Qt::SkipEmptyParts ); | ||
if ( string.length() < 3 || words.isEmpty() ) | ||
{ | ||
return; | ||
} | ||
|
||
QNetworkRequest request( QUrl( "https://docs.qfield.org/search/search_index.json" ) ); | ||
QgsBlockingNetworkRequest blockingRequest; | ||
const QgsBlockingNetworkRequest::ErrorCode errorCode = blockingRequest.get( request, false, feedback ); | ||
if ( errorCode != QgsBlockingNetworkRequest::NoError ) | ||
{ | ||
return; | ||
} | ||
|
||
QJsonParseError err; | ||
const QJsonDocument jsonDoc = QJsonDocument::fromJson( blockingRequest.reply().content(), &err ); | ||
if ( jsonDoc.isNull() ) | ||
{ | ||
return; | ||
} | ||
const QVariantMap searchMap = jsonDoc.object().toVariantMap(); | ||
const QStringList lang = searchMap.value( QStringLiteral( "config" ) ).toMap().value( QStringLiteral( "lang" ) ).toStringList(); | ||
const QList<QVariant> docs = searchMap.value( QStringLiteral( "docs" ) ).toList(); | ||
|
||
const QLocale locale; | ||
QString userLocale = locale.name().mid( 0, 2 ); | ||
if ( !lang.contains( userLocale ) || userLocale == QStringLiteral( "en" ) ) | ||
{ | ||
userLocale.clear(); | ||
} | ||
|
||
QRegularExpression rx( QStringLiteral( "\\A([a-z]{2})\\/" ) ); | ||
for ( const QVariant &doc : docs ) | ||
{ | ||
QVariantMap details = doc.toMap(); | ||
const QString title = details.value( QStringLiteral( "title" ) ).toString().toLower(); | ||
const QString text = details.value( QStringLiteral( "text" ) ).toString().toLower(); | ||
|
||
if ( text.isEmpty() ) | ||
{ | ||
continue; | ||
} | ||
|
||
const QString location = details.value( QStringLiteral( "location" ) ).toString(); | ||
QString locationLocale; | ||
QRegularExpressionMatch rxMatch = rx.match( location ); | ||
if ( rxMatch.hasMatch() ) | ||
{ | ||
locationLocale = rxMatch.captured( 1 ); | ||
} | ||
|
||
if ( locationLocale == userLocale ) | ||
{ | ||
bool match = false; | ||
int matchScore = 0; | ||
for ( const QString &word : words ) | ||
{ | ||
match = title.contains( word ) || text.contains( word ); | ||
matchScore += title.count( word ) * 2 + text.count( word ); | ||
} | ||
|
||
if ( match ) | ||
{ | ||
if ( !location.isEmpty() ) | ||
{ | ||
if ( QgsStringUtils::soundex( title ) == QgsStringUtils::soundex( searchString ) ) | ||
{ | ||
// When the search term is a near-match to the title, add a big bonus (e.g. search term project matching page title projects) | ||
matchScore += 100; | ||
} | ||
|
||
QTextDocument htmlDoc; | ||
htmlDoc.setHtml( details.value( QStringLiteral( "text" ) ).toString() ); | ||
|
||
QgsLocatorResult result; | ||
result.displayString = details.value( QStringLiteral( "title" ) ).toString(); | ||
result.description = htmlDoc.toPlainText(); | ||
result.score = matchScore; | ||
result.filter = this; | ||
result.setUserData( QStringLiteral( "https://docs.qfield.org/%1" ).arg( location ) ); | ||
emit resultFetched( result ); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
void HelpLocatorFilter::triggerResult( const QgsLocatorResult &result ) | ||
{ | ||
triggerResultFromAction( result, Normal ); | ||
} | ||
|
||
void HelpLocatorFilter::triggerResultFromAction( const QgsLocatorResult &result, const int ) | ||
{ | ||
const QString url = result.userData().toString(); | ||
qDebug() << url; | ||
QDesktopServices::openUrl( url ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/*************************************************************************** | ||
helplocatorfilter.h | ||
--------------------- | ||
begin : 02.07.2024 | ||
copyright : (C) 2024 by Mathieu Pellerin | ||
email : mathieu at opengis dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
|
||
#ifndef HELPLOCATORFILTER_H | ||
#define HELPLOCATORFILTER_H | ||
|
||
#include <QObject> | ||
#include <qgslocatorfilter.h> | ||
|
||
|
||
class LocatorModelSuperBridge; | ||
|
||
/** | ||
* HelpLocatorFilter is a locator filter to search | ||
* for and display QField documentation pages. | ||
*/ | ||
class HelpLocatorFilter : public QgsLocatorFilter | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
//! Origin of the action which triggers the result | ||
enum ActionOrigin | ||
{ | ||
Normal, | ||
}; | ||
|
||
explicit HelpLocatorFilter( LocatorModelSuperBridge *locatorBridge, QObject *parent = nullptr ); | ||
HelpLocatorFilter *clone() const override; | ||
QString name() const override { return QStringLiteral( "optionpages" ); } // name should be "help" but we're working around QGIS guarding against 1-character prefix | ||
QString displayName() const override { return tr( "QField Documentation" ); } | ||
Priority priority() const override { return Medium; } | ||
QString prefix() const override { return QStringLiteral( "?" ); } | ||
|
||
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override; | ||
void triggerResult( const QgsLocatorResult &result ) override; | ||
void triggerResultFromAction( const QgsLocatorResult &result, const int actionId ) override; | ||
|
||
private: | ||
LocatorModelSuperBridge *mLocatorBridge = nullptr; | ||
}; | ||
|
||
#endif // HELPLOCATORFILTER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters