265 changes: 265 additions & 0 deletions python/plugins/fTools/tools/doEliminate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
# -*- coding: utf-8 -*-
#-----------------------------------------------------------
#
# Eliminate for fTools
# Copyright (C) 2011 Bernhard Ströbl
# EMAIL: bernhard.stroebl@jena.de
#
# Eliminate sliver polygons
#
#-----------------------------------------------------------
#
# licensed under the terms of GNU GPL 2
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#---------------------------------------------------------------------

from PyQt4 import QtCore, QtGui
from qgis.core import *

import ftools_utils
from ui_frmEliminate import Ui_Dialog

class Dialog(QtGui.QDialog, Ui_Dialog):
def __init__(self, iface):
QtGui.QDialog.__init__(self)
self.iface = iface
# Set up the user interface from Designer.
self.setupUi(self)
QtCore.QObject.connect(self.toolOut, QtCore.SIGNAL("clicked()"), self.outFile)
QtCore.QObject.connect(self.inShape, QtCore.SIGNAL("currentIndexChanged(QString)"), self.update)
QtCore.QObject.connect(self.writeShapefileCheck, QtCore.SIGNAL("stateChanged(int)"), self.on_writeShapefileCheck_stateChanged)
self.setWindowTitle(self.tr("Eliminate sliver polygons"))
self.buttonOk = self.buttonBox_2.button(QtGui.QDialogButtonBox.Ok)
# populate layer list
self.progressBar.setValue(0)
self.area.setChecked(True)
layers = ftools_utils.getLayerNames([QGis.Polygon])
self.inShape.addItems(layers)

if len(layers) > 0:
self.update(layers[0])

self.on_writeShapefileCheck_stateChanged(self.writeShapefileCheck.checkState())

def update(self, inputLayer):
changedLayer = ftools_utils.getVectorLayerByName(inputLayer)
selFeatures = changedLayer.selectedFeatureCount()
self.selected.setText( self.tr("Selected features: %1").arg(selFeatures))

def on_writeShapefileCheck_stateChanged(self, newState):
doEnable = (newState == 2)
self.outShape.setEnabled(doEnable)
self.toolOut.setEnabled(doEnable)
self.addToCanvasCheck.setEnabled(doEnable)

def accept(self):
self.buttonOk.setEnabled(False)

if self.inShape.currentText() == "":
QtGui.QMessageBox.information(self, self.tr("Eliminate"), self.tr("No input shapefile specified"))
else:

if self.writeShapefileCheck.isChecked():
outFileName = self.outShape.text()

if outFileName == "":
QtGui.MessageBox.information(self, self.tr("Eliminate"), self.tr("Please specify output shapefile"))
else:
outFile = QtCore.QFile(outFileName)

if outFile.exists():
if not QgsVectorFileWriter.deleteShapeFile(outFileName):
QtGui.QMessageBox.warning(self, self.tr("Delete error"),
self.tr("Can't delete file %1").arg(outFileName))
return

outFileName = unicode(outFileName)
else:
outFileName = None

inLayer = ftools_utils.getVectorLayerByName(unicode(self.inShape.currentText()))

if inLayer.selectedFeatureCount() == 0:
QtGui.QMessageBox.information(self, self.tr("Eliminate"), self.tr("No selection in input layer"))
else:
self.progressBar.setValue(5)
boundary = self.boundary.isChecked()
self.eliminate(inLayer, boundary, self.progressBar, outFileName)
self.progressBar.setValue(100)
self.outShape.clear()

self.progressBar.setValue(0)
self.buttonOk.setEnabled(True)

def outFile(self):
self.outShape.clear()
(outFileName, self.encoding) = ftools_utils.saveDialog(self)
if outFileName is None or self.encoding is None:
return
self.outShape.setText(outFileName)

def eliminate(self, inLayer, boundary, progressBar, outFileName = None):
# keep references to the features to eliminate
fidsToEliminate = inLayer.selectedFeaturesIds()
fidsToProcess = inLayer.selectedFeaturesIds()

