78 changes: 39 additions & 39 deletions doc/TRANSLATORS

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion doc/overview.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ Required build deps:
- Sqlite3 >= 3.0.0
- GDAL/OGR >= 1.4.x
- Qwt >= 5.0
- expat >= 1.95
-

Optional dependencies:

- for GRASS plugin - GRASS >= 6.0.0 (libraries compiled with exceptions support on Linux 32bit)
- for georeferencer - GSL >= 1.8
- for postgis support and SPIT plugin - PostgreSQL >= 8.0.x
- for gps plugin - expat >= 1.95 and gpsbabel
- for gps plugin - gpsbabel
- for mapserver export and PyQGIS - Python >= 2.3 (2.5+ preferred)
- for python support - SIP >= 4.8, PyQt >= must match Qt version, Qscintilla2
- for qgis mapserver - FastCGI
Expand Down
2,806 changes: 1,172 additions & 1,634 deletions i18n/qgis_de.ts

Large diffs are not rendered by default.

6,341 changes: 3,818 additions & 2,523 deletions i18n/qgis_gl_ES.ts

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion python/console/console_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def __init__(self, edit, out=None, style=None):

def write(self, m):
if self.style == "traceback":
self.outputArea.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
# Show errors in red
pos = self.outputArea.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)
self.outputArea.SendScintilla(QsciScintilla.SCI_STARTSTYLING, pos, 31)
self.outputArea.append(m)
self.outputArea.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
else:
Expand Down
4 changes: 4 additions & 0 deletions python/core/qgsapplication.sip
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ static void qtgui_UpdatePyArgv(PyObject *argvlist, int argc, char **argv)
//! @note added in 1.4
static const QStringList svgPaths();

//! Returns the system environment variables passed to application.
//! @note added in 1.9
static const QMap<QString, QString> systemEnvVars();

//! Returns the path to the application prefix directory.
static const QString prefixPath();

Expand Down
3 changes: 3 additions & 0 deletions python/core/qgsmaplayerregistry.sip
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class QgsMapLayerRegistry : QObject
//! Retrieve a pointer to a loaded layer by id
QgsMapLayer *mapLayer( QString theLayerId );

//! Retrieve all layers using their name
QList<QgsMapLayer *> mapLayersByName( QString layerName );

//! Retrieve the mapLayers collection (mainly intended for use by projection)
QMap<QString, QgsMapLayer*> & mapLayers();

Expand Down
7 changes: 5 additions & 2 deletions python/core/qgsvectorlayerimport.sip
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class QgsVectorLayerImport
%TypeHeaderCode
#include <qgsvectorlayerimport.h>
#include <qgsfield.h>
class QProgressDialog;
%End

public:
Expand Down Expand Up @@ -37,7 +38,8 @@ class QgsVectorLayerImport
bool onlySelected = false,
QString *errorMessage /Out/ = 0,
bool skipAttributeCreation = false,
QMap<QString, QVariant> *options = 0
QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** create a empty layer and add fields to it */
Expand All @@ -47,7 +49,8 @@ class QgsVectorLayerImport
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite = false,
const QMap<QString, QVariant> *options = 0
const QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** checks whether there were any errors */
Expand Down
9 changes: 4 additions & 5 deletions python/plugins/GdalTools/tools/dialogSRS.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,17 @@ def __init__(self, title, parent=None):
self.connect(buttonBox, SIGNAL("accepted()"), self.accept)
self.connect(buttonBox, SIGNAL("rejected()"), self.reject)

def epsg(self):
return "EPSG:" + str(self.selector.selectedEpsg())
def authid(self):
return str(self.selector.selectedAuthId())

def proj4string(self):
return self.selector.selectedProj4String()

def getProjection(self):
if self.selector.selectedEpsg() != 0:
return self.epsg()
if self.authid().startsWith("EPSG:", Qt.CaseInsensitive):
return self.authid()

if not self.selector.selectedProj4String().isEmpty():
return self.proj4string()

