331 changes: 173 additions & 158 deletions i18n/qgis_pt_PT.ts

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion python/console/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ def openHelp(self):
self.helpDlg.activateWindow()

def openSettings(self):
#options = optionsDialog()
self.options.exec_()

def prefChanged(self):
Expand Down
15 changes: 5 additions & 10 deletions python/console/console_sci.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ def __init__(self, parent=None):
self.setCaretWidth(2)

# Set Python lexer
# Set style for Python comments (style number 1) to a fixed-width
# courier.
self.setLexers()

# Indentation
Expand Down Expand Up @@ -130,19 +128,16 @@ def commandConsole(self, command):
self.setSelection(line, 4, line, selCmdLenght)
self.removeSelectedText()
if command == "iface":
"""Import QgisInterface class"""
# import QgisInterface class
self.append('from qgis.utils import iface')
elif command == "sextante":
"""Import Sextante class"""
self.append('from sextante.core.Sextante import Sextante')
elif command == "cLayer":
"""Retrieve current Layer from map camvas"""
self.append('cLayer = iface.mapCanvas().currentLayer()')
# import Sextante class
self.append('import sextante')
elif command == "qtCore":
"""Import QtCore class"""
# import QtCore class
self.append('from PyQt4.QtCore import *')
elif command == "qtGui":
"""Import QtGui class"""
# import QtGui class
self.append('from PyQt4.QtGui import *')
self.entered()
self.move_cursor_to_end()
Expand Down
2 changes: 2 additions & 0 deletions python/core/qgspallabeling.sip
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class QgsPalLayerSettings
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
double maxCurvedCharAngleOut; // maximum angle between outside curved label characters (defaults to -20.0, range -20.0 to -95.0)
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
int fontMinPixelSize; // minimum pixel size for showing rendered map unit labels (1 - 1000)
Expand Down
15 changes: 8 additions & 7 deletions python/core/qgsvectorfilewriter.sip
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ class QgsVectorFileWriter
const QString& driverName = "ESRI Shapefile",
bool onlySelected = false,
QString *errorMessage = 0,
const QStringList &datasourceOptions = QStringList(),
const QStringList &layerOptions = QStringList(),
bool skipAttributeCreation = false, // added in 1.7
QString *newFilename = 0
const QStringList &datasourceOptions = QStringList(), // added in 1.6
const QStringList &layerOptions = QStringList(), // added in 1.6
bool skipAttributeCreation = false, // added in 1.6
QString *newFilename = 0 // added in 1.9
);

/** create shapefile and initialize it */
Expand All @@ -61,9 +61,10 @@ class QgsVectorFileWriter
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* srs,
const QString& driverName = "ESRI Shapefile",
const QStringList &datasourceOptions = QStringList(),
const QStringList &layerOptions = QStringList(),
QString *newFilename = 0 );
const QStringList &datasourceOptions = QStringList(), // added in 1.6
const QStringList &layerOptions = QStringList(), // added in 1.6
QString *newFilename = 0 // added in 1.9
);

/**Returns map with format filter string as key and OGR format key as value*/
static QMap< QString, QString> supportedFiltersAndFormats();
Expand Down
5 changes: 3 additions & 2 deletions python/core/symbology-ng/qgssvgcache.sip
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class QgsSvgCacheEntry
/**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files
according to the svg params specification (http://www.w3.org/TR/2009/WD-SVGParamPrimer-20090616/). Supported are
the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g. <circle fill="param(fill-color red)" stroke="param(pen-color black)" stroke-width="param(outline-width 1)"*/
class QgsSvgCache
class QgsSvgCache : QObject
{
%TypeHeaderCode
#include <qgssvgcache.h>
Expand All @@ -56,7 +56,8 @@ class QgsSvgCache
double& defaultOutlineWidth ) const;

protected:
QgsSvgCache();
//! 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,
Expand Down
6 changes: 5 additions & 1 deletion python/gui/qgisinterface.sip
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,16 @@ class QgisInterface : QObject
virtual QAction *actionAddPgLayer() = 0;
virtual QAction *actionAddWmsLayer() = 0;
virtual QAction *actionLayerSeparator1() = 0 /Deprecated/;
/** @note added in 1.9 */
virtual QAction *actionCopyLayerStyle() = 0;
/** @note added in 1.9 */
virtual QAction *actionPasteLayerStyle() = 0;
virtual QAction *actionOpenTable() = 0;
virtual QAction *actionToggleEditing() = 0;
virtual QAction *actionLayerSaveAs() = 0;
virtual QAction *actionLayerSelectionSaveAs() = 0;
virtual QAction *actionRemoveLayer() = 0;
/** @note added in 2.0 */
/** @note added in 1.9 */
virtual QAction *actionDuplicateLayer() = 0;
virtual QAction *actionLayerProperties() = 0;
virtual QAction *actionLayerSeparator2() = 0 /Deprecated/;
Expand Down
7 changes: 6 additions & 1 deletion python/gui/qgslegendinterface.sip
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ class QgsLegendInterface : QObject
//! Return the relationship between groups and layers in the legend
virtual QList< QPair< QString, QList<QString> > > groupLayerRelationship();

//! Return all layers in the project in legend order
//! Returns the currently selected layers of QgsLegendLayers.
//! @param inDrawOrder return layers in drawing order (added in 1.9)
//! @returns list of layers, else an empty list
virtual QList<QgsMapLayer *> selectedLayers( bool inDrawOrder = false ) const = 0;

//! Return all layers in the project in drawing order
//! @note added in 1.5
virtual QList< QgsMapLayer * > layers() const = 0;

Expand Down
16 changes: 0 additions & 16 deletions python/plugins/db_manager/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

from .db_tree import DBTree

from .db_plugins import getDbPluginErrors
from .db_plugins.plugin import BaseError
from .dlg_db_error import DlgDbError

Expand All @@ -53,21 +52,6 @@ def __init__(self, iface, parent=None):
self.connect(self.tree, SIGNAL("selectedItemChanged"), self.itemChanged)
self.itemChanged(None)

self.displayDbPluginErrors()

def displayDbPluginErrors(self):
if len(getDbPluginErrors()) <= 0:
return

if not hasattr(self, '_dbPluginErrorIndex') or self._dbPluginErrorIndex >= len(getDbPluginErrors()):
self._dbPluginErrorIndex = 0

msg = getDbPluginErrors()[self._dbPluginErrorIndex]
self._dbPluginErrorIndex += 1

self.statusBar.showMessage( msg, 5000 )
QTimer.singleShot( 6000, self.displayDbPluginErrors)


def closeEvent(self, e):
self.unregisterAllActions()
Expand Down
13 changes: 2 additions & 11 deletions python/plugins/db_manager/db_plugins/info_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,14 @@ def spatialInfo(self):

tbl = [
("Library:", info[0]),
("Scripts:", info[1]),
("GEOS:", info[3]),
("Proj:", info[4]),
("Use stats:", info[5])
("GEOS:", info[1]),
("Proj:", info[2])
]
ret.append( HtmlTable( tbl ) )

if info[1] != None and info[1] != info[2]:
ret.append( HtmlParagraph( u"<warning> Version of installed scripts doesn't match version of released scripts!\n" \
"This is probably a result of incorrect PostGIS upgrade." ) )

if not self.db.connector.has_geometry_columns:
ret.append( HtmlParagraph( u"<warning> geometry_columns table doesn't exist!\n" \
"This table is essential for many GIS applications for enumeration of tables." ) )
elif not self.db.connector.has_geometry_columns_access:
ret.append( HtmlParagraph( u"<warning> This user doesn't have privileges to read contents of geometry_columns table!\n" \
"This table is essential for many GIS applications for enumeration of tables." ) )

return ret

Expand Down
9 changes: 4 additions & 5 deletions python/plugins/db_manager/db_plugins/postgis/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,17 @@ def getInfo(self):
def getSpatialInfo(self):
""" returns tuple about postgis support:
- lib version
- installed scripts version
- released scripts version
- geos version
- proj version
- whether uses stats
- installed scripts version
- released scripts version
"""
if not self.has_spatial:
return

c = self._get_cursor()
try:
self._execute(c, u"SELECT postgis_lib_version(), postgis_scripts_installed(), postgis_scripts_released(), postgis_geos_version(), postgis_proj_version(), postgis_uses_stats()")
self._execute(c, u"SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()")
except DbError:
return

Expand All @@ -151,7 +150,7 @@ def fieldTypes(self):
"integer", "bigint", "smallint", # integers
"serial", "bigserial", # auto-incrementing ints
"real", "double precision", "numeric", # floats
"varchar", "varchar(n)", "char(n)", "text", # strings
"varchar", "varchar(255)", "char(20)", "text", # strings
"date", "time", "timestamp" # date/time
]

Expand Down
28 changes: 28 additions & 0 deletions python/plugins/db_manager/db_plugins/postgis/info_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,34 @@ def generalInfo(self):

return ret

def getSpatialInfo(self):
ret = []

info = self.db.connector.getSpatialInfo()
if info == None:
return

tbl = [
("Library:", info[0]),
("Scripts:", info[3]),
("GEOS:", info[1]),
("Proj:", info[2])
]
ret.append( HtmlTable( tbl ) )

if info[1] != None and info[1] != info[2]:
ret.append( HtmlParagraph( u"<warning> Version of installed scripts doesn't match version of released scripts!\n" \
"This is probably a result of incorrect PostGIS upgrade." ) )

if not self.db.connector.has_geometry_columns:
ret.append( HtmlParagraph( u"<warning> geometry_columns table doesn't exist!\n" \
"This table is essential for many GIS applications for enumeration of tables." ) )
elif not self.db.connector.has_geometry_columns_access:
ret.append( HtmlParagraph( u"<warning> This user doesn't have privileges to read contents of geometry_columns table!\n" \
"This table is essential for many GIS applications for enumeration of tables." ) )

return ret


def fieldsDetails(self):
tbl = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def fieldTypes(self):
return [
"integer", "bigint", "smallint", # integers
"real", "double", "float", "numeric", # floats
"varchar(n)", "character(n)", "text", # strings
"varchar", "varchar(255)", "character(20)", "text", # strings
"date", "datetime" # date/time
]

Expand Down
20 changes: 0 additions & 20 deletions python/plugins/db_manager/db_plugins/spatialite/info_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,6 @@ def connectionDetails(self):
]
return HtmlTable( tbl )

def spatialInfo(self):
ret = []

info = self.db.connector.getSpatialInfo()
if info == None:
return

tbl = [
("Library:", info[0]),
("GEOS:", info[1]),
("Proj:", info[2])
]
ret.append( HtmlTable( tbl ) )

if not self.db.connector.has_geometry_columns:
ret.append( HtmlParagraph( u"<warning> geometry_columns table doesn't exist!\n" \
"This table is essential for many GIS applications for enumeration of tables." ) )

return ret

def generalInfo(self):
info = self.db.connector.getInfo()
tbl = [
Expand Down
14 changes: 8 additions & 6 deletions python/plugins/db_manager/dlg_import_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, inLayer, outDb, outUri, parent=None):

self.default_pk = "id"
self.default_geom = "geom"

