add showApiDocumentation method

This commit is contained in:
Yoann Quenach de Quivillic 2024-10-03 22:39:17 +02:00 committed by Nyall Dawson
parent 25480e872c
commit c851835729
14 changed files with 369 additions and 38 deletions

View File

@ -1490,6 +1490,13 @@ Unregister a previously registered tool factory from the development/debugging t
.. seealso:: :py:func:`registerDevToolWidgetFactory`
.. versionadded:: 3.14
%End
virtual void showApiDocumentation( const QString &api = QStringLiteral( "qgis" ), bool python = true, bool embedded = true, const QString &module = QString(), const QString &object = QString() ) = 0;
%Docstring
Show a page of the API documentation in the embedded Dev tool webview
.. versionadded:: 3.42
%End
virtual void registerApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker ) = 0;

View File

@ -103,27 +103,18 @@ def __parse_object(object=None):
return 'qt', module, obj
""",
r"""
def _help(object=None, api="c++"):
def _help(object=None, api="c++", embedded=True):
'''
Link to the C++ or PyQGIS API documentation for the given object.
If no object is given, the main PyQGIS API page is opened.
If the object is not part of the QGIS API but is a Qt object the Qt documentation is opened.
'''
import webbrowser
if 'master' in Qgis.QGIS_VERSION.lower():
if api == "c++":
version = ''
else:
version = 'master'
else:
version = re.findall(r'^\d.[0-9]*', Qgis.QGIS_VERSION)[0]
if object is None:
if api == "c++":
webbrowser.open(f"https://qgis.org/pyqgis/{version}")
iface.showApiDocumentation(python=True)
else:
webbrowser.open(f"https://qgis.org/api/{version}")
iface.showApiDocumentation()
return
if isinstance(object, str):
@ -135,15 +126,9 @@ def _help(object=None, api="c++"):
obj_info = __parse_object(object)
if not obj_info:
return
obj_type, module, class_name = obj_info
iface.showApiDocumentation(obj_type, python= not api=="c++", module=module, object=class_name)
if obj_info[0] == 'qgis':
if api == "c++":
webbrowser.open(f"https://api.qgis.org/api/{version}/class{obj_info[2]}.html")
else:
webbrowser.open(f"https://qgis.org/pyqgis/{version}/{obj_info[1]}/{obj_info[2]}.html")
elif obj_info[0] == 'qt':
qtversion = '.'.join(qVersion().split(".")[:2])
webbrowser.open(f"https://doc.qt.io/qt-{qtversion}/{obj_info[2].lower()}.html")
""",
r"""
def _api(object=None):

View File

@ -1490,6 +1490,13 @@ Unregister a previously registered tool factory from the development/debugging t
.. seealso:: :py:func:`registerDevToolWidgetFactory`
.. versionadded:: 3.14
%End
virtual void showApiDocumentation( const QString &api = QStringLiteral( "qgis" ), bool python = true, bool embedded = true, const QString &module = QString(), const QString &object = QString() ) = 0;
%Docstring
Show a page of the API documentation in the embedded Dev tool webview
.. versionadded:: 3.42
%End
virtual void registerApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker ) = 0;

View File

