Skip to content
Permalink
Browse files

[Expressions] Redesign expression function editor.

Add auto save
  • Loading branch information
NathanW2 committed Nov 4, 2015
1 parent 90a82ba commit 8c86aab0f4dd332b2c79aa1d038a69cbb08a91e3
@@ -165,22 +165,29 @@ class QgsExpressionBuilderWidget : QWidget
void updateFunctionFileList( const QString& path );

public slots:
void currentChanged( const QModelIndex &index, const QModelIndex & );
void on_btnRun_pressed();
void on_btnNewFile_pressed();
void on_cmbFileNames_currentIndexChanged( int index );
void on_btnSaveFile_pressed();
void on_expressionTree_doubleClicked( const QModelIndex &index );
void on_txtExpressionString_textChanged();
void on_txtSearchEdit_textChanged();
void on_txtSearchEditValues_textChanged();
void on_lblPreview_linkActivated( const QString& link );
void on_mValuesListView_doubleClicked( const QModelIndex &index );
void operatorButtonClicked();
void showContextMenu( const QPoint & );

/**
* Load sample values into the sample value area
*/
void loadSampleValues();

/**
* Load all unique values from the set layer into the sample area
*/
void loadAllValues();

/**
* Auto save the current Python function code.
*/
void autosave();

/**
* Enabled or disable auto saving. When enabled Python scripts will be auto saved
* when text changes.
* @param enabled True to enable auto saving.
*/
void setAutoSave( bool enabled );

signals:
/** Emitted when the user changes the expression in the widget.
* Users of this widget should connect to this signal to decide if to let the user
@@ -127,7 +127,7 @@ bool QgsCodeEditorPython::loadScript( const QString &script )

QTextStream in( &file );

setText( in.readAll() );
setText( in.readAll().trimmed() );
file.close();

setSciLexerPython();
@@ -27,12 +27,16 @@
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QInputDialog>
#include <QComboBox>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>



QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
: QWidget( parent )
, mAutoSave( true )
, mLayer( NULL )
, highlighter( NULL )
, mExpressionValid( false )
@@ -75,6 +79,7 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )

QSettings settings;
splitter->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/splitter" ).toByteArray() );
editorSplit->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/editorsplitter" ).toByteArray() );
functionsplit->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/functionsplitter" ).toByteArray() );

txtExpressionString->setFoldingVisible( false );
@@ -84,27 +89,27 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
if ( QgsPythonRunner::isValid() )
{
QgsPythonRunner::eval( "qgis.user.expressionspath", mFunctionsPath );
newFunctionFile();
// The scratch file gets written each time the widget opens.
saveFunctionFile( "scratch" );
updateFunctionFileList( mFunctionsPath );
}
else
{
tab_2->setEnabled( false );
tab_2->hide();
}

// select the first item in the function list
// in order to avoid a blank help widget
QModelIndex firstItem = mProxyModel->index( 0, 0, QModelIndex() );
expressionTree->setCurrentIndex( firstItem );

lblAutoSave->setText("");
}


QgsExpressionBuilderWidget::~QgsExpressionBuilderWidget()
{
QSettings settings;
settings.setValue( "/windows/QgsExpressionBuilderWidget/splitter", splitter->saveState() );
settings.setValue( "/windows/QgsExpressionBuilderWidget/editorsplitter", editorSplit->saveState() );
settings.setValue( "/windows/QgsExpressionBuilderWidget/functionsplitter", functionsplit->saveState() );

delete mModel;
@@ -149,7 +154,11 @@ void QgsExpressionBuilderWidget::currentChanged( const QModelIndex &index, const

void QgsExpressionBuilderWidget::on_btnRun_pressed()
{
saveFunctionFile( cmbFileNames->currentText() );
if ( !cmbFileNames->currentItem() )
return;

QString file = cmbFileNames->currentItem()->text();
saveFunctionFile( file );
runPythonCode( txtPython->text() );
}

@@ -180,7 +189,7 @@ void QgsExpressionBuilderWidget::saveFunctionFile( QString fileName )

fileName = mFunctionsPath + QDir::separator() + fileName;
QFile myFile( fileName );
if ( myFile.open( QIODevice::WriteOnly ) )
if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
{
QTextStream myFileStream( &myFile );
myFileStream << txtPython->text() << endl;
@@ -199,33 +208,47 @@ void QgsExpressionBuilderWidget::updateFunctionFileList( const QString& path )
{
QFileInfo info( mFunctionsPath + QDir::separator() + name );
if ( info.baseName() == "__init__" ) continue;
cmbFileNames->addItem( info.baseName() );
QListWidgetItem* item = new QListWidgetItem( QgsApplication::getThemeIcon("console/iconTabEditorConsole.png"), info.baseName() );
cmbFileNames->addItem( item );
}
if ( !cmbFileNames->currentItem() )
cmbFileNames->setCurrentRow( 0 );
}

void QgsExpressionBuilderWidget::newFunctionFile( const QString& fileName )
{
QList<QListWidgetItem*> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
if ( items.count() > 0 )
return;

QString templatetxt;
QgsPythonRunner::eval( "qgis.user.expressions.template", templatetxt );
txtPython->setText( templatetxt );
int index = cmbFileNames->findText( fileName );
if ( index == -1 )
cmbFileNames->setEditText( fileName );
else
cmbFileNames->setCurrentIndex( index );
cmbFileNames->insertItem( 0, fileName );
cmbFileNames->setCurrentRow( 0 );
saveFunctionFile( fileName );
}

void QgsExpressionBuilderWidget::on_btnNewFile_pressed()
{
newFunctionFile();
bool ok;
QString text = QInputDialog::getText( this, tr( "Enter new file name" ),
tr( "File name:" ), QLineEdit::Normal,
"", &ok );
if ( ok && !text.isEmpty() )
{
newFunctionFile( text );
}
}

void QgsExpressionBuilderWidget::on_cmbFileNames_currentIndexChanged( int index )
void QgsExpressionBuilderWidget::on_cmbFileNames_currentItemChanged( QListWidgetItem* item, QListWidgetItem* lastitem )
{
if ( index == -1 )
return;

QString path = mFunctionsPath + QDir::separator() + cmbFileNames->currentText();
if ( lastitem )
{
QString filename = lastitem->text();
saveFunctionFile( filename );
}
QString path = mFunctionsPath + QDir::separator() + item->text();
loadCodeFromFile( path );
}

@@ -242,18 +265,6 @@ void QgsExpressionBuilderWidget::loadFunctionCode( const QString& code )
txtPython->setText( code );
}

void QgsExpressionBuilderWidget::on_btnSaveFile_pressed()
{
QString name = cmbFileNames->currentText();
saveFunctionFile( name );
int index = cmbFileNames->findText( name );
if ( index == -1 )
{
cmbFileNames->addItem( name );
cmbFileNames->setCurrentIndex( cmbFileNames->count() - 1 );
}
}

void QgsExpressionBuilderWidget::on_expressionTree_doubleClicked( const QModelIndex &index )
{
QModelIndex idx = mProxyModel->mapToSource( index );
@@ -733,6 +744,38 @@ void QgsExpressionBuilderWidget::loadAllValues()
fillFieldValues( item->text(), -1 );
}

void QgsExpressionBuilderWidget::on_txtPython_textChanged()
{
lblAutoSave->setText( "Saving..." );
if ( mAutoSave )
{
autosave();
}
}

void QgsExpressionBuilderWidget::autosave()
{
// Don't auto save if not on function editor that would be silly.
if ( tabWidget->currentIndex() != 1 )
return;

QListWidgetItem* item = cmbFileNames->currentItem();
if ( !item )
return;

QString file = item->text();
saveFunctionFile( file );
lblAutoSave->setText( "Saved" );
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect();
lblAutoSave->setGraphicsEffect( effect );
QPropertyAnimation *anim = new QPropertyAnimation( effect, "opacity" );
anim->setDuration( 2000 );
anim->setStartValue( 1.0 );
anim->setEndValue( 0.0 );
anim->setEasingCurve( QEasingCurve::OutQuad );
anim->start( QAbstractAnimation::DeleteWhenStopped );
}

void QgsExpressionBuilderWidget::setExpressionState( bool state )
{
mExpressionValid = state;
@@ -232,24 +232,43 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
void updateFunctionFileList( const QString& path );

public slots:

/**
* Load sample values into the sample value area
*/
void loadSampleValues();

