14,685 changes: 8,268 additions & 6,417 deletions i18n/qgis_lo.ts

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions images/images.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -490,24 +490,24 @@
<file>themes/default/text.png</file>
<file>themes/default/histogram.png</file>
<file>themes/default/pie-chart.png</file>
<file>console/iconClassConsole.png</file>
<file>console/iconSaveConsole.png</file>
<file>console/iconHelpConsole.png</file>
<file>console/iconSettingsConsole.png</file>
<file>console/iconOpenConsole.png</file>
<file>console/iconClearConsole.png</file>
<file>console/imgHelpDialog.png</file>
<file>console/iconSextanteConsole.png</file>
<file>console/iconScriptConsole.png</file>
<file>console/iconIfaceConsole.png</file>
<file>console/iconQtCoreConsole.png</file>
<file>console/iconQtGuiConsole.png</file>
<file>console/iconRunConsole.png</file>
<file>console/iconAboutConsole.png</file>
<file>console/iconCodepadConsole.png</file>
<file>console/imgHelpConsole.png</file>
<file>console/imgHelpMenu.png</file>
<file>console/iconHideToolConsole.png</file>
<file>themes/default/console/iconClassConsole.png</file>
<file>themes/default/console/iconSaveConsole.png</file>
<file>themes/default/console/iconHelpConsole.png</file>
<file>themes/default/console/iconSettingsConsole.png</file>
<file>themes/default/console/iconOpenConsole.png</file>
<file>themes/default/console/iconClearConsole.png</file>
<file>themes/default/console/imgHelpDialog.png</file>
<file>themes/default/console/iconSextanteConsole.png</file>
<file>themes/default/console/iconScriptConsole.png</file>
<file>themes/default/console/iconIfaceConsole.png</file>
<file>themes/default/console/iconQtCoreConsole.png</file>
<file>themes/default/console/iconQtGuiConsole.png</file>
<file>themes/default/console/iconRunConsole.png</file>
<file>themes/default/console/iconAboutConsole.png</file>
<file>themes/default/console/iconCodepadConsole.png</file>
<file>themes/default/console/imgHelpConsole.png</file>
<file>themes/default/console/imgHelpMenu.png</file>
<file>themes/default/console/iconHideToolConsole.png</file>
<file>flags/sr_Cyrl.png</file>
<file>flags/sr_Latn.png</file>
<file>flags/sw.png</file>
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
5 changes: 2 additions & 3 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)

ADD_SUBDIRECTORY(plugins)
ADD_SUBDIRECTORY(qsci_apis)
ADD_SUBDIRECTORY(console)

IF (WITH_PYSPATIALITE)
ADD_SUBDIRECTORY(pyspatialite)
Expand Down Expand Up @@ -150,7 +151,7 @@ ADD_CUSTOM_TARGET(pyutils ALL)
INSTALL(FILES ${PY_FILES} DESTINATION "${QGIS_PYTHON_DIR}")

# stage to output to make available when QGIS is run from build directory
FOREACH(pyfile ${PY_FILES} ${PYUI_FILES})
FOREACH(pyfile ${PY_FILES})
ADD_CUSTOM_COMMAND(TARGET pyutils
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} "${QGIS_PYTHON_OUTPUT_DIRECTORY}"
Expand All @@ -159,8 +160,6 @@ FOREACH(pyfile ${PY_FILES} ${PYUI_FILES})
)
ENDFOREACH(pyfile)

ADD_SUBDIRECTORY(console)

# Byte-compile staged PyQGIS utilities
IF(WITH_PY_COMPILE)
ADD_CUSTOM_TARGET(pycompile_pyutils ALL
Expand Down
14 changes: 7 additions & 7 deletions python/console/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
ADD_SUBDIRECTORY(console_help)

SET(PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)
SET(QGIS_PYTHON_DIR ${PYTHON_SITE_PACKAGES_DIR}/qgis)
SET (QGIS_CONSOLE_DIR ${QGIS_DATA_DIR}/python/console)
SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)

# PyQGIS console files to copy to staging or install
SET(PY_CONSOLE_FILES
console.py
console_sci.py
console_help.py
console_settings.py
console_output.py
__init__.py
)

FILE(GLOB UI_FILES *.ui)
PYQT4_WRAP_UI(PYUI_FILES ${UI_FILES}) # returns absolute paths
PYQT4_WRAP_UI(PYUI_FILES ${UI_FILES})
ADD_CUSTOM_TARGET(pyconsole ALL DEPENDS ${PYUI_FILES})

# stage to output to make available when QGIS is run from build directory
FOREACH(pyfile ${PY_CONSOLE_FILES} ${PYUI_FILES})
ADD_CUSTOM_COMMAND(TARGET pyconsole
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} "${QGIS_PYTHON_OUTPUT_DIRECTORY}"
COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTHON_OUTPUT_DIRECTORY}/console
COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} ${PYTHON_OUTPUT_DIRECTORY}/console
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${pyfile}
)
ENDFOREACH(pyfile)

INSTALL(FILES ${PY_CONSOLE_FILES} ${PYUI_FILES} DESTINATION "${QGIS_PYTHON_DIR}")
INSTALL(FILES ${PY_CONSOLE_FILES} ${PYUI_FILES} DESTINATION "${QGIS_CONSOLE_DIR}")

26 changes: 26 additions & 0 deletions python/console/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
__init__.py
---------------------
Date : September 2012
Copyright : (C) 2012 by Salvatore Larosa
Email : lrssvtml at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Salvatore Larosa'
__date__ = 'September 2012'
__copyright__ = '(C) 2012, Salvatore Larosa'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

from console import show_console
25 changes: 13 additions & 12 deletions python/console/console.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from console_output import EditorOutput
from console_help import HelpDialog
from console_settings import optionsDialog
from qgis.core import QgsApplication