# updates of UI
for widget in [self.radCreate, self.chkDropTable, self.radAppend,
self.chkPrimaryKey, self.chkGeomColumn, self.chkSpatialIndex,
Expand All @@ -58,11 +58,14 @@ def __init__(self, inLayer, outDb, outUri, parent=None):
self.populateEncodings()
self.updateUi()

# set default values
self.cboTable.setEditText(self.outUri.table())

pk = self.outUri.keyColumn()
self.editPrimaryKey.setText(pk if pk != "" else self.default_pk)
geom = self.outUri.geometryColumn()
self.editGeomColumn.setText(geom if geom != "" else self.default_geom)

inCrs = self.inLayer.crs()
srid = inCrs.postgisSrid() if inCrs.isValid() else 4236
self.editSourceSrid.setText( "%s" % srid )
Expand All @@ -73,7 +76,7 @@ def __init__(self, inLayer, outDb, outUri, parent=None):

def checkSupports(self):
allowSpatial = self.db.connector.hasSpatialSupport()
self.chkGeomColumn.setEnabled(allowSpatial)
self.chkGeomColumn.setEnabled(allowSpatial and self.inLayer.hasGeometryType())
self.chkSourceSrid.setEnabled(allowSpatial)
self.chkTargetSrid.setEnabled(allowSpatial)
self.chkSpatialIndex.setEnabled(allowSpatial)
Expand Down Expand Up @@ -168,12 +171,11 @@ def importLayer(self):
schema = self.outUri.schema() if not self.cboSchema.isEnabled() else self.cboSchema.currentText()
table = self.cboTable.currentText()

# get pk and geom field names from the source layer or use the
# ones defined by the user
pk = self.outUri.keyColumn() if not self.chkPrimaryKey.isChecked() else self.editPrimaryKey.text()
pk = pk if pk != "" else self.default_pk

geom = self.outUri.geometryColumn() if not self.chkGeomColumn.isChecked() else self.editGeomColumn.text()
if self.inLayer.hasGeometryType():
geom = geom if geom != "" else self.default_geom
geom = geom if geom != "" else self.default_geom

self.outUri.setDataSource( schema, table, geom, QString(), pk )
uri = self.outUri.uri()
Expand Down
12 changes: 11 additions & 1 deletion python/plugins/db_manager/info_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def __init__(self, parent=None):
self.dirty = False

self._clear()
self._showPluginInfo()

self.connect(self, SIGNAL("anchorClicked(const QUrl&)"), self._linkClicked)

def _linkClicked(self, url):
Expand Down Expand Up @@ -89,6 +91,15 @@ def _clear(self):
self.item = None
self.setHtml("")


def _showPluginInfo(self):
from .db_plugins import getDbPluginErrors
html = u'<div style="background-color:#ffffcc;"><h1>&nbsp;DB Manager</h1></div>'
html += '<div style="margin-left:8px;">'
for msg in getDbPluginErrors():
html += u"<p>%s" % msg
self.setHtml(html)

def _showDatabaseInfo(self, connection):
html = u'<div style="background-color:#ccffcc;"><h1>&nbsp;%s</h1></div>' % connection.connectionName()
html += '<div style="margin-left:8px;">'
Expand Down Expand Up @@ -126,7 +137,6 @@ def _showTableInfo(self, table):
return True



def setHtml(self, html):
# convert special tags :)
html = unicode(html).replace( '<warning>', '<img src=":/db_manager/warning">&nbsp;&nbsp; ' )
Expand Down
154 changes: 115 additions & 39 deletions python/plugins/fTools/tools/doValidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def setGeom(self, p):

def reset(self):
if not self.__marker is None:
self.__canvas.scene().removeItem(self.__marker)
self.__canvas.scene().removeItem(self.__marker)
del self.__marker
self.__marker = None

Expand All @@ -83,9 +83,10 @@ def __init__(self, iface):
self.tblUnique.setSelectionBehavior(QAbstractItemView.SelectRows)
# populate list of available layers
myList = ftools_utils.getLayerNames( [ QGis.Point, QGis.Line, QGis.Polygon ] )
self.connect(self.tblUnique, SIGNAL("currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)" ),
self.connect(self.tblUnique, SIGNAL("currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)" ),
self.zoomToError)
self.inShape.addItems( myList )
self.buttonBox_2.setOrientation(Qt.Horizontal)
self.cancel_close = self.buttonBox_2.button(QDialogButtonBox.Close)
self.buttonOk = self.buttonBox_2.button(QDialogButtonBox.Ok)
self.progressBar.setValue(0)
Expand All @@ -96,12 +97,16 @@ def __init__(self, iface):
settings = QSettings()
self.restoreGeometry( settings.value("/fTools/ValidateDialog/geometry").toByteArray() )

QObject.connect( self.browseShpError, SIGNAL( "clicked()" ), self.outFile )
QObject.connect( self.ckBoxShpError, SIGNAL( "stateChanged( int )" ), self.updateGui )
self.updateGui()

def closeEvent(self, e):
settings = QSettings()
settings.setValue( "/fTools/ValidateDialog/geometry", QVariant(self.saveGeometry()) )
QDialog.closeEvent(self, e)
del self.marker

def keyPressEvent( self, e ):
if ( e.modifiers() == Qt.ControlModifier or \
e.modifiers() == Qt.MetaModifier ) and \
Expand All @@ -122,10 +127,37 @@ def accept( self ):
QMessageBox.information( self, self.tr("Error!"), self.tr( "Please specify input vector layer" ) )
elif self.cmbField.isVisible() and self.cmbField.currentText() == "":
QMessageBox.information( self, self.tr("Error!"), self.tr( "Please specify input field" ) )
elif self.ckBoxShpError.isChecked() and self.lineEditShpError.text() == "":
QMessageBox.information( self, self.tr( "Error!" ), self.tr( "Please specify output shapefile" ) )
else:
self.vlayer = ftools_utils.getVectorLayerByName( self.inShape.currentText() )
self.validate( self.useSelected.checkState() )


def updateGui( self ):
if self.ckBoxShpError.isChecked():
self.lineEditShpError.setEnabled( True )
self.browseShpError.setEnabled( True )
self.tblUnique.setEnabled( False )
self.lstCount.setEnabled( False )
self.label_2.setEnabled( False )
self.label_4.setEnabled( False )
self.label_5.setEnabled( False )
else:
self.lineEditShpError.setEnabled( False )
self.browseShpError.setEnabled( False )
self.tblUnique.setEnabled( True )
self.lstCount.setEnabled( True )
self.label_2.setEnabled( True )
self.label_4.setEnabled( True )
self.label_5.setEnabled( True )

def outFile( self ):
self.lineEditShpError.clear()
(self.shapefileName, self.encoding) = ftools_utils.saveDialog( self )
if self.shapefileName is None or self.encoding is None:
return
self.lineEditShpError.setText( QString( self.shapefileName ) )

def zoomToError(self, curr, prev):
if curr is None:
return
Expand Down Expand Up @@ -162,11 +194,16 @@ def zoomToError(self, curr, prev):
mc.refresh()

def validate( self, mySelection ):
self.tblUnique.clearContents()
self.tblUnique.setRowCount( 0 )
self.lstCount.clear()
if not self.ckBoxShpError.isChecked():
self.tblUnique.clearContents()
self.tblUnique.setRowCount( 0 )
self.lstCount.clear()
self.shapefileName = None
self.encoding = None

self.buttonOk.setEnabled( False )
self.testThread = validateThread( self.iface.mainWindow(), self, self.vlayer, mySelection )

self.testThread = validateThread( self.iface.mainWindow(), self, self.vlayer, mySelection, self.shapefileName, self.encoding, self.ckBoxShpError.isChecked() )
QObject.connect( self.testThread, SIGNAL( "runFinished(PyQt_PyObject)" ), self.runFinishedFromThread )
QObject.connect( self.testThread, SIGNAL( "runStatus(PyQt_PyObject)" ), self.runStatusFromThread )
QObject.connect( self.testThread, SIGNAL( "runRange(PyQt_PyObject)" ), self.runRangeFromThread )
Expand All @@ -180,60 +217,73 @@ def reject(self):
# Remove Marker
self.marker.reset()
QDialog.reject(self)

def cancelThread( self ):
self.testThread.stop()
QApplication.restoreOverrideCursor()
self.buttonOk.setEnabled( True )
def runFinishedFromThread( self, output ):

def runFinishedFromThread( self, success ):
self.testThread.stop()
QApplication.restoreOverrideCursor()
self.buttonOk.setEnabled( True )
self.tblUnique.setColumnCount( 2 )
count = 0
for rec in output:
if len(rec[1]) < 1:
continue
where = None
for err in rec[1]: # for each error we find
self.tblUnique.insertRow(count)
fidItem = QTableWidgetItem( str(rec[0]) )
self.tblUnique.setItem( count, 0, fidItem )
message = err.what()
errItem = QTableWidgetItem( message )
if err.hasWhere(): # if there is a location associated with the error
errItem.setData(Qt.UserRole, QVariant(err.where()))
self.tblUnique.setItem( count, 1, errItem )
count += 1
self.tblUnique.setHorizontalHeaderLabels( [ self.tr("Feature"), self.tr("Error(s)") ] )
self.tblUnique.horizontalHeader().setResizeMode( 0, QHeaderView.ResizeToContents )
self.tblUnique.horizontalHeader().show()
self.tblUnique.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch )
self.tblUnique.resizeRowsToContents()
self.lstCount.insert(str(count))
if success == "writeShape":
extra = ""
addToTOC = QMessageBox.question( self, self.tr("Geometry"),
self.tr( "Created output shapefile:\n%1\n%2\n\nWould you like to add the new layer to the TOC?" ).arg( unicode( self.shapefileName ) ).arg( extra ),
QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton )
if addToTOC == QMessageBox.Yes:
if not ftools_utils.addShapeToCanvas( unicode( self.shapefileName ) ):
QMessageBox.warning( self, self.tr( "Geometry"),
self.tr( "Error loading output shapefile:\n%1" ).arg( unicode( self.shapefileName ) ) )
else:
self.tblUnique.setColumnCount( 2 )
count = 0
for rec in success:
if len(rec[1]) < 1:
continue
where = None
for err in rec[1]: # for each error we find
self.tblUnique.insertRow(count)
fidItem = QTableWidgetItem( str(rec[0]) )
self.tblUnique.setItem( count, 0, fidItem )
message = err.what()
errItem = QTableWidgetItem( message )
if err.hasWhere(): # if there is a location associated with the error
errItem.setData(Qt.UserRole, QVariant(err.where()))
self.tblUnique.setItem( count, 1, errItem )
count += 1
self.tblUnique.setHorizontalHeaderLabels( [ self.tr("Feature"), self.tr("Error(s)") ] )
self.tblUnique.horizontalHeader().setResizeMode( 0, QHeaderView.ResizeToContents )
self.tblUnique.horizontalHeader().show()
self.tblUnique.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch )
self.tblUnique.resizeRowsToContents()
self.lstCount.insert(str(count))
self.cancel_close.setText( "Close" )
QObject.disconnect( self.cancel_close, SIGNAL( "clicked()" ), self.cancelThread )
return True

def runStatusFromThread( self, status ):
self.progressBar.setValue( status )

def runRangeFromThread( self, range_vals ):
self.progressBar.setRange( range_vals[ 0 ], range_vals[ 1 ] )

class validateThread( QThread ):
def __init__( self, parentThread, parentObject, vlayer, mySelection ):
def __init__( self, parentThread, parentObject, vlayer, mySelection, myName, myEncoding, myNewShape ):
QThread.__init__( self, parentThread )
self.parent = parentObject
self.running = False
self.vlayer = vlayer
self.mySelection = mySelection
self.myName = myName
self.myEncoding = myEncoding
self.writeShape = myNewShape

def run( self ):
self.running = True
output = self.check_geometry( self.vlayer )
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), output )
success = self.check_geometry( self.vlayer )
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), success )

def stop(self):
self.running = False
Expand Down Expand Up @@ -265,4 +315,30 @@ def check_geometry( self, vlayer ):
if not geom.isGeosEmpty():
lstErrors.append((feat.id(), list(geom.validateGeometry())))
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nFeat )
return lstErrors

if self.writeShape:
fields = { 0 : QgsField( "FEAT_ID", QVariant.Int ),
1 : QgsField( "ERROR", QVariant.String ) }
writer = QgsVectorFileWriter( self.myName, self.myEncoding, fields,
QGis.WKBPoint, vlayer.crs() )
for rec in lstErrors:
if len(rec[1]) < 1:
continue
for err in rec[1]:
fidItem = str(rec[0])
message = err.what()
if err.hasWhere():
locErr = err.where()
xP = locErr.x()
yP = locErr.y()
myPoint = QgsPoint( xP, yP )
geometry = QgsGeometry().fromPoint( myPoint )
ft = QgsFeature()
ft.setGeometry( geometry )
ft.setAttributeMap( { 0 : QVariant( fidItem ),
1 : QVariant( message ) } )
writer.addFeature( ft )
del writer
return "writeShape"
else:
return lstErrors
13 changes: 11 additions & 2 deletions python/plugins/fTools/tools/doVisual.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ def __init__( self, iface, function ):
self.iface = iface
self.setupUi( self )
self.myFunction = function

## Set object visibility to False if tool is not Check geometry
self.ckBoxShpError.hide()
self.browseShpError.hide()
self.lineEditShpError.hide()
self.label_6.hide()
self.line.hide()
self.buttonBox_2.setOrientation(Qt.Horizontal)

