mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Substitution list support for labeling
Adds the ability to specify a list of text substitutes to make which apply to label text. Eg abbrevating street types. Users can export and import lists of substitutes to make reuse and sharing easier.
This commit is contained in:
parent
4a89b7c470
commit
7dea9700a6
@ -464,6 +464,11 @@ class QgsPalLayerSettings
|
||||
QPainter::CompositionMode blendMode;
|
||||
QColor previewBkgrdColor;
|
||||
|
||||
//! Substitution collection for automatic text substitution with labels
|
||||
QgsStringReplacementCollection substitutions;
|
||||
//! True if substitutions should be applied
|
||||
bool useSubstitutions;
|
||||
|
||||
//-- text formatting
|
||||
|
||||
QString wrapChar;
|
||||
|
@ -1,3 +1,115 @@
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringReplacement
|
||||
* \brief A representation of a single string replacement.
|
||||
* \note Added in version 3.0
|
||||
*/
|
||||
|
||||
class QgsStringReplacement
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsstringutils.h>
|
||||
%End
|
||||
public:
|
||||
|
||||
/** Constructor for QgsStringReplacement.
|
||||
* @param match string to match
|
||||
* @param replacement string to replace match with
|
||||
* @param caseSensitive set to true for a case sensitive match
|
||||
* @param wholeWordOnly set to true to match complete words only, or false to allow partial word matches
|
||||
*/
|
||||
QgsStringReplacement( const QString& match,
|
||||
const QString& replacement,
|
||||
bool caseSensitive = false,
|
||||
bool wholeWordOnly = false );
|
||||
|
||||
//! Returns the string matched by this object
|
||||
QString match() const;
|
||||
|
||||
//! Returns the string to replace matches with
|
||||
QString replacement() const;
|
||||
|
||||
//! Returns true if match is case sensitive
|
||||
bool caseSensitive() const;
|
||||
|
||||
//! Returns true if match only applies to whole words, or false if partial word matches are permitted
|
||||
bool wholeWordOnly() const;
|
||||
|
||||
/** Processes a given input string, applying any valid replacements which should be made.
|
||||
* @param input input string
|
||||
* @returns input string with any matches replaced by replacement string
|
||||
*/
|
||||
QString process( const QString& input ) const;
|
||||
|
||||
bool operator==( const QgsStringReplacement& other );
|
||||
|
||||
/** Returns a map of the replacement properties.
|
||||
* @see fromProperties()
|
||||
*/
|
||||
QgsStringMap properties() const;
|
||||
|
||||
/** Creates a new QgsStringReplacement from an encoded properties map.
|
||||
* @see properties()
|
||||
*/
|
||||
static QgsStringReplacement fromProperties( const QgsStringMap& properties );
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringReplacementCollection
|
||||
* \brief A collection of string replacements (specified using QgsStringReplacement objects).
|
||||
* \note Added in version 3.0
|
||||
*/
|
||||
|
||||
class QgsStringReplacementCollection
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsstringutils.h>
|
||||
%End
|
||||
public:
|
||||
|
||||
/** Constructor for QgsStringReplacementCollection
|
||||
* @param replacements initial list of string replacements
|
||||
*/
|
||||
QgsStringReplacementCollection( const QList< QgsStringReplacement >& replacements = QList< QgsStringReplacement >() );
|
||||
|
||||
/** Returns the list of string replacements in this collection.
|
||||
* @see setReplacements()
|
||||
*/
|
||||
QList< QgsStringReplacement > replacements() const;
|
||||
|
||||
/** Sets the list of string replacements in this collection.
|
||||
* @param replacements list of string replacements to apply. Replacements are applied in the
|
||||
* order they are specified here.
|
||||
* @see replacements()
|
||||
*/
|
||||
void setReplacements( const QList< QgsStringReplacement >& replacements );
|
||||
|
||||
/** Processes a given input string, applying any valid replacements which should be made
|
||||
* using QgsStringReplacement objects contained by this collection. Replacements
|
||||
* are made in order of the QgsStringReplacement objects contained in the collection.
|
||||
* @param input input string
|
||||
* @returns input string with any matches replaced by replacement string
|
||||
*/
|
||||
QString process( const QString& input ) const;
|
||||
|
||||
/** Writes the collection state to an XML element.
|
||||
* @param elem target DOM element
|
||||
* @param doc DOM document
|
||||
* @see readXml()
|
||||
*/
|
||||
void writeXml( QDomElement& elem, QDomDocument& doc ) const;
|
||||
|
||||
/** Reads the collection state from an XML element.
|
||||
* @param elem DOM element
|
||||
* @see writeXml()
|
||||
*/
|
||||
void readXml( const QDomElement& elem );
|
||||
};
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringUtils
|
||||
* \brief Utility functions for working with strings.
|
||||
|
@ -114,6 +114,7 @@ SET(QGIS_APP_SRCS
|
||||
qgsrelationadddlg.cpp
|
||||
qgsselectbyformdialog.cpp
|
||||
qgsstatisticalsummarydockwidget.cpp
|
||||
qgssubstitutionlistwidget.cpp
|
||||
qgstextannotationdialog.cpp
|
||||
qgssnappingdialog.cpp
|
||||
qgssvgannotationdialog.cpp
|
||||
@ -290,6 +291,7 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgssnappingdialog.h
|
||||
qgssponsors.h
|
||||
qgsstatisticalsummarydockwidget.h
|
||||
qgssubstitutionlistwidget.h
|
||||
qgssvgannotationdialog.h
|
||||
qgstextannotationdialog.h
|
||||
qgstipgui.h
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "qgssvgselectorwidget.h"
|
||||
#include "qgsvectorlayerlabeling.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgssubstitutionlistwidget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QSettings>
|
||||
@ -137,6 +138,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
|
||||
connect( mShadowTranspSlider, SIGNAL( valueChanged( int ) ), mShadowTranspSpnBx, SLOT( setValue( int ) ) );
|
||||
connect( mShadowTranspSpnBx, SIGNAL( valueChanged( int ) ), mShadowTranspSlider, SLOT( setValue( int ) ) );
|
||||
connect( mLimitLabelChkBox, SIGNAL( toggled( bool ) ), mLimitLabelSpinBox, SLOT( setEnabled( bool ) ) );
|
||||
connect( mCheckBoxSubstituteText, SIGNAL( toggled( bool ) ), mToolButtonConfigureSubstitutes, SLOT( setEnabled( bool ) ) );
|
||||
|
||||
//connections to prevent users removing all line placement positions
|
||||
connect( chkLineAbove, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) );
|
||||
@ -466,7 +468,8 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
|
||||
<< radPolygonPerimeter
|
||||
<< radPolygonPerimeterCurved
|
||||
<< radPredefinedOrder
|
||||
<< mFieldExpressionWidget;
|
||||
<< mFieldExpressionWidget
|
||||
<< mCheckBoxSubstituteText;
|
||||
connectValueChanged( widgets, SLOT( updatePreview() ) );
|
||||
|
||||
connect( mQuadrantBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePreview() ) );
|
||||
@ -623,6 +626,8 @@ void QgsLabelingGui::init()
|
||||
// set the current field or add the current expression to the bottom of the list
|
||||
mFieldExpressionWidget->setRow( -1 );
|
||||
mFieldExpressionWidget->setField( lyr.fieldName );
|
||||
mCheckBoxSubstituteText->setChecked( lyr.useSubstitutions );
|
||||
mSubstitutions = lyr.substitutions;
|
||||
|
||||
// populate placement options
|
||||
mCentroidRadioWhole->setChecked( lyr.centroidWhole );
|
||||
@ -1013,6 +1018,8 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
|
||||
lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
|
||||
lyr.scaleMin = mScaleBasedVisibilityMinSpnBx->value();
|
||||
lyr.scaleMax = mScaleBasedVisibilityMaxSpnBx->value();
|
||||
lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
|
||||
lyr.substitutions = mSubstitutions;
|
||||
|
||||
// buffer
|
||||
lyr.bufferDraw = mBufferDrawChkBx->isChecked();
|
||||
@ -1973,6 +1980,12 @@ void QgsLabelingGui::updateLinePlacementOptions()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLabelingGui::onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions )
|
||||
{
|
||||
mSubstitutions = substitutions;
|
||||
emit widgetChanged();
|
||||
}
|
||||
|
||||
void QgsLabelingGui::updateSvgWidgets( const QString& svgPath )
|
||||
{
|
||||
if ( mShapeSVGPathLineEdit->text() != svgPath )
|
||||
@ -2099,6 +2112,28 @@ void QgsLabelingGui::on_mChkNoObstacle_toggled( bool active )
|
||||
mObstaclePriorityFrame->setEnabled( active );
|
||||
}
|
||||
|
||||
void QgsLabelingGui::on_mToolButtonConfigureSubstitutes_clicked()
|
||||
{
|
||||
QgsPanelWidget* panel = QgsPanelWidget::findParentPanel( this );
|
||||
if ( panel && panel->dockMode() )
|
||||
{
|
||||
QgsSubstitutionListWidget* widget = new QgsSubstitutionListWidget( panel );
|
||||
widget->setPanelTitle( tr( "Substitutions" ) );
|
||||
widget->setSubstitutions( mSubstitutions );
|
||||
connect( widget, SIGNAL( substitutionsChanged( QgsStringReplacementCollection ) ), this, SLOT( onSubstitutionsChanged( QgsStringReplacementCollection ) ) );
|
||||
panel->openPanel( widget );
|
||||
return;
|
||||
}
|
||||
|
||||
QgsSubstitutionListDialog dlg( this );
|
||||
dlg.setSubstitutions( mSubstitutions );
|
||||
if ( dlg.exec() == QDialog::Accepted )
|
||||
{
|
||||
mSubstitutions = dlg.substitutions();
|
||||
emit widgetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLabelingGui::showBackgroundRadius( bool show )
|
||||
{
|
||||
mShapeRadiusLabel->setVisible( show );
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <QDialog>
|
||||
#include <QFontDatabase>
|
||||
#include <ui_qgslabelingguibase.h>
|
||||
#include "qgsstringutils.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsMapCanvas;
|
||||
@ -94,6 +95,8 @@ class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
|
||||
void on_mDirectSymbRightToolBtn_clicked();
|
||||
void on_mChkNoObstacle_toggled( bool active );
|
||||
|
||||
void on_mToolButtonConfigureSubstitutes_clicked();
|
||||
|
||||
protected:
|
||||
void blockInitSignals( bool block );
|
||||
void blockFontChangeSignals( bool blk );
|
||||
@ -133,6 +136,8 @@ class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
|
||||
|
||||
bool mLoadSvgParams;
|
||||
|
||||
QgsStringReplacementCollection mSubstitutions;
|
||||
|
||||
void enableDataDefinedAlignment( bool enable );
|
||||
|
||||
QgsExpressionContext createExpressionContext() const override;
|
||||
@ -143,6 +148,7 @@ class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
|
||||
void showBackgroundPenStyle( bool show );
|
||||
void on_mShapeSVGPathLineEdit_textChanged( const QString& text );
|
||||
void updateLinePlacementOptions();
|
||||
void onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
230
src/app/qgssubstitutionlistwidget.cpp
Normal file
230
src/app/qgssubstitutionlistwidget.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/***************************************************************************
|
||||
qgssubstitutionlistwidget.cpp
|
||||
-----------------------------
|
||||
begin : August 2016
|
||||
copyright : (C) 2016 Nyall Dawson
|
||||
email : nyall dot dawson 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 "qgssubstitutionlistwidget.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QCheckBox>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
|
||||
QgsSubstitutionListWidget::QgsSubstitutionListWidget( QWidget* parent )
|
||||
: QgsPanelWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
connect( mTableSubstitutions, SIGNAL( cellChanged( int, int ) ), this, SLOT( tableChanged() ) );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::setSubstitutions( const QgsStringReplacementCollection& substitutions )
|
||||
{
|
||||
mTableSubstitutions->blockSignals( true );
|
||||
mTableSubstitutions->clearContents();
|
||||
Q_FOREACH ( const QgsStringReplacement& replacement, substitutions.replacements() )
|
||||
{
|
||||
addSubstitution( replacement );
|
||||
}
|
||||
mTableSubstitutions->blockSignals( false );
|
||||
}
|
||||
|
||||
QgsStringReplacementCollection QgsSubstitutionListWidget::substitutions() const
|
||||
{
|
||||
QList< QgsStringReplacement > result;
|
||||
for ( int i = 0; i < mTableSubstitutions->rowCount(); ++i )
|
||||
{
|
||||
if ( !mTableSubstitutions->item( i, 0 ) )
|
||||
continue;
|
||||
|
||||
if ( mTableSubstitutions->item( i, 0 )->text().isEmpty() )
|
||||
continue;
|
||||
|
||||
QCheckBox* chkCaseSensitive = qobject_cast<QCheckBox*>( mTableSubstitutions->cellWidget( i, 2 ) );
|
||||
QCheckBox* chkWholeWord = qobject_cast<QCheckBox*>( mTableSubstitutions->cellWidget( i, 3 ) );
|
||||
|
||||
QgsStringReplacement replacement( mTableSubstitutions->item( i, 0 )->text(),
|
||||
mTableSubstitutions->item( i, 1 )->text(),
|
||||
chkCaseSensitive->isChecked(),
|
||||
chkWholeWord->isChecked() );
|
||||
result << replacement;
|
||||
}
|
||||
return QgsStringReplacementCollection( result );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::on_mButtonAdd_clicked()
|
||||
{
|
||||
addSubstitution( QgsStringReplacement( QString(), QString(), false, true ) );
|
||||
mTableSubstitutions->setFocus();
|
||||
mTableSubstitutions->setCurrentCell( mTableSubstitutions->rowCount() - 1, 0 );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::on_mButtonRemove_clicked()
|
||||
{
|
||||
int currentRow = mTableSubstitutions->currentRow();
|
||||
mTableSubstitutions->removeRow( currentRow );
|
||||
tableChanged();
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::tableChanged()
|
||||
{
|
||||
emit substitutionsChanged( substitutions() );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::on_mButtonExport_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName( this, tr( "Save substitutions" ), QDir::homePath(),
|
||||
tr( "XML files (*.xml *.XML)" ) );
|
||||
if ( fileName.isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the user never ommited the extension from the file name
|
||||
if ( !fileName.endsWith( ".xml", Qt::CaseInsensitive ) )
|
||||
{
|
||||
fileName += ".xml";
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
QDomElement root = doc.createElement( "substitutions" );
|
||||
root.setAttribute( "version", "1.0" );
|
||||
QgsStringReplacementCollection collection = substitutions();
|
||||
collection.writeXml( root, doc );
|
||||
doc.appendChild( root );
|
||||
|
||||
QFile file( fileName );
|
||||
if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
||||
{
|
||||
QMessageBox::warning( nullptr, tr( "Export substitutions" ),
|
||||
tr( "Cannot write file %1:\n%2." ).arg( fileName, file.errorString() ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream out( &file );
|
||||
doc.save( out, 4 );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::on_mButtonImport_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName( this, tr( "Load substitutions" ), QDir::homePath(),
|
||||
tr( "XML files (*.xml *.XML)" ) );
|
||||
if ( fileName.isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file( fileName );
|
||||
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
QMessageBox::warning( nullptr, tr( "Import substitutions" ),
|
||||
tr( "Cannot read file %1:\n%2." ).arg( fileName, file.errorString() ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
QString errorStr;
|
||||
int errorLine;
|
||||
int errorColumn;
|
||||
|
||||
if ( !doc.setContent( &file, true, &errorStr, &errorLine, &errorColumn ) )
|
||||
{
|
||||
QMessageBox::warning( nullptr, tr( "Import substitutions" ),
|
||||
tr( "Parse error at line %1, column %2:\n%3" )
|
||||
.arg( errorLine )
|
||||
.arg( errorColumn )
|
||||
.arg( errorStr ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
if ( root.tagName() != "substitutions" )
|
||||
{
|
||||
QMessageBox::warning( nullptr, tr( "Import substitutions" ),
|
||||
tr( "The selected file in not an substitutions list." ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
|
||||
QgsStringReplacementCollection collection;
|
||||
collection.readXml( root );
|
||||
setSubstitutions( collection );
|
||||
tableChanged();
|
||||
}
|
||||
|
||||
void QgsSubstitutionListWidget::addSubstitution( const QgsStringReplacement& substitution )
|
||||
{
|
||||
int row = mTableSubstitutions->rowCount();
|
||||
mTableSubstitutions->insertRow( row );
|
||||
|
||||
Qt::ItemFlags itemFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable
|
||||
| Qt::ItemIsEditable;
|
||||
|
||||
QTableWidgetItem* matchItem = new QTableWidgetItem( substitution.match() );
|
||||
matchItem->setFlags( itemFlags );
|
||||
mTableSubstitutions->setItem( row, 0, matchItem );
|
||||
QTableWidgetItem* replaceItem = new QTableWidgetItem( substitution.replacement() );
|
||||
replaceItem->setFlags( itemFlags );
|
||||
mTableSubstitutions->setItem( row, 1, replaceItem );
|
||||
|
||||
QCheckBox* caseSensitiveChk = new QCheckBox( this );
|
||||
caseSensitiveChk->setChecked( substitution.caseSensitive() );
|
||||
mTableSubstitutions->setCellWidget( row, 2, caseSensitiveChk );
|
||||
connect( caseSensitiveChk, SIGNAL( toggled( bool ) ), this, SLOT( tableChanged() ) );
|
||||
|
||||
QCheckBox* wholeWordChk = new QCheckBox( this );
|
||||
wholeWordChk->setChecked( substitution.wholeWordOnly() );
|
||||
mTableSubstitutions->setCellWidget( row, 3, wholeWordChk );
|
||||
connect( wholeWordChk, SIGNAL( toggled( bool ) ), this, SLOT( tableChanged() ) );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsSubstitutionListDialog
|
||||
//
|
||||
|
||||
|
||||
QgsSubstitutionListDialog::QgsSubstitutionListDialog( QWidget* parent )
|
||||
: QDialog( parent )
|
||||
, mWidget( nullptr )
|
||||
{
|
||||
setWindowTitle( tr( "Substitutions" ) );
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
mWidget = new QgsSubstitutionListWidget();
|
||||
vLayout->addWidget( mWidget );
|
||||
QDialogButtonBox* bbox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal );
|
||||
connect( bbox, SIGNAL( accepted() ), this, SLOT( accept() ) );
|
||||
connect( bbox, SIGNAL( rejected() ), this, SLOT( reject() ) );
|
||||
vLayout->addWidget( bbox );
|
||||
setLayout( vLayout );
|
||||
}
|
||||
|
||||
void QgsSubstitutionListDialog::setSubstitutions( const QgsStringReplacementCollection& substitutions )
|
||||
{
|
||||
mWidget->setSubstitutions( substitutions );
|
||||
}
|
||||
|
||||
QgsStringReplacementCollection QgsSubstitutionListDialog::substitutions() const
|
||||
{
|
||||
return mWidget->substitutions();
|
||||
}
|
111
src/app/qgssubstitutionlistwidget.h
Normal file
111
src/app/qgssubstitutionlistwidget.h
Normal file
@ -0,0 +1,111 @@
|
||||
/***************************************************************************
|
||||
qgssubstitutionlistwidget.h
|
||||
---------------------------
|
||||
begin : August 2016
|
||||
copyright : (C) 2016 Nyall Dawson
|
||||
email : nyall dot dawson 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 QGSSUBSTITUTIONLISTWIDGET_H
|
||||
#define QGSSUBSTITUTIONLISTWIDGET_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "qgspanelwidget.h"
|
||||
#include "ui_qgssubstitutionlistwidgetbase.h"
|
||||
#include "qgsstringutils.h"
|
||||
|
||||
/** \class QgsSubstitutionListWidget
|
||||
* \ingroup app
|
||||
* A widget which allows users to specify a list of substitutions to apply to a string, with
|
||||
* options for exporting and importing substitution lists.
|
||||
* \note added in QGIS 3.0
|
||||
* \see QgsSubstitutionListDialog
|
||||
*/
|
||||
class APP_EXPORT QgsSubstitutionListWidget : public QgsPanelWidget, private Ui::QgsSubstitutionListWidgetBase
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QgsStringReplacementCollection substitutions READ substitutions WRITE setSubstitutions NOTIFY substitutionsChanged )
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for QgsSubstitutionListWidget.
|
||||
* @param parent parent widget
|
||||
*/
|
||||
QgsSubstitutionListWidget( QWidget* parent = nullptr );
|
||||
|
||||
/** Sets the list of substitutions to show in the widget.
|
||||
* @param substitutions substitution list
|
||||
* @see substitutions()
|
||||
*/
|
||||
void setSubstitutions( const QgsStringReplacementCollection& substitutions );
|
||||
|
||||
/** Returns the list of substitutions currently defined by the widget.
|
||||
* @see setSubstitutions()
|
||||
*/
|
||||
QgsStringReplacementCollection substitutions() const;
|
||||
|
||||
signals:
|
||||
|
||||
//! Emitted when the substitution definitions change.
|
||||
void substitutionsChanged( const QgsStringReplacementCollection& substitutions );
|
||||
|
||||
private slots:
|
||||
|
||||
void on_mButtonAdd_clicked();
|
||||
void on_mButtonRemove_clicked();
|
||||
void tableChanged();
|
||||
void on_mButtonExport_clicked();
|
||||
void on_mButtonImport_clicked();
|
||||
|
||||
private:
|
||||
|
||||
void addSubstitution( const QgsStringReplacement& substitution );
|
||||
|
||||
};
|
||||
|
||||
/** \class QgsSubstitutionListDialog
|
||||
* \ingroup app
|
||||
* A dialog which allows users to specify a list of substitutions to apply to a string, with
|
||||
* options for exporting and importing substitution lists.
|
||||
* \see QgsSubstitutionListWidget
|
||||
*/
|
||||
class APP_EXPORT QgsSubstitutionListDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QgsStringReplacementCollection substitutions READ substitutions WRITE setSubstitutions )
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for QgsSubstitutionListDialog.
|
||||
* @param parent parent widget
|
||||
*/
|
||||
QgsSubstitutionListDialog( QWidget* parent = nullptr );
|
||||
|
||||
/** Sets the list of substitutions to show in the dialog.
|
||||
* @param substitutions substitution list
|
||||
* @see substitutions()
|
||||
*/
|
||||
void setSubstitutions( const QgsStringReplacementCollection& substitutions );
|
||||
|
||||
/** Returns the list of substitutions currently defined by the dialog.
|
||||
* @see setSubstitutions()
|
||||
*/
|
||||
QgsStringReplacementCollection substitutions() const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QgsSubstitutionListWidget* mWidget;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSSUBSTITUTIONLISTWIDGET_H
|
@ -128,6 +128,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
|
||||
// font processing info
|
||||
mTextFontFound = true;
|
||||
mTextFontFamily = QApplication::font().family();
|
||||
useSubstitutions = false;
|
||||
|
||||
// text formatting
|
||||
wrapChar = "";
|
||||
@ -387,6 +388,8 @@ QgsPalLayerSettings& QgsPalLayerSettings::operator=( const QgsPalLayerSettings &
|
||||
// font processing info
|
||||
mTextFontFound = s.mTextFontFound;
|
||||
mTextFontFamily = s.mTextFontFamily;
|
||||
substitutions = s.substitutions;
|
||||
useSubstitutions = s.useSubstitutions;
|
||||
|
||||
// text formatting
|
||||
wrapChar = s.wrapChar;
|
||||
@ -847,7 +850,11 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
|
||||
blendMode = QgsPainting::getCompositionMode(
|
||||
static_cast< QgsPainting::BlendMode >( layer->customProperty( "labeling/blendMode", QVariant( QgsPainting::BlendNormal ) ).toUInt() ) );
|
||||
previewBkgrdColor = QColor( layer->customProperty( "labeling/previewBkgrdColor", QVariant( "#ffffff" ) ).toString() );
|
||||
|
||||
QDomDocument doc( "substitutions" );
|
||||
doc.setContent( layer->customProperty( "labeling/substitutions" ).toString() );
|
||||
QDomElement replacementElem = doc.firstChildElement( "substitutions" );
|
||||
substitutions.readXml( replacementElem );
|
||||
useSubstitutions = layer->customProperty( "labeling/useSubstitutions" ).toBool();
|
||||
|
||||
// text formatting
|
||||
wrapChar = layer->customProperty( "labeling/wrapChar" ).toString();
|
||||
@ -1127,6 +1134,14 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
|
||||
layer->setCustomProperty( "labeling/textTransp", textTransp );
|
||||
layer->setCustomProperty( "labeling/blendMode", QgsPainting::getBlendModeEnum( blendMode ) );
|
||||
layer->setCustomProperty( "labeling/previewBkgrdColor", previewBkgrdColor.name() );
|
||||
QDomDocument doc( "substitutions" );
|
||||
QDomElement replacementElem = doc.createElement( "substitutions" );
|
||||
substitutions.writeXml( replacementElem, doc );
|
||||
QString replacementProps;
|
||||
QTextStream stream( &replacementProps );
|
||||
replacementElem.save( stream, -1 );
|
||||
layer->setCustomProperty( "labeling/substitutions", replacementProps );
|
||||
layer->setCustomProperty( "labeling/useSubstitutions", useSubstitutions );
|
||||
|
||||
// text formatting
|
||||
layer->setCustomProperty( "labeling/wrapChar", wrapChar );
|
||||
@ -1298,7 +1313,8 @@ void QgsPalLayerSettings::readXml( QDomElement& elem )
|
||||
blendMode = QgsPainting::getCompositionMode(
|
||||
static_cast< QgsPainting::BlendMode >( textStyleElem.attribute( "blendMode", QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
|
||||
previewBkgrdColor = QColor( textStyleElem.attribute( "previewBkgrdColor", "#ffffff" ) );
|
||||
|
||||
substitutions.readXml( textStyleElem.firstChildElement( "substitutions" ) );
|
||||
useSubstitutions = textStyleElem.attribute( "useSubstitutions" ).toInt();
|
||||
|
||||
// text formatting
|
||||
QDomElement textFormatElem = elem.firstChildElement( "text-format" );
|
||||
@ -1564,6 +1580,10 @@ QDomElement QgsPalLayerSettings::writeXml( QDomDocument& doc )
|
||||
textStyleElem.setAttribute( "textTransp", textTransp );
|
||||
textStyleElem.setAttribute( "blendMode", QgsPainting::getBlendModeEnum( blendMode ) );
|
||||
textStyleElem.setAttribute( "previewBkgrdColor", previewBkgrdColor.name() );
|
||||
QDomElement replacementElem = doc.createElement( "substitutions" );
|
||||
substitutions.writeXml( replacementElem, doc );
|
||||
textStyleElem.appendChild( replacementElem );
|
||||
textStyleElem.setAttribute( "useSubstitutions", useSubstitutions );
|
||||
|
||||
// text formatting
|
||||
QDomElement textFormatElem = doc.createElement( "text-format" );
|
||||
@ -2314,6 +2334,12 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
|
||||
labelText = v.isNull() ? "" : v.toString();
|
||||
}
|
||||
|
||||
// apply text replacements
|
||||
if ( useSubstitutions )
|
||||
{
|
||||
labelText = substitutions.process( labelText );
|
||||
}
|
||||
|
||||
// data defined format numbers?
|
||||
bool formatnum = formatNumbers;
|
||||
if ( dataDefinedEvaluate( QgsPalLayerSettings::NumFormat, exprVal, &context.expressionContext(), formatNumbers ) )
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "qgsfield.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgsmapunitscale.h"
|
||||
#include "qgsstringutils.h"
|
||||
|
||||
namespace pal
|
||||
{
|
||||
@ -480,6 +481,11 @@ class CORE_EXPORT QgsPalLayerSettings
|
||||
QPainter::CompositionMode blendMode;
|
||||
QColor previewBkgrdColor;
|
||||
|
||||
//! Substitution collection for automatic text substitution with labels
|
||||
QgsStringReplacementCollection substitutions;
|
||||
//! True if substitutions should be applied
|
||||
bool useSubstitutions;
|
||||
|
||||
//-- text formatting
|
||||
|
||||
QString wrapChar;
|
||||
|
@ -337,3 +337,89 @@ QString QgsStringUtils::insertLinks( const QString& string, bool *foundLinks )
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
QgsStringReplacement::QgsStringReplacement( const QString& match, const QString& replacement, bool caseSensitive, bool wholeWordOnly )
|
||||
: mMatch( match )
|
||||
, mReplacement( replacement )
|
||||
, mCaseSensitive( caseSensitive )
|
||||
, mWholeWordOnly( wholeWordOnly )
|
||||
{
|
||||
if ( mWholeWordOnly )
|
||||
mRx = QRegExp( QString( "\\b%1\\b" ).arg( mMatch ),
|
||||
mCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
|
||||
}
|
||||
|
||||
QString QgsStringReplacement::process( const QString& input ) const
|
||||
{
|
||||
QString result = input;
|
||||
if ( !mWholeWordOnly )
|
||||
{
|
||||
return result.replace( mMatch, mReplacement, mCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
|
||||
}
|
||||
else
|
||||
{
|
||||
return result.replace( mRx, mReplacement );
|
||||
}
|
||||
}
|
||||
|
||||
QgsStringMap QgsStringReplacement::properties() const
|
||||
{
|
||||
QgsStringMap map;
|
||||
map.insert( "match", mMatch );
|
||||
map.insert( "replace", mReplacement );
|
||||
map.insert( "caseSensitive", mCaseSensitive ? "1" : "0" );
|
||||
map.insert( "wholeWord", mWholeWordOnly ? "1" : "0" );
|
||||
return map;
|
||||
}
|
||||
|
||||
QgsStringReplacement QgsStringReplacement::fromProperties( const QgsStringMap& properties )
|
||||
{
|
||||
return QgsStringReplacement( properties.value( "match" ),
|
||||
properties.value( "replace" ),
|
||||
properties.value( "caseSensitive", "0" ) == "1",
|
||||
properties.value( "wholeWord", "0" ) == "1" );
|
||||
}
|
||||
|
||||
QString QgsStringReplacementCollection::process( const QString& input ) const
|
||||
{
|
||||
QString result = input;
|
||||
Q_FOREACH ( const QgsStringReplacement& r, mReplacements )
|
||||
{
|
||||
result = r.process( result );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QgsStringReplacementCollection::writeXml( QDomElement& elem, QDomDocument& doc ) const
|
||||
{
|
||||
Q_FOREACH ( const QgsStringReplacement& r, mReplacements )
|
||||
{
|
||||
QgsStringMap props = r.properties();
|
||||
QDomElement propEl = doc.createElement( "replacement" );
|
||||
QgsStringMap::const_iterator it = props.constBegin();
|
||||
for ( ; it != props.constEnd(); ++it )
|
||||
{
|
||||
propEl.setAttribute( it.key(), it.value() );
|
||||
}
|
||||
elem.appendChild( propEl );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsStringReplacementCollection::readXml( const QDomElement& elem )
|
||||
{
|
||||
mReplacements.clear();
|
||||
QDomNodeList nodelist = elem.elementsByTagName( "replacement" );
|
||||
for ( int i = 0;i < nodelist.count(); i++ )
|
||||
{
|
||||
QDomElement replacementElem = nodelist.at( i ).toElement();
|
||||
QDomNamedNodeMap nodeMap = replacementElem.attributes();
|
||||
|
||||
QgsStringMap props;
|
||||
for ( int j = 0; j < nodeMap.count(); ++j )
|
||||
{
|
||||
props.insert( nodeMap.item( j ).nodeName(), nodeMap.item( j ).nodeValue() );
|
||||
}
|
||||
mReplacements << QgsStringReplacement::fromProperties( props );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,10 +14,148 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QList>
|
||||
#include <QDomDocument>
|
||||
#include "qgis.h"
|
||||
|
||||
#ifndef QGSSTRINGUTILS_H
|
||||
#define QGSSTRINGUTILS_H
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringReplacement
|
||||
* \brief A representation of a single string replacement.
|
||||
* \note Added in version 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsStringReplacement
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for QgsStringReplacement.
|
||||
* @param match string to match
|
||||
* @param replacement string to replace match with
|
||||
* @param caseSensitive set to true for a case sensitive match
|
||||
* @param wholeWordOnly set to true to match complete words only, or false to allow partial word matches
|
||||
*/
|
||||
QgsStringReplacement( const QString& match,
|
||||
const QString& replacement,
|
||||
bool caseSensitive = false,
|
||||
bool wholeWordOnly = false );
|
||||
|
||||
//! Returns the string matched by this object
|
||||
QString match() const { return mMatch; }
|
||||
|
||||
//! Returns the string to replace matches with
|
||||
QString replacement() const { return mReplacement; }
|
||||
|
||||
//! Returns true if match is case sensitive
|
||||
bool caseSensitive() const { return mCaseSensitive; }
|
||||
|
||||
//! Returns true if match only applies to whole words, or false if partial word matches are permitted
|
||||
bool wholeWordOnly() const { return mWholeWordOnly; }
|
||||
|
||||
/** Processes a given input string, applying any valid replacements which should be made.
|
||||
* @param input input string
|
||||
* @returns input string with any matches replaced by replacement string
|
||||
*/
|
||||
QString process( const QString& input ) const;
|
||||
|
||||
bool operator==( const QgsStringReplacement& other )
|
||||
{
|
||||
return mMatch == other.mMatch
|
||||
&& mReplacement == other.mReplacement
|
||||
&& mCaseSensitive == other.mCaseSensitive
|
||||
&& mWholeWordOnly == other.mWholeWordOnly;
|
||||
}
|
||||
|
||||
/** Returns a map of the replacement properties.
|
||||
* @see fromProperties()
|
||||
*/
|
||||
QgsStringMap properties() const;
|
||||
|
||||
/** Creates a new QgsStringReplacement from an encoded properties map.
|
||||
* @see properties()
|
||||
*/
|
||||
static QgsStringReplacement fromProperties( const QgsStringMap& properties );
|
||||
|
||||
private:
|
||||
|
||||
QString mMatch;
|
||||
|
||||
QString mReplacement;
|
||||
|
||||
bool mCaseSensitive;
|
||||
|
||||
bool mWholeWordOnly;
|
||||
|
||||
QRegExp mRx;
|
||||
};
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringReplacementCollection
|
||||
* \brief A collection of string replacements (specified using QgsStringReplacement objects).
|
||||
* \note Added in version 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsStringReplacementCollection
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor for QgsStringReplacementCollection
|
||||
* @param replacements initial list of string replacements
|
||||
*/
|
||||
QgsStringReplacementCollection( const QList< QgsStringReplacement >& replacements = QList< QgsStringReplacement >() )
|
||||
: mReplacements( replacements )
|
||||
{}
|
||||
|
||||
/** Returns the list of string replacements in this collection.
|
||||
* @see setReplacements()
|
||||
*/
|
||||
QList< QgsStringReplacement > replacements() const { return mReplacements; }
|
||||
|
||||
/** Sets the list of string replacements in this collection.
|
||||
* @param replacements list of string replacements to apply. Replacements are applied in the
|
||||
* order they are specified here.
|
||||
* @see replacements()
|
||||
*/
|
||||
void setReplacements( const QList< QgsStringReplacement >& replacements )
|
||||
{
|
||||
mReplacements = replacements;
|
||||
}
|
||||
|
||||
/** Processes a given input string, applying any valid replacements which should be made
|
||||
* using QgsStringReplacement objects contained by this collection. Replacements
|
||||
* are made in order of the QgsStringReplacement objects contained in the collection.
|
||||
* @param input input string
|
||||
* @returns input string with any matches replaced by replacement string
|
||||
*/
|
||||
QString process( const QString& input ) const;
|
||||
|
||||
/** Writes the collection state to an XML element.
|
||||
* @param elem target DOM element
|
||||
* @param doc DOM document
|
||||
* @see readXml()
|
||||
*/
|
||||
void writeXml( QDomElement& elem, QDomDocument& doc ) const;
|
||||
|
||||
/** Reads the collection state from an XML element.
|
||||
* @param elem DOM element
|
||||
* @see writeXml()
|
||||
*/
|
||||
void readXml( const QDomElement& elem );
|
||||
|
||||
private:
|
||||
|
||||
QList< QgsStringReplacement > mReplacements;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsStringUtils
|
||||
* \brief Utility functions for working with strings.
|
||||
|
@ -118,6 +118,8 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
|
||||
|
||||
//! List of generated
|
||||
QList<QgsLabelFeature*> mLabels;
|
||||
|
||||
friend class TestQgsLabelingEngine;
|
||||
};
|
||||
|
||||
#endif // QGSVECTORLAYERLABELPROVIDER_H
|
||||
|
@ -618,7 +618,7 @@
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="mLabelStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>5</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mLabelPage_Text">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
@ -646,9 +646,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<y>-78</y>
|
||||
<width>448</width>
|
||||
<height>411</height>
|
||||
<height>442</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
@ -691,6 +691,91 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="3" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontStyleDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="mFontStyleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QgsUnitSelectionWidget" name="mFontSizeUnitWidget" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mFontLabel_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="mFontTranspLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Transparency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QgsColorButton" name="btnTextColor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="labelBlendMode">
|
||||
<property name="text">
|
||||
<string>Blend mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontColorDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||
<item>
|
||||
@ -743,73 +828,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="mFontSizeSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="showClearButton" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="12" column="1">
|
||||
<widget class="QgsBlendModeComboBox" name="comboBlendMode"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="mFontStyleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="9" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontCaseDDBtn">
|
||||
<property name="text">
|
||||
<string>Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="mFontCapitalsComboBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Capitalization style of text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="mFontTranspLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Transparency</string>
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -857,38 +882,36 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontCaseDDBtn">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="mFontCapitalsLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Type case</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontBlendModeDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontUnitsDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="mFontSizeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontColorDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontTranspDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -960,46 +983,66 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="mFontCapitalsLabel">
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="mFontFamilyFrame">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="mFontMissingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #990000;
|
||||
font-style: italic;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Font is missing.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="mFontSizeSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Type case</string>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontBlendModeDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="mFontColorLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<property name="maximum">
|
||||
<double>999999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontSizeDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<property name="showClearButton" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1010,86 +1053,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QgsColorButton" name="btnTextColor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="labelBlendMode">
|
||||
<item row="6" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontUnitsDDBtn">
|
||||
<property name="text">
|
||||
<string>Blend mode</string>
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||
<item>
|
||||
<widget class="QLabel" name="mFontWordSpacingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>word</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsDoubleSpinBox" name="mFontWordSpacingSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Space in pixels or map units, relative to size unit choice</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="showClearButton" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsDataDefinedButton" name="mFontWordSpacingDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="1" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
@ -1273,66 +1249,64 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QgsBlendModeComboBox" name="comboBlendMode"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontStyleDDBtn">
|
||||
<item row="8" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontTranspDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="mFontSizeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="mFontFamilyFrame">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="mFontMissingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #990000;
|
||||
font-style: italic;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Font is missing.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<item row="11" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||
<item>
|
||||
<widget class="QLabel" name="mFontWordSpacingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>word</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsDoubleSpinBox" name="mFontWordSpacingSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Space in pixels or map units, relative to size unit choice</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="showClearButton" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsDataDefinedButton" name="mFontWordSpacingDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFontComboBox" name="mFontFamilyCmbBx">
|
||||
@ -1341,22 +1315,71 @@ font-style: italic;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QgsUnitSelectionWidget" name="mFontSizeUnitWidget" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mFontLabel_2">
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="mFontCapitalsComboBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Capitalization style of text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="mFontColorLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
<string>Color</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mFontSizeDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mCheckBoxSubstituteText">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the label text will automatically be modified using a preset list of substitutes</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Apply label text substitutes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="2">
|
||||
<widget class="QToolButton" name="mToolButtonConfigureSubstitutes">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Configure substitutes</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -5389,7 +5412,7 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>448</width>
|
||||
<width>429</width>
|
||||
<height>799</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
134
src/ui/qgssubstitutionlistwidgetbase.ui
Normal file
134
src/ui/qgssubstitutionlistwidgetbase.ui
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsSubstitutionListWidgetBase</class>
|
||||
<widget class="QgsPanelWidget" name="QgsSubstitutionListWidgetBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>291</width>
|
||||
<height>416</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="mTableSubstitutions">
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Substitution</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Case Sensitive</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Whole Word</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If checked, only whole word matches are replaced</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="mButtonAdd">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/symbologyAdd.svg</normaloff>:/images/themes/default/symbologyAdd.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mButtonRemove">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/symbologyRemove.svg</normaloff>:/images/themes/default/symbologyRemove.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mButtonImport">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionFileOpen.svg</normaloff>:/images/themes/default/mActionFileOpen.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mButtonExport">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionFileSave.svg</normaloff>:/images/themes/default/mActionFileSave.svg</iconset>
|
||||
</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>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsPanelWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgspanelwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../images/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -43,6 +43,7 @@ class TestQgsLabelingEngine : public QObject
|
||||
void testRuleBased();
|
||||
void zOrder(); //test that labels are stacked correctly
|
||||
void testEncodeDecodePositionOrder();
|
||||
void testSubstitutions();
|
||||
|
||||
private:
|
||||
QgsVectorLayer* vl;
|
||||
@ -413,6 +414,46 @@ void TestQgsLabelingEngine::testEncodeDecodePositionOrder()
|
||||
QCOMPARE( decoded, expected );
|
||||
}
|
||||
|
||||
void TestQgsLabelingEngine::testSubstitutions()
|
||||
{
|
||||
QgsPalLayerSettings settings;
|
||||
settings.useSubstitutions = false;
|
||||
QgsStringReplacementCollection collection( QList< QgsStringReplacement >() << QgsStringReplacement( "aa", "bb" ) );
|
||||
settings.substitutions = collection;
|
||||
settings.fieldName = QString( "'aa label'" );
|
||||
settings.isExpression = true;
|
||||
|
||||
QgsVectorLayerLabelProvider* provider = new QgsVectorLayerLabelProvider( vl, "test", true, &settings );
|
||||
QgsFeature f( vl->fields(), 1 );
|
||||
f.setGeometry( QgsGeometry::fromPoint( QgsPoint( 1, 2 ) ) );
|
||||
|
||||
// make a fake render context
|
||||
QSize size( 640, 480 );
|
||||
QgsMapSettings mapSettings;
|
||||
mapSettings.setOutputSize( size );
|
||||
mapSettings.setExtent( vl->extent() );
|
||||
mapSettings.setLayers( QStringList() << vl->id() );
|
||||
mapSettings.setOutputDpi( 96 );
|
||||
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
|
||||
QStringList attributes;
|
||||
QgsLabelingEngine engine;
|
||||
engine.setMapSettings( mapSettings );
|
||||
engine.addProvider( provider );
|
||||
provider->prepare( context, attributes );
|
||||
|
||||
provider->registerFeature( f, context );
|
||||
QCOMPARE( provider->mLabels.at( 0 )->labelText(), QString( "aa label" ) );
|
||||
|
||||
//with substitution
|
||||
settings.useSubstitutions = true;
|
||||
QgsVectorLayerLabelProvider* provider2 = new QgsVectorLayerLabelProvider( vl, "test2", true, &settings );
|
||||
engine.addProvider( provider2 );
|
||||
provider2->prepare( context, attributes );
|
||||
|
||||
provider2->registerFeature( f, context );
|
||||
QCOMPARE( provider2->mLabels.at( 0 )->labelText(), QString( "bb label" ) );
|
||||
}
|
||||
|
||||
bool TestQgsLabelingEngine::imageCheck( const QString& testName, QImage &image, int mismatchCount )
|
||||
{
|
||||
//draw background
|
||||
|
@ -92,6 +92,7 @@ ADD_PYTHON_TEST(PyQgsSymbolLayerCreateSld test_qgssymbollayer_createsld.py)
|
||||
ADD_PYTHON_TEST(PyQgsArrowSymbolLayer test_qgsarrowsymbollayer.py)
|
||||
ADD_PYTHON_TEST(PyQgsSymbolExpressionVariables test_qgssymbolexpressionvariables.py)
|
||||
ADD_PYTHON_TEST(PyQgsSyntacticSugar test_syntactic_sugar.py)
|
||||
ADD_PYTHON_TEST(PyQgsStringUtils test_qgsstringutils.py)
|
||||
ADD_PYTHON_TEST(PyQgsSymbol test_qgssymbol.py)
|
||||
ADD_PYTHON_TEST(PyQgsTreeWidgetItem test_qgstreewidgetitem.py)
|
||||
ADD_PYTHON_TEST(PyQgsUnitTypes test_qgsunittypes.py)
|
||||
|
137
tests/src/python/test_qgsstringutils.py
Normal file
137
tests/src/python/test_qgsstringutils.py
Normal file
@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsStringUtils.
|
||||
|
||||
.. note:: 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.
|
||||
"""
|
||||
__author__ = 'Nyall Dawson'
|
||||
__date__ = '30/08/2016'
|
||||
__copyright__ = 'Copyright 2016, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
from qgis.PyQt.QtXml import (QDomDocument, QDomElement)
|
||||
|
||||
from qgis.core import (QgsStringUtils,
|
||||
QgsStringReplacement,
|
||||
QgsStringReplacementCollection
|
||||
)
|
||||
from qgis.testing import unittest
|
||||
|
||||
|
||||
class PyQgsStringReplacement(unittest.TestCase):
|
||||
|
||||
def testBasic(self):
|
||||
""" basic tests for QgsStringReplacement"""
|
||||
r = QgsStringReplacement('match', 'replace')
|
||||
self.assertEqual(r.match(), 'match')
|
||||
self.assertEqual(r.replacement(), 'replace')
|
||||
|
||||
r = QgsStringReplacement('match', 'replace', True, True)
|
||||
self.assertTrue(r.wholeWordOnly())
|
||||
self.assertTrue(r.caseSensitive())
|
||||
|
||||
def testReplace(self):
|
||||
""" test applying replacements"""
|
||||
|
||||
# case insensitive
|
||||
r = QgsStringReplacement('match', 'replace', False, False)
|
||||
self.assertEqual(r.process('one MaTch only'), 'one replace only')
|
||||
self.assertEqual(r.process('more then one MaTch here match two'), 'more then one replace here replace two')
|
||||
self.assertEqual(r.process('match start and end MaTch'), 'replace start and end replace')
|
||||
self.assertEqual(r.process('no hits'), 'no hits')
|
||||
self.assertEqual(r.process('some exmatches here'), 'some exreplacees here')
|
||||
self.assertEqual(r.process(''), '')
|
||||
|
||||
# case sensitive
|
||||
r = QgsStringReplacement('match', 'replace', True, False)
|
||||
self.assertEqual(r.process('one MaTch only'), 'one MaTch only')
|
||||
self.assertEqual(r.process('one match only'), 'one replace only')
|
||||
|
||||
# whole word only, case insensitive
|
||||
r = QgsStringReplacement('match', 'replace', False, True)
|
||||
self.assertEqual(r.process('some exmatches here'), 'some exmatches here')
|
||||
self.assertEqual(r.process('some match here'), 'some replace here')
|
||||
self.assertEqual(r.process('some exmatches MaTch here'), 'some exmatches replace here')
|
||||
self.assertEqual(r.process('some match maTCh here'), 'some replace replace here')
|
||||
self.assertEqual(r.process('some -match. here'), 'some -replace. here')
|
||||
self.assertEqual(r.process('match here'), 'replace here')
|
||||
self.assertEqual(r.process('some match'), 'some replace')
|
||||
|
||||
# whole word only, case sensitive
|
||||
r = QgsStringReplacement('match', 'replace', True, True)
|
||||
self.assertEqual(r.process('some exmatches here'), 'some exmatches here')
|
||||
self.assertEqual(r.process('some match here'), 'some replace here')
|
||||
self.assertEqual(r.process('some exmatches MaTch here'), 'some exmatches MaTch here')
|
||||
self.assertEqual(r.process('some match maTCh here'), 'some replace maTCh here')
|
||||
|
||||
def testEquality(self):
|
||||
""" test equality operator"""
|
||||
r1 = QgsStringReplacement('a', 'b', True, True)
|
||||
r2 = QgsStringReplacement('a', 'b', True, True)
|
||||
self.assertEqual(r1, r2)
|
||||
r2 = QgsStringReplacement('c', 'b')
|
||||
self.assertNotEqual(r1, r2)
|
||||
r2 = QgsStringReplacement('a', 'c')
|
||||
self.assertNotEqual(r1, r2)
|
||||
r2 = QgsStringReplacement('a', 'b', False, True)
|
||||
self.assertNotEqual(r1, r2)
|
||||
r2 = QgsStringReplacement('c', 'b', True, False)
|
||||
self.assertNotEqual(r1, r2)
|
||||
|
||||
def testSaveRestore(self):
|
||||
""" test saving/restoring replacement to map"""
|
||||
r1 = QgsStringReplacement('a', 'b', True, True)
|
||||
props = r1.properties()
|
||||
r2 = QgsStringReplacement.fromProperties(props)
|
||||
self.assertEqual(r1, r2)
|
||||
r1 = QgsStringReplacement('a', 'b', False, False)
|
||||
props = r1.properties()
|
||||
r2 = QgsStringReplacement.fromProperties(props)
|
||||
self.assertEqual(r1, r2)
|
||||
|
||||
|
||||
class PyQgsStringReplacementCollection(unittest.TestCase):
|
||||
|
||||
def testBasic(self):
|
||||
""" basic QgsStringReplacementCollection tests"""
|
||||
list = [QgsStringReplacement('aa', '11'),
|
||||
QgsStringReplacement('bb', '22')]
|
||||
c = QgsStringReplacementCollection(list)
|
||||
self.assertEqual(c.replacements(), list)
|
||||
|
||||
def testReplacements(self):
|
||||
""" test replacing using collection of replacements """
|
||||
c = QgsStringReplacementCollection()
|
||||
c.setReplacements([QgsStringReplacement('aa', '11'),
|
||||
QgsStringReplacement('bb', '22')])
|
||||
self.assertEqual(c.process('here aa bb is aa string bb'), 'here 11 22 is 11 string 22')
|
||||
self.assertEqual(c.process('no matches'), 'no matches')
|
||||
self.assertEqual(c.process(''), '')
|
||||
|
||||
# test replacements are done in order
|
||||
c.setReplacements([QgsStringReplacement('aa', '11'),
|
||||
QgsStringReplacement('11', '22')])
|
||||
self.assertEqual(c.process('string aa'), 'string 22')
|
||||
# no replacements
|
||||
c.setReplacements([])
|
||||
self.assertEqual(c.process('string aa'), 'string aa')
|
||||
|
||||
def testSaveRestore(self):
|
||||
""" test saving and restoring collections """
|
||||
c = QgsStringReplacementCollection([QgsStringReplacement('aa', '11', False, False),
|
||||
QgsStringReplacement('bb', '22', True, True)])
|
||||
doc = QDomDocument("testdoc")
|
||||
elem = doc.createElement("replacements")
|
||||
c.writeXml(elem, doc)
|
||||
c2 = QgsStringReplacementCollection()
|
||||
c2.readXml(elem)
|
||||
self.assertEqual(c2.replacements(), c.replacements())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user