/**
* Load all unique values from the set layer into the sample area
*/
void loadAllValues();

/**
* Auto save the current Python function code.
*/
void autosave();
/**
* Enabled or disable auto saving. When enabled Python scripts will be auto saved
* when text changes.
* @param enabled True to enable auto saving.
*/
void setAutoSave( bool enabled ) { mAutoSave = enabled; }

private slots:
void showContextMenu( const QPoint & );
void setExpressionState( bool state );
void currentChanged( const QModelIndex &index, const QModelIndex & );
void operatorButtonClicked();
void on_btnRun_pressed();
void on_btnNewFile_pressed();
void on_cmbFileNames_currentIndexChanged( int index );
void on_btnSaveFile_pressed();
void on_cmbFileNames_currentItemChanged( QListWidgetItem* item, QListWidgetItem* lastitem );
void on_expressionTree_doubleClicked( const QModelIndex &index );
void on_txtExpressionString_textChanged();
void on_txtSearchEdit_textChanged();
void on_txtSearchEditValues_textChanged();
void on_lblPreview_linkActivated( const QString& link );
void on_mValuesListView_doubleClicked( const QModelIndex &index );
void operatorButtonClicked();
void showContextMenu( const QPoint & );
void loadSampleValues();
void loadAllValues();

private slots:
void setExpressionState( bool state );
void on_txtPython_textChanged();

signals:
/** Emitted when the user changes the expression in the widget.
@@ -277,6 +296,7 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp

void loadExpressionContext();

bool mAutoSave;
QString mFunctionsPath;
QgsVectorLayer *mLayer;
QStandardItemModel *mModel;

0 comments on commit 8c86aab

Please sign in to comment.
You can’t perform that action at this time.