create a method in QgsGui to determine if running Python macros is allowed

This commit is contained in:
Denis Rouzaud 2019-09-30 13:45:54 +02:00
parent 96e8abde39
commit 86550e9837
12 changed files with 104 additions and 42 deletions

View File

@ -1,9 +1,10 @@
# The following has been generated automatically from src/core/qgis.h
# monkey patching scoped based enum
Qgis.PythonMacroMode.Never.__doc__ = "Macros are never run"
Qgis.PythonMacroMode.Ask.__doc__ = "User is prompt before runnning"
Qgis.PythonMacroMode.Ask.__doc__ = "User is prompt before running"
Qgis.PythonMacroMode.SessionOnly.__doc__ = "Only during this session"
Qgis.PythonMacroMode.Always.__doc__ = "Macros are always run"
Qgis.PythonMacroMode.__doc__ = 'Authorisation to run Python Macros\n\n.. versionadded:: 3.10\n\n' + '* ``Never``: ' + Qgis.PythonMacroMode.Never.__doc__ + '\n' + '* ``Ask``: ' + Qgis.PythonMacroMode.Ask.__doc__ + '\n' + '* ``SessionOnly``: ' + Qgis.PythonMacroMode.SessionOnly.__doc__ + '\n' + '* ``Always``: ' + Qgis.PythonMacroMode.Always.__doc__
Qgis.PythonMacroMode.NotForThisSession.__doc__ = "Macros will not be run for this session"
Qgis.PythonMacroMode.__doc__ = 'Authorisation to run Python Macros\n\n.. versionadded:: 3.10\n\n' + '* ``Never``: ' + Qgis.PythonMacroMode.Never.__doc__ + '\n' + '* ``Ask``: ' + Qgis.PythonMacroMode.Ask.__doc__ + '\n' + '* ``SessionOnly``: ' + Qgis.PythonMacroMode.SessionOnly.__doc__ + '\n' + '* ``Always``: ' + Qgis.PythonMacroMode.Always.__doc__ + '\n' + '* ``NotForThisSession``: ' + Qgis.PythonMacroMode.NotForThisSession.__doc__
# --
Qgis.PythonMacroMode.baseClass = Qgis

View File

@ -70,7 +70,8 @@ The Qgis class provides global constants for use throughout the application.
Never,
Ask,
SessionOnly,
Always
Always,
NotForThisSession,
};
static const double DEFAULT_SEARCH_RADIUS_MM;

View File

@ -5,7 +5,6 @@
%Include auto_generated/expression/qgsexpressionnodeimpl.sip
%Include auto_generated/expression/qgsexpressionfunction.sip
%Include auto_generated/qgstessellator.sip
%Include auto_generated/qgis.sip
%Include auto_generated/qgsabstractproviderconnection.sip
%Include auto_generated/qgsabstractdatabaseproviderconnection.sip
%Include auto_generated/qgsaction.sip
@ -335,6 +334,7 @@
%Include auto_generated/validity/qgsvaliditycheckregistry.sip
%Include auto_generated/gps/qgsqtlocationconnection.sip
%Include auto_generated/gps/qgsgpsconnectionregistry.sip
%Include auto_generated/qgis.sip
%Include auto_generated/qgsabstractcontentcache.sip
%Include auto_generated/qgsapplication.sip
%Include auto_generated/qgsactionscoperegistry.sip

View File

@ -640,7 +640,6 @@ This represents the current layer tree group and index where newly added map lay
.. versionadded:: 3.10
%End
public slots: // TODO: do these functions really need to be slots?

View File

@ -159,6 +159,7 @@ Returns the screen at the given global ``point`` (pixel).
.. versionadded:: 3.10
%End
private:
QgsGui( const QgsGui &other );
};

View File

