Skip to content

Commit dfeb19b

Browse files
committedMay 12, 2011
Merge remote branch 'pb/master'
2 parents 5b1a9f9 + 76751f6 commit dfeb19b

23 files changed

+356
-48
lines changed
 

‎debian/control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Build-Depends:
2424
python-dev,
2525
python-qt4-dev (>=4.1.0),
2626
python-sip-dev (>= 4.5.0) | python-sip4-dev (>= 4.5.0) | sip4 (>= 4.5),
27-
git,
27+
git-core | git,
2828
txt2tags,
2929
doxygen
3030
Build-Conflicts: libqgis-dev, qgis-dev

‎debian/control.hardy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Build-Depends: debhelper (>= 5.0.51~), libgdal1-dev, libpq-dev,
88
python-sip4 (>= 4.5.0), python-central (>=0.5), python, sip4 (>= 4.5),
99
libqt4-core (>=4.2.0), libqt4-dev (>=4.2.0), libqt4-gui (>=4.2.0),
1010
libqt4-sql (>=4.2.0), python-qt4 (>=4.1.0), python-qt4-dev (>=4.1.0),
11-
python-sip4-dev (>= 4.5.0), pyqt4-dev-tools, fcgi-dev, git
11+
python-sip4-dev (>= 4.5.0), pyqt4-dev-tools, fcgi-dev, git-core
1212
Build-Conflicts: libqgis-dev, qgis-dev
1313
Standards-Version: 3.8.0
1414
XS-Python-Version: current

‎debian/control.intrepid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Build-Depends: debhelper (>= 5.0.51~), libgdal1-dev, libpq-dev,
99
libqt4-core (>=4.2.0), libqt4-dev (>=4.2.0), libqt4-gui (>=4.2.0),
1010
libqt4-sql (>=4.2.0), python-qt4 (>=4.1.0), python-qt4-dev (>=4.1.0),
1111
python-sip4-dev (>= 4.5.0), pyqt4-dev-tools, libqwt5-qt4-dev, libfcgi-dev,
12-
git, doxygen, graphviz, txt2tags
12+
git-core, doxygen, graphviz, txt2tags
1313
Build-Conflicts: libqgis-dev, qgis-dev
1414
Standards-Version: 3.8.0
1515
XS-Python-Version: current

‎debian/control.jaunty

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Build-Depends: debhelper (>= 5.0.51~), libgdal1-dev, libpq-dev,
99
libqt4-core (>=4.2.0), libqt4-dev (>=4.2.0), libqt4-gui (>=4.2.0),
1010
libqt4-sql (>=4.2.0), python-qt4 (>=4.1.0), python-qt4-dev (>=4.1.0),
1111
python-sip4-dev (>= 4.5.0), pyqt4-dev-tools, libqwt5-qt4-dev, libfcgi-dev,
12-
git, doxygen, graphviz, txt2tags
12+
git-core, doxygen, graphviz, txt2tags
1313
Build-Conflicts: libqgis-dev, qgis-dev
1414
Standards-Version: 3.8.0
1515
XS-Python-Version: current

‎debian/control.karmic

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Build-Depends: debhelper (>= 5.0.51~), libgdal1-dev, libpq-dev,
99
libqt4-core (>=4.2.0), libqt4-dev (>=4.2.0), libqt4-gui (>=4.2.0),
1010
libqt4-sql (>=4.2.0), python-qt4 (>=4.1.0), python-qt4-dev (>=4.1.0),
1111
python-sip4-dev (>= 4.5.0), pyqt4-dev-tools, libqwt5-qt4-dev, libfcgi-dev,
12-
git, doxygen, graphviz, txt2tags
12+
git-core, doxygen, graphviz, txt2tags
1313
Build-Conflicts: libqgis-dev, qgis-dev
1414
Standards-Version: 3.8.0
1515
XS-Python-Version: current

‎debian/control.lenny

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Build-Depends:
2727
python-qt4-dev (>=4.1.0),
2828
python-sip4-dev (>= 4.5.0),
2929
sip4 (>= 4.5),
30-
git,
30+
git-core,
3131
doxygen,
3232
graphviz,
3333
txt2tags

