Skip to content

Commit 3d311d6

Browse files
committedDec 5, 2015
Merge pull request #2498 from elpaso/pythoninitcode
Refactored the python init function selector
2 parents de3ce15 + 3ca5441 commit 3d311d6

9 files changed

+393
-183
lines changed
 

‎python/core/qgseditformconfig.sip

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ class QgsEditFormConfig : QObject
5757
SuppressOff = 2 //!< Do not suppress feature form
5858
};
5959

60+
/**
61+
* The python init code source options.
62+
*/
63+
enum PythonInitCodeSource
64+
{
65+
CodeSourceNone = 0, //!< Do not use python code at all
66+
CodeSourceFile = 1, //!< Load the python code from a file
67+
CodeSourceDialog = 2, //!< Use the python code provided in the dialog
68+
CodeSourceEnvironment = 3 //!< Use the python code available in the python environment
69+
};
70+
71+
6072
/**
6173
* This is only useful in combination with EditorLayout::TabLayout.
6274
*
@@ -208,15 +220,6 @@ class QgsEditFormConfig : QObject
208220
void setLabelOnTop( int idx, bool onTop );
209221

210222

211-
212-
213-
214-
215-
216-
217-
218-
219-
220223
// Python stuff
221224

222225

@@ -237,22 +240,38 @@ class QgsEditFormConfig : QObject
237240
void setInitFunction( const QString& function );
238241

239242
/**
240-
* Get python code for edit form initialization.
243+
* Get python code for edit form initialization from the configuration dialog.
241244
*/
242245
QString initCode() const;
243246

247+
/**
248+
* Get python external file path for edit form initialization.
249+
*/
250+
QString initFilePath() const;
251+
252+
/**
253+
* Set python external file path for edit form initialization.
254+
* Make sure that you also set the appropriate function name in
255+
* @link setInitFunction @endlink
256+
*/
257+
void setInitFilePath( const QString& filePath );
258+
244259
/**
245260
* Get python code for edit form initialization.
246261
* Make sure that you also set the appropriate function name in
247262
* @link setInitFunction @endlink
248263
*/
249264
void setInitCode( const QString& code );
250265

251-
/** Return if python code shall be loaded for edit form initialization */
252-
bool useInitCode() const;
266+
/** Return python code source for edit form initialization
267+
* (if it shall be loaded from a file, read from the
268+
* provided dialog editor or just read from the environment
269+
*/
270+
PythonInitCodeSource initCodeSource() const;
253271

254272
/** Set if python code shall be used for edit form initialization */
255-
void setUseInitCode( const bool useCode );
273+
void setInitCodeSource( const PythonInitCodeSource initCodeSource );
274+
256275

257276
/** Type of feature form pop-up suppression after feature creation (overrides app setting) */
258277
FeatureFormSuppress suppress() const;

‎src/app/qgsfieldsproperties.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ QgsFieldsProperties::QgsFieldsProperties( QgsVectorLayer *layer, QWidget* parent
115115
mRelationsList->setHorizontalHeaderItem( RelFieldCol, new QTableWidgetItem( tr( "Field" ) ) );
116116
mRelationsList->verticalHeader()->hide();
117117

118+
// Init function stuff
119+
mInitCodeSourceComboBox->addItem( tr( "" ) );
120+
mInitCodeSourceComboBox->addItem( tr( "Load from external file" ) );
121+
mInitCodeSourceComboBox->addItem( tr( "Provide code in this dialog" ) );
122+
mInitCodeSourceComboBox->addItem( tr( "Load from the environment" ) );
123+
118124
loadRelations();
119125

120126
updateButtons();
@@ -183,11 +189,15 @@ QTreeWidgetItem *QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeE
183189
return newWidget;
184190
}
185191