if self.myFunction == 2 or self.myFunction == 3:
QObject.connect( self.inShape, SIGNAL( "currentIndexChanged(QString)" ), self.update )
self.manageGui()
Expand Down Expand Up @@ -289,7 +298,7 @@ def basic_statistics( self, vlayer, myField ):
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
else: # there is no selection, process the whole layer
nFeat = vprovider.featureCount()
if nFeat > 0:
if nFeat > 0:
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
vprovider.select( allAttrs )
Expand Down Expand Up @@ -355,7 +364,7 @@ def basic_statistics( self, vlayer, myField ):
else: # there is no selection, process the whole layer
nFeat = vprovider.featureCount()
uniqueVal = ftools_utils.getUniqueValuesCount( vlayer, index, False )
if nFeat > 0:
if nFeat > 0:
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
vprovider.select( allAttrs )
Expand Down
123 changes: 85 additions & 38 deletions python/plugins/fTools/tools/frmVisual.ui
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>404</width>
<height>481</height>
<width>370</width>
<height>484</height>
</rect>
</property>
<property name="windowTitle">
Expand All @@ -20,7 +20,7 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<item row="0" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label_3">
Expand All @@ -34,18 +34,7 @@
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="useSelected">
<property name="text">
<string>Use only selected features</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<item row="2" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label">
Expand All @@ -59,7 +48,7 @@
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<item row="3" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label_2">
Expand Down Expand Up @@ -107,7 +96,7 @@
</item>
</layout>
</item>
<item row="6" column="0" colspan="2">
<item row="4" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label_4">
Expand All @@ -125,37 +114,95 @@
</item>
</layout>
</item>
<item row="9" column="0">
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<item row="7" column="0">
<widget class="QCheckBox" name="ckBoxShpError">
<property name="text">
<string>Save errors location</string>
</property>
</widget>
</item>
<item row="8" column="1" rowspan="2">
<widget class="QDialogButtonBox" name="buttonBox_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Press Ctrl+C to copy results to the clipboard</string>
</property>
</widget>
</item>
<item row="9" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineEditShpError">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="browseShpError">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="8" column="0">
<widget class="QProgressBar" name="partProgressBar">
<property name="value">
<number>24</number>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Output point shapefile</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Press Ctrl+C to copy results to the clipboard</string>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="useSelected">
<property name="text">
<string>Use only selected features</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="10" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QProgressBar" name="partProgressBar">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
Expand Down
46 changes: 44 additions & 2 deletions src/app/composer/qgscomposerlegendwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ QgsComposerLegendWidget::QgsComposerLegendWidget( QgsComposerLegend* legend ): m
mWrapCharLineEdit->setText( legend->wrapChar() );

setGuiElements();
connect( mItemTreeView, SIGNAL( itemChanged() ), this, SLOT( setGuiElements() ) );

connect( mItemTreeView->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ),
this, SLOT( selectedChanged( const QModelIndex &, const QModelIndex & ) ) );
Expand All @@ -88,13 +87,16 @@ void QgsComposerLegendWidget::setGuiElements()
blockAllSignals( true );
mTitleLineEdit->setText( mLegend->title() );
mColumnCountSpinBox->setValue( mLegend->columnCount() );
mSplitLayerCheckBox->setChecked( mLegend->splitLayer() );
mEqualColumnWidthCheckBox->setChecked( mLegend->equalColumnWidth() );
mSymbolWidthSpinBox->setValue( mLegend->symbolWidth() );
mSymbolHeightSpinBox->setValue( mLegend->symbolHeight() );
mGroupSpaceSpinBox->setValue( mLegend->groupSpace() );
mLayerSpaceSpinBox->setValue( mLegend->layerSpace() );
mSymbolSpaceSpinBox->setValue( mLegend->symbolSpace() );
mIconLabelSpaceSpinBox->setValue( mLegend->iconLabelSpace() );
mBoxSpaceSpinBox->setValue( mLegend->boxSpace() );
mColumnSpaceSpinBox->setValue( mLegend->columnSpace() );
if ( mLegend->model() )
{
mCheckBoxAutoUpdate->setChecked( mLegend->model()->autoUpdate() );
Expand Down Expand Up @@ -147,6 +149,32 @@ void QgsComposerLegendWidget::on_mColumnCountSpinBox_valueChanged( int c )
mLegend->update();
mLegend->endCommand();
}
mSplitLayerCheckBox->setEnabled( c > 1 );
mEqualColumnWidthCheckBox->setEnabled( c > 1 );
}

void QgsComposerLegendWidget::on_mSplitLayerCheckBox_toggled( bool checked )
{
if ( mLegend )
{
mLegend->beginCommand( tr( "Legend split layers" ), QgsComposerMergeCommand::LegendSplitLayer );
mLegend->setSplitLayer( checked );
mLegend->adjustBoxSize();
mLegend->update();
mLegend->endCommand();
}
}

void QgsComposerLegendWidget::on_mEqualColumnWidthCheckBox_toggled( bool checked )
{
if ( mLegend )
{
mLegend->beginCommand( tr( "Legend equal column width" ), QgsComposerMergeCommand::LegendEqualColumnWidth );
mLegend->setEqualColumnWidth( checked );
mLegend->adjustBoxSize();
mLegend->update();
mLegend->endCommand();
}
}

void QgsComposerLegendWidget::on_mSymbolWidthSpinBox_valueChanged( double d )
Expand Down Expand Up @@ -309,7 +337,6 @@ void QgsComposerLegendWidget::on_mItemFontButton_clicked()
}
}


void QgsComposerLegendWidget::on_mBoxSpaceSpinBox_valueChanged( double d )
{
if ( mLegend )
Expand All @@ -322,6 +349,18 @@ void QgsComposerLegendWidget::on_mBoxSpaceSpinBox_valueChanged( double d )
}
}

void QgsComposerLegendWidget::on_mColumnSpaceSpinBox_valueChanged( double d )
{
if ( mLegend )
{
mLegend->beginCommand( tr( "Legend box space" ), QgsComposerMergeCommand::LegendColumnSpace );
mLegend->setColumnSpace( d );
mLegend->adjustBoxSize();
mLegend->update();
mLegend->endCommand();
}
}

void QgsComposerLegendWidget::on_mMoveDownToolButton_clicked()
{
if ( !mLegend )
Expand Down Expand Up @@ -731,13 +770,16 @@ void QgsComposerLegendWidget::blockAllSignals( bool b )
mCheckBoxAutoUpdate->blockSignals( b );
mMapComboBox->blockSignals( b );
mColumnCountSpinBox->blockSignals( b );
mSplitLayerCheckBox->blockSignals( b );
mEqualColumnWidthCheckBox->blockSignals( b );
mSymbolWidthSpinBox->blockSignals( b );
mSymbolHeightSpinBox->blockSignals( b );
mGroupSpaceSpinBox->blockSignals( b );
mLayerSpaceSpinBox->blockSignals( b );
mSymbolSpaceSpinBox->blockSignals( b );
mIconLabelSpaceSpinBox->blockSignals( b );
mBoxSpaceSpinBox->blockSignals( b );
mColumnSpaceSpinBox->blockSignals( b );
}

void QgsComposerLegendWidget::refreshMapComboBox()
Expand Down
3 changes: 3 additions & 0 deletions src/app/composer/qgscomposerlegendwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class QgsComposerLegendWidget: public QWidget, private Ui::QgsComposerLegendWidg
void on_mWrapCharLineEdit_textChanged( const QString& text );
void on_mTitleLineEdit_textChanged( const QString& text );
void on_mColumnCountSpinBox_valueChanged( int c );
void on_mSplitLayerCheckBox_toggled( bool checked );
void on_mEqualColumnWidthCheckBox_toggled( bool checked );
void on_mSymbolWidthSpinBox_valueChanged( double d );
void on_mSymbolHeightSpinBox_valueChanged( double d );
void on_mGroupSpaceSpinBox_valueChanged( double d );
Expand All @@ -53,6 +55,7 @@ class QgsComposerLegendWidget: public QWidget, private Ui::QgsComposerLegendWidg
void on_mLayerFontButton_clicked();
void on_mItemFontButton_clicked();
void on_mBoxSpaceSpinBox_valueChanged( double d );
void on_mColumnSpaceSpinBox_valueChanged( double d );
void on_mCheckBoxAutoUpdate_stateChanged( int state );
void on_mMapComboBox_currentIndexChanged( int index );

Expand Down
5 changes: 5 additions & 0 deletions src/app/legend/qgsapplegendinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ bool QgsAppLegendInterface::isLayerVisible( QgsMapLayer * ml )
return ( Qt::Checked == mLegend->layerCheckState( ml ) );
}

QList<QgsMapLayer *> QgsAppLegendInterface::selectedLayers( bool inDrawOrder ) const
{
return mLegend->selectedLayers( inDrawOrder );
}