‎debian/control.lucid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Build-Depends:
2828
python-qt4-dev (>=4.1.0),
2929
python-sip (>= 4.5.0),
3030
python-sip-dev (>= 4.5.0),
31-
git,
31+
git-core,
3232
doxygen,
3333
graphviz,
3434
txt2tags

‎python/plugins/fTools/tools/doMergeShapes.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ def __init__( self, iface ):
1919
self.mergeThread = None
2020
self.inputFiles = None
2121
self.outFileName = None
22+
self.inEncoding = None
2223

2324
self.btnOk = self.buttonBox.button( QDialogButtonBox.Ok )
2425
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
2526

2627
QObject.connect( self.btnSelectDir, SIGNAL( "clicked()" ), self.inputDir )
2728
QObject.connect( self.btnSelectFile, SIGNAL( "clicked()" ), self.outFile )
2829
QObject.connect( self.chkListMode, SIGNAL( "stateChanged( int )" ), self.changeMode )
30+
QObject.connect( self.leOutShape, SIGNAL( "editingFinished()" ), self.updateOutFile )
2931

3032
def inputDir( self ):
3133
inDir = QFileDialog.getExistingDirectory( self,
@@ -83,6 +85,11 @@ def changeMode( self ):
8385
self.lblGeometry.setEnabled( True )
8486
self.cmbGeometry.setEnabled( True )
8587

88+
def updateOutFile( self ):
89+
self.outFileName = self.leOutShape.text()
90+
settings = QSettings()
91+
self.outEncoding = settings.value( "/UI/encoding" ).toString()
92+
8693
def reject( self ):
8794
QDialog.reject( self )
8895

@@ -110,22 +117,27 @@ def accept( self ):
110117
else:
111118
baseDir = self.leInputDir.text()
112119

113-
# look for shapes with specified geometry type
114-
self.inputFiles = ftools_utils.getShapesByGeometryType( baseDir, self.inputFiles, self.cmbGeometry.currentIndex() )
115-
116-
self.progressFiles.setRange( 0, self.inputFiles.count() )
117-
118120
outFile = QFile( self.outFileName )
119121
if outFile.exists():
120122
if not QgsVectorFileWriter.deleteShapeFile( self.outFileName ):
121123
QMessageBox.warning( self, self.tr( "Delete error" ), self.tr( "Can't delete file %1" ).arg( outFileName ) )
122124
return
123125

126+
# look for shapes with specified geometry type
127+
self.inputFiles = ftools_utils.getShapesByGeometryType( baseDir, self.inputFiles, self.cmbGeometry.currentIndex() )
128+
self.progressFiles.setRange( 0, self.inputFiles.count() )
129+
130+
if self.inEncoding == None:
131+
self.inEncoding = "System"
132+
124133
QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) )
125134
self.btnOk.setEnabled( False )
126135

127-
self.mergeThread = ShapeMergeThread( baseDir, self.inputFiles, self.outFileName, self.encoding )
136+
self.mergeThread = ShapeMergeThread( baseDir, self.inputFiles, self.inEncoding, self.outFileName, self.encoding )
128137
QObject.connect( self.mergeThread, SIGNAL( "rangeChanged( PyQt_PyObject )" ), self.setProgressRange )
138+
QObject.connect( self.mergeThread, SIGNAL( "checkStarted()" ), self.setFeatureProgressFormat )
139+
QObject.connect( self.mergeThread, SIGNAL( "checkFinished()" ), self.resetFeatureProgressFormat )
140+
QObject.connect( self.mergeThread, SIGNAL( "fileNameChanged( PyQt_PyObject )" ), self.setShapeProgressFormat )
129141
QObject.connect( self.mergeThread, SIGNAL( "featureProcessed()" ), self.featureProcessed )
130142
QObject.connect( self.mergeThread, SIGNAL( "shapeProcessed()" ), self.shapeProcessed )
131143
QObject.connect( self.mergeThread, SIGNAL( "processingFinished()" ), self.processingFinished )
@@ -141,9 +153,18 @@ def setProgressRange( self, max ):
141153
self.progressFeatures.setRange( 0, max )
142154
self.progressFeatures.setValue( 0 )
143155