@ -2096,11 +2096,19 @@ void QgisApp::readSettings()
// Read legacy settings
readRecentProjects();
// this is a new session! reset enable macros value to "ask"
// whether set to "just for this session"
if ( settings.value( QStringLiteral( "qgis/enableMacros" ), 1 ).toInt() == 2 )
// this is a new session, reset enable macros value when they are set for session
Qgis::PythonMacroMode macroMode = settings.enumValue( QStringLiteral( "qgis/enableMacros" ), Qgis::PythonMacroMode::Ask );
switch ( macroMode )
{
settings.setValue( QStringLiteral( "qgis/enableMacros" ), 1 );
case Qgis::PythonMacroMode::NotForThisSession:
case Qgis::PythonMacroMode::SessionOnly:
settings.setEnumValue( QStringLiteral( "qgis/enableMacros" ), Qgis::PythonMacroMode::Ask );
break;
case Qgis::PythonMacroMode::Always:
case Qgis::PythonMacroMode::Never:
case Qgis::PythonMacroMode::Ask:
break;
}
}
@ -6297,29 +6305,8 @@ bool QgisApp::addProject( const QString &projectFile )
}
else if ( enableMacros == Qgis::PythonMacroMode::Ask )
{
// create the notification widget for macros
QToolButton *btnEnableMacros = new QToolButton();
btnEnableMacros->setText( tr( "Enable Macros" ) );
btnEnableMacros->setStyleSheet( QStringLiteral( "background-color: rgba(255, 255, 255, 0); color: black; text-decoration: underline;" ) );
btnEnableMacros->setCursor( Qt::PointingHandCursor );
btnEnableMacros->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
QgsMessageBarItem *macroMsg = new QgsMessageBarItem(
tr( "Security warning" ),
tr( "project macros have been disabled." ),
btnEnableMacros,
Qgis::Warning,
0,
mInfoBar );
connect( btnEnableMacros, &QToolButton::clicked, this, [this, macroMsg]
{
enableProjectMacros();
mInfoBar->popWidget( macroMsg );
} );
// display the macros notification widget
mInfoBar->pushItem( macroMsg );
auto lambda = []() {QgisApp::instance()->enableProjectMacros();};
QgsGui::pythonMacroAllowed( lambda, mInfoBar );
}
}
}

View File

@ -237,7 +237,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/**
* Attempts to run a Python script
* \param filePath full path to Python script
* \since QGIS 2.7
*/
void runScript( const QString &filePath );

View File

@ -102,9 +102,10 @@ class CORE_EXPORT Qgis
enum class PythonMacroMode
{
Never = 0, //!< Macros are never run
Ask = 1, //!< User is prompt before runnning
Ask = 1, //!< User is prompt before running
SessionOnly = 2, //!< Only during this session
Always = 3 //!< Macros are always run
Always = 3, //!< Macros are always run
NotForThisSession, //!< Macros will not be run for this session
};
Q_ENUM( PythonMacroMode )

View File

@ -570,7 +570,6 @@ class GUI_EXPORT QgisInterface : public QObject
*/
virtual QgsLayerTreeRegistryBridge::InsertionPoint layerTreeInsertionPoint() = 0;
public slots: // TODO: do these functions really need to be slots?
/* Exposed functions */

View File

@ -20,6 +20,7 @@
#include "qgsattributeformrelationeditorwidget.h"
#include "qgseditorwidgetregistry.h"
#include "qgsfeatureiterator.h"
#include "qgsgui.h"
#include "qgsproject.h"
#include "qgspythonrunner.h"
#include "qgsrelationwidgetwrapper.h"
@ -1744,13 +1745,12 @@ void QgsAttributeForm::initPython()
case QgsEditFormConfig::CodeSourceEnvironment:
case QgsEditFormConfig::CodeSourceNone:
default:
// Nothing to do: the function code should be already in the environment
break;
}
// If we have a function code, run it
if ( ! initCode.isEmpty() )
if ( !initCode.isEmpty() && QgsGui::pythonMacroAllowed() )
{
QgsPythonRunner::run( initCode );
}

View File