QList< QgsMapLayer * > QgsAppLegendInterface::layers() const
{
return mLegend->layers();
Expand Down
5 changes: 4 additions & 1 deletion src/app/legend/qgsapplegendinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ class QgsAppLegendInterface : public QgsLegendInterface
//! Return the relationship between groups and layers in the legend
QList< GroupLayerInfo > groupLayerRelationship();

//! Return all layers in the project in legend order
//! Returns the currently selected layers of QgsLegendLayers.
QList<QgsMapLayer *> selectedLayers( bool inDrawOrder = false ) const;

//! Return all layers in the project in drawing order
QList< QgsMapLayer * > layers() const;

//! Check if a group exists
Expand Down
80 changes: 41 additions & 39 deletions src/app/legend/qgslayerorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "qgsmaplayer.h"
#include "qgslogger.h"
#include "qgslegend.h"
#include "qgslegendgroup.h"
#include "qgslegendlayer.h"
#include "qgslegendlayer.h"
#include "qgsproject.h"

Expand All @@ -33,10 +35,6 @@ QgsLayerOrder::QgsLayerOrder( QgsLegend *legend, QWidget * parent, const char *n
{
setObjectName( name );

// track visibility changed in legend
connect( mLegend, SIGNAL( itemChanged( QTreeWidgetItem *, int ) ),
this, SLOT( legendItemChanged( QTreeWidgetItem *, int ) ) );

// track if legend mode changes
connect( mLegend, SIGNAL( updateDrawingOrderChecked( bool ) ),
this, SLOT( updateDrawingOrderChecked( bool ) ) );
Expand Down Expand Up @@ -85,13 +83,14 @@ void QgsLayerOrder::refreshLayerList()
{
clear();

foreach ( QgsLegendLayer *layer, mLegend->legendLayers() )
QList<DrawingOrderInfo> drawingOrderList = mLegend->drawingOrder();
QList<DrawingOrderInfo>::const_iterator it = drawingOrderList.constBegin();
for ( ; it != drawingOrderList.constEnd(); ++it )
{
QListWidgetItem *item = new QListWidgetItem( layer->layer()->name() );
item->setData( 1, QString::number( layer->drawingOrder() ) );
item->setData( Qt::UserRole, qVariantFromValue( qobject_cast<QObject*>( layer->layer() ) ) );
item->setCheckState( layer->isVisible() ? Qt::Checked : Qt::Unchecked );
QgsDebugMsg( QString( "add item=%1 at %2" ).arg( item ? item->text() : "(null item)" ).arg( count() ) );
QListWidgetItem *item = new QListWidgetItem( it->name );
item->setCheckState( it->checked ? Qt::Checked : Qt::Unchecked );
item->setData( Qt::UserRole, it->id );
item->setData( Qt::UserRole + 1, it->embeddedGroup );
addItem( item );
}
}
Expand All @@ -113,35 +112,28 @@ QListWidgetItem *QgsLayerOrder::layerItem( QgsMapLayer *layer ) const

void QgsLayerOrder::itemChanged( QListWidgetItem *item )
{
QgsDebugMsg( "Entering." );
QgsDebugMsg( QString( "item=%1" ).arg( item ? item->text() : "(null item)" ) );

QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( item->data( Qt::UserRole ).value<QObject*>() );
mLegend->setLayerVisible( layer, item->checkState() == Qt::Checked );

QString name = item->text();
QString id = item->data( Qt::UserRole ).toString();
bool embeddedGroup = item->data( Qt::UserRole + 1 ).toBool();
if ( embeddedGroup )
{
QgsLegendGroup* grp = mLegend->findLegendGroup( name, id );
if ( grp )
{
grp->setCheckState( 0, item->checkState() );
}
}
else
{
QgsLegendLayer* ll = mLegend->findLegendLayer( id );
if ( ll )
{
ll->setCheckState( 0, item->checkState() );
}
}
updateLayerOrder();
}

void QgsLayerOrder::legendItemChanged( QTreeWidgetItem *item, int col )
{
QgsDebugMsg( "Entering." );

if ( col != 0 )
return;

QgsDebugMsg( QString( "legendItem changed=%1" ).arg( item ? item->text( 0 ) : "(null item)" ) );

QgsLegendLayer *ll = dynamic_cast< QgsLegendLayer * >( item );
if ( !ll )
return;

QListWidgetItem *lwi = layerItem( ll->layer() );
if ( !lwi )
return;

lwi->setCheckState( item->checkState( col ) );
}

void QgsLayerOrder::mousePressEvent( QMouseEvent * e )
{
QgsDebugMsg( "Entering." );
Expand Down Expand Up @@ -261,14 +253,24 @@ void QgsLayerOrder::updateLayerOrder()
if ( !isEnabled() )
return;

QList<QgsMapLayer *> layers;
QList<DrawingOrderInfo> drawingOrder;

for ( int i = 0; i < count(); i++ )
{
layers << qobject_cast<QgsMapLayer *>( item( i )->data( Qt::UserRole ).value<QObject*>() );
QListWidgetItem* listItem = item( i );
if ( !listItem )
{
continue;
}
DrawingOrderInfo info;
info.name = listItem->text();
info.id = listItem->data( Qt::UserRole ).toString();
info.checked = listItem->checkState() == Qt::Checked;
info.embeddedGroup = listItem->data( Qt::UserRole + 1 ).toBool();
drawingOrder.push_back( info );
}

mLegend->setDrawingOrder( layers );
mLegend->setDrawingOrder( drawingOrder );
}

void QgsLayerOrder::hideLine()
Expand Down
1 change: 0 additions & 1 deletion src/app/legend/qgslayerorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class QgsLayerOrder : public QListWidget
private slots:
void updateDrawingOrderChecked( bool );
void itemChanged( QListWidgetItem * );
void legendItemChanged( QTreeWidgetItem *, int );
void refreshLayerList();

private:
Expand Down
214 changes: 204 additions & 10 deletions src/app/legend/qgslegend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ QgsLegend::QgsLegend( QgsMapCanvas *canvas, QWidget * parent, const char *name )
, mMapCanvas( canvas )
, mMinimumIconSize( 20, 20 )
, mChanging( false )
, mUpdateDrawingOrder( false )
, mUpdateDrawingOrder( true )
{
setObjectName( name );

Expand Down Expand Up @@ -679,7 +679,17 @@ void QgsLegend::mouseReleaseEvent( QMouseEvent * e )

void QgsLegend::mouseDoubleClickEvent( QMouseEvent *e )
{
#ifdef Q_WS_MAC
// fix for when quick left-then-right clicks (when legend is out of focus)
// register as left double click: show contextual menu as user intended
if ( e->button() == Qt::RightButton )
{
mousePressEvent( e );
return;
}
#else
Q_UNUSED( e );
#endif

QSettings settings;
switch ( settings.value( "/qgis/legendDoubleClickAction", 0 ).toInt() )
Expand Down Expand Up @@ -841,6 +851,9 @@ QgsLegendGroup* QgsLegend::addEmbeddedGroup( const QString& groupName, const QSt
group = new QgsLegendGroup( this, groupName );
}

group->setEmbedded( true );
group->setProjectPath( projectFilePath );

QFont groupFont;
groupFont.setItalic( true );
group->setFont( 0, groupFont );
Expand Down Expand Up @@ -1080,15 +1093,26 @@ QgsMapLayer* QgsLegend::currentLayer()
}
}

QList<QgsMapLayer *> QgsLegend::selectedLayers()
QList<QgsMapLayer *> QgsLegend::selectedLayers( bool inDrawOrder )
{
QList<QgsMapLayer *> layers;

foreach ( QTreeWidgetItem * item, selectedItems() )
if ( inDrawOrder )
{
QgsLegendLayer *ll = dynamic_cast<QgsLegendLayer *>( item );
if ( ll )
layers << ll->layer();
foreach ( QgsLegendLayer *ll, legendLayers() )
{
if ( ll->isSelected() )
layers << ll->layer();
}
}
else
{
foreach ( QTreeWidgetItem * item, selectedItems() )
{
QgsLegendLayer *ll = dynamic_cast<QgsLegendLayer *>( item );
if ( ll )
layers << ll->layer();
}
}

return layers;
Expand Down Expand Up @@ -1146,6 +1170,68 @@ QList<QgsLegendLayer *> QgsLegend::legendLayers()
}
}

QList<DrawingOrderInfo> QgsLegend::drawingOrder()
{
QMap<int, DrawingOrderInfo> drawingOrder;
QSet<QgsLegendLayer*> embeddedGroupChildren;
int nEntries = 0;

QTreeWidgetItemIterator it( this );
while ( *it )
{
QgsLegendLayer* llayer = dynamic_cast<QgsLegendLayer *>( *it );
QgsLegendGroup* lgroup = dynamic_cast<QgsLegendGroup *>( *it );
if ( llayer )
{
if ( !embeddedGroupChildren.contains( llayer ) )
{
DrawingOrderInfo dInfo;
dInfo.name = llayer->layerName();
dInfo.id = llayer->layer()->id();
dInfo.checked = ( llayer->checkState( 0 ) == Qt::Checked );
dInfo.embeddedGroup = false;
if ( mUpdateDrawingOrder )
{
drawingOrder.insertMulti( nEntries, dInfo );
}
else
{
drawingOrder.insertMulti( llayer->drawingOrder(), dInfo );
}
++nEntries;
}
}
else if ( lgroup )
{
if ( lgroup->isEmbedded() && !( lgroup->parent() ) )
{
QList<QgsLegendLayer*> groupLayers = lgroup->legendLayers();
QList<QgsLegendLayer*>::const_iterator groupLayerIt = groupLayers.constBegin();
for ( ; groupLayerIt != groupLayers.constEnd(); ++groupLayerIt )
{
embeddedGroupChildren.insert( *groupLayerIt );
}
DrawingOrderInfo dInfo;
dInfo.name = lgroup->text( 0 );
dInfo.id = lgroup->projectPath();
dInfo.checked = ( lgroup->checkState( 0 ) != Qt::Unchecked );
dInfo.embeddedGroup = true;
if ( mUpdateDrawingOrder )
{
drawingOrder.insertMulti( nEntries, dInfo );
}
else
{
drawingOrder.insertMulti( lgroup->drawingOrder(), dInfo );
}
++nEntries;
}
}
++it;
}
return drawingOrder.values();
}

QList<QgsMapLayer *> QgsLegend::layers()
{
QList<QgsMapLayer *> ls;
Expand All @@ -1160,14 +1246,58 @@ QList<QgsMapLayer *> QgsLegend::layers()

QList<QgsMapCanvasLayer> QgsLegend::canvasLayers()
{
QList<QgsMapCanvasLayer> ls;
QMap<int, QgsMapCanvasLayer> layers;
QSet<QgsLegendLayer*> embeddedGroupChildren;
int nEntries = 0;

foreach ( QgsLegendLayer *l, legendLayers() )
QTreeWidgetItemIterator it( this );
while ( *it )
{
ls << l->canvasLayer();
QgsLegendLayer* llayer = dynamic_cast<QgsLegendLayer *>( *it );
QgsLegendGroup* lgroup = dynamic_cast<QgsLegendGroup *>( *it );
if ( llayer && !embeddedGroupChildren.contains( llayer ) )
{
QgsMapCanvasLayer canvasLayer = llayer->canvasLayer();
if ( mUpdateDrawingOrder )
{
layers.insertMulti( nEntries + embeddedGroupChildren.size(), canvasLayer );
}
else
{
layers.insertMulti( llayer->drawingOrder(), canvasLayer );
}
}
else if ( lgroup )
{
if ( lgroup->isEmbedded() )
{
int groupDrawingOrder = lgroup->drawingOrder();
QList<QgsLegendLayer*> groupLayers = lgroup->legendLayers();
for ( int i = groupLayers.size() - 1; i >= 0; --i )
{
QgsLegendLayer* ll = groupLayers.at( i );
if ( !ll || embeddedGroupChildren.contains( ll ) )
{
continue;
}

if ( mUpdateDrawingOrder )
{
layers.insertMulti( nEntries, ll->canvasLayer() );
}
else
{
layers.insertMulti( groupDrawingOrder, ll->canvasLayer() );
}
embeddedGroupChildren.insert( ll );
}
}
}
++it;
++nEntries;
}

return ls;
return layers.values();
}

void QgsLegend::setDrawingOrder( QList<QgsMapLayer *> layers )
Expand All @@ -1186,6 +1316,44 @@ void QgsLegend::setDrawingOrder( QList<QgsMapLayer *> layers )
updateMapCanvasLayerSet();
}

void QgsLegend::setDrawingOrder( const QList<DrawingOrderInfo>& order )
{
QList<QgsMapCanvasLayer> layers;

QList<DrawingOrderInfo>::const_iterator orderIt = order.constBegin();
int i = 0;
for ( ; orderIt != order.constEnd(); ++orderIt )
{
if ( orderIt->embeddedGroup )
{
//find group
QgsLegendGroup* group = findLegendGroup( orderIt->name, orderIt->id );
if ( group )
{
group->setDrawingOrder( i );
QList<QgsLegendLayer*> groupLayers = group->legendLayers();
QList<QgsLegendLayer*>::iterator groupIt = groupLayers.begin();
for ( ; groupIt != groupLayers.end(); ++groupIt )
{
layers.push_back(( *groupIt )->canvasLayer() );
}
++i;
}
}
else
{
QgsLegendLayer *ll = findLegendLayer( orderIt->id );
if ( ll )
{
ll->setDrawingOrder( i );
layers.push_back( ll->canvasLayer() );
++i;
}
}
}
mMapCanvas->setLayerSet( layers );
}

bool QgsLegend::setCurrentLayer( QgsMapLayer *layer )
{
QgsLegendLayer *ll = findLegendLayer( layer );
Expand Down Expand Up @@ -1405,6 +1573,11 @@ bool QgsLegend::writeXML( QList<QTreeWidgetItem *> items, QDomNode &node, QDomDo
{
legendgroupnode.setAttribute( "embedded", 1 );
legendgroupnode.setAttribute( "project", QgsProject::instance()->writePath( embedIt.value() ) );
QgsLegendGroup* group = dynamic_cast<QgsLegendGroup*>( item );
if ( group )
{
legendgroupnode.setAttribute( "drawingOrder", group->drawingOrder() );
}
}
else
{
Expand Down Expand Up @@ -1531,6 +1704,10 @@ bool QgsLegend::readXML( QgsLegendGroup *parent, const QDomNode &node )
if ( childelem.attribute( "embedded" ) == "1" )
{
theGroup = addEmbeddedGroup( name, QgsProject::instance()->readPath( childelem.attribute( "project" ) ) );
if ( childelem.hasAttribute( "drawingOrder" ) )
{
theGroup->setDrawingOrder( childelem.attribute( "drawingOrder" ).toInt() );
}
updateGroupCheckStates( theGroup );
}
else
Expand Down Expand Up @@ -1742,6 +1919,23 @@ QgsLegendLayer* QgsLegend::findLegendLayer( const QgsMapLayer *layer )
return 0;
}

QgsLegendGroup* QgsLegend::findLegendGroup( const QString& name, const QString& projectPath )
{
QgsLegendGroup* group = 0;
for ( QTreeWidgetItem* theItem = firstItem(); theItem; theItem = nextItem( theItem ) )
{
group = dynamic_cast<QgsLegendGroup*>( theItem );
if ( group )
{
if ( group->text( 0 ) == name && group->projectPath() == projectPath )
{
return group;
}
}
}
return 0;
}


void QgsLegend::adjustIconSize()
{
Expand Down
25 changes: 22 additions & 3 deletions src/app/legend/qgslegend.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ class QgsMapCanvasLayer;
//value: containter with layer ids contained in the group
typedef QPair< QString, QList<QString> > GroupLayerInfo;

struct DrawingOrderInfo
{
QString name;
QString id;
bool checked;
bool embeddedGroup;
};

/**
\class QgsLegend
\brief A Legend treeview for QGIS
Expand Down Expand Up @@ -109,9 +117,10 @@ class QgsLegend : public QTreeWidget
Else, 0 is returned.*/
QgsMapLayer* currentLayer();

/*!Returns the currently selected layer QgsLegendLayers.
Else, an empty list is returned.*/
QList<QgsMapLayer *> selectedLayers();
/** Returns the currently selected layers of QgsLegendLayers.
* @param inDrawOrder return layers in drawing order (added in 1.9)
* @returns list of layers, else an empty list */
QList<QgsMapLayer *> selectedLayers( bool inDrawOrder = false );

/*!Returns all layers loaded in QgsMapCanvas in drawing order
Else, an empty list is returned.*/
Expand All @@ -120,8 +129,15 @@ class QgsLegend : public QTreeWidget
//!Return all layers in drawing order
QList<QgsLegendLayer *> legendLayers();

//!Return info about layers and embedded groups in drawing order
QList<DrawingOrderInfo> drawingOrder();

QStringList drawingOrderLayers();

void setDrawingOrder( QList<QgsMapLayer *> );

void setDrawingOrder( const QList<DrawingOrderInfo>& order );

/*!set the current layer
returns true if the layer exists, false otherwise*/
bool setCurrentLayer( QgsMapLayer *layer );
Expand Down Expand Up @@ -212,6 +228,9 @@ class QgsLegend : public QTreeWidget
/**Returns the legend layer to which a map layer belongs to*/
QgsLegendLayer* findLegendLayer( const QgsMapLayer *layer );

/**Returns legend group by group name and project path (empty for not-embedded groups)*/
QgsLegendGroup* findLegendGroup( const QString& name, const QString& projectPath = QString() );

public slots:

/*!Adds a new layer group with the maplayers to the canvas*/
Expand Down
6 changes: 6 additions & 0 deletions src/app/legend/qgslegendgroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ QgsLegendGroup::QgsLegendGroup( QTreeWidgetItem * theItem, QString theName )
setCheckState( 0, Qt::Checked );
QIcon myIcon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
setIcon( 0, myIcon );
mEmbedded = false;
mDrawingOrder = -1;
}
QgsLegendGroup::QgsLegendGroup( QTreeWidget* theListView, QString theString )
: QgsLegendItem( theListView, theString )
Expand All @@ -36,6 +38,8 @@ QgsLegendGroup::QgsLegendGroup( QTreeWidget* theListView, QString theString )
setCheckState( 0, Qt::Checked );
QIcon myIcon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
setIcon( 0, myIcon );
mEmbedded = false;
mDrawingOrder = -1;
}

QgsLegendGroup::QgsLegendGroup( QString name ): QgsLegendItem()
Expand All @@ -46,6 +50,8 @@ QgsLegendGroup::QgsLegendGroup( QString name ): QgsLegendItem()
QIcon myIcon = QgsApplication::getThemeIcon( + "/mActionFolder.png" );
setText( 0, name );
setIcon( 0, myIcon );
mEmbedded = false;
mDrawingOrder = -1;
}

QgsLegendGroup::~QgsLegendGroup()
Expand Down
16 changes: 16 additions & 0 deletions src/app/legend/qgslegendgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ class QgsLegendGroup : public QgsLegendItem
QList<QgsLegendLayer*> legendLayers( bool recurse = true );

Qt::CheckState pendingCheckState();

bool isEmbedded() const { return mEmbedded; }
void setEmbedded( bool b ) { mEmbedded = b; }

QString projectPath() const { return mProjectPath; }
void setProjectPath( const QString& path ) { mProjectPath = path; }

int drawingOrder() const { return mDrawingOrder; }
void setDrawingOrder( int i ) { mDrawingOrder = i; }

private:
bool mEmbedded;
/**Path to project from which the group is embedded. Empty for not-embedded groups*/
QString mProjectPath;
int mDrawingOrder;

};

#endif
24 changes: 23 additions & 1 deletion src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ void usage( std::string const & appName )
<< "\t[--nologo]\thide splash screen\n"
<< "\t[--noplugins]\tdon't restore plugins on startup\n"
<< "\t[--nocustomization]\tdon't apply GUI customization\n"
<< "\t[--customizationfile]\tuse the given ini file as GUI customization\n"
<< "\t[--optionspath path]\tuse the given QSettings path\n"
<< "\t[--configpath path]\tuse the given path for all user configuration\n"
<< "\t[--code path]\tRun the given python file on load. \n"
Expand Down Expand Up @@ -270,6 +271,8 @@ int main( int argc, char *argv[] )

QString pythonfile;

QString customizationfile;

#if defined(ANDROID)
QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
//put all QGIS settings in the same place
Expand Down Expand Up @@ -333,6 +336,10 @@ int main( int argc, char *argv[] )
{
pythonfile = argv[++i];
}
else if ( i + 1 < argc && ( arg == "--customizationfile" || arg == "-z" ) )
{
customizationfile = argv[++i];
}
else
{
myFileList.append( QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[i] ) ).absoluteFilePath() ) );
Expand Down Expand Up @@ -366,6 +373,7 @@ int main( int argc, char *argv[] )
{"extent", required_argument, 0, 'e'},
{"optionspath", required_argument, 0, 'o'},
{"configpath", required_argument, 0, 'c'},
{"customizationfile", required_argument, 0, 'z'},
{"code", required_argument, 0, 'f'},
{"android", required_argument, 0, 'a'},
{0, 0, 0, 0}
Expand Down Expand Up @@ -441,6 +449,10 @@ int main( int argc, char *argv[] )
pythonfile = optarg;
break;