@ -174,6 +174,7 @@ set(QGIS_APP_SRCS
devtools/networklogger/qgsnetworkloggerwidgetfactory.cpp
devtools/profiler/qgsprofilerpanelwidget.cpp
devtools/profiler/qgsprofilerwidgetfactory.cpp
devtools/documentation/qgsdocumentationpanelwidget.cpp
devtools/querylogger/qgsappquerylogger.cpp
devtools/querylogger/qgsdatabasequeryloggernode.cpp
devtools/querylogger/qgsqueryloggerpanelwidget.cpp

View File

@ -0,0 +1,39 @@
/***************************************************************************
qgsdocumentationpanelwidget.cpp
-------------------------
begin : October 2024
copyright : (C) 2024 by Yoann Quenach de Quivillic
email : yoann dot quenach at gmail 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 "qgsdocumentationpanelwidget.h"
#include "qgswebview.h"
#include "qgisapp.h"
#include <QVBoxLayout>
//
// QgsDocumentationPanelWidget
//
QgsDocumentationPanelWidget::QgsDocumentationPanelWidget( QWidget *parent )
: QgsDevToolWidget( parent )
{
setupUi( this );
connect( mCppHomeButton, &QToolButton::clicked, this, [this] {QgisApp::instance()->showApiDocumentation( QStringLiteral( "qgis" ), false, true );} );
connect( mPythonHomeButton, &QToolButton::clicked, this, [this] {QgisApp::instance()->showApiDocumentation( QStringLiteral( "qgis" ), true, true );} );
connect( mQtHomeButton, &QToolButton::clicked, this, [this] {QgisApp::instance()->showApiDocumentation( QStringLiteral( "qt" ), false, true );} );
}
void QgsDocumentationPanelWidget::showUrl( const QUrl &url )
{
mWebView->setUrl( url );
}

View File

@ -0,0 +1,45 @@
/***************************************************************************
qgsdocumentationpanelwidget.h
-------------------------
begin : October 2024
copyright : (C) 2024 by Yoann Quenach de Quivillic
email : yoann dot quenach at gmail 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 QGSDOCUMENTATIONPANELWIDGET_H
#define QGSDOCUMENTATIONPANELWIDGET_H
#include "qgsdevtoolwidget.h"
#include "ui_qgsdocumentationpanelbase.h"
/**
* \ingroup app
* \class QgsDocumentationPanelWidget
* \brief A panel widget showing profiled startup times for debugging.
*
* \since QGIS 3.14
*/
class QgsDocumentationPanelWidget : public QgsDevToolWidget, private Ui::QgsDocumentationPanelBase
{
Q_OBJECT
public:
/**
* Constructor for QgsDocumentationPanelWidget.
*/
QgsDocumentationPanelWidget( QWidget *parent );
void showUrl( const QUrl &url );
};
#endif // QGSDOCUMENTATIONPANELWIDGET_H

View File

@ -12964,25 +12964,12 @@ void QgisApp::helpContents()
void QgisApp::apiDocumentation()
{
if ( QFileInfo::exists( QgsApplication::pkgDataPath() + "/doc/api/index.html" ) )
{
openURL( QStringLiteral( "api/index.html" ) );
}
else
{
QgsSettings settings;
QString QgisApiUrl = settings.value( QStringLiteral( "qgis/QgisApiUrl" ),
QStringLiteral( "https://qgis.org/api/" ) ).toString();
openURL( QgisApiUrl, false );
}
showApiDocumentation( "qgis", false, false );
}
void QgisApp::pyQgisApiDocumentation()
{
QgsSettings settings;
QString PyQgisApiUrl = settings.value( QStringLiteral( "qgis/PyQgisApiUrl" ),
QStringLiteral( "https://qgis.org/pyqgis/" ) ).toString();
openURL( PyQgisApiUrl, false );
showApiDocumentation( "qgis", true, false );
}
void QgisApp::reportaBug()
@ -13126,6 +13113,95 @@ void QgisApp::unregisterDevToolFactory( QgsDevToolWidgetFactory *factory )
mDevToolFactories.removeAll( factory );
}
void QgisApp::showApiDocumentation( const QString &api, bool python, bool embedded, const QString &module, const QString &object )
{
bool useQgisDocDirectory = false;
QString baseUrl;
if ( api == "qt" )
{
const QStringList parts = QString( qVersion() ).split( "." );
baseUrl = QString( "https://doc.qt.io/qt-%1.%2/" ).arg( parts[0], parts[1] );
}
else if ( api == "qgis" )
{
// Get the current QGIS version
QString version;
if ( Qgis::version().toLower().contains( QStringLiteral( "master" ) ) )
{
version = QStringLiteral( "master" );
}
else
{
version = Qgis::version().left( 4 );
}
if ( python )
{
QgsSettings settings;
baseUrl = settings.value( QStringLiteral( "qgis/PyQgisApiUrl" ),
QString( "https://qgis.org/pyqgis/%1" ).arg( version ) ).toString();
}
else
{
if ( QFileInfo::exists( QgsApplication::pkgDataPath() + "/doc/api/index.html" ) )
{
useQgisDocDirectory = true;
baseUrl = "api/index.html";
}
else
{
QgsSettings settings;
baseUrl = settings.value( QStringLiteral( "qgis/QgisApiUrl" ),
QString( "https://qgis.org/api/%1" ).arg( version ) ).toString();
}
}
}
else
{
messageBar()->pushWarning( tr( "Unknown API" ), api );
return;
}
QString url;
if ( object.isEmpty() )
{
url = baseUrl;
}
else
{
if ( api == QStringLiteral( "qgis" ) )
{
if ( python ) // pyQGIS
{
url = baseUrl + QString( "/%1/%2.html" ).arg( module, object );
}
else
{
url = baseUrl + QString( "/class%1.html" ).arg( object );
}
}
else // Qt
{
url = baseUrl + QString( "/%1.html" ).arg( object.toLower() );
}
}
if ( embedded )
{
if ( useQgisDocDirectory )
{
url = "file://" + QgsApplication::pkgDataPath() + "/doc/" + url;
}
mDevToolsDock->show();
mDevToolsWidget->showUrl( QUrl( url ) );
}
else
{
openURL( baseUrl, useQgisDocDirectory );
}
}
void QgisApp::registerApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker )
{
mApplicationExitBlockers << blocker;

View File

@ -798,6 +798,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Unregister a previously registered dev tool factory
void unregisterDevToolFactory( QgsDevToolWidgetFactory *factory );
//! Show a page of the API documentation
void showApiDocumentation( const QString &api, bool python, bool embedded, const QString &module = QString(), const QString &object = QString() );
/**
* Register a new application exit blocker, which can be used to prevent the QGIS application
* from exiting while a plugin or script has unsaved changes.
@ -1415,6 +1418,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/
void activateDeactivateLayerRelatedActions( QgsMapLayer *layer );
//! Open a url in the users configured browser
void openURL( QString url, bool useQgisDocDirectory = true );
protected:
void showEvent( QShowEvent *event ) override;
@ -1778,8 +1784,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void supportProviders();
//! Open the QGIS homepage in users browser
void helpQgisHomePage();
//! Open a url in the users configured browser
void openURL( QString url, bool useQgisDocDirectory = true );
//! Check qgis version against the qgis version server
void checkQgisVersion();
//!Invoke the custom projection dialog
@ -2737,6 +2741,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsScopedDevToolWidgetFactory mStartupProfilerWidgetFactory;
QgsAppQueryLogger *mQueryLogger = nullptr;
QgsScopedDevToolWidgetFactory mQueryLoggerWidgetFactory;
QgsScopedDevToolWidgetFactory mDocumentationWidgetFactory;
std::vector< QgsScopedOptionsWidgetFactory > mOptionWidgetFactories;

View File

@ -641,6 +641,12 @@ void QgisAppInterface::unregisterDevToolWidgetFactory( QgsDevToolWidgetFactory *
qgis->unregisterDevToolFactory( factory );
}
void QgisAppInterface::showApiDocumentation( const QString &api, bool python, bool embedded, const QString &module, const QString &object )
{
qgis->showApiDocumentation( api, python, embedded, module, object );
}
void QgisAppInterface::registerApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker )
{
qgis->registerApplicationExitBlocker( blocker );

View File

@ -157,6 +157,7 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
void unregisterProjectPropertiesWidgetFactory( QgsOptionsWidgetFactory *factory ) override;
void registerDevToolWidgetFactory( QgsDevToolWidgetFactory *factory ) override;
void unregisterDevToolWidgetFactory( QgsDevToolWidgetFactory *factory ) override;
void showApiDocumentation( const QString &api, bool python, bool embedded, const QString &module, const QString &object ) override;
void registerApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker ) override;
void unregisterApplicationExitBlocker( QgsApplicationExitBlockerInterface *blocker ) override;
void registerMapToolHandler( QgsAbstractMapToolHandler *handler ) override;

View File

@ -19,6 +19,7 @@
#include "qgsdevtoolwidget.h"
#include "qgspanelwidgetstack.h"
#include "qgssettingsentryimpl.h"
#include "devtools/documentation/qgsdocumentationpanelwidget.h"
const QgsSettingsEntryString *QgsDevToolsPanelWidget::settingLastActiveTab = new QgsSettingsEntryString( QStringLiteral( "last-active-tab" ), QgsDevToolsPanelWidget::sTreeDevTools, QString(), QStringLiteral( "Last visible tab in developer tools panel" ) );
@ -31,6 +32,11 @@ QgsDevToolsPanelWidget::QgsDevToolsPanelWidget( const QList<QgsDevToolWidgetFact
mOptionsListWidget->setIconSize( QgisApp::instance()->iconSize( false ) );
mOptionsListWidget->setMaximumWidth( static_cast< int >( mOptionsListWidget->iconSize().width() * 1.18 ) );
// Add embedded documentation
mDocumentationPanel = new QgsDocumentationPanelWidget( this );
addToolWidget( mDocumentationPanel ) ;
for ( QgsDevToolWidgetFactory *factory : factories )
addToolFactory( factory );
@ -44,6 +50,23 @@ QgsDevToolsPanelWidget::QgsDevToolsPanelWidget( const QList<QgsDevToolWidgetFact
QgsDevToolsPanelWidget::~QgsDevToolsPanelWidget() = default;
void QgsDevToolsPanelWidget::addToolWidget( QgsDevToolWidget *widget )
{
QgsPanelWidgetStack *toolStack = new QgsPanelWidgetStack();
toolStack->setMainPanel( widget );
mStackedWidget->addWidget( toolStack );
QListWidgetItem *item = new QListWidgetItem( widget->windowIcon(), QString() );
item->setToolTip( widget->windowTitle() );
item->setData( Qt::UserRole, widget->windowTitle() );
mOptionsListWidget->addItem( item );
if ( mOptionsListWidget->count() == 1 )
{
setCurrentTool( 0 );
}
}
void QgsDevToolsPanelWidget::addToolFactory( QgsDevToolWidgetFactory *factory )
{
if ( QgsDevToolWidget *toolWidget = factory->createWidget( this ) )
@ -104,3 +127,9 @@ void QgsDevToolsPanelWidget::setCurrentTool( int row )
whileBlocking( mOptionsListWidget )->setCurrentRow( row );
mStackedWidget->setCurrentIndex( row );
}
void QgsDevToolsPanelWidget::showUrl( const QUrl &url )
{
whileBlocking( mOptionsListWidget )->setCurrentRow( 0 );
mDocumentationPanel->showUrl( url );
}

View File

@ -20,7 +20,8 @@
#include "qgssettingstree.h"
class QgsDevToolWidgetFactory;
class QgsDevToolWidget;
class QgsDocumentationPanelWidget;
class APP_EXPORT QgsDevToolsPanelWidget : public QWidget, private Ui::QgsDevToolsWidgetBase
{
Q_OBJECT
@ -32,12 +33,15 @@ class APP_EXPORT QgsDevToolsPanelWidget : public QWidget, private Ui::QgsDevTool
QgsDevToolsPanelWidget( const QList<QgsDevToolWidgetFactory *> &factories, QWidget *parent = nullptr );
~QgsDevToolsPanelWidget() override;
void addToolWidget( QgsDevToolWidget *widget );
void addToolFactory( QgsDevToolWidgetFactory *factory );
void removeToolFactory( QgsDevToolWidgetFactory *factory );
void setActiveTab( const QString &title );
void showUrl( const QUrl &url );
private slots:
void setCurrentTool( int row );
@ -45,6 +49,7 @@ class APP_EXPORT QgsDevToolsPanelWidget : public QWidget, private Ui::QgsDevTool
private:
QMap< QgsDevToolWidgetFactory *, int> mFactoryPages;
QgsDocumentationPanelWidget *mDocumentationPanel;
};
#endif // QGSDEVTOOLSPANELWIDGET_H

View File

@ -1280,6 +1280,12 @@ class GUI_EXPORT QgisInterface : public QObject
*/
virtual void unregisterDevToolWidgetFactory( QgsDevToolWidgetFactory *factory ) = 0;
/**
* Show a page of the API documentation in the embedded Dev tool webview
* \since QGIS 3.42
*/
virtual void showApiDocumentation( const QString &api = QStringLiteral( "qgis" ), bool python = true, bool embedded = true, const QString &module = QString(), const QString &object = QString() ) = 0;
/**
* Register a new application exit blocker, which can be used to prevent the QGIS application
* from exiting while a plugin or script has unsaved changes.

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsDocumentationPanelBase</class>
<widget class="QgsPanelWidget" name="QgsDocumentationPanelBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>538</height>
</rect>
</property>
<property name="windowTitle">
<string>Documentation</string>
</property>
<property name="windowIcon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionHelpContents.svg</normaloff>:/images/themes/default/mActionHelpContents.svg</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="mCppHomeButton">
<property name="toolTip">
<string>C++ API documentation</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/icons/qgis_icon.svg</normaloff>:/images/icons/qgis_icon.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mPythonHomeButton">
<property name="toolTip">
<string>PyQGIS API Documentation</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconPythonFile.svg</normaloff>:/images/themes/default/mIconPythonFile.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mQtHomeButton">
<property name="toolTip">
<string>Qt API Documentation</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/console/iconQtCoreConsole.svg</normaloff>:/images/themes/default/console/iconQtCoreConsole.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QgsWebView" name="mWebView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsPanelWidget</class>
<extends>QWidget</extends>
<header>qgspanelwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsWebView</class>
<extends>QWidget</extends>
<header>qgswebview.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../images/images.qrc"/>
</resources>
<connections/>
</ui>