if outFileName: # user wants a new shape file to be created as result
provider = inLayer.dataProvider()
error = QgsVectorFileWriter.writeAsVectorFormat(inLayer, outFileName, provider.encoding(), inLayer.crs(), "ESRI Shapefile")

if error != QgsVectorFileWriter.NoError:
QtGui.QMessageBox.warning(self, self.tr("Eliminate"), self.tr("Error creating output file"))
return None

outLayer = QgsVectorLayer(outFileName, QtCore.QFileInfo(outFileName).completeBaseName(), "ogr")

else:
outLayer = inLayer
outLayer.removeSelection(False)

outLayer.startEditing()
doCommit = True

# ANALYZE
start = 20.00
progressBar.setValue(start)
add = 80.00 / len(fidsToEliminate)

lastLen = 0
geomsToMerge = dict()

# we go through the list and see if we find any polygons we can merge the selected with
# if we have no success with some we merge and then restart the whole story
while (lastLen != len(fidsToProcess)): #check if we made any progress
lastLen = len(fidsToProcess)
fidsNotEliminated = []
fidsToDelete = []

#iterate over the polygons to eliminate
for fid in fidsToProcess:
feat = QgsFeature()

if outLayer.featureAtId(fid, feat, True, False):
geom = feat.geometry()
bbox = geom.boundingBox()
outLayer.select(bbox, False) # make a new selection
mergeWithFid = None
mergeWithGeom = None
max = 0

for selFid in outLayer.selectedFeaturesIds():
if fid != selFid:
#check if this feature is to be eliminated, too
try:
found = fidsToEliminate.index(selFid)
except ValueError: #selFid is not in fidsToEliminate
# check wether the geometry to eliminate and the other geometry intersect
selFeat = QgsFeature()

if outLayer.featureAtId(selFid, selFeat, True, False):
selGeom = selFeat.geometry()

if geom.intersects(selGeom): # we have a candidate
iGeom = geom.intersection(selGeom)

if boundary:
selValue = iGeom.length()
else:
# we need a common boundary
if 0 < iGeom.length():
selValue = selGeom.area()
else:
selValue = 0

if selValue > max:
max = selValue
mergeWithFid = selFid
mergeWithGeom = QgsGeometry(selGeom) # deep copy of the geometry

if mergeWithFid: # a successful candidate
try:
geomList = geomsToMerge[mergeWithFid]
except KeyError:
geomList = [mergeWithGeom]

geomList.append(QgsGeometry(geom)) # deep copy of the geom
geomsToMerge[mergeWithFid] = geomList
fidsToDelete.append(fid)

start = start + add
progressBar.setValue(start)
else:
fidsNotEliminated.append(fid)

# PROCESS
for aFid in geomsToMerge.iterkeys():
geomList = geomsToMerge[aFid]

if len(geomList) > 1:
for i in range(len(geomList)):
aGeom = geomList[i]

if i == 0:
newGeom = aGeom
else:
newGeom = newGeom.combine(aGeom)

# replace geometry in outLayer
if not outLayer.changeGeometry(aFid, newGeom):
QtGui.QMessageBox.warning(self, self.tr("Eliminate"),
self.tr("Could not replace geometry of feature with id ") + str(aFid))
doCommit = False
break

# delete eliminated features
for aFid in fidsToDelete:
if not outLayer.deleteFeature(aFid):
QtGui.QMessageBox.warning(self, self.tr("Eliminate"),
self.tr("Could not delete feature with id ") + str(aFid))
doCommit = False
break
# prepare array for the next loop
fidsToProcess = fidsNotEliminated

# SAVE CHANGES
if doCommit:
if not outLayer.commitChanges():
QtGui.QMessageBox.warning(self, self.tr("Commit error"), self.tr("Commit Error"))
else:
outLayer.rollBack()

if outFileName:
if self.addToCanvasCheck.isChecked():
ftools_utils.addShapeToCanvas(outFileName)
else:
QtGui.QMessageBox.information(self, self.tr("Eliminate"),
self.tr("Created output shapefile:\n%1").arg(outFileName))