case 'z':
customizationfile = optarg;
break;

case '?':
usage( argv[0] );
return 2; // XXX need standard exit codes
Expand Down Expand Up @@ -531,6 +543,12 @@ int main( int argc, char *argv[] )
customizationsettings = new QSettings( "QuantumGIS", "QGISCUSTOMIZATION" );
}

// Using the customizationfile option always overrides the option and config path options.
if ( !customizationfile.isEmpty() )
{
customizationsettings = new QSettings( customizationfile, QSettings::IniFormat);
}

// Load and set possible default customization, must be done afterQgsApplication init and QSettings ( QCoreApplication ) init
QgsCustomization::instance()->setSettings( customizationsettings );
QgsCustomization::instance()->loadDefault();
Expand Down Expand Up @@ -662,8 +680,12 @@ int main( int argc, char *argv[] )
QStringList myPathList;
QCoreApplication::setLibraryPaths( myPathList );
// Now set the paths inside the bundle
myPath += "/Contents/plugins";
myPath += "/Contents/Plugins";
QCoreApplication::addLibraryPath( myPath );
if ( QgsApplication::isRunningFromBuildDir() )
{
QCoreApplication::addLibraryPath( QTPLUGINSDIR );
}
//next two lines should not be needed, testing only
//QCoreApplication::addLibraryPath( myPath + "/imageformats" );
//QCoreApplication::addLibraryPath( myPath + "/sqldrivers" );
Expand Down
39 changes: 36 additions & 3 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6076,6 +6076,37 @@ void QgisApp::setExtent( QgsRectangle theRect )
*/
bool QgisApp::saveDirty()
{
QString whyDirty = "";
bool hasUnsavedEdits = false;
// extra check to see if there are any vector layers with unsaved provider edits
// to ensure user has opportunity to save any editing
if ( QgsMapLayerRegistry::instance()->count() > 0 )
{
QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers();
for ( QMap<QString, QgsMapLayer*>::iterator it = layers.begin(); it != layers.end(); it++ )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
if ( !vl )
{
continue;
}

hasUnsavedEdits = ( vl->isEditable() && vl->isModified() );
if ( hasUnsavedEdits )
{
break;
}
}

if ( hasUnsavedEdits )
{
markDirty();
whyDirty = "<p style='color:darkred;'>";
whyDirty += tr( "Project has layer(s) in edit mode with unsaved edits, which will NOT be saved!" );
whyDirty += "</p>";
}
}

QMessageBox::StandardButton answer( QMessageBox::Discard );
mMapCanvas->freeze( true );

Expand All @@ -6096,8 +6127,10 @@ bool QgisApp::saveDirty()

// prompt user to save
answer = QMessageBox::information( this, tr( "Save?" ),
tr( "Do you want to save the current project?" ),
QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard );
tr( "Do you want to save the current project?%1" )
.arg( whyDirty ),
QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard,
hasUnsavedEdits ? QMessageBox::Cancel : QMessageBox::Save );
if ( QMessageBox::Save == answer )
{
if ( !fileSave() )
Expand Down Expand Up @@ -7935,7 +7968,7 @@ void QgisApp::showLayerProperties( QgsMapLayer *ml )
else
{
rlp = new QgsRasterLayerProperties( ml, mMapCanvas, this );
connect( rlp, SIGNAL( refreshLegend( QString, QgsLegendItem::Expansion ) ), mMapLegend, SLOT( refreshLayerSymbology( QString, QgsLegendItem::Expansion ) ) );
connect( rlp, SIGNAL( refreshLegend( QString, bool ) ), mMapLegend, SLOT( refreshLayerSymbology( QString, bool ) ) );
}

rlp->exec();
Expand Down
12 changes: 8 additions & 4 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,17 +280,21 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionAddOgrLayer() { return mActionAddOgrLayer; }
QAction *actionAddRasterLayer() { return mActionAddRasterLayer; }
QAction *actionAddPgLayer() { return mActionAddPgLayer; }
QAction *actionAddSpatiaLiteLayer() { return mActionAddSpatiaLiteLayer; };
QAction *actionAddSpatiaLiteLayer() { return mActionAddSpatiaLiteLayer; }
QAction *actionAddWmsLayer() { return mActionAddWmsLayer; }
QAction *actionAddWcsLayer() { return mActionAddWcsLayer; }
QAction *actionAddWfsLayer() { return mActionAddWfsLayer; }
/** @note added in 1.9 */
QAction *actionCopyLayerStyle() { return mActionCopyStyle; }
/** @note added in 1.9 */
QAction *actionPasteLayerStyle() { return mActionPasteStyle; }
QAction *actionOpenTable() { return mActionOpenTable; }
QAction *actionToggleEditing() { return mActionToggleEditing; }
QAction *actionSaveEdits() { return mActionSaveEdits; }
QAction *actionLayerSaveAs() { return mActionLayerSaveAs; }
QAction *actionLayerSelectionSaveAs() { return mActionLayerSelectionSaveAs; }
QAction *actionRemoveLayer() { return mActionRemoveLayer; }
/** @note added in 2.0 */
/** @note added in 1.9 */
QAction *actionDuplicateLayer() { return mActionDuplicateLayer; }
QAction *actionSetLayerCRS() { return mActionSetLayerCRS; }
QAction *actionSetProjectCRSFromLayer() { return mActionSetProjectCRSFromLayer; }
Expand Down Expand Up @@ -437,13 +441,13 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
(defaults to the active layer on the legend)
*/
void editPaste( QgsMapLayer * destinationLayer = 0 );

//! copies style of the active layer to the clipboard
/**
\param sourceLayer The layer where the style will be taken from
(defaults to the active layer on the legend)
*/
void copyStyle( QgsMapLayer * sourceLayer = 0 );
//! copies style on the clipboard to the active layer
//! pastes style on the clipboard to the active layer
/**
\param destinatioLayer The layer that the clipboard will be pasted to
(defaults to the active layer on the legend)
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgisappinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ QAction *QgisAppInterface::actionAddRasterLayer() { return qgis->actionAddRaster
QAction *QgisAppInterface::actionAddPgLayer() { return qgis->actionAddPgLayer(); }
QAction *QgisAppInterface::actionAddWmsLayer() { return qgis->actionAddWmsLayer(); }
QAction *QgisAppInterface::actionLayerSeparator1() { return 0; }
QAction *QgisAppInterface::actionCopyLayerStyle() { return qgis->actionCopyLayerStyle(); }
QAction *QgisAppInterface::actionPasteLayerStyle() { return qgis->actionPasteLayerStyle(); }
QAction *QgisAppInterface::actionOpenTable() { return qgis->actionOpenTable(); }
QAction *QgisAppInterface::actionToggleEditing() { return qgis->actionToggleEditing(); }
QAction *QgisAppInterface::actionLayerSaveAs() { return qgis->actionLayerSaveAs(); }
Expand Down
6 changes: 5 additions & 1 deletion src/app/qgisappinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,16 @@ class QgisAppInterface : public QgisInterface
virtual QAction *actionAddPgLayer();
virtual QAction *actionAddWmsLayer();
virtual QAction *actionLayerSeparator1();
/** @note added in 1.9 */
virtual QAction *actionCopyLayerStyle();
/** @note added in 1.9 */
virtual QAction *actionPasteLayerStyle();
virtual QAction *actionOpenTable();
virtual QAction *actionToggleEditing();
virtual QAction *actionLayerSaveAs();
virtual QAction *actionLayerSelectionSaveAs();
virtual QAction *actionRemoveLayer();
/** @note added in 2.0 */
/** @note added in 1.9 */
virtual QAction *actionDuplicateLayer();
virtual QAction *actionLayerProperties();
virtual QAction *actionLayerSeparator2();
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsattributeactiondialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ void QgsAttributeActionDialog::addDefaultActions()
insertRow( pos++, QgsAction::GenericPython, tr( "Selected field's value (Identify features tool)" ), "QtGui.QMessageBox.information(None, \"Current field's value\", \"[% $currentfield %]\")", false );
insertRow( pos++, QgsAction::GenericPython, tr( "Clicked coordinates (Run feature actions tool)" ), "QtGui.QMessageBox.information(None, \"Clicked coords\", \"layer: [% $layerid %]\\ncoords: ([% $clickx %],[% $clickx %])\")", false );
insertRow( pos++, QgsAction::OpenUrl, tr( "Open file" ), "[% \"PATH\" %]", false );
insertRow( pos++, QgsAction::OpenUrl, tr( "Search on web based on attribute's value" ), "http://www.google.it/?q=[% \"ATTRIBUTE\" %]", false );
insertRow( pos++, QgsAction::OpenUrl, tr( "Search on web based on attribute's value" ), "http://www.google.com/search?q=[% \"ATTRIBUTE\" %]", false );
}