import sys
import os
Expand Down Expand Up @@ -121,7 +122,7 @@ def __init__(self, parent=None):
self.clearButton = QAction(parent)
self.clearButton.setCheckable(False)
self.clearButton.setEnabled(True)
self.clearButton.setIcon(QIcon(":/images/console/iconClearConsole.png"))
self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.png"))
self.clearButton.setMenuRole(QAction.PreferencesRole)
self.clearButton.setIconVisibleInMenu(True)
self.clearButton.setToolTip(clearBt)
Expand All @@ -131,7 +132,7 @@ def __init__(self, parent=None):
self.optionsButton = QAction(parent)
self.optionsButton.setCheckable(False)
self.optionsButton.setEnabled(True)
self.optionsButton.setIcon(QIcon(":/images/console/iconSettingsConsole.png"))
self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.png"))
self.optionsButton.setMenuRole(QAction.PreferencesRole)
self.optionsButton.setIconVisibleInMenu(True)
self.optionsButton.setToolTip(optionsBt)
Expand All @@ -141,7 +142,7 @@ def __init__(self, parent=None):
self.actionClass = QAction(parent)
self.actionClass.setCheckable(False)
self.actionClass.setEnabled(True)
self.actionClass.setIcon(QIcon(":/images/console/iconClassConsole.png"))
self.actionClass.setIcon(QgsApplication.getThemeIcon("console/iconClassConsole.png"))
self.actionClass.setMenuRole(QAction.PreferencesRole)
self.actionClass.setIconVisibleInMenu(True)
self.actionClass.setToolTip(actionClassBt)
Expand All @@ -151,7 +152,7 @@ def __init__(self, parent=None):
self.actionScript = QAction(parent)
self.actionScript.setCheckable(False)
self.actionScript.setEnabled(True)
self.actionScript.setIcon(QIcon(":/images/console/iconScriptConsole.png"))
self.actionScript.setIcon(QgsApplication.getThemeIcon("console/iconScriptConsole.png"))
self.actionScript.setMenuRole(QAction.PreferencesRole)
self.actionScript.setIconVisibleInMenu(True)
self.actionScript.setToolTip(actionScriptBt)
Expand All @@ -161,7 +162,7 @@ def __init__(self, parent=None):
self.loadSextanteButton = QAction(parent)
self.loadSextanteButton.setCheckable(False)
self.loadSextanteButton.setEnabled(True)
self.loadSextanteButton.setIcon(QIcon(":/images/console/iconSextanteConsole.png"))
self.loadSextanteButton.setIcon(QgsApplication.getThemeIcon("console/iconSextanteConsole.png"))
self.loadSextanteButton.setMenuRole(QAction.PreferencesRole)
self.loadSextanteButton.setIconVisibleInMenu(True)
self.loadSextanteButton.setToolTip(loadSextanteBt)
Expand All @@ -171,7 +172,7 @@ def __init__(self, parent=None):
self.loadIfaceButton = QAction(parent)
self.loadIfaceButton.setCheckable(False)
self.loadIfaceButton.setEnabled(True)
self.loadIfaceButton.setIcon(QIcon(":/images/console/iconIfaceConsole.png"))
self.loadIfaceButton.setIcon(QgsApplication.getThemeIcon("console/iconIfaceConsole.png"))
self.loadIfaceButton.setMenuRole(QAction.PreferencesRole)
self.loadIfaceButton.setIconVisibleInMenu(True)
self.loadIfaceButton.setToolTip(loadIfaceBt)
Expand All @@ -181,7 +182,7 @@ def __init__(self, parent=None):
self.loadQtCoreButton = QAction(parent)
self.loadQtCoreButton.setCheckable(False)
self.loadQtCoreButton.setEnabled(True)
self.loadQtCoreButton.setIcon(QIcon(":/images/console/iconQtCoreConsole.png"))
self.loadQtCoreButton.setIcon(QgsApplication.getThemeIcon("console/iconQtCoreConsole.png"))
self.loadQtCoreButton.setMenuRole(QAction.PreferencesRole)
self.loadQtCoreButton.setIconVisibleInMenu(True)
self.loadQtCoreButton.setToolTip(loadQtCoreBt)
Expand All @@ -191,7 +192,7 @@ def __init__(self, parent=None):
self.loadQtGuiButton = QAction(parent)
self.loadQtGuiButton.setCheckable(False)
self.loadQtGuiButton.setEnabled(True)
self.loadQtGuiButton.setIcon(QIcon(":/images/console/iconQtGuiConsole.png"))
self.loadQtGuiButton.setIcon(QgsApplication.getThemeIcon("console/iconQtGuiConsole.png"))
self.loadQtGuiButton.setMenuRole(QAction.PreferencesRole)
self.loadQtGuiButton.setIconVisibleInMenu(True)
self.loadQtGuiButton.setToolTip(loadQtGuiBt)
Expand All @@ -201,7 +202,7 @@ def __init__(self, parent=None):
self.openFileButton = QAction(parent)
self.openFileButton.setCheckable(False)
self.openFileButton.setEnabled(True)
self.openFileButton.setIcon(QIcon(":/images/console/iconOpenConsole.png"))
self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.png"))
self.openFileButton.setMenuRole(QAction.PreferencesRole)
self.openFileButton.setIconVisibleInMenu(True)
self.openFileButton.setToolTip(openFileBt)
Expand All @@ -211,7 +212,7 @@ def __init__(self, parent=None):
self.saveFileButton = QAction(parent)
self.saveFileButton.setCheckable(False)
self.saveFileButton.setEnabled(True)
self.saveFileButton.setIcon(QIcon(":/images/console/iconSaveConsole.png"))
self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.png"))
self.saveFileButton.setMenuRole(QAction.PreferencesRole)
self.saveFileButton.setIconVisibleInMenu(True)
self.saveFileButton.setToolTip(saveFileBt)
Expand All @@ -221,7 +222,7 @@ def __init__(self, parent=None):
self.runButton = QAction(parent)
self.runButton.setCheckable(False)
self.runButton.setEnabled(True)
self.runButton.setIcon(QIcon(":/images/console/iconRunConsole.png"))
self.runButton.setIcon(QgsApplication.getThemeIcon("console/iconRunConsole.png"))
self.runButton.setMenuRole(QAction.PreferencesRole)
self.runButton.setIconVisibleInMenu(True)
self.runButton.setToolTip(runBt)
Expand All @@ -231,7 +232,7 @@ def __init__(self, parent=None):
self.helpButton = QAction(parent)
self.helpButton.setCheckable(False)
self.helpButton.setEnabled(True)
self.helpButton.setIcon(QIcon(":/images/console/iconHelpConsole.png"))
self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.png"))
self.helpButton.setMenuRole(QAction.PreferencesRole)
self.helpButton.setIconVisibleInMenu(True)
self.helpButton.setToolTip(helpBt)
Expand Down
30 changes: 15 additions & 15 deletions python/console/console_help/help.htm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<table id="header">
<tr>
<td>
<img src="qrc:/images/console/imgHelpDialog.png" />
<img src="qrc:/images/themes/default/console/imgHelpDialog.png" />
</td>
<td>
<span id="headerTitle" class="_title">Python Console for QGIS</span>
Expand All @@ -58,7 +58,7 @@
</td>
</tr>
<tr>
<td><img src="qrc:/images/console/imgHelpConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/imgHelpConsole.png" /></td>
</tr>
<tr>
<td>
Expand All @@ -69,7 +69,7 @@
You can drag and drop or copy text into input area (no matter if selected text contains >>> or ...).
Use 'Share on codepad' from contextual menu for sharing snippets code.
The context menu looks like the image below.</span><br><br>
<img src="qrc:/images/console/imgHelpMenu.png"><br>
<img src="qrc:/images/themes/default/console/imgHelpMenu.png"><br>
<span id="headerSubjectB">Input area pane is the interactive python shell for input commands.</span>
</p>
</td>
Expand Down Expand Up @@ -127,49 +127,49 @@
<p><span id="toolbarTitle">The following is a description of the tools in the toolbar:</span></p>
<table width="100%" border="0" id="headerTool">
<tr>
<td><img src="qrc:/images/console/iconClearConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconClearConsole.png" /></td>
<td colspan="2"><span id="toolbarClear">Tool to clear python console</span></td>
</tr>
<tr>
<td><img src="qrc:/images/console/iconClassConsole.png" /></td>
<td><img src="qrc:/images/console/iconIfaceConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconClassConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconIfaceConsole.png" /></td>
<td><span id="toolbarIfaceClass">Tool to import QgisInterface class</span></td>
</tr>
<tr>
<td></td>
<td><img src="qrc:/images/console/iconSextanteConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconSextanteConsole.png" /></td>
<td><span id="toolbarSextClass">Tool to import Sextante class</span></td>
</tr>
<tr>
<td></td>
<td><img src="qrc:/images/console/iconQtCoreConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconQtCoreConsole.png" /></td>
<td><span id="toolbarQtCoreClass">Tool to import PyQt4.QtCore class</span></td>
</tr>
<tr>
<td></td>
<td><img src="qrc:/images/console/iconQtGuiConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconQtGuiConsole.png" /></td>
<td><span id="toolbarQtGuiClass">Tool to import PyQt4.QtGui class</span></td>
</tr>
<tr>
<td><img src="qrc:/images/console/iconScriptConsole.png" /></td>
<td><img src="qrc:/images/console/iconOpenConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconScriptConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconOpenConsole.png" /></td>
<td><span id="toolbarScriptOpen">Tool to open a python script and load in console</span></td>
</tr>
<tr>
<td></td>
<td><img src="qrc:/images/console/iconSaveConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconSaveConsole.png" /></td>
<td><span id="toolbarScriptSave">Tool to save a python script</span></td>
</tr>
<tr>
<td><img src="qrc:/images/console/iconSettingsConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconSettingsConsole.png" /></td>
<td colspan="2"><span id="toolbarSettings">Settings</span></td>
</tr>
<tr>
<td><img src="qrc:/images/console/iconHelpConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconHelpConsole.png" /></td>
<td colspan="2"><span id="toolbarHelp">Help</span></td>
</tr>
<tr>
<td><img src="qrc:/images/console/iconRunConsole.png" /></td>
<td><img src="qrc:/images/themes/default/console/iconRunConsole.png" /></td>
<td colspan="2"><span id="toolbarRun">Run command (like Enter key pressed)</span></td>
</tr>
</table>
Expand Down
13 changes: 8 additions & 5 deletions python/console/console_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from PyQt4.Qsci import (QsciScintilla,
QsciScintillaBase,
QsciLexerPython)
from qgis.core import QgsApplication
import sys