156+
def setFeatureProgressFormat( self ):
157+
self.progressFeatures.setFormat( "Checking files: %p% ")
158+
159+
def resetFeatureProgressFormat( self ):
160+
self.progressFeatures.setFormat( "%p% ")
161+
144162
def featureProcessed( self ):
145163
self.progressFeatures.setValue( self.progressFeatures.value() + 1 )
146164

165+
def setShapeProgressFormat( self, fileName ):
166+
self.progressFiles.setFormat( "%p% " + fileName )
167+
147168
def shapeProcessed( self ):
148169
self.progressFiles.setValue( self.progressFiles.value() + 1 )
149170

@@ -152,7 +173,9 @@ def processingFinished( self ):
152173

153174
if self.chkAddToCanvas.isChecked():
154175
if not ftools_utils.addShapeToCanvas( unicode( self.outFileName ) ):
155-
QMessageBox.warning( self, self.tr( "Merging" ), self.tr( "Error loading output shapefile:\n%1" ).arg( unicode( self.outFileName ) ) )
176+
QMessageBox.warning( self, self.tr( "Merging" ),
177+
self.tr( "Error loading output shapefile:\n%1" )
178+
.arg( unicode( self.outFileName ) ) )
156179

157180
self.restoreGui()
158181

@@ -165,6 +188,7 @@ def stopProcessing( self ):
165188
self.mergeThread = None
166189

167190
def restoreGui( self ):
191+
self.progressFiles.setFormat( "%p%" )
168192
self.progressFeatures.setRange( 0, 100 )
169193
self.progressFeatures.setValue( 0 )
170194
self.progressFiles.setValue( 0 )
@@ -174,10 +198,11 @@ def restoreGui( self ):
174198
self.btnOk.setEnabled( True )
175199

176200
class ShapeMergeThread( QThread ):
177-
def __init__( self, dir, shapes, outputFileName, outputEncoding ):
201+
def __init__( self, dir, shapes, inputEncoding, outputFileName, outputEncoding ):
178202
QThread.__init__( self, QThread.currentThread() )
179203
self.baseDir = dir
180204
self.shapes = shapes
205+
self.inputEncoding = inputEncoding
181206
self.outputFileName = outputFileName
182207
self.outputEncoding = outputEncoding
183208

@@ -208,10 +233,12 @@ def run( self ):
208233
if not newLayer.isValid():
209234
continue
210235
vprovider = newLayer.dataProvider()
236+
vprovider.setEncoding( self.inputEncoding )
211237
allAttrs = vprovider.attributeIndexes()
212238
vprovider.select( allAttrs )
213239
nFeat = vprovider.featureCount()
214240
self.emit( SIGNAL( "rangeChanged( PyQt_PyObject )" ), nFeat )
241+
self.emit( SIGNAL( "fileNameChanged( PyQt_PyObject )" ), fileName )
215242
inFeat = QgsFeature()
216243
outFeat = QgsFeature()
217244
inGeom = QgsGeometry()

‎src/core/qgsvectorfilewriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ QgsVectorFileWriter::QgsVectorFileWriter(
147147

148148
if ( !found )
149149
{
150-
vectorFileName += "." + exts[0];
150+
vectorFileName += "." + allExts[0];
151151
}
152152
}
153153