186-
void QgsFieldsProperties::setEditFormInit( const QString &editForm, const QString &editFormInit, const QString &editFormInitCode, const bool editFormInitUseCode )
192+
void QgsFieldsProperties::setEditFormInit( const QString &editForm,
193+
const QString &initFunction,
194+
const QString &initCode,
195+
const QString &initFilePath,
196+
const QgsEditFormConfig::PythonInitCodeSource &codeSource )
187197
{
188198

189199
// Python init function and code
190-
QString code( editFormInitCode );
200+
QString code( initCode );
191201
if ( code.isEmpty( ) )
192202
{
193203
code.append( tr( "# -*- coding: utf-8 -*-\n\"\"\"\n"
@@ -206,12 +216,11 @@ void QgsFieldsProperties::setEditFormInit( const QString &editForm, const QStrin
206216
"\tcontrol = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
207217

208218
}
209-
leEditForm->setText( editForm );
210-
leEditFormInitCode->setText( code );
211-
leEditFormInit->setText( editFormInit );
212-
leEditFormInitUseCode->setChecked( editFormInitUseCode );
213-
// Show or hide as needed
214-
mPythonInitCodeGroupBox->setVisible( editFormInitUseCode );
219+
mEditFormLineEdit->setText( editForm );
220+
mInitFilePathLineEdit->setText( initFilePath );
221+
mInitCodeEditorPython->setText( code );
222+
mInitFunctionLineEdit->setText( initFunction );
223+
mInitCodeSourceComboBox->setCurrentIndex( codeSource );
215224
}
216225

217226

@@ -453,9 +462,14 @@ void QgsFieldsProperties::on_mMoveUpItem_clicked()
453462
}
454463
}
455464

456-
void QgsFieldsProperties::on_leEditFormInitUseCode_toggled( bool checked )
465+
void QgsFieldsProperties::on_mInitCodeSourceComboBox_currentIndexChanged( int codeSource )
457466
{
458-
mPythonInitCodeGroupBox->setVisible( checked );
467+
// Show or hide ui elements as needed
468+
mInitFunctionContainer->setVisible( codeSource != QgsEditFormConfig::PythonInitCodeSource::CodeSourceNone );
469+
mPythonInitCodeGroupBox->setVisible( codeSource == QgsEditFormConfig::PythonInitCodeSource::CodeSourceDialog );
470+
mInitFilePathLineEdit->setVisible( codeSource == QgsEditFormConfig::PythonInitCodeSource::CodeSourceFile );
471+
mInitFilePathLabel->setVisible( codeSource == QgsEditFormConfig::PythonInitCodeSource::CodeSourceFile );
472+
pbtnSelectInitFilePath->setVisible( codeSource == QgsEditFormConfig::PythonInitCodeSource::CodeSourceFile );
459473
}
460474

461475
void QgsFieldsProperties::attributeTypeDialog()
@@ -805,6 +819,22 @@ QgsAttributeEditorElement* QgsFieldsProperties::createAttributeEditorWidget( QTr
805819
return widgetDef;
806820
}
807821

822+
823+
void QgsFieldsProperties::on_pbtnSelectInitFilePath_clicked()
824+
{
825+
QSettings myQSettings;
826+
QString lastUsedDir = myQSettings.value( "style/lastUIDir", "." ).toString();
827+
QString pyfilename = QFileDialog::getOpenFileName( this, tr( "Select Python file" ), lastUsedDir, tr( "Python file" ) + " (*.py)" );
828+
829+
if ( pyfilename.isNull() )
830+
return;
831+
832+
QFileInfo fi( pyfilename );
833+
myQSettings.setValue( "style/lastUIDir", fi.path() );
834+
mInitFilePathLineEdit->setText( pyfilename );
835+
}
836+
837+
808838
void QgsFieldsProperties::on_pbnSelectEditForm_clicked()
809839
{
810840
QSettings myQSettings;
@@ -816,7 +846,7 @@ void QgsFieldsProperties::on_pbnSelectEditForm_clicked()
816846

817847
QFileInfo fi( uifilename );
818848
myQSettings.setValue( "style/lastUIDir", fi.path() );
819-
leEditForm->setText( uifilename );
849+
mEditFormLineEdit->setText( uifilename );
820850
}
821851

822852
void QgsFieldsProperties::on_mEditorLayoutComboBox_currentIndexChanged( int index )
@@ -875,10 +905,14 @@ void QgsFieldsProperties::apply()
875905

876906
mLayer->editFormConfig()->setLayout(( QgsEditFormConfig::EditorLayout ) mEditorLayoutComboBox->currentIndex() );
877907
if ( mEditorLayoutComboBox->currentIndex() == QgsEditFormConfig::UiFileLayout )
878-
mLayer->editFormConfig()->setUiForm( leEditForm->text() );
879-
mLayer->editFormConfig()->setInitFunction( leEditFormInit->text() );
880-
mLayer->editFormConfig()->setUseInitCode( leEditFormInitUseCode->isChecked() );
881-
mLayer->editFormConfig()->setInitCode( leEditFormInitCode->text() );
908+
mLayer->editFormConfig()->setUiForm( mEditFormLineEdit->text() );
909+
910+
// Init function configuration
911+
mLayer->editFormConfig()->setInitFunction( mInitFunctionLineEdit->text( ) );
912+
mLayer->editFormConfig()->setInitCode( mInitCodeEditorPython->text( ) );
913+
mLayer->editFormConfig()->setInitFilePath( mInitFilePathLineEdit->text( ) );
914+
mLayer->editFormConfig()->setInitCodeSource(( QgsEditFormConfig::PythonInitCodeSource )mInitCodeSourceComboBox->currentIndex() );
915+
882916
mLayer->editFormConfig()->setSuppress(( QgsEditFormConfig::FeatureFormSuppress )mFormSuppressCmbBx->currentIndex() );
883917

884918
mLayer->setExcludeAttributesWMS( excludeAttributesWMS );

‎src/app/qgsfieldsproperties.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,16 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
163163
/**
164164
* @brief setEditFormInit set the private ui fields
165165
* @param editForm
166-
* @param editFormInit
167-
* @param editFormInitCode
168-
* @param editFormInitUseCode
166+
* @param initFunction
167+
* @param initCode
168+
* @param initFilePath
169+
* @param codeSource
169170
*/
170-
void setEditFormInit( const QString &editForm, const QString &editFormInit, const QString &editFormInitCode, const bool editFormInitUseCode );
171+
void setEditFormInit( const QString &editForm,
172+
const QString &initFunction,
173+
const QString &initCode,
174+
const QString &initFilePath,
175+
const QgsEditFormConfig::PythonInitCodeSource &codeSource );
171176

172177
signals:
173178
void toggleEditing();
@@ -177,9 +182,10 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
177182
void on_mDeleteAttributeButton_clicked();
178183
void on_mCalculateFieldButton_clicked();
179184
void onAttributeSelectionChanged();
185+
void on_pbtnSelectInitFilePath_clicked();
180186
void on_pbnSelectEditForm_clicked();
181187
void on_mEditorLayoutComboBox_currentIndexChanged( int index );
182-
void on_leEditFormInitUseCode_toggled( bool checked );
188+
void on_mInitCodeSourceComboBox_currentIndexChanged( int codeSource );
183189
void attributeAdded( int idx );
184190
void attributeDeleted( int idx );
185191
void attributeTypeDialog();

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,5 +1317,5 @@ void QgsVectorLayerProperties::updateVariableEditor()
13171317
void QgsVectorLayerProperties::updateFieldsPropertiesDialog()
13181318
{
13191319
QgsEditFormConfig* cfg = layer->editFormConfig();
1320-
mFieldsPropertiesDialog->setEditFormInit( cfg->uiForm(), cfg->initFunction(), cfg->initCode(), cfg->useInitCode() );
1320+
mFieldsPropertiesDialog->setEditFormInit( cfg->uiForm(), cfg->initFunction(), cfg->initCode(), cfg->initFilePath(), cfg->initCodeSource() );
13211321
}

‎src/core/qgseditformconfig.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
QgsEditFormConfig::QgsEditFormConfig( QObject* parent )
55
: QObject( parent )
66
, mEditorLayout( GeneratedLayout )
7+
, mInitCodeSource( QgsEditFormConfig::PythonInitCodeSource::CodeSourceNone )
78
, mFeatureFormSuppress( SuppressDefault )
8-
, mUseInitCode( false )
99
{
1010
connect( QgsProject::instance()->relationManager(), SIGNAL( relationsLoaded() ), this, SLOT( onRelationsLoaded() ) );
1111
}

‎src/core/qgseditformconfig.h

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
271271
Q_OBJECT
272272

273273
public:
274+
274275
/** The different types to layout the attribute editor. */
275276
enum EditorLayout
276277
{
@@ -308,6 +309,17 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
308309
SuppressOff = 2 //!< Do not suppress feature form
309310
};
310311

312+
/**
313+
* The python init code source options.
314+
*/
315+
enum PythonInitCodeSource
316+
{
317+
CodeSourceNone = 0, //!< Do not use python code at all
318+
CodeSourceFile = 1, //!< Load the python code from an external file
319+
CodeSourceDialog = 2, //!< Use the python code provided in the dialog
320+
CodeSourceEnvironment = 3 //!< Use the python code available in the python environment
321+
};
322+
311323
/**
312324
* This is only useful in combination with EditorLayout::TabLayout.
313325
*
@@ -459,17 +471,7 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
459471
void setLabelOnTop( int idx, bool onTop );
460472

461473

462-
463-
464-
465-
466-
467-
468-
469-
470-
471-
// Python stuff
472-
474+
// Python form init function stuff
473475

474476
/**
475477
* Get python function for edit form initialization.
@@ -490,20 +492,35 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
490492
/**
491493
* Get python code for edit form initialization.
492494
*/
493-
QString initCode() const { return mEditFormInitCode; }
495+
QString initCode() const { return mInitCode; }
494496

495497
/**
496-
* Get python code for edit form initialization.
498+
* Set python code for edit form initialization.
497499
* Make sure that you also set the appropriate function name in
498500
* @link setInitFunction @endlink
499501
*/
500-
void setInitCode( const QString& code ) { mEditFormInitCode = code; }
502+
void setInitCode( const QString& code ) { mInitCode = code; }
503+
504+
/**
505+
* Get python external file path for edit form initialization.
506+
*/
507+
QString initFilePath() const { return mInitFilePath; }
501508

502-
/** Return if python code shall be loaded for edit form initialization */
503-
bool useInitCode() const { return mUseInitCode; }
509+
/**
510+
* Set python external file path for edit form initialization.
511+
* Make sure that you also set the appropriate function name in
512+
* @link setInitFunction @endlink
513+
*/
514+
void setInitFilePath( const QString& filePath ) { mInitFilePath = filePath; }
515+
516+
/** Return python code source for edit form initialization
517+
* (if it shall be loaded from a file, read from the
518+
* provided dialog editor or inherited from the environment)
519+
*/
520+
PythonInitCodeSource initCodeSource() const { return mInitCodeSource; }
504521

505-
/** Set if python code shall be used for edit form initialization */
506-
void setUseInitCode( const bool useCode ) { mUseInitCode = useCode; }
522+
/** Set if python code shall be used for edit form initialization and its origin */
523+
void setInitCodeSource( const PythonInitCodeSource initCodeSource ) { mInitCodeSource = initCodeSource; }
507524

508525
/** Type of feature form pop-up suppression after feature creation (overrides app setting) */
509526
FeatureFormSuppress suppress() const { return mFeatureFormSuppress; }
@@ -547,9 +564,16 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
547564
/** Defines the default layout to use for the attribute editor (Drag and drop, UI File, Generated) */
548565
EditorLayout mEditorLayout;
549566

567+
/** Init form instance */
550568
QString mEditForm;
569+
/** Name of the python form init function */
551570
QString mInitFunction;
552-
QString mEditFormInitCode;
571+
/** Path of the python external file to be loaded */
572+
QString mInitFilePath;
573+
/** Choose the source of the init founction */
574+
PythonInitCodeSource mInitCodeSource;
575+
/** Python init code provided in the dialog */
576+
QString mInitCode;
553577

554578
/** Type of feature form suppression after feature creation */
555579
FeatureFormSuppress mFeatureFormSuppress;

‎src/core/qgsvectorlayer.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,16 +1780,37 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
17801780
mEditFormConfig->setInitFunction( editFormInitNode.toElement().text() );
17811781
}
17821782