void QgsAttributeActionDialog::itemSelectionChanged()
Expand Down
80 changes: 47 additions & 33 deletions src/app/qgsbrowserdockwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,18 +269,9 @@ void QgsBrowserDockWidget::showEvent( QShowEvent * e )
{
mModel = new QgsBrowserModel( mBrowserView );

bool useFilter = true;
if ( useFilter ) // enable proxy model
{
// mBrowserView->setModel( mModel );
mProxyModel = new QgsBrowserTreeFilterProxyModel( this );
mProxyModel->setBrowserModel( mModel );
mBrowserView->setModel( mProxyModel );
}
else
{
mBrowserView->setModel( mModel );
}
mProxyModel = new QgsBrowserTreeFilterProxyModel( this );
mProxyModel->setBrowserModel( mModel );
mBrowserView->setModel( mProxyModel );
// provide a horizontal scroll bar instead of using ellipse (...) for longer items
mBrowserView->setTextElideMode( Qt::ElideNone );
mBrowserView->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
Expand All @@ -301,8 +292,8 @@ void QgsBrowserDockWidget::showEvent( QShowEvent * e )

void QgsBrowserDockWidget::showContextMenu( const QPoint & pt )
{
QModelIndex idx = mBrowserView->indexAt( pt );
QgsDataItem* item = dataItem( idx );
QModelIndex index = mProxyModel->mapToSource( mBrowserView->indexAt( pt ) );
QgsDataItem* item = mModel->dataItem( index );
if ( !item )
return;

Expand All @@ -325,6 +316,10 @@ void QgsBrowserDockWidget::showContextMenu( const QPoint & pt )
menu->addAction( tr( "Remove favourite" ), this, SLOT( removeFavourite() ) );
}
menu->addAction( tr( "Properties" ), this, SLOT( showProperties( ) ) );
QAction *action = menu->addAction( tr( "Fast scan this dir." ), this, SLOT( toggleFastScan( ) ) );
action->setCheckable( true );
action->setChecked( settings.value( "/qgis/scanItemsFastScanUris",
QStringList() ).toStringList().contains( item->path() ) );
}
else if ( item->type() == QgsDataItem::Layer )
{
Expand Down Expand Up @@ -358,7 +353,8 @@ void QgsBrowserDockWidget::showContextMenu( const QPoint & pt )

void QgsBrowserDockWidget::addFavourite()
{
QgsDataItem* item = dataItem( mBrowserView->currentIndex() );
QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
QgsDataItem* item = mModel->dataItem( index );
if ( !item )
return;

Expand Down Expand Up @@ -390,7 +386,8 @@ void QgsBrowserDockWidget::addFavouriteDirectory( QString favDir )

void QgsBrowserDockWidget::removeFavourite()
{
QgsDataItem* item = dataItem( mBrowserView->currentIndex() );
QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
QgsDataItem* item = mModel->dataItem( index );

if ( !item )
return;
Expand Down Expand Up @@ -420,7 +417,7 @@ void QgsBrowserDockWidget::refreshModel( const QModelIndex& index )
QgsDebugMsg( "Entered" );
if ( index.isValid() )
{
QgsDataItem *item = dataItem( index );
QgsDataItem *item = mModel->dataItem( index );
if ( item )
{
QgsDebugMsg( "path = " + item->path() );
Expand All @@ -436,7 +433,8 @@ void QgsBrowserDockWidget::refreshModel( const QModelIndex& index )
for ( int i = 0 ; i < mModel->rowCount( index ); i++ )
{
QModelIndex idx = mModel->index( i, 0, index );
if ( mBrowserView->isExpanded( idx ) || !mModel->hasChildren( idx ) )
QModelIndex proxyIdx = mProxyModel->mapFromSource( idx );
if ( mBrowserView->isExpanded( proxyIdx ) || !mModel->hasChildren( proxyIdx ) )
{
refreshModel( idx );
}
Expand Down Expand Up @@ -468,7 +466,7 @@ void QgsBrowserDockWidget::addLayer( QgsLayerItem *layerItem )

void QgsBrowserDockWidget::addLayerAtIndex( const QModelIndex& index )
{
QgsDataItem *item = dataItem( index );
QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );

if ( item != NULL && item->type() == QgsDataItem::Layer )
{
Expand Down Expand Up @@ -498,8 +496,7 @@ void QgsBrowserDockWidget::addSelectedLayers()
// add items in reverse order so they are in correct order in the layers dock
for ( int i = list.size() - 1; i >= 0; i-- )
{
QModelIndex index = list[i];
QgsDataItem *item = dataItem( index );
QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( list[i] ) );
if ( item && item->type() == QgsDataItem::Layer )
{
QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( item );
Expand All @@ -513,9 +510,8 @@ void QgsBrowserDockWidget::addSelectedLayers()

void QgsBrowserDockWidget::showProperties( )
{
QgsDebugMsg( "Entered" );
QModelIndex index = mBrowserView->currentIndex();
QgsDataItem* item = dataItem( index );
QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
QgsDataItem* item = mModel->dataItem( index );
if ( ! item )
return;

Expand Down Expand Up @@ -612,6 +608,33 @@ void QgsBrowserDockWidget::showProperties( )
}
}

void QgsBrowserDockWidget::toggleFastScan( )
{
QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
QgsDataItem* item = mModel->dataItem( index );
if ( ! item )
return;

if ( item->type() == QgsDataItem::Directory )
{
QSettings settings;
QStringList fastScanDirs = settings.value( "/qgis/scanItemsFastScanUris",
QStringList() ).toStringList();
int idx = fastScanDirs.indexOf( item->path() );
if ( idx != -1 )
{
fastScanDirs.removeAt( idx );
}
else
{
fastScanDirs << item->path();
}
settings.setValue( "/qgis/scanItemsFastScanUris", fastScanDirs );
}
}



void QgsBrowserDockWidget::showFilterWidget( bool visible )
{
mWidgetFilter->setVisible( visible );
Expand All @@ -635,12 +658,3 @@ void QgsBrowserDockWidget::setFilterSyntax( QAction * action )
return;
mProxyModel->setFilterSyntax(( QRegExp::PatternSyntax ) action->data().toInt() );
}

QgsDataItem* QgsBrowserDockWidget::dataItem( const QModelIndex& index )
{
if ( ! mProxyModel )
return mModel->dataItem( index );
else
return mModel->dataItem( mProxyModel->mapToSource( index ) );
}

4 changes: 3 additions & 1 deletion src/app/qgsbrowserdockwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class QgsBrowserDockWidget : public QDockWidget, private Ui::QgsBrowserDockWidge
void addCurrentLayer();
void addSelectedLayers();
void showProperties();
void toggleFastScan();

protected:
void addFavouriteDirectory( QString favDir );
Expand All @@ -61,7 +62,8 @@ class QgsBrowserDockWidget : public QDockWidget, private Ui::QgsBrowserDockWidge

void addLayer( QgsLayerItem *layerItem );

QgsDataItem* dataItem( const QModelIndex& index );
// removed dataItem(), call mModel->dataItem directly (to avoid passing index from the wrong model)

QgsBrowserTreeView* mBrowserView;
QgsBrowserModel* mModel;
QgsBrowserTreeFilterProxyModel* mProxyModel;
Expand Down
9 changes: 9 additions & 0 deletions src/app/qgslabelinggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
mUpsidedownRadioOff->setChecked( true );
break;
}
mMaxCharAngleInDSpinBox->setValue( lyr.maxCurvedCharAngleIn );
// lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
mMaxCharAngleOutDSpinBox->setValue( qAbs( lyr.maxCurvedCharAngleOut ) );

wrapCharacterEdit->setText( lyr.wrapChar );
mFontLineHeightSpinBox->setValue( lyr.multilineHeight );
Expand Down Expand Up @@ -501,6 +504,10 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
{
lyr.upsidedownLabels = QgsPalLayerSettings::ShowAll;
}
lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
// lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();

lyr.minFeatureSize = mMinSizeSpinBox->value();
lyr.limitNumLabels = mLimitLabelChkBox->isChecked();
lyr.maxNumLabels = mLimitLabelSpinBox->value();
Expand Down Expand Up @@ -958,6 +965,8 @@ void QgsLabelingGui::updateOptions()
|| ( stackedPlacement->currentWidget() == pageLine && radLineCurved->isChecked() ) )
{
stackedOptions->setCurrentWidget( pageOptionsLine );
mMaxCharAngleFrame->setVisible(( stackedPlacement->currentWidget() == pageLine
&& radLineCurved->isChecked() ) );
}
else
{
Expand Down
25 changes: 15 additions & 10 deletions src/app/qgsmaptoolidentify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int
return false;
}

QMap< QString, QString > attributes, derivedAttributes;
QMap< QString, QString > derivedAttributes;

QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );

Expand Down Expand Up @@ -259,6 +259,7 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int
calc.setEllipsoid( ellipsoid );
calc.setSourceCrs( layer->crs().srsid() );
}

QgsFeatureList::iterator f_it = featureList.begin();

bool filter = false;
Expand All @@ -280,8 +281,6 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int

featureCount++;

QMap<QString, QString> derivedAttributes;

// Calculate derived attributes and insert:
// measure distance or area depending on geometry type
if ( layer->geometryType() == QGis::Line )
Expand All @@ -295,33 +294,39 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int
f_it->geometry()->wkbType() == QGis::WKBLineString25D )
{
// Add the start and end points in as derived attributes
str = QLocale::system().toString( f_it->geometry()->asPolyline().first().x(), 'g', 10 );
QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, f_it->geometry()->asPolyline().first() );
str = QLocale::system().toString( pnt.x(), 'g', 10 );
derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().first().y(), 'g', 10 );
str = QLocale::system().toString( pnt.y(), 'g', 10 );
derivedAttributes.insert( tr( "firstY" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().last().x(), 'g', 10 );
pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, f_it->geometry()->asPolyline().last() );
str = QLocale::system().toString( pnt.x(), 'g', 10 );
derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().last().y(), 'g', 10 );
str = QLocale::system().toString( pnt.y(), 'g', 10 );
derivedAttributes.insert( tr( "lastY" ), str );
}
}
else if ( layer->geometryType() == QGis::Polygon )
{
double area = calc.measure( f_it->geometry() );
double perimeter = calc.measurePerimeter( f_it->geometry() );
QGis::UnitType myDisplayUnits;
convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
QString str = calc.textUnit( area, 3, myDisplayUnits, true );
derivedAttributes.insert( tr( "Area" ), str );
convertMeasurement( calc, perimeter, myDisplayUnits, false ); // area and myDisplayUnits are out params
str = calc.textUnit( perimeter, 3, myDisplayUnits, false );
derivedAttributes.insert( tr( "Perimeter" ), str );
}
else if ( layer->geometryType() == QGis::Point &&
( f_it->geometry()->wkbType() == QGis::WKBPoint ||
f_it->geometry()->wkbType() == QGis::WKBPoint25D ) )
{
// Include the x and y coordinates of the point as a derived attribute
QString str;
str = QLocale::system().toString( f_it->geometry()->asPoint().x(), 'g', 10 );
QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, f_it->geometry()->asPoint() );
QString str = QLocale::system().toString( pnt.x(), 'g', 10 );
derivedAttributes.insert( "X", str );
str = QLocale::system().toString( f_it->geometry()->asPoint().y(), 'g', 10 );
str = QLocale::system().toString( pnt.y(), 'g', 10 );
derivedAttributes.insert( "Y", str );
}

Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ SET(QGIS_CORE_MOC_HDRS
gps/qgsgpsdconnection.h

symbology-ng/qgscptcityarchive.h
symbology-ng/qgssvgcache.h
)