# inform user
if len(fidsNotEliminated) > 0:
fidList = QtCore.QString()

for fid in fidsNotEliminated:
if not fidList.isEmpty():
fidList.append(", ")

fidList.append(str(fid))

QtGui.QMessageBox.information(self, self.tr("Eliminate"),
self.tr("Could not eliminate features with these ids:\n%1").arg(fidList))

self.iface.mapCanvas().refresh()
2 changes: 1 addition & 1 deletion python/plugins/fTools/tools/doGeoprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def populateLayers( self ):
self.inShapeB.clear()

if self.myFunction == 4:
myListA = ftools_utils.getLayerNames( [ QGis.Polygon ] )
myListA = ftools_utils.getLayerNames( [ QGis.Line, QGis.Polygon ] )
myListB = []
else:
myListA = ftools_utils.getLayerNames( [ QGis.Point, QGis.Line, QGis.Polygon ] )
Expand Down
144 changes: 144 additions & 0 deletions python/plugins/fTools/tools/frmEliminate.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>377</width>
<height>243</height>
</rect>
</property>
<property name="windowTitle">
<string>Eliminate sliver polygons</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QRadioButton" name="area">
<property name="text">
<string>area</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="selected">
<property name="text">
<string>Selected features:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Input vector layer</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QRadioButton" name="boundary">
<property name="text">
<string>common boundary</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>Merge selection with the neighbouring polygon with the largest</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="inShape"/>
</item>
<item row="6" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="writeShapefileCheck">
<property name="text">
<string>Save to new file</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="outShape">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolOut">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="addToCanvasCheck">
<property name="text">
<string>Add result to canvas</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QDialogButtonBox" name="buttonBox_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox_2</sender>
<signal>accepted()</signal>
<receiver>Dialog</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_2</sender>
<signal>rejected()</signal>
<receiver>Dialog</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>
2 changes: 1 addition & 1 deletion python/plugins/sextante/saga/SagaAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def processAlgorithm(self, progress):
if value in self.exportedLayers.keys():
command+=(" -" + param.name + " \"" + self.exportedLayers[value] + "\"")
else:
command+=(" -" + param.name + " " + value)
command+=(" -" + param.name + " \"" + value + "\"")
elif isinstance(param, ParameterMultipleInput):
s = param.value
for layer in self.exportedLayers.keys():
Expand Down
40 changes: 39 additions & 1 deletion src/app/qgslabelinggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
chkPlusSign->setChecked( plusSign );
}

// set pixel size limiting checked state before unit choice so limiting can be
// turned on as a default for map units, if minimum trigger value of 0 is used
mFontLimitPixelGroupBox->setChecked( lyr.fontLimitPixelSize );
mMinPixelLimit = lyr.fontMinPixelSize; // ignored after first settings save
mFontMinPixelSpinBox->setValue( lyr.fontMinPixelSize == 0 ? 3 : lyr.fontMinPixelSize );
mFontMaxPixelSpinBox->setValue( lyr.fontMaxPixelSize );
if ( lyr.fontSizeInMapUnits )
{
mFontSizeUnitComboBox->setCurrentIndex( 1 );
Expand Down Expand Up @@ -465,6 +471,9 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
}
lyr.minFeatureSize = mMinSizeSpinBox->value();
lyr.fontSizeInMapUnits = ( mFontSizeUnitComboBox->currentIndex() == 1 );
lyr.fontLimitPixelSize = mFontLimitPixelGroupBox->isChecked();
lyr.fontMinPixelSize = mFontMinPixelSpinBox->value();
lyr.fontMaxPixelSize = mFontMaxPixelSpinBox->value();
lyr.wrapChar = wrapCharacterEdit->text();
lyr.multilineHeight = mFontLineHeightSpinBox->value();
lyr.multilineAlign = ( QgsPalLayerSettings::MultiLineAlign ) mFontMultiLineComboBox->currentIndex();
Expand Down Expand Up @@ -1004,10 +1013,39 @@ void QgsLabelingGui::on_mFontLetterSpacingSpinBox_valueChanged( double spacing )