1783+
QDomNode editFormInitCodeSourceNode = node.namedItem( "editforminitcodesource" );
1784+
if ( !editFormInitCodeSourceNode.isNull() || ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() ) )
1785+
{
1786+
mEditFormConfig->setInitCodeSource(( QgsEditFormConfig::PythonInitCodeSource ) editFormInitCodeSourceNode.toElement().text().toInt() );
1787+
}
1788+
17831789
QDomNode editFormInitCodeNode = node.namedItem( "editforminitcode" );
17841790
if ( !editFormInitCodeNode.isNull() )
17851791
{
17861792
mEditFormConfig->setInitCode( editFormInitCodeNode.toElement().text() );
17871793
}
17881794

1789-
QDomNode editFormInitUseCodeNode = node.namedItem( "editforminitusecode" );
1790-
if ( !editFormInitCodeNode.isNull() || ( !editFormInitNode.isNull() && !editFormInitNode.toElement().text().isEmpty() ) )
1795+
// Temporary < 2.12 b/w compatibility "dot" support patch
1796+
// @see: https://github.com/qgis/QGIS/pull/2498
1797+
// For b/w compatibility, check if there's a dot in the function name
1798+
// and if yes, transform it in an import statement for the module
1799+
// and set the PythonInitCodeSource to CodeSourceDialog
1800+
QString initFunction = mEditFormConfig->initFunction();
1801+
int dotPos = initFunction.lastIndexOf( '.' );
1802+
if ( dotPos >= 0 ) // It's a module
17911803
{
1792-
mEditFormConfig->setUseInitCode( editFormInitUseCodeNode.toElement().text().toInt() );
1804+
mEditFormConfig->setInitCodeSource( QgsEditFormConfig::PythonInitCodeSource::CodeSourceDialog );
1805+
mEditFormConfig->setInitFunction( initFunction.mid( dotPos + 1 ) );
1806+
mEditFormConfig->setInitCode( QString( "from %1 import %2\n" ).arg( initFunction.left( dotPos ), initFunction.mid( dotPos + 1 ) ) );
1807+
}
1808+
1809+
1810+
QDomNode editFormInitFilePathNode = node.namedItem( "editforminitfilepath" );
1811+
if ( !editFormInitFilePathNode.isNull() || ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() ) )
1812+
{
1813+
mEditFormConfig->setInitFilePath( editFormInitFilePathNode.toElement().text() );
17931814
}
17941815