‎src/gui/qgsmapcanvas.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
8282
, mCanvasProperties( new CanvasProperties )
8383
, mNewSize( QSize() )
8484
, mPainting( false )
85+
, mAntiAliasing( false )
8586
{
8687
//disable the update that leads to the resize crash
87-
if( viewport() )
88+
if ( viewport() )
8889
{
8990
viewport()->setAttribute( Qt::WA_PaintOnScreen, true );
9091
}
@@ -163,6 +164,7 @@ QgsMapCanvas::~QgsMapCanvas()
163164

164165
void QgsMapCanvas::enableAntiAliasing( bool theFlag )
165166
{
167+
mAntiAliasing = theFlag;
166168
mMap->enableAntiAliasing( theFlag );
167169
if ( mMapOverview )
168170
mMapOverview->enableAntiAliasing( theFlag );

‎src/gui/qgsmapcanvas.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
244244
//! used to determine if anti-aliasing is enabled or not
245245
void enableAntiAliasing( bool theFlag );
246246

247+
//! true if antialising is enabled
248+
bool antiAliasingEnabled() const { return mAntiAliasing; }
249+
247250
//! Select which Qt class to render with
248251
void useImageToRender( bool theFlag );
249252

@@ -463,6 +466,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
463466
//! currently in paint event
464467
bool mPainting;
465468

469+
//! indicates whether antialiasing will be used for rendering
470+
bool mAntiAliasing;
466471
}; // class QgsMapCanvas
467472

468473

‎src/gui/qgsmapcanvasitem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ void QgsMapCanvasItem::paint( QPainter * painter,
4242
const QStyleOptionGraphicsItem * option,
4343
QWidget * widget )
4444
{
45+
if ( mMapCanvas->antiAliasingEnabled() )
46+
{
47+
painter->setRenderHint( QPainter::Antialiasing );
48+
}
4549
paint( painter ); // call the derived item's drawing routines
4650
}
4751

‎src/mac/Contents/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
SET(COMPLETE_VERSION_WITH_RELEASE_NAME \"${COMPLETE_VERSION}-${RELEASE_NAME}\")
66
7-
IF (NOT EXISTS SVN_MARKER)
8-
SET (SVN_MARKER ${CMAKE_SOURCE_DIR}/CMakeLists.txt) # Dummy file
9-
ENDIF (NOT EXISTS SVN_MARKER)
7+
IF (NOT EXISTS GIT_MARKER)
8+
SET (GIT_MARKER ${CMAKE_SOURCE_DIR}/CMakeLists.txt) # Dummy file
9+
ENDIF (NOT EXISTS GIT_MARKER)
1010
1111
ADD_CUSTOM_TARGET(Info.plist ALL
12-
DEPENDS ${SVN_MARKER}
12+
DEPENDS ${GIT_MARKER}
1313
COMMAND ${CMAKE_COMMAND}
1414
-D CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
1515
-D SOURCE_DIR=${CMAKE_SOURCE_DIR}

‎src/mac/Contents/Info.plist.cmake

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
SET(CMAKE_BACKWARDS_COMPATIBILITY "2.4")
22

3-
# See if we have svn installed
4-
FIND_PROGRAM(SVNVERSION svnversion)
3+
# See if we have git installed
4+
FIND_PROGRAM (GIT git)
55

66
# Read the revision if installed, else set to "unknown"
7-
IF (SVNVERSION)
8-
EXEC_PROGRAM (${SVNVERSION} ARGS ${SOURCE_DIR} OUTPUT_VARIABLE REVISION)
9-
ELSE (SVNVERSION)
7+
IF (GIT)
8+
EXEC_PROGRAM (${GIT} ${SOURCE_DIR} ARGS "log -n1 --pretty=%h" OUTPUT_VARIABLE REVISION)
9+
ELSE (GIT)
1010
SET (REVISION unknown)
11-
ENDIF (SVNVERSION)
11+
ENDIF (GIT)
1212

1313
# Create Info.plist
1414
CONFIGURE_FILE (${CURRENT_SOURCE_DIR}/Info.plist.in

‎src/mac/Contents/Info.plist.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundleSignature</key>
1616
<string>QGIS</string>
1717
<key>CFBundleGetInfoString</key>
18-
<string>QGIS @VERSION@ (@REVISION@), © 2002-2010 QGIS Development Team</string>
18+
<string>QGIS @VERSION@ (@REVISION@), © 2002-2011 QGIS Development Team</string>
1919
<key>CFBundleShortVersionString</key>
2020
<string>@VERSION_NUM@</string>
2121
<key>CFBundleVersion</key>

‎src/mapserver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ENDIF (CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo
1717

1818
SET ( qgis_mapserv_SRCS
1919
qgis_map_serv.cpp
20+
qgscapabilitiescache.cpp
2021
qgsconfigcache.cpp
2122
qgsconfigparser.cpp
2223
qgsepsgcache.cpp

‎src/mapserver/qgis_map_serv.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ map service syntax for SOAP/HTTP POST
1818
***************************************************************************/
1919

2020
#include "qgsapplication.h"
21+
#include "qgscapabilitiescache.h"
2122
#include "qgsconfigcache.h"
2223
#include "qgsgetrequesthandler.h"
2324
#include "qgssoaprequesthandler.h"
@@ -191,6 +192,9 @@ int main( int argc, char * argv[] )
191192
}
192193
}
193194

195+
//create cache for capabilities XML
196+
QgsCapabilitiesCache capabilitiesCache;
197+
194198
//creating QgsMapRenderer is expensive (access to srs.db), so we do it here before the fcgi loop
195199
QgsMapRenderer* theMapRenderer = new QgsMapRenderer();
196200

@@ -291,20 +295,34 @@ int main( int argc, char * argv[] )
291295

292296
if ( requestIt->second == "GetCapabilities" )
293297
{
294-
QDomDocument capabilitiesDocument;
295-
try
298+
const QDomDocument* capabilitiesDocument = capabilitiesCache.searchCapabilitiesDocument( configFilePath );
299+
if( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
300+
{
301+
QgsMSDebugMsg( "Capabilities document not found in cache" );
302+
QDomDocument doc;
303+
try
304+
{
305+
doc = theServer->getCapabilities();
306+
}
307+
catch ( QgsMapServiceException& ex )
308+
{
309+
theRequestHandler->sendServiceException( ex );
310+
delete theRequestHandler;
311+
delete theServer;
312+
continue;
313+
}
314+
capabilitiesCache.insertCapabilitiesDocument( configFilePath, &doc );
315+
capabilitiesDocument = capabilitiesCache.searchCapabilitiesDocument( configFilePath );
316+
}
317+
else
296318
{
297-
capabilitiesDocument = theServer->getCapabilities();
319+
QgsMSDebugMsg( "Found capabilities document in cache" );
298320
}
299-
catch ( QgsMapServiceException& ex )
321+
322+
if( capabilitiesDocument )
300323
{
301-
theRequestHandler->sendServiceException( ex );
302-
delete theRequestHandler;
303-
delete theServer;
304-
continue;
324+
theRequestHandler->sendGetCapabilitiesResponse( *capabilitiesDocument );
305325
}
306-
QgsMSDebugMsg( "sending GetCapabilities response" );
307-
theRequestHandler->sendGetCapabilitiesResponse( capabilitiesDocument );
308326
delete theRequestHandler;
309327
delete theServer;
310328
continue;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/***************************************************************************
2+
qgscapabilitiescache.h
3+
----------------------
4+
begin : May 11th, 2011
5+
copyright : (C) 2011 by Marco Hugentobler
6+
email : marco dot hugentobler at sourcepole dot ch
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgscapabilitiescache.h"
19+
20+
QgsCapabilitiesCache::QgsCapabilitiesCache()
21+
{
22+
}
23+
24+
QgsCapabilitiesCache::~QgsCapabilitiesCache()
25+
{
26+
}
27+
28+
const QDomDocument* QgsCapabilitiesCache::searchCapabilitiesDocument( const QString& configFilePath ) const
29+
{
30+
QHash< QString, QDomDocument >::const_iterator it = mCachedCapabilities.find( configFilePath );
31+
if( it == mCachedCapabilities.constEnd() )
32+
{
33+
return 0;
34+
}
35+
else
36+
{
37+
return &(it.value());
38+
}
39+
}
40+
41+
void QgsCapabilitiesCache::insertCapabilitiesDocument( const QString& configFilePath, const QDomDocument* doc )
42+
{
43+
if( mCachedCapabilities.size() > 40 )
44+
{
45+
//remove another cache entry to avoid memory problems
46+
QHash<QString, QDomDocument>::iterator capIt = mCachedCapabilities.begin();
47+
mCachedCapabilities.erase( capIt );
48+
}
49+
mCachedCapabilities.insert( configFilePath, doc->cloneNode().toDocument() );
50+
}

‎src/mapserver/qgscapabilitiescache.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/***************************************************************************
2+
qgscapabilitiescache.h
3+
----------------------
4+
begin : May 11th, 2011
5+
copyright : (C) 2011 by Marco Hugentobler
6+
email : marco dot hugentobler at sourcepole dot ch
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSCAPABILITIESCACHE_H
19+
#define QGSCAPABILITIESCACHE_H
20+
21+
#include <QDomDocument>
22+
#include <QHash>
23+
24+
/**A cache for capabilities xml documents (by configuration file path)*/
25+
class QgsCapabilitiesCache
26+
{
27+
public:
28+
QgsCapabilitiesCache();
29+
~QgsCapabilitiesCache();
30+
31+
/**Returns cached capabilities document (or 0 if document for configuration file not in cache)*/
32+
const QDomDocument* searchCapabilitiesDocument( const QString& configFilePath ) const;
33+
/**Inserts new capabilities document (creates a copy of the document, does not take ownership)*/
34+
void insertCapabilitiesDocument( const QString& configFilePath, const QDomDocument* doc );
35+
36+
private:
37+
QHash< QString, QDomDocument > mCachedCapabilities;
38+
};
39+
40+
#endif // QGSCAPABILITIESCACHE_H

‎src/mapserver/qgsconfigcache.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ QgsConfigCache::QgsConfigCache()
2727

2828
QgsConfigCache::~QgsConfigCache()
2929
{
30-
QMap<QString, QgsConfigParser*>::iterator configIt = mCachedConfigurations.begin();
30+
QHash<QString, QgsConfigParser*>::iterator configIt = mCachedConfigurations.begin();
3131
for ( ; configIt != mCachedConfigurations.end(); ++configIt )
3232
{
3333
delete configIt.value();
@@ -37,7 +37,7 @@ QgsConfigCache::~QgsConfigCache()
3737
QgsConfigParser* QgsConfigCache::searchConfiguration( const QString& filePath )
3838
{
3939
QgsConfigParser* p = 0;
40-
QMap<QString, QgsConfigParser*>::const_iterator configIt = mCachedConfigurations.find( filePath );
40+
QHash<QString, QgsConfigParser*>::const_iterator configIt = mCachedConfigurations.find( filePath );
4141
if ( configIt == mCachedConfigurations.constEnd() )
4242
{
4343
QgsMSDebugMsg( "Create new configuration" );
@@ -61,12 +61,9 @@ QgsConfigParser* QgsConfigCache::insertConfiguration( const QString& filePath )
6161
{
6262
if ( mCachedConfigurations.size() > 40 )
6363
{
64-
//remove 10 elements to avoid memory problems
65-
QMap<QString, QgsConfigParser*>::iterator configIt = mCachedConfigurations.begin();
66-
for ( int i = 0; i < 10; ++i )
67-
{
68-
configIt = mCachedConfigurations.erase( configIt );
69-
}
64+
//remove a cache entry to avoid memory problems
65+
QHash<QString, QgsConfigParser*>::iterator configIt = mCachedConfigurations.begin();
66+
mCachedConfigurations.erase( configIt );
7067
}
7168

7269
//first open file

‎src/mapserver/qgsconfigcache.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#ifndef QGSCONFIGCACHE_H
1919
#define QGSCONFIGCACHE_H
2020

21-
#include <QMap>
21+
#include <QHash>
2222
#include <QString>
2323

2424
class QgsConfigParser;
@@ -39,7 +39,7 @@ class QgsConfigCache
3939
@return the inserted config parser or 0 in case of error*/
4040
QgsConfigParser* insertConfiguration( const QString& filePath );
4141
/**Cached XML configuration documents. Key: file path, value: config parser. Default configuration has key '$default$'*/
42-
QMap<QString, QgsConfigParser*> mCachedConfigurations;
42+
QHash<QString, QgsConfigParser*> mCachedConfigurations;
4343
};
4444

4545
#endif // QGSCONFIGCACHE_H

‎src/mapserver/qgswmsserver.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
350350
}
351351
delete theImage;
352352

353+
QMap<QString, QString> originalLayerFilters = applyRequestedLayerFilters( layersList, layerIdList );
354+
353355
//GetPrint request needs a template parameter
354356
std::map<QString, QString>::const_iterator templateIt = mParameterMap.find( "TEMPLATE" );
355357
if ( templateIt == mParameterMap.end() )
@@ -360,6 +362,7 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
360362
QgsComposition* c = mConfigParser->createPrintComposition( templateIt->second, mMapRenderer, QMap<QString, QString>( mParameterMap ) );
361363
if ( !c )
362364
{
365+
restoreLayerFilters( originalLayerFilters );
363366
return 0;
364367
}
365368

@@ -416,6 +419,7 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
416419
if ( !tempFile.open() )
417420
{
418421
delete c;
422+
restoreLayerFilters( originalLayerFilters );
419423
return 0;
420424
}
421425

@@ -450,6 +454,7 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
450454
{
451455
throw QgsMapServiceException( "InvalidFormat", "Output format '" + formatString + "' is not supported in the GetPrint request" );
452456
}
457+
restoreLayerFilters( originalLayerFilters );
453458

454459
delete c;
455460
return ba;
@@ -478,7 +483,10 @@ QImage* QgsWMSServer::getMap()
478483

479484
QPainter thePainter( theImage );
480485
thePainter.setRenderHint( QPainter::Antialiasing ); //make it look nicer
486+
487+
QMap<QString, QString> originalLayerFilters = applyRequestedLayerFilters( layersList, layerIdList );
481488
mMapRenderer->render( &thePainter );
489+
restoreLayerFilters( originalLayerFilters );
482490

483491
QgsMapLayerRegistry::instance()->mapLayers().clear();
484492
return theImage;
@@ -1500,3 +1508,150 @@ void QgsWMSServer::drawRasterSymbol( QgsComposerLegendItem* item, QPainter* p, d
15001508
}
15011509
p->setPen( savedPen );
15021510
}
1511+
1512+
QMap<QString, QString> QgsWMSServer::applyRequestedLayerFilters( const QStringList& layerList, const QStringList& layerIds ) const
1513+
{
1514+
QMap<QString, QString> filterMap;
1515+
1516+
if ( layerList.isEmpty() || layerIds.isEmpty() )
1517+
{
1518+
return filterMap;
1519+
}
1520+
1521+
std::map<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" );
1522+
if ( filterIt != mParameterMap.end() )
1523+
{
1524+
QString filterParameter = filterIt->second;
1525+
QStringList layerSplit = filterParameter.split( ";" );
1526+
QStringList::const_iterator layerIt = layerSplit.constBegin();
1527+
for ( ; layerIt != layerSplit.constEnd(); ++layerIt )
1528+
{
1529+
QStringList eqSplit = layerIt->split( ":" );
1530+
if ( eqSplit.size() < 2 )
1531+
{
1532+
continue;
1533+
}
1534+
1535+
//filter string could be unsafe (danger of sql injection)
1536+
if ( !testFilterStringSafety( eqSplit.at( 1 ) ) )
1537+
{
1538+
throw QgsMapServiceException( "Filter string rejected", "The filter string " + eqSplit.at( 1 ) +
1539+
" has been rejected because of security reasons. Note: Text strings have to be enclosed in single or double quotes. " +
1540+
"A space between each word / special character is mandatory. Allowed Keywords and special characters are " +
1541+
"AND,OR,IN,<,>=,>,>=,!=,',',(,). Not allowed are semicolons in the filter expression." );
1542+
}
1543+
1544+
//we know the layer name, but need to go through the list because a layer could be there several times...
1545+
int listPos = 1;
1546+
QStringList::const_iterator layerIt = layerList.constBegin();
1547+
for ( ; layerIt != layerList.constEnd(); ++layerIt )
1548+
{
1549+
if ( *layerIt == eqSplit.at( 0 ) )
1550+
{
1551+
QString layerId = layerIds.at( layerIds.size() - listPos );
1552+
QgsVectorLayer* filteredLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
1553+
if ( filteredLayer )
1554+
{
1555+
QgsVectorDataProvider* dp = filteredLayer->dataProvider();
1556+
if ( dp )
1557+
{
1558+
filterMap.insert( layerId, dp->subsetString() );
1559+
}
1560+
1561+
QString newSubsetString = eqSplit.at( 1 );
1562+
if ( !dp->subsetString().isEmpty() )
1563+
{
1564+
newSubsetString.prepend( " AND " );
1565+
newSubsetString.prepend( dp->subsetString() );
1566+
}
1567+
dp->setSubsetString( newSubsetString );
1568+
}
1569+
}
1570+
++listPos;
1571+
}
1572+
}
1573+
}
1574+
return filterMap;
1575+
}
1576+
1577+
void QgsWMSServer::restoreLayerFilters( const QMap < QString, QString >& filterMap ) const
1578+
{
1579+
QMap < QString, QString >::const_iterator filterIt = filterMap.constBegin();
1580+
for ( ; filterIt != filterMap.constEnd(); ++filterIt )
1581+
{
1582+
QgsVectorLayer* filteredLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( filterIt.key() ) );
1583+
if ( filteredLayer )
1584+
{
1585+
QgsVectorDataProvider* dp = filteredLayer->dataProvider();
1586+
if ( dp )
1587+
{
1588+
dp->setSubsetString( filterIt.value() );
1589+
}
1590+
}
1591+
}
1592+
}
1593+
1594+
bool QgsWMSServer::testFilterStringSafety( const QString& filter ) const
1595+
{
1596+
//; too dangerous for sql injections
1597+
if ( filter.contains( ";" ) )
1598+
{
1599+
return false;
1600+
}
1601+
1602+
QStringList tokens = filter.split( " ", QString::SkipEmptyParts );
1603+
QStringList::const_iterator tokenIt = tokens.constBegin();
1604+
for ( ; tokenIt != tokens.constEnd(); ++tokenIt )
1605+
{
1606+
//whitelist of allowed characters and keywords
1607+
if ( tokenIt->compare( "," ) == 0
1608+
|| tokenIt->compare( "(" ) == 0
1609+
|| tokenIt->compare( ")" ) == 0
1610+
|| tokenIt->compare( "=" ) == 0
1611+
|| tokenIt->compare( "!=" ) == 0
1612+
|| tokenIt->compare( "<" ) == 0
1613+
|| tokenIt->compare( "<=" ) == 0
1614+
|| tokenIt->compare( ">" ) == 0
1615+
|| tokenIt->compare( ">=" ) == 0
1616+
|| tokenIt->compare( "AND", Qt::CaseInsensitive ) == 0
1617+
|| tokenIt->compare( "OR", Qt::CaseInsensitive ) == 0
1618+
|| tokenIt->compare( "IN", Qt::CaseInsensitive ) == 0 )
1619+
{
1620+
continue;
1621+
}
1622+
1623+
//numbers are ok
1624+
bool isNumeric;
1625+
tokenIt->toDouble( &isNumeric );
1626+
if ( isNumeric )
1627+
{
1628+
continue;
1629+
}
1630+
1631+
//numeric strings need to be quoted once either with single or with double quotes
1632+
1633+
//single quote
1634+
if ( tokenIt->size() > 2
1635+
&& ( *tokenIt )[0] == QChar( '\'' )
1636+
&& ( *tokenIt )[tokenIt->size() - 1] == QChar( '\'' )
1637+
&& ( *tokenIt )[1] != QChar( '\'' )
1638+
&& ( *tokenIt )[tokenIt->size() - 2] != QChar( '\'' ) )
1639+
{
1640+
continue;
1641+
}
1642+
1643+
//double quote
1644+
if ( tokenIt->size() > 2
1645+
&& ( *tokenIt )[0] == QChar( '"' )
1646+
&& ( *tokenIt )[tokenIt->size() - 1] == QChar( '"' )
1647+
&& ( *tokenIt )[1] != QChar( '"' )
1648+
&& ( *tokenIt )[tokenIt->size() - 2] != QChar( '"' ) )
1649+
{
1650+
continue;
1651+
}
1652+
1653+
return false;
1654+
}
1655+
1656+
return true;
1657+
}

‎src/mapserver/qgswmsserver.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ class QgsWMSServer
138138

139139
QImage* printCompositionToImage( QgsComposition* c ) const;
140140

141+
/**Apply filter (subset) strings from the request to the layers. Example: '&FILTER=<layer1>:"AND property > 100",<layer2>:"AND bla = 'hallo!'" '
142+
@return a map with the original filters ( layer id / filter string )*/
143+
QMap<QString, QString> applyRequestedLayerFilters( const QStringList& layerList, const QStringList& layerIds ) const;
144+
/**Restores the original layer filters*/
145+
void restoreLayerFilters( const QMap < QString, QString >& filterMap ) const;
146+
/**Tests if a filter sql string is allowed (safe)
147+
@return true in case of success, false if string seems unsafe*/
148+
bool testFilterStringSafety( const QString& filter ) const;
149+
141150
/**Map containing the WMS parameters*/
142151
std::map<QString, QString> mParameterMap;
143152
QgsConfigParser* mConfigParser;

0 commit comments

Comments
 (0)
Please sign in to comment.