void QgsLabelingGui::on_mFontSizeUnitComboBox_currentIndexChanged( int index )
{
Q_UNUSED( index );
// disable pixel size limiting for labels defined in points
if ( index == 0 )
{
mFontLimitPixelGroupBox->setChecked( false );
}
else if ( index == 1 && mMinPixelLimit == 0 )
{
// initial minimum trigger value set, turn on pixel size limiting by default
// for labels defined in map units (ignored after first settings save)
mFontLimitPixelGroupBox->setChecked( true );
}
updateFont( mRefFont );
}

void QgsLabelingGui::on_mFontMinPixelSpinBox_valueChanged( int px )
{
// ensure max font pixel size for map unit labels can't be lower than min
mFontMaxPixelSpinBox->setMinimum( px );
mFontMaxPixelSpinBox->update();
}

void QgsLabelingGui::on_mFontMaxPixelSpinBox_valueChanged( int px )
{
// ensure max font pixel size for map unit labels can't be lower than min
if ( px < mFontMinPixelSpinBox->value() )
{
mFontMaxPixelSpinBox->blockSignals( true );
mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() );
mFontMaxPixelSpinBox->blockSignals( false );
}
mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() );
}

void QgsLabelingGui::on_mBufferUnitComboBox_currentIndexChanged( int index )
{
Q_UNUSED( index );
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgslabelinggui.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
void on_mFontWordSpacingSpinBox_valueChanged( double spacing );
void on_mFontLetterSpacingSpinBox_valueChanged( double spacing );
void on_mFontSizeUnitComboBox_currentIndexChanged( int index );
void on_mFontMinPixelSpinBox_valueChanged( int px );
void on_mFontMaxPixelSpinBox_valueChanged( int px );
void on_mBufferUnitComboBox_currentIndexChanged( int index );
void on_mXCoordinateComboBox_currentIndexChanged( const QString & text );
void on_mYCoordinateComboBox_currentIndexChanged( const QString & text );
Expand Down Expand Up @@ -95,6 +97,7 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase

int mXQuadOffset;
int mYQuadOffset;
int mMinPixelLimit;

void disableDataDefinedAlignment();
void enableDataDefinedAlignment();
Expand Down
62 changes: 41 additions & 21 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ QgsPalLayerSettings::QgsPalLayerSettings()
addDirectionSymbol = false;
upsidedownLabels = Upright;
fontSizeInMapUnits = false;
fontLimitPixelSize = false;
fontMinPixelSize = 0; //trigger to turn it on by default for map unit labels
fontMaxPixelSize = 10000;
bufferSizeInMapUnits = false;
labelOffsetInMapUnits = true;
distInMapUnits = false;
Expand Down Expand Up @@ -265,6 +268,9 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
addDirectionSymbol = s.addDirectionSymbol;
upsidedownLabels = s.upsidedownLabels;
fontSizeInMapUnits = s.fontSizeInMapUnits;
fontLimitPixelSize = s.fontLimitPixelSize;
fontMinPixelSize = s.fontMinPixelSize;
fontMaxPixelSize = s.fontMaxPixelSize;
bufferSizeInMapUnits = s.bufferSizeInMapUnits;
distInMapUnits = s.distInMapUnits;
labelOffsetInMapUnits = s.labelOffsetInMapUnits;
Expand Down Expand Up @@ -448,6 +454,9 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
upsidedownLabels = ( UpsideDownLabels ) layer->customProperty( "labeling/upsidedownLabels", QVariant( Upright ) ).toUInt();
minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool();
fontLimitPixelSize = layer->customProperty( "labeling/fontLimitPixelSize", QVariant( false ) ).toBool();
fontMinPixelSize = layer->customProperty( "labeling/fontMinPixelSize", QVariant( 0 ) ).toInt();
fontMaxPixelSize = layer->customProperty( "labeling/fontMaxPixelSize", QVariant( 10000 ) ).toInt();
bufferSizeInMapUnits = layer->customProperty( "labeling/bufferSizeInMapUnits" ).toBool();
distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
labelOffsetInMapUnits = layer->customProperty( "labeling/labelOffsetInMapUnits", QVariant( true ) ).toBool();
Expand Down Expand Up @@ -509,6 +518,9 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/upsidedownLabels", ( unsigned int )upsidedownLabels );
layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
layer->setCustomProperty( "labeling/fontLimitPixelSize", fontLimitPixelSize );
layer->setCustomProperty( "labeling/fontMinPixelSize", fontMinPixelSize );
layer->setCustomProperty( "labeling/fontMaxPixelSize", fontMaxPixelSize );
layer->setCustomProperty( "labeling/bufferSizeInMapUnits", bufferSizeInMapUnits );
layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
layer->setCustomProperty( "labeling/labelOffsetInMapUnits", labelOffsetInMapUnits );
Expand Down Expand Up @@ -658,6 +670,33 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
}
}