return QString()

Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def run(item, action, mainwindow):
# face
layer = db.toSqlLayer(u'SELECT face_id, topology.ST_GetFaceGeometry(%s, face_id) as geom ' \
'FROM %s.face WHERE face_id > 0' % (quoteStr(toponame), quoteId(toponame)),
'geom', 'face_id', u'geom')
'geom', 'face_id', u'%s.face' % toponame)
layer.loadNamedStyle(os.path.join(template_dir, 'face.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -117,7 +117,7 @@ def run(item, action, mainwindow):
# face_seed
layer = db.toSqlLayer(u'SELECT face_id, ST_PointOnSurface(topology.ST_GetFaceGeometry(%s, face_id)) as geom ' \
'FROM %s.face WHERE face_id > 0' % (quoteStr(toponame), quoteId(toponame)),
'geom', 'face_id', u'seed')
'geom', 'face_id', u'%s.face_seed' % toponame)
layer.loadNamedStyle(os.path.join(template_dir, 'face_seed.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -134,7 +134,7 @@ def run(item, action, mainwindow):

# node
uri.setDataSource(toponame, 'node', 'geom', '', 'node_id')
layer = QgsVectorLayer(uri.uri(), u'geom', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.node' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'node.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -143,7 +143,7 @@ def run(item, action, mainwindow):

# node labels
uri.setDataSource(toponame, 'node', 'geom', '', 'node_id')
layer = QgsVectorLayer(uri.uri(), u'node_id', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.node_id' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'node_label.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -157,15 +157,15 @@ def run(item, action, mainwindow):

# edge
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'geom', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.edge' % toponame, provider)
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
legend.setLayerExpanded(layer, False)
legend.moveLayer(layer, group)

# directed edge
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'directed_geom', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.directed_edge' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'edge.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -175,7 +175,7 @@ def run(item, action, mainwindow):

# edge labels
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'edge_id', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.edge_id' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'edge_label.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -184,7 +184,7 @@ def run(item, action, mainwindow):

# face_left
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'face_left', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.face_left' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'face_left.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -193,7 +193,7 @@ def run(item, action, mainwindow):

# face_right
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'face_right', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.face_right' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'face_right.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -202,7 +202,7 @@ def run(item, action, mainwindow):

# next_left
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'next_left', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.next_left' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'next_left.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -211,7 +211,7 @@ def run(item, action, mainwindow):

# next_right
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'next_right', provider)
layer = QgsVectorLayer(uri.uri(), u'%s.next_right' % toponame, provider)
layer.loadNamedStyle(os.path.join(template_dir, 'next_right.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/db_manager/layer_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ def _loadTablePreview(self, table, limit=False):
if not vl.isValid():
self.setLayerSet( [] )
else:
newLayerId = vl.id() if hasattr(vl, 'id') else vl.getLayerID()
newLayerId = vl.id() if hasattr(vl, 'id') else vl.id()
self.setLayerSet( [ QgsMapCanvasLayer(vl) ] )
QgsMapLayerRegistry.instance().addMapLayers([vl], False)
self.zoomToFullExtent()

# remove old layer (if any) and set new
if self.currentLayerId:
QgsMapLayerRegistry.instance().removeMapLayer(self.currentLayerId, False)
QgsMapLayerRegistry.instance().removeMapLayers([self.currentLayerId], False)
self.currentLayerId = newLayerId

self.setRenderFlag(True)
Expand Down
3 changes: 2 additions & 1 deletion python/plugins/fTools/tools/doGeometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ def simpleMeasure( self, inGeom, calcType, ellips, crs ):
if calcType == 2:
measure.setSourceCrs( crs )
measure.setEllipsoid( ellips )
measure.setProjectionsEnabled( True )
measure.setEllipsoidalMode( True )

attr1 = measure.measure( inGeom )
if inGeom.type() == QGis.Polygon:
Expand Down Expand Up @@ -1174,6 +1174,7 @@ def findOrCreateFields( self, vlayer ):
else:
index2 = len( fieldKeys ) + 1
newFields.append( field )
# FIXME: addAttributes was deprecated and removed
vprovider.addAttributes( newFields )
vlayer.updateFieldMap()
return ( index1, index2 )
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/fTools/tools/doRandPoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def accept(self):
self.tr("Created output point shapefile:\n%1\n\nWould you like to add the new layer to the TOC?").arg(outPath), QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
if addToTOC == QMessageBox.Yes:
self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
QgsMapLayerRegistry.instance().addMapLayer([self.vlayer])
QgsMapLayerRegistry.instance().addMapLayers([self.vlayer])
self.populateLayers()
self.progressBar.setValue(0)
self.buttonOk.setEnabled( True )
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/fTools/tools/doRegPoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def accept(self):
addToTOC = QMessageBox.question(self, self.tr("Generate Regular Points"), self.tr("Created output point shapefile:\n%1\n\nWould you like to add the new layer to the TOC?").arg( outPath ), QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
if addToTOC == QMessageBox.Yes:
self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
QgsMapLayerRegistry.instance().addMapLayer([self.vlayer])
QgsMapLayerRegistry.instance().addMapLayers([self.vlayer])
self.populateLayers()
self.progressBar.setValue(0)
self.buttonOk.setEnabled( True )
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/fTools/tools/doSpatialJoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def accept(self):
.arg(unicode(outPath)), QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
if addToTOC == QMessageBox.Yes:
self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
QgsMapLayerRegistry.instance().addMapLayer([self.vlayer])
QgsMapLayerRegistry.instance().addMapLayers([self.vlayer])
self.progressBar.setValue(0)
self.buttonOk.setEnabled( True )

Expand Down
2 changes: 1 addition & 1 deletion python/plugins/fTools/tools/ftools_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def writeVectorLayerToShape( vlayer, outputPath, encoding ):
if not mCodec:
return False
#Here we should check that the output path is valid
QgsVectorFileWriter.writeAsShapefile( vlayer, outputPath, encoding, vlayer.dataProvider().crs(), False )
QgsVectorFileWriter.writeAsVectorFormat( vlayer, outputPath, encoding, vlayer.dataProvider().crs(), "ESRI Shapefile", False )
return True

# For use with memory provider/layer, converts QGis vector type definition to simple string
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/osm/OsmLoadDlg.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def onOK(self):

if replacing:
# remove layers of current data first
QgsMapLayerRegistry.instance().removeMapLayer(self.canvas.currentLayer().id(),True)
QgsMapLayerRegistry.instance().removeMapLayers([self.canvas.currentLayer().id()],True)

if self.chkCustomRenderer.isChecked():
styleFile=self.styleFiles[self.styleCombo.currentIndex()]
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/sextante/algs/ftools/ExportGeometryInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def simpleMeasure(self, geom, method, ellips, crs):
if method == 2:
measure.setSourceCrs(crs)
measure.setEllipsoid(ellips)
measure.setProjectionsEnabled(True)
measure.setEllipsoidalMode(True)

attr1 = measure.measure(geom)
if geom.type() == QGis.Polygon:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/sextante/algs/ftools/ftools_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def writeVectorLayerToShape( vlayer, outputPath, encoding ):
if not mCodec:
return False
#Here we should check that the output path is valid
QgsVectorFileWriter.writeAsShapefile( vlayer, outputPath, encoding, vlayer.dataProvider().crs(), False )
QgsVectorFileWriter.writeAsVectorFormat( vlayer, outputPath, encoding, vlayer.dataProvider().crs(), "ESRI Shapefile", False )
return True

# For use with memory provider/layer, converts QGis vector type definition to simple string
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/sextante/algs/mmqgisx/mmqgisx_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ def mmqgisx_hub_distance(progress, sourcelayer, hubslayer, nameattributename, un
source = feature.geometry().boundingBox().center()
distance = QgsDistanceArea()
distance.setSourceCrs(sourcelayer.dataProvider().crs().srsid())
distance.setProjectionsEnabled(1)
distance.setEllipsoidalMode(True)

closest = hubs[0]
hubdist = distance.measureLine(source, closest.point)
Expand Down
1 change: 1 addition & 0 deletions python/plugins/sextante/core/SextanteVectorWriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def __init__(self, fileName, encoding, fields, geometryType, crs, options=None):
uri += "?crs=" + crs.authid()
self.memLayer = QgsVectorLayer(uri, self.fileName, "memory")
self.writer = self.memLayer.dataProvider()
# FIXME: addAttributes was deprecated and removed
self.writer.addAttributes(fields.values())
self.memLayer.updateFieldMap()
else:
Expand Down
8 changes: 4 additions & 4 deletions python/plugins/sextante/gdal/warp.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def defineCharacteristics(self):
self.name = "Warp (reproject)"
self.group = "[GDAL] Projections"
self.addParameter(ParameterRaster(warp.INPUT, "Input layer", False))
self.addParameter(ParameterCrs(warp.SOURCE_SRS, "Source SRS (EPSG Code)", "4326"))
self.addParameter(ParameterCrs(warp.DEST_SRS, "Destination SRS (EPSG Code)", "4326"))
self.addParameter(ParameterCrs(warp.SOURCE_SRS, "Source SRS (EPSG Code)", "EPSG:4326"))
self.addParameter(ParameterCrs(warp.DEST_SRS, "Destination SRS (EPSG Code)", "EPSG:4326"))
self.addParameter(ParameterSelection(warp.METHOD, "Resampling method", warp.METHOD_OPTIONS))
self.addOutput(OutputRaster(warp.OUTPUT, "Output layer"))

Expand All @@ -60,9 +60,9 @@ def processAlgorithm(self, progress):
self.crs = QgsCoordinateReferenceSystem(int(srs))
commands = ["gdalwarp"]
commands.append("-s_srs")
commands.append("EPSG:" + str(self.getParameterValue(warp.SOURCE_SRS)))
commands.append(str(self.getParameterValue(warp.SOURCE_SRS)))
commands.append("-t_srs")
commands.append("EPSG:" + str(srs))
commands.append(str(srs))
commands.append("-r")
commands.append(warp.METHOD_OPTIONS[self.getParameterValue(warp.METHOD)])
commands.append("-of")
Expand Down
8 changes: 4 additions & 4 deletions python/plugins/sextante/gui/CrsSelectionDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class CrsSelectionDialog(QDialog):

def __init__(self):
QDialog.__init__(self)
self.epsg = None
self.authid = None
layout = QVBoxLayout()
self.selector = QgsProjectionSelector(self)
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close)
Expand All @@ -44,9 +44,9 @@ def __init__(self):
self.connect(buttonBox, SIGNAL("rejected()"), self.cancelPressed)

def okPressed(self):
self.epsg = self.selector.selectedEpsg()
self.authid = self.selector.selectedAuthId()
self.close()

def cancelPressed(self):
self.epsg = None
self.close()
self.authid = None
self.close()
10 changes: 5 additions & 5 deletions python/plugins/sextante/gui/CrsSelectionPanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CrsSelectionPanel(QtGui.QWidget):

def __init__(self, default):
super(CrsSelectionPanel, self).__init__(None)
self.epsg = default
self.authid = default
self.horizontalLayout = QtGui.QHBoxLayout(self)
self.horizontalLayout.setSpacing(2)
self.horizontalLayout.setMargin(0)
Expand All @@ -48,12 +48,12 @@ def __init__(self, default):
def showSelectionDialog(self):
dialog = CrsSelectionDialog()
dialog.exec_()
if dialog.epsg:
self.epsg = str(dialog.epsg)
if dialog.authid:
self.authid = str(dialog.authid)
self.setText()

def setText(self):
self.text.setText("EPSG:" + str(self.epsg))
self.text.setText(str(self.authid))

def getValue(self):
return self.epsg
return self.authid
4 changes: 2 additions & 2 deletions python/plugins/sextante/parameters/ParameterCrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@

class ParameterCrs(Parameter):

def __init__(self, name="", description="", default = "4326"):
'''The value is the EPSG code of the CRS'''
def __init__(self, name="", description="", default = "EPSG:4326"):
'''The value is the auth id of the CRS'''
Parameter.__init__(self, name, description)
self.value = None
self.default = default
Expand Down
3 changes: 1 addition & 2 deletions python/plugins/sextante/tests/qgis_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ def __init__(self, canvas):
self.canvas = canvas
self.testRaster = QgsRasterLayer('data/raster', "raster")
self.testVector = QgsVectorLayer('data/vector', "vector", 'ogr')
QgsMapLayerRegistry.instance().addMapLayer(self.testRaster)
QgsMapLayerRegistry.instance().addMapLayer(self.testVector)
QgsMapLayerRegistry.instance().addMapLayers([self.testRaster,self.testVector])

self.statusBar = type('FakeStatusBar', (),
{'showMessage' : lambda _, m: None
Expand Down
4 changes: 2 additions & 2 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ SET(QGIS_APP_SRCS
qgsmeasuretool.cpp
qgsmergeattributesdialog.cpp
qgsoptions.cpp
qgspastetransformations.cpp
#qgspastetransformations.cpp
qgspointrotationitem.cpp
qgspluginitem.cpp
qgspluginmanager.cpp
Expand Down Expand Up @@ -244,7 +244,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmeasuretool.h
qgsmergeattributesdialog.h
qgsoptions.h
qgspastetransformations.h
#qgspastetransformations.h
qgspluginmanager.h
qgsprojectlayergroupdialog.h
qgsprojectproperties.h
Expand Down
2 changes: 1 addition & 1 deletion src/app/legend/qgslegendlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ void QgsLegendLayer::addToPopupMenu( QMenu& theMenu )
}

if ( !vlayer->isEditable() && vlayer->dataProvider()->supportsSubsetString() && vlayer->vectorJoins().isEmpty() )
theMenu.addAction( tr( "&Query..." ), QgisApp::instance(), SLOT( layerSubsetString() ) );
theMenu.addAction( tr( "&Filter..." ), QgisApp::instance(), SLOT( layerSubsetString() ) );

//show number of features in legend if requested
QAction* showNFeaturesAction = new QAction( tr( "Show Feature Count" ), &theMenu );
Expand Down
54 changes: 54 additions & 0 deletions src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,60 @@ int main( int argc, char *argv[] )

QSettings mySettings;

// custom environment variables
QMap<QString, QString> systemEnvVars = QgsApplication::systemEnvVars();
bool useCustomVars = mySettings.value( "qgis/customEnvVarsUse", QVariant( false ) ).toBool();
if ( useCustomVars )
{
QStringList customVarsList = mySettings.value( "qgis/customEnvVars", "" ).toStringList();
if ( !customVarsList.isEmpty() )
{
foreach ( const QString &varStr, customVarsList )
{
int pos = varStr.indexOf( QLatin1Char( '|' ) );
if ( pos == -1 )
continue;
QString envVarApply = varStr.left( pos );
QString varStrNameValue = varStr.mid( pos + 1 );
pos = varStrNameValue.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QString envVarName = varStrNameValue.left( pos );
QString envVarValue = varStrNameValue.mid( pos + 1 );

if ( systemEnvVars.contains( envVarName ) )
{
if ( envVarApply == "prepend" )
{
envVarValue += systemEnvVars.value( envVarName );
}
else if ( envVarApply == "append" )
{
envVarValue = systemEnvVars.value( envVarName ) + envVarValue;
}
}

if ( systemEnvVars.contains( envVarName ) && envVarApply == "unset" )
{
#ifdef Q_WS_WIN
putenv( envVarName.toUtf8().constData() );
#else
unsetenv( envVarName.toUtf8().constData() );
#endif
}
else
{
#ifdef Q_WS_WIN
if ( envVarApply != "undefined" || !getenv( envVarName.toUtf8().constData() ) )
putenv( QString( "%1=%2" ).arg( envVarName ).arg( envVarValue ).toUtf8().constData() );
#else
setenv( envVarName.toUtf8().constData(), envVarValue.toUtf8().constData(), envVarApply == "undefined" ? 0 : 1 );
#endif
}
}
}
}

// Set the application style. If it's not set QT will use the platform style except on Windows
// as it looks really ugly so we use QPlastiqueStyle.
QString style = mySettings.value( "/qgis/style" ).toString();
Expand Down
12 changes: 8 additions & 4 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
#include "qgsmultibandcolorrenderer.h"
#include "qgsnewvectorlayerdialog.h"
#include "qgsoptions.h"
#include "qgspastetransformations.h"
// #include "qgspastetransformations.h"
#include "qgspluginitem.h"
#include "qgspluginlayer.h"
#include "qgspluginlayerregistry.h"
Expand Down Expand Up @@ -3330,11 +3330,12 @@ bool QgisApp::addProject( QString projectFile )

if ( ! QgsProject::instance()->read( projectFile ) )
{
QApplication::restoreOverrideCursor();

QMessageBox::critical( this,
tr( "Unable to open project" ),
QgsProject::instance()->error() );

QApplication::restoreOverrideCursor();

mMapCanvas->freeze( false );
mMapCanvas->refresh();
Expand Down Expand Up @@ -4964,11 +4965,13 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )

QHash<int, int> remap;
const QgsFieldMap &fields = clipboard()->fields();
QgsAttributeList pkAttrList = pasteVectorLayer->pendingPkAttributesList();
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); it++ )
{
int dst = pasteVectorLayer->fieldNameIndex( it->name() );
if ( dst < 0 )
if ( dst < 0 || pkAttrList.contains( dst ) )
{
// skip primary key attributes
continue;
}
remap.insert( it.key(), dst );
Expand Down Expand Up @@ -5064,6 +5067,7 @@ void QgisApp::pasteStyle( QgsMapLayer * destinationLayer )
}
}

#if 0
void QgisApp::pasteTransformations()
{
QgsPasteTransformations *pt = new QgsPasteTransformations();
Expand All @@ -5072,7 +5076,7 @@ void QgisApp::pasteTransformations()

pt->exec();
}

#endif

void QgisApp::refreshMapCanvas()
{
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
//! Read Well Known Binary stream from PostGIS
//void readWKB(const char *, QStringList tables);
//! shows the paste-transformations dialog
void pasteTransformations();
// void pasteTransformations();
//! check to see if file is dirty and if so, prompt the user th save it
bool saveDirty();
/** Helper function to union several geometries together (used in function mergeSelectedFeatures)
Expand Down
12 changes: 8 additions & 4 deletions src/app/qgsattributedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,23 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
.arg( vl->id() )
.arg(( unsigned long ) vl );

QString feature = QString( "_qgis_feature_%1 = wrapinstance( %2, qgis.core.QgsFeature )" )
.arg( mFeature->id() )
// Generate the unique ID of this feature. We used to use feature ID but some providers
// return a ID that is an invalid python variable when we have new unsaved features.
QDateTime dt = QDateTime::currentDateTime();
QString featurevarname = QString( "_qgis_feature_%1" ).arg( dt.toString( "yyyyMMddhhmmsszzz" ) );
QString feature = QString( "%1 = wrapinstance( %2, qgis.core.QgsFeature )" )
.arg( featurevarname )
.arg(( unsigned long ) mFeature );

QgsPythonRunner::run( form );
QgsPythonRunner::run( feature );
QgsPythonRunner::run( layer );

QString expr = QString( "%1(_qgis_featureform_%2, _qgis_layer_%3, _qgis_feature_%4)" )
QString expr = QString( "%1(_qgis_featureform_%2, _qgis_layer_%3, %4)" )
.arg( vl->editFormInit() )
.arg( mFormNr )
.arg( vl->id() )
.arg( mFeature->id() );
.arg( featurevarname );

QgsDebugMsg( QString( "running featureForm init: %1" ).arg( expr ) );
QgsPythonRunner::run( expr );
Expand Down
5 changes: 5 additions & 0 deletions src/app/qgsbrowserdockwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"
#include "qgisapp.h"
#include "qgsproject.h"

// browser layer properties dialog
#include "qgsapplication.h"
Expand Down Expand Up @@ -285,6 +286,10 @@ void QgsBrowserDockWidget::showEvent( QShowEvent * e )
if ( item && item->type() == QgsDataItem::Favourites )
mBrowserView->expand( index );
}

connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ), mModel, SLOT( reload() ) );
connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ), mModel, SLOT( reload() ) );
connect( QgisApp::instance(), SIGNAL( newProject() ), mModel, SLOT( reload() ) );
}

QDockWidget::showEvent( e );
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsfieldsproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ QgsAttributeEditorElement* QgsFieldsProperties::createAttributeEditorWidget( QTr

if ( item->data( 0, Qt::UserRole ) == "field" )
{
int idx = *mLayer->dataProvider()->fieldNameMap().find( item->text( 0 ) );
int idx = *( mLayer->dataProvider()->fieldNameMap() ).find( item->text( 0 ) );
widgetDef = new QgsAttributeEditorField( item->text( 0 ), idx, parent );
}
else
Expand Down
16 changes: 11 additions & 5 deletions src/app/qgsmergeattributesdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ void QgsMergeAttributesDialog::createTableWidgetContents()

//create combo boxes and insert attribute names
const QgsFieldMap& fieldMap = mVectorLayer->pendingFields();
QgsAttributeList pkAttrList = mVectorLayer->pendingPkAttributesList();

int col = 0;
for ( QgsFieldMap::const_iterator fieldIt = fieldMap.constBegin();
Expand All @@ -96,7 +97,12 @@ void QgsMergeAttributesDialog::createTableWidgetContents()

mTableWidget->setColumnCount( col + 1 );

mTableWidget->setCellWidget( 0, col, createMergeComboBox( fieldIt->type() ) );
QComboBox *cb = createMergeComboBox( fieldIt->type() );
if ( pkAttrList.contains( fieldIt.key() ) )
{
cb->setCurrentIndex( cb->findText( tr( "Skip attribute" ) ) );
}
mTableWidget->setCellWidget( 0, col, cb );

QTableWidgetItem *item = new QTableWidgetItem( fieldIt.value().name() );
item->setData( Qt::UserRole, fieldIt.key() );
Expand Down Expand Up @@ -135,14 +141,14 @@ void QgsMergeAttributesDialog::createTableWidgetContents()
}
}

QComboBox* QgsMergeAttributesDialog::createMergeComboBox( QVariant::Type columnType ) const
QComboBox *QgsMergeAttributesDialog::createMergeComboBox( QVariant::Type columnType ) const
{
QComboBox* newComboBox = new QComboBox();
QComboBox *newComboBox = new QComboBox();
//add items for feature
QgsFeatureList::const_iterator f_it = mFeatureList.constBegin();
for ( ; f_it != mFeatureList.constEnd(); ++f_it )
{
newComboBox->addItem( tr( "feature %1" ).arg( f_it->id() ) );
newComboBox->addItem( tr( "Feature %1" ).arg( f_it->id() ) );
}

if ( columnType == QVariant::Double || columnType == QVariant::Int )
Expand Down Expand Up @@ -183,7 +189,7 @@ int QgsMergeAttributesDialog::findComboColumn( QComboBox* c ) const
void QgsMergeAttributesDialog::comboValueChanged( const QString &text )
{
Q_UNUSED( text );
QComboBox* senderComboBox = qobject_cast<QComboBox *>( sender() );
QComboBox *senderComboBox = qobject_cast<QComboBox *>( sender() );
if ( !senderComboBox )
{
return;
Expand Down
232 changes: 225 additions & 7 deletions src/app/qgsoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
#include <QSettings>
#include <QColorDialog>
#include <QLocale>
#include <QProcess>
#include <QToolBar>
#include <QScrollBar>
#include <QSize>
#include <QStyleFactory>
#include <QMessageBox>
Expand Down Expand Up @@ -68,6 +70,8 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
{
setupUi( this );

connect( mOptionsSplitter, SIGNAL( splitterMoved( int, int ) ), this, SLOT( updateVerticalTabs() ) );

connect( cmbTheme, SIGNAL( activated( const QString& ) ), this, SLOT( themeChanged( const QString& ) ) );
connect( cmbTheme, SIGNAL( highlighted( const QString& ) ), this, SLOT( themeChanged( const QString& ) ) );
connect( cmbTheme, SIGNAL( textChanged( const QString& ) ), this, SLOT( themeChanged( const QString& ) ) );
Expand Down Expand Up @@ -110,6 +114,97 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
spinBoxIdentifyValue->setMinimum( 0.01 );
spinBoxIdentifyValue->setValue( identifyValue );

// custom environment variables
bool useCustomVars = settings.value( "qgis/customEnvVarsUse", QVariant( false ) ).toBool();
mCustomVariablesChkBx->setChecked( useCustomVars );
if ( !useCustomVars )
{
mAddCustomVarBtn->setEnabled( false );
mRemoveCustomVarBtn->setEnabled( false );
mCustomVariablesTable->setEnabled( false );
}
QStringList customVarsList = settings.value( "qgis/customEnvVars", "" ).toStringList();
foreach ( const QString &varStr, customVarsList )
{
int pos = varStr.indexOf( QLatin1Char( '|' ) );
if ( pos == -1 )
continue;
QString varStrApply = varStr.left( pos );
QString varStrNameValue = varStr.mid( pos + 1 );
pos = varStrNameValue.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QString varStrName = varStrNameValue.left( pos );
QString varStrValue = varStrNameValue.mid( pos + 1 );

addCustomEnvVarRow( varStrName, varStrValue, varStrApply );
}
QFontMetrics fmCustomVar( mCustomVariablesTable->horizontalHeader()->font() );
int fmCustomVarH = fmCustomVar.height() + 2;
mCustomVariablesTable->horizontalHeader()->setFixedHeight( fmCustomVarH );

mCustomVariablesTable->setColumnWidth( 0, 120 );
if ( mCustomVariablesTable->rowCount() > 0 )
{
mCustomVariablesTable->resizeColumnToContents( 1 );
}
else
{
mCustomVariablesTable->setColumnWidth( 1, 120 );
}

// current environment variables
mCurrentVariablesTable->horizontalHeader()->setFixedHeight( fmCustomVarH );
QMap<QString, QString> sysVarsMap = QgsApplication::systemEnvVars();
QStringList currentVarsList = QProcess::systemEnvironment();

foreach ( const QString &varStr, currentVarsList )
{
int pos = varStr.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QStringList varStrItms;
QString varStrName = varStr.left( pos );
QString varStrValue = varStr.mid( pos + 1 );
varStrItms << varStrName << varStrValue;

// check if different than system variable
QString sysVarVal = QString( "" );
bool sysVarMissing = !sysVarsMap.contains( varStrName );
if ( sysVarMissing )
sysVarVal = tr( "not present" );

if ( !sysVarMissing && sysVarsMap.value( varStrName ) != varStrValue )
sysVarVal = sysVarsMap.value( varStrName );

if ( !sysVarVal.isEmpty() )
sysVarVal = tr( "System value: %1" ).arg( sysVarVal );

int rowCnt = mCurrentVariablesTable->rowCount();
mCurrentVariablesTable->insertRow( rowCnt );

QFont fItm;
for ( int i = 0; i < varStrItms.size(); ++i )
{
QTableWidgetItem* varNameItm = new QTableWidgetItem( varStrItms.at( i ) );
varNameItm->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
| Qt::ItemIsEditable | Qt::ItemIsDragEnabled );
fItm = varNameItm->font();
if ( !sysVarVal.isEmpty() )
{
fItm.setBold( true );
varNameItm->setFont( fItm );
varNameItm->setToolTip( sysVarVal );
}
mCurrentVariablesTable->setItem( rowCnt, i, varNameItm );
}
fItm.setBold( true );
QFontMetrics fmRow( fItm );
mCurrentVariablesTable->setRowHeight( rowCnt, fmRow.height() + 6 );
}
if ( mCurrentVariablesTable->rowCount() > 0 )
mCurrentVariablesTable->resizeColumnToContents( 0 );

//local directories to search when loading c++ plugins
QString myPaths = settings.value( "plugins/searchPathsForPlugins", "" ).toString();
if ( !myPaths.isEmpty() )
Expand Down Expand Up @@ -611,23 +706,61 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
mOverlayAlgorithmComboBox->setCurrentIndex( 0 );
} //default is central point

// restore window and widget geometry/state
restoreGeometry( settings.value( "/Windows/Options/geometry" ).toByteArray() );
mOptionsSplitter->restoreState( settings.value( "/Windows/Options/splitState" ).toByteArray() );

int currentIndx = settings.value( "/Windows/Options/row" ).toInt();
mOptionsListWidget->setCurrentRow( currentIndx );
mOptionsStackedWidget->setCurrentIndex( currentIndx );

// load gdal driver list only when gdal tab is first opened
mLoadedGdalDriverList = false;

// tabWidget->setCurrentIndex( settings.value( "/Windows/Options/row" ).toInt() );
int currentTab = settings.value( "/Windows/Options/row" ).toInt();
tabWidget->setCurrentIndex( currentTab );
on_tabWidget_currentChanged( currentTab );
// update option section frame state
on_mOptionsListWidget_currentRowChanged( currentIndx );
}

//! Destructor
QgsOptions::~QgsOptions()
{
QSettings settings;
settings.setValue( "/Windows/Options/geometry", saveGeometry() );
settings.setValue( "/Windows/Options/row", tabWidget->currentIndex() );
settings.setValue( "/Windows/Options/splitState", mOptionsSplitter->saveState() );
settings.setValue( "/Windows/Options/row", mOptionsListWidget->currentRow() );
}

void QgsOptions::showEvent( QShowEvent * e )
{
Q_UNUSED( e );
updateVerticalTabs();
}

void QgsOptions::resizeEvent( QResizeEvent * e )
{
Q_UNUSED( e );
if ( mOptionsListWidget->isVisible() )
updateVerticalTabs();
}

void QgsOptions::updateVerticalTabs()
{
// auto-resize splitter for vert scrollbar without covering icons in icon-only mode
// TODO: mOptionsListWidget has fixed 32px wide icons for now, allow user-defined
int iconWidth = mOptionsListWidget->iconSize().width();
int snapToIconWidth = iconWidth + 32;
QList<int> splitSizes = mOptionsSplitter->sizes();
bool iconOnly = splitSizes.at( 0 ) <= snapToIconWidth;

int newWidth = mOptionsListWidget->verticalScrollBar()->isVisible() ? iconWidth + 26 : iconWidth + 12;
mOptionsListWidget->setMinimumWidth( newWidth );
if ( iconOnly )
{
splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
splitSizes[0] = newWidth;
mOptionsSplitter->setSizes( splitSizes );
}
mOptionsListWidget->setWordWrap( !iconOnly );
}

void QgsOptions::on_cbxProjectDefaultNew_toggled( bool checked )
Expand Down Expand Up @@ -781,6 +914,23 @@ void QgsOptions::saveOptions()
{
QSettings settings;

// custom environment variables
settings.setValue( "qgis/customEnvVarsUse", QVariant( mCustomVariablesChkBx->isChecked() ) );
QStringList customVars;
for ( int i = 0; i < mCustomVariablesTable->rowCount(); ++i )
{
if ( mCustomVariablesTable->item( i, 1 )->text().isEmpty() )
continue;
QComboBox* varApplyCmbBx = qobject_cast<QComboBox*>( mCustomVariablesTable->cellWidget( i, 0 ) );
QString customVar = varApplyCmbBx->itemData( varApplyCmbBx->currentIndex() ).toString();
customVar += "|";
customVar += mCustomVariablesTable->item( i, 1 )->text();
customVar += "=";
customVar += mCustomVariablesTable->item( i, 2 )->text();
customVars << customVar;
}
settings.setValue( "qgis/customEnvVars", QVariant( customVars ) );

//search directories for user plugins
QString myPaths;
for ( int i = 0; i < mListPluginPaths->count(); ++i )
Expand Down Expand Up @@ -1211,6 +1361,74 @@ QStringList QgsOptions::i18nList()
return myList;
}

void QgsOptions::addCustomEnvVarRow( QString varName, QString varVal, QString varApply )
{
int rowCnt = mCustomVariablesTable->rowCount();
mCustomVariablesTable->insertRow( rowCnt );

QComboBox* varApplyCmbBx = new QComboBox( this );
varApplyCmbBx->addItem( tr( "Overwrite" ), QVariant( "overwrite" ) );
varApplyCmbBx->addItem( tr( "If Undefined" ), QVariant( "undefined" ) );
varApplyCmbBx->addItem( tr( "Unset" ), QVariant( "unset" ) );
varApplyCmbBx->addItem( tr( "Prepend" ), QVariant( "prepend" ) );
varApplyCmbBx->addItem( tr( "Append" ), QVariant( "append" ) );
varApplyCmbBx->setCurrentIndex( varApply.isEmpty() ? 0 : varApplyCmbBx->findData( QVariant( varApply ) ) );

QFont cbf = varApplyCmbBx->font();
QFontMetrics cbfm = QFontMetrics( cbf );
cbf.setPointSize( cbf.pointSize() - 2 );
varApplyCmbBx->setFont( cbf );
mCustomVariablesTable->setCellWidget( rowCnt, 0, varApplyCmbBx );

Qt::ItemFlags itmFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable
| Qt::ItemIsEditable | Qt::ItemIsDropEnabled;

QTableWidgetItem* varNameItm = new QTableWidgetItem( varName );
varNameItm->setFlags( itmFlags );
mCustomVariablesTable->setItem( rowCnt, 1, varNameItm );

QTableWidgetItem* varValueItm = new QTableWidgetItem( varVal );
varNameItm->setFlags( itmFlags );
mCustomVariablesTable->setItem( rowCnt, 2, varValueItm );

mCustomVariablesTable->setRowHeight( rowCnt, cbfm.height() + 8 );
}

void QgsOptions::on_mAddCustomVarBtn_clicked()
{
addCustomEnvVarRow( QString( "" ), QString( "" ) );
mCustomVariablesTable->setFocus();
mCustomVariablesTable->setCurrentCell( mCustomVariablesTable->rowCount() - 1, 1 );
mCustomVariablesTable->edit( mCustomVariablesTable->currentIndex() );
}

void QgsOptions::on_mRemoveCustomVarBtn_clicked()
{
mCustomVariablesTable->removeRow( mCustomVariablesTable->currentRow() );
}

void QgsOptions::on_mCurrentVariablesQGISChxBx_toggled( bool qgisSpecific )
{
for ( int i = mCurrentVariablesTable->rowCount() - 1; i >= 0; --i )
{
if ( qgisSpecific )
{
QString itmTxt = mCurrentVariablesTable->item( i, 0 )->text();
if ( !itmTxt.startsWith( "QGIS", Qt::CaseInsensitive ) )
mCurrentVariablesTable->hideRow( i );
}
else
{
mCurrentVariablesTable->showRow( i );
}
}
if ( mCurrentVariablesTable->rowCount() > 0 )
{
mCurrentVariablesTable->sortByColumn( 0, Qt::AscendingOrder );
mCurrentVariablesTable->resizeColumnToContents( 0 );
}
}

void QgsOptions::on_mBtnAddPluginPath_clicked()
{
QString myDir = QFileDialog::getExistingDirectory(
Expand Down Expand Up @@ -1302,10 +1520,10 @@ void QgsOptions::on_mClearCache_clicked()
#endif
}

void QgsOptions::on_tabWidget_currentChanged( int theTab )
void QgsOptions::on_mOptionsListWidget_currentRowChanged( int theIndx )
{
// load gdal driver list when gdal tab is first opened
if ( theTab == 1 && ! mLoadedGdalDriverList )
if ( theIndx == 2 && ! mLoadedGdalDriverList )
{
loadGdalDriverList();
}
Expand Down
34 changes: 31 additions & 3 deletions src/app/qgsoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
/**Remove an URL to exclude from Proxy*/
void on_mRemoveUrlPushButton_clicked();

/** Slot to add a custom environment variable to the app
* @note added in QGIS 1.9
*/
void on_mAddCustomVarBtn_clicked();

/** Slot to remove a custom environment variable from the app
* @note added in QGIS 1.9
*/
void on_mRemoveCustomVarBtn_clicked();

/** Slot to filter out current environment variables not specific to QGIS
* @note added in QGIS 1.9
*/
void on_mCurrentVariablesQGISChxBx_toggled( bool qgisSpecific );

/* Let the user add a path to the list of search paths
* used for finding user Plugin libs.
* @note added in QGIS 1.7
Expand Down Expand Up @@ -174,10 +189,15 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
*/
void on_pbnExportScales_clicked();

/** Auto slot executed when the active page in the main widget stack is changed
* @note added in 2.0
/** Auto slot executed when the active item in the option section list widget is changed
* @note added in 1.9
*/
void on_mOptionsListWidget_currentRowChanged( int theIndx );

/** Slot to update widget of vertical tabs
* @note added in QGIS 1.9
*/
void on_tabWidget_currentChanged( int theTab );
void updateVerticalTabs();

/* Load the list of drivers available in GDAL
* @note added in 2.0
Expand All @@ -197,6 +217,14 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
QgsCoordinateReferenceSystem mLayerDefaultCrs;
bool mLoadedGdalDriverList;

/** Generate table row for custom environment variables
* @note added in QGIS 1.9
*/
void addCustomEnvVarRow( QString varName, QString varVal, QString varApply = QString() );

protected:
void showEvent( QShowEvent * e );
void resizeEvent( QResizeEvent * e );
};

#endif // #ifndef QGSOPTIONS_H
7 changes: 7 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ SET(QGIS_CORE_SRCS
qgsmessageoutput.cpp
qgsmimedatautils.cpp
qgsmessagelog.cpp
qgsnetworkreplyparser.cpp
qgscredentials.cpp
qgsoverlayobject.cpp
qgsowsconnection.cpp
Expand Down Expand Up @@ -111,6 +112,7 @@ SET(QGIS_CORE_SRCS
qgsvectorlayerjoinbuffer.cpp
qgsvectorlayerundocommand.cpp
qgsvectoroverlay.cpp
qgswfsdata.cpp

qgsnetworkaccessmanager.cpp

Expand Down Expand Up @@ -285,13 +287,15 @@ SET(QGIS_CORE_MOC_HDRS
qgsmaprenderer.h
qgsmessageoutput.h
qgsmessagelog.h
qgsnetworkreplyparser.h
qgscredentials.h
qgspluginlayer.h
qgsproject.h
qgsrunprocess.h
qgsvectorlayer.h
qgsnetworkaccessmanager.h
qgsvectordataprovider.h
qgswfsdata.h
qgsgeometryvalidator.h

composer/qgsaddremoveitemcommand.h
Expand Down Expand Up @@ -373,6 +377,7 @@ SET(QGIS_CORE_HDRS
qgsmaptopixel.h
qgsmessageoutput.h
qgsmimedatautils.h
qgsnetworkreplyparser.h
qgscredentials.h
qgsoverlayobjectpositionmanager.h
qgsowsconnection.h
Expand Down Expand Up @@ -402,6 +407,7 @@ SET(QGIS_CORE_HDRS
qgsvectorlayer.h
qgsvectorlayerimport.h
qgsvectoroverlay.h
qgswfsdata.h
qgstolerance.h

diagram/qgsdiagram.h
Expand Down Expand Up @@ -584,6 +590,7 @@ TARGET_LINK_LIBRARIES(qgis_core
${GEOS_LIBRARY}
${GDAL_LIBRARY}
${SPATIALINDEX_LIBRARY}
${EXPAT_LIBRARY}
)

IF (WITH_INTERNAL_SPATIALITE)
Expand Down
3 changes: 2 additions & 1 deletion src/core/gps/tok.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ double nmea_atof( const char *str, int str_sz )

if ( str_sz < NMEA_CONVSTR_BUF )
{
const char *oldlocale = setlocale( LC_NUMERIC, NULL );

memcpy( &buff[0], str, str_sz );
buff[str_sz] = '\0';
const char *oldlocale = setlocale( LC_NUMERIC, NULL );
setlocale( LC_NUMERIC, "C" );
res = strtod( &buff[0], &tmp_ptr );
setlocale( LC_NUMERIC, oldlocale );
Expand Down
15 changes: 15 additions & 0 deletions src/core/qgsapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <QFileOpenEvent>
#include <QMessageBox>
#include <QPalette>
#include <QProcess>
#include <QSettings>
#include <QIcon>
#include <QPixmap>
Expand All @@ -50,6 +51,7 @@ QString ABISYM( QgsApplication::mLibraryPath );
QString ABISYM( QgsApplication::mLibexecPath );
QString ABISYM( QgsApplication::mThemeName );
QStringList ABISYM( QgsApplication::mDefaultSvgPaths );
QMap<QString, QString> ABISYM( QgsApplication::mSystemEnvVars );
QString ABISYM( QgsApplication::mConfigPath );
bool ABISYM( QgsApplication::mRunningFromBuildDir ) = false;
QString ABISYM( QgsApplication::mBuildSourcePath );
Expand Down Expand Up @@ -152,6 +154,19 @@ void QgsApplication::init( QString customConfigPath )

ABISYM( mDefaultSvgPaths ) << qgisSettingsDirPath() + QString( "svg/" );

// store system environment variables passed to application, before they are adjusted
QMap<QString, QString> systemEnvVarMap;
foreach ( const QString &varStr, QProcess::systemEnvironment() )
{
int pos = varStr.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QString varStrName = varStr.left( pos );
QString varStrValue = varStr.mid( pos + 1 );
systemEnvVarMap.insert( varStrName, varStrValue );
}
ABISYM( mSystemEnvVars ) = systemEnvVarMap;

// set a working directory up for gdal to write .aux.xml files into
// for cases where the raster dir is read only to the user
// if the env var is already set it will be used preferentially
Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ class CORE_EXPORT QgsApplication: public QApplication
//! @note added in 1.4
static const QStringList svgPaths();

//! Returns the system environment variables passed to application.
//! @note added in 1.9
static const QMap<QString, QString> systemEnvVars() { return ABISYM( mSystemEnvVars ); }

//! Returns the path to the application prefix directory.
static const QString prefixPath();

Expand Down Expand Up @@ -253,7 +257,7 @@ class CORE_EXPORT QgsApplication: public QApplication
* GDAL_SKIP environment variable)
* @note added in 2.0
*/
static QStringList skippedGdalDrivers( ) { return ABISYM( mGdalSkipList ); };
static QStringList skippedGdalDrivers( ) { return ABISYM( mGdalSkipList ); }

/** Apply the skipped drivers list to gdal
* @see skipGdalDriver
Expand All @@ -277,6 +281,7 @@ class CORE_EXPORT QgsApplication: public QApplication
static QString ABISYM( mLibexecPath );
static QString ABISYM( mThemeName );
static QStringList ABISYM( mDefaultSvgPaths );
static QMap<QString, QString> ABISYM( mSystemEnvVars );

static QString ABISYM( mConfigPath );

Expand Down
15 changes: 13 additions & 2 deletions src/core/qgsbrowsermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "qgsproviderregistry.h"

#include "qgsbrowsermodel.h"
#include "qgsproject.h"

#include <QSettings>

Expand All @@ -40,8 +41,18 @@ QgsBrowserModel::~QgsBrowserModel()

void QgsBrowserModel::addRootItems()
{
// give the home directory a prominent first place
QgsDirectoryItem *item = new QgsDirectoryItem( NULL, tr( "Home" ), QDir::homePath() );
QgsDirectoryItem *item;

QString home = QgsProject::instance()->homePath();

if( !home.isNull() )
{
item = new QgsDirectoryItem( NULL, tr( "Project home" ), home );
mRootItems << item;
}

// give the home directory a prominent second place
item = new QgsDirectoryItem( NULL, tr( "Home" ), QDir::homePath() );
QStyle *style = QApplication::style();
QIcon homeIcon( style->standardPixmap( QStyle::SP_DirHomeIcon ) );
item->setIcon( homeIcon );
Expand Down
5 changes: 2 additions & 3 deletions src/core/qgsbrowsermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel

bool hasChildren( const QModelIndex &parent = QModelIndex() ) const;

// Reload the whole model
void reload();

// Refresh item specified by path
void refresh( QString path );

Expand All @@ -93,6 +90,8 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
void fetchMore( const QModelIndex & parent );

public slots:
// Reload the whole model
void reload();

void beginInsertItems( QgsDataItem *parent, int first, int last );
void endInsertItems();
Expand Down
13 changes: 13 additions & 0 deletions src/core/qgsmaplayerregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ QgsMapLayer * QgsMapLayerRegistry::mapLayer( QString theLayerId )
return mMapLayers.value( theLayerId );
}

QList<QgsMapLayer *> QgsMapLayerRegistry::mapLayersByName( QString layerName )
{
QList<QgsMapLayer *> myResultList;
foreach ( QgsMapLayer* layer, mMapLayers )
{
if ( layer->name() == layerName )
{
myResultList << layer;
}
}
return myResultList;
}

//introduced in 1.8
QList<QgsMapLayer *> QgsMapLayerRegistry::addMapLayers(
QList<QgsMapLayer *> theMapLayers,
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsmaplayerregistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class CORE_EXPORT QgsMapLayerRegistry : public QObject
//! Retrieve a pointer to a loaded layer by id
QgsMapLayer *mapLayer( QString theLayerId );

//! Retrieve a pointer to a loaded layer by name
QList<QgsMapLayer *> mapLayersByName( QString layerName );

//! Retrieve the mapLayers collection (mainly intended for use by projection)
QMap<QString, QgsMapLayer*> & mapLayers();

Expand Down
144 changes: 144 additions & 0 deletions src/core/qgsnetworkreplyparser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/***************************************************************************
qgsnetworkreplyparser.cpp - Multipart QNetworkReply parser
-------------------
begin : 4 January, 2013
copyright : (C) 2013 by Radim Blazek
email : radim dot blazek at gmail.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 "qgslogger.h"
#include "qgsnetworkreplyparser.h"

#include <QNetworkReply>
#include <QObject>
#include <QRegExp>
#include <QString>
#include <QStringList>

QgsNetworkReplyParser::QgsNetworkReplyParser( QNetworkReply *reply )
: mReply(reply)
, mValid(false)
{
if ( !mReply ) return;

// Content type examples:
// multipart/mixed; boundary=wcs
// multipart/mixed; boundary="wcs"\n
if ( !isMultipart( mReply ) )
{
// reply is not multipart, copy body and headers
QMap<QByteArray,QByteArray> headers;
foreach ( QByteArray h, mReply->rawHeaderList() )
{
headers.insert( h, mReply->rawHeader( h ) );
}
mHeaders.append( headers );
mBodies.append( mReply->readAll() );
}
else // multipart
{
QString contentType = mReply->header( QNetworkRequest::ContentTypeHeader ).toString();
QgsDebugMsg( "contentType: " + contentType );

QRegExp re( ".*boundary=\"?([^\"]+)\"?\\s?", Qt::CaseInsensitive );

if ( !re.indexIn( contentType ) == 0 )
{
mError = tr( "Cannot find boundary in multipart content type" );
return;
}

QString boundary = re.cap( 1 );
QgsDebugMsg( "boundary = " + boundary );
boundary = "--" + boundary;

// Lines should be terminated by CRLF ("\r\n") but any new line combination may appear
QByteArray data = mReply->readAll();
int from, to;
from = data.indexOf( boundary.toAscii(), 0 ) + boundary.length() + 1 ;
//QVector<QByteArray> partHeaders;
//QVector<QByteArray> partBodies;
while ( true )
{
to = data.indexOf( boundary.toAscii(), from );
if ( to < 0 )
{
// It may happent that bondary is missing at the end (GeoServer)
// in that case, take everything to th end
if ( data.size() - from > 1 )
{
to = data.size(); // out of range OK
}
else
{
break;
}
}
QgsDebugMsg( QString( "part %1 - %2" ).arg( from ).arg( to ) );
QByteArray part = data.mid( from, to - from );
// Remove possible new line from beginning
while ( part.size() > 0 && ( part.at( 0 ) == '\r' || part.at( 0 ) == '\n' ) )
{
part.remove( 0, 1 );
}
// Split header and data (find empty new line)
// New lines should be CRLF, but we support also CRLFCRLF, LFLF to find empty line
int pos = 0; // body start
while ( pos < part.size() - 1 )
{
if ( part.at( pos ) == '\n' && ( part.at( pos + 1 ) == '\n' || part.at( pos + 1 ) == '\r' ) )
{
if ( part.at( pos + 1 ) == '\r' ) pos++;
pos += 2;
break;
}
pos++;
}
// parse headers
QMap<QByteArray,QByteArray> headersMap;
QByteArray headers = part.left( pos );
QgsDebugMsg( "headers:\n" + headers );

QStringList headerRows = QString( headers ).split( QRegExp( "[\n\r]+" ) );
foreach ( QString row, headerRows )
{
QgsDebugMsg( "row = " + row );
QStringList kv = row.split( ": " );
headersMap.insert( kv.value( 0 ).toAscii(), kv.value( 1 ).toAscii() );
}
mHeaders.append( headersMap );

mBodies.append( part.mid( pos ) );

from = to + boundary.length() + 1;
}
}
mValid = true;
}

bool QgsNetworkReplyParser::isMultipart( QNetworkReply *reply )
{
if ( !reply ) return false;

QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
QgsDebugMsg( "contentType: " + contentType );

// Multipart content type examples:
// multipart/mixed; boundary=wcs
// multipart/mixed; boundary="wcs"\n
if ( contentType.startsWith( "multipart/", Qt::CaseInsensitive ) )
{
return true;
}
return false;
}
82 changes: 82 additions & 0 deletions src/core/qgsnetworkreplyparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***************************************************************************
qgsnetworkreplyparser.h - Multipart QNetworkReply parser
-------------------
begin : 4 January, 2013
copyright : (C) 2013 by Radim Blazek
email : radim dot blazek at gmail.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 QGSNETWORKREPLYPARSER_H
#define QGSNETWORKREPLYPARSER_H

#include <QNetworkReply>

/**
\brief Multipart QNetworkReply parser.
It seams that Qt does not have currently support for multipart reply
and it is not even possible to create QNetworkReply from raw data
so we need a class for multipart QNetworkReply parsing.
*/

class CORE_EXPORT QgsNetworkReplyParser : public QObject
{
Q_OBJECT

public:
/** Constructor
* @param reply */
QgsNetworkReplyParser( QNetworkReply *reply );

/** Indicates if successfully parsed
* @return true if successfully parsed */
bool isValid() const { return mValid; }

/** Get number of parts
* @return number of parts */
int parts() const { return mHeaders.size(); }

/** Get part header
* @param part part index
* @param headerName header name
* @return raw header */
QByteArray rawHeader( int part, const QByteArray & headerName ) const { return mHeaders.value( part ).value( headerName ); }

/** Get part part body
* @param part part index
* @return part body */
QByteArray body( int part ) const { return mBodies.value( part ); }

/** Parsing error */
QString error() const { return mError; }

/** Test if reply is multipart.
* @return true if reply is multipart */
static bool isMultipart( QNetworkReply *reply );

private:
QNetworkReply *mReply;

bool mValid;

QString mError;

/* List of header maps */
QList< QMap<QByteArray, QByteArray> > mHeaders;

/* List of part bodies */
QList<QByteArray> mBodies;
};

#endif
13 changes: 10 additions & 3 deletions src/core/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1368,11 +1368,11 @@ QString QgsProject::readPath( QString src ) const
// That means that it was saved with an earlier version of "relative path support",
// where the source file had to exist and only the project directory was stripped
// from the filename.
QFileInfo pfi( fileName() );
if ( !pfi.exists() )
QString home = homePath();
if( home.isNull() )
return src;

QFileInfo fi( pfi.canonicalPath() + "/" + src );
QFileInfo fi( home + "/" + src );

if ( !fi.exists() )
{
Expand Down Expand Up @@ -1763,4 +1763,11 @@ void QgsProjectBadLayerDefaultHandler::handleBadLayers( QList<QDomNode> /*layers
// just ignore any bad layers
}

QString QgsProject::homePath() const
{
QFileInfo pfi( fileName() );
if ( !pfi.exists() )
return QString::null;

return pfi.canonicalPath();
}
5 changes: 5 additions & 0 deletions src/core/qgsproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,11 @@ class CORE_EXPORT QgsProject : public QObject
@note added in version 1.9*/
bool topologicalEditing() const;

/** Return project's home path
@return home path of project (or QString::null if not set)
@note added in version 2.0 */
QString homePath() const;

protected:

/** Set error message from read/write operation
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsvectordataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
*/
virtual QgsAttributeList attributeIndexes();

/**
* Return list of indexes of fields that make up the primary key
* @note added in 2.0
*/
virtual QgsAttributeList pkAttributeIndexes() { return QgsAttributeList(); }

/**
* Set whether provider should also return features that don't have
* associated geometry. false by default
Expand Down
213 changes: 126 additions & 87 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
, mLabel( 0 )
, mLabelOn( false )
, mVertexMarkerOnlyForSelection( false )
, mEditorLayout( GeneratedLayout )
, mFetching( false )
, mJoinBuffer( 0 )
, mDiagramRenderer( 0 )
Expand Down Expand Up @@ -2512,16 +2513,13 @@ int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topolo

if ( mDataProvider )
{
//use default value where possible (primary key issue), otherwise the value from the original (split) feature
QgsAttributeMap newAttributes = select_it->attributeMap();
QVariant defaultValue;
foreach ( int j, newAttributes.keys() )

// overwrite primary key field with default values
foreach ( int idx, pendingPkAttributesList() )
{
defaultValue = mDataProvider->defaultValue( j );
if ( !defaultValue.isNull() )
{
newAttributes.insert( j, defaultValue );
}
if( newAttributes.contains( idx ) )
newAttributes.insert( idx, mDataProvider->defaultValue( idx ) );
}

newFeature.setAttributeMap( newAttributes );
Expand Down Expand Up @@ -3129,28 +3127,6 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
//also restore custom properties (for labeling-ng)
readCustomProperties( node, "labeling" );

// tab display
QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
if ( editorLayoutNode.isNull() )
{
mEditorLayout = GeneratedLayout;
}
else
{
if ( editorLayoutNode.toElement().text() == "uifilelayout" )
{
mEditorLayout = UiFileLayout;
}
else if ( editorLayoutNode.toElement().text() == "tablayout" )
{
mEditorLayout = TabLayout;
}
else
{
mEditorLayout = GeneratedLayout;
}
}

// Test if labeling is on or off
QDomNode labelnode = node.namedItem( "label" );
QDomElement element = labelnode.toElement();
Expand Down Expand Up @@ -3330,6 +3306,27 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
}
}

// tab display
QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
if ( editorLayoutNode.isNull() )
{
mEditorLayout = GeneratedLayout;
}
else
{
if ( editorLayoutNode.toElement().text() == "uifilelayout" )
{
mEditorLayout = UiFileLayout;
}
else if ( editorLayoutNode.toElement().text() == "tablayout" )
{
mEditorLayout = TabLayout;
}
else
{
mEditorLayout = GeneratedLayout;
}
}

//Attributes excluded from WMS and WFS
mExcludeAttributesWMS.clear();
Expand Down Expand Up @@ -3390,7 +3387,9 @@ QgsAttributeEditorElement* QgsVectorLayer::attributeEditorElementFromDomElement(
}
else if ( elem.tagName() == "attributeEditorField" )
{
newElement = new QgsAttributeEditorField( elem.attribute( "name" ), elem.attribute( "idx" ).toInt(), parent );
QString name = elem.attribute( "name" );
int idx = *( dataProvider()->fieldNameMap() ).find( name );
newElement = new QgsAttributeEditorField( name, idx, parent );
}

return newElement;
Expand Down Expand Up @@ -3446,26 +3445,6 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
//save customproperties (for labeling ng)
writeCustomProperties( node, doc );

// tab display
QDomElement editorLayoutElem = doc.createElement( "editorlayout" );
switch ( mEditorLayout )
{
case UiFileLayout:
editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
break;

case TabLayout:
editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
break;

case GeneratedLayout:
default:
editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
break;
}

node.appendChild( editorLayoutElem );

// add the display field
QDomElement dField = doc.createElement( "displayfield" );
QDomText dFieldText = doc.createTextNode( displayField() );
Expand Down Expand Up @@ -3608,6 +3587,26 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
afField.appendChild( afText );
node.appendChild( afField );

// tab display
QDomElement editorLayoutElem = doc.createElement( "editorlayout" );
switch ( mEditorLayout )
{
case UiFileLayout:
editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
break;

case TabLayout:
editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
break;

case GeneratedLayout:
default:
editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
break;
}

node.appendChild( editorLayoutElem );

//attribute aliases
if ( mAttributeAliasMap.size() > 0 )
{
Expand Down Expand Up @@ -3890,6 +3889,21 @@ QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
return mUpdatedFields.keys();
}

QgsAttributeList QgsVectorLayer::pendingPkAttributesList()
{
QgsAttributeList pkAttributesList;

foreach ( int idx, mDataProvider->pkAttributeIndexes() )
{
if ( !mUpdatedFields.contains( idx ) )
continue;

pkAttributesList << idx;
}

return pkAttributesList;
}

int QgsVectorLayer::pendingFeatureCount()
{
return mDataProvider->featureCount()
Expand Down Expand Up @@ -3970,14 +3984,31 @@ bool QgsVectorLayer::commitChanges()
}
}

// collect new feature ids that weren't deleted again and forget still
// pending updates for deleted features
QHash<QgsFeatureId, int> addedFeaturesIdx;
for ( int i = 0; i < mAddedFeatures.size(); i++ )
{
const QgsFeature &f = mAddedFeatures.at( i );
if ( !mDeletedFeatureIds.remove( f.id() ) )
{
addedFeaturesIdx.insert( f.id(), i );
}
else
{
mChangedAttributeValues.remove( f.id() );
mChangedGeometries.remove( f.id() );
}
}

//
// remap changed and attributes of added features
//
bool attributeChangesOk = true;
if ( attributesChanged )
{
// map updates field indexes to names
QMap<int, QString> src;
QHash<int, QString> src;
for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
{
src[ it.key()] = it.value().name();
Expand All @@ -3987,7 +4018,7 @@ bool QgsVectorLayer::commitChanges()
const QgsFieldMap &pFields = mDataProvider->fields();

// map provider table names to field indexes
QMap<QString, int> dst;
QHash<QString, int> dst;
for ( QgsFieldMap::const_iterator it = pFields.begin(); it != pFields.end(); it++ )
{
dst[ it.value().name()] = it.key();
Expand Down Expand Up @@ -4019,8 +4050,8 @@ bool QgsVectorLayer::commitChanges()
}

// map updated fields to provider fields
QMap<int, int> remap;
for ( QMap<int, QString>::const_iterator it = src.begin(); it != src.end(); it++ )
QHash<int, int> remap;
for ( QHash<int, QString>::const_iterator it = src.begin(); it != src.end(); it++ )
{
if ( dst.contains( it.value() ) )
{
Expand Down Expand Up @@ -4060,7 +4091,7 @@ bool QgsVectorLayer::commitChanges()
QgsFieldMap attributes;

// update private field map
for ( QMap<int, int>::iterator it = remap.begin(); it != remap.end(); it++ )
for ( QHash<int, int>::iterator it = remap.begin(); it != remap.end(); it++ )
attributes[ it.value()] = mUpdatedFields[ it.key()];

mUpdatedFields = attributes;
Expand Down Expand Up @@ -4088,21 +4119,42 @@ bool QgsVectorLayer::commitChanges()
}
}

//
// delete features
//
if ( mDeletedFeatureIds.size() > 0 )
{
if (( cap & QgsVectorDataProvider::DeleteFeatures ) && mDataProvider->deleteFeatures( mDeletedFeatureIds ) )
{
mCommitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
foreach ( const QgsFeatureId &id, mDeletedFeatureIds )
{
mChangedAttributeValues.remove( id );
mChangedGeometries.remove( id );
}

emit committedFeaturesRemoved( id(), mDeletedFeatureIds );

mDeletedFeatureIds.clear();
}
else
{
mCommitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
success = false;
}
}

//
// add features
//
if ( mAddedFeatures.size() > 0 )
{
for ( int i = 0; i < mAddedFeatures.size(); i++ )
foreach ( int i, addedFeaturesIdx.values() )
{
QgsFeature &f = mAddedFeatures[i];

if ( mDeletedFeatureIds.contains( f.id() ) )
if ( mDeletedFeatureIds.remove( f.id() ) )
{
mDeletedFeatureIds.remove( f.id() );

if ( mChangedGeometries.contains( f.id() ) )
mChangedGeometries.remove( f.id() );

mAddedFeatures.removeAt( i-- );
continue;
Expand Down Expand Up @@ -4174,31 +4226,6 @@ bool QgsVectorLayer::commitChanges()
}
}

//
// delete features
//
if ( mDeletedFeatureIds.size() > 0 )
{
if (( cap & QgsVectorDataProvider::DeleteFeatures ) && mDataProvider->deleteFeatures( mDeletedFeatureIds ) )
{
mCommitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); it++ )
{
mChangedAttributeValues.remove( *it );
mChangedGeometries.remove( *it );
}

emit committedFeaturesRemoved( id(), mDeletedFeatureIds );

mDeletedFeatureIds.clear();
}
else
{
mCommitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
success = false;
}
}

if ( !success )
{
if ( mDataProvider->hasErrors() )
Expand Down Expand Up @@ -5779,6 +5806,18 @@ QString QgsVectorLayer::metadata()
myMetadata += "</td></tr>";
}

QgsAttributeList pkAttrList = pendingPkAttributesList();
if ( !pkAttrList.isEmpty() )
{
myMetadata += "<tr><td>";
myMetadata += tr( "Primary key attributes: " );
foreach( int idx, pkAttrList )
{
myMetadata += pendingFields()[ idx ].name() + " ";
}
myMetadata += "</td></tr>";
}


//feature count
myMetadata += "<tr><td>";
Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
* @param elem the DOM element
* @param parent the QObject which will own this object
*/
static QgsAttributeEditorElement* attributeEditorElementFromDomElement( QDomElement &elem, QObject* parent );
QgsAttributeEditorElement* attributeEditorElementFromDomElement( QDomElement &elem, QObject* parent );

/** Read the symbology for the current layer from the Dom node supplied.
* @param node node that will contain the symbology definition for this layer.
Expand Down Expand Up @@ -632,6 +632,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** returns list of attributes */
QgsAttributeList pendingAllAttributesList();

/** returns list of attribute making up the primary key
* @note added in 2.0
*/
QgsAttributeList pendingPkAttributesList();

/** returns feature count after commit */
int pendingFeatureCount();

Expand Down
32 changes: 28 additions & 4 deletions src/core/qgsvectorlayerimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "qgsvectorlayerimport.h"
#include "qgsproviderregistry.h"

#include <QProgressDialog>

#define FEATURE_BUFFER_SIZE 200

typedef QgsVectorLayerImport::ImportError createEmptyLayer_t(
Expand All @@ -45,8 +47,10 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite,
const QMap<QString, QVariant> *options )
const QMap<QString, QVariant> *options,
QProgressDialog *progress )
: mErrorCount( 0 )
, mProgress( progress )
{
mProvider = NULL;

Expand Down Expand Up @@ -83,7 +87,7 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QgsDebugMsg( "Created empty layer" );

QgsVectorDataProvider *vectorProvider = ( QgsVectorDataProvider* ) pReg->provider( providerKey, uri );
if ( !vectorProvider || !vectorProvider->isValid() )
if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
{
mError = ErrInvalidLayer;
mErrorMessage = QObject::tr( "Loading of layer failed" );
Expand Down Expand Up @@ -181,7 +185,8 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
bool onlySelected,
QString *errorMessage,
bool skipAttributeCreation,
QMap<QString, QVariant> *options )
QMap<QString, QVariant> *options,
QProgressDialog *progress )
{
const QgsCoordinateReferenceSystem* outputCRS;
QgsCoordinateTransform* ct = 0;
Expand Down Expand Up @@ -255,7 +260,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}

QgsVectorLayerImport * writer =
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options );
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options, progress );

// check whether file creation was successful
ImportError err = writer->hasError();
Expand Down Expand Up @@ -298,9 +303,23 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
*errorMessage = QObject::tr( "Feature write errors:" );
}

if ( progress )
{
progress->setRange( 0, layer->featureCount() );
}

// write all features
while ( layer->nextFeature( fet ) )
{
if ( progress && progress->wasCanceled() )
{
if ( errorMessage )
{
*errorMessage += "\n" + QObject::tr( "Import was canceled at %1 of %2" ).arg( progress->value() ).arg( progress->maximum() );
}
break;
}

if ( writer->errorCount() > 1000 )
{
if ( errorMessage )
Expand Down Expand Up @@ -348,6 +367,11 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}
}
n++;

if ( progress )
{
progress->setValue( n );
}
}

// flush the buffer to be sure that all features are written
Expand Down
9 changes: 7 additions & 2 deletions src/core/qgsvectorlayerimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"

class QProgressDialog;

/** \ingroup core
* A convenience class for writing vector files to disk.
There are two possibilities how to use this class:
Expand Down Expand Up @@ -59,7 +61,8 @@ class CORE_EXPORT QgsVectorLayerImport
bool onlySelected = false,
QString *errorMessage = 0,
bool skipAttributeCreation = false,
QMap<QString, QVariant> *options = 0
QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** create a empty layer and add fields to it */
Expand All @@ -69,7 +72,8 @@ class CORE_EXPORT QgsVectorLayerImport
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite = false,
const QMap<QString, QVariant> *options = 0
const QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** checks whether there were any errors */
Expand Down Expand Up @@ -102,6 +106,7 @@ class CORE_EXPORT QgsVectorLayerImport
QMap<int, int> mOldToNewAttrIdx;

QgsFeatureList mFeatureBuffer;
QProgressDialog *mProgress;
};

#endif
File renamed without changes.
20 changes: 13 additions & 7 deletions src/providers/wfs/qgswfsdata.h → src/core/qgswfsdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@ class QgsCoordinateReferenceSystem;


/**This class reads data from a WFS server or alternatively from a GML file. It uses the expat XML parser and an event based model to keep performance high. The parsing starts when the first data arrives, it does not wait until the request is finished*/
class QgsWFSData: public QObject
class CORE_EXPORT QgsWFSData: public QObject
{
Q_OBJECT
public:
/** Constructor.
@param uri request uri
@param extent the extent of the WFS layer
@param features the features of the layer
@param idMap
@param geometryAttribute
@param thematicAttributes
@param wkbType */
QgsWFSData(
const QString& uri,
QgsRectangle* extent,
Expand All @@ -46,11 +54,7 @@ class QgsWFSData: public QObject
~QgsWFSData();

/**Does the Http GET request to the wfs server
@param query string (to define the requested typename)
@param extent the extent of the WFS layer
@param srs the reference system of the layer
@param features the features of the layer
@return 0 in case of success*/
@return 0 in case of success */
int getWFSData();

private slots:
Expand Down Expand Up @@ -108,7 +112,9 @@ class QgsWFSData: public QObject
@return 0 in case of success*/
int readEpsgFromAttribute( int& epsgNr, const XML_Char** attr ) const;
/**Reads attribute as string
@return attribute value or an empty string if no such attribute*/
@param attributeName
@param attr
@return attribute value or an empty string if no such attribute*/
QString readAttribute( const QString& attributeName, const XML_Char** attr ) const;
/**Creates a rectangle from a coordinate string.
@return 0 in case of success*/
Expand Down
6 changes: 6 additions & 0 deletions src/gui/attributetable/qgsattributetableidcolumnpair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ bool QgsAttributeTableIdColumnPair::operator<( const QgsAttributeTableIdColumnPa
//QVariant thinks gid is a string!
QVariant::Type columnType = mItem.type();

if ( mItem.isNull() )
return 1;

if ( b.mItem.isNull() )
return 0;

switch ( columnType )
{
case QVariant::Int:
Expand Down
22 changes: 19 additions & 3 deletions src/gui/qgsattributeeditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <qgsmaplayerregistry.h>
#include <qgslogger.h>

#include <QScrollArea>
#include <QPushButton>
#include <QLineEdit>
#include <QTextEdit>
Expand Down Expand Up @@ -987,13 +988,23 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
QGroupBox* groupBox = new QGroupBox( parent );
groupBox->setTitle( container->name() );
myContainer = groupBox;
newWidget = myContainer;
}
else
{
myContainer = new QWidget( parent );
QScrollArea *scrollArea = new QScrollArea( parent );

myContainer = new QWidget( scrollArea );

scrollArea->setWidget( myContainer );
scrollArea->setWidgetResizable( true );
scrollArea->setFrameShape( QFrame::NoFrame );

newWidget = scrollArea;
}

QGridLayout* gbLayout = new QGridLayout( myContainer );
myContainer->setLayout( gbLayout );

int index = 0;

Expand All @@ -1010,17 +1021,22 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
}
else
{
const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( childDef );

//show attribute alias if available
QString myFieldName = vl->attributeDisplayName( fieldDef->idx() );
QLabel * mypLabel = new QLabel( myContainer );
gbLayout->addWidget( mypLabel, index, 0 );
mypLabel->setText( childDef->name() );
mypLabel->setText( myFieldName );

// add editor widget
gbLayout->addWidget( editor, index, 1 );
}

++index;
}
gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index , 0 );

newWidget = myContainer;
break;
}

Expand Down
5 changes: 1 addition & 4 deletions src/gui/qgssearchquerybuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,11 @@ void QgsSearchQueryBuilder::populateFields()
return;

QgsDebugMsg( "entering." );
QRegExp reQuote( "[A-Za-z_][A-Za-z0-9_]*" );
const QgsFieldMap& fields = mLayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
{
QString fieldName = it->name();
mFieldMap[fieldName] = it.key();
if ( !reQuote.exactMatch( fieldName ) ) // quote if necessary
fieldName = QgsExpression::quotedColumnRef( fieldName );
QStandardItem *myItem = new QStandardItem( fieldName );
myItem->setEditable( false );
mModelFields->insertRow( mModelFields->rowCount(), myItem );
Expand Down Expand Up @@ -314,7 +311,7 @@ void QgsSearchQueryBuilder::setSearchString( QString searchString )

void QgsSearchQueryBuilder::on_lstFields_doubleClicked( const QModelIndex &index )
{
txtSQL->insertPlainText( "\"" + mModelFields->data( index ).toString() + "\"" );
txtSQL->insertPlainText( QgsExpression::quotedColumnRef( mModelFields->data( index ).toString() ) );
}

void QgsSearchQueryBuilder::on_lstValues_doubleClicked( const QModelIndex &index )
Expand Down
5 changes: 1 addition & 4 deletions src/plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ ADD_SUBDIRECTORY(sqlanywhere)
ADD_SUBDIRECTORY(roadgraph)
ADD_SUBDIRECTORY(zonal_statistics)
ADD_SUBDIRECTORY(georeferencer)
ADD_SUBDIRECTORY(gps_importer)

IF (WITH_SPATIALITE)
ADD_SUBDIRECTORY(offline_editing)
Expand All @@ -28,10 +29,6 @@ IF (GRASS_FOUND)
ADD_SUBDIRECTORY(grass)
ENDIF (GRASS_FOUND)

IF (EXPAT_FOUND)
ADD_SUBDIRECTORY(gps_importer)
ENDIF (EXPAT_FOUND)

IF (WITH_GLOBE)
ADD_SUBDIRECTORY(globe)
ENDIF (WITH_GLOBE)
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/sqlanywhere/sasourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ SaSourceSelect::SaSourceSelect( QWidget *parent, Qt::WFlags fl )
connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addTables() ) );
mAddButton->setEnabled( false );

mBuildQueryButton = new QPushButton( tr( "&Build Query" ) );
mBuildQueryButton = new QPushButton( tr( "&Set Filter" ) );
buttonBox->addButton( mBuildQueryButton, QDialogButtonBox::ActionRole );
connect( mBuildQueryButton, SIGNAL( clicked() ), this, SLOT( buildQuery() ) );
mBuildQueryButton->setEnabled( false );
Expand Down
7 changes: 2 additions & 5 deletions src/providers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ ADD_SUBDIRECTORY(gdal)
ADD_SUBDIRECTORY(mssql)
ADD_SUBDIRECTORY(ows)
ADD_SUBDIRECTORY(wcs)
ADD_SUBDIRECTORY(gpx)
ADD_SUBDIRECTORY(wfs)

IF (POSTGRES_FOUND)
ADD_SUBDIRECTORY(postgres)
Expand All @@ -21,11 +23,6 @@ IF (SPATIALITE_FOUND OR WITH_INTERNAL_SPATIALITE)
ADD_SUBDIRECTORY(spatialite)
ENDIF (SPATIALITE_FOUND OR WITH_INTERNAL_SPATIALITE)

IF (EXPAT_FOUND)
ADD_SUBDIRECTORY(gpx)
ADD_SUBDIRECTORY(wfs)
ENDIF (EXPAT_FOUND)

IF (GRASS_FOUND)
ADD_SUBDIRECTORY(grass)
ENDIF (GRASS_FOUND)
2 changes: 1 addition & 1 deletion src/providers/mssql/qgsmssqlprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,7 @@ QgsVectorLayerImport::ImportError QgsMssqlProvider::createEmptyLayer(
QString pk = primaryKey = "qgs_fid";
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
{
if ( fldIt.value().name() == pk )
if ( fldIt.value().name() == primaryKey )
{
// it already exists, try again with a new name
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );
Expand Down
4 changes: 2 additions & 2 deletions src/providers/mssql/qgsmssqlsourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ QgsMssqlSourceSelect::QgsMssqlSourceSelect( QWidget *parent, Qt::WFlags fl, bool
mAddButton = new QPushButton( tr( "&Add" ) );
mAddButton->setEnabled( false );

mBuildQueryButton = new QPushButton( tr( "&Build query" ) );
mBuildQueryButton->setToolTip( tr( "Build query" ) );
mBuildQueryButton = new QPushButton( tr( "&Set Filter" ) );
mBuildQueryButton->setToolTip( tr( "Set Filter" ) );
mBuildQueryButton->setDisabled( true );

if ( !mManagerMode )
Expand Down
4 changes: 2 additions & 2 deletions src/providers/postgres/qgspgsourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WFlags fl, bool manag
mAddButton = new QPushButton( tr( "&Add" ) );
mAddButton->setEnabled( false );

mBuildQueryButton = new QPushButton( tr( "&Build query" ) );
mBuildQueryButton->setToolTip( tr( "Build query" ) );
mBuildQueryButton = new QPushButton( tr( "&Set Filter" ) );
mBuildQueryButton->setToolTip( tr( "Set Filter" ) );
mBuildQueryButton->setDisabled( true );

if ( !mManagerMode )
Expand Down
58 changes: 50 additions & 8 deletions src/providers/postgres/qgspostgresdataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,51 @@
#include "qgsapplication.h"

#include <QMessageBox>
#include <QProgressDialog>

QGISEXTERN bool deleteLayer( const QString& uri, QString& errCause );

// ---------------------------------------------------------------------------
QgsPGConnectionItem::QgsPGConnectionItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
, mColumnTypeThread( 0 )
{
mIcon = QgsApplication::getThemeIcon( "mIconConnect.png" );
}

QgsPGConnectionItem::~QgsPGConnectionItem()
{
stop();
}

void QgsPGConnectionItem::stop()
{
if ( mColumnTypeThread )
{
mColumnTypeThread->stop();
mColumnTypeThread->wait();
delete mColumnTypeThread;
mColumnTypeThread = 0;
}
}

void QgsPGConnectionItem::refresh()
{
QApplication::setOverrideCursor( Qt::WaitCursor );

stop();

foreach ( QgsDataItem *child, mChildren )
{
deleteChildItem( child );
}

foreach ( QgsDataItem *item, createChildren() )
{
addChildItem( item, true );
}

QApplication::restoreOverrideCursor();
}

QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
Expand All @@ -42,6 +75,8 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
QVector<QgsDataItem*> children;
QgsDataSourceURI uri = QgsPostgresConn::connUri( mName );

mSchemaMap.clear();

mConn = QgsPostgresConn::connectDb( uri.connectionInfo(), true );
if ( !mConn )
return children;
Expand All @@ -62,7 +97,7 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
return children;
}

QgsGeomColumnTypeThread *columnTypeThread = 0;
stop();

foreach ( QgsPostgresLayerProperty layerProperty, layerProperties )
{
Expand All @@ -76,17 +111,17 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()

if ( QgsPostgresConn::wkbTypeFromPostgis( layerProperty.type ) == QGis::WKBUnknown )
{
if ( !columnTypeThread )
if ( !mColumnTypeThread )
{
QgsPostgresConn *conn = QgsPostgresConn::connectDb( uri.connectionInfo(), true /* readonly */ );
if ( conn )
{
columnTypeThread = new QgsGeomColumnTypeThread( conn, true /* use estimated metadata */ );
mColumnTypeThread = new QgsGeomColumnTypeThread( conn, true /* use estimated metadata */ );

connect( columnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
connect( mColumnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
this, SLOT( setLayerType( QgsPostgresLayerProperty ) ) );
connect( this, SIGNAL( addGeometryColumn( QgsPostgresLayerProperty ) ),
columnTypeThread, SLOT( addGeometryColumn( QgsPostgresLayerProperty ) ) );
mColumnTypeThread, SLOT( addGeometryColumn( QgsPostgresLayerProperty ) ) );
}
}

Expand All @@ -98,8 +133,8 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
schemaItem->addLayer( layerProperty );
}

if ( columnTypeThread )
columnTypeThread->start();
if ( mColumnTypeThread )
mColumnTypeThread->start();

return children;
}
Expand Down Expand Up @@ -186,6 +221,11 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )

qApp->setOverrideCursor( Qt::WaitCursor );

QProgressDialog *progress = new QProgressDialog( tr( "Copying features..." ), tr( "Abort" ), 0, 0, 0 );
progress->setWindowTitle( tr( "Import layer" ) );
progress->setWindowModality( Qt::WindowModal );
progress->show();

QStringList importResults;
bool hasError = false;
QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data );
Expand All @@ -207,7 +247,7 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
QgsDebugMsg( "URI " + uri.uri() );
QgsVectorLayerImport::ImportError err;
QString importError;
err = QgsVectorLayerImport::importLayer( srcLayer, uri.uri(), "postgres", &srcLayer->crs(), false, &importError );
err = QgsVectorLayerImport::importLayer( srcLayer, uri.uri(), "postgres", &srcLayer->crs(), false, &importError, false, 0, progress );
if ( err == QgsVectorLayerImport::NoError )
importResults.append( tr( "%1: OK!" ).arg( u.name ) );
else
Expand All @@ -225,6 +265,8 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
delete srcLayer;
}

delete progress;

qApp->restoreOverrideCursor();

if ( hasError )
Expand Down
4 changes: 4 additions & 0 deletions src/providers/postgres/qgspostgresdataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class QgsPGConnectionItem : public QgsDataCollectionItem

QgsPostgresConn *connection() const { return mConn; }

void refresh();

signals:
void addGeometryColumn( QgsPostgresLayerProperty );

Expand All @@ -71,8 +73,10 @@ class QgsPGConnectionItem : public QgsDataCollectionItem
void setLayerType( QgsPostgresLayerProperty layerProperty );

private:
void stop();
QgsPostgresConn *mConn;
QMap<QString, QgsPGSchemaItem * > mSchemaMap;
QgsGeomColumnTypeThread *mColumnTypeThread;
};

class QgsPGSchemaItem : public QgsDataCollectionItem
Expand Down
2 changes: 1 addition & 1 deletion src/providers/postgres/qgspostgresprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3274,7 +3274,7 @@ QgsVectorLayerImport::ImportError QgsPostgresProvider::createEmptyLayer(
QString pk = primaryKey = "id";
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
{
if ( fldIt.value().name() == pk )
if ( fldIt.value().name() == primaryKey )
{
// it already exists, try again with a new name
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );
Expand Down
4 changes: 3 additions & 1 deletion src/providers/postgres/qgspostgresprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class QgsPostgresProvider : public QgsVectorDataProvider

QgsAttributeList attributeIndexes();

QgsAttributeList pkAttributeIndexes() { return mPrimaryKeyAttrs; }

/**Returns the default value for field specified by @c fieldName */
QVariant defaultValue( QString fieldName, QString tableName = QString::null, QString schemaName = QString::null );

Expand Down Expand Up @@ -445,7 +447,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
long layerId;
};

TopoLayerInfo mTopoLayerInfo;
TopoLayerInfo mTopoLayerInfo;

bool getTopoLayerInfo();

Expand Down
2 changes: 1 addition & 1 deletion src/providers/spatialite/qgsspatialitesourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ QgsSpatiaLiteSourceSelect::QgsSpatiaLiteSourceSelect( QWidget * parent, Qt::WFla
connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addClicked() ) );
mAddButton->setEnabled( false );

mBuildQueryButton = new QPushButton( tr( "&Build Query" ) );
mBuildQueryButton = new QPushButton( tr( "&Set Filter" ) );
connect( mBuildQueryButton, SIGNAL( clicked() ), this, SLOT( buildQuery() ) );
mBuildQueryButton->setEnabled( false );

Expand Down
103 changes: 19 additions & 84 deletions src/providers/wcs/qgswcsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsnetworkreplyparser.h"
#include "qgsmessageoutput.h"
#include "qgsmessagelog.h"

Expand Down Expand Up @@ -848,6 +849,7 @@ void QgsWcsProvider::cacheReplyFinished()
}

QVariant status = mCacheReply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
QgsDebugMsg( QString( "status = %1" ).arg( status.toInt() ) );
if ( !status.isNull() && status.toInt() >= 400 )
{
QVariant phrase = mCacheReply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
Expand Down Expand Up @@ -902,111 +904,44 @@ void QgsWcsProvider::cacheReplyFinished()
}

// WCS 1.1 gives response as multipart, e.g.
// multipart/mixed; boundary=wcs
// multipart/mixed; boundary="wcs"\n
if ( contentType.startsWith( "multipart/", Qt::CaseInsensitive ) )
if ( QgsNetworkReplyParser::isMultipart( mCacheReply ) )
{
// It seams that Qt does not have currently support for multipart reply
// and it is not even possible to create QNetworkReply from raw data
// so we have to parse response
QRegExp re( ".*boundary=\"?([^\"]+)\"?\\s?", Qt::CaseInsensitive );
QgsDebugMsg( "reply is multipart" );
QgsNetworkReplyParser parser( mCacheReply );

if ( !re.indexIn( contentType ) == 0 )
if ( !parser.isValid() )
{
QgsMessageLog::logMessage( tr( "Cannot find boundary in multipart content type" ), tr( "WCS" ) );
QgsMessageLog::logMessage( tr( "Cannot parse multipart response: %1" ).arg( parser.error() ), tr( "WCS" ) );
clearCache();
mCacheReply->deleteLater();
mCacheReply = 0;
return;
}

QString boundary = re.cap( 1 );
QgsDebugMsg( "boundary = " + boundary );
boundary = "--" + boundary;

// Lines should be terminated by CRLF ("\r\n") but any new line combination may appear
QByteArray data = mCacheReply->readAll();
int from, to;
from = data.indexOf( boundary.toAscii(), 0 ) + boundary.length() + 1 ;
QVector<QByteArray> partHeaders;
QVector<QByteArray> partBodies;
while ( true )
if ( parser.parts() < 2 )
{
to = data.indexOf( boundary.toAscii(), from );
if ( to < 0 )
{
// It may happent that bondary is missing at the end (GeoServer)
// in that case, take everything to th end
if ( data.size() - from > 1 )
{
to = data.size(); // out of range OK
}
else
{
break;
}
}
QgsDebugMsg( QString( "part %1 - %2" ).arg( from ).arg( to ) );
QByteArray part = data.mid( from, to - from );
// Remove possible new line from beginning
while ( part.size() > 0 && ( part.at( 0 ) == '\r' || part.at( 0 ) == '\n' ) )
{
part.remove( 0, 1 );
}
// Split header and data (find empty new line)
// New lines should be CRLF, but we support also CRLFCRLF, LFLF to find empty line
int pos = 0; // body start
while ( pos < part.size() - 1 )
{
if ( part.at( pos ) == '\n' && ( part.at( pos + 1 ) == '\n' || part.at( pos + 1 ) == '\r' ) )
{
if ( part.at( pos + 1 ) == '\r' ) pos++;
pos += 2;
break;
}
pos++;
}
partHeaders.append( part.left( pos ) );
partBodies.append( part.mid( pos ) );
QgsDebugMsg( "Part header:\n" + partHeaders.last() );

from = to + boundary.length() + 1;
}
if ( partBodies.size() < 2 )
{
QgsMessageLog::logMessage( tr( "Expected 2 parts, %1 received" ).arg( partBodies.size() ), tr( "WCS" ) );
QgsMessageLog::logMessage( tr( "Expected 2 parts, %1 received" ).arg( parser.parts() ), tr( "WCS" ) );
clearCache();
mCacheReply->deleteLater();
mCacheReply = 0;
return;
}
else if ( partBodies.size() > 2 )
else if ( parser.parts() > 2 )
{
// We will try the second one
QgsMessageLog::logMessage( tr( "More than 2 parts (%1) received" ).arg( partBodies.size() ), tr( "WCS" ) );
QgsMessageLog::logMessage( tr( "More than 2 parts (%1) received" ).arg( parser.parts() ), tr( "WCS" ) );
}

QStringList headerRows = QString( partHeaders.value( 1 ) ).split( QRegExp( "[\n\r]+" ) );
QString transferEncoding;
foreach ( QString row, headerRows )
{
QgsDebugMsg( "row = " + row );
//Content-Transfer-Encoding: base64
QStringList kv = row.split( ": " );
if ( kv.value( 0 ) == "Content-Transfer-Encoding" )
{
transferEncoding = kv.value( 1 );
break;
}
}
QString transferEncoding = parser.rawHeader( 1, QString( "Content-Transfer-Encoding" ).toAscii() );
QgsDebugMsg( "transferEncoding = " + transferEncoding );

// It may happen (GeoServer) that in part header is for example
// Content-Type: image/tiff and Content-Transfer-Encoding: base64
// but content is xml ExceptionReport which is not in base64
if ( partBodies.value( 1 ).startsWith( "<?xml" ) )
QByteArray body = parser.body( 1 );
if ( body.startsWith( "<?xml" ) )
{
if ( parseServiceExceptionReportDom( partBodies.value( 1 ) ) )
if ( parseServiceExceptionReportDom( body ) )
{
QgsMessageLog::logMessage( tr( "Map request error (Title:%1; Error:%2; URL: %3)" )
.arg( mErrorCaption ).arg( mError )
Expand All @@ -1015,7 +950,7 @@ void QgsWcsProvider::cacheReplyFinished()
else
{
QgsMessageLog::logMessage( tr( "Map request error (Response: %1; URL:%2)" )
.arg( QString::fromUtf8( partBodies.value( 1 ) ) )
.arg( QString::fromUtf8( body ) )
.arg( mCacheReply->url().toString() ), tr( "WCS" ) );
}

Expand All @@ -1026,11 +961,11 @@ void QgsWcsProvider::cacheReplyFinished()

if ( transferEncoding == "binary" )
{
mCachedData = partBodies.value( 1 );
mCachedData = body;
}
else if ( transferEncoding == "base64" )
{
mCachedData = QByteArray::fromBase64( partBodies.value( 1 ) );
mCachedData = QByteArray::fromBase64( body );
}
else
{
Expand All @@ -1051,6 +986,7 @@ void QgsWcsProvider::cacheReplyFinished()
mCachedData = mCacheReply->readAll();
}

QgsDebugMsg( QString( "%1 bytes received" ).arg( mCachedData.size() ) );
if ( mCachedData.size() == 0 )
{
QgsMessageLog::logMessage( tr( "No data received" ), tr( "WCS" ) );
Expand All @@ -1059,7 +995,6 @@ void QgsWcsProvider::cacheReplyFinished()
mCacheReply = 0;
return;
}
QgsDebugMsg( QString( "%1 bytes received" ).arg( mCachedData.size() ) );

#if 0
QFile myFile( "/tmp/qgiswcscache.dat" );
Expand Down
2 changes: 0 additions & 2 deletions src/providers/wfs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ SET(WFS_SRCS
qgswfsprovider.cpp
qgswfscapabilities.cpp
qgswfsdataitems.cpp
qgswfsdata.cpp
qgswfssourceselect.cpp
qgswfsutils.cpp
)

SET (WFS_MOC_HDRS
qgswfsdata.h
qgswfscapabilities.h
qgswfsdataitems.h
qgswfsprovider.h
Expand Down
10 changes: 10 additions & 0 deletions src/providers/wfs/qgswfscapabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@ void QgsWFSCapabilities::capabilitiesReplyFinished()

mCaps.clear();

//test wfs version
QString version = capabilitiesDocument.documentElement().attribute( "version" );
if ( version != "1.0.0" && version != "1.0" )
{
mErrorCode = WFSVersionNotSupported;
mErrorMessage = tr( "The WFS server does not support WFS version 1.0" );
emit gotCapabilities();
return;
}

// get the <FeatureType> elements
QDomNodeList featureTypeList = capabilitiesDocument.elementsByTagNameNS( WFS_NAMESPACE, "FeatureType" );
for ( unsigned int i = 0; i < featureTypeList.length(); ++i )
Expand Down
2 changes: 1 addition & 1 deletion src/providers/wfs/qgswfscapabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class QgsWFSCapabilities : public QObject
QList<FeatureType> featureTypes;
};

enum ErrorCode { NoError, NetworkError, XmlError, ServerExceptionError };
enum ErrorCode { NoError, NetworkError, XmlError, ServerExceptionError, WFSVersionNotSupported };
ErrorCode errorCode() { return mErrorCode; }
QString errorMessage() { return mErrorMessage; }

Expand Down
2 changes: 1 addition & 1 deletion src/providers/wms/qgswmssourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ QgsWMSSourceSelect::QgsWMSSourceSelect( QWidget * parent, Qt::WFlags fl, bool ma
: QDialog( parent, fl )
, mManagerMode( managerMode )
, mEmbeddedMode( embeddedMode )
, mCurrentTileset( 0 )
, mDefaultCRS( GEO_EPSG_CRS_AUTHID )
, mCurrentTileset( 0 )
{
setupUi( this );

Expand Down
Loading