[gui] Introduce dialog to add function files, allowing users to choose whether to store functions in a .py file (current behavior) or in the QGIS project

This commit is contained in:
Germán Carrillo 2024-05-30 16:03:36 -05:00
parent 72da31baa5
commit 37724a6d1a
6 changed files with 306 additions and 11 deletions

View File

@ -588,6 +588,7 @@ set(QGIS_GUI_SRCS
qgsdockwidget.cpp
qgsencodingfiledialog.cpp
qgserrordialog.cpp
qgsexpressionaddfunctionfiledialog.cpp
qgsexpressionbuilderdialog.cpp
qgsexpressionbuilderwidget.cpp
qgsexpressionfinder.cpp
@ -852,6 +853,7 @@ set(QGIS_GUI_HDRS
qgsdoublevalidator.h
qgsencodingfiledialog.h
qgserrordialog.h
qgsexpressionaddfunctionfiledialog.h
qgsexpressionbuilderdialog.h
qgsexpressionstoredialog.h
qgsexpressionbuilderwidget.h

View File

@ -0,0 +1,58 @@
/***************************************************************************
qgsexpressionaddfunctionfiledialog.cpp
---------------------
begin : May 2024
copyright : (C) 2024 by Germán Carrillo
email : german at opengis dot ch
***************************************************************************
* *
* 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 <QPushButton>
#include <QStandardItemModel>
#include "qgsexpressionaddfunctionfiledialog.h"
QgsExpressionAddFunctionFileDialog::QgsExpressionAddFunctionFileDialog( const bool enableProjectFunctions, QWidget *parent )
: QDialog( parent )
{
setupUi( this );
cboFileOptions->addItem( QStringLiteral( "Function file" ) );
cboFileOptions->addItem( QStringLiteral( "Project functions" ), QStringLiteral( "project" ) );
// Disable project functions (they should be created only once)
if ( !enableProjectFunctions )
{
QStandardItem *item = qobject_cast<QStandardItemModel *>( cboFileOptions->model() )->item( 1 );
item->setFlags( item->flags() & ~Qt::ItemIsEnabled );
}
connect( cboFileOptions, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsExpressionAddFunctionFileDialog::cboFileOptions_currentIndexChanged );
connect( txtNewFileName, &QLineEdit::textChanged, this, [ = ]( const QString & ) { updateOkButtonStatus(); } );
updateOkButtonStatus();
}
void QgsExpressionAddFunctionFileDialog::cboFileOptions_currentIndexChanged( int )
{
bool projectSelected = cboFileOptions->currentData() == "project";
lblNewFileName->setVisible( !projectSelected );
txtNewFileName->setVisible( !projectSelected );
updateOkButtonStatus();
}
void QgsExpressionAddFunctionFileDialog::updateOkButtonStatus()
{
QPushButton *okBtn = buttonBox->button( QDialogButtonBox::StandardButton::Ok );
okBtn->setEnabled( true );
if ( cboFileOptions->currentData() != "project" )
{
okBtn->setEnabled( !txtNewFileName->text().trimmed().isEmpty() );
}
}

View File

@ -0,0 +1,52 @@
/***************************************************************************
qgsexpressionaddfunctionfiledialog.h
---------------------
begin : May 2024
copyright : (C) 2024 by Germán Carrillo
email : german at opengis dot ch
***************************************************************************
* *
* 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 QGSEXPRESSIONADDFUNCTIONFILEDIALOG_H
#define QGSEXPRESSIONADDFUNCTIONFILEDIALOG_H
#include "qgis_gui.h"
#include <QDialog>
#include "ui_qgsexpressionaddfunctionfiledialogbase.h"
/**
* \ingroup gui
* \brief A dialog to select whether to create a function file or project functions.
* \since QGIS 3.40
*/
class GUI_EXPORT QgsExpressionAddFunctionFileDialog : public QDialog, private Ui::QgsExpressionAddFunctionFileDialogBase
{
Q_OBJECT
public:
QgsExpressionAddFunctionFileDialog( const bool enableProjectFunctions, QWidget *parent );
/**
* Returns whether user has selected to create project functions
*/
bool createProjectFunctions() const {return cboFileOptions->currentData() == "project";};
/**
* Returns the new file name
*/
QString fileName() {return txtNewFileName->text().trimmed();};
private slots:
void cboFileOptions_currentIndexChanged( int );
private:
void updateOkButtonStatus();
};
#endif // QGSEXPRESSIONADDFUNCTIONFILEDIALOG_H

View File

@ -17,7 +17,6 @@
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QInputDialog>
#include <QComboBox>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
@ -49,6 +48,7 @@
#include "qgsexpressionstoredialog.h"
#include "qgsexpressiontreeview.h"
#include "qgscodeeditorwidget.h"
#include "qgsexpressionaddfunctionfiledialog.h"
bool formatterCanProvideAvailableValues( QgsVectorLayer *layer, const QString &fieldName )
@ -428,7 +428,7 @@ void QgsExpressionBuilderWidget::updateFunctionFileList( const QString &path )
mProject->readEntry( QStringLiteral( "ExpressionFunctions" ), QStringLiteral( "/pythonCode" ), QString(), &ok );
if ( ok )
{
QListWidgetItem *item = new QListWidgetItem( QgsApplication::getThemeIcon( QStringLiteral( "console/iconTabEditorConsole.svg" ) ), DEFAULT_PROJECT_FUNCTIONS_ITEM_NAME );
QListWidgetItem *item = new QListWidgetItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconQgsProjectFile.svg" ) ), DEFAULT_PROJECT_FUNCTIONS_ITEM_NAME );
item->setData( Qt::UserRole, QStringLiteral( "project" ) );
cmbFileNames->insertItem( 0, item );
}
@ -466,15 +466,19 @@ void QgsExpressionBuilderWidget::newFunctionFile( const QString &fileName )
void QgsExpressionBuilderWidget::btnNewFile_pressed()
{
bool ok;
QString text = QInputDialog::getText( this, tr( "New File" ),
tr( "New file name:" ), QLineEdit::Normal,
QString(), &ok );
if ( ok && !text.isEmpty() )
// If a project has an entry for functions, then we should
// already have a 'Project functions' item in the file list.
// Since only one item should correspond to 'Project functions',
// we'll disable this option in the 'add function file' dialog.
bool ok = false;
mProject->readEntry( QStringLiteral( "ExpressionFunctions" ), QStringLiteral( "/pythonCode" ), QString(), &ok );
QgsExpressionAddFunctionFileDialog dlg {!ok, this};
if ( dlg.exec() == QDialog::DialogCode::Accepted )
{
if ( text.contains( QStringLiteral( "project" ) ) )
if ( dlg.createProjectFunctions() )
{
QListWidgetItem *item = new QListWidgetItem( QgsApplication::getThemeIcon( QStringLiteral( "console/iconTabEditorConsole.svg" ) ), DEFAULT_PROJECT_FUNCTIONS_ITEM_NAME );
QListWidgetItem *item = new QListWidgetItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconQgsProjectFile.svg" ) ), DEFAULT_PROJECT_FUNCTIONS_ITEM_NAME );
item->setData( Qt::UserRole, QStringLiteral( "project" ) );
cmbFileNames->insertItem( 0, item );
cmbFileNames->setCurrentRow( 0 );
@ -486,9 +490,8 @@ void QgsExpressionBuilderWidget::btnNewFile_pressed()
}
else
{
newFunctionFile( text );
newFunctionFile( dlg.fileName() );
}
btnRemoveFile->setEnabled( cmbFileNames->count() > 0 );
}
}

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsExpressionAddFunctionFileDialogBase</class>
<widget class="QDialog" name="QgsExpressionAddFunctionFileDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>265</width>
<height>135</height>
</rect>
</property>
<property name="windowTitle">
<string>Add Function File</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtNewFileName"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cboFileOptions"/>
</item>
<item row="2" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblNewFileName">
<property name="text">
<string>File name</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsExpressionAddFunctionFileDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsExpressionAddFunctionFileDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,96 @@
/********************************************************************************
** Form generated from reading UI file 'qgsexpressionaddfunctionfiledialogbase.ui'
**
** Created by: Qt User Interface Compiler version 5.15.3
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef QGSEXPRESSIONADDFUNCTIONFILEDIALOGBASE_H
#define QGSEXPRESSIONADDFUNCTIONFILEDIALOGBASE_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialog>
#include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
QT_BEGIN_NAMESPACE
class Ui_QgsAddFunctionFileDialogBase
{
public:
QGridLayout *gridLayout;
QLabel *label;
QComboBox *cboFileOptions;
QLabel *lblNewFileName;
QDialogButtonBox *buttonBox;
QLineEdit *txtNewFileName;
void setupUi( QDialog *QgsAddFunctionFileDialogBase )
{
if ( QgsAddFunctionFileDialogBase->objectName().isEmpty() )
QgsAddFunctionFileDialogBase->setObjectName( QString::fromUtf8( "QgsAddFunctionFileDialogBase" ) );
QgsAddFunctionFileDialogBase->resize( 277, 132 );
gridLayout = new QGridLayout( QgsAddFunctionFileDialogBase );
gridLayout->setObjectName( QString::fromUtf8( "gridLayout" ) );
label = new QLabel( QgsAddFunctionFileDialogBase );
label->setObjectName( QString::fromUtf8( "label" ) );
gridLayout->addWidget( label, 0, 0, 1, 1 );
cboFileOptions = new QComboBox( QgsAddFunctionFileDialogBase );
cboFileOptions->addItem( QString() );
cboFileOptions->addItem( QString() );
cboFileOptions->setObjectName( QString::fromUtf8( "cboFileOptions" ) );
gridLayout->addWidget( cboFileOptions, 0, 1, 1, 1 );
lblNewFileName = new QLabel( QgsAddFunctionFileDialogBase );
lblNewFileName->setObjectName( QString::fromUtf8( "lblNewFileName" ) );
gridLayout->addWidget( lblNewFileName, 1, 0, 1, 1 );
buttonBox = new QDialogButtonBox( QgsAddFunctionFileDialogBase );
buttonBox->setObjectName( QString::fromUtf8( "buttonBox" ) );
buttonBox->setOrientation( Qt::Horizontal );
buttonBox->setStandardButtons( QDialogButtonBox::Cancel | QDialogButtonBox::Ok );
gridLayout->addWidget( buttonBox, 2, 0, 1, 2 );
txtNewFileName = new QLineEdit( QgsAddFunctionFileDialogBase );
txtNewFileName->setObjectName( QString::fromUtf8( "txtNewFileName" ) );
gridLayout->addWidget( txtNewFileName, 1, 1, 1, 1 );
retranslateUi( QgsAddFunctionFileDialogBase );
QObject::connect( buttonBox, SIGNAL( accepted() ), QgsAddFunctionFileDialogBase, SLOT( accept() ) );
QObject::connect( buttonBox, SIGNAL( rejected() ), QgsAddFunctionFileDialogBase, SLOT( reject() ) );
QMetaObject::connectSlotsByName( QgsAddFunctionFileDialogBase );
} // setupUi
void retranslateUi( QDialog *QgsAddFunctionFileDialogBase )
{
QgsAddFunctionFileDialogBase->setWindowTitle( QCoreApplication::translate( "QgsAddFunctionFileDialogBase", "Add Function File", nullptr ) );
label->setText( QCoreApplication::translate( "QgsAddFunctionFileDialogBase", "Create", nullptr ) );
cboFileOptions->setItemText( 0, QCoreApplication::translate( "QgsAddFunctionFileDialogBase", "Function file", nullptr ) );
cboFileOptions->setItemText( 1, QCoreApplication::translate( "QgsAddFunctionFileDialogBase", "Project functions", nullptr ) );
lblNewFileName->setText( QCoreApplication::translate( "QgsAddFunctionFileDialogBase", "File name", nullptr ) );
} // retranslateUi
};
namespace Ui
{
class QgsAddFunctionFileDialogBase: public Ui_QgsAddFunctionFileDialogBase {};
} // namespace Ui
QT_END_NAMESPACE
#endif // QGSEXPRESSIONADDFUNCTIONFILEDIALOGBASE_H