class writeOut:
Expand All @@ -37,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 Expand Up @@ -162,10 +165,10 @@ def clearConsole(self):

def contextMenuEvent(self, e):
menu = QMenu(self)
iconRun = QIcon(":/images/console/iconRunConsole.png")
iconPastebin = QIcon(":/images/console/iconCodepadConsole.png")
iconClear = QIcon(":/images/console/iconClearConsole.png")
iconHideTool = QIcon(":/images/console/iconHideToolConsole.png")
iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png")
iconPastebin = QgsApplication.getThemeIcon("console/iconCodepadConsole.png")
iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.png")
iconHideTool = QgsApplication.getThemeIcon("console/iconHideToolConsole.png")
hideToolBar = menu.addAction(iconHideTool,
"Hide/Show Toolbar",
self.hideToolBar)
Expand Down
Empty file modified python/console/console_sci.py
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion python/core/symbology-ng/qgssvgcache.sip
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class QgsSvgCache : QObject
~QgsSvgCache();

const QImage& svgAsImage( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );
double widthScaleFactor, double rasterScaleFactor, bool& fitsInCache );
const QPicture& svgAsPicture( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,22 @@ def run(item, action, mainwindow):
prevRenderFlagState = iface.mapCanvas().renderFlag()
iface.mapCanvas().setRenderFlag( False )
try:
# NOTE: -1 parent is a request to always add to the root
# See http://hub.qgis.org/issues/6879
supergroup = legend.addGroup(u'Topology "%s"' % toponame, False, -1)
supergroup = legend.addGroup(u'Topology "%s"' % toponame, False)
# should not be needed: http://hub.qgis.org/issues/6938
legend.setGroupVisible(supergroup, False)

provider = db.dbplugin().providerName()
uri = db.uri();

# FACES
group = legend.addGroup(u'Faces', False, supergroup)
# should not be needed: http://hub.qgis.org/issues/6938
legend.setGroupVisible(group, False)

# 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')
'FROM %s.face WHERE face_id > 0' % (quoteStr(toponame), quoteId(toponame)),
'geom', 'face_id', u'geom')
layer.loadNamedStyle(os.path.join(template_dir, 'face.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -114,8 +116,8 @@ 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')
'FROM %s.face WHERE face_id > 0' % (quoteStr(toponame), quoteId(toponame)),
'geom', 'face_id', u'seed')
layer.loadNamedStyle(os.path.join(template_dir, 'face_seed.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
Expand All @@ -127,6 +129,8 @@ def run(item, action, mainwindow):

# NODES
group = legend.addGroup(u'Nodes', False, supergroup)
# should not be needed: http://hub.qgis.org/issues/6938
legend.setGroupVisible(group, False)

# node
uri.setDataSource(toponame, 'node', 'geom', '', 'node_id')
Expand All @@ -148,16 +152,27 @@ def run(item, action, mainwindow):

# EDGES
group = legend.addGroup(u'Edges', False, supergroup)
# should not be needed: http://hub.qgis.org/issues/6938
legend.setGroupVisible(group, False)

# edge
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'geom', 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.loadNamedStyle(os.path.join(template_dir, 'edge.qml'))
registry.addMapLayers([layer])
legend.setLayerVisible(layer, False)
legend.setLayerExpanded(layer, False)
legend.moveLayer(layer, group)


# edge labels
uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
layer = QgsVectorLayer(uri.uri(), u'edge_id', provider)
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/fTools/tools/doEliminate.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def eliminate(self, inLayer, boundary, progressBar, outFileName = None):
try:
found = fidsToEliminate.index(selFid)
except ValueError: #selFid is not in fidsToEliminate
# check wether the geometry to eliminate and the other geometry intersect
# check whether the geometry to eliminate and the other geometry intersect
selFeat = QgsFeature()

if outLayer.featureAtId(selFid, selFeat, True, False):
Expand All @@ -190,7 +190,7 @@ def eliminate(self, inLayer, boundary, progressBar, outFileName = None):
mergeWithFid = selFid
mergeWithGeom = QgsGeometry(selGeom) # deep copy of the geometry

if mergeWithFid: # a successful candidate
if mergeWithFid != None: # a successful candidate
try:
geomList = geomsToMerge[mergeWithFid]
except KeyError:
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 @@ -215,7 +215,7 @@ def randomize(self, inLayer, outPath, minimum, design, value):
points = self.vectorRandom(int(value), inLayer,
ext.xMinimum(), ext.xMaximum(), ext.yMinimum(), ext.yMaximum())
else: points = self.loopThruPolygons(inLayer, value, design)
crs = self.iface.mapCanvas().mapRenderer().destinationSrs()
crs = self.iface.mapCanvas().mapRenderer().destinationCrs()
if not crs.isValid(): crs = None
fields = { 0 : QgsField("ID", QVariant.Int) }
check = QFile(self.shapefileName)
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 @@ -85,7 +85,7 @@ def accept(self):
crs = mLayer.crs()
else:
boundBox = QgsRectangle(float(self.xMin.text()), float(self.yMin.text()), float(self.xMax.text()), float(self.yMax.text()))
crs = self.mapCanvas.mapRenderer().destinationSrs()
crs = self.mapCanvas.mapRenderer().destinationCrs()
print crs.isValid()
if not crs.isValid(): crs = None
self.regularize(boundBox, outPath, offset, value, self.rdoSpacing.isChecked(), self.spnInset.value(), crs)
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/fTools/tools/doValidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def zoomToError(self, curr, prev):
self.marker.setGeom(e)

rect = mc.extent()
rect.expand( 0.25, e )
rect.scale( 0.5, e )

else:
self.marker.reset()
Expand All @@ -186,7 +186,7 @@ def zoomToError(self, curr, prev):
return

rect = mc.mapRenderer().layerExtentToOutputExtent( self.vlayer, ft.geometry().boundingBox() )
rect.expand(1.05)
rect.scale( 1.05 )

# Set the extent to our new rectangle
mc.setExtent(rect)
Expand Down
8 changes: 4 additions & 4 deletions python/plugins/osm/OsmDatabaseManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,22 +168,22 @@ def layerRemoved(self,layerID):
key=dbFileName.toLatin1().data()

# remove map layers that belong to dbFileName database
if key in self.lineLayers.keys() and layer.id()==self.lineLayers[key].getLayerID():
if key in self.lineLayers.keys() and layer.id()==self.lineLayers[key].id():
del self.lineLayers[key]

elif key in self.pointLayers.keys() and layer.id()==self.pointLayers[key].id():
del self.pointLayers[key]
if key in self.lineLayers.keys():
if self.lineLayers[key]:
lineLayID=self.lineLayers[key].id()
self.mapReg.removeMapLayer(lineLayID,True)
self.mapReg.removeMapLayers([lineLayID],True)

elif key in self.polygonLayers.keys() and layer.id()==self.polygonLayers[key].id():
del self.polygonLayers[key]
if key in self.pointLayers.keys():
if self.pointLayers[key]:
pointLayID=self.pointLayers[key].id()
self.mapReg.removeMapLayer(pointLayID,True)
self.mapReg.removeMapLayers([pointLayID],True)

if key in self.dbConns.keys():
del self.dbConns[key]
Expand All @@ -202,7 +202,7 @@ def removeAllOsmLayers(self):
continue

if layer.type()==QgsMapLayer.VectorLayer and layer.dataProvider().name()=="osm":
QgsMapLayerRegistry.instance().removeMapLayer(layer.id(),True)
QgsMapLayerRegistry.instance().removeMapLayers([layer.id()],True)

self.dbConns={} # map dbFileName->sqlite3ConnectionObject
self.pointLayers={}
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/osm/OsmDownloadDlg.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def __init__(self, plugin):
# check whether the extent needs to be projected back to WGS84
mapRenderer = plugin.canvas.mapRenderer()
if mapRenderer.hasCrsTransformEnabled():
crsMap=mapRenderer.destinationSrs()
crsMap=mapRenderer.destinationCrs()
crsWgs84=QgsCoordinateReferenceSystem(4326)
xform=QgsCoordinateTransform(crsMap, crsWgs84)
currentExtent=xform.transformBoundingBox(currentExtent)
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/osm/OsmFeatureDW.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def projectionChanged(self):

renderer = self.plugin.canvas.mapRenderer()
if renderer.hasCrsTransformEnabled():
self.coordXform = QgsCoordinateTransform(renderer.destinationSrs(), QgsCoordinateReferenceSystem(4326))
self.coordXform = QgsCoordinateTransform(renderer.destinationCrs(), QgsCoordinateReferenceSystem(4326))
else:
self.coordXform = None

Expand Down
2 changes: 1 addition & 1 deletion scripts/tsstat.pl
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
ja => 'BABA Yoshihiko, Yoichi Kayama',
ka_GE => 'Shota Murtskhvaladze, George Machitidze',
ko_KR => 'BJ Jang',
lo => 'Anousak Souphavanh',
lo => 'Anousak Souphavanh, Soukanh Lathsavong',
lv => 'Maris Nartiss, Pēteris Brūns',
lt => 'Kestas M',
nl => 'Richard Duivenvoorde, Raymond Nijssen, Carlo van Rijswijk',
Expand Down
5 changes: 3 additions & 2 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,8 @@ void QgisApp::showPythonDialog()
return;

bool res = mPythonUtils->runStringUnsafe(
"import qgis.console\n"
"qgis.console.show_console()\n", false );
"import console\n"
"console.show_console()\n", false );

if ( !res )
{
Expand Down Expand Up @@ -1658,6 +1658,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionToggleFullScreen->setIcon( QgsApplication::getThemeIcon( "/mActionToggleFullScreen.png" ) );
mActionProjectProperties->setIcon( QgsApplication::getThemeIcon( "/mActionProjectProperties.png" ) );
mActionManagePlugins->setIcon( QgsApplication::getThemeIcon( "/mActionShowPluginManager.png" ) );
mActionShowPythonDialog->setIcon( QgsApplication::getThemeIcon( "console/iconRunConsole.png" ) );
mActionCheckQgisVersion->setIcon( QgsApplication::getThemeIcon( "/mActionCheckQgisVersion.png" ) );
mActionOptions->setIcon( QgsApplication::getThemeIcon( "/mActionOptions.png" ) );
mActionConfigureShortcuts->setIcon( QgsApplication::getThemeIcon( "/mActionOptions.png" ) );
Expand Down
6 changes: 6 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
7 changes: 7 additions & 0 deletions src/core/composer/qgscomposeritem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,13 @@ double QgsComposerItem::fontAscentMillimeters( const QFont& font ) const
return ( fontMetrics.ascent() / FONT_WORKAROUND_SCALE );
}

double QgsComposerItem::fontDescentMillimeters( const QFont& font ) const
{
QFont metricsFont = scaledFontPixelSize( font );
QFontMetricsF fontMetrics( metricsFont );
return ( fontMetrics.descent() / FONT_WORKAROUND_SCALE );
}

double QgsComposerItem::pixelFontSize( double pointSize ) const
{
return ( pointSize * 0.3527 );
Expand Down
3 changes: 3 additions & 0 deletions src/core/composer/qgscomposeritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
/**Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE*/
double fontAscentMillimeters( const QFont& font ) const;

/**Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE*/
double fontDescentMillimeters( const QFont& font ) const;

/**Calculates font to from point size to pixel size*/
double pixelFontSize( double pointSize ) const;

Expand Down
2 changes: 1 addition & 1 deletion src/core/composer/qgscomposerlegend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ QSizeF QgsComposerLegend::drawTitle( QPainter* painter, QPointF point, Qt::Align
{
// it does not draw the last world if rectangle width is exactly text width
double width = textWidthMillimeters( mTitleFont, *titlePart ) + 1;
double height = fontAscentMillimeters( mTitleFont );
double height = fontAscentMillimeters( mTitleFont ) + fontDescentMillimeters( mTitleFont );

double left = halignement == Qt::AlignLeft ? point.x() : point.x() - width / 2;

Expand Down
4 changes: 4 additions & 0 deletions src/core/gps/tok.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <locale.h>

#define NMEA_TOKS_COMPARE (1)
#define NMEA_TOKS_PERCENT (2)
Expand Down Expand Up @@ -86,7 +87,10 @@ double nmea_atof( const char *str, int str_sz )
{
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 );
}

return res;
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;
}
81 changes: 81 additions & 0 deletions src/core/qgsnetworkreplyparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/***************************************************************************
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
* @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
File renamed without changes.
2 changes: 1 addition & 1 deletion src/providers/wfs/qgswfsdata.h → src/core/qgswfsdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ 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:
Expand Down
137 changes: 70 additions & 67 deletions src/core/raster/qgsrasterfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,9 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType , destHasNoDataValueList, destNoDataValueList );
error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
}
if ( destProvider ) delete destProvider;

if ( destProvider )
delete destProvider;

return error;
}
Expand Down Expand Up @@ -347,9 +349,9 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
}

// hmm why is there a while( true ) here ..
// hmm why is there a for(;;) here ..
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
while ( true )
for ( ;; )
{
for ( int i = 1; i <= nBands; ++i )
{
Expand All @@ -359,8 +361,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
//delete destProvider;
if ( mTiledMode )
{
QFileInfo outputInfo( mOutputUrl );
QString vrtFilePath( mOutputUrl + "/" + outputInfo.baseName() + ".vrt" );
QString vrtFilePath( mOutputUrl + "/" + vrtFileName() );
writeVRT( vrtFilePath );
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
{
Expand Down Expand Up @@ -421,17 +422,20 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
iterLeft, iterTop, mOutputUrl,
fileIndex, nBands, destDataType, crs );

//write data to output file. todo: loop over the data list
for ( int i = 1; i <= nBands; ++i )
if ( partDestProvider )
{
partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
delete destBlockList[i - 1];
addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
//write data to output file. todo: loop over the data list
for ( int i = 1; i <= nBands; ++i )
{
partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
delete destBlockList[i - 1];
addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
}
delete partDestProvider;
}
delete partDestProvider;
}
else
else if ( destProvider )
{
//loop over data
for ( int i = 1; i <= nBands; ++i )
Expand Down Expand Up @@ -556,19 +560,22 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
iterLeft, iterTop, mOutputUrl, fileIndex,
4, QGis::Byte, crs );

//write data to output file
partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 );
partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 );
partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 );
partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 );

addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
delete partDestProvider;
if ( partDestProvider )
{
//write data to output file
partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 );
partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 );
partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 );
partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 );

addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
delete partDestProvider;
}
}
else
else if ( destProvider )
{
destProvider->write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
destProvider->write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
Expand All @@ -579,7 +586,9 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
++fileIndex;
}

if ( destProvider ) delete destProvider;
if ( destProvider )
delete destProvider;

QgsFree( redData ); QgsFree( greenData ); QgsFree( blueData ); QgsFree( alphaData );

if ( progressDialog )
Expand All @@ -589,8 +598,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste

if ( mTiledMode )
{
QFileInfo outputInfo( mOutputUrl );
QString vrtFilePath( mOutputUrl + "/" + outputInfo.baseName() + ".vrt" );
QString vrtFilePath( mOutputUrl + "/" + vrtFileName() );
writeVRT( vrtFilePath );
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
{
Expand Down Expand Up @@ -674,13 +682,15 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename )
overviewList[4] = 32;
overviewList[5] = 64;

/*if ( mProgressDialog )
#if 0
if ( mProgressDialog )
{
mProgressDialog->setLabelText( QObject::tr( "Building Pyramids..." ) );
mProgressDialog->setValue( 0 );
mProgressDialog->setWindowModality( Qt::WindowModal );
mProgressDialog->show();
}*/
}
#endif
GDALBuildOverviews( dataSet, "AVERAGE", 6, overviewList, 0, 0, /*pyramidsProgress*/ 0, /*mProgressDialog*/ 0 );
}
#endif
Expand Down Expand Up @@ -872,12 +882,14 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang
QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );

QString outputFile = outputUrl + "/" + partFileName( fileIndex );
#if 0
//QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile );
//QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile );
//if ( !destProvider )
//{
// return 0;
//}
QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile );
if ( !destProvider )
{
return 0;
}
#endif

//geotransform
double geoTransform[6];
Expand All @@ -889,29 +901,18 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang
geoTransform[5] = -mup;

// perhaps we need a separate createOptions for tiles ?
/*
if ( !destProvider->create( mOutputFormat, nBands, type, iterCols, iterRows, geoTransform,
crs ) )
{
delete destProvider;
return 0;
}
*/

QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions ) ;

if ( !destProvider )
{
return 0;
}

// TODO: return provider and report error
if ( !destProvider->isValid() )
#if 0
if ( !destProvider->create( mOutputFormat, nBands, type, iterCols, iterRows, geoTransform,
crs ) )
{
delete destProvider;
return 0;
}
#endif

QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions ) ;

// TODO: return provider and report error
return destProvider;
}

Expand All @@ -926,35 +927,31 @@ QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, co
}
else
{
#if 0
// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
// should this belong in provider? should also test that source provider is gdal
// if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
// mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
#endif

//QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl );
//QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, mOutputUrl );
QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, nCols, nRows, geoTransform, crs, mCreateOptions ) ;