@ -15,6 +15,11 @@
* *
***************************************************************************/
#include <QScreen>
#include <QDesktopWidget>
#include <QMessageBox>
#include "qgsgui.h"
#include "qgseditorwidgetregistry.h"
#include "qgslayertreeembeddedwidgetregistry.h"
@ -49,9 +54,9 @@
#include "qgsproviderregistry.h"
#include "qgsproviderguiregistry.h"
#include "qgsprojectstorageguiregistry.h"
#include "qgsmessagebar.h"
#include "qgsmessagebaritem.h"
#include <QScreen>
#include <QDesktopWidget>
QgsGui *QgsGui::instance()
{
@ -229,6 +234,66 @@ QgsGui::QgsGui()
mWidgetStateHelper = new QgsWidgetStateHelper();
mProcessingRecentAlgorithmLog = new QgsProcessingRecentAlgorithmLog();
mProcessingGuiRegistry = new QgsProcessingGuiRegistry();
}
bool QgsGui::pythonMacroAllowed( void ( *lambda )(), QgsMessageBar *messageBar )
{
Qgis::PythonMacroMode macroMode = QgsSettings().enumValue( QStringLiteral( "qgis/enableMacros" ), Qgis::PythonMacroMode::Ask );
switch ( macroMode )
{
case Qgis::PythonMacroMode::SessionOnly:
case Qgis::PythonMacroMode::Always:
return true;
case Qgis::PythonMacroMode::Never:
case Qgis::PythonMacroMode::NotForThisSession:
return false;
case Qgis::PythonMacroMode::Ask:
if ( !lambda )
{
QMessageBox msgBox( QMessageBox::Information, "Python Macros",
tr( "Python macros are currently disabled. Do you allow this macro to run?" ) );
QAbstractButton *stopSessionButton = msgBox.addButton( tr( "Don't ask anymore" ), QMessageBox::DestructiveRole );
msgBox.addButton( tr( "No" ), QMessageBox::NoRole );
QAbstractButton *yesButton = msgBox.addButton( tr( "Yes" ), QMessageBox::YesRole );
QAbstractButton *clicked = msgBox.clickedButton();
if ( clicked == stopSessionButton )
{
QgsSettings().setEnumValue( QStringLiteral( "qgis/enableMacros" ), Qgis::PythonMacroMode::NotForThisSession );
}
return clicked == yesButton;
}
else
{
// create the notification widget for macros
Q_ASSERT( messageBar );
if ( messageBar )
{
QToolButton *btnEnableMacros = new QToolButton();
btnEnableMacros->setText( tr( "Enable Macros" ) );
btnEnableMacros->setStyleSheet( QStringLiteral( "background-color: rgba(255, 255, 255, 0); color: black; text-decoration: underline;" ) );
btnEnableMacros->setCursor( Qt::PointingHandCursor );
btnEnableMacros->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
QgsMessageBarItem *macroMsg = new QgsMessageBarItem(
tr( "Security warning" ),
tr( "Python macros cannot currently be run." ),
btnEnableMacros,
Qgis::Warning,
0,
messageBar );
connect( btnEnableMacros, &QToolButton::clicked, [ = ]()
{
lambda();
messageBar->popWidget( macroMsg );
} );
// display the macros notification widget
messageBar->pushItem( macroMsg );
}
return false;
}
}
}

View File

@ -37,6 +37,7 @@ class QgsWindowManagerInterface;
class QgsDataItemGuiProviderRegistry;
class QgsProviderGuiRegistry;
class QgsProjectStorageGuiRegistry;
class QgsMessageBar;
/**
* \ingroup gui
@ -192,6 +193,14 @@ class GUI_EXPORT QgsGui : public QObject
*/
static QScreen *findScreenAt( QPoint point );
/**
* Returns true if python macros are currently allowed to be run
* If the global option is to ask user, a modal dialog will be shown
* \param lambda a pointer to a lambda method. If specified, the dialog is not modal,
* a message bar is shown with a button to enable macro and run the lambda
*/
static bool pythonMacroAllowed( void ( *lambda )() = nullptr, QgsMessageBar *messageBar = nullptr ) SIP_SKIP;
private:
QgsGui();