17951816
QDomNode fFSuppNode = node.namedItem( "featformsuppress" );
@@ -2054,9 +2075,14 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
20542075
efiField.appendChild( doc.createTextNode( mEditFormConfig->initFunction() ) );
20552076
node.appendChild( efiField );
20562077

2057-
QDomElement efiucField = doc.createElement( "editforminitusecode" );
2058-
efiucField.appendChild( doc.createTextNode( mEditFormConfig->useInitCode() ? "1" : "0" ) );
2059-
node.appendChild( efiucField );
2078+
QDomElement eficsField = doc.createElement( "editforminitcodesource" );
2079+
eficsField.appendChild( doc.createTextNode( QString::number( mEditFormConfig->initCodeSource() ) ) );
2080+
node.appendChild( eficsField );
2081+
2082+
QDomElement efifpField = doc.createElement( "editforminitfilepath" );
2083+
efifpField.appendChild( doc.createTextNode( QgsProject::instance()->writePath( mEditFormConfig->initFilePath() ) ) );
2084+
node.appendChild( efifpField );
2085+
20602086

20612087
QDomElement eficField = doc.createElement( "editforminitcode" );
20622088
eficField.appendChild( doc.createCDATASection( mEditFormConfig->initCode() ) );

‎src/gui/qgsattributeform.cpp

