QGIS/python/plugins/osm/OsmSaveDlg.py
jef 29fdde20cb OSM plugin & provider update from Lukas Berka:
- new OSM style files !! map looks pretty good now... (finally)
- new icons !
- some texts on dialogs were changed and completed
- "Saving OSM into file" functionality was improved a little...
- now OSM Plugin verify if osm provider is available...
- fixed some problems with encoding... ascii --> utf-8
- removing all OSM layers automatically after disabling OSM plugin in plugin manager
- some dialogs has been renamed
- other small bugfixes ...

Thanks.



git-svn-id: http://svn.osgeo.org/qgis/trunk@11603 c8812cc2-4d05-0410-92ff-de0c093fc19c
2009-09-09 12:16:24 +00:00

464 lines
19 KiB
Python

# -*- coding: utf-8 -*-
"""@package OsmSaveDlg
This module is used to save OSM data into XML file.
Of course, user is asked where to save the current data first.
"""
from ui_OsmSaveDlg import Ui_OsmSaveDlg
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtXml import *
from PyQt4 import *
from sip import unwrapinstance
from qgis.core import QgsVectorLayer, QgsMapLayerRegistry
import sqlite3
class OsmSaveDlg(QDialog, Ui_OsmSaveDlg):
"""This class provides all structures and methods neccessary for current OSM data saving.
Saving is done to XML file.
After XML file selection and confirming the dialog, process is started.
"""
def __init__(self, plugin):
"""The constructor.
@param plugin is pointer to instance of OSM Plugin
"""
QDialog.__init__(self, None)
self.setupUi(self)
self.plugin=plugin
self.ur=plugin.undoredo
self.dbm=plugin.dbm
self.progressDialog = QProgressDialog(self)
self.progressDialog.setModal(True)
self.progressDialog.setAutoClose(False)
# variables for identifiers of all objects that will be saved to output file
self.nodeIds=set()
# connecting dialog and progressbar signals
QObject.connect(self.browseOSMButton,SIGNAL("clicked()"),self.showSaveFileDialog)
QObject.connect(self.buttonBox,SIGNAL("accepted()"),self.onOK)
QObject.connect(self.progressDialog, SIGNAL("canceled()"), self.cancelSaving)
def cancelSaving(self):
"""Function stops the whole OSM Saving process.
Destination file is closed and removed.
"""
# writing into output file was canceled, file must be enclosed
self.outFile.close()
# end removed
self.outFile.remove()
self.outFile=None
# close the whole Save OSM dialog
self.close()
def showSaveFileDialog(self):
"""Function opens dialog for selecting XML file.
Only files with extension .osm can be selected.
Default directory for file selection is remembered/reload.
"""
settings = QSettings()
lastDir = settings.value("/OSM_Plugin/lastDir", QVariant(QString())).toString()
# display file open dialog and get absolute path to selected file
fileSelected = QFileDialog.getSaveFileName(self,"Choose an Open Street Map file",lastDir,"OSM Files (*.osm)");
# insert OSM file path into line edit control
if not fileSelected.isNull():
self.OSMFileEdit.setText(fileSelected)
# remember directory
fi = QFileInfo(fileSelected)
settings.setValue("/OSM_Plugin/lastDir", QVariant(fi.path()) )
def onOK(self):
"""Function is called after clicking on OK button of OSM Save dialog.
It performs all actions neccessary for OSM data saving.
"""
# prepare data
self.fname=self.OSMFileEdit.text()
self.outFile=QFile(self.fname)
if not self.outFile.open(QIODevice.WriteOnly):
QMessageBox.information(self,self.tr("Save OSM to file"),self.tr("Unable to save the file %1: %2.")
.arg(self.fname).arg(self.outFile.errorString()))
self.outFile=None
return
points=self.chkPoints.isChecked()
lines=self.chkLines.isChecked()
polys=self.chkPolygons.isChecked()
rels=self.chkRelations.isChecked()
tags=self.chkTags.isChecked()
self.xml=QXmlStreamWriter(self.outFile)
self.xml.setCodec(QTextCodec.codecForName("utf-8"))
self.xml.setAutoFormatting(True)
c=self.dbm.getConnection().cursor()
cntPoints=cntLines=cntPolys=cntRels=0
c.execute("select count(*) from node")
for rec in c:
cntPoints=rec[0]
c.execute("select count(*) from way where closed=0")
for rec in c:
cntLines=rec[0]
c.execute("select count(*) from way where closed=1")
for rec in c:
cntPolys=rec[0]
c.execute("select count(*) from relation")
for rec in c:
cntRels=rec[0]
self.xml.writeStartDocument()
self.xml.writeStartElement("osm")
self.xml.writeAttribute("version","0.6")
self.xml.writeAttribute("generator","OpenStreetMap server")
self.progressDialog.setWindowTitle(self.tr("Save OSM to file"))
self.progressDialog.setLabelText(self.tr("Initializing..."))
self.progressDialog.setMaximum(1)
self.progressDialog.setValue(0)
self.progressDialog.show()
# <bounds> element
dataExtent=self.plugin.canvas.extent()
self.xml.writeEmptyElement("bounds")
self.xml.writeAttribute("minlat",str(dataExtent.yMinimum()))
self.xml.writeAttribute("minlon",str(dataExtent.xMinimum()))
self.xml.writeAttribute("maxlat",str(dataExtent.yMaximum()))
self.xml.writeAttribute("maxlon",str(dataExtent.xMaximum()))
# todo: uid and changeset attributes are not compulsory! support for them in future!
if points:
self.progressDialog.setLabelText(self.tr("Saving nodes..."))
self.progressDialog.setMaximum(cntPoints)
self.progressDialog.setValue(0)
i=0
c.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
where n.status<>'R' and n.u=1 and v.object_id=n.id and v.object_type='node' \
and n.lat>=:minLat AND n.lat<=:maxLat AND n.lon>=:minLon AND n.lon<=:maxLon"
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
for (nid,lat,lon,ver,usr,tms) in c:
anyTags=False
tagList=[]
self.nodeIds.add(nid)
if tags:
tagList=self.dbm.getFeatureTags(nid,'Point')
if len(tagList)>0:
anyTags=True
if anyTags:
self.xml.writeStartElement("node")
else:
self.xml.writeEmptyElement("node")
self.xml.writeAttribute("id",str(nid))
self.xml.writeAttribute("lat",str(lat))
self.xml.writeAttribute("lon",str(lon))
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
if anyTags:
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
i=i+1
self.progressDialog.setValue(i)
if lines:
self.progressDialog.setLabelText(self.tr("Saving lines..."))
self.progressDialog.setMaximum(cntLines)
self.progressDialog.setValue(0)
i=0
c.execute("select w.id,v.version_id,w.user,w.timestamp from way w,version v \
where w.closed=0 and w.status<>'R' and w.u=1 and v.object_id=w.id and v.object_type='way' \
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon)))"
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
for (lid,ver,usr,tms) in c:
geom=self.dbm.getFeatureGeometry(lid,'Line')
if not geom.intersects(dataExtent):
continue
self.xml.writeStartElement("way")
self.xml.writeAttribute("id",str(lid))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
d=self.dbm.getConnection().cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":lid})
for r in d:
self.xml.writeEmptyElement("nd")
self.xml.writeAttribute("ref",str(r[0]))
d.close()
if tags:
tagList=self.dbm.getFeatureTags(lid,'Line')
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
d=self.dbm.getConnection().cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":lid})
for r in d:
if r[0] not in self.nodeIds:
e=self.dbm.getConnection().cursor()
e.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
where n.id=:nid",{"nid":r[0]})
for nodeRec in e:
nid=nodeRec[0]
lat=nodeRec[1]
lon=nodeRec[2]
ver=nodeRec[3]
usr=nodeRec[4]
tms=nodeRec[5]
e.close()
anyTags=False
tagList=[]
self.nodeIds.add(nid)
if tags:
tagList=self.dbm.getFeatureTags(nid,'Point')
if len(tagList)>0:
anyTags=True
if anyTags:
self.xml.writeStartElement("node")
else:
self.xml.writeEmptyElement("node")
self.xml.writeAttribute("id",str(nid))
self.xml.writeAttribute("lat",str(lat))
self.xml.writeAttribute("lon",str(lon))
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
if anyTags:
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
d.close()
i=i+1
self.progressDialog.setValue(i)
if polys:
self.progressDialog.setLabelText(self.tr("Saving polygons..."))
self.progressDialog.setMaximum(cntPolys)
self.progressDialog.setValue(0)
i=0
c.execute("select w.id,v.version_id,w.user,w.timestamp from way w,version v \
where w.closed=1 and w.status<>'R' and w.u=1 and v.object_id=w.id and v.object_type='way' \
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon)))"
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
for (pid,ver,usr,tms) in c:
geom=self.dbm.getFeatureGeometry(pid,'Polygon')
if not geom.intersects(dataExtent):
continue
self.xml.writeStartElement("way")
self.xml.writeAttribute("id",str(pid))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
d=self.dbm.getConnection().cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":pid})
first=None
for r in d:
self.xml.writeEmptyElement("nd")
self.xml.writeAttribute("ref",str(r[0]))
if first==None:
first=r[0]
d.close()
self.xml.writeEmptyElement("nd")
self.xml.writeAttribute("ref",str(first))
if tags:
tagList=self.dbm.getFeatureTags(pid,'Polygon')
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
d=self.dbm.getConnection().cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":pid})
for r in d:
if r[0] not in self.nodeIds:
e=self.dbm.getConnection().cursor()
e.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
where n.id=:nid",{"nid":r[0]})
for nodeRec in e:
nid=nodeRec[0]
lat=nodeRec[1]
lon=nodeRec[2]
ver=nodeRec[3]
usr=nodeRec[4]
tms=nodeRec[5]
e.close()
anyTags=False
tagList=[]
self.nodeIds.add(nid)
if tags:
tagList=self.dbm.getFeatureTags(nid,'Point')
if len(tagList)>0:
anyTags=True
if anyTags:
self.xml.writeStartElement("node")
else:
self.xml.writeEmptyElement("node")
self.xml.writeAttribute("id",str(nid))
self.xml.writeAttribute("lat",str(lat))
self.xml.writeAttribute("lon",str(lon))
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
if anyTags:
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
d.close()
i=i+1
self.progressDialog.setValue(i)
if rels:
self.progressDialog.setLabelText(self.tr("Saving relations..."))
self.progressDialog.setMaximum(cntRels)
self.progressDialog.setValue(0)
i=0
c.execute("select r.id,v.version_id,r.user,r.timestamp from relation r,version v \
where r.status<>'R' and r.u=1 and v.object_id=r.id and v.object_type='relation' \
and ( \
exists ( \
select 1 from node n, relation_member rm \
where rm.relation_id=r.id and n.status<>'R' and n.u=1 and rm.member_id=n.id and rm.member_type='node' \
and n.lat>=:minLat and n.lat<=:maxLat and n.lon>=:minLon and n.lon<=:maxLon ) \
or exists ( \
select 1 from way w, relation_member rm \
where rm.relation_id=r.id and w.status<>'R' and w.u=1 and rm.member_id=w.id and rm.member_type='way' \
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon))) \
))"
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
for (rid,ver,usr,tms) in c:
self.xml.writeStartElement("relation")
self.xml.writeAttribute("id",str(rid))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",tms)
self.xml.writeAttribute("version",str(ver))
if usr<>"":
self.xml.writeAttribute("user",usr)
d=self.dbm.getConnection().cursor()
d.execute("select member_id,member_type,role from relation_member where relation_id=:relId",{"relId":rid})
for r in d:
self.xml.writeEmptyElement("member")
self.xml.writeAttribute("type",r[1])
self.xml.writeAttribute("ref",str(r[0]))
self.xml.writeAttribute("role",r[2])
d.close()
if tags:
tagList=self.dbm.getFeatureTags(rid,'Relation')
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
self.xml.writeEndElement()
i=i+1
self.progressDialog.setValue(i)
self.xml.writeEndElement() # osm
self.xml.writeEndDocument()
c.close()
self.disconnect(self.progressDialog, SIGNAL("canceled()"), self.cancelSaving)
self.progressDialog.close()
# writing into output file was finished, file can be enclosed
if self.outFile and self.outFile.exists():
self.outFile.close()
self.close()