if ( !destProvider )
{
return 0;
QgsDebugMsg( "No provider created" );
}

// TODO: return provider and report error
if ( !destProvider->isValid() )
#if 0
if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform,
crs, mCreateOptions ) )
{
delete destProvider;
return 0;
}
#endif

/*
if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform,
crs, mCreateOptions ) )
{
delete destProvider;
return 0;
}
*/
return destProvider;
}
}
Expand All @@ -981,5 +978,11 @@ QString QgsRasterFileWriter::partFileName( int fileIndex )
{
// .tif for now
QFileInfo outputInfo( mOutputUrl );
return QString( "%1.%2.tif" ).arg( outputInfo.baseName() ).arg( fileIndex );
return QString( "%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
}

QString QgsRasterFileWriter::vrtFileName()
{
QFileInfo outputInfo( mOutputUrl );
return QString( "%1.vrt" ).arg( outputInfo.fileName() );
}
1 change: 1 addition & 0 deletions src/core/raster/qgsrasterfilewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class CORE_EXPORT QgsRasterFileWriter
void globalOutputParameters( const QgsRectangle& extent, int nCols, int& nRows, double* geoTransform, double& pixelSize );

QString partFileName( int fileIndex );
QString vrtFileName();

Mode mMode;
QString mOutputUrl;
Expand Down
55 changes: 44 additions & 11 deletions src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double
mOutlineWidth = 0.3;
mAngle = angle;
setDefaultSvgParams();
mSvgPattern = 0;
}

QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): QgsImageFillSymbolLayer(), mPatternWidth( width ),
Expand All @@ -300,11 +301,13 @@ QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double
mAngle = angle;
setSubSymbol( new QgsLineSymbolV2() );
setDefaultSvgParams();
mSvgPattern = 0;
}

QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer()
{
delete mOutline;
delete mSvgPattern;
}

void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
Expand Down Expand Up @@ -382,22 +385,52 @@ void QgsSVGFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
return;
}