IF (WITH_INTERNAL_QEXTSERIALPORT)
Expand Down
3 changes: 3 additions & 0 deletions src/core/composer/qgscomposeritemcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,16 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
//composer legend
ComposerLegendText,
LegendColumnCount,
LegendSplitLayer,
LegendEqualColumnWidth,
LegendSymbolWidth,
LegendSymbolHeight,
LegendGroupSpace,
LegendLayerSpace,
LegendSymbolSpace,
LegendIconSymbolSpace,
LegendBoxSpace,
LegendColumnSpace,
//composer picture
ComposerPictureRotation,
// composer scalebar
Expand Down
908 changes: 507 additions & 401 deletions src/core/composer/qgscomposerlegend.cpp

Large diffs are not rendered by default.

121 changes: 70 additions & 51 deletions src/core/composer/qgscomposerlegend.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,40 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
void setItemFont( const QFont& f );

double boxSpace() const {return mBoxSpace;}
void setBoxSpace( double s ) {mBoxSpace = s; mColumns.clear();}
void setBoxSpace( double s ) {mBoxSpace = s;}

double columnSpace() const {return mColumnSpace;}
void setColumnSpace( double s ) { mColumnSpace = s;}

double groupSpace() const {return mGroupSpace;}
void setGroupSpace( double s ) {mGroupSpace = s;mColumns.clear();}
void setGroupSpace( double s ) {mGroupSpace = s;}

double layerSpace() const {return mLayerSpace;}
void setLayerSpace( double s ) {mLayerSpace = s;mColumns.clear();}
void setLayerSpace( double s ) {mLayerSpace = s;}

double symbolSpace() const {return mSymbolSpace;}
void setSymbolSpace( double s ) {mSymbolSpace = s;mColumns.clear();}
void setSymbolSpace( double s ) {mSymbolSpace = s;}

double iconLabelSpace() const {return mIconLabelSpace;}
void setIconLabelSpace( double s ) {mIconLabelSpace = s;mColumns.clear();}
void setIconLabelSpace( double s ) {mIconLabelSpace = s;}

double symbolWidth() const {return mSymbolWidth;}
void setSymbolWidth( double w ) {mSymbolWidth = w;mColumns.clear();}
void setSymbolWidth( double w ) {mSymbolWidth = w;}

double symbolHeight() const {return mSymbolHeight;}
void setSymbolHeight( double h ) {mSymbolHeight = h;mColumns.clear();}
void setSymbolHeight( double h ) {mSymbolHeight = h;}

void setWrapChar( const QString& t ) {mWrapChar = t;mColumns.clear();}
void setWrapChar( const QString& t ) {mWrapChar = t;}
QString wrapChar() const {return mWrapChar;}

int columnCount() const { return mColumnCount; }
void setColumnCount( int c ) { mColumnCount = c;mColumns.clear();}
void setColumnCount( int c ) { mColumnCount = c;}

int splitLayer() const { return mSplitLayer; }
void setSplitLayer( bool s ) { mSplitLayer = s;}

int equalColumnWidth() const { return mEqualColumnWidth; }
void setEqualColumnWidth( bool s ) { mEqualColumnWidth = s;}

void setComposerMap( const QgsComposerMap* map );
const QgsComposerMap* composerMap() const { return mComposerMap;}
Expand Down Expand Up @@ -135,6 +144,8 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem

/**Space between item box and contents*/
double mBoxSpace;
/**Space between columns*/
double mColumnSpace;
/**Vertical space between group entries*/
double mGroupSpace;
/**Vertical space between layer entries*/
Expand All @@ -153,68 +164,75 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem

/** Number of legend columns */
int mColumnCount;
/** Cached division of items to columns */
QMap<QStandardItem *, int> mColumns;

QgsLegendModel mLegendModel;

/**Reference to map (because symbols are sometimes in map units)*/
const QgsComposerMap* mComposerMap;

/** Allow splitting layers into multiple columns */
bool mSplitLayer;

/** Use the same width (maximum) for all columns */
bool mEqualColumnWidth;

private:
// Group or layer size
struct Size
{
QSizeF size;
//bool isLayer; // layer or group
QgsComposerLegendItem::ItemType type;
QStandardItem * item;
Size() {}
Size( QSizeF s, QgsComposerLegendItem::ItemType t, QStandardItem * i ): size( s ), type( t ), item( i ) {}
} ;
struct LegendSize
/** Nucleon is either group title, layer title or layer child item.
* Nucleon is similar to QgsComposerLegendItem but it does not have
* the same hierarchy. E.g. layer title nucleon is just title, it does not
* include all layer subitems, the same with groups.
*/
class Nucleon
{
QSizeF size; // legend size
QList<Size> sizes; // layer / group sizes
LegendSize() {}
LegendSize( QSizeF s, QList<Size>ls ): size( s ), sizes( ls ) {}
public:
QgsComposerLegendItem* item;
// Symbol size size without any space around for symbol item
QSizeF symbolSize;
// Label size without any space around for symbol item
QSizeF labelSize;
QSizeF size;
// Offset of symbol label, this offset is the same for all symbol labels
// of the same layer in the same column
double labelXOffset;
};
class Position

/** Atom is indivisible set (indivisible into more columns). It may consists
* of one or more Nucleon, depending on layer splitting mode:
* 1) no layer split: [group_title ...] layer_title layer_item [layer_item ...]
* 2) layer split: [group_title ...] layer_title layer_item
* or: layer_item
* It means that group titles must not be split from layer title and layer title
* must not be split from first item, because it would look bad and it would not
* be readable to leave group or layer title at the bottom of column.
*/
class Atom
{
public:
QSizeF titleSize; // without spaces around
QPointF point; // current position
double columnTop; // y coord where columns start (mBoxSpace + title height)
Atom(): size( QSizeF( 0, 0 ) ), column( 0 ) {}
QList<Nucleon> nucleons;
// Atom size including nucleons interspaces but without any space around atom.
QSizeF size;
int column;
QMap<QStandardItem *, int> columns;
// widths of columns, does not include spaces before/between/after columns
QVector<double> widths;
double maxColumnHeight;
// set max width for current column
void expandWidth( double w );
// set column and x position
void setColumn( QStandardItem *item );
double boxSpace;
double columnSpace; // space between columns
};

/** Create list of atoms according to current layer splitting mode */
QList<Atom> createAtomList( QStandardItem* rootItem, bool splitLayer );

/** Divide atoms to columns and set columns on atoms */
void setColumns( QList<Atom>& atomList );

QgsComposerLegend(); //forbidden

QSizeF drawTitle( QPainter* painter = 0, QPointF point = QPointF(), Qt::AlignmentFlag halignement = Qt::AlignLeft );

/**Draws a group item and all subitems
* Returns list of sizes of layers and groups including this group.
*/
QList<Size> drawGroupItem( QPainter* p, QgsComposerGroupItem* groupItem, Position& currentPosition );
QSizeF drawGroupItemTitle( QgsComposerGroupItem* groupItem, QPainter* painter = 0, QPointF point = QPointF() );
/**Draws a layer item and all subitems*/
Size drawLayerItem( QPainter* p, QgsComposerLayerItem* layerItem, Position& currentPosition );
QSizeF drawLayerItemTitle( QgsComposerLayerItem* layerItem, QPainter* painter = 0, QPointF point = QPointF() );

/**Draws child items of a layer item
@param p painter
@param layerItem parent model item (layer)
@param currentPosition in/out: current y position of legend item
@param layerOpacity opacity of the corresponding map layer
*/
QSizeF drawLayerChildItems( QPainter* p, QStandardItem* layerItem, Position& currentPosition, int layerOpacity = 255 );
Nucleon drawSymbolItem( QgsComposerLegendItem* symbolItem, QPainter* painter = 0, QPointF point = QPointF(), double labelXOffset = 0. );

/**Draws a symbol at the current y position and returns the new x position. Returns real symbol height, because for points,
it is possible that it differs from mSymbolHeight*/
Expand All @@ -224,12 +242,13 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
void drawLineSymbol( QPainter*, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity = 255 ) const;
void drawPolygonSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity = 255 ) const;

LegendSize paintAndDetermineSize( QPainter* painter, QMap<QStandardItem *, int> columns );
void drawAtom( Atom atom, QPainter* painter = 0, QPointF point = QPointF() );

double spaceAboveAtom( Atom atom );

/**Helper function that lists ids of layers contained in map canvas*/
QStringList layerIdList() const;

private:
/** Splits a string using the wrap char taking into account handling empty
wrap char which means no wrapping */
QStringList splitStringForWrapping( QString stringToSplt );
Expand Down
5 changes: 4 additions & 1 deletion src/core/pal/feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,10 @@ namespace pal
// normalise between -180 and 180
while ( angle_delta > M_PI ) angle_delta -= 2 * M_PI;
while ( angle_delta < -M_PI ) angle_delta += 2 * M_PI;
if ( f->labelInfo->max_char_angle_delta > 0 && fabs( angle_delta ) > f->labelInfo->max_char_angle_delta*( M_PI / 180 ) )
if (( f->labelInfo->max_char_angle_inside > 0 && angle_delta > 0
&& angle_delta > f->labelInfo->max_char_angle_inside*( M_PI / 180 ) )
|| ( f->labelInfo->max_char_angle_outside < 0 && angle_delta < 0
&& angle_delta < f->labelInfo->max_char_angle_outside*( M_PI / 180 ) ) )
{
delete slp;
return NULL;
Expand Down
9 changes: 6 additions & 3 deletions src/core/pal/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,19 @@ namespace pal
double width;
} CharacterInfo;

LabelInfo( int num, double height )
LabelInfo( int num, double height, double maxinangle = 20.0, double maxoutangle = -20.0 )
{
max_char_angle_delta = 20;
max_char_angle_inside = maxinangle;
// outside angle should be negative
max_char_angle_outside = maxoutangle > 0 ? -maxoutangle : maxoutangle;
label_height = height;
char_num = num;
char_info = new CharacterInfo[num];
}
~LabelInfo() { delete [] char_info; }

double max_char_angle_delta;
double max_char_angle_inside;
double max_char_angle_outside;
double label_height;
int char_num;
CharacterInfo* char_info;
Expand Down
33 changes: 8 additions & 25 deletions src/core/qgsdataitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,8 @@ QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
QString path = dir.absoluteFilePath( name );
QFileInfo fileInfo( path );

QString vsiPrefix = QgsZipItem::vsiPrefix( path );
// vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here
if (( settings.value( "/qgis/scanZipInBrowser2", QVariant( "basic" ) ).toString() != "no" ) &&
( vsiPrefix == "/vsizip/" || vsiPrefix == "/vsitar/" ) )
// so we assume it's available anyway
{
QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name );
if ( item )
Expand Down Expand Up @@ -869,14 +867,6 @@ QVector<QgsDataItem*> QgsZipItem::createChildren( )
return children;
}