Lines changed: 85 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#include "qgsvectordataprovider.h"
2626

2727
#include <QDir>
28+
#include <QTextStream>
2829
#include <QFileInfo>
30+
#include <QFile>
2931
#include <QFormLayout>
3032
#include <QGridLayout>
3133
#include <QGroupBox>
@@ -35,6 +37,7 @@
3537
#include <QScrollArea>
3638
#include <QTabWidget>
3739
#include <QUiLoader>
40+
#include <QMessageBox>
3841

3942
int QgsAttributeForm::sFormCounter = 0;
4043

@@ -574,64 +577,106 @@ void QgsAttributeForm::initPython()
574577
{
575578
cleanPython();
576579

577-
// Init Python
578-
if ( !mLayer->editFormConfig()->initFunction().isEmpty() )
580+
// Init Python, if init function is not empty and the combo indicates
581+
// the source for the function code
582+
if ( !mLayer->editFormConfig()->initFunction().isEmpty()
583+
&& mLayer->editFormConfig()->initCodeSource() != QgsEditFormConfig::PythonInitCodeSource::CodeSourceNone )
579584
{
580-
QString module = mLayer->editFormConfig()->initFunction();
581585

582-
int pos = module.lastIndexOf( '.' );
586+
QString initFunction = mLayer->editFormConfig()->initFunction();
587+
QString initFilePath = mLayer->editFormConfig()->initFilePath();
588+
QString initCode;
583589

584-
if ( pos >= 0 ) // It's a module
590+
switch ( mLayer->editFormConfig()->initCodeSource() )
585591
{
586-
QgsPythonRunner::run( QString( "import %1" ).arg( module.left( pos ) ) );
587-
/* Reload the module if the DEBUGMODE switch has been set in the module.
588-
If set to False you have to reload QGIS to reset it to True due to Python
589-
module caching */
590-
QString reload = QString( "if hasattr(%1,'DEBUGMODE') and %1.DEBUGMODE:"
591-
" reload(%1)" ).arg( module.left( pos ) );
592-
593-
QgsPythonRunner::run( reload );
594-
}
595-
else if ( mLayer->editFormConfig()->useInitCode() ) // Must be supplied code
596-
{
597-
QgsPythonRunner::run( mLayer->editFormConfig()->initCode() );
592+
case QgsEditFormConfig::PythonInitCodeSource::CodeSourceFile:
593+
if ( ! initFilePath.isEmpty() )
594+
{
595+
QFile inputFile( initFilePath );
596+
597+
if ( inputFile.open( QFile::ReadOnly ) )
598+
{
599+
// Read it into a string
600+
QTextStream inf( &inputFile );
601+
initCode = inf.readAll();
602+
inputFile.close();
603+
}
604+
else // The file couldn't be opened
605+
{
606+
QgsLogger::warning( QString( "The external python file path %1 could not be opened!" ).arg( initFilePath ) );
607+
}
608+
}
609+
else
610+
{
611+
QgsLogger::warning( QString( "The external python file path is empty!" ) );
612+
}
613+
break;
614+
615+
case( QgsEditFormConfig::PythonInitCodeSource::CodeSourceDialog ):
616+
initCode = mLayer->editFormConfig()->initCode();
617+
if ( initCode.isEmpty() )
618+
{
619+
QgsLogger::warning( QString( "The python code provided in the dialog is empty!" ) );
620+
}
621+
break;
622+
623+
case( QgsEditFormConfig::PythonInitCodeSource::CodeSourceEnvironment ):
624+
case( QgsEditFormConfig::PythonInitCodeSource::CodeSourceNone ):
625+
default:
626+
// Nothing to do: the function code should be already in the environment
627+
break;
598628
}
599-
else
629+
630+
// If we have a function code, run it
631+
if ( ! initCode.isEmpty() )
600632
{
601-
QgsDebugMsg( "No dot in editFormInit and no custom python code provided! There is nothing to run." );
633+
QgsPythonRunner::run( initCode );
602634
}
603635

604-
605636
QgsPythonRunner::run( "import inspect" );
606637
QString numArgs;
607-
QgsPythonRunner::eval( QString( "len(inspect.getargspec(%1)[0])" ).arg( module ), numArgs );
608638

609-
static int sFormId = 0;
610-
mPyFormVarName = QString( "_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
639+
// Check for eval result
640+
if ( QgsPythonRunner::eval( QString( "len(inspect.getargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
641+
{
642+
static int sFormId = 0;
643+
mPyFormVarName = QString( "_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
611644

612-
QString form = QString( "%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
613-
.arg( mPyFormVarName )
614-
.arg(( unsigned long ) this );
645+
QString form = QString( "%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
646+
.arg( mPyFormVarName )
647+
.arg(( unsigned long ) this );
615648

616-
QgsPythonRunner::run( form );
649+
QgsPythonRunner::run( form );
617650

618-
QgsDebugMsg( QString( "running featureForm init: %1" ).arg( mPyFormVarName ) );
651+
QgsDebugMsg( QString( "running featureForm init: %1" ).arg( mPyFormVarName ) );
619652

620-
// Legacy
621-
if ( numArgs == "3" )
622-
{
623-
addInterface( new QgsAttributeFormLegacyInterface( module, mPyFormVarName, this ) );
653+
// Legacy
654+
if ( numArgs == "3" )
655+
{
656+
addInterface( new QgsAttributeFormLegacyInterface( initFunction, mPyFormVarName, this ) );
657+
}
658+
else
659+
{
660+
// If we get here, it means that the function doesn't accept three arguments
661+
QMessageBox msgBox;
662+
msgBox.setText( tr( "The python init function (<code>%1</code>) does not accept three arguments as expected!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
663+
msgBox.exec();
664+
#if 0
665+
QString expr = QString( "%1(%2)" )
666+
.arg( mLayer->editFormInit() )
667+
.arg( mPyFormVarName );
668+
QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr, "QgsAttributeFormInterface" );
669+
if ( iface )
670+
addInterface( iface );
671+
#endif
672+
}
624673
}
625674
else
626675
{
627-
#if 0
628-
QString expr = QString( "%1(%2)" )
629-
.arg( mLayer->editFormInit() )
630-
.arg( mPyFormVarName );
631-
QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr, "QgsAttributeFormInterface" );
632-
if ( iface )
633-
addInterface( iface );
634-
#endif
676+
// If we get here, it means that inspect couldn't find the function
677+
QMessageBox msgBox;
678+
msgBox.setText( tr( "The python init function (<code>%1</code>) could not be found!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
679+
msgBox.exec();
635680
}
636681
}
637682
}

‎src/ui/qgsfieldspropertiesbase.ui

Lines changed: 139 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>965</width>
10-
<height>634</height>
9+
<width>614</width>
10+
<height>423</height>
1111
</rect>
1212
</property>
1313
<layout class="QGridLayout" name="gridLayout_6">
14-
<item row="1" column="0" colspan="7">
14+
<item row="0" column="0">
1515
<layout class="QHBoxLayout" name="horizontalLayout_3">
1616
<item>
1717
<widget class="QLabel" name="label_2">
@@ -66,71 +66,114 @@
6666
<property name="toolTip">
6767
<string>QGIS forms can have a Python function that is called when the form is opened.
6868
Use this function to add extra logic to your forms.
69+
The function code of the function can be loaded from the source code entered
70+
in this dialog, from an external python file or from the environment (for example
71+
from a plugin or from startup.py).
6972

70-
An example is (in module MyForms.py):
73+
An example is:
7174

72-
def open(dialog, layer, feature):
75+
from PyQt4.QtGui import QWidget
76+
77+
def my_form_open(dialog, layer, feature):
7378
geom = feature.geometry()
7479
control = dialog.findChild(QWidget,&quot;MyLineEdit&quot;)
7580

76-
Reference in Python Init Function like so: MyForms.open
81+
Reference in function name: my_form_open
7782

78-
MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.</string>
83+
</string>
7984
</property>
8085
<property name="text">
8186
<string>Python Init function</string>
8287
</property>
8388
</widget>
8489
</item>
8590
<item>
86-
<widget class="QLineEdit" name="leEditFormInit">
91+
<widget class="QComboBox" name="mInitCodeSourceComboBox">
8792
<property name="toolTip">
8893
<string>QGIS forms can have a Python function that is called when the form is opened.
89-
Use this function to add extra logic to your forms. You can either provide the python
90-
code directly in this dialog or run the code from an external file (that must live on
91-
PYTHONPATH, .qgis/python, or inside the project folder).
94+
Use this function to add extra logic to your forms.
95+
The function code of the function can be loaded from the source code entered
96+
in this dialog, from an external python file or from the environment (for example
97+
from a plugin or from startup.py).
98+
99+
An example is:
92100

93-
An example is (in module MyForms.py):
101+
from PyQt4.QtGui import QWidget
94102

95-
def open(dialog, layer, feature):
103+
def my_form_open(dialog, layer, feature):
96104
geom = feature.geometry()
97105
control = dialog.findChild(QWidget,&quot;MyLineEdit&quot;)
98106

99-
Reference in Python Init Function like so: &quot;MyForms.open&quot; or just &quot;open&quot; if provided
100-
directly in this dialog.
101-
107+
Reference in function name: my_form_open
102108

103109
</string>
104110
</property>
105111
</widget>
106112
</item>
113+
</layout>
114+
</item>
115+
<item row="3" column="0">
116+
<layout class="QHBoxLayout" name="horizontalLayout">
107117
<item>
108-
<spacer name="horizontalSpacer_3">
109-
<property name="orientation">
110-
<enum>Qt::Horizontal</enum>
118+
<widget class="QLabel" name="mFormSuppressLabel">
119+
<property name="sizePolicy">
120+
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
121+
<horstretch>0</horstretch>
122+
<verstretch>0</verstretch>
123+
</sizepolicy>
111124
</property>
112-
<property name="sizeHint" stdset="0">
125+
<property name="minimumSize">
113126
<size>
114-
<width>40</width>
115-
<height>20</height>
127+
<width>150</width>
128+
<height>0</height>
116129
</size>
117130
</property>
118-
</spacer>
131+
<property name="text">
132+
<string>Suppress attribute form pop-up after feature creation</string>
133+
</property>
134+
<property name="alignment">
135+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
136+
</property>
137+
<property name="wordWrap">
138+
<bool>true</bool>
139+
</property>
140+
</widget>
119141
</item>
120142
<item>
121-
<widget class="QCheckBox" name="leEditFormInitUseCode">
122-
<property name="toolTip">
123-
<string>Check this box to provide python init function code here instead of using an external file.</string>
124-
</property>
125-
<property name="text">
126-
<string>Use provided code</string>
143+
<widget class="QComboBox" name="mFormSuppressCmbBx">
144+
<property name="sizePolicy">
145+
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
146+
<horstretch>0</horstretch>
147+
<verstretch>0</verstretch>
148+
</sizepolicy>
127149
</property>
150+
<item>
151+
<property name="text">
152+
<string>Default</string>
153+
</property>
154+
</item>
155+
<item>
156+
<property name="text">
157+
<string>On</string>
158+
</property>
159+
</item>
160+
<item>
161+
<property name="text">
162+
<string>Off</string>
163+
</property>
164+
</item>
128165
</widget>
129166
</item>
130167
</layout>
131168
</item>
132-
<item row="2" column="0" colspan="7">
169+
<item row="2" column="0">
133170
<widget class="QSplitter" name="mSplitter">
171+
<property name="sizePolicy">
172+
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
173+
<horstretch>0</horstretch>
174+
<verstretch>0</verstretch>
175+
</sizepolicy>
176+
</property>
134177
<property name="orientation">
135178
<enum>Qt::Horizontal</enum>
136179
</property>
@@ -164,7 +207,7 @@ directly in this dialog.
164207
</property>
165208
<property name="icon">
166209
<iconset>
167-
<normaloff>.designer/xpm/delete_attribute.png</normaloff>.designer/xpm/delete_attribute.png</iconset>
210+
<normaloff>../../../../.designer/backup/.designer/xpm/delete_attribute.png</normaloff>../../../../.designer/backup/.designer/xpm/delete_attribute.png</iconset>
168211
</property>
169212
<property name="shortcut">
170213
<string>Ctrl+X</string>
@@ -219,7 +262,7 @@ directly in this dialog.
219262
</property>
220263
<property name="icon">
221264
<iconset>
222-
<normaloff>.designer/xpm/new_attribute.png</normaloff>.designer/xpm/new_attribute.png</iconset>
265+
<normaloff>../../../../.designer/backup/.designer/xpm/new_attribute.png</normaloff>../../../../.designer/backup/.designer/xpm/new_attribute.png</iconset>
223266
</property>
224267
<property name="shortcut">
225268
<string>Ctrl+N</string>
@@ -264,7 +307,7 @@ directly in this dialog.
264307
</property>
265308
<layout class="QGridLayout" name="gridLayout">
266309
<item row="0" column="0">
267-
<widget class="QgsCodeEditorPython" name="leEditFormInitCode" native="true"/>
310+
<widget class="QgsCodeEditorPython" name="mInitCodeEditorPython" native="true"/>
268311
</item>
269312
</layout>
270313
</widget>
@@ -293,7 +336,7 @@ directly in this dialog.
293336
<item row="0" column="1">
294337
<layout class="QHBoxLayout" name="horizontalLayout_2">
295338
<item>
296-
<widget class="QLineEdit" name="leEditForm"/>
339+
<widget class="QLineEdit" name="mEditFormLineEdit"/>
297340
</item>
298341
<item>
299342
<widget class="QToolButton" name="pbnSelectEditForm">
@@ -486,59 +529,73 @@ directly in this dialog.
486529
</widget>
487530
</widget>
488531
</item>
489-
<item row="3" column="0" colspan="7">
490-
<layout class="QHBoxLayout" name="horizontalLayout">
491-
<item>
492-
<widget class="QLabel" name="mFormSuppressLabel">
493-
<property name="sizePolicy">
494-
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
495-
<horstretch>0</horstretch>
496-
<verstretch>0</verstretch>
497-
</sizepolicy>
498-
</property>
499-
<property name="minimumSize">
500-
<size>
501-
<width>150</width>
502-
<height>0</height>
503-
</size>
504-
</property>
505-
<property name="text">
506-
<string>Suppress attribute form pop-up after feature creation</string>
507-
</property>
508-
<property name="alignment">
509-
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
510-
</property>
511-
<property name="wordWrap">
512-
<bool>true</bool>
513-
</property>
514-
</widget>
515-
</item>
516-
<item>
517-
<widget class="QComboBox" name="mFormSuppressCmbBx">
518-
<property name="sizePolicy">
519-
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
520-
<horstretch>0</horstretch>
521-
<verstretch>0</verstretch>
522-
</sizepolicy>
523-
</property>
524-
<item>
532+
<item row="1" column="0">
533+
<widget class="QWidget" name="mInitFunctionContainer" native="true">
534+
<property name="sizePolicy">
535+
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
536+
<horstretch>0</horstretch>
537+
<verstretch>0</verstretch>
538+
</sizepolicy>
539+
</property>
540+
<layout class="QHBoxLayout" name="horizontalLayout_4">
541+
<property name="leftMargin">
542+
<number>0</number>
543+
</property>
544+
<property name="topMargin">
545+
<number>0</number>
546+
</property>
547+
<property name="rightMargin">
548+
<number>0</number>
549+
</property>
550+
<property name="bottomMargin">
551+
<number>0</number>
552+
</property>
553+
<item>
554+
<widget class="QLabel" name="mInitFunctionLabel">
525555
<property name="text">
526-
<string>Default</string>
556+
<string>Function name</string>
527557
</property>
528-
</item>
529-
<item>
558+
</widget>
559+
</item>
560+
<item>
561+
<widget class="QLineEdit" name="mInitFunctionLineEdit">
562+
<property name="toolTip">
563+
<string>Enter the name of the form init function.</string>
564+
</property>
565+
</widget>
566+
</item>
567+
<item>
568+
<widget class="QLabel" name="mInitFilePathLabel">
530569
<property name="text">
531-
<string>On</string>
570+
<string>External file</string>
532571
</property>
533-
</item>
534-
<item>
572+
</widget>
573+
</item>
574+
<item>
575+
<widget class="QLineEdit" name="mInitFilePathLineEdit"/>
576+
</item>
577+
<item>
578+
<widget class="QToolButton" name="pbtnSelectInitFilePath">
535579
<property name="text">
536-
<string>Off</string>
580+
<string>...</string>
537581
</property>
538-
</item>
539-
</widget>
540-
</item>
541-
</layout>
582+
</widget>
583+
</item>
584+
<item>
585+
<spacer name="horizontalSpacer_4">
586+
<property name="orientation">
587+
<enum>Qt::Horizontal</enum>
588+
</property>
589+
<property name="sizeHint" stdset="0">
590+
<size>
591+
<width>0</width>
592+
<height>0</height>
593+
</size>
594+
</property>
595+
</spacer>
596+
</item>
597+
</layout>
598+
</widget>
542599
</item>
543600
</layout>
544601
</widget>
@@ -558,12 +615,11 @@ directly in this dialog.
558615
</customwidgets>
559616
<tabstops>
560617
<tabstop>mEditorLayoutComboBox</tabstop>
561-
<tabstop>leEditFormInit</tabstop>
562618
<tabstop>mAddAttributeButton</tabstop>
563619
<tabstop>mDeleteAttributeButton</tabstop>
564620
<tabstop>mToggleEditingButton</tabstop>
565621
<tabstop>mCalculateFieldButton</tabstop>
566-
<tabstop>leEditForm</tabstop>
622+
<tabstop>mEditFormLineEdit</tabstop>
567623
<tabstop>pbnSelectEditForm</tabstop>
568624
<tabstop>mAddTabOrGroupButton</tabstop>
569625
<tabstop>mRemoveTabGroupItemButton</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.