int size = context.outputPixelSize( mPatternWidth );
const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( mSvgFilePath, size, mSvgFillColor, mSvgOutlineColor, mSvgOutlineWidth,
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
QTransform brushTransform;
brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
if ( !doubleNear( context.alpha(), 1.0 ) )
delete mSvgPattern;
mSvgPattern = 0;
double size = context.outputPixelSize( mPatternWidth );

//don't render pattern if symbol size is below one or above 10,000 pixels
if (( int )size < 1.0 || 10000.0 < size )
{
QImage transparentImage = patternImage.copy();
QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
mBrush.setTextureImage( transparentImage );
mSvgPattern = new QImage();
mBrush.setTextureImage( *mSvgPattern );
}
else
{
mBrush.setTextureImage( patternImage );
bool fitsInCache = true;
const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( mSvgFilePath, size, mSvgFillColor, mSvgOutlineColor, mSvgOutlineWidth,
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );

if ( !fitsInCache )
{
const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( mSvgFilePath, size, mSvgFillColor, mSvgOutlineColor, mSvgOutlineWidth,
context.renderContext().scaleFactor(), 1.0 );
double hwRatio = 1.0;
if ( patternPict.width() > 0 )
{
hwRatio = ( double )patternPict.height() / ( double )patternPict.width();
}
mSvgPattern = new QImage(( int )size, ( int )( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
mSvgPattern->fill( 0 ); // transparent background

QPainter p( mSvgPattern );
p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
}

QTransform brushTransform;
brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
if ( !doubleNear( context.alpha(), 1.0 ) )
{
QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
mBrush.setTextureImage( transparentImage );
}
else
{
mBrush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
}
mBrush.setTransform( brushTransform );
}
mBrush.setTransform( brushTransform );

if ( mOutline )
{
Expand Down
3 changes: 3 additions & 0 deletions src/core/symbology-ng/qgsfillsymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ class CORE_EXPORT QgsSVGFillSymbolLayer: public QgsImageFillSymbolLayer
QString mSvgFilePath;
/**SVG view box (to keep the aspect ratio */
QRectF mSvgViewBox;
/** SVG pattern image
* @note added in 1.9 */
QImage* mSvgPattern;

//param(fill), param(outline), param(outline-width) are going
//to be replaced in memory
Expand Down
66 changes: 45 additions & 21 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,55 +637,79 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re
return;
}

double size = context.outputLineWidth( mSize );
//don't render symbols with size below one or above 10,000 pixels
if (( int )size < 1 || 10000.0 < size )
{
return;
}

p->save();
QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
if ( mAngle )
outputOffset = _rotatedOffset( outputOffset, mAngle );
p->translate( point + outputOffset );

int size = ( int )( context.outputLineWidth( mSize ) );
if ( size < 1 ) //don't render symbols with size below one pixel
{
return;
}

bool rotated = !doubleNear( mAngle, 0 );
bool drawOnScreen = doubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 );
if ( rotated )
p->rotate( mAngle );

bool fitsInCache = true;
bool usePict = true;
double hwRatio = 1.0;
if ( drawOnScreen && !rotated )
{
usePict = false;
const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, size, mFillColor, mOutlineColor, mOutlineWidth,
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
//consider transparency
if ( !doubleNear( context.alpha(), 1.0 ) )
{
QImage transparentImage = img.copy();
QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
}
else
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
if ( fitsInCache && img.width() > 1 )
{
p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
//consider transparency
if ( !doubleNear( context.alpha(), 1.0 ) )
{
QImage transparentImage = img.copy();
QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width();
}
else
{
p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
hwRatio = ( double )img.height() / ( double )img.width();
}
}
}
else

if ( usePict || !fitsInCache )
{
p->setOpacity( context.alpha() );
const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, size, mFillColor, mOutlineColor, mOutlineWidth,
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
p->drawPicture( 0, 0, pct );

if ( pct.width() > 1 )
{
p->drawPicture( 0, 0, pct );
hwRatio = ( double )pct.height() / ( double )pct.width();
}
}

if ( context.selected() )
{
QPen pen( context.selectionColor() );
pen.setWidth( context.outputLineWidth( 1.0 ) );
double penWidth = context.outputLineWidth( 1.0 );
if ( penWidth > size / 20 )
{
// keep the pen width from covering symbol
penWidth = size / 20;
}
double penOffset = penWidth / 2;
pen.setWidth( penWidth );
p->setPen( pen );
p->setBrush( Qt::NoBrush );
double sizePixel = context.outputLineWidth( mSize );
p->drawRect( QRectF( -sizePixel / 2.0, -sizePixel / 2.0, sizePixel, sizePixel ) );
double wSize = size + penOffset;
double hSize = size * hwRatio + penOffset;
p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
}

p->restore();
Expand Down
107 changes: 85 additions & 22 deletions src/core/symbology-ng/qgssvgcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
***************************************************************************/

#include "qgssvgcache.h"
#include "qgis.h"
#include "qgslogger.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsmessagelog.h"
Expand All @@ -33,7 +34,7 @@
#include <QNetworkReply>
#include <QNetworkRequest>

QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ),
QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0.0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ),
outline( Qt::black ), image( 0 ), picture( 0 )
{
}
Expand Down Expand Up @@ -107,28 +108,52 @@ QgsSvgCache::~QgsSvgCache()
}


const QImage& QgsSvgCache::svgAsImage( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor )
const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor, bool& fitsInCache )
{
fitsInCache = true;
QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );

//if current entry image is 0: cache image for entry
// checks to see if image will fit into cache
//update stats for memory usage
if ( !currentEntry->image )
{
cacheImage( currentEntry );
QSvgRenderer r( currentEntry->svgContent );
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
long cachedDataSize = 0;
cachedDataSize += currentEntry->svgContent.size();
cachedDataSize += ( int )( currentEntry->size * currentEntry->size * hwRatio * 32 );
if ( cachedDataSize > mMaximumSize / 2 )
{
fitsInCache = false;
delete currentEntry->image;
currentEntry->image = 0;
//currentEntry->image = new QImage( 0, 0 );

// instead cache picture
cachePicture( currentEntry );
}
else
{
cacheImage( currentEntry );
}
trimToMaximumSize();
}

return *( currentEntry->image );
}

const QPicture& QgsSvgCache::svgAsPicture( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor )
{
QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );

//if current entry image is 0: cache image for entry
//if current entry picture is 0: cache picture for entry
//update stats for memory usage
if ( !currentEntry->picture )
{
Expand All @@ -139,7 +164,7 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, int size, const
return *( currentEntry->picture );
}

QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor )
{
QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline );
Expand Down Expand Up @@ -326,21 +351,38 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry )
delete entry->image;
entry->image = 0;

int imageSize = entry->size;
QImage* image = new QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
QSvgRenderer r( entry->svgContent );
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
double wSize = entry->size;
int wImgSize = ( int )wSize;
if ( wImgSize < 1 )
{
wImgSize = 1;
}
double hSize = wSize * hwRatio;
int hImgSize = ( int )hSize;
if ( hImgSize < 1 )
{
hImgSize = 1;
}
// cast double image sizes to int for QImage
QImage* image = new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
image->fill( 0 ); // transparent background