QFont labelFont = textFont;

//data defined label size?
QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size );
if ( it != dataDefinedProperties.constEnd() )
{
//find out size
QVariant size = f.attributeMap().value( *it );
if ( size.isValid() )
{
double sizeDouble = size.toDouble();
if ( sizeDouble <= 0.0 || sizeToPixel( sizeDouble, context ) < 1 )
{
return;
}
labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) );
}
}

// defined 'minimum/maximum pixel font size' option
// TODO: add any data defined setting to override fontMinPixelSize/fontMaxPixelSize
if ( fontLimitPixelSize && fontSizeInMapUnits &&
( fontMinPixelSize > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixelSize ) )
{
return;
}

QString labelText;

// Check to see if we are a expression string.
Expand Down Expand Up @@ -695,28 +734,9 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
labelText = f.attributeMap()[fieldIndex].toString();
}

double labelX, labelY; // will receive label size
QFont labelFont = textFont;

//data defined label size?
QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size );
if ( it != dataDefinedProperties.constEnd() )
{
//find out size
QVariant size = f.attributeMap().value( *it );
if ( size.isValid() )
{
double sizeDouble = size.toDouble();
if ( sizeDouble <= 0.0 || sizeToPixel( sizeDouble, context ) < 1 )
{
return;
}
labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) );
}
}

// this should come after any data defined option that affects font metrics
// this should come AFTER any data defined option that affects font metrics
QFontMetricsF* labelFontMetrics = new QFontMetricsF( labelFont );
double labelX, labelY; // will receive label size
calculateLabelSize( labelFontMetrics, labelText, labelX, labelY );