// if scanZipBrowser == passthru: do not scan zip and allow to open directly with /vsizip/
// if ( scanZipSetting == 1 )
// {
// mPath = "/vsizip/" + path(); // should check for extension
// QgsDebugMsg( "set path to " + path() );
// return children;
// }

// first get list of files
getZipFileList();

Expand Down Expand Up @@ -966,21 +956,15 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin

QgsDebugMsgLevel( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path ).arg( name ).arg( scanZipSetting ).arg( vsiPrefix ), 3 );

// if scanZipBrowser == no: don't read the zip file
// don't scan if scanZipBrowser == no
if ( scanZipSetting == "no" )
{
return 0;
}
// if scanZipBrowser == passthru: do not scan zip and allow to open directly with /vsizip/
// else if ( scanZipSetting == 1 )
// {
// vsizipPath = "/vsizip/" + path;
// zipItem = 0;
// }
else
{
zipItem = new QgsZipItem( parent, name, path );
}

// don't scan if this file is not a /vsizip/ or /vsitar/ item
if (( vsiPrefix != "/vsizip/" && vsiPrefix != "/vsitar/" ) )
return 0;

zipItem = new QgsZipItem( parent, name, path );

if ( zipItem )
{
Expand Down Expand Up @@ -1036,7 +1020,6 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin
// try first with normal path (Passthru)
// this is to simplify .qml handling, and without this some tests will fail
// (e.g. testZipItemVectorTransparency(), second test)
// if (( scanZipSetting == 1 ) ||
if (( mProviderNames[i] == "ogr" ) ||
( mProviderNames[i] == "gdal" && zipFileCount == 1 ) )
item = dataItem( path, parent );
Expand Down
34 changes: 31 additions & 3 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,23 @@ class QgsPalGeometry : public PalGeometry
const char* strId() { return mStrId.data(); }
QString text() { return mText; }

pal::LabelInfo* info( QFontMetricsF* fm, const QgsMapToPixel* xform, double fontScale )
pal::LabelInfo* info( QFontMetricsF* fm, const QgsMapToPixel* xform, double fontScale, double maxinangle, double maxoutangle )
{
if ( mInfo )
return mInfo;

mFontMetrics = new QFontMetricsF( *fm ); // duplicate metrics for when drawing label

// max angle between curved label characters (20.0/-20.0 was default in QGIS <= 1.8)
if ( maxinangle < 20.0 )
maxinangle = 20.0;
if ( 60.0 < maxinangle )
maxinangle = 60.0;
if ( maxoutangle > -20.0 )
maxoutangle = -20.0;
if ( -95.0 > maxoutangle )
maxoutangle = -95.0;

// create label info!
QgsPoint ptZero = xform->toMapCoordinates( 0, 0 );
QgsPoint ptSize = xform->toMapCoordinatesF( 0.0, -fm->height() / fontScale );
Expand All @@ -111,7 +121,7 @@ class QgsPalGeometry : public PalGeometry
// (non-curved spacings handled by Qt in QgsPalLayerSettings/QgsPalLabeling)
qreal charWidth;
qreal wordSpaceFix;
mInfo = new pal::LabelInfo( mText.count(), ptSize.y() - ptZero.y() );
mInfo = new pal::LabelInfo( mText.count(), ptSize.y() - ptZero.y(), maxinangle, maxoutangle );
for ( int i = 0; i < mText.count(); i++ )
{
mInfo->char_info[i].chr = mText[i].unicode();
Expand Down Expand Up @@ -221,6 +231,8 @@ QgsPalLayerSettings::QgsPalLayerSettings()
reverseDirectionSymbol = false;
placeDirectionSymbol = SymbolLeftRight;
upsidedownLabels = Upright;
maxCurvedCharAngleIn = 20.0;
maxCurvedCharAngleOut = -20.0;
fontSizeInMapUnits = false;
fontLimitPixelSize = false;
fontMinPixelSize = 0; //trigger to turn it on by default for map unit labels
Expand Down Expand Up @@ -280,6 +292,8 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
reverseDirectionSymbol = s.reverseDirectionSymbol;
placeDirectionSymbol = s.placeDirectionSymbol;
upsidedownLabels = s.upsidedownLabels;
maxCurvedCharAngleIn = s.maxCurvedCharAngleIn;
maxCurvedCharAngleOut = s.maxCurvedCharAngleOut;
fontSizeInMapUnits = s.fontSizeInMapUnits;
fontLimitPixelSize = s.fontLimitPixelSize;
fontMinPixelSize = s.fontMinPixelSize;
Expand Down Expand Up @@ -470,6 +484,8 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
reverseDirectionSymbol = layer->customProperty( "labeling/reverseDirectionSymbol" ).toBool();
placeDirectionSymbol = ( DirectionSymbols ) layer->customProperty( "labeling/placeDirectionSymbol", QVariant( SymbolLeftRight ) ).toUInt();
upsidedownLabels = ( UpsideDownLabels ) layer->customProperty( "labeling/upsidedownLabels", QVariant( Upright ) ).toUInt();
maxCurvedCharAngleIn = layer->customProperty( "labeling/maxCurvedCharAngleIn", QVariant( 20.0 ) ).toDouble();
maxCurvedCharAngleOut = layer->customProperty( "labeling/maxCurvedCharAngleOut", QVariant( -20.0 ) ).toDouble();
minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
limitNumLabels = layer->customProperty( "labeling/limitNumLabels", QVariant( false ) ).toBool();
maxNumLabels = layer->customProperty( "labeling/maxNumLabels", QVariant( 2000 ) ).toInt();
Expand Down Expand Up @@ -540,6 +556,8 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/reverseDirectionSymbol", reverseDirectionSymbol );
layer->setCustomProperty( "labeling/placeDirectionSymbol", ( unsigned int )placeDirectionSymbol );
layer->setCustomProperty( "labeling/upsidedownLabels", ( unsigned int )upsidedownLabels );
layer->setCustomProperty( "labeling/maxCurvedCharAngleIn", maxCurvedCharAngleIn );
layer->setCustomProperty( "labeling/maxCurvedCharAngleOut", maxCurvedCharAngleOut );
layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
layer->setCustomProperty( "labeling/limitNumLabels", limitNumLabels );
layer->setCustomProperty( "labeling/maxNumLabels", maxNumLabels );
Expand Down Expand Up @@ -776,6 +794,16 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
double labelX, labelY; // will receive label size
calculateLabelSize( labelFontMetrics, labelText, labelX, labelY );

// maximum angle between curved label characters
double maxcharanglein = 20.0;
double maxcharangleout = -20.0;
if ( placement == QgsPalLayerSettings::Curved )
{
maxcharanglein = maxCurvedCharAngleIn;
maxcharangleout = maxCurvedCharAngleOut > 0 ? -maxCurvedCharAngleOut : maxCurvedCharAngleOut;
}
// TODO: add data defined override for maximum angle between curved label characters

QgsGeometry* geom = f.geometry();
if ( !geom )
{
Expand Down Expand Up @@ -1037,7 +1065,7 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
// TODO: only for placement which needs character info
pal::Feature* feat = palLayer->getFeature( lbl->strId() );
// account for any data defined font metrics adjustments
feat->setLabelInfo( lbl->info( labelFontMetrics, xform, rasterCompressFactor ) );
feat->setLabelInfo( lbl->info( labelFontMetrics, xform, rasterCompressFactor, maxcharanglein, maxcharangleout ) );
delete labelFontMetrics;

// TODO: allow layer-wide feature dist in PAL...?
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgspallabeling.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class CORE_EXPORT QgsPalLayerSettings
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
double maxCurvedCharAngleOut; // maximum angle between outside curved label characters (defaults to -20.0, range -20.0 to -95.0)
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
int fontMinPixelSize; // minimum pixel size for showing rendered map unit labels (1 - 1000)
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,8 @@ bool QgsProject::write()

dirty( false ); // reset to pristine state

emit projectSaved();

return true;
} // QgsProject::write

Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@ class CORE_EXPORT QgsProject : public QObject
//! emitted when project is being written
void writeProject( QDomDocument & );

//! emitted when the project file has been written and closed
void projectSaved();

//! emitted when an old project file is read.
void oldProjectVersionWarning( QString );

Expand Down
5 changes: 4 additions & 1 deletion src/core/qgsvectorfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,10 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
QgsVectorFileWriter* writer =
new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFieldMap() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename );

QgsDebugMsg( "newFilename = " + *newFilename );
if ( newFilename )
{
QgsDebugMsg( "newFilename = " + *newFilename );
}

// check whether file creation was successful
WriterError err = writer->hasError();
Expand Down
15 changes: 14 additions & 1 deletion src/core/qgsvectorfilewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,20 @@ class CORE_EXPORT QgsVectorFileWriter
);

/** Write contents of vector layer to an (OGR supported) vector formt
@note: this method was added in version 1.5*/
@note: this method was added in version 1.5
@param layer layer to write
@param fileName file name to write to
@param fileEncoding encoding to use
@param destCRS pointer to CRS to reproject exported geometries to
@param driverName OGR driver to use
@param onlySelected write only selected features of layer
@param errorMessage pointer to buffer fo error message
@param datasourceOptions list of OGR data source creation options
@param layerOptions list of OGR layer creation options
@param skipAttributeCreation only write geometries
@param newFilename QString pointer which will contain the new file name created
(in case it is different to fileName).
*/
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
const QString& fileName,
const QString& fileEncoding,
Expand Down
32 changes: 30 additions & 2 deletions src/core/qgsvectorlayerimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,41 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}

QgsFieldMap fields = skipAttributeCreation ? QgsFieldMap() : layer->pendingFields();
QGis::WkbType wkbType = layer->wkbType();

// Special handling for Shapefiles
if ( layer->providerType() == "ogr" && layer->storageType() == "ESRI Shapefile" )
{
// convert field names to lowercase
for ( QgsFieldMap::iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
{
fldIt.value().setName( fldIt.value().name().toLower() );
}

// convert wkbtype to multipart (see #5547)
switch ( wkbType )
{
case QGis::WKBPoint:
wkbType = QGis::WKBMultiPoint;
break;
case QGis::WKBLineString:
wkbType = QGis::WKBMultiLineString;
break;
case QGis::WKBPolygon:
wkbType = QGis::WKBMultiPolygon;
break;
case QGis::WKBPoint25D:
wkbType = QGis::WKBMultiPoint25D;
break;
case QGis::WKBLineString25D:
wkbType = QGis::WKBMultiLineString25D;
break;
case QGis::WKBPolygon25D:
wkbType = QGis::WKBMultiPolygon25D;
break;
default:
break;
}
}

bool overwrite = false;
Expand All @@ -220,7 +248,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}

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

// check whether file creation was successful
ImportError err = writer->hasError();
Expand All @@ -240,7 +268,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
QgsFeature fet;

layer->select( allAttr, QgsRectangle(), layer->wkbType() != QGis::WKBNoGeometry );
layer->select( allAttr, QgsRectangle(), wkbType != QGis::WKBNoGeometry );

const QgsFeatureIds& ids = layer->selectedFeaturesIds();

Expand Down
8 changes: 2 additions & 6 deletions src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,9 @@ QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer()

void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
{
QFile svgFile( svgPath );
if ( svgFile.open( QFile::ReadOnly ) )
{
mSvgData = svgFile.readAll();
mSvgData = QgsSvgCache::instance()->getImageData( svgPath );
storeViewBox();

storeViewBox();
}
mSvgFilePath = svgPath;
setDefaultSvgParams();
}
Expand Down
22 changes: 21 additions & 1 deletion src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re
}
else
{
p->setOpacity( context.alpha( ) );
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 );
Expand Down Expand Up @@ -842,6 +842,26 @@ QString QgsSvgMarkerSymbolLayerV2::symbolNameToPath( QString name )
if ( QFile( name ).exists() )
return QFileInfo( name ).canonicalFilePath();

// or it might be an url...
QUrl url( name );
if ( url.isValid() && !url.scheme().isEmpty() )
{
if ( url.scheme().compare( "file", Qt::CaseInsensitive ) == 0 )
{
// it's a url to a local file
name = url.toLocalFile();
if ( QFile( name ).exists() )
{
return QFileInfo( name ).canonicalFilePath();
}
}
else
{
// it's a url pointing to a online resource
return name;
}
}

// SVG symbol not found - probably a relative path was used

QStringList svgPaths = QgsApplication::svgPaths();
Expand Down
Loading