QPainter p( image );
QSvgRenderer r( entry->svgContent );
if ( r.viewBox().width() == r.viewBox().height() )
if ( r.viewBoxF().width() == r.viewBoxF().height() )
{
r.render( &p );
}
else
{
QSize s( r.viewBox().size() );
s.scale( imageSize, imageSize, Qt::KeepAspectRatio );
QRect rect(( imageSize - s.width() ) / 2, ( imageSize - s.height() ) / 2, s.width(), s.height() );
QSizeF s( r.viewBoxF().size() );
s.scale( wSize, hSize, Qt::KeepAspectRatio );
QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
r.render( &p, rect );
}

Expand All @@ -360,18 +402,39 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry )

//correct QPictures dpi correction
QPicture* picture = new QPicture();
double pictureSize = entry->size / 25.4 / ( entry->rasterScaleFactor * entry->widthScaleFactor ) * picture->logicalDpiX();
QRectF rect( QPointF( -pictureSize / 2.0, -pictureSize / 2.0 ), QSizeF( pictureSize, pictureSize ) );

QRectF rect;
QSvgRenderer r( entry->svgContent );
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
bool drawOnScreen = doubleNear( entry->rasterScaleFactor, 1.0, 0.1 );
if ( drawOnScreen )
{
// fix to ensure rotated symbols scale with composer page (i.e. not map item) zoom
double wSize = entry->size;
double hSize = wSize * hwRatio;
QSizeF s( r.viewBoxF().size() );
s.scale( wSize, hSize, Qt::KeepAspectRatio );
rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
}
else
{
// output for print or image saving @ specific dpi
double scaledSize = entry->size / 25.4 / ( entry->rasterScaleFactor * entry->widthScaleFactor );
double wSize = scaledSize * picture->logicalDpiX();
double hSize = scaledSize * picture->logicalDpiY() * r.viewBoxF().height() / r.viewBoxF().width();
rect = QRectF( QPointF( -wSize / 2.0, -hSize / 2.0 ), QSizeF( wSize, hSize ) );
}

QSvgRenderer renderer( entry->svgContent );
QPainter painter( picture );
renderer.render( &painter, rect );
QPainter p( picture );
r.render( &p, rect );
entry->picture = picture;
mTotalSize += entry->picture->size();
}

QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor )
{
//search entries in mEntryLookup
Expand All @@ -382,7 +445,7 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, int size, const
for ( ; entryIt != entries.end(); ++entryIt )
{
QgsSvgCacheEntry* cacheEntry = *entryIt;
if ( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline &&
if ( cacheEntry->file == file && doubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->outline == outline &&
cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor )
{
currentEntry = cacheEntry;
Expand Down
14 changes: 7 additions & 7 deletions src/core/symbology-ng/qgssvgcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CORE_EXPORT QgsSvgCacheEntry
~QgsSvgCacheEntry();

QString file;
int size; //size in pixel
double size; //size in pixels (cast to int for QImage)
double outlineWidth;
double widthScaleFactor;
double rasterScaleFactor;
Expand Down Expand Up @@ -69,9 +69,9 @@ class CORE_EXPORT QgsSvgCache : public QObject
static QgsSvgCache* instance();
~QgsSvgCache();

const QImage& svgAsImage( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );
const QPicture& svgAsPicture( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
const QImage& svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor, bool& fitsInCache );
const QPicture& svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );

/**Tests if an svg file contains parameters for fill, outline color, outline width. If yes, possible default values are returned. If there are several
Expand All @@ -84,21 +84,21 @@ class CORE_EXPORT QgsSvgCache : public QObject

signals:
/** Emit a signal to be caught by qgisapp and display a msg on status bar */
void statusChanged( QString const & theStatusQString );
void statusChanged( const QString& theStatusQString );

protected:
//! protected constructor
QgsSvgCache( QObject * parent = 0 );

/**Creates new cache entry and returns pointer to it*/
QgsSvgCacheEntry* insertSVG( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
QgsSvgCacheEntry* insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );

void replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry );
void cacheImage( QgsSvgCacheEntry* entry );
void cachePicture( QgsSvgCacheEntry* entry );
/**Returns entry from cache or creates a new entry if it does not exist already*/
QgsSvgCacheEntry* cacheEntry( const QString& file, int size, const QColor& fill, const QColor& outline, double outlineWidth,
QgsSvgCacheEntry* cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );

/**Removes the least used items until the maximum size is under the limit*/
Expand Down
3 changes: 2 additions & 1 deletion src/gui/symbology-ng/qgssymbollayerv2widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,8 @@ class QgsSvgListModel : public QAbstractListModel
bool fillParam, outlineParam, outlineWidthParam;
QgsSvgCache::instance()->containsParams( entry, fillParam, fill, outlineParam, outline, outlineWidthParam, outlineWidth );

const QImage& img = QgsSvgCache::instance()->svgAsImage( entry, 30, fill, outline, outlineWidth, 3.5 /*appr. 88 dpi*/, 1.0 );
bool fitsInCache; // should always fit in cache at these sizes (i.e. under 559 px ^ 2, or half cache size)
const QImage& img = QgsSvgCache::instance()->svgAsImage( entry, 30.0, fill, outline, outlineWidth, 3.5 /*appr. 88 dpi*/, 1.0, fitsInCache );
pixmap = QPixmap::fromImage( img );
QPixmapCache::insert( entry, pixmap );
}
Expand Down
36 changes: 21 additions & 15 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ int CPL_STDCALL progressCallback( double dfComplete,
QgsGdalProvider::QgsGdalProvider( QString const & uri, QgsError error )
: QgsRasterDataProvider( uri )
, mValid( false )
, mGdalBaseDataset( 0 )
, mGdalDataset( 0 )
{
setError( error );
}
Expand All @@ -103,13 +105,11 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri, bool update )
: QgsRasterDataProvider( uri )
, QgsGdalProviderBase()
, mUpdate( update )
, mValid( true )
, mValid( false )
, mGdalBaseDataset( 0 )
, mGdalDataset( 0 )
{
QgsDebugMsg( "QgsGdalProvider: constructing with uri '" + uri + "'." );

mValid = false;
mGdalBaseDataset = 0;
mGdalDataset = 0;
QgsDebugMsg( "constructing with uri '" + uri + "'." );

QgsGdalProviderBase::registerGdalDrivers();

Expand All @@ -123,7 +123,7 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri, bool update )
return;
}

mGdalDataset = NULL;
mGdalDataset = 0;

// Try to open using VSIFileHandler (see qgsogrprovider.cpp)
QString vsiPrefix = QgsZipItem::vsiPrefix( uri );
Expand Down Expand Up @@ -196,7 +196,7 @@ bool QgsGdalProvider::crsFromWkt( const char *wkt )