QgsGeometry* geom = f.geometry();
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgspallabeling.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ class CORE_EXPORT QgsPalLayerSettings
bool addDirectionSymbol;
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
int fontMinPixelSize; // minimum pixel size for showing rendered map unit labels (1 - 1000)
int fontMaxPixelSize; // maximum pixel size for showing rendered map unit labels (1 - 10000)
bool bufferSizeInMapUnits; //true if buffer is in map units (otherwise in mm)
bool labelOffsetInMapUnits; //true if label offset is in map units (otherwise in mm)
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
Expand Down
6 changes: 6 additions & 0 deletions src/gui/qgsrubberband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,12 @@ void QgsRubberBand::addGeometry( QgsGeometry* geom, QgsVectorLayer* layer )
for ( int i = 0; i < mline.size(); ++i, ++idx )
{
QgsPolyline line = mline[i];

if ( line.size() == 0 )
{
--idx;
}

for ( int j = 0; j < line.size(); ++j )
{
if ( layer )
Expand Down
4 changes: 2 additions & 2 deletions src/gui/symbology-ng/qgsellipsesymbollayerv2widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ void QgsEllipseSymbolLayerV2Widget::on_btnChangeColorBorder_clicked()
{
if ( mLayer )
{
QColor newColor = QColorDialog::getColor( mLayer->outlineColor() );
QColor newColor = QColorDialog::getColor( mLayer->outlineColor(), this, "", QColorDialog::ShowAlphaChannel );
if ( newColor.isValid() )
{
mLayer->setOutlineColor( newColor );
Expand All @@ -205,7 +205,7 @@ void QgsEllipseSymbolLayerV2Widget::on_btnChangeColorFill_clicked()
{
if ( mLayer )
{
QColor newColor = QColorDialog::getColor( mLayer->fillColor() );
QColor newColor = QColorDialog::getColor( mLayer->fillColor(), this, "", QColorDialog::ShowAlphaChannel );
if ( newColor.isValid() )
{
mLayer->setFillColor( newColor );
Expand Down
447 changes: 341 additions & 106 deletions src/ui/qgslabelingguibase.ui

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ ADD_PYTHON_TEST(PyQgsPoint test_qgspoint.py)
ADD_PYTHON_TEST(PyQgsAtlasComposition test_qgsatlascomposition.py)
ADD_PYTHON_TEST(PyQgsComposerLabel test_qgscomposerlabel.py)
#ADD_PYTHON_TEST(PyQgsPalLabeling test_qgspallabeling.py)
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)
12 changes: 12 additions & 0 deletions tests/src/python/test_qgsmemoryprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,17 @@ def testAddFeatures(self):

assert str(geom.exportToWkt()) == "POINT(10.0 10.0)", myMessage

def testFromUri(self):
"""Test we can construct the mem provider from a uri"""
myMemoryLayer = QgsVectorLayer(
('Point?crs=epsg:4326&field=name:string(20)&'
'field=age:integer&field=size:double&index=yes'),
'test',
'memory')

assert myMemoryLayer is not None, 'Provider not initialised'
myProvider = myMemoryLayer.dataProvider()
assert myProvider is not None

if __name__ == '__main__':
unittest.main()
88 changes: 88 additions & 0 deletions tests/src/python/test_qgsvectorfilewriter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsVectorFileWriter.
.. 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__ = 'Tim Sutton'
__date__ = '20/08/2012'
__copyright__ = 'Copyright 2012, The Quantum GIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import os

from PyQt4.QtCore import QVariant, QDir, QString, QStringList

from qgis.core import (QgsVectorLayer,
QgsFeature,
QgsField,
QgsGeometry,
QgsPoint,
QgsVectorFileWriter,
QgsCoordinateReferenceSystem)

from utilities import (unitTestDataPath,
getQgisTestApp,
TestCase,
unittest,
#expectedFailure
)
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()


class TestQgsVectorLayer(TestCase):

mMemoryLayer = None

def setUp(self):
self.mMemoryLayer = QgsVectorLayer(
('Point?crs=epsg:4326&field=name:string(20)&'
'field=age:integer&field=size:double&index=yes'),
'test',
'memory')

assert self.mMemoryLayer is not None, 'Provider not initialised'
myProvider = self.mMemoryLayer.dataProvider()
assert myProvider is not None

ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10,10)))
ft.setAttributeMap({0 : QVariant('Johny'),
1 : QVariant(20),
2 : QVariant(0.3)})
myResult, myFeatures = myProvider.addFeatures([ft])
assert myResult == True
assert len(myFeatures) > 0


def testWrite(self):
"""Check we can write a vector file."""

myFileName = os.path.join(str(QDir.tempPath()), 'writetest.shp')
print myFileName
# Explicitly giving all options, not really needed but nice for clarity
myErrorMessage = QString()
myOptions = QStringList()
myLayerOptions = QStringList()
mySelectedOnlyFlag = False
mySkipAttributesFlag = False
myGeoCrs = QgsCoordinateReferenceSystem()
myGeoCrs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
myResult = QgsVectorFileWriter.writeAsVectorFormat(
self.mMemoryLayer,
myFileName,
'utf-8',
myGeoCrs,
'ESRI Shapefile',
mySelectedOnlyFlag,
myErrorMessage,
myOptions,
myLayerOptions,
mySkipAttributesFlag)
assert myResult==True

if __name__ == '__main__':
unittest.main()
1 change: 1 addition & 0 deletions tests/src/python/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,4 @@ def setCanvasCrs(theEpsgId, theOtfpFlag=False):
# Reproject all layers to WGS84 geographic CRS
CANVAS.mapRenderer().setDestinationCrs(myCrs)