QgsGdalProvider::~QgsGdalProvider()
{
QgsDebugMsg( "QgsGdalProvider: deconstructing." );
QgsDebugMsg( "entering." );
if ( mGdalBaseDataset )
{
GDALDereferenceDataset( mGdalBaseDataset );
Expand Down Expand Up @@ -2414,10 +2414,7 @@ QGISEXTERN QgsGdalProvider * create(
return new QgsGdalProvider( uri, error );
}

QString tmpStr = "create options:";
foreach ( QString option, createOptions )
tmpStr += " " + option;
QgsDebugMsg( tmpStr );
QgsDebugMsg( "create options: " + createOptions.join( " " ) );

//create dataset
CPLErrorReset();
Expand All @@ -2427,6 +2424,7 @@ QGISEXTERN QgsGdalProvider * create(
if ( dataset == NULL )
{
QgsError error( QString( "Cannot create new dataset %1:\n%2" ).arg( uri ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ), "GDAL provider" );
QgsDebugMsg( error.summary() );
return new QgsGdalProvider( uri, error );
}

Expand All @@ -2439,17 +2437,25 @@ QGISEXTERN QgsGdalProvider * create(

bool QgsGdalProvider::write( void* data, int band, int width, int height, int xOffset, int yOffset )
{
if ( !mGdalDataset )
{
return false;
}

GDALRasterBandH rasterBand = GDALGetRasterBand( mGdalDataset, band );
if ( rasterBand == NULL )
if ( !rasterBand )
{
return false;
}
return ( GDALRasterIO( rasterBand, GF_Write, xOffset, yOffset, width, height, data, width, height, GDALGetRasterDataType( rasterBand ), 0, 0 ) == CE_None );
return GDALRasterIO( rasterBand, GF_Write, xOffset, yOffset, width, height, data, width, height, GDALGetRasterDataType( rasterBand ), 0, 0 ) == CE_None;
}

bool QgsGdalProvider::setNoDataValue( int bandNo, double noDataValue )
{
if ( !mGdalDataset ) return false;
if ( !mGdalDataset )
{
return false;
}

GDALRasterBandH rasterBand = GDALGetRasterBand( mGdalDataset, bandNo );
CPLErrorReset();
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
10 changes: 6 additions & 4 deletions src/providers/wms/qgswmssourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ QgsWMSSourceSelect::QgsWMSSourceSelect( QWidget * parent, Qt::WFlags fl, bool ma
, mManagerMode( managerMode )
, mEmbeddedMode( embeddedMode )
, mCurrentTileset( 0 )
, mDefaultCRS( GEO_EPSG_CRS_AUTHID )
{
setupUi( this );

Expand Down Expand Up @@ -117,7 +118,7 @@ QgsWMSSourceSelect::QgsWMSSourceSelect( QWidget * parent, Qt::WFlags fl, bool ma
QgsCoordinateReferenceSystem currentRefSys( currentCRS, QgsCoordinateReferenceSystem::InternalCrsId );
if ( currentRefSys.isValid() )
{
mCRS = currentRefSys.authid();
mDefaultCRS = mCRS = currentRefSys.authid();
}
}

Expand Down Expand Up @@ -409,6 +410,8 @@ bool QgsWMSSourceSelect::populateLayerList( QgsWmsProvider *wmsProvider )
lstLayers->expandItem( lstLayers->topLevelItem( 0 ) );
}

on_lstLayers_itemSelectionChanged();

return true;
}

Expand Down Expand Up @@ -741,7 +744,6 @@ void QgsWMSSourceSelect::on_lstLayers_itemSelectionChanged()
mCurrentSelection = lstLayers->selectedItems();
lstLayers->blockSignals( false );


// selected layers with styles
QStringList layers;
QStringList styles;
Expand Down Expand Up @@ -801,7 +803,7 @@ void QgsWMSSourceSelect::on_lstLayers_itemSelectionChanged()
defaultCRS = *it;

// prefer value of DEFAULT_GEO_EPSG_CRS_ID if available
if ( *it == GEO_EPSG_CRS_AUTHID )
if ( *it == mDefaultCRS )
defaultCRS = *it;
}

Expand All @@ -813,7 +815,7 @@ void QgsWMSSourceSelect::on_lstLayers_itemSelectionChanged()
}

}
else if ( mCRSs.isEmpty() )
else if ( layers.isEmpty() || mCRSs.isEmpty() )
{
mCRS = "";
labelCoordRefSys->setText( "" );
Expand Down
3 changes: 3 additions & 0 deletions src/providers/wms/qgswmssourceselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ class QgsWMSSourceSelect : public QDialog, private Ui::QgsWMSSourceSelectBase
//! Selected CRS
QString mCRS;

//! Default CRS
QString mDefaultCRS;

//! Common CRSs for selected layers
QSet<QString> mCRSs;

Expand Down
4 changes: 3 additions & 1 deletion tests/src/core/testqgsrastersublayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,16 @@ void TestQgsRasterSubLayer::subLayersList()
//QVERIFY( mpRasterLayer->isValid() );
QStringList expected;
// Sublayer format: NETCDF:"/path/to/landsat2.nc":Band1
// NETCDF:"c:/path/to/landsat2.nc":Band1
// File path is delicate on Windows -> compare only sublayers
expected << "Band1";
expected << "Band2";

QStringList sublayers;
foreach ( QString s, mpRasterLayer->subLayers() )
{
sublayers << s.split( ':' ).value( 2 );
qDebug() << "sublayer: " << s;
sublayers << s.split( ':' ).last();
}
qDebug() << "sublayers: " << sublayers.join( "," );
mReport += QString( "sublayers:<br>%1<br>\n" ).arg( sublayers.join( "<br>" ) );
Expand Down
17 changes: 13 additions & 4 deletions tests/src/providers/testqgswcsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,22 @@ void TestQgsWcsProvider::read( )
identifiers << "band3_float32_noct_epsg4326";

// How to reasonably log multiple fails within this loop?
QTemporaryFile* tmpFile = new QTemporaryFile( "qgis-wcs-test-XXXXXX.tif" );
tmpFile->open();
QString tmpFilePath = tmpFile->fileName();
delete tmpFile; // removes the file
foreach ( QString version, versions )
{
foreach ( QString identifier, identifiers )
{
foreach ( QString ext, QStringList() << ".tif" << ".tif.aux.xml" )
// copy to temporary to avoid creation/changes/use of GDAL .aux.xml files
QString testFilePath = mTestDataDir + "/" + identifier + ".tif";
qDebug() << "copy " << testFilePath << " to " << tmpFilePath;
if ( !QFile::copy( testFilePath, tmpFilePath ) )
{
QFile::remove( QDir::tempPath() + "/" + identifier + ext );
QVERIFY( QFile::copy( mTestDataDir + "/" + identifier + ext, QDir::tempPath() + "/" + identifier + ext ) );
mReport += QString( "Cannot copy %1 to %2" ).arg( testFilePath ).arg( tmpFilePath );
ok = false;
continue;
}

QgsDataSourceURI uri;
Expand All @@ -126,10 +134,11 @@ void TestQgsWcsProvider::read( )
uri.setParam( "version", version );
uri.setParam( "cache", "AlwaysNetwork" );

if ( !read( identifier, uri.encodedUri(), QDir::tempPath() + "/" + identifier + ".tif", mReport ) )
if ( !read( identifier, uri.encodedUri(), tmpFilePath, mReport ) )
{
ok = false;
}
QFile::remove( tmpFilePath );
}
}
QVERIFY2( ok, "Reading data failed. See report for details." );
Expand Down