[FEATURE] Imported OpenStreetMap provider and plugin.

git-svn-id: http://svn.osgeo.org/qgis/trunk@11210 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
wonder 2009-07-30 11:08:18 +00:00
parent 79aa90be10
commit 257e30ea9b
69 changed files with 22609 additions and 2 deletions

View File

@ -1 +1 @@
SUBDIRS(plugin_installer mapserver_export fTools)
SUBDIRS(plugin_installer mapserver_export fTools osm)

View File

@ -0,0 +1,12 @@
#TODO: Need to configure cmake to run pyrcc4 and pyuic4 as required when the resource
# file or the ui change
SET (OSM_PLUGIN_DIR ${QGIS_DATA_DIR}/python/plugins/osm)
FILE (GLOB PYTHON_FILES *.py)
FILE (GLOB MAPTOOLS_PYTHON_FILES map_tools/*.py)
FILE (GLOB STYLE_FILES styles/*.style)
INSTALL (FILES ${PYTHON_FILES} DESTINATION ${OSM_PLUGIN_DIR})
INSTALL (FILES ${MAPTOOLS_PYTHON_FILES} DESTINATION ${OSM_PLUGIN_DIR}/map_tools)
INSTALL (FILES ${STYLE_FILES} DESTINATION ${OSM_PLUGIN_DIR}/styles)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,798 @@
"""@package DlgAddRelation
The main class of this module (DlgAddRelation) is descendant of "Create OSM Relation" dialog.
The dialog either shows detail info on existing relation or is empty when no relation id is passed to constructor.
In brief this module (and its main class) just provides easy way to create or change OSM relation.
...
"""
from DlgAddRelation_ui import Ui_DlgAddRelation
from map_tools.IdentifyMapTool import IdentifyMapTool
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import *
from sip import unwrapinstance
from qgis.core import *
from qgis.gui import *
import sqlite3
class DlgAddRelation(QDialog, Ui_DlgAddRelation):
"""This class is direct descendant of "Create OSM Relation" dialog. It provides easy way to create
or change OSM relation. Methods of DlgAddRelation class catch signals emitted when changing relations
type, tags or members, submitting or rejecting the whole dialog. After catching signal, methods must
perform appropriate operation using methods of DatabaseManager. The other methods serve to initialize
dialog when displaying info on existing relation."""
def __init__(self, plugin, newRelationFirstMember=None, relationToEdit=None):
"""The constructor.
@param plugin pointer to OSM Plugin object; parent of this object
@param newRelationFirstMember info on feature (in form: "idSPACEtype") which will be first member of new relation
@param relationToEdit if relation is given, this dialog is for editing of existing relation, not for creation a new one
"""
QDialog.__init__(self,None)
self.setupUi(self)
self.dockWidget=plugin.dockWidget
self.plugin=plugin
self.dbm=plugin.dbm
self.ur=plugin.undoredo
self.canvas=plugin.canvas
# set icons for tool buttons (identify,move,createPoint,createLine,createPolygon)
self.chooseMemberButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_identify.png"))
self.removeMemberButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_remove.png"))
self.removeTagButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_remove.png"))
self.loadStandardTagsButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_star.png"))
self.typeInfoButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_questionMark.png"))
self.info = dict()
self.newTagLabel = "<new tag here>"
self.newMemberLabel = "<new member here>"
self.tagInfoTextEdit.setText("<nothing>")
if relationToEdit:
# we are editing existing relation
self.editing = True
self.relId = relationToEdit
self.createRelButton.setText("Save")
self.setWindowTitle("Edit OSM relation")
else:
self.editing = False
# we are adding new relation
if newRelationFirstMember:
ix = newRelationFirstMember.indexOf(" ")
self.firstMemberType = QString(newRelationFirstMember).left(ix)
self.firstMemberId = QString(newRelationFirstMember).right(len(newRelationFirstMember)-ix-1)
self.relTags=[]
self.relTagsEditIndex=-1
self.relMembersRoleEditIndex=-1
self.relMembersTypeEditIndex=-1
self.connectDlgSignals()
# clear all dialog items first
self.clear()
# load default values to combobox determining relation type
self.relationTypes=["boundary","multipolygon","restriction","route","enforcement"]
self.typeCombo.addItem("")
self.typeCombo.addItems(self.relationTypes)
if self.editing:
# we are editing existing relation, we'll load relation data first
self.loadRelationData(self.relId)
else:
if newRelationFirstMember:
self.addRelationMember(self.firstMemberId,self.firstMemberType,None)
# enable related tool buttons
self.removeMemberButton.setEnabled(True)
self.relMembersLoaded = True
self.relMembersTable.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.relTagsTable.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.relMembersTable.setSelectionBehavior(QAbstractItemView.SelectRows)
self.relTagsTable.setSelectionBehavior(QAbstractItemView.SelectRows)
def connectDlgSignals(self):
"""Function connects important dialog signals to appropriate slots.
"""
# signals on working with tag and member tables
QObject.connect(self.typeCombo, SIGNAL("currentIndexChanged(const QString &)"), self.__onTypeSelectionChanged)
QObject.connect(self.relTagsTable, SIGNAL("itemDoubleClicked(QTableWidgetItem*)"), self.__onTagsItemDoubleClicked)
QObject.connect(self.relMembersTable, SIGNAL("itemDoubleClicked(QTableWidgetItem*)"), self.__onMembersItemDoubleClicked)
QObject.connect(self.relTagsTable, SIGNAL("cellChanged(int,int)"), self.__onTagsCellChanged)
QObject.connect(self.relMembersTable, SIGNAL("cellChanged(int,int)"), self.__onMembersCellChanged)
# signals on buttons clicking
QObject.connect(self.createRelButton, SIGNAL("clicked()"), self.createOrUpdateRelation)
QObject.connect(self.stornoButton, SIGNAL("clicked()"), self.stornoDialog)
QObject.connect(self.typeInfoButton, SIGNAL("clicked()"), self.__showTypeInfo)
QObject.connect(self.loadStandardTagsButton, SIGNAL("clicked()"), self.loadStandardTags)
QObject.connect(self.removeTagButton, SIGNAL("clicked()"), self.removeSelectedRelTags)
QObject.connect(self.removeMemberButton, SIGNAL("clicked()"), self.removeSelectedRelMembers)
QObject.connect(self.chooseMemberButton, SIGNAL("clicked()"), self.__startIdentifyingMember)
def addRelationMember(self,memberId,memberType,memberRole):
"""Function inserts one record into table representing list of all relations' members.
New record is put to the first place of the list.
@param memberId identifier of new relation member
@param memberType type of new relation member
@param memberRole role of new relation member
"""
# insert row for new relation member
self.relMembersTable.insertRow(0)
self.relMembersTable.setItem(0,0,QTableWidgetItem(str(memberId)))
self.relMembersTable.setItem(0,1,QTableWidgetItem(str(memberType)))
self.relMembersTable.setItem(0,2,QTableWidgetItem(str(memberRole)))
self.relMembersTable.item(0,0).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(0,1).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(0,2).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
def addRelationTag(self,tagKey,tagValue):
"""Function inserts one record into table representing list of all relations' tags.
New record is put to the first place of the list.
@param tagKey key of inserted tag
@param tagValue value of inserted tag
"""
# insert row for new relation tag
self.relTagsTable.insertRow(0)
self.relTagsTable.setItem(0,0,QTableWidgetItem(tagKey))
self.relTagsTable.setItem(0,1,QTableWidgetItem(tagValue))
self.relTagsTable.item(0,0).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.relTagsTable.item(0,1).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
def loadRelationData(self,relId):
"""Function fills dialog items with data of given relation.
Data of relation means its type, tags and members.
@param relId identifier of relation
"""
# load tags of specified relation
self.relTags=self.dbm.getFeatureTags(relId,'Relation')
rowCount = len(self.relTags)
for i in range(0,rowCount):
key = self.relTags[i][0]
value = self.relTags[i][1]
if key=="type":
# tag with key "type" is not shown in relation tags table, there is special combobox for it instead
ix=self.typeCombo.findText(value)
if ix<>-1:
self.typeCombo.setCurrentIndex(ix)
else:
self.typeCombo.setEditText(value)
else:
# all other tags are displayed in tags table
self.addRelationTag(key,value)
# fill relation members table with relation members data
mems=self.dbm.getRelationMembers(relId)
# printing members
for i in range(0,len(mems)):
self.addRelationMember(mems[i][0],mems[i][1],mems[i][2])
# enable related tool buttons
self.removeMemberButton.setEnabled(True)
# set new flags values
self.relTagsLoaded = True
self.relMembersLoaded = True
def __startIdentifyingMember(self):
"""Function enables maptool for identifying relation members directly on map.
"""
if self.chooseMemberButton.isChecked():
self.mapTool=IdentifyMapTool(self.canvas, self.dockWidget, self.dbm)
self.canvas.setMapTool(self.mapTool)
self.canvas.setCursor(QCursor(Qt.ArrowCursor))
self.canvas.setFocus(Qt.OtherFocusReason)
else:
self.addRelationMember(self.dockWidget.feature.id(),self.dockWidget.featureType,"")
self.canvas.unsetMapTool(self.mapTool)
del self.mapTool
self.mapTool=None
def removeSelectedRelTags(self):
"""Function removes all selected tags from relation tags table.
"""
# remove selected tags (rows)
selectedItems=self.relTagsTable.selectedItems()
selectedRowsIndexes=[]
lastRowIndex=self.relTagsTable.rowCount()-1
self.relTagsTable.setCurrentCell(lastRowIndex,0)
for i in selectedItems:
if i.column()==0 and not i.row()==lastRowIndex:
selectedRowsIndexes.append(i.row())
selectedRowsIndexes.sort()
selectedRowsIndexes.reverse()
for ix in selectedRowsIndexes:
key=self.relTagsTable.item(ix,0).text()
self.relTagsTable.removeRow(ix)
def removeSelectedRelMembers(self):
"""Function removes all selected members from relation members table.
"""
# remove selected members (rows)
selectedItems=self.relMembersTable.selectedItems()
selectedRowsIndexes=[]
lastRowIndex=self.relMembersTable.rowCount()-1
self.relMembersTable.setCurrentCell(lastRowIndex,0)
for i in selectedItems:
if i.column()==0 and not i.row()==lastRowIndex:
selectedRowsIndexes.append(i.row())
selectedRowsIndexes.sort()
selectedRowsIndexes.reverse()
for ix in selectedRowsIndexes:
key=self.relMembersTable.item(ix,0).text()
self.relMembersTable.removeRow(ix)
def __onTagsCellChanged(self,row,column):
"""Function to handle user changes in cells of relations' tags table.
It's called automatically whenever signal "cellChanged(...)" is emitted.
@param row index of a row that has changed
@param column index of a column that has changed
"""
if not self.relTagsLoaded:
return
if row==self.relTagsTable.rowCount()-1:
# changing value of the last row
key = self.relTagsTable.item(row,0).text()
if key=="" or key==self.newTagLabel:
return
# adding new tag to table
if column==0:
newLastRow = row+1
self.relTagsTable.setRowCount(row+2)
self.relTagsTable.setItem(newLastRow,0,QTableWidgetItem(self.newTagLabel))
self.relTagsTable.setItem(newLastRow,1,QTableWidgetItem(""))
self.relTagsTable.item(newLastRow,0).setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relTagsTable.item(newLastRow,1).setFlags(Qt.ItemIsEnabled)
self.relTagsTable.item(row,0).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.relTagsTable.item(row,1).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
def __onMembersCellChanged(self,row,column):
"""Function to handle user changes in cells of relations' members table.
it's called automatically whenever signal "cellChanged(...)" is emitted.
@param row index of a row that has changed
@param column index of a column that has changed
"""
if not self.relMembersLoaded:
return
if row==self.relMembersTable.rowCount()-1:
# changing value of the last row
memberId = self.relMembersTable.item(row,0).text()
if memberId=="" or memberId==self.newMemberLabel:
return
# adding new member
if column==0:
newLastRow = row+1
self.relMembersTable.setRowCount(row+2)
self.relMembersTable.setItem(newLastRow,0,QTableWidgetItem(self.newMemberLabel))
self.relMembersTable.setItem(newLastRow,1,QTableWidgetItem(""))
self.relMembersTable.setItem(newLastRow,2,QTableWidgetItem(""))
self.relMembersTable.item(newLastRow,0).setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(newLastRow,1).setFlags(Qt.ItemIsEnabled)
self.relMembersTable.item(newLastRow,2).setFlags(Qt.ItemIsEnabled)
self.relMembersTable.item(row,0).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(row,1).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(row,2).setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
def clear(self):
"""Function removes content of all dialog items (with one exception) and set them to default values.
The only exception is combobox determining relation type.
It stays untouched.
"""
# clear table of relation properties(tags) and all related buttons
self.relTagsTable.clear()
self.removeTagButton.setEnabled(True)
# clear table of relation members and all related buttons
self.relMembersTable.clear()
self.chooseMemberButton.setEnabled(True)
self.removeMemberButton.setEnabled(False)
# clear information panel
self.tagInfoTextEdit.setText("<nothing>")
self.tagInfoTextEdit.setEnabled(False)
# set loading flags to false
self.relTagsLoaded = True
self.relMembersLoaded = True
# load default data into relation members table
self.relMembersTable.setColumnCount(3)
self.relMembersTable.setHorizontalHeaderItem(0,QTableWidgetItem("Id"))
self.relMembersTable.setHorizontalHeaderItem(1,QTableWidgetItem("Type"))
self.relMembersTable.setHorizontalHeaderItem(2,QTableWidgetItem("Role"))
self.relMembersTable.setRowCount(1)
self.relMembersTable.setItem(0,0,QTableWidgetItem(self.newMemberLabel))
self.relMembersTable.setItem(0,1,QTableWidgetItem(""))
self.relMembersTable.setItem(0,2,QTableWidgetItem(""))
self.relMembersTable.item(0,0).setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relMembersTable.item(0,1).setFlags(Qt.ItemIsEnabled)
self.relMembersTable.item(0,2).setFlags(Qt.ItemIsEnabled)
# load default data into relation tags table
self.relTagsTable.setColumnCount(2)
self.relTagsTable.setHorizontalHeaderItem(0,QTableWidgetItem("Key"))
self.relTagsTable.setHorizontalHeaderItem(1,QTableWidgetItem("Value"))
self.relTagsTable.setRowCount(1)
self.relTagsTable.removeCellWidget(0,1)
self.relTagsTable.setItem(0,0,QTableWidgetItem(self.newTagLabel))
self.relTagsTable.setItem(0,1,QTableWidgetItem(""))
self.relTagsTable.item(0,0).setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relTagsTable.item(0,1).setFlags(Qt.ItemIsEnabled)
def loadStandardTags(self):
"""Function clears relations' tags table and then loads tags that are typical
for chosen relation type.
This provides good way how to help users with creating standard relations.
User doesn't need to find out what tags are usually used for some relation.
"""
# clear relation tags table first
self.relTagsTable.clear()
self.relTagsTable.setColumnCount(2)
self.relTagsTable.setHorizontalHeaderItem(0,QTableWidgetItem("Key"))
self.relTagsTable.setHorizontalHeaderItem(1,QTableWidgetItem("Value"))
self.relTagsTable.setRowCount(1)
self.relTagsTable.removeCellWidget(0,1)
self.relTagsTable.setItem(0,0,QTableWidgetItem(self.newTagLabel))
self.relTagsTable.setItem(0,1,QTableWidgetItem(""))
self.relTagsTable.item(0,0).setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
self.relTagsTable.item(0,1).setFlags(Qt.ItemIsEnabled)
# find tags that are recommended for chosen relation type
self.relTags = self.determineSuitableTags(self.typeCombo.currentText())
# put found tags into relation tags table
rowCount = len(self.relTags)
for i in range(0,rowCount):
self.addRelationTag(list(self.relTags)[i],"")
# set variables and enable buttons for better manipulation with table
self.removeTagButton.setEnabled(True)
self.relTagsLoaded = True
def __onTypeSelectionChanged(self,typeName):
"""Function is called after currentIndexChanged(...) signal is emitted on "RELATION TYPE" combobox.
That means user select new relation type. Either one of predefined types or a new one.
Function doesn't perform change of relation type this time. Everything will be done
after submiting the whole dialog.
@param typeName name of new selected type
"""
# if non-standard typename was set up, loadStandardTagsButton is useless
if typeName.toAscii().data() in self.relationTypes:
self.loadStandardTagsButton.setEnabled(True)
else:
self.loadStandardTagsButton.setEnabled(False)
def determineSuitableMemberRoles(self,relType):
"""Function is used to find typical member roles to given relation type.
With help of this function plugin gives advice to user on relation creation.
@param relType name of relation type
@return list of typical roles to given type of relation
"""
roles = []
if relType=="boundary":
roles = ["enclave","exclave"]
elif relType=="multipolygon":
roles = ["outer","inner"]
elif relType=="restriction":
roles = ["from","to","via","location_hint"]
elif relType=="route":
roles = ["forward","backward","stop_0","stop_1","stop_2","stop_3","stop_4","stop_5","stop_6","stop_7","stop_8","stop_9"
,"forward_stop_0","forward_stop_1","forward_stop_2","forward_stop_3","forward_stop_4","forward_stop_5","forward_stop_6"
,"forward_stop_7","forward_stop_8","forward_stop_9","backward_stop_0","backward_stop_1","backward_stop_2"
,"backward_stop_3","backward_stop_4","backward_stop_5","backward_stop_6","backward_stop_7","backward_stop_8","backward_stop_9"]
elif relType=="enforcement":
roles = []
return roles
def determineSuitableTags(self,relType):
"""Function is used to find typical tags to given relation type.
With of this function plugin gives advice to user on relation creation.
@param relType name of relation type
@return list of typical tags to given type of relation
"""
tags = []
if relType=="boundary":
tags = dict(
boundary='For a real boundary (sometimes in the middle of a river or 12 Miles away from coastline).'
,land_area='For coastline and real boundaries on land.'
,name=''
,admin_level=''
)
elif relType=="multipolygon":
tags = dict()
elif relType=="restriction":
tags = {
"restriction":"If the first word is \"no\", then no routing is possible from the \"from\" to the \"to\" member, and if it is \"only_\", then you know that the only routing originating from the \"from\" member leads to the \"to\" member. The \"from\" and \"to\" members must start/end at the \"via\" node (see 1)."
,"except":"The restriction does not apply to these vehicle types (possible more than one: except=bicycle;psv)"
,"day_on":"For example, no right turn in the morning peak on weekdays might be day_on=Monday;day_off=Friday;hour_on=07:30;hour_off=09:30."
,"day_off":""
,"hour_on":""
,"hour_off":""
}
elif relType=="route":
tags = dict(
route='A road (e.g. the ways making up the A14 trunk road), bicycle route, hiking route or whatever route.'
,name='The route is known by this name (e.g. "Jubilee Cycle Route", "Pembrokeshire Coastal Path").'
,ref='The route is known by this reference (e.g. "A14", "NCN 11", "Citi 4" (bus number); in germany there is always a space between character and number, e.g. "A 1", "L 130", "K 5"; in france too).'
,network='A wider network of routes of which this is one example. For example, the UKs national cycle network; the Cambridge Citi bus network; the UKs long distance footpath network. (The "uk_" bit isnt particularly to identify it as belonging to the uk, merely to be a conventional way to separate the namespace.)'
,operator='The route is operated by this authority/company etc. e.g. "Stagecoach Cambridge", "Eurostar".'
,state='Sometimes routes may not be permanent (ie: diversions), or may be in a proposed state (ie: UK NCN routes are sometimes not official routes pending some negotiation or development). Connection is used for routes linking two different routes or linking a route with for example a village centre.'
,symbol='Describes the symbol that is used to mark the way along the route, e.g., "Red cross on white ground" for the "Frankenweg" in Franconia, Germany.'
,color='(optional) Color code noted in hex triplet format. Especially useful for public transport routes. Example: "#008080" for teal color.'
,description='Description tells what is special about this route.'
,distance='(optional) The distance covered by this route, if known. For information of users and automatic evaluation e.g. of completeness. Given including a unit and with a dot for decimals. (e.g. "12.5km")'
)
elif relType=="enforcement":
tags = dict()
return tags
def determineSuitableTagValues(self,relType,tagKey):
"""Function is used to find typical tag values for given relation type and given key.
With help of this function plugin gives advice to user on relation creation.
@param relType name of relation type
@param tagKey key of tag
@return list of typical tag values to given relation type
"""
vals = []
if relType=="boundary":
if tagKey=="boundary":
vals = ["administrative","national_park","political","civil"]
elif tagKey=="land_area":
vals = ["administrative"]
elif tagKey=="admin_level":
vals = ["1","2","3","4","5","6","7","8","9","10","11"]
elif relType=="restriction":
if tagKey=="restriction":
vals = ["no_right_turn","no_left_turn","no_u_turn","no_straight_on","only_right_turn","only_left_turn","only_straight_on"]
elif tagKey=="except":
vals = ["psv","bicycle","hgv","motorcar"]
elif relType=="route":
if tagKey=="route":
vals = ["road","bicycle","foot","hiking","bus","pilgrimage","detour","railway","tram","mtb","roller_skate","running","horse"]
elif tagKey=="network":
vals = ["ncn","rcn","lcn","uk_ldp","lwn","rwn","nwn","e-road"]
elif tagKey=="state":
vals = ["proposed","alternate","temporary","connection"]
return vals
def createRelation(self):
"""Function creates new OSM relation from dialog data.
It performs commit.
"""
# collect relation members data into a list
relMems=[]
for i in range(0,self.relMembersTable.rowCount()-1): # except from the last row
memId = self.relMembersTable.item(i,0).text().toUtf8().data()
memType = self.relMembersTable.item(i,1).text().toUtf8().data()
memRole = self.relMembersTable.item(i,2).text().toUtf8().data()
relMems.append((memId,memType,memRole))
# find out relation type
relType=self.typeCombo.currentText().toUtf8().data()
# call relation creation
self.ur.startAction("Create relation.")
relId=self.dbm.createRelation(relType,relMems)
relTags=[]
for i in range(0,self.relTagsTable.rowCount()-1): # except from the last row
key=self.relTagsTable.item(i,0).text().toUtf8().data()
val=self.relTagsTable.item(i,1).text().toUtf8().data()
relTags.append((key,val))
# relation type has to be stored as tag too
relTags.append(('type',relType))
# insert relation tags
self.dbm.insertTags(relId,'Relation',relTags)
# make actions persistent
self.dbm.commit()
self.ur.stopAction()
def updateRelation(self):
"""Function updates existing OSM relation.
It performs commit.
Relation is not given in parameter; it's in member variable of this class.
"""
self.ur.startAction("Update relation.")
# find out relation type and change it
relType=self.typeCombo.currentText().toUtf8().data()
self.dbm.changeRelationType(self.relId,relType)
# remove all relation tags and members
self.dbm.removeFeaturesTags(self.relId,'Relation')
# collect relation members into a list
relMems=[]
for i in range(0,self.relMembersTable.rowCount()-1): # except from the last row
memId = self.relMembersTable.item(i,0).text().toUtf8().data()
memType = self.relMembersTable.item(i,1).text().toUtf8().data()
memRole = self.relMembersTable.item(i,2).text().toUtf8().data()
relMems.append((memId,memType,memRole))
# remove old members and insert new ones
self.dbm.changeAllRelationMembers(self.relId,relMems)
# collect relation tags into a list
relTags=[]
for i in range(0,self.relTagsTable.rowCount()-1): # except from the last row
key=self.relTagsTable.item(i,0).text().toUtf8().data()
val=self.relTagsTable.item(i,1).text().toUtf8().data()
relTags.append((key,val))
# relation type has to be stored as tag too
relTags.append(('type',relType))
# insert relation tags
self.dbm.insertTags(self.relId,'Relation',relTags)
# make actions persistent
self.ur.stopAction()
self.dbm.commit()
def createOrUpdateRelation(self):
"""Function starts process of creation of new OSM relation from dialog data.
When in editing mode function updates opened relation instead.
"""
if not self.editing:
# lets create new relation from predefined information
self.createRelation()
else:
# lets update existing relation
self.updateRelation()
# close addRelation dialog
self.close()
#load features' relations info into dockWidget again
if self.dockWidget.feature:
self.dockWidget.reloadFeatureRelations()
def stornoDialog(self):
"""Function just cancels the whole dialog.
It is called after clicked() signal is emitted on "Storno" button.
"""
# close addRelation dialog
self.close()
def __onTagsItemDoubleClicked(self,item):
"""Function is called after itemDoubleClicked(...) signal is emitted on table of relation tags.
It shows combobox with possible values for given item of table.
@param item item of table of relation tags
"""
if item.column()==0:
return
if self.relTagsEditIndex<>None:
row=self.relTagsEditIndex
if row<>-1:
value=self.relTagsTable.cellWidget(row,1).currentText()
self.relTagsTable.item(row,1).setText(value)
self.relTagsTable.removeCellWidget(row,1)
tagValues = self.determineSuitableTagValues(self.typeCombo.currentText(),self.relTagsTable.item(item.row(),0).text())
if len(tagValues)>0:
valCombo=QComboBox()
valCombo.setEditable(True)
valCombo.addItem("")
valCombo.addItems(tagValues)
ix=valCombo.findText(self.relTagsTable.item(item.row(),1).text())
valCombo.setCurrentIndex(ix)
self.relTagsTable.setCellWidget(item.row(),1,valCombo)
self.relTagsEditIndex=item.row()
QObject.connect(valCombo, SIGNAL("currentIndexChanged(const QString &)"), self.__onValueSelectionChanged)
def __onMembersItemDoubleClicked(self,item):
"""Function is called after itemDoubleClicked(...) signal is emitted on table of relation members.
It shows combobox with possible values for given item of table.
@param item item of table of relation members
"""
if (item.column()==0) or (item.row()==self.relMembersTable.rowCount()-1):
return
if item.column()==2:
if self.relMembersRoleEditIndex<>None:
row=self.relMembersRoleEditIndex
if row<>-1:
role=self.relMembersTable.cellWidget(row,2).currentText()
self.relMembersTable.item(row,2).setText(role)
self.relMembersTable.removeCellWidget(row,2)
memberRoles = self.determineSuitableMemberRoles(self.typeCombo.currentText())
if len(memberRoles)>0:
rolesCombo=QComboBox()
rolesCombo.setEditable(True)
rolesCombo.addItem("")
rolesCombo.addItems(memberRoles)
ix=rolesCombo.findText(self.relMembersTable.item(item.row(),1).text())
rolesCombo.setCurrentIndex(ix)
self.relMembersTable.setCellWidget(item.row(),2,rolesCombo)
self.relMembersRoleEditIndex=item.row()
QObject.connect(rolesCombo, SIGNAL("currentIndexChanged(const QString &)"), self.__onRoleSelectionChanged)
elif item.column()==1:
if self.relMembersTypeEditIndex<>None:
row=self.relMembersTypeEditIndex
if row<>-1:
memType=self.relMembersTable.cellWidget(row,1).currentText()
self.relMembersTable.item(row,1).setText(memType)
self.relMembersTable.removeCellWidget(row,1)
memberTypes=["Point","Line","Polygon","Relation"]
memTypesCombo=QComboBox()
memTypesCombo.setEditable(True)
memTypesCombo.addItem("")
memTypesCombo.addItems(memberTypes)
ix=memTypesCombo.findText(self.relMembersTable.item(item.row(),1).text())
memTypesCombo.setCurrentIndex(ix)
self.relMembersTable.setCellWidget(item.row(),1,memTypesCombo)
self.relMembersTypeEditIndex=item.row()
QObject.connect(memTypesCombo, SIGNAL("currentIndexChanged(const QString &)"), self.__onMemTypeSelectionChanged)
def __onValueSelectionChanged(self,value):
"""Function is called after currentIndexChanged(...) signal is emitted on combobox of table item.
This combobox is related to table of relation tags (column Value).
@param value new current value in combobox
"""
row=self.relTagsEditIndex
self.relTagsTable.item(row,1).setText(value)
self.relTagsTable.removeCellWidget(row,1)
self.relTagsEditIndex=-1
def __onRoleSelectionChanged(self,role):
"""Function is called after currentIndexChanged(...) signal is emitted on combobox of table item.
This combobox is related to table of relation members (column Role).
@param role new current value in combobox
"""
row=self.relMembersRoleEditIndex
self.relMembersTable.item(row,2).setText(role)
self.relMembersTable.removeCellWidget(row,2)
self.relMembersRoleEditIndex=-1
def __onMemTypeSelectionChanged(self,memType):
"""Function is called after currentIndexChanged(...) signal is emitted on combobox of table item.
This combobox is related to table of relation members (column Type).
@param memType new current value in combobox
"""
row=self.relMembersTypeEditIndex
self.relMembersTable.item(row,1).setText(memType)
self.relMembersTable.removeCellWidget(row,1)
self.relMembersTypeEditIndex=-1
def __showTypeInfo(self):
"""Function shows messagebox with brief information on currently selected relation type.
"""
typeName = self.typeCombo.currentText()
info = ""
if typeName=="boundary":
info = "for grouping boundaries and marking enclaves / exclaves"
elif typeName=="multipolygon":
info = "to put holes into areas (might have to be renamed, see article)"
elif typeName=="restriction":
info = "any kind of turn restriction"
elif typeName=="route":
info = "like bus routes, cycle routes and numbered highways"
elif typeName=="enforcement":
info = "traffic enforcement devices; speed cameras, redlight cameras, weight checks, ..."
QMessageBox.information(self, self.tr("OSM Information")
,self.tr(info))

View File

@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgAddRelation.ui'
#
# Created: Tue Jul 14 14:44:27 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgAddRelation(object):
def setupUi(self, DlgAddRelation):
DlgAddRelation.setObjectName("DlgAddRelation")
DlgAddRelation.resize(620, 461)
DlgAddRelation.setModal(False)
self.vboxlayout = QtGui.QVBoxLayout(DlgAddRelation)
self.vboxlayout.setObjectName("vboxlayout")
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.label = QtGui.QLabel(DlgAddRelation)
self.label.setObjectName("label")
self.hboxlayout.addWidget(self.label)
spacerItem = QtGui.QSpacerItem(24, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem)
self.typeCombo = QtGui.QComboBox(DlgAddRelation)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.typeCombo.sizePolicy().hasHeightForWidth())
self.typeCombo.setSizePolicy(sizePolicy)
self.typeCombo.setMinimumSize(QtCore.QSize(164, 24))
self.typeCombo.setMaximumSize(QtCore.QSize(164, 16777215))
self.typeCombo.setEditable(True)
self.typeCombo.setObjectName("typeCombo")
self.hboxlayout.addWidget(self.typeCombo)
self.typeInfoButton = QtGui.QToolButton(DlgAddRelation)
self.typeInfoButton.setObjectName("typeInfoButton")
self.hboxlayout.addWidget(self.typeInfoButton)
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem1)
self.vboxlayout.addLayout(self.hboxlayout)
self.hboxlayout1 = QtGui.QHBoxLayout()
self.hboxlayout1.setObjectName("hboxlayout1")
self.vboxlayout1 = QtGui.QVBoxLayout()
self.vboxlayout1.setObjectName("vboxlayout1")
self.hboxlayout2 = QtGui.QHBoxLayout()
self.hboxlayout2.setObjectName("hboxlayout2")
self.label_2 = QtGui.QLabel(DlgAddRelation)
self.label_2.setObjectName("label_2")
self.hboxlayout2.addWidget(self.label_2)
spacerItem2 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout2.addItem(spacerItem2)
self.loadStandardTagsButton = QtGui.QToolButton(DlgAddRelation)
self.loadStandardTagsButton.setObjectName("loadStandardTagsButton")
self.hboxlayout2.addWidget(self.loadStandardTagsButton)
self.removeTagButton = QtGui.QToolButton(DlgAddRelation)
self.removeTagButton.setObjectName("removeTagButton")
self.hboxlayout2.addWidget(self.removeTagButton)
self.vboxlayout1.addLayout(self.hboxlayout2)
self.relTagsTable = QtGui.QTableWidget(DlgAddRelation)
self.relTagsTable.setMinimumSize(QtCore.QSize(240, 0))
self.relTagsTable.setObjectName("relTagsTable")
self.relTagsTable.setColumnCount(0)
self.relTagsTable.setRowCount(0)
self.vboxlayout1.addWidget(self.relTagsTable)
self.hboxlayout1.addLayout(self.vboxlayout1)
self.vboxlayout2 = QtGui.QVBoxLayout()
self.vboxlayout2.setObjectName("vboxlayout2")
self.hboxlayout3 = QtGui.QHBoxLayout()
self.hboxlayout3.setObjectName("hboxlayout3")
self.label_5 = QtGui.QLabel(DlgAddRelation)
self.label_5.setObjectName("label_5")
self.hboxlayout3.addWidget(self.label_5)
spacerItem3 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout3.addItem(spacerItem3)
self.chooseMemberButton = QtGui.QToolButton(DlgAddRelation)
self.chooseMemberButton.setCheckable(True)
self.chooseMemberButton.setObjectName("chooseMemberButton")
self.hboxlayout3.addWidget(self.chooseMemberButton)
self.removeMemberButton = QtGui.QToolButton(DlgAddRelation)
self.removeMemberButton.setObjectName("removeMemberButton")
self.hboxlayout3.addWidget(self.removeMemberButton)
self.vboxlayout2.addLayout(self.hboxlayout3)
self.relMembersTable = QtGui.QTableWidget(DlgAddRelation)
self.relMembersTable.setMinimumSize(QtCore.QSize(346, 0))
self.relMembersTable.setObjectName("relMembersTable")
self.relMembersTable.setColumnCount(0)
self.relMembersTable.setRowCount(0)
self.vboxlayout2.addWidget(self.relMembersTable)
self.tagInfoTextEdit = QtGui.QTextEdit(DlgAddRelation)
self.tagInfoTextEdit.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.tagInfoTextEdit.sizePolicy().hasHeightForWidth())
self.tagInfoTextEdit.setSizePolicy(sizePolicy)
self.tagInfoTextEdit.setMaximumSize(QtCore.QSize(16777215, 140))
self.tagInfoTextEdit.setReadOnly(True)
self.tagInfoTextEdit.setObjectName("tagInfoTextEdit")
self.vboxlayout2.addWidget(self.tagInfoTextEdit)
self.hboxlayout1.addLayout(self.vboxlayout2)
self.vboxlayout.addLayout(self.hboxlayout1)
self.hboxlayout4 = QtGui.QHBoxLayout()
self.hboxlayout4.setObjectName("hboxlayout4")
spacerItem4 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout4.addItem(spacerItem4)
self.createRelButton = QtGui.QPushButton(DlgAddRelation)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.createRelButton.sizePolicy().hasHeightForWidth())
self.createRelButton.setSizePolicy(sizePolicy)
self.createRelButton.setMinimumSize(QtCore.QSize(0, 30))
self.createRelButton.setAutoDefault(False)
self.createRelButton.setObjectName("createRelButton")
self.hboxlayout4.addWidget(self.createRelButton)
self.stornoButton = QtGui.QPushButton(DlgAddRelation)
self.stornoButton.setMinimumSize(QtCore.QSize(0, 30))
self.stornoButton.setAutoDefault(False)
self.stornoButton.setObjectName("stornoButton")
self.hboxlayout4.addWidget(self.stornoButton)
self.vboxlayout.addLayout(self.hboxlayout4)
self.retranslateUi(DlgAddRelation)
QtCore.QMetaObject.connectSlotsByName(DlgAddRelation)
def retranslateUi(self, DlgAddRelation):
DlgAddRelation.setWindowTitle(QtGui.QApplication.translate("DlgAddRelation", "Create OSM relation", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgAddRelation", "Relation type:", None, QtGui.QApplication.UnicodeUTF8))
self.typeInfoButton.setText(QtGui.QApplication.translate("DlgAddRelation", "...", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgAddRelation", "Properties", None, QtGui.QApplication.UnicodeUTF8))
self.loadStandardTagsButton.setText(QtGui.QApplication.translate("DlgAddRelation", "...", None, QtGui.QApplication.UnicodeUTF8))
self.removeTagButton.setText(QtGui.QApplication.translate("DlgAddRelation", "...", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("DlgAddRelation", "Members", None, QtGui.QApplication.UnicodeUTF8))
self.chooseMemberButton.setText(QtGui.QApplication.translate("DlgAddRelation", "...", None, QtGui.QApplication.UnicodeUTF8))
self.removeMemberButton.setText(QtGui.QApplication.translate("DlgAddRelation", "...", None, QtGui.QApplication.UnicodeUTF8))
self.createRelButton.setText(QtGui.QApplication.translate("DlgAddRelation", "Create", None, QtGui.QApplication.UnicodeUTF8))
self.stornoButton.setText(QtGui.QApplication.translate("DlgAddRelation", "Storno", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,491 @@
"""@package DlgDownloadOSM
Module provides simple way how to download OSM data.
First user is asked to choose download region, output file etc.
Then HTTP connection to OpenStreetMap server is created and download operation is started.
Note that OpenStreetMap server you are downloading OSM data from (~api.openstreetmap.org)
has fixed limitations of how much data you can get. As written on wiki.openstreetmap.org
neighter latitude nor longitude extent of downloaded region can be larger than 0.25 degree.
Each error response from OSM server is caught by OSM Plugin and display to its user.
"""
from DlgDownloadOSM_ui import Ui_DlgDownloadOSM
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
from PyQt4 import *
from time import *
from qgis.core import *
class DlgDownloadOSM(QDialog, Ui_DlgDownloadOSM):
"""This is the main class of this module.
It's direct descendant of "OSM Download" dialog.
It provides simple way how to download OSM data.
First user is asked to choose download region, output file etc.
Then HTTP connection to OpenStreetMap server is created and download operation is started.
Note that OpenStreetMap server you are downloading OSM data from (~api.openstreetmap.org)
has fixed limitations of how much data you can get. As written on wiki.openstreetmap.org
neighter latitude nor longitude extent of downloaded region can be larger than 0.25 degree.
Each error response from OSM server is caught by OSM Plugin and display to its user.
"""
def __init__(self, plugin):
"""The constructor.
Performs initialization of OSM Download dialog and inner structures.
Default download region is set according to current canvas extent.
@param plugin is pointer to instance of OSM Plugin.
"""
QDialog.__init__(self, None)
self.setupUi(self)
self.dbm=plugin.dbm
self.urlHost="api.openstreetmap.org"
self.urlPathPrefix="/api/0.6/map?bbox="
self.downloadButton.setDefault(True)
self.downloadButton.setEnabled(False)
# determining default area for download
currentExtent=plugin.canvas.extent()
# check whether the extent needs to be projected back to WGS84
mapRenderer = plugin.canvas.mapRenderer()
if mapRenderer.hasCrsTransformEnabled():
crsMap=mapRenderer.destinationSrs()
crsWgs84=QgsCoordinateReferenceSystem(4326)
xform=QgsCoordinateTransform(crsMap, crsWgs84)
currentExtent=xform.transformBoundingBox(currentExtent)
self.latFromLineEdit.setText(QString("%1").arg(currentExtent.yMinimum(),0,'f',10))
self.latToLineEdit.setText(QString("%1").arg(currentExtent.yMaximum(),0,'f',10))
self.lonFromLineEdit.setText(QString("%1").arg(currentExtent.xMinimum(),0,'f',10))
self.lonToLineEdit.setText(QString("%1").arg(currentExtent.xMaximum(),0,'f',10))
# create object for http connection
self.outFile=None
self.httpGetId=0
self.httpSuccess=False
self.errMessage=None
self.finished=False
self.responseHeader=""
# connect all important signals to slots
self.connectDlgSignals()
self.helpButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_questionMark.png"))
# set special font for extentInfoLabel
myFont = self.extentInfoLabel.font()
myFont.setPointSize( myFont.pointSize()+1 )
myFont.setBold(True)
self.extentInfoLabel.setFont(myFont)
# generating default name for output file
defaultFileName=self.generateDefFileName()
self.destdirLineEdit.setText(defaultFileName)
self.destdirLineEdit.setEnabled(True)
self.downloadButton.setEnabled(True)
# check default extent
self.checkExtent()
# load default values to combobox determining style for custom renderer
self.styles=["Small scale","Medium scale","Large scale"]
self.styleCombo.addItems(self.styles)
# just determine if "replace data" checkbox should be checked
if not plugin.dbm.currentKey:
self.chkReplaceData.setEnabled(False)
def downloadFile(self):
"""Function starts thw whole download process.
It's called after click() signal is emitted on Download button.
"""
if self.finished:
return
self.downloadButton.setEnabled(False)
self.disconnectDlgSignals()
# finding out which area should be downloaded, and to where
urlPath = self.urlPathPrefix + self.lonFromLineEdit.text() + "," + self.latFromLineEdit.text() + "," + self.lonToLineEdit.text() + "," + self.latToLineEdit.text()
fileName = self.destdirLineEdit.text()
# remove the old database file
if QFile.exists(fileName+".db"):
QFile.remove(fileName+".db")
self.outFile=QFile(fileName)
if not self.outFile.open(QIODevice.WriteOnly):
QMessageBox.information(self, self.tr("OSM Download"),
self.tr("Unable to save the file %1: %2.")
.arg(fileName).arg(self.outFile.errorString()))
self.outFile = None
return
# creating progress dialog for download
self.progressDialog=QProgressDialog(self)
# !!! don't set progress dialog modal !!! it would cause serious problems!
self.progressDialog.setAutoClose(False)
self.progressDialog.setWindowTitle(self.tr("OSM Download"))
self.connect(self.progressDialog,SIGNAL("canceled()"), self.progressDlgCanceled)
self.setEnabled(False)
self.progressDialog.setEnabled(True)
self.progressDialog.show()
self.progressDialog.setLabelText(self.tr("Waiting for OpenStreetMap server ..."))
self.progressDialog.setMaximum(1)
self.progressDialog.setValue(0)
# create object for http connection
self.http=QHttp(self)
# catching http signals!
self.connect(self.http,SIGNAL("requestFinished(int, bool)"), self.httpRequestFinished)
self.connect(self.http,SIGNAL("dataReadProgress(int, int)"), self.updateDataReadProgress)
self.connect(self.http,SIGNAL("responseHeaderReceived(QHttpResponseHeader)"), self.readResponseHeader)
self.connect(self.http,SIGNAL("stateChanged(int)"), self.stateChanged)
self.connect(self.http,SIGNAL("done(bool)"), self.httpDone)
self.setProxy()
self.http.setHost(self.urlHost, 80)
self.httpGetId=self.http.get(urlPath, self.outFile)
def httpRequestFinished(self, requestId, error):
"""Function is called when requestFinished(...) signal is emitted
on global HTTP connection object.
@param requestId identifier of http request that was finished
@param error True if error occured on given request; False otherwise
"""
if self.finished:
return
def readResponseHeader(self, responseHeader):
"""Function is called when responseHeaderReceived(...) signal is emitted
on global HTTP connection object.
If statusCode of responseHeader doesn't equal to 200, function cancels the whole connection.
@param responseHeader header of HTTP response from the OSM server
"""
if self.finished:
return
if responseHeader.statusCode() != 200:
self.cancelDownload(self.tr("Download process failed. OpenStreetMap server response: %1 - %2")
.arg(responseHeader.reasonPhrase())
.arg(responseHeader.value("Error")))
def updateDataReadProgress(self, bytesRead, totalBytes):
"""Function is called after dataReadProgress(...) signal is emitted on global HTTP connection object.
It updates progress dialog.
@param bytesRead total number of bytes that has been already read through the HTTP connection
@param totalBytes total number of bytes that will be received through HTTP connection
"""
if self.finished:
return
# note that progress dialog mustn't be modal!
self.progressDialog.setMaximum(totalBytes)
self.progressDialog.setValue(bytesRead)
def stateChanged(self,newState):
"""Function is called after stateChanged(...) signal is emitted on HTTP connection.
OSM Downloader does actully nothing in here.
Maybe in future function will be used.
@param newState number representing new state of the connection
"""
if self.finished:
return
def httpDone(self,error):
"""Function is called after done(...) signal is emitted on HTTP connection.
(Done signal is emitted immediatelly after all requests of HTTP connection
are finished ~ emits an requestFinished(...) signal).
@param error True if error occured on any of HTTP connection requests; False otherwise
"""
if self.finished:
return
self.finished=True
self.outFile.flush()
self.outFile.close()
# we are no more interested in signals emitted on QHttp object
self.disconnect(self.http,SIGNAL("done(bool)"), self.httpDone)
self.disconnect(self.http,SIGNAL("requestFinished(int, bool)"), self.httpRequestFinished)
self.disconnect(self.http,SIGNAL("dataReadProgress(int, int)"), self.updateDataReadProgress)
self.disconnect(self.http,SIGNAL("responseHeaderReceived(QHttpResponseHeader)"), self.readResponseHeader)
self.disconnect(self.http,SIGNAL("stateChanged(int)"), self.stateChanged)
del self.http
self.http=None
# request was not aborted
if error:
self.httpSuccess=False
# remove output file
if self.outFile and self.outFile.exists():
self.outFile.remove()
del self.outFile
self.outFile=None
# and tell user
if self.errMessage==None:
self.errMessage="Check your internet connection"
QMessageBox.information(self, self.tr("OSM Download Error")
,self.tr("Download failed: %1.").arg(self.errMessage))
else:
self.httpSuccess=True
# well, download process has finished successfully;
# close progress dialog and the whole download dialog
self.progressDialog.close()
self.close()
def cancelDownload(self,errMessage=None):
"""Function aborts global HTTP connection.
It gets an error message and just store it into member variable.
It will be displayed to Quantum GIS user later after done(...) will be emitted.
@param errMessage error message ~ the reason why connection is canceled
"""
if self.finished:
return
self.errMessage=errMessage
# stop http communication
self.http.abort()
####################################################################################
############ NON-HTTP FUNCTIONS ####################################################
####################################################################################
def showChooseDirectoryDialog(self):
"""Function just shows dialog for directory selection.
Only OSM files can be selected.
"""
if self.finished:
return
# display file open dialog and get absolute path to selected directory
fileSelected = QFileDialog.getSaveFileName(self, "Choose file to save","download.osm", "OSM Files (*.osm)");
# insert selected directory path into line edit control
if not fileSelected.isNull():
self.destdirLineEdit.setText(fileSelected)
self.downloadButton.setEnabled(True)
def generateDefFileName(self):
"""This function creates default name for output file.
It's called mainly from downloader initialization.
Default name is always unique. It consist of current timestamp and a postfix.
"""
if self.finished:
return
prefix=QString("/tmp/")
if self.dbm.currentKey:
key=QString(self.dbm.currentKey)
p=key.lastIndexOf("/")
prefix=key.left(p+1)
timestring=strftime("%y%m%d_%H%M%S",localtime(time()))
return prefix.append(QString(timestring)).append("_downloaded.osm")
def autoLoadClicked(self):
"""Function is called after clicking on AutoLoad checkbox.
"""
if self.finished:
return
if not self.autoLoadCheckBox.isChecked():
self.chkCustomRenderer.setEnabled(False)
self.chkReplaceData.setEnabled(False)
else:
self.chkCustomRenderer.setEnabled(True)
self.chkReplaceData.setEnabled(True)
def showExtentHelp(self):
"""Function is called after clicking on Help button.
It shows basic information on downloading.
"""
if self.finished:
return
mb=QMessageBox()
mb.setMinimumWidth(390)
mb.information(self, self.tr("Getting data"),self.tr("The OpenStreetMap server you are downloading OSM data from (~ api.openstreetmap.org) has fixed limitations of how much data you can get. As written at <http://wiki.openstreetmap.org/wiki/Getting_Data> neighter latitude nor longitude extent of downloaded region can be larger than 0.25 degree. Note that Quantum GIS allows you to specify any extent you want, but OpenStreetMap server will reject all request that won't satisfy downloading limitations."))
def checkExtent(self):
"""Function checks if extent, currently set on dialog, is valid.
It's called whenever download region changed.
Result of checking is displayed on dialog.
"""
if self.finished:
return
lim = 0.25 # download limitations of openstreetmap server in degrees
# get coordinates that are currently set
latFrom = self.latFromLineEdit.text().toDouble()[0]
lonFrom = self.lonFromLineEdit.text().toDouble()[0]
latTo = self.latToLineEdit.text().toDouble()[0]
lonTo = self.lonToLineEdit.text().toDouble()[0]
# tested conditions
largeLatExt = False
largeLonExt = False
if abs(latTo-latFrom)>lim:
largeLatExt = True
if abs(lonTo-lonFrom)>lim:
largeLonExt = True
if largeLatExt and largeLonExt:
self.extentInfoLabel.setText(self.tr("Both extents are too large!"))
elif largeLatExt:
self.extentInfoLabel.setText(self.tr("Latitude extent is too large!"))
elif largeLonExt:
self.extentInfoLabel.setText(self.tr("Longitude extent is too large!"))
else:
self.extentInfoLabel.setText(self.tr("OK! Area is probably acceptable to server."))
def progressDlgCanceled(self):
"""Function is called after progress dialog is canceled.
It aborts HTTP connection.
"""
if self.finished:
return
# cancel download with no message for user
self.cancelDownload()
def setProxy(self):
"""Function sets proxy to HTTP connection of downloader.
HTTP connection object is not given in function parameter,
because it's global - accessible for the whole downloader.
"""
if self.finished:
return
# getting and setting proxy information
settings=QSettings()
proxyHost=QString()
proxyUser=QString()
proxyPassword=QString()
proxyPort=0
proxyType=QNetworkProxy.NoProxy
proxyEnabled=settings.value("proxy/proxyEnabled",QVariant(0)).toBool()
if proxyEnabled:
proxyHost=settings.value("proxy/proxyHost",QVariant("")).toString()
proxyPort=settings.value("proxy/proxyPort",QVariant(8080)).toInt()[0]
proxyUser=settings.value("proxy/proxyUser",QVariant("")).toString()
proxyPassword=settings.value("proxy/proxyPassword",QVariant("")).toString()
proxyTypeString=settings.value("proxy/proxyType",QVariant("")).toString()
if proxyTypeString=="DefaultProxy":
proxyType=QNetworkProxy.DefaultProxy
elif proxyTypeString=="Socks5Proxy":
proxyType=QNetworkProxy.Socks5Proxy
elif proxyTypeString=="HttpProxy":
proxyType=QNetworkProxy.HttpProxy
elif proxyTypeString=="HttpCachingProxy":
proxyType=QNetworkProxy.HttpCachingProxy
elif proxyTypeString=="FtpCachingProxy":
proxyType=QNetworkProxy.FtpCachingProxy
self.proxy=QNetworkProxy()
self.proxy.setType(proxyType)
self.proxy.setHostName(proxyHost)
self.proxy.setPort(proxyPort)
self.http.setProxy(self.proxy)
def connectDlgSignals(self):
"""Function connects neccessary signals to appropriate slots.
"""
# whenever extent coordinates are changed, currently set extent has to be tested for validity
# (coz openstreetmap has some limitations for how large area and how much data can be downloaded at once)
self.connect(self.latFromLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.connect(self.latToLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.connect(self.lonFromLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.connect(self.lonToLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.connect(self.helpButton, SIGNAL("clicked()"), self.showExtentHelp)
self.connect(self.downloadButton, SIGNAL("clicked()"), self.downloadFile)
self.connect(self.cancelButton, SIGNAL("clicked()"), self.close)
self.connect(self.choosedirButton, SIGNAL("clicked()"), self.showChooseDirectoryDialog)
self.connect(self.autoLoadCheckBox, SIGNAL("clicked()"), self.autoLoadClicked)
def disconnectDlgSignals(self):
"""Function disconnects connected signals.
"""
self.disconnect(self.latFromLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.disconnect(self.latToLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.disconnect(self.lonFromLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.disconnect(self.lonToLineEdit, SIGNAL("textChanged(const QString &)"), self.checkExtent)
self.disconnect(self.helpButton, SIGNAL("clicked()"), self.showExtentHelp)
self.disconnect(self.downloadButton, SIGNAL("clicked()"), self.downloadFile)
self.disconnect(self.choosedirButton, SIGNAL("clicked()"), self.showChooseDirectoryDialog)
self.disconnect(self.autoLoadCheckBox, SIGNAL("clicked()"), self.autoLoadClicked)

View File

@ -0,0 +1,162 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgDownloadOSM.ui'
#
# Created: Fri Jul 10 15:27:30 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgDownloadOSM(object):
def setupUi(self, DlgDownloadOSM):
DlgDownloadOSM.setObjectName("DlgDownloadOSM")
DlgDownloadOSM.setWindowModality(QtCore.Qt.ApplicationModal)
DlgDownloadOSM.resize(595, 357)
DlgDownloadOSM.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
DlgDownloadOSM.setModal(True)
self.vboxlayout = QtGui.QVBoxLayout(DlgDownloadOSM)
self.vboxlayout.setObjectName("vboxlayout")
self.groupBox = QtGui.QGroupBox(DlgDownloadOSM)
self.groupBox.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.groupBox.setObjectName("groupBox")
self.vboxlayout1 = QtGui.QVBoxLayout(self.groupBox)
self.vboxlayout1.setObjectName("vboxlayout1")
self.gridlayout = QtGui.QGridLayout()
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(self.groupBox)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label, 0, 1, 1, 1)
self.label_4 = QtGui.QLabel(self.groupBox)
self.label_4.setObjectName("label_4")
self.gridlayout.addWidget(self.label_4, 0, 2, 1, 1)
self.latFromLineEdit = QtGui.QLineEdit(self.groupBox)
self.latFromLineEdit.setEnabled(True)
self.latFromLineEdit.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.latFromLineEdit.setObjectName("latFromLineEdit")
self.gridlayout.addWidget(self.latFromLineEdit, 0, 3, 1, 1)
self.label_6 = QtGui.QLabel(self.groupBox)
self.label_6.setObjectName("label_6")
self.gridlayout.addWidget(self.label_6, 0, 4, 1, 1)
self.latToLineEdit = QtGui.QLineEdit(self.groupBox)
self.latToLineEdit.setEnabled(True)
self.latToLineEdit.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.latToLineEdit.setObjectName("latToLineEdit")
self.gridlayout.addWidget(self.latToLineEdit, 0, 5, 1, 1)
self.label_2 = QtGui.QLabel(self.groupBox)
self.label_2.setObjectName("label_2")
self.gridlayout.addWidget(self.label_2, 1, 1, 1, 1)
self.label_5 = QtGui.QLabel(self.groupBox)
self.label_5.setObjectName("label_5")
self.gridlayout.addWidget(self.label_5, 1, 2, 1, 1)
self.lonFromLineEdit = QtGui.QLineEdit(self.groupBox)
self.lonFromLineEdit.setEnabled(True)
self.lonFromLineEdit.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.lonFromLineEdit.setObjectName("lonFromLineEdit")
self.gridlayout.addWidget(self.lonFromLineEdit, 1, 3, 1, 1)
self.label_7 = QtGui.QLabel(self.groupBox)
self.label_7.setObjectName("label_7")
self.gridlayout.addWidget(self.label_7, 1, 4, 1, 1)
self.lonToLineEdit = QtGui.QLineEdit(self.groupBox)
self.lonToLineEdit.setEnabled(True)
self.lonToLineEdit.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.lonToLineEdit.setObjectName("lonToLineEdit")
self.gridlayout.addWidget(self.lonToLineEdit, 1, 5, 1, 1)
self.vboxlayout1.addLayout(self.gridlayout)
spacerItem = QtGui.QSpacerItem(20, 8, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
self.vboxlayout1.addItem(spacerItem)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
spacerItem1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem1)
self.extentInfoLabel = QtGui.QLabel(self.groupBox)
self.extentInfoLabel.setMargin(0)
self.extentInfoLabel.setObjectName("extentInfoLabel")
self.hboxlayout.addWidget(self.extentInfoLabel)
self.helpButton = QtGui.QToolButton(self.groupBox)
self.helpButton.setMaximumSize(QtCore.QSize(23, 23))
self.helpButton.setObjectName("helpButton")
self.hboxlayout.addWidget(self.helpButton)
self.vboxlayout1.addLayout(self.hboxlayout)
self.vboxlayout.addWidget(self.groupBox)
self.gridlayout1 = QtGui.QGridLayout()
self.gridlayout1.setObjectName("gridlayout1")
self.label_9 = QtGui.QLabel(DlgDownloadOSM)
self.label_9.setObjectName("label_9")
self.gridlayout1.addWidget(self.label_9, 0, 0, 1, 2)
self.destdirLineEdit = QtGui.QLineEdit(DlgDownloadOSM)
self.destdirLineEdit.setEnabled(False)
self.destdirLineEdit.setObjectName("destdirLineEdit")
self.gridlayout1.addWidget(self.destdirLineEdit, 1, 0, 1, 1)
self.choosedirButton = QtGui.QPushButton(DlgDownloadOSM)
self.choosedirButton.setObjectName("choosedirButton")
self.gridlayout1.addWidget(self.choosedirButton, 1, 1, 1, 1)
self.vboxlayout.addLayout(self.gridlayout1)
self.autoLoadCheckBox = QtGui.QCheckBox(DlgDownloadOSM)
self.autoLoadCheckBox.setChecked(True)
self.autoLoadCheckBox.setObjectName("autoLoadCheckBox")
self.vboxlayout.addWidget(self.autoLoadCheckBox)
self.hboxlayout1 = QtGui.QHBoxLayout()
self.hboxlayout1.setObjectName("hboxlayout1")
spacerItem2 = QtGui.QSpacerItem(15, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.hboxlayout1.addItem(spacerItem2)
self.chkReplaceData = QtGui.QCheckBox(DlgDownloadOSM)
self.chkReplaceData.setChecked(False)
self.chkReplaceData.setObjectName("chkReplaceData")
self.hboxlayout1.addWidget(self.chkReplaceData)
self.vboxlayout.addLayout(self.hboxlayout1)
self.hboxlayout2 = QtGui.QHBoxLayout()
self.hboxlayout2.setSpacing(0)
self.hboxlayout2.setContentsMargins(-1, 0, -1, -1)
self.hboxlayout2.setObjectName("hboxlayout2")
spacerItem3 = QtGui.QSpacerItem(15, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.hboxlayout2.addItem(spacerItem3)
self.chkCustomRenderer = QtGui.QCheckBox(DlgDownloadOSM)
self.chkCustomRenderer.setChecked(True)
self.chkCustomRenderer.setObjectName("chkCustomRenderer")
self.hboxlayout2.addWidget(self.chkCustomRenderer)
spacerItem4 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.hboxlayout2.addItem(spacerItem4)
self.styleCombo = QtGui.QComboBox(DlgDownloadOSM)
self.styleCombo.setMinimumSize(QtCore.QSize(182, 0))
self.styleCombo.setMaximumSize(QtCore.QSize(182, 16777215))
self.styleCombo.setObjectName("styleCombo")
self.hboxlayout2.addWidget(self.styleCombo)
spacerItem5 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout2.addItem(spacerItem5)
self.vboxlayout.addLayout(self.hboxlayout2)
self.hboxlayout3 = QtGui.QHBoxLayout()
self.hboxlayout3.setObjectName("hboxlayout3")
spacerItem6 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout3.addItem(spacerItem6)
self.downloadButton = QtGui.QPushButton(DlgDownloadOSM)
self.downloadButton.setObjectName("downloadButton")
self.hboxlayout3.addWidget(self.downloadButton)
self.cancelButton = QtGui.QPushButton(DlgDownloadOSM)
self.cancelButton.setObjectName("cancelButton")
self.hboxlayout3.addWidget(self.cancelButton)
self.vboxlayout.addLayout(self.hboxlayout3)
self.retranslateUi(DlgDownloadOSM)
QtCore.QMetaObject.connectSlotsByName(DlgDownloadOSM)
def retranslateUi(self, DlgDownloadOSM):
DlgDownloadOSM.setWindowTitle(QtGui.QApplication.translate("DlgDownloadOSM", "Download OSM data", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("DlgDownloadOSM", "Extent", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Latitude:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("DlgDownloadOSM", " From", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("DlgDownloadOSM", "To", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Longitude:", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("DlgDownloadOSM", " From", None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate("DlgDownloadOSM", "To", None, QtGui.QApplication.UnicodeUTF8))
self.extentInfoLabel.setText(QtGui.QApplication.translate("DlgDownloadOSM", "<nothing>", None, QtGui.QApplication.UnicodeUTF8))
self.helpButton.setText(QtGui.QApplication.translate("DlgDownloadOSM", "...", None, QtGui.QApplication.UnicodeUTF8))
self.label_9.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Download to:", None, QtGui.QApplication.UnicodeUTF8))
self.choosedirButton.setText(QtGui.QApplication.translate("DlgDownloadOSM", "...", None, QtGui.QApplication.UnicodeUTF8))
self.autoLoadCheckBox.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Open data automatically after download", None, QtGui.QApplication.UnicodeUTF8))
self.chkReplaceData.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Replace current data (current layer will be removed)", None, QtGui.QApplication.UnicodeUTF8))
self.chkCustomRenderer.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Use custom renderer", None, QtGui.QApplication.UnicodeUTF8))
self.downloadButton.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Download", None, QtGui.QApplication.UnicodeUTF8))
self.cancelButton.setText(QtGui.QApplication.translate("DlgDownloadOSM", "Cancel", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,252 @@
# -*- coding: utf-8 -*-
"""@package DlgImport
This module is used to import OSM data from standard QGIS vector layer.
"""
from DlgImport_ui import Ui_DlgImport
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
class dummyPoint:
"""A wrapper around QgsPoint which adds hash calculation.
"""
def __init__(self, pt):
"""The constructor."""
self.pt = pt
def __hash__(self):
return int(self.pt.x()*230783 + self.pt.y()*680091)
def __eq__(self, other):
return self.pt.x() == other.pt.x() and self.pt.y() == other.pt.y()
class dummyFeat:
"""A dummy QgsFeature that just returns its feature id.
"""
def __init__(self, fid):
"""The constructor."""
self.fid = fid
def id(self):
return self.fid
class DlgImport(QDialog, Ui_DlgImport):
"""This class provides structures and methods neccessary for import OSM data.
Class is direct descendant of OSM Import dialog.
After confirming OSM Import dialog process is immediately 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.dbm = plugin.dbm
self.affected=set()
self.populateLayers()
QObject.connect(self.buttonBox,SIGNAL("accepted()"),self.onOK)
QObject.connect(self.cboLayer,SIGNAL("currentIndexChanged(int)"), self.updateUi)
if self.cboLayer.count() > 0:
self.updateUi(0)
def updateUi(self, index):
"""Function checks whether there is any selection in the layer.
"""
layerId = self.cboLayer.itemData(index).toString()
layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
if layer is None or len(layer.selectedFeaturesIds()) == 0:
self.chkOnlySelection.setChecked(False)
self.chkOnlySelection.setEnabled(False)
def populateLayers(self):
"""Funtion populates layers.
"""
self.cboLayer.clear()
layers = QgsMapLayerRegistry.instance().mapLayers()
for lyrId,lyr in layers.iteritems():
if lyr.type() == QgsMapLayer.VectorLayer and lyr.dataProvider().name() != "osm":
self.cboLayer.addItem(lyr.name(), QVariant(lyrId) )
def onOK(self):
"""Function does OSM data importing.
"""
layerId = self.cboLayer.itemData(self.cboLayer.currentIndex()).toString()
onlySel = self.chkOnlySelection.isChecked()
layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
if layer is None:
QMessageBox.warning(self, "Layer doesn't exist", "The selected layer doesn't exist anymore!")
return
self.progress = QProgressDialog("Importing features...", "Cancel", 0, 100, self)
self.progress.setWindowModality(Qt.WindowModal)
self.nodes = { }
if onlySel:
# only selected features
features = layer.selectedFeatures()
count = len(features)
self.progress.setMaximum(count)
for f in features:
if not self.updateProgress():
break
self.addFeature(f)
else:
# all features from layer
count = layer.featureCount()
self.progress.setMaximum(count)
layer.select()
f = QgsFeature()
while layer.nextFeature(f):
if not self.updateProgress():
break
self.addFeature(f)
self.dbm.commit()
self.progress.setValue(count)
self.dbm.recacheAffectedNow(self.affected)
self.plugin.canvas.refresh()
QMessageBox.information(self, "Import", "Import has been completed.")
self.accept()
def updateProgress(self):
"""Function updates progress dialog.
"""
self.progress.setValue( self.progress.value()+1 )
return not self.progress.wasCanceled()
def addFeature(self,f):
"""Function adds given feature.
@param f feature to be added
"""
g = f.geometry()
if g is None:
return
wkbType = g.wkbType()
if wkbType == QGis.WKBPoint:
self.extractPoint(g.asPoint())
elif wkbType == QGis.WKBLineString:
self.extractLineString(g.asPolyline())
elif wkbType == QGis.WKBPolygon:
self.extractPolygon(g.asPolygon())
elif wkbType == QGis.WKBMultiPoint:
for pnt in g.asMultiPoint():
self.extractPoint(pnt)
elif wkbType == QGis.WKBMultiLineString:
for line in g.asMultiPolyline():
self.extractLineString(line)
elif wkbType == QGis.WKBMultiPolygon:
for polygon in g.asMultiPolygon():
self.extractPolygon(polygon)
def extractPoint(self, pnt):
"""Function extracts a point.
@param pnt point to extract
"""
# TODO: check that another point isn't already at the same position
(node,affected)=self.dbm.createPoint(pnt, None, None, False)
self.affected.update(affected)
def snapPoint(self, pnt):
""" Function checks whether there's already other point with the same position.
If so, it pretends it got snapped to that point.
@param pnt point to snap
"""
dp = dummyPoint(pnt)
if dp in self.nodes:
return (pnt, self.nodes[dp], 'Point')
else:
return (pnt,None,None)
def extractLineString(self, line):
"""Function extracts a line.
@param line line to extract
"""
points = map(self.snapPoint, line)
(feat,affected) = self.dbm.createLine(points, False)
self.affected.update(affected)
# this is a hack that uses the knowledge of inner working of createLine.
# that sucks.
nodeId = feat.id()-1
for p in points:
if p[1] is None:
dp = dummyPoint(p[0])
self.nodes[dp] = dummyFeat(nodeId)
nodeId -= 1
def extractPolygon(self, polygon):
"""Function extracts a polygon.
@param polygon polygon to extract
"""
# TODO: do something with holes?
points=map(self.snapPoint, polygon[0])
if len(points)>0:
points.pop()
(feat,affected)=self.dbm.createPolygon(points, False)
self.affected.update(affected)
# this is a hack that uses the knowledge of inner working of createPolygon.
# that sucks.
nodeId = feat.id()-1
for p in points:
if p[1] is None:
dp = dummyPoint(p[0])
self.nodes[dp] = dummyFeat(nodeId)
nodeId -= 1

View File

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgImport.ui'
#
# Created: Tue Jul 14 14:44:27 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgImport(object):
def setupUi(self, DlgImport):
DlgImport.setObjectName("DlgImport")
DlgImport.setWindowModality(QtCore.Qt.ApplicationModal)
DlgImport.resize(248, 228)
DlgImport.setModal(True)
self.vboxlayout = QtGui.QVBoxLayout(DlgImport)
self.vboxlayout.setObjectName("vboxlayout")
self.label = QtGui.QLabel(DlgImport)
self.label.setWordWrap(True)
self.label.setObjectName("label")
self.vboxlayout.addWidget(self.label)
spacerItem = QtGui.QSpacerItem(20, 29, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.vboxlayout.addItem(spacerItem)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.label_2 = QtGui.QLabel(DlgImport)
self.label_2.setObjectName("label_2")
self.hboxlayout.addWidget(self.label_2)
self.cboLayer = QtGui.QComboBox(DlgImport)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.cboLayer.sizePolicy().hasHeightForWidth())
self.cboLayer.setSizePolicy(sizePolicy)
self.cboLayer.setObjectName("cboLayer")
self.hboxlayout.addWidget(self.cboLayer)
self.vboxlayout.addLayout(self.hboxlayout)
self.chkOnlySelection = QtGui.QCheckBox(DlgImport)
self.chkOnlySelection.setObjectName("chkOnlySelection")
self.vboxlayout.addWidget(self.chkOnlySelection)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.vboxlayout.addItem(spacerItem1)
self.buttonBox = QtGui.QDialogButtonBox(DlgImport)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.vboxlayout.addWidget(self.buttonBox)
self.retranslateUi(DlgImport)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), DlgImport.reject)
QtCore.QMetaObject.connectSlotsByName(DlgImport)
DlgImport.setTabOrder(self.cboLayer, self.chkOnlySelection)
DlgImport.setTabOrder(self.chkOnlySelection, self.buttonBox)
def retranslateUi(self, DlgImport):
DlgImport.setWindowTitle(QtGui.QApplication.translate("DlgImport", "Import data to OSM", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgImport", "In this dialog you can import a layer loaded in QGIS into active OSM data.", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgImport", "Layer", None, QtGui.QApplication.UnicodeUTF8))
self.chkOnlySelection.setText(QtGui.QApplication.translate("DlgImport", "Import only current selection", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,320 @@
# -*- coding: utf-8 -*-
"""@package DlgLoadOSM
This module provides all structures and methods neccessary for OSM data loading.
Loading is done from XML file. After XML file selection and confirming the dialog three vector layers
are created in Quantum GIS. Layer for points, one for lines and one for polygons.
All these layers are created with OSM data provider.
Data provider is the one, who parses an input XML file.
OSM data loading can be canceled, in such case system returns to the same state as the one before loading.
"""
from DlgLoadOSM_ui import Ui_DlgLoadOSM
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import *
from sip import unwrapinstance
from qgis.core import QgsVectorLayer, QgsMapLayerRegistry, QgsRectangle
from sip import *
class DlgLoadOSM(QDialog, Ui_DlgLoadOSM):
"""This class provides all structures and methods neccessary for OSM data loading.
Loading is done from XML file. After XML file selection and confirming the dialog three vector layers
are created in Quantum GIS. Layer for points, one for lines and one for polygons.
All these layers are created with OSM data provider.
Data provider is the one, who parses an input XML file.
OSM data loading can be canceled, in such case system returns to the same state as the one before loading.
"""
def __init__(self, plugin):
"""The constructor.
@param plugin is pointer to instance of OSM Plugin
"""
QDialog.__init__(self, None)
self.setupUi(self)
self.canvas=plugin.canvas
self.dbm=plugin.dbm
self.progress = None
# we must connect action "click on browse button" with method for showing open file dialog
QObject.connect(self.browseOSMButton,SIGNAL("clicked()"),self.showOpenFileDialog)
QObject.connect(self.buttonBox,SIGNAL("accepted()"), self.onOK)
for tag in ['name','place','highway','landuse','waterway','railway','amenity','tourism','learning']:
item = QListWidgetItem(tag, self.lstTags)
item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
item.setCheckState(Qt.Checked if tag == 'name' else Qt.Unchecked)
# gui initialization
self.initGui()
def initGui(self):
"""Initializes GUI of OSM Load dialog.
"""
# load default values to combobox determining style for custom renderer
self.styles=["Small scale","Medium scale","Large scale"]
thisFile=QString(__file__)
directory=thisFile.left(thisFile.lastIndexOf('/'))
self.styleFiles=[directory+"/styles/small_scale.style", directory+"/styles/medium_scale.style", directory+"/styles/big_scale.style"]
self.styleCombo.addItems(self.styles)
if not self.dbm.currentKey:
self.chkReplaceData.setEnabled(False)
def showOpenFileDialog(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.getOpenFileName(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)
# save 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 Load dialog.
It performs all actions neccessary for OSM data loading.
It creates three QGIS vector layers for loaded data (point,line,polygon layer).
"""
self.buttonBox.setEnabled(False)
# after closing a dialog, we want to add map layers using osm provider
self.fname = self.OSMFileEdit.text()
if self.fname=='':
QMessageBox.information(self, "OSM Load", QString("Please enter path to OSM data file."))
self.buttonBox.setEnabled(True)
return
osmfile = QFileInfo(self.fname)
observer = "&observer="+str(unwrapinstance(self))
basename = osmfile.baseName()
if not osmfile.exists():
QMessageBox.information(self, "OSM Load", QString("Path to OSM file is invalid: %1.").arg(self.fname))
return
fLoaded=self.filesLoaded()
replacing=self.chkReplaceData.isChecked()
newDB=self.fname.toAscii().data()+".db"
curDB=self.dbm.currentKey
if basename in fLoaded and newDB<>curDB:
QMessageBox.information(self, "Error", QString("Layers of OSM file \"%1\" are loaded already.").arg(self.fname))
return
if replacing:
# remove layers of current data first
QgsMapLayerRegistry.instance().removeMapLayer(self.canvas.currentLayer().getLayerID(),True)
tags = "&tags=yes"
if self.chkCustomRenderer.isChecked():
styleFile=self.styleFiles[self.styleCombo.currentIndex()]
style="&style="+styleFile
else:
style=""
# some specific tags?
tag = ""
for row in xrange(self.lstTags.count()):
item = self.lstTags.item(row)
if item.checkState() == Qt.Checked:
if len(tag) > 0: tag += "+"
tag += item.text()
if len(tag) > 0:
tag = "&tag=" + tag
# freeze map canvas until all vector layers are created
self.canvas.freeze(True)
self.loadingCanceled=False
self.setProperty("osm_stop_parsing",QVariant(0))
# add polygon layer
polygonLayer = QgsVectorLayer(self.fname+"?type=polygon"+observer + tags + tag + style, basename+" polygons", "osm")
if self.loadingCanceled:
polygonLayer=None
return
if not polygonLayer.isValid():
QMessageBox.information(self,"Error",QString("Failed to load polygon layer."))
return
if self.chkCustomRenderer.isChecked():
self.setCustomRenderer(polygonLayer)
QgsMapLayerRegistry.instance().addMapLayer(polygonLayer)
# add line layer
lineLayer = QgsVectorLayer(self.fname+"?type=line"+observer + tags + tag + style, basename+" lines", "osm")
if self.loadingCanceled:
lineLayer=None
return
if not lineLayer.isValid():
QMessageBox.information(self,"Error",QString("Failed to load line layer."))
return
if self.chkCustomRenderer.isChecked():
self.setCustomRenderer(lineLayer)
QgsMapLayerRegistry.instance().addMapLayer(lineLayer)
# add point layer
pointLayer = QgsVectorLayer(self.fname+"?type=point"+observer + tags + tag + style, basename+" points", "osm")
if self.loadingCanceled:
pointLayer=None
return
if not pointLayer.isValid():
QMessageBox.information(self,"Error",QString("Failed to load point layer."))
return
if self.chkCustomRenderer.isChecked():
self.setCustomRenderer(pointLayer)
QgsMapLayerRegistry.instance().addMapLayer(pointLayer)
# remember layers
self.polygonLayer=polygonLayer
self.lineLayer=lineLayer
self.pointLayer=pointLayer
self.canvas.freeze(False)
rect=self.canvas.extent()
if self.chkCustomRenderer.isChecked():
midX=rect.xMinimum()+(rect.xMaximum()-rect.xMinimum())/2
midY=rect.yMinimum()+(rect.yMaximum()-rect.yMinimum())/2
rX=rect.xMaximum()-midX
rY=rect.yMaximum()-midY
st=self.styles[self.styleCombo.currentIndex()]
if st=="Small scale":
rect=QgsRectangle(midX-rX/15,midY-rY/15,midX+rX/15,midY+rY/15)
elif st=="Medium scale":
rect=QgsRectangle(midX-rX/8,midY-rY/8,midX+rX/8,midY+rY/8)
else:
rect=QgsRectangle(midX-rX/1.2,midY-rY/1.2,midX+rX/1.2,midY+rY/1.2)
self.canvas.setExtent(rect)
self.canvas.refresh()
self.accept()
def setCustomRenderer(self, layer):
"""Function provides a way how to set custom renderer.
For more check changeAttributeValues() implementation of OSM provider.
@param layer point to QGIS vector layer
"""
import sip
layerAddr = sip.unwrapinstance(layer)
layer.dataProvider().changeAttributeValues( { 0x12345678 : { 0 : QVariant(layerAddr) } } )
def filesLoaded(self):
"""Function returns list of keys of all currently loaded vector layers.
Note that names are not absolute and not unique.
@return list of keys of all currently loaded vector layers
"""
mapLayers=QgsMapLayerRegistry.instance().mapLayers()
fLoaded=[]
for ix in mapLayers.keys():
fileName=QString(ix)
pos=ix.lastIndexOf("_")
fileName=fileName.left(pos)
if fileName not in fLoaded:
fLoaded.append(fileName)
return fLoaded
def cancelLoading(self):
"""Function is called when progress dialog is canceled
It's purpose is to tell OSM provider to stop XML file parsing.
"""
self.setProperty("osm_stop_parsing",QVariant(1))
self.loadingCanceled=True
def event(self, e):
"""Function is used for OSM provider <-> OSM Plugin communication.
"""
if e.type() == QEvent.DynamicPropertyChange:
if e.propertyName() == "osm_status":
# we're starting new part
if not self.progress:
self.progress = QProgressDialog(self)
self.progress.setAutoClose(False)
self.progress.setModal(True)
QObject.connect(self.progress,SIGNAL("canceled()"),self.cancelLoading)
self.progress.show()
status = self.property("osm_status").toString()
self.progress.setLabelText(status)
self.progress.setValue(0)
if e.propertyName() == "osm_max":
if not self.loadingCanceled:
# we've got new max. value
osm_max = self.property("osm_max").toInt()[0]
self.progress.setMaximum(osm_max)
elif e.propertyName() == "osm_value":
if not self.loadingCanceled:
# update in progressbar
osm_val = self.property("osm_value").toInt()[0]
self.progress.setValue(osm_val)
elif e.propertyName() == "osm_done":
if not self.loadingCanceled:
# we're done
QObject.disconnect(self.progress,SIGNAL("canceled()"),self.cancelLoading)
self.progress.close()
self.progress = None
elif e.propertyName() == "osm_failure":
if not self.loadingCanceled:
self.loadingCanceled=True
QObject.disconnect(self.progress,SIGNAL("canceled()"),self.cancelLoading)
self.progress.close()
self.progress = None
QMessageBox.information(self,"Error",QString("Failed to load layers: %1")
.arg(self.property("osm_failure").toString()))
qApp.processEvents()
return QDialog.event(self,e)

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgLoadOSM.ui'
#
# Created: Wed Jul 22 12:16:56 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgLoadOSM(object):
def setupUi(self, DlgLoadOSM):
DlgLoadOSM.setObjectName("DlgLoadOSM")
DlgLoadOSM.setWindowModality(QtCore.Qt.ApplicationModal)
DlgLoadOSM.resize(508, 309)
DlgLoadOSM.setModal(True)
self.gridlayout = QtGui.QGridLayout(DlgLoadOSM)
self.gridlayout.setObjectName("gridlayout")
self.gridlayout1 = QtGui.QGridLayout()
self.gridlayout1.setObjectName("gridlayout1")
self.label = QtGui.QLabel(DlgLoadOSM)
self.label.setIndent(-1)
self.label.setObjectName("label")
self.gridlayout1.addWidget(self.label, 0, 0, 1, 2)
self.OSMFileEdit = QtGui.QLineEdit(DlgLoadOSM)
self.OSMFileEdit.setObjectName("OSMFileEdit")
self.gridlayout1.addWidget(self.OSMFileEdit, 1, 0, 1, 1)
self.browseOSMButton = QtGui.QPushButton(DlgLoadOSM)
self.browseOSMButton.setObjectName("browseOSMButton")
self.gridlayout1.addWidget(self.browseOSMButton, 1, 1, 1, 1)
self.gridlayout.addLayout(self.gridlayout1, 0, 0, 1, 2)
self.label_2 = QtGui.QLabel(DlgLoadOSM)
self.label_2.setObjectName("label_2")
self.gridlayout.addWidget(self.label_2, 1, 0, 1, 1)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.lstTags = QtGui.QListWidget(DlgLoadOSM)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lstTags.sizePolicy().hasHeightForWidth())
self.lstTags.setSizePolicy(sizePolicy)
self.lstTags.setObjectName("lstTags")
self.hboxlayout.addWidget(self.lstTags)
self.gridlayout.addLayout(self.hboxlayout, 2, 0, 1, 2)
self.hboxlayout1 = QtGui.QHBoxLayout()
self.hboxlayout1.setObjectName("hboxlayout1")
self.chkCustomRenderer = QtGui.QCheckBox(DlgLoadOSM)
self.chkCustomRenderer.setChecked(True)
self.chkCustomRenderer.setObjectName("chkCustomRenderer")
self.hboxlayout1.addWidget(self.chkCustomRenderer)
self.styleCombo = QtGui.QComboBox(DlgLoadOSM)
self.styleCombo.setMinimumSize(QtCore.QSize(182, 0))
self.styleCombo.setMaximumSize(QtCore.QSize(182, 16777215))
self.styleCombo.setObjectName("styleCombo")
self.hboxlayout1.addWidget(self.styleCombo)
self.gridlayout.addLayout(self.hboxlayout1, 4, 0, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(DlgLoadOSM)
self.buttonBox.setMaximumSize(QtCore.QSize(110, 16777215))
self.buttonBox.setBaseSize(QtCore.QSize(110, 0))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridlayout.addWidget(self.buttonBox, 4, 1, 1, 1)
self.chkReplaceData = QtGui.QCheckBox(DlgLoadOSM)
self.chkReplaceData.setChecked(False)
self.chkReplaceData.setObjectName("chkReplaceData")
self.gridlayout.addWidget(self.chkReplaceData, 3, 0, 1, 1)
self.retranslateUi(DlgLoadOSM)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), DlgLoadOSM.reject)
QtCore.QMetaObject.connectSlotsByName(DlgLoadOSM)
DlgLoadOSM.setTabOrder(self.OSMFileEdit, self.browseOSMButton)
DlgLoadOSM.setTabOrder(self.browseOSMButton, self.lstTags)
DlgLoadOSM.setTabOrder(self.lstTags, self.chkCustomRenderer)
DlgLoadOSM.setTabOrder(self.chkCustomRenderer, self.buttonBox)
def retranslateUi(self, DlgLoadOSM):
DlgLoadOSM.setWindowTitle(QtGui.QApplication.translate("DlgLoadOSM", "Load OSM", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgLoadOSM", "OpenStreetMap file to load:", None, QtGui.QApplication.UnicodeUTF8))
self.browseOSMButton.setText(QtGui.QApplication.translate("DlgLoadOSM", "...", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgLoadOSM", "Add columns for tags:", None, QtGui.QApplication.UnicodeUTF8))
self.chkCustomRenderer.setText(QtGui.QApplication.translate("DlgLoadOSM", "Use custom renderer", None, QtGui.QApplication.UnicodeUTF8))
self.chkReplaceData.setText(QtGui.QApplication.translate("DlgLoadOSM", "Replace current data (current layers will be removed)", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,314 @@
# -*- coding: utf-8 -*-
"""@package DlgSaveOSM
This module is used to save OSM data into XML file.
Of course, user is asked where to save the current data first.
"""
from DlgSaveOSM_ui import Ui_DlgSaveOSM
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
#from sip import *
import sqlite3
class DlgSaveOSM(QDialog, Ui_DlgSaveOSM):
"""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)
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
# if self.xml.device().isOpen():
# self.xml.device().close()
# close the whole Save OSM dialog
self.close()
# todo: segfault... why????
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.
"""
# after closing a dialog, we want to save data into osm
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)
self.dbConnection=sqlite3.connect(self.plugin.dbFileName.toLatin1().data())
c=self.dbConnection.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()
# todo: <bounds> element?
# todo: and what about uid? changeset? are they compulsory?
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 v.object_id=n.id and v.object_type='node'")
for rec in c:
anyTags=False
tagList=[]
if tags:
tagList=self.dbm.getFeatureTags(rec[0],'Point')
if len(tagList)>0:
anyTags=True
if anyTags:
self.xml.writeStartElement("node")
else:
self.xml.writeEmptyElement("node")
self.xml.writeAttribute("id",str(rec[0]))
self.xml.writeAttribute("lat",str(rec[1]))
self.xml.writeAttribute("lon",str(rec[2]))
self.xml.writeAttribute("version",str(rec[3]))
self.xml.writeAttribute("user",rec[4])
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",rec[5])
if anyTags:
for r in tagList:
self.xml.writeEmptyElement("tag")
self.xml.writeAttribute("k",r[0])
self.xml.writeAttribute("v",r[1])
if anyTags:
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 v.object_id=w.id and v.object_type='way'")
for rec in c:
self.xml.writeStartElement("way")
self.xml.writeAttribute("id",str(rec[0]))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",rec[3])
self.xml.writeAttribute("version",str(rec[1]))
self.xml.writeAttribute("user",rec[2])
d=self.dbConnection.cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":rec[0]})
for r in d:
self.xml.writeStartElement("nd")
self.xml.writeAttribute("ref",str(r[0]))
self.xml.writeEndElement()
d.close()
if tags:
tagList=self.dbm.getFeatureTags(rec[0],'Line')
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 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 v.object_id=w.id and v.object_type='way'")
for rec in c:
self.xml.writeStartElement("way")
self.xml.writeAttribute("id",str(rec[0]))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",rec[3])
self.xml.writeAttribute("version",str(rec[1]))
self.xml.writeAttribute("user",rec[2])
d=self.dbConnection.cursor()
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":rec[0]})
for r in d:
self.xml.writeStartElement("nd")
self.xml.writeAttribute("ref",str(r[0]))
self.xml.writeEndElement()
d.close()
if tags:
tagList=self.dbm.getFeatureTags(rec[0],'Polygon')
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 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 v.object_id=r.id and v.object_type='relation'")
for rec in c:
self.xml.writeStartElement("relation")
self.xml.writeAttribute("id",str(rec[0]))
self.xml.writeAttribute("visible","true")
self.xml.writeAttribute("timestamp",rec[3])
self.xml.writeAttribute("version",str(rec[1]))
self.xml.writeAttribute("user",rec[2])
d=self.dbConnection.cursor()
d.execute("select member_id,member_type,role from relation_member where relation_id=:relId",{"relId":rec[0]})
for r in d:
self.xml.writeStartElement("member")
self.xml.writeAttribute("type",r[1])
self.xml.writeAttribute("ref",str(r[0]))
self.xml.writeAttribute("role",r[2])
self.xml.writeEndElement()
d.close()
if tags:
tagList=self.dbm.getFeatureTags(rec[0],'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()

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgSaveOSM.ui'
#
# Created: Tue Jul 14 14:44:25 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgSaveOSM(object):
def setupUi(self, DlgSaveOSM):
DlgSaveOSM.setObjectName("DlgSaveOSM")
DlgSaveOSM.setWindowModality(QtCore.Qt.ApplicationModal)
DlgSaveOSM.resize(370, 206)
DlgSaveOSM.setModal(True)
self.vboxlayout = QtGui.QVBoxLayout(DlgSaveOSM)
self.vboxlayout.setObjectName("vboxlayout")
self.gridlayout = QtGui.QGridLayout()
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(DlgSaveOSM)
self.label.setIndent(-1)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label, 0, 0, 1, 2)
self.OSMFileEdit = QtGui.QLineEdit(DlgSaveOSM)
self.OSMFileEdit.setObjectName("OSMFileEdit")
self.gridlayout.addWidget(self.OSMFileEdit, 1, 0, 1, 1)
self.browseOSMButton = QtGui.QPushButton(DlgSaveOSM)
self.browseOSMButton.setMaximumSize(QtCore.QSize(50, 16777215))
self.browseOSMButton.setObjectName("browseOSMButton")
self.gridlayout.addWidget(self.browseOSMButton, 1, 1, 1, 1)
self.vboxlayout.addLayout(self.gridlayout)
self.label_2 = QtGui.QLabel(DlgSaveOSM)
self.label_2.setObjectName("label_2")
self.vboxlayout.addWidget(self.label_2)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setContentsMargins(15, -1, 0, 10)
self.hboxlayout.setObjectName("hboxlayout")
self.vboxlayout1 = QtGui.QVBoxLayout()
self.vboxlayout1.setObjectName("vboxlayout1")
self.chkPoints = QtGui.QCheckBox(DlgSaveOSM)
self.chkPoints.setChecked(True)
self.chkPoints.setObjectName("chkPoints")
self.vboxlayout1.addWidget(self.chkPoints)
self.chkLines = QtGui.QCheckBox(DlgSaveOSM)
self.chkLines.setChecked(True)
self.chkLines.setObjectName("chkLines")
self.vboxlayout1.addWidget(self.chkLines)
self.chkPolygons = QtGui.QCheckBox(DlgSaveOSM)
self.chkPolygons.setChecked(True)
self.chkPolygons.setObjectName("chkPolygons")
self.vboxlayout1.addWidget(self.chkPolygons)
self.hboxlayout.addLayout(self.vboxlayout1)
self.vboxlayout2 = QtGui.QVBoxLayout()
self.vboxlayout2.setObjectName("vboxlayout2")
self.chkRelations = QtGui.QCheckBox(DlgSaveOSM)
self.chkRelations.setChecked(True)
self.chkRelations.setObjectName("chkRelations")
self.vboxlayout2.addWidget(self.chkRelations)
self.chkTags = QtGui.QCheckBox(DlgSaveOSM)
self.chkTags.setChecked(True)
self.chkTags.setObjectName("chkTags")
self.vboxlayout2.addWidget(self.chkTags)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.vboxlayout2.addItem(spacerItem)
self.hboxlayout.addLayout(self.vboxlayout2)
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem1)
self.vboxlayout3 = QtGui.QVBoxLayout()
self.vboxlayout3.setObjectName("vboxlayout3")
spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.vboxlayout3.addItem(spacerItem2)
self.buttonBox = QtGui.QDialogButtonBox(DlgSaveOSM)
self.buttonBox.setMaximumSize(QtCore.QSize(110, 16777215))
self.buttonBox.setBaseSize(QtCore.QSize(110, 0))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.vboxlayout3.addWidget(self.buttonBox)
self.hboxlayout.addLayout(self.vboxlayout3)
self.vboxlayout.addLayout(self.hboxlayout)
self.retranslateUi(DlgSaveOSM)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), DlgSaveOSM.reject)
QtCore.QMetaObject.connectSlotsByName(DlgSaveOSM)
DlgSaveOSM.setTabOrder(self.OSMFileEdit, self.browseOSMButton)
def retranslateUi(self, DlgSaveOSM):
DlgSaveOSM.setWindowTitle(QtGui.QApplication.translate("DlgSaveOSM", "Save OSM", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgSaveOSM", "Where to save:", None, QtGui.QApplication.UnicodeUTF8))
self.browseOSMButton.setText(QtGui.QApplication.translate("DlgSaveOSM", "...", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgSaveOSM", "Features to save:", None, QtGui.QApplication.UnicodeUTF8))
self.chkPoints.setText(QtGui.QApplication.translate("DlgSaveOSM", "Points", None, QtGui.QApplication.UnicodeUTF8))
self.chkLines.setText(QtGui.QApplication.translate("DlgSaveOSM", "Lines", None, QtGui.QApplication.UnicodeUTF8))
self.chkPolygons.setText(QtGui.QApplication.translate("DlgSaveOSM", "Polygons", None, QtGui.QApplication.UnicodeUTF8))
self.chkRelations.setText(QtGui.QApplication.translate("DlgSaveOSM", "Relations", None, QtGui.QApplication.UnicodeUTF8))
self.chkTags.setText(QtGui.QApplication.translate("DlgSaveOSM", "Tags", None, QtGui.QApplication.UnicodeUTF8))

1548
python/plugins/osm/DlgUploadOSM.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DlgUploadOSM.ui'
#
# Created: Tue Jul 14 14:44:26 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_DlgUploadOSM(object):
def setupUi(self, DlgUploadOSM):
DlgUploadOSM.setObjectName("DlgUploadOSM")
DlgUploadOSM.setWindowModality(QtCore.Qt.ApplicationModal)
DlgUploadOSM.resize(373, 468)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(DlgUploadOSM.sizePolicy().hasHeightForWidth())
DlgUploadOSM.setSizePolicy(sizePolicy)
DlgUploadOSM.setModal(True)
self.vboxlayout = QtGui.QVBoxLayout(DlgUploadOSM)
self.vboxlayout.setObjectName("vboxlayout")
self.groupBox = QtGui.QGroupBox(DlgUploadOSM)
self.groupBox.setObjectName("groupBox")
self.vboxlayout1 = QtGui.QVBoxLayout(self.groupBox)
self.vboxlayout1.setObjectName("vboxlayout1")
self.uploadChangesTable = QtGui.QTreeWidget(self.groupBox)
self.uploadChangesTable.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uploadChangesTable.sizePolicy().hasHeightForWidth())
self.uploadChangesTable.setSizePolicy(sizePolicy)
self.uploadChangesTable.setMinimumSize(QtCore.QSize(330, 90))
self.uploadChangesTable.setMaximumSize(QtCore.QSize(330, 90))
self.uploadChangesTable.setAutoFillBackground(False)
self.uploadChangesTable.setTextElideMode(QtCore.Qt.ElideLeft)
self.uploadChangesTable.setRootIsDecorated(False)
self.uploadChangesTable.setItemsExpandable(False)
self.uploadChangesTable.setColumnCount(5)
self.uploadChangesTable.setObjectName("uploadChangesTable")
self.vboxlayout1.addWidget(self.uploadChangesTable)
self.label_4 = QtGui.QLabel(self.groupBox)
self.label_4.setObjectName("label_4")
self.vboxlayout1.addWidget(self.label_4)
self.commentTextEdit = QtGui.QTextEdit(self.groupBox)
self.commentTextEdit.setEnabled(True)
self.commentTextEdit.setMaximumSize(QtCore.QSize(16777215, 85))
self.commentTextEdit.setObjectName("commentTextEdit")
self.vboxlayout1.addWidget(self.commentTextEdit)
self.vboxlayout.addWidget(self.groupBox)
self.accountGroupBox = QtGui.QGroupBox(DlgUploadOSM)
self.accountGroupBox.setEnabled(True)
self.accountGroupBox.setObjectName("accountGroupBox")
self.vboxlayout2 = QtGui.QVBoxLayout(self.accountGroupBox)
self.vboxlayout2.setObjectName("vboxlayout2")
self.gridlayout = QtGui.QGridLayout()
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(self.accountGroupBox)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label, 0, 0, 1, 1)
self.userLineEdit = QtGui.QLineEdit(self.accountGroupBox)
self.userLineEdit.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.userLineEdit.sizePolicy().hasHeightForWidth())
self.userLineEdit.setSizePolicy(sizePolicy)
self.userLineEdit.setObjectName("userLineEdit")
self.gridlayout.addWidget(self.userLineEdit, 0, 1, 1, 1)
self.label_2 = QtGui.QLabel(self.accountGroupBox)
self.label_2.setObjectName("label_2")
self.gridlayout.addWidget(self.label_2, 1, 0, 1, 1)
self.passwdLineEdit = QtGui.QLineEdit(self.accountGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.passwdLineEdit.sizePolicy().hasHeightForWidth())
self.passwdLineEdit.setSizePolicy(sizePolicy)
self.passwdLineEdit.setObjectName("passwdLineEdit")
self.gridlayout.addWidget(self.passwdLineEdit, 1, 1, 1, 1)
self.chkShowPasswd = QtGui.QCheckBox(self.accountGroupBox)
self.chkShowPasswd.setObjectName("chkShowPasswd")
self.gridlayout.addWidget(self.chkShowPasswd, 2, 1, 1, 1)
self.chkSavePasswd = QtGui.QCheckBox(self.accountGroupBox)
self.chkSavePasswd.setObjectName("chkSavePasswd")
self.gridlayout.addWidget(self.chkSavePasswd, 3, 1, 1, 1)
self.vboxlayout2.addLayout(self.gridlayout)
self.vboxlayout.addWidget(self.accountGroupBox)
self.buttonBox = QtGui.QDialogButtonBox(DlgUploadOSM)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.buttonBox.setObjectName("buttonBox")
self.vboxlayout.addWidget(self.buttonBox)
self.retranslateUi(DlgUploadOSM)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), DlgUploadOSM.reject)
QtCore.QMetaObject.connectSlotsByName(DlgUploadOSM)
DlgUploadOSM.setTabOrder(self.userLineEdit, self.passwdLineEdit)
DlgUploadOSM.setTabOrder(self.passwdLineEdit, self.chkShowPasswd)
DlgUploadOSM.setTabOrder(self.chkShowPasswd, self.buttonBox)
def retranslateUi(self, DlgUploadOSM):
DlgUploadOSM.setWindowTitle(QtGui.QApplication.translate("DlgUploadOSM", "Upload OSM data", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("DlgUploadOSM", "Ready for upload", None, QtGui.QApplication.UnicodeUTF8))
self.uploadChangesTable.headerItem().setText(0, QtGui.QApplication.translate("DlgUploadOSM", "1", None, QtGui.QApplication.UnicodeUTF8))
self.uploadChangesTable.headerItem().setText(1, QtGui.QApplication.translate("DlgUploadOSM", "2", None, QtGui.QApplication.UnicodeUTF8))
self.uploadChangesTable.headerItem().setText(2, QtGui.QApplication.translate("DlgUploadOSM", "3", None, QtGui.QApplication.UnicodeUTF8))
self.uploadChangesTable.headerItem().setText(3, QtGui.QApplication.translate("DlgUploadOSM", "4", None, QtGui.QApplication.UnicodeUTF8))
self.uploadChangesTable.headerItem().setText(4, QtGui.QApplication.translate("DlgUploadOSM", "5", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("DlgUploadOSM", "Comment on your changes:", None, QtGui.QApplication.UnicodeUTF8))
self.accountGroupBox.setTitle(QtGui.QApplication.translate("DlgUploadOSM", "OSM account", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("DlgUploadOSM", "Username:", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("DlgUploadOSM", "Password:", None, QtGui.QApplication.UnicodeUTF8))
self.chkShowPasswd.setText(QtGui.QApplication.translate("DlgUploadOSM", "Show password", None, QtGui.QApplication.UnicodeUTF8))
self.chkSavePasswd.setText(QtGui.QApplication.translate("DlgUploadOSM", "Save password", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,441 @@
"""@package DockUndoRedo
This module holds evidence of user edit actions.
Such evidence exists for each loaded OSM data.
Module provides easy way how to call undo/redo actions.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
from DockUndoRedo_ui import Ui_OsmUndoRedoDockWidget
from DatabaseManager import DatabaseManager
import sqlite3
from math import *
from time import *
class DockUndoRedo(QDockWidget, Ui_OsmUndoRedoDockWidget, object):
"""This class extends functionality of Ui_UndoRedo dialog which displays history of user edit actions.
Such history exists for each loaded OSM data.
This class provides easy way how to call undo/redo actions.
"""
def __init__(self, plugin):
"""The constructor.
Does basic initialization, connecting dialog signals to appropriate slots
and setting icons to its buttons.
@param plugin pointer to OSM Plugin instance
"""
QDockWidget.__init__(self, None)
self.setupUi(self)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
self.undoButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_undo.png"))
self.redoButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_redo.png"))
self.clearButton.setIcon(QIcon(":/plugins/osm_plugin/images/osm_remove.png"))
self.canvas=plugin.canvas
self.iface=plugin.iface
self.dbm=plugin.dbm
self.plugin=plugin
self.actionList.setDragDropMode(QAbstractItemView.NoDragDrop)
QObject.connect(self.undoButton,SIGNAL("clicked()"),self.undo)
QObject.connect(self.redoButton,SIGNAL("clicked()"),self.redo)
QObject.connect(self.clearButton,SIGNAL("clicked()"),self.clear)
QObject.connect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
# structures for evidence of user edit changes (required by undo and redo operations)
self.mapActions={}
self.mapIxAction={}
self.currentMapKey=None
self.actStartId=self.actStopId=self.actNote=None
self.actionInProgress=False
self.redoCounter=0
self.undoCounter=0
self.affected=set()
self.urIsBusy=False
self.actionList.addItem(QString("<empty>"))
self.actionList.setCurrentRow(0)
def currRowChanged(self,row):
"""This function is called after currentRowChanged(...) signal is emmited on dialog's list of edit actions.
Functions calls as many undo actions (as many redo actions) as needed to jump in editing history to selected row.
@param row row number from the list of edit actions
"""
if row<0:
return
self.goToAction(row)
def setContentEnabled(self,flag):
if flag:
if self.undoCounter>0:
self.undoButton.setEnabled(True)
if self.redoCounter>0:
self.redoButton.setEnabled(True)
else:
self.undoButton.setEnabled(False)
self.redoButton.setEnabled(False)
self.clearButton.setEnabled(flag)
self.actionList.setEnabled(flag)
def clear(self):
"""Function clears (re-initializes) the whole undo/redo dialog.
"""
if self.dbm and self.dbm.currentKey:
self.dbm.removeAllChangeSteps()
self.actionList.clear()
self.actStartId=self.actStopId=self.actNote=None
self.actionInProgress=False
self.urIsBusy=False
self.actionList.addItem(QString("<empty>"))
self.actionList.setCurrentRow(0)
self.redoCounter=0
self.redoButton.setEnabled(False)
self.undoCounter=0
self.undoButton.setEnabled(False)
if self.plugin:
if self.plugin.dockWidget:
self.plugin.dockWidget.redoButton.setEnabled(False)
self.plugin.dockWidget.undoButton.setEnabled(False)
if self.currentMapKey:
self.mapActions[self.currentMapKey]=[]
self.mapIxAction[self.currentMapKey]=-1
def databaseChanged(self,dbKey):
"""Functions is called when current database of OSM Plugin changed.
OSM Undo/Redo module clears its list of actions and loads the one for new current database.
If dbKey parameter is None, there is no current database. In this case function just clears the list
and reinitialize its inner structures.
@param dbKey key/name of new current database file
"""
# clear the list widget
self.actionList.clear()
# clear inner structures
self.actStartId=self.actStopId=self.actNote=None
self.actionInProgress=False
self.currentMapKey=dbKey
self.urIsBusy=False
if not dbKey:
self.setContentEnabled(False)
return
self.setContentEnabled(True)
if dbKey in self.mapActions.keys():
# load the list widget
self.redoCounter=0
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
self.undoCounter=0
self.undoButton.setEnabled(False)
self.plugin.dockWidget.undoButton.setEnabled(False)
self.actionList.addItem(QString("<empty>"))
for action in self.mapActions[self.currentMapKey]:
self.actionList.addItem(action[2]) # 2 ~ actionNote!
ixAction=self.mapIxAction[self.currentMapKey]
self.undoCounter=ixAction+1
self.redoCounter=len(self.mapActions[self.currentMapKey])-self.undoCounter
self.actionList.setCurrentRow(ixAction+1)
if self.undoCounter>0:
self.undoButton.setEnabled(True)
self.plugin.dockWidget.undoButton.setEnabled(True)
if self.redoCounter>0:
self.redoButton.setEnabled(True)
self.plugin.dockWidget.redoButton.setEnabled(True)
return
# new dbKey has no undo/redo history yet
self.actionList.addItem(QString("<empty>"))
self.actionList.setCurrentRow(0)
self.redoCounter=0
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
self.undoCounter=0
self.undoButton.setEnabled(False)
self.plugin.dockWidget.undoButton.setEnabled(False)
self.mapActions[dbKey]=[]
self.mapIxAction[dbKey]=-1
def goToAction(self,row):
"""Functions goes to the selected row in history of edit actions.
It calls as many undo/redo operations, as needed.
@param row row index to list of edit actions history
"""
curr=self.actionList.currentRow()
self.actionList.setEnabled(False)
if not self.currentMapKey in self.mapIxAction:
return
ixGoto=row # ix of row which was clicked
ixCurrent=self.mapIxAction[self.currentMapKey]+1 # current action index
# how many undo/redo actions are necessary?
howFar=0
self.affected=set()
if ixCurrent<ixGoto:
# redo actions; we move "whitespace item" behind the row which was clicked
howFar=ixGoto-ixCurrent
for ix in range(0,howFar):
self.redo(False)
elif ixCurrent>ixGoto:
# undo actions; we move "whitespace item" before the row which was clicked
howFar=ixCurrent-ixGoto
for ix in range(0,howFar):
self.undo(False)
else:
self.actionList.setEnabled(True)
QObject.disconnect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.actionList.setCurrentRow(curr)
QObject.connect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
return
self.dbm.commit()
self.dbm.recacheAffectedNow(self.affected)
self.affected=set()
self.canvas.refresh()
if self.plugin.dockWidget:
lFeat=self.plugin.dockWidget.feature
lFeatType=self.plugin.dockWidget.featureType
self.plugin.dockWidget.loadFeature(lFeat,lFeatType)
self.actionList.setEnabled(True)
QObject.disconnect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.actionList.setCurrentRow(curr)
QObject.connect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
def startAction(self,actNote):
"""Function remembers current state of system.
This function is called before performing an action that should be put into editing history.
It's expected that you call stopAction() function after edit actions finishes.
Then new record in history will be created.
@param actNote action description (in brief)
"""
if not self.dbm.currentKey:
# there is no current database
return
if self.actionInProgress:
print "failed! change in progress!"
return
self.actionInProgress=True
self.actStartId=self.dbm.getCurrentActionNumber()
self.actStopId=None
self.actNote=actNote
def stopAction(self,affected=set()):
"""Function is called after an edit action. It stores current state of system
and the state from last calling of startAction(). This two states of system
are considered new edit history record together and are stored in database.
@param affected list of all OSM features that was affected with just finished action"""
if not self.dbm.currentKey:
# there is no current database
return
if affected==None:
affected=set()
self.actStopId=self.dbm.getCurrentActionNumber()
if self.actStopId<=self.actStartId:
self.actionInProgress=False
return
for ix in range(len(self.mapActions[self.currentMapKey]),self.actionList.currentRow(),-1):
self.actionList.takeItem(ix)
self.redoCounter=self.redoCounter-1
ixAction=self.mapIxAction[self.currentMapKey]
cntActions=len(self.mapActions[self.currentMapKey])
if ixAction>-1:
fromId=self.mapActions[self.currentMapKey][ixAction][1]+1
self.dbm.removeChangeStepsBetween(fromId,self.actStartId)
del self.mapActions[self.currentMapKey][ixAction+1:cntActions]
if self.redoCounter==0:
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
self.mapIxAction[self.currentMapKey]=ixAction+1
ixAction=ixAction+1
# increase undo counter
self.undoCounter=self.undoCounter+1
self.undoButton.setEnabled(True)
self.plugin.dockWidget.undoButton.setEnabled(True)
self.mapActions[self.currentMapKey].append((self.actStartId,self.actStopId,self.actNote,affected))
self.actionList.addItem(self.actNote)
self.actionList.setCurrentRow(ixAction+1)
self.actStartId=self.actStopId=self.actNote=None
self.actionInProgress=False
def undo(self,standAlone=True):
"""Functions performs exactly one undo operation in system.
Last edit action is reverted, list of editing history on undo/redo dialog
shifts its current row up.
@param refresh if False, no canvas refresh will be performed after reverting an action; default is True
"""
self.undoButton.setEnabled(False)
self.plugin.dockWidget.undoButton.setEnabled(False)
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
(startId,stopId,note,affected)=self.mapActions[self.currentMapKey][self.mapIxAction[self.currentMapKey]]
# shift up in the list widget
ixCurrent=self.actionList.currentRow()
QObject.disconnect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.actionList.setCurrentRow(ixCurrent-1)
QObject.connect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.mapIxAction[self.currentMapKey]=self.mapIxAction[self.currentMapKey]-1
changeSteps=self.dbm.getChangeSteps(startId,stopId)
for (change_type,tab_name,row_id,col_name,old_value,new_value) in changeSteps:
if change_type=='I':
self.dbm.setRowDeleted(tab_name,row_id)
elif change_type=='D':
self.dbm.setRowNotDeleted(tab_name,row_id)
elif change_type=='U':
self.dbm.setRowColumnValue(tab_name,col_name,old_value,row_id)
# increase redo counter
self.redoCounter=self.redoCounter+1
# decrease undo counter
self.undoCounter=self.undoCounter-1
# refresh
if standAlone:
self.dbm.commit()
self.dbm.recacheAffectedNow(affected)
self.canvas.refresh()
self.plugin.dockWidget.loadFeature(self.plugin.dockWidget.feature,self.plugin.dockWidget.featureType)
else:
self.affected.update(affected)
self.redoButton.setEnabled(True)
self.plugin.dockWidget.redoButton.setEnabled(True)
if self.undoCounter>0:
self.undoButton.setEnabled(True)
self.plugin.dockWidget.undoButton.setEnabled(True)
def redo(self,standAlone=True):
"""Functions performs exactly one redo operation in system.
Last reverted edit action is redone again. List of editing history on undo/redo dialog
shifts its current row down.
@param refresh if False, no canvas refresh will be performed after redo action; default is True
"""
self.undoButton.setEnabled(False)
self.plugin.dockWidget.undoButton.setEnabled(False)
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
(startId,stopId,note,affected)=self.mapActions[self.currentMapKey][self.mapIxAction[self.currentMapKey]+1]
# shift down in the list widget
ixCurrent=self.actionList.currentRow()
QObject.disconnect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.actionList.setCurrentRow(ixCurrent+1)
QObject.connect(self.actionList,SIGNAL("currentRowChanged(int)"),self.currRowChanged)
self.mapIxAction[self.currentMapKey]=self.mapIxAction[self.currentMapKey]+1
if self.mapIxAction[self.currentMapKey]==len(self.mapActions[self.currentMapKey]):
self.redoButton.setEnabled(False)
self.plugin.dockWidget.redoButton.setEnabled(False)
changeSteps=self.dbm.getChangeSteps(startId,stopId)
for (change_type,tab_name,row_id,col_name,old_value,new_value) in changeSteps:
if change_type=='I':
self.dbm.setRowNotDeleted(tab_name,row_id)
elif change_type=='D':
self.dbm.setRowDeleted(tab_name,row_id)
elif change_type=='U':
self.dbm.setRowColumnValue(tab_name,col_name,new_value,row_id)
# decrease redo counter
self.redoCounter=self.redoCounter-1
# increase undo counter
self.undoCounter=self.undoCounter+1
# refresh
if standAlone:
self.dbm.commit()
self.dbm.recacheAffectedNow(affected)
self.canvas.refresh()
self.plugin.dockWidget.loadFeature(self.plugin.dockWidget.feature,self.plugin.dockWidget.featureType)
else:
self.affected.update(affected)
self.undoButton.setEnabled(True)
self.plugin.dockWidget.undoButton.setEnabled(True)
if self.redoCounter>0:
self.redoButton.setEnabled(True)
self.plugin.dockWidget.redoButton.setEnabled(True)

View File

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DockUndoRedo.ui'
#
# Created: Wed Jul 29 12:14:34 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_OsmUndoRedoDockWidget(object):
def setupUi(self, OsmUndoRedoDockWidget):
OsmUndoRedoDockWidget.setObjectName("OsmUndoRedoDockWidget")
OsmUndoRedoDockWidget.resize(227, 374)
OsmUndoRedoDockWidget.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas)
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.vboxlayout = QtGui.QVBoxLayout(self.dockWidgetContents)
self.vboxlayout.setObjectName("vboxlayout")
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.clearButton = QtGui.QToolButton(self.dockWidgetContents)
self.clearButton.setObjectName("clearButton")
self.hboxlayout.addWidget(self.clearButton)
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem)
self.undoButton = QtGui.QToolButton(self.dockWidgetContents)
self.undoButton.setEnabled(False)
self.undoButton.setObjectName("undoButton")
self.hboxlayout.addWidget(self.undoButton)
self.redoButton = QtGui.QToolButton(self.dockWidgetContents)
self.redoButton.setEnabled(False)
self.redoButton.setObjectName("redoButton")
self.hboxlayout.addWidget(self.redoButton)
self.vboxlayout.addLayout(self.hboxlayout)
self.actionList = QtGui.QListWidget(self.dockWidgetContents)
self.actionList.setObjectName("actionList")
self.vboxlayout.addWidget(self.actionList)
OsmUndoRedoDockWidget.setWidget(self.dockWidgetContents)
self.retranslateUi(OsmUndoRedoDockWidget)
QtCore.QMetaObject.connectSlotsByName(OsmUndoRedoDockWidget)
def retranslateUi(self, OsmUndoRedoDockWidget):
OsmUndoRedoDockWidget.setWindowTitle(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "OSM Edit History", None, QtGui.QApplication.UnicodeUTF8))
self.clearButton.setToolTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Clear all", None, QtGui.QApplication.UnicodeUTF8))
self.clearButton.setStatusTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Clear all", None, QtGui.QApplication.UnicodeUTF8))
self.clearButton.setWhatsThis(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Clear all", None, QtGui.QApplication.UnicodeUTF8))
self.clearButton.setText(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setToolTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setStatusTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setWhatsThis(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setText(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setToolTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setStatusTip(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setWhatsThis(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setText(QtGui.QApplication.translate("OsmUndoRedoDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,290 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_files/DockWidget.ui'
#
# Created: Wed Jul 29 12:14:33 2009
# by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_OsmDockWidget(object):
def setupUi(self, OsmDockWidget):
OsmDockWidget.setObjectName("OsmDockWidget")
OsmDockWidget.setWindowModality(QtCore.Qt.NonModal)
OsmDockWidget.setEnabled(True)
OsmDockWidget.resize(265, 776)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(OsmDockWidget.sizePolicy().hasHeightForWidth())
OsmDockWidget.setSizePolicy(sizePolicy)
OsmDockWidget.setMinimumSize(QtCore.QSize(261, 357))
OsmDockWidget.setMaximumSize(QtCore.QSize(524287, 524287))
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.vboxlayout = QtGui.QVBoxLayout(self.dockWidgetContents)
self.vboxlayout.setObjectName("vboxlayout")
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setSpacing(1)
self.hboxlayout.setContentsMargins(-1, -1, 0, -1)
self.hboxlayout.setObjectName("hboxlayout")
self.dummyButton = QtGui.QToolButton(self.dockWidgetContents)
self.dummyButton.setMinimumSize(QtCore.QSize(1, 25))
self.dummyButton.setMaximumSize(QtCore.QSize(1, 27))
self.dummyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.dummyButton.setCheckable(True)
self.dummyButton.setObjectName("dummyButton")
self.hboxlayout.addWidget(self.dummyButton)
self.identifyButton = QtGui.QToolButton(self.dockWidgetContents)
self.identifyButton.setMinimumSize(QtCore.QSize(26, 25))
self.identifyButton.setMaximumSize(QtCore.QSize(25, 26))
self.identifyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.identifyButton.setCheckable(True)
self.identifyButton.setObjectName("identifyButton")
self.hboxlayout.addWidget(self.identifyButton)
self.moveButton = QtGui.QToolButton(self.dockWidgetContents)
self.moveButton.setMinimumSize(QtCore.QSize(26, 25))
self.moveButton.setMaximumSize(QtCore.QSize(25, 26))
self.moveButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.moveButton.setCheckable(True)
self.moveButton.setObjectName("moveButton")
self.hboxlayout.addWidget(self.moveButton)
self.createPointButton = QtGui.QToolButton(self.dockWidgetContents)
self.createPointButton.setMinimumSize(QtCore.QSize(26, 25))
self.createPointButton.setMaximumSize(QtCore.QSize(25, 26))
self.createPointButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.createPointButton.setCheckable(True)
self.createPointButton.setObjectName("createPointButton")
self.hboxlayout.addWidget(self.createPointButton)
self.createLineButton = QtGui.QToolButton(self.dockWidgetContents)
self.createLineButton.setMinimumSize(QtCore.QSize(26, 25))
self.createLineButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.createLineButton.setCheckable(True)
self.createLineButton.setObjectName("createLineButton")
self.hboxlayout.addWidget(self.createLineButton)
self.createPolygonButton = QtGui.QToolButton(self.dockWidgetContents)
self.createPolygonButton.setMinimumSize(QtCore.QSize(26, 25))
self.createPolygonButton.setMaximumSize(QtCore.QSize(25, 26))
self.createPolygonButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.createPolygonButton.setCheckable(True)
self.createPolygonButton.setObjectName("createPolygonButton")
self.hboxlayout.addWidget(self.createPolygonButton)
self.createRelationButton = QtGui.QToolButton(self.dockWidgetContents)
self.createRelationButton.setMinimumSize(QtCore.QSize(26, 25))
self.createRelationButton.setMaximumSize(QtCore.QSize(25, 26))
self.createRelationButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.createRelationButton.setCheckable(True)
self.createRelationButton.setObjectName("createRelationButton")
self.hboxlayout.addWidget(self.createRelationButton)
self.undoButton = QtGui.QToolButton(self.dockWidgetContents)
self.undoButton.setMaximumSize(QtCore.QSize(25, 26))
self.undoButton.setObjectName("undoButton")
self.hboxlayout.addWidget(self.undoButton)
self.redoButton = QtGui.QToolButton(self.dockWidgetContents)
self.redoButton.setMaximumSize(QtCore.QSize(25, 26))
self.redoButton.setObjectName("redoButton")
self.hboxlayout.addWidget(self.redoButton)
self.urDetailsButton = QtGui.QToolButton(self.dockWidgetContents)
self.urDetailsButton.setMaximumSize(QtCore.QSize(25, 26))
self.urDetailsButton.setCheckable(True)
self.urDetailsButton.setObjectName("urDetailsButton")
self.hboxlayout.addWidget(self.urDetailsButton)
self.vboxlayout.addLayout(self.hboxlayout)
self.featInfoBox = QtGui.QGroupBox(self.dockWidgetContents)
self.featInfoBox.setEnabled(True)
self.featInfoBox.setMinimumSize(QtCore.QSize(0, 95))
self.featInfoBox.setMaximumSize(QtCore.QSize(16777215, 95))
self.featInfoBox.setObjectName("featInfoBox")
self.vboxlayout1 = QtGui.QVBoxLayout(self.featInfoBox)
self.vboxlayout1.setSpacing(0)
self.vboxlayout1.setContentsMargins(18, 4, 3, 6)
self.vboxlayout1.setObjectName("vboxlayout1")
self.gridlayout = QtGui.QGridLayout()
self.gridlayout.setSpacing(0)
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(self.featInfoBox)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label, 0, 0, 1, 1)
self.label_4 = QtGui.QLabel(self.featInfoBox)
self.label_4.setObjectName("label_4")
self.gridlayout.addWidget(self.label_4, 1, 0, 1, 1)
self.label_5 = QtGui.QLabel(self.featInfoBox)
self.label_5.setObjectName("label_5")
self.gridlayout.addWidget(self.label_5, 2, 0, 1, 1)
self.typeIdLabel = QtGui.QLabel(self.featInfoBox)
self.typeIdLabel.setObjectName("typeIdLabel")
self.gridlayout.addWidget(self.typeIdLabel, 0, 1, 1, 1)
self.createdLabel = QtGui.QLabel(self.featInfoBox)
self.createdLabel.setObjectName("createdLabel")
self.gridlayout.addWidget(self.createdLabel, 1, 1, 1, 1)
self.userLabel = QtGui.QLabel(self.featInfoBox)
self.userLabel.setObjectName("userLabel")
self.gridlayout.addWidget(self.userLabel, 2, 1, 1, 1)
self.removeButton = QtGui.QToolButton(self.featInfoBox)
self.removeButton.setMaximumSize(QtCore.QSize(25, 25))
self.removeButton.setObjectName("removeButton")
self.gridlayout.addWidget(self.removeButton, 2, 2, 1, 1)
self.vboxlayout1.addLayout(self.gridlayout)
self.vboxlayout.addWidget(self.featInfoBox)
self.propRelBox = QtGui.QTabWidget(self.dockWidgetContents)
self.propRelBox.setMinimumSize(QtCore.QSize(0, 175))
self.propRelBox.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.propRelBox.setTabPosition(QtGui.QTabWidget.North)
self.propRelBox.setTabShape(QtGui.QTabWidget.Rounded)
self.propRelBox.setObjectName("propRelBox")
self.Properties = QtGui.QWidget()
self.Properties.setObjectName("Properties")
self.vboxlayout2 = QtGui.QVBoxLayout(self.Properties)
self.vboxlayout2.setObjectName("vboxlayout2")
self.tagsTableWidget = QtGui.QTableWidget(self.Properties)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.tagsTableWidget.sizePolicy().hasHeightForWidth())
self.tagsTableWidget.setSizePolicy(sizePolicy)
self.tagsTableWidget.setMinimumSize(QtCore.QSize(205, 100))
self.tagsTableWidget.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.tagsTableWidget.setFrameShape(QtGui.QFrame.Box)
self.tagsTableWidget.setObjectName("tagsTableWidget")
self.tagsTableWidget.setColumnCount(0)
self.tagsTableWidget.setRowCount(0)
self.vboxlayout2.addWidget(self.tagsTableWidget)
self.hboxlayout1 = QtGui.QHBoxLayout()
self.hboxlayout1.setObjectName("hboxlayout1")
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.hboxlayout1.addItem(spacerItem)
self.deleteTagsButton = QtGui.QToolButton(self.Properties)
self.deleteTagsButton.setObjectName("deleteTagsButton")
self.hboxlayout1.addWidget(self.deleteTagsButton)
self.vboxlayout2.addLayout(self.hboxlayout1)
self.propRelBox.addTab(self.Properties, "")
self.Relations = QtGui.QWidget()
self.Relations.setObjectName("Relations")
self.vboxlayout3 = QtGui.QVBoxLayout(self.Relations)
self.vboxlayout3.setObjectName("vboxlayout3")
self.hboxlayout2 = QtGui.QHBoxLayout()
self.hboxlayout2.setObjectName("hboxlayout2")
self.relListWidget = QtGui.QListWidget(self.Relations)
self.relListWidget.setEnabled(False)
self.relListWidget.setMinimumSize(QtCore.QSize(0, 60))
self.relListWidget.setMaximumSize(QtCore.QSize(16777215, 104))
self.relListWidget.setFrameShape(QtGui.QFrame.Box)
self.relListWidget.setObjectName("relListWidget")
self.hboxlayout2.addWidget(self.relListWidget)
self.vboxlayout4 = QtGui.QVBoxLayout()
self.vboxlayout4.setObjectName("vboxlayout4")
self.addRelationButton = QtGui.QPushButton(self.Relations)
self.addRelationButton.setEnabled(False)
self.addRelationButton.setMinimumSize(QtCore.QSize(26, 25))
self.addRelationButton.setMaximumSize(QtCore.QSize(26, 25))
self.addRelationButton.setObjectName("addRelationButton")
self.vboxlayout4.addWidget(self.addRelationButton)
self.editRelationButton = QtGui.QPushButton(self.Relations)
self.editRelationButton.setEnabled(False)
self.editRelationButton.setMinimumSize(QtCore.QSize(26, 25))
self.editRelationButton.setMaximumSize(QtCore.QSize(26, 25))
self.editRelationButton.setObjectName("editRelationButton")
self.vboxlayout4.addWidget(self.editRelationButton)
self.removeRelationButton = QtGui.QPushButton(self.Relations)
self.removeRelationButton.setEnabled(False)
self.removeRelationButton.setMinimumSize(QtCore.QSize(26, 25))
self.removeRelationButton.setMaximumSize(QtCore.QSize(26, 25))
self.removeRelationButton.setObjectName("removeRelationButton")
self.vboxlayout4.addWidget(self.removeRelationButton)
spacerItem1 = QtGui.QSpacerItem(26, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
self.vboxlayout4.addItem(spacerItem1)
self.hboxlayout2.addLayout(self.vboxlayout4)
self.vboxlayout3.addLayout(self.hboxlayout2)
self.label_2 = QtGui.QLabel(self.Relations)
self.label_2.setObjectName("label_2")
self.vboxlayout3.addWidget(self.label_2)
self.relTagsTreeWidget = QtGui.QTreeWidget(self.Relations)
self.relTagsTreeWidget.setEnabled(False)
self.relTagsTreeWidget.setMinimumSize(QtCore.QSize(0, 115))
self.relTagsTreeWidget.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.relTagsTreeWidget.setProperty("cursor", QtCore.QVariant(QtCore.Qt.ForbiddenCursor))
self.relTagsTreeWidget.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
self.relTagsTreeWidget.setFrameShape(QtGui.QFrame.Box)
self.relTagsTreeWidget.setFrameShadow(QtGui.QFrame.Sunken)
self.relTagsTreeWidget.setIndentation(0)
self.relTagsTreeWidget.setRootIsDecorated(False)
self.relTagsTreeWidget.setItemsExpandable(False)
self.relTagsTreeWidget.setColumnCount(1)
self.relTagsTreeWidget.setObjectName("relTagsTreeWidget")
self.vboxlayout3.addWidget(self.relTagsTreeWidget)
self.label_3 = QtGui.QLabel(self.Relations)
self.label_3.setObjectName("label_3")
self.vboxlayout3.addWidget(self.label_3)
self.relMembersList = QtGui.QListWidget(self.Relations)
self.relMembersList.setEnabled(False)
self.relMembersList.setMinimumSize(QtCore.QSize(0, 115))
self.relMembersList.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.relMembersList.setFrameShape(QtGui.QFrame.Box)
self.relMembersList.setObjectName("relMembersList")
self.vboxlayout3.addWidget(self.relMembersList)
self.propRelBox.addTab(self.Relations, "")
self.vboxlayout.addWidget(self.propRelBox)
OsmDockWidget.setWidget(self.dockWidgetContents)
self.retranslateUi(OsmDockWidget)
self.propRelBox.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(OsmDockWidget)
def retranslateUi(self, OsmDockWidget):
OsmDockWidget.setWindowTitle(QtGui.QApplication.translate("OsmDockWidget", "OSM Feature", None, QtGui.QApplication.UnicodeUTF8))
self.dummyButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.identifyButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Identify object", None, QtGui.QApplication.UnicodeUTF8))
self.identifyButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Identify object", None, QtGui.QApplication.UnicodeUTF8))
self.identifyButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Identify object", None, QtGui.QApplication.UnicodeUTF8))
self.identifyButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.moveButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Move object", None, QtGui.QApplication.UnicodeUTF8))
self.moveButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.createPointButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Create point", None, QtGui.QApplication.UnicodeUTF8))
self.createPointButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.createLineButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Create line", None, QtGui.QApplication.UnicodeUTF8))
self.createLineButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.createPolygonButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Create polygon", None, QtGui.QApplication.UnicodeUTF8))
self.createPolygonButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.createRelationButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Create relation", None, QtGui.QApplication.UnicodeUTF8))
self.createRelationButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Undo", None, QtGui.QApplication.UnicodeUTF8))
self.undoButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Redo", None, QtGui.QApplication.UnicodeUTF8))
self.redoButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.urDetailsButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Show/Hide OSM Edit History", None, QtGui.QApplication.UnicodeUTF8))
self.urDetailsButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Show/Hide OSM Edit History", None, QtGui.QApplication.UnicodeUTF8))
self.urDetailsButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Show/Hide OSM Edit History", None, QtGui.QApplication.UnicodeUTF8))
self.urDetailsButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.featInfoBox.setTitle(QtGui.QApplication.translate("OsmDockWidget", "Feature:", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("OsmDockWidget", "TYPE, ID:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("OsmDockWidget", "CREATED:", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("OsmDockWidget", "USER:", None, QtGui.QApplication.UnicodeUTF8))
self.typeIdLabel.setText(QtGui.QApplication.translate("OsmDockWidget", "unknown", None, QtGui.QApplication.UnicodeUTF8))
self.createdLabel.setText(QtGui.QApplication.translate("OsmDockWidget", "unknown", None, QtGui.QApplication.UnicodeUTF8))
self.userLabel.setText(QtGui.QApplication.translate("OsmDockWidget", "unknown", None, QtGui.QApplication.UnicodeUTF8))
self.removeButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.deleteTagsButton.setText(QtGui.QApplication.translate("OsmDockWidget", "...", None, QtGui.QApplication.UnicodeUTF8))
self.propRelBox.setTabText(self.propRelBox.indexOf(self.Properties), QtGui.QApplication.translate("OsmDockWidget", "Properties", None, QtGui.QApplication.UnicodeUTF8))
self.addRelationButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Add new relation", None, QtGui.QApplication.UnicodeUTF8))
self.addRelationButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Add new relation", None, QtGui.QApplication.UnicodeUTF8))
self.addRelationButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Add new relation", None, QtGui.QApplication.UnicodeUTF8))
self.addRelationButton.setText(QtGui.QApplication.translate("OsmDockWidget", "A", None, QtGui.QApplication.UnicodeUTF8))
self.editRelationButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Edit selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.editRelationButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Edit selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.editRelationButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Edit selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.editRelationButton.setText(QtGui.QApplication.translate("OsmDockWidget", "E", None, QtGui.QApplication.UnicodeUTF8))
self.removeRelationButton.setToolTip(QtGui.QApplication.translate("OsmDockWidget", "Remove selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.removeRelationButton.setStatusTip(QtGui.QApplication.translate("OsmDockWidget", "Remove selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.removeRelationButton.setWhatsThis(QtGui.QApplication.translate("OsmDockWidget", "Remove selected relation", None, QtGui.QApplication.UnicodeUTF8))
self.removeRelationButton.setText(QtGui.QApplication.translate("OsmDockWidget", "R", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("OsmDockWidget", "Relation tags:", None, QtGui.QApplication.UnicodeUTF8))
self.relTagsTreeWidget.headerItem().setText(0, QtGui.QApplication.translate("OsmDockWidget", "1", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("OsmDockWidget", "Relation members:", None, QtGui.QApplication.UnicodeUTF8))
self.propRelBox.setTabText(self.propRelBox.indexOf(self.Relations), QtGui.QApplication.translate("OsmDockWidget", "Relations", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -0,0 +1,37 @@
GEN_FILES = DlgLoadOSM_ui.py DlgSaveOSM_ui.py DlgDownloadOSM_ui.py DlgUploadOSM_ui.py DockWidget_ui.py DlgAddRelation_ui.py DockUndoRedo_ui.py DlgImport_ui.py resources.py
all: $(GEN_FILES)
DlgLoadOSM_ui.py: ui_files/DlgLoadOSM.ui
pyuic4 -o DlgLoadOSM_ui.py ui_files/DlgLoadOSM.ui
DlgSaveOSM_ui.py: ui_files/DlgSaveOSM.ui
pyuic4 -o DlgSaveOSM_ui.py ui_files/DlgSaveOSM.ui
DlgDownloadOSM_ui.py: ui_files/DlgDownloadOSM.ui
pyuic4 -o DlgDownloadOSM_ui.py ui_files/DlgDownloadOSM.ui
DlgUploadOSM_ui.py: ui_files/DlgUploadOSM.ui
pyuic4 -o DlgUploadOSM_ui.py ui_files/DlgUploadOSM.ui
DockWidget_ui.py: ui_files/DockWidget.ui
pyuic4 -o DockWidget_ui.py ui_files/DockWidget.ui
DlgAddRelation_ui.py: ui_files/DlgAddRelation.ui
pyuic4 -o DlgAddRelation_ui.py ui_files/DlgAddRelation.ui
DockUndoRedo_ui.py: ui_files/DockUndoRedo.ui
pyuic4 -o DockUndoRedo_ui.py ui_files/DockUndoRedo.ui
DlgImport_ui.py: ui_files/DlgImport.ui
pyuic4 -o DlgImport_ui.py ui_files/DlgImport.ui
resources.py: resources.qrc
pyrcc4 -o resources.py resources.qrc
clean:
rm -f $(GEN_FILES) *.pyc
package:
cd .. && rm -f osm_plugin.zip && zip -r osm_plugin.zip osm_plugin -x \*.svn-base -x \*.pyc

View File

@ -0,0 +1,65 @@
"""@package __init__
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
This is the main module of OpenStreetMap plugin for Quantum GIS.
It initializes the plugin, making it known to QGIS.
OSM Plugin is viewer and editor for OpenStreetMap data.
"""
def name():
"""Function returns name of this plugin.
@return name of this plugin ~ OpenStreetMap plugin
"""
return "OpenStreetMap plugin"
def description():
"""Function returns brief description of this plugin.
@return brief description of this plugin.
"""
return "Viewer and editor for OpenStreetMap data"
def version():
"""Function returns version of this plugin.
@return version of this plugin
"""
return "Version 0.4"
def qgisMinimumVersion():
"""Function returns information on what minimum version
of Quantum GIS this plugin works with.
@return minimum supported version of QGIS
"""
return "1.0.0"
def classFactory(iface):
"""Function returns OSM Plugin instance.
@return instance of OSM Plugin
"""
# load TestPlugin class from file testplug.py
from osm_plugin import OSMPlugin
# return object of our plugin with reference to QGIS interface as the only argument
return OSMPlugin(iface)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,337 @@
"""@package CreateLineMapTool
This module holds all structures and methods required to perform
"create line" operation on current OSM data.
Snapping to existing points is supported when creating new line.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
class CreateLineMapTool(QgsMapTool):
"""This class holds all structures and methods required to perform
"create line" operation on current OSM data.
Snapping to existing points is supported when creating new line.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
def __init__(self, plugin):
"""The constructor.
Initializes the map tool, creates necessary snappers.
@param plugin pointer to OSM Plugin instance
"""
QgsMapTool.__init__(self,plugin.canvas)
self.canvas=plugin.canvas
self.dockWidget=plugin.dockWidget
self.dbm=plugin.dbm
self.ur=plugin.undoredo
# initialization
self.snappingEnabled=True
self.lastPointIsStable=True
self.linePoints=[]
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
# creating rubberband which will be on new line
self.lineRubBand=self.createLineRubberband()
# creating rubberband for snapped objects
self.snapVerMarker=self.createSnapVertexMarker()
# creating snapper to this map tool
self.snapper=self.createSnapper(self.canvas.mapRenderer())
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function does re-initialization of maptool and create new snappers again (if necessary).
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.snappingEnabled=True
self.snapFeat=None
self.snapFeatType=None
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
del self.snapVerMarker
self.snapVerMarker=self.createSnapVertexMarker()
self.lineRubBand.reset(False)
self.lastPointIsStable=True
self.linePoints=[]
self.snappedPoint=None
if dbKey:
del self.snapper
self.snapper=self.createSnapper(self.canvas.mapRenderer())
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def createLineRubberband(self):
"""Function creates rubberband that is used for marking new line on the map.
@return rubberband that marks new line
"""
# get qgis settings of line width and color for rubberband
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
rband=QgsRubberBand(self.canvas,False)
rband.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
rband.setWidth(qgsLineWidth[0])
return rband
def createSnapVertexMarker(self):
"""Function creates vertexMarker that is used for marking feature
to which snapping was done.
@return vertex marker - QgsVertexMarker object
"""
# get qgis settings
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
verMarker=QgsVertexMarker(self.canvas)
verMarker.setIconType(2)
verMarker.setIconSize(13)
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
verMarker.setPenWidth(qgsLineWidth[0])
verMarker.setCenter(QgsPoint(-1000,-1000))
return verMarker
def createSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping of this snapper is done to all segments and vertexes
of all three layers of current OSM database.
@param canvasRenderer renderer of current map canvas
@return instance of vertex+segment QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(self.canvas.mapRenderer())
snapper=QgsSnapper(self.canvas.mapRenderer())
snapLayers=[]
# snap to osm layers from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def deactivate(self):
"""Functions is called when create line map-tool is being deactivated.
Function performs standard cleaning; re-initialization etc.
"""
self.lineRubBand.reset()
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappingEnabled=True
self.lastPointIsStable=True
self.linePoints=[]
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.createLineButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
def keyPressEvent(self, event):
"""This function is called after keyPressEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was pressed, function disables snapping til key is released again.
@param event event that occured when key pressing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = False
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappedPoint=None
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
def keyReleaseEvent(self, event):
"""This function is called after keyReleaseEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was released, function enables snapping again.
@param event event that occured when key releasing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON. Hold Ctrl to disable it.")
def canvasMoveEvent(self, event):
"""This function is called when mouse moving.
@param event event that occured when mouse moving.
"""
self.mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
if len(self.linePoints)>0:
if not self.lastPointIsStable:
self.lineRubBand.removeLastPoint()
self.lineRubBand.addPoint(QgsPoint(self.mapPoint.x(),self.mapPoint.y()))
self.lastPointIsStable=False
if not self.snappingEnabled:
self.snapVerMarker.setCenter(self.mapPoint)
return
# snapping! first reset old snapping vertexMarker
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
# try snapping to the closest vertex/segment
(retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])
if len(snappingResults)==0:
self.snapVerMarker.setCenter(self.mapPoint)
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
if self.dockWidget.feature:
self.dockWidget.clear()
return
# process snapping result (get point, set vertex marker)
self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
self.snapVerMarker.setCenter(self.snappedPoint)
if len(self.linePoints)>0:
self.lineRubBand.removeLastPoint()
self.lineRubBand.addPoint(QgsPoint(self.snappedPoint.x(),self.snappedPoint.y()))
# start identification
feature=self.dbm.findFeature(self.snappedPoint)
if feature:
(self.snapFeat,self.snapFeatType)=feature
if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)
def canvasReleaseEvent(self, event):
"""This function is called after mouse button releasing when using this map tool.
If left button is released new vertex of line is created (pre-created).
If right button is released the whole process of line creation is finished.
@param event event that occured when button releasing
"""
# we are interested in left/right button clicking only
if event.button() not in (Qt.LeftButton,Qt.RightButton):
return
if event.button()==Qt.LeftButton:
# where we are exactly?
actualMapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
# what point will be the next line member?
newLinePoint=actualMapPoint
if self.snappedPoint:
newLinePoint=self.snappedPoint
# add new point into rubberband (and removing last one if neccessary) and into new line members list
if not self.lastPointIsStable:
self.lineRubBand.removeLastPoint()
self.lastPointIsStable=True
self.lineRubBand.addPoint(newLinePoint)
self.linePoints.append((newLinePoint,self.snapFeat,self.snapFeatType))
# right button clicking signalizes the last line member!
elif event.button()==Qt.RightButton:
# line must have at least 2 member points (else it's point rather than line)
if len(self.linePoints)<2:
self.lineRubBand.reset()
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.lastPointIsStable=True
self.linePoints=[]
return
self.ur.startAction("Create a line.")
# call function of database manager that will create new line
(line,affected)=self.dbm.createLine(self.linePoints)
self.ur.stopAction(affected)
self.dbm.recacheAffectedNow(affected)
if line:
self.dockWidget.loadFeature(line,"Line",2)
# cleaning..
self.lineRubBand.reset()
self.linePoints=[]
# after line creation canvas must be refresh so that changes take effect on map
self.canvas.refresh()

View File

@ -0,0 +1,265 @@
"""@package CreatePointMapTool
This module holds all structures and methods required to perform
"create point" operation on current OSM data.
Snapping to existing segments of lines/polygons is supported when creating new point.
Process generates vertexMarkers so that user can watch results
of the operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
New points are loaded to it dynamically.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
import sqlite3
from math import *
class CreatePointMapTool(QgsMapTool):
"""This class holds all structures and methods required to perform
"create point" operation on current OSM data.
Snapping to existing segments of lines/polygons is supported when creating new point.
Process generates vertexMarkers so that user can watch results
of the operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
New points are loaded to it dynamically.
"""
def __init__(self,plugin):
"""The constructor.
Initializes the map tool, creates necessary snappers.
@param plugin pointer to OSM Plugin instance
"""
QgsMapTool.__init__(self,plugin.canvas)
self.canvas=plugin.canvas
self.dockWidget=plugin.dockWidget
self.dbm=plugin.dbm
self.ur=plugin.undoredo
self.snappingEnabled=True
self.snapFeat=None
self.snapFeatType=None
# creating vertex marker
self.verMarker=self.createVertexMarker()
# creating snapper to this map tool
self.snapper=self.createSnapper(self.canvas.mapRenderer())
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function does re-initialization of maptool and create new snapper again (if necessary).
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.snappingEnabled=True
self.snapFeat=None
self.snapFeatType=None
self.verMarker.setCenter(QgsPoint(-1000,-1000))
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
if self.verMarker:
self.canvas.scene().removeItem(self.verMarker)
del self.verMarker
self.verMarker=None
if not dbKey:
return
self.verMarker=self.createVertexMarker()
del self.snapper
self.snapper=self.createSnapper(self.canvas.mapRenderer())
def createVertexMarker(self):
"""Function creates vertexMarker that is used for marking new point on map.
@return vertex marker - QgsVertexMarker object
"""
# get qgis settings
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
verMarker=QgsVertexMarker(self.canvas)
verMarker.setIconType(2)
verMarker.setIconSize(13)
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
verMarker.setPenWidth(qgsLineWidth[0])
verMarker.setCenter(QgsPoint(-1000,-1000))
return verMarker
def createSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping is done to all segments of both line and polygon layer.
@param canvasRenderer renderer of current map canvas
@return instance of segment QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(self.canvas.mapRenderer())
snapper=QgsSnapper(self.canvas.mapRenderer())
snapLayers=[]
# snap to line and polygon layer from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToSegment
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToSegment
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def deactivate(self):
"""Functions is called when create point map-tool is being deactivated.
Function performs standard cleaning; re-initialization etc.
"""
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.createPointButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
if self.verMarker:
self.verMarker.setCenter(QgsPoint(-1000,-1000))
self.canvas.scene().removeItem(self.verMarker)
del self.verMarker
self.verMarker=None
self.dockWidget.clear()
def keyPressEvent(self, event):
"""This function is called after keyPressEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was pressed, function disables snapping til key is released again.
@param event event that occured when key pressing
"""
if (event.key()==Qt.Key_Control):
self.snappingEnabled=False
if self.verMarker:
self.verMarker.setCenter(QgsPoint(-1000,-1000))
self.snappedPoint=None
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
def keyReleaseEvent(self, event):
"""This function is called after keyReleaseEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was released, function enables snapping again.
@param event event that occured when key releasing
"""
if (event.key()==Qt.Key_Control):
self.snappingEnabled=True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON. Hold Ctrl to disable it.")
def canvasReleaseEvent(self,event):
"""This function is called after mouse button releasing when using this map tool.
If left button is released new point is created.
Right (and other) clicking does nothing.
@param event event that occured when button releasing
"""
if event.button()<>Qt.LeftButton:
return # nothing to do
if not self.snappedPoint:
newPoint = self.dockWidget.canvasToOsmCoords(event.pos())
else:
newPoint=self.snappedPoint
self.ur.startAction("Create a point.")
(node,affected)=self.dbm.createPoint(newPoint,self.snapFeat,self.snapFeatType)
self.ur.stopAction(affected)
self.dbm.recacheAffectedNow(affected)
if node:
self.dockWidget.loadFeature(node,"Point",2)
self.canvas.refresh()
def canvasMoveEvent(self,event):
"""This function is called when mouse moving.
@param event event that occured when mouse moving.
"""
self.mapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
# try snapping to the closest vertex/segment
if not self.snappingEnabled:
self.verMarker.setCenter(self.mapPoint)
return
# snapping! first reset old snapping vertexMarker
self.verMarker.setCenter(QgsPoint(-1000,-1000))
(retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])
if len(snappingResults)==0:
self.verMarker.setCenter(self.mapPoint)
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
if self.dockWidget.feature:
self.dockWidget.clear()
return
self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
self.verMarker.setCenter(self.snappedPoint)
# start identification
feature=self.dbm.findFeature(self.snappedPoint)
if feature:
(self.snapFeat,self.snapFeatType)=feature
if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)

View File

@ -0,0 +1,336 @@
"""@package CreatePolygonMapTool
This module holds all structures and methods required to perform
"create polygon" operation on current OSM data.
Snapping to existing points is supported when creating new polygon.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
class CreatePolygonMapTool(QgsMapTool):
"""This class holds all structures and methods required to perform
"create polygon" operation on current OSM data.
Snapping to existing points is supported when creating new polygon.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
def __init__(self, plugin):
"""The constructor.
Initializes the map tool, creates necessary snappers.
@param plugin pointer to OSM Plugin instance
"""
QgsMapTool.__init__(self,plugin.canvas)
self.canvas=plugin.canvas
self.dockWidget=plugin.dockWidget
self.dbm=plugin.dbm
self.ur=plugin.undoredo
# initialization
self.snappingEnabled=True
self.lastPointIsStable=True
self.polygonPoints=[]
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
# creating rubberband which will be on new polygon
self.polygonRubBand=self.createPolygonRubberband()
# creating rubberband for snapped objects
self.snapVerMarker=self.createSnapVertexMarker()
# creating snapper to this map tool
self.snapper=self.createSnapper(self.canvas.mapRenderer())
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function does re-initialization of maptool and create new snappers again (if necessary).
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.snappingEnabled=True
self.snapFeat=None
self.snapFeatType=None
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
del self.snapVerMarker
self.snapVerMarker=self.createSnapVertexMarker()
self.polygonRubBand.reset(True)
self.lastPointIsStable=True
self.polygonPoints=[]
self.snappedPoint=None
if dbKey:
del self.snapper
self.snapper=self.createSnapper(self.canvas.mapRenderer())
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def createPolygonRubberband(self):
"""Function creates rubberband that is used for marking new polygon on the map.
@return rubberband that marks new polygon
"""
# get qgis settings of line width and color for rubberband
settings = QSettings()
qgsLineWidth = settings.value( "/qgis/digitizing/line_width", QVariant(10) ).toInt()
qgsLineRed = settings.value( "/qgis/digitizing/line_color_red", QVariant(255) ).toInt()
qgsLineGreen = settings.value( "/qgis/digitizing/line_color_green", QVariant(0) ).toInt()
qgsLineBlue = settings.value( "/qgis/digitizing/line_color_blue", QVariant(0) ).toInt()
rband=QgsRubberBand(self.canvas,True)
rband.setColor( QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]) )
rband.setWidth( qgsLineWidth[0] )
return rband
def createSnapVertexMarker(self):
"""Function creates vertexMarker that is used for marking feature
to which snapping was done.
@return vertex marker - QgsVertexMarker object
"""
# get qgis settings
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
verMarker=QgsVertexMarker(self.canvas)
verMarker.setIconType(2)
verMarker.setIconSize(13)
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
verMarker.setPenWidth(qgsLineWidth[0])
verMarker.setCenter(QgsPoint(-1000,-1000))
return verMarker
def createSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping of this snapper is done to all segments and vertexes
of all three layers of current OSM database.
@param canvasRenderer renderer of current map canvas
@return instance of vertex+segment QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(self.canvas.mapRenderer())
snapper=QgsSnapper(self.canvas.mapRenderer())
snapLayers=[]
# snap to osm layers from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def deactivate(self):
"""Functions is called when create polygon map-tool is being deactivated.
Function performs standard cleaning; re-initialization etc.
"""
self.polygonRubBand.reset(True)
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappingEnabled=True
self.lastPointIsStable=True
self.polygonPoints=[]
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.createPolygonButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
def keyPressEvent(self, event):
"""This function is called after keyPressEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was pressed, function disables snapping til key is released again.
@param event event that occured when key pressing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = False
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappedPoint=None
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
def keyReleaseEvent(self, event):
"""This function is called after keyReleaseEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was released, function enables snapping again.
@param event event that occured when key releasing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON - hold Ctrl to disable it.")
def canvasMoveEvent(self, event):
"""This function is called when mouse moving.
@param event event that occured when mouse moving.
"""
self.mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
if len(self.polygonPoints)>0:
if not self.lastPointIsStable:
self.polygonRubBand.removeLastPoint()
self.polygonRubBand.addPoint(QgsPoint(self.mapPoint.x(),self.mapPoint.y()))
self.lastPointIsStable=False
if not self.snappingEnabled:
self.snapVerMarker.setCenter(self.mapPoint)
return
# snapping! first reset old snapping vertexMarker
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
# try snapping to the closest vertex/segment
(retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])
if len(snappingResults)==0:
self.snapVerMarker.setCenter(self.mapPoint)
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
if self.dockWidget.feature:
self.dockWidget.clear()
return
# process snapping result (get point, set rubberband)
self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
self.snapVerMarker.setCenter(self.snappedPoint)
if len(self.polygonPoints)>0:
self.polygonRubBand.removeLastPoint()
self.polygonRubBand.addPoint(QgsPoint(self.snappedPoint.x(),self.snappedPoint.y()))
# start identification
feature=self.dbm.findFeature(self.snappedPoint)
if feature:
(self.snapFeat,self.snapFeatType)=feature
if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)
def canvasReleaseEvent(self, event):
"""This function is called after mouse button releasing when using this map tool.
If left button is released new vertex of polygon is created (pre-created).
If right button is released the whole process of polygon creation is finished.
@param event event that occured when button releasing
"""
# we are interested only in left/right button clicking
if event.button() not in (Qt.LeftButton,Qt.RightButton):
return
if event.button()==Qt.LeftButton:
# where we are exactly?
actualMapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
# what point will be the next polygon member?
newPolygonPoint=actualMapPoint
if self.snappedPoint:
newPolygonPoint=self.snappedPoint
# add new point into rubberband (and removing last one if neccessary) and into new polygon members list
if not self.lastPointIsStable:
self.polygonRubBand.removeLastPoint()
self.lastPointIsStable=True
self.polygonRubBand.addPoint(newPolygonPoint)
self.polygonPoints.append((newPolygonPoint,self.snapFeat,self.snapFeatType))
# right button clicking signalizes the last line member!
elif event.button()==Qt.RightButton:
# polygon must have at least three member points (triangle)
if len(self.polygonPoints)<3:
self.polygonRubBand.reset(True)
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.lastPointIsStable=True
self.polygonPoints=[]
return
self.ur.startAction("Create a polygon.")
# call function of database manager that will create new polygon
(polyg,affected)=self.dbm.createPolygon(self.polygonPoints)
self.ur.stopAction(affected)
self.dbm.recacheAffectedNow(affected)
if polyg:
self.dockWidget.loadFeature(polyg,'Polygon',2)
# cleaning..
self.polygonRubBand.reset(True)
self.polygonPoints=[]
# after polygon creation canvas must be refresh so that changes take effect on map
self.canvas.refresh()

View File

@ -0,0 +1,292 @@
"""@package IdentifyMapTool
This module holds all structures and methods required to perform
"identify feature" operation on current OSM data.
When feature is identified its id, type, timestamp, owner, properties/tags, relations are loaded
into OSM Feature widget. Feature is also marked with rubberband (or vertexmarker for points) on map.
If you want to identify some feature, just left-click on it.
If OSM Plugin marked wrong feature after that, repeat RIGHT-clicking til the right one is marked.
(Right-clicking gives you one by one each feature that is in the place where left-click was done.)
If no feature is marked after your left-clicking, you missed the feature :-) Try again.
If you are not able to hit any feature, be sure that map data you are trying to identify are the current OSM data.
If they are, maybe there is something wrong in your QGIS settings. Be sure that there aren't too small values
in QGIS Settings -> Digitalization -> Tolerance/Snapping.
If you've just identified the wrong feature or want to identify a new one,
just left-click to continue the identification process.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
class IdentifyMapTool(QgsMapTool):
"""This class holds all structures and methods required to perform
"identify feature" operation on current OSM data.
When feature is identified its id, type, timestamp, owner, properties/tags, relations are loaded
into OSM Feature widget. Feature is also marked with rubberband (or vertexmarker for points) on map.
If you want to identify some feature, just left-click on it.
If OSM Plugin marked wrong feature after that, repeat RIGHT-clicking til the right one is marked.
(Right-clicking gives you one by one each feature that is in the place where left-click was done.)
If no feature is marked after your left-clicking, you missed the feature :-) Try again.
If you are not able to hit any feature, be sure that map data you are trying to identify are the current OSM data.
If they are, maybe there is something wrong in your QGIS settings. Be sure that there aren't too small values
in QGIS Settings -> Digitalization -> Tolerance/Snapping.
If you've just identified the wrong feature or want to identify a new one,
just left-click to continue the identification process.
"""
def __init__(self, canvas, dockWidget, dbManager):
"""The constructor.
Initializes the map tool.
@param canvas map canvas
@param dockWidget pointer to the main widget (OSM Feature widget) of OSM Plugin
@param dbManager pointer to instance of DatabaseManager; for communication with sqlite3 database
"""
QgsMapTool.__init__(self,canvas)
self.canvas=canvas
self.dockWidget=dockWidget
self.dbm=dbManager
self.moves=0
self.pause=False
self.doubleclick=False
self.featuresFound=[]
self.ixFeature=0
self.dlgSelect=QDialog(self.dockWidget)
self.dlgSelect.setWindowTitle("Feature identification")
butBox=QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,Qt.Horizontal,self.dlgSelect)
self.lw=QListWidget(self.dlgSelect)
layout=QVBoxLayout(self.dlgSelect)
layout.addWidget(self.lw)
layout.addWidget(butBox)
self.dlgSelect.setLayout(layout)
QObject.connect(butBox,SIGNAL("accepted()"),self.onSelectDlgOK)
QObject.connect(butBox,SIGNAL("rejected()"),self.onSelectDlgCancel)
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function does re-initialization of maptool.
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.pause=False
self.doubleclick=False
self.featuresFound=[]
self.ixFeature=0
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def canvasDoubleClickEvent(self,event):
"""This function is called after doubleclick is done on map when using this map tool.
Function is interested into left-doubleclicking only.
It finds out all features that are currently at the place where doubleclick was done.
Then it shows simple dialog with the list of all these features. User can select the required one
and close dialog.
Selected feature is then loaded into OSM Feature widget.
@param event event that occured when double clicking
"""
if event.button()<>Qt.LeftButton:
return
self.dockWidget.clear()
# find out map coordinates from mouse click
mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
# display modal dialog with features selection
self.featuresFound=self.dbm.findAllFeatures(mapPoint)
self.ixFeature=0
lwItems=[]
for f in self.featuresFound:
feat=f[0]
featType=f[1]
name=self.dbm.getTagValue(feat.id(),featType,"name")
lwItems.append(QString("[%1] ").arg(feat.id()).append(featType).append(QString(" ")).append(name))
self.lw.clear()
self.lw.addItems(lwItems)
self.pause=False
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
self.doubleclick=True
# continue only if OK button was clicked
if self.dlgSelect.exec_()==0:
return
def canvasReleaseEvent(self,event):
"""This function is called after mouse button is released on map when using this map tool.
It finds out all features that are currently at place where releasing was done.
OSM Plugin then marks the first of them. User can repeat right-clicking to mark
the next one, the next one, the next one... periodically...
Note that only one feature is marked at a time.
Each marked feature is also loaded into OSM Feature widget.
@param event event that occured when button releasing
"""
if self.doubleclick:
self.doubleclick=False
return
# we are interested only in left/right button clicking
if event.button() not in (Qt.LeftButton,Qt.RightButton):
return
# find out map coordinates from mouse click
mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
if event.button()==Qt.LeftButton:
if self.pause:
self.pause=False
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
self.featuresFound=[]
self.ixFeature=0
return
# start identification
self.featuresFound=self.dbm.findAllFeatures(mapPoint)
self.ixFeature=0
if len(self.featuresFound)>0:
self.pause=True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("PAUSED. Left-click to continue.")
(feat,featType)=self.featuresFound[self.ixFeature]
self.dockWidget.loadFeature(feat,featType,2)
elif self.dockWidget.feature:
self.dockWidget.clear()
elif event.button()==Qt.RightButton:
if len(self.featuresFound)<1:
return
self.ixFeature=self.ixFeature+1
if self.ixFeature>=len(self.featuresFound):
self.ixFeature=0
(feat,featType)=self.featuresFound[self.ixFeature]
self.dockWidget.loadFeature(feat,featType,2)
def canvasMoveEvent(self,event):
"""This function is called after mouse moving.
Feature are marked and loaded dynamically when going over them.
@param event event that occured when mouse moving.
"""
if self.pause:
return
if self.moves<>1:
self.moves=self.moves+1
return
self.moves=0
# find out map coordinates from mouse click
mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
# start identification
feature=self.dbm.findFeature(mapPoint)
if feature:
(feat,featType)=feature
if not self.dockWidget.feature or feat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(feat,featType,1)
elif self.dockWidget.feature:
self.dockWidget.clear()
def onSelectDlgOK(self):
"""This function handles clicking on OK button of selection dialog.
"""
self.dlgSelect.close()
if not self.lw.currentItem():
return
self.ixFeature=self.lw.currentRow()
(feat,featType)=self.featuresFound[self.ixFeature]
if feat:
self.dockWidget.loadFeature(feat,featType,2)
self.pause=True
def onSelectDlgCancel(self):
"""This function handles clicking on Cancel button of selection dialog.
"""
self.dlgSelect.close()
def deactivate(self):
"""Functions is called when identify-map-tool is being deactivated.
It performs standard cleaning;
re-initialization etc.
"""
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.identifyButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
self.pause=False
self.doubleclick=False
self.dockWidget.clear()
self.featuresFound=[]
self.ixFeature=0

View File

@ -0,0 +1,768 @@
"""@package MoveMapTool
This module holds all structures and methods required to perform move operation on OSM data.
Snapping to existing features is supported when moving a feature.
Moving process generates some rubberBands and vertexMarkers so that user can watch
the whole action on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog. Affected features are dynamically
loaded to it; thanks to that user is not confused about what (s)he is moving.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
from math import *
class MoveMapTool(QgsMapTool):
"""This class represents map tool for feature moving (see QgsMapTool from Quantum GIS API).
It enables to move any OSM feature. User is expected to left click, select and move... The second phase (selecting)
is necessary, because there can be more than one feature at the same place.
At the beginning of action left-click is used to choose the position on the map.
Repeatable right-clicking is then used to select required feature from specified position.
After that mouse moving moves selected feature.
The last action is left-clicking again (that confirms the moving operation) or right-clicking (canceling operation).
Snapping to existing features is supported when moving a feature. When moving a line/polygon, only three closest
vertexes to the mouse position can be snapped. If snapping is enabled for all vertexes, operation will be very slow
on features with many vertexes.
When moving a point (also vertex of line/polygon) snapping to both vertexes and segments is done.
When moving a line/polygon snapping to vertexes is supported only.
Moving process generates some rubberBands and vertexMarkers so that user can watch
the whole action on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog. Affected features are dynamically
loaded to it; thanks to that user is not confused about what (s)he is moving.
Map tool catches the signal of changing OSM database. It such case not-ended operation is canceled.
"""
def __init__(self, plugin):
"""The constructor.
Initializes the map tool, creates necessary snappers.
@param plugin pointer to OSM Plugin instance
"""
QgsMapTool.__init__(self,plugin.canvas)
self.canvas=plugin.canvas
self.dockWidget=plugin.dockWidget
self.dbm=plugin.dbm
self.ur=plugin.undoredo
# init info about feature that is being moved!
self.mapPointFrom=None
self.mapPointTo=None
self.movFeatType=None
self.movFeat=None
self.movIsPolygon=False
self.movIndexes=[]
self.snapDeltas=None
self.snapVertexIx=None
self.snapFeat=None
self.snapFeatType=None
# init variables that keeps system state
self.snappingEnabled=True
self.doubleclick=False
self.movingMode="INTRO" # -> "SELECTION" -> "MOVING"
self.moves=0
self.featuresFound=[]
self.ixFeature=0
# init objects to display on canvas
self.rubBands=[] # rubBands of neighbour (non-point) feats that are also affected by moving operation
self.isPolygonFlags=[] # isPolygon flags for self.rubBands[]
self.memberIndexes=[]
self.snapRubBand=self.__createSnapRubberband() # creating rubberband for snapped objects
self.verMarker=self.__createVertexMarker() # creating vertex marker for point moving
# creating Vertex & Segment snapper + creating Vertex (only!) snapper
self.snapperVS=self.__createVSSnapper(self.canvas.mapRenderer())
self.snapperV=self.__createVSnapper(self.canvas.mapRenderer())
# create dialog with feature selection
self.dlgSelect=QDialog(self.dockWidget)
self.dlgSelect.setWindowTitle("Feature identification")
butBox=QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,Qt.Horizontal,self.dlgSelect)
self.lw=QListWidget(self.dlgSelect)
layout=QVBoxLayout(self.dlgSelect)
layout.addWidget(self.lw)
layout.addWidget(butBox)
self.dlgSelect.setLayout(layout)
# set dialog signals
QObject.connect(butBox,SIGNAL("accepted()"),self.__onSelectDlgOK)
QObject.connect(butBox,SIGNAL("rejected()"),self.__onSelectDlgCancel)
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def reinit(self):
"""Function re-initializes the map tool, prepare necessary rubberbands again.
After calling this function, move map tool is in the same state as after its creation.
"""
# reinit info about feature that is being moved!
self.mapPointFrom=None
self.mapPointTo=None
self.movFeatType=None
self.movFeat=None
self.movIsPolygon=False
self.movIndexes=[]
self.snapDeltas=None
self.snapVertexIx=None
self.snapFeat=None
self.snapFeatType=None
# reinit variables that keeps system state
self.snappingEnabled=True
self.doubleclick=False
self.movingMode="INTRO" # -> "SELECTION" -> "MOVING"
self.moves=0
self.featuresFound=[]
self.ixFeature=0
# reinit objects to display on canvas
for ix in range(0,len(self.rubBands)):
self.rubBands[ix].reset(self.isPolygonFlags[ix])
del self.rubBands
self.rubBands=[] # rubBands of neighbour feats that are also affected by moving operation
del self.isPolygonFlags
del self.memberIndexes
self.isPolygonFlags=[] # isPolygon flags for self.rubBands[]
self.memberIndexes=[]
self.snapRubBand.reset() # todo: ??? polygon ???
del self.snapRubBand
self.snapRubBand=self.__createSnapRubberband() # recreating rubberband for snapped objects
self.verMarker.setCenter(QgsPoint(-1000,-1000))
del self.verMarker
self.verMarker=self.__createVertexMarker() # recreating vertex marker for point moving
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function calls re-initialization of maptool and create new snappers again.
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.reinit()
# plus creation of new snappers
if dbKey:
del self.snapperVS
self.snapperVS=self.__createVSSnapper(self.canvas.mapRenderer())
del self.snapperV
self.snapperV=self.__createVSnapper(self.canvas.mapRenderer())
def __createFeatRubberband(self,isPolygon):
"""Function creates rubberband that is used for marking moved feature on the map.
@param isPolygon is hint for this function; it says if feature is of polygon type or not
@return rubberband for marking moved feature on the map
"""
# get qgis settings of line width and color for rubberband
settings=QSettings()
qgsLineWidth=settings.value( "/qgis/digitizing/line_width", QVariant(10) ).toInt()
qgsLineRed=settings.value( "/qgis/digitizing/line_color_red", QVariant(255) ).toInt()
qgsLineGreen=settings.value( "/qgis/digitizing/line_color_green", QVariant(0) ).toInt()
qgsLineBlue=settings.value( "/qgis/digitizing/line_color_blue", QVariant(0) ).toInt()
rband=QgsRubberBand(self.canvas,isPolygon)
rband.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
rband.setWidth( qgsLineWidth[0] )
return rband
def __createSnapRubberband(self):
"""Function creates rubberband that is used for marking map features
to which snapping will be performed.
@return rubberband for marking map features
"""
# get qgis settings of line width and color for rubberband
settings=QSettings()
qgsLineWidth=settings.value( "/qgis/digitizing/line_width", QVariant(10) ).toInt()
rband=QgsRubberBand(self.canvas,False)
rband.setColor(QColor(255,0,0))
rband.setWidth(qgsLineWidth[0])
return rband
def __createVertexMarker(self):
"""Function creates vertexMarker that is used for marking moved feature (point) on the map.
@return vertex marker for marking moved feature on map
"""
# get qgis settings
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
verMarker=QgsVertexMarker(self.canvas)
verMarker.setIconType(2)
verMarker.setIconSize(13)
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
verMarker.setPenWidth(qgsLineWidth[0])
verMarker.setCenter(QgsPoint(-1000,-1000))
return verMarker
def __createVSSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping of this snapper is done to all segments and vertexes
of all three layers of current OSM database.
@param canvasRenderer renderer of current map canvas
@return instance of vertex+segment QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(canvasRenderer)
snapper=QgsSnapper(canvasRenderer)
snapLayers=[]
# snap to osm layers from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,canvasRenderer)
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,canvasRenderer)
sLayer.mSnapTo=QgsSnapper.SnapToVertexAndSegment
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,canvasRenderer)
sLayer.mSnapTo=QgsSnapper.SnapToVertexAndSegment
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def __createVSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping of this snapper is done to all vertexes (but not segments)
of all three layers of current OSM database.
@param canvasRenderer renderer of current map canvas
@return instance of vertex QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(canvasRenderer)
snapper=QgsSnapper(canvasRenderer)
snapLayers=[]
# snap to osm layers from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,canvasRenderer)
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,canvasRenderer)
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def deactivate(self):
"""Functions is called when move-map-tool is being deactivated.
Function performs standard cleaning; re-initialization etc.
"""
self.reinit()
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.moveButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
def keyPressEvent(self, event):
"""This function is called after keyPressEvent(QKeyEvent *) signal is emmited when using move map tool.
If Control key was pressed, function disables snapping til key is released.
@param event event that occured when key pressing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled=False
self.snapRubBand.reset()
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
def keyReleaseEvent(self, event):
"""This function is called after keyReleaseEvent(QKeyEvent *) signal is emmited when using move map tool.
If Control key was released, function enables snapping again.
@param event event that occured when key releasing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON - hold Ctrl to disable it.")
def canvasDoubleClickEvent(self,event):
"""This function is called after doubleclick on map when using move map tool.
Function is interested into left-doubleclicking only.
It finds out all features that are currently at the place where doubleclick was done.
Then it shows simple dialog with the list of all these features. User can select the required one,
close dialog and continue moving.
@param event event that occured when double clicking
"""
if event.button()<>Qt.LeftButton:
return
self.dockWidget.clear()
#self.removeMarkers()
# find out map coordinates from mouse click
mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
# display modal dialog with features selection
self.featuresFound=self.dbm.findAllFeatures(mapPoint)
self.ixFeature=0
lwItems=[]
for f in self.featuresFound:
feat=f[0]
featType=f[1]
name=self.dbm.getTagValue(feat.id(),featType,"name")
lwItems.append(QString("[%1] ").arg(feat.id()).append(featType).append(QString(" ")).append(name))
self.lw.clear()
self.lw.addItems(lwItems)
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
self.doubleclick=True
if self.dlgSelect:
# continue only if OK button was clicked
if self.dlgSelect.exec_()==0:
return
def canvasReleaseEvent(self, event):
"""This function is called after mouse button releasing on map when using move map tool.
Such button releasing can have a lot of meanings.
It depends on the current phase of moving. See documentation of the whole move map tool
to know how moving works and how many times user has to release the mouse button to perform the whole moving.
@param event event that occured when button releasing
"""
if self.doubleclick:
self.doubleclick=False
return
if self.movingMode=="INTRO":
# we are interested only in left button clicking
if event.button()<>Qt.LeftButton:
return
# find out map coordinates from mouse click
self.mapPointFrom = self.dockWidget.canvasToOsmCoords(event.pos())
# what to move?
self.featuresFound=self.dbm.findAllFeatures(self.mapPointFrom)
self.ixFeature=0
if len(self.featuresFound)>0:
self.movingMode="SELECTION"
(feat,featType)=self.featuresFound[self.ixFeature]
self.dockWidget.loadFeature(feat,featType,2)
elif self.dockWidget.feature:
self.dockWidget.clear()
self.mapPointFrom=None
return
elif self.movingMode=="SELECTION":
# we are interested only in left/right button clicking
if event.button() not in (Qt.LeftButton,Qt.RightButton):
return
if event.button()==Qt.RightButton:
if len(self.featuresFound)<1:
return
self.ixFeature=self.ixFeature+1
if self.ixFeature>=len(self.featuresFound):
self.ixFeature=0
(feat,featType)=self.featuresFound[self.ixFeature]
self.dockWidget.loadFeature(feat,featType,2)
else: # LeftButton
self.reinit()
if self.dockWidget.feature:
self.dockWidget.clear()
elif self.movingMode=="MOVING":
# finish feature moving
# we are interested only in left button clicking; other buttons just cancel moving operation
if event.button()<>Qt.LeftButton:
self.reinit()
return
whereIAm = self.dockWidget.canvasToOsmCoords(event.pos())
if self.snapDeltas:
self.mapPointTo=QgsPoint(whereIAm.x()+self.snapDeltas[0],whereIAm.y()+self.snapDeltas[1])
else:
# no snapping for this moving
self.snapVertexIx=-1
self.mapPointTo=whereIAm
deltaX=self.mapPointTo.x()-self.mapPointFrom.x()
deltaY=self.mapPointTo.y()-self.mapPointFrom.y()
self.__finishFeatureMoving(deltaX,deltaY)
def __tryIdentifyFeature(self,event):
"""Function just finds first feature at the place when event occured.
Feature is marked on map with rubberBand (or vertexMarker) and is loaded to OSM Feature widget.
@param event event that occured
"""
# find out map coordinates from mouse click
mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
feature=self.dbm.findFeature(mapPoint)
if feature:
(feat,featType)=feature
if not self.dockWidget.feature or feat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(feat,featType,1)
elif self.dockWidget.feature:
self.dockWidget.clear()
def canvasMoveEvent(self,event):
"""This function is called after mouse moving.
Mouse moving is ignored before feature (to move) is selected.
@param event event that occured when mouse moving.
"""
# ignore one move from each two moves
if self.moves<>1:
self.moves=self.moves+1
return
self.moves=0
if self.movingMode=="INTRO":
self.__tryIdentifyFeature(event)
return
if self.movingMode=="SELECTION":
# remember what to move
self.movFeat=self.featuresFound[self.ixFeature][0]
self.movFeatType=self.featuresFound[self.ixFeature][1]
self.movIsPolygon=False
self.featuresFound=[]
self.ixFeature=0
# initializing rubberbands
if self.movFeatType in ('Polygon','Line'):
layer=self.dbm.lineLayers[self.dbm.currentKey]
if self.movFeatType=='Polygon':
self.movIsPolygon=True
layer=self.dbm.polygonLayers[self.dbm.currentKey]
# finding out three closest vertexes (for these snapping will be enabled)
self.movIndexes=[]
(p,ix,ixB,ixA,dis)=self.movFeat.geometry().closestVertex(self.mapPointFrom)
self.movIndexes.append(ix)
self.movIndexes.append(ixB)
self.movIndexes.append(ixA)
rubBand=self.__createFeatRubberband(self.movIsPolygon)
rubBand.setToGeometry(self.movFeat.geometry(),layer)
self.rubBands.append(rubBand)
self.isPolygonFlags.append(self.movIsPolygon)
elif self.movFeatType in ('Point'):
# find out parent features
(parentFeats,self.memberIndexes,self.isPolygonFlags)=self.dbm.getNodeParents(self.movFeat)
self.movParentVertices=[]
if len(parentFeats)==0:
self.verMarker.setCenter(self.movFeat.geometry().asPoint())
for ix in range(0,len(parentFeats)):
layer=None
if self.isPolygonFlags[ix]:
layer=self.dbm.polygonLayers[self.dbm.currentKey]
self.movParentVertices=self.movParentVertices+(parentFeats[ix].geometry().asPolygon())[0]
else:
layer=self.dbm.lineLayers[self.dbm.currentKey]
self.movParentVertices=self.movParentVertices+parentFeats[ix].geometry().asPolyline()
parentRubBand=self.__createFeatRubberband(self.isPolygonFlags[ix])
parentRubBand.setToGeometry(parentFeats[ix].geometry(),layer)
self.rubBands.append(parentRubBand)
if self.dockWidget.feature:
self.dockWidget.clear()
# change moving mode to the last one!
self.movingMode="MOVING"
# movingMode ~ "MOVING"
if self.movFeatType=='Point':
(deltaX,deltaY)=self.__getDeltaForPoint(event) # snapping is done in this function
targetPoint=QgsPoint(self.mapPointFrom.x()+deltaX,self.mapPointFrom.y()+deltaY)
if len(self.rubBands)==0:
point=self.movFeat.geometry().asPoint()
self.verMarker.setCenter(QgsPoint(point.x()+deltaX,point.y()+deltaY))
# move rubberbands
for ix in range(0,len(self.rubBands)):
for j in range(0,len(self.memberIndexes[ix])):
vertexIx=self.memberIndexes[ix][j]
lastVertexIx=self.rubBands[ix].numberOfVertices()-1
self.rubBands[ix].movePoint(vertexIx,targetPoint)
if self.isPolygonFlags[ix]:
if vertexIx==1:
self.rubBands[ix].movePoint(lastVertexIx,targetPoint)
elif vertexIx==lastVertexIx:
self.rubBands[ix].movePoint(vertexIx,targetPoint)
if vertexIx==1:
self.rubBands[ix].movePoint(0,targetPoint)
elif self.movFeatType in ('Line','Polygon'):
(deltaX,deltaY)=self.__getDeltaForLinePolygon(event)
# move feature rubberband
self.rubBands[0].setTranslationOffset(deltaX,deltaY)
def __getDeltaForPoint(self,event):
"""Function gets an event object, performs snapping from place where event occured and then counts distance
of found position from the place where the whole moving operation has started.
Special version for points.
@param event event that occured
"""
# find out where and how far (from the place where moving was started) we are now
mapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
if not self.snappingEnabled:
self.snapDeltas=self.snapFeat=self.snapFeatType=None
# returns how far from the place where moving was started we are now
return (mapPoint.x()-self.mapPointFrom.x(),mapPoint.y()-self.mapPointFrom.y())
# perform snapping
self.movParentVertices.append(self.movFeat.geometry().asPoint())
(retval,snappingResults)=self.snapperVS.snapPoint(event.pos(),self.movParentVertices)
if len(snappingResults)==0:
self.snapDeltas=self.snapFeat=self.snapFeatType=None
# returns how far from the place where moving was started we are now
return (mapPoint.x()-self.mapPointFrom.x(),mapPoint.y()-self.mapPointFrom.y())
# we snapped successfully to something
snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
self.snapDeltas=(snappedPoint.x()-mapPoint.x(),snappedPoint.y()-mapPoint.y())
# use snappingResults[0].layer in findFeature() ??? findFeatureInLayer() ???
(self.snapFeat,self.snapFeatType)=self.dbm.findFeature(snappedPoint)
# returns how far from the place where moving was started we are now
return (snappedPoint.x()-self.mapPointFrom.x(),snappedPoint.y()-self.mapPointFrom.y())
def __getDeltaForLinePolygon(self,event):
"""Function gets an event object, performs snapping from place where event occured and then counts distance
of found position from the place where the whole moving operation has started.
Special version for lines and polygons.
@param event event that occured
"""
# find out where and how far (from the place where moving was started) we are now
mapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
deltaX=mapPoint.x()-self.mapPointFrom.x()
deltaY=mapPoint.y()-self.mapPointFrom.y()
if not self.snappingEnabled:
self.snapDeltas=self.snapFeat=self.snapFeatType=None
return (deltaX,deltaY)
lineMembers=[]
for ix in self.movIndexes:
lineMembers.append(self.movFeat.geometry().vertexAt(ix))
allMembers=[]
if self.movFeatType=='Line':
allMembers=self.movFeat.geometry().asPolyline()
else:
polygon=self.movFeat.geometry().asPolygon()
allMembers=polygon[0]
minDistance=99999
bestSnappedPoint=None
bestActualLineMember=None
for i in range(0,len(lineMembers)):
actualLineMember=QgsPoint(lineMembers[i].x()+deltaX,lineMembers[i].y()+deltaY)
point=self.canvas.getCoordinateTransform().transform(actualLineMember)
(retval,snappingResults)=self.snapperV.snapPoint(QPoint(point.x(),point.y()),allMembers)
if len(snappingResults)>0:
snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
dX=snappedPoint.x()-(actualLineMember.x()+deltaX)
dY=snappedPoint.y()-(actualLineMember.y()+deltaY)
dist=sqrt(pow(dX,2)+pow(dY,2)) # pythagoras ;)
if dist<minDistance:
minDistance=dist
bestSnappedPoint=snappedPoint
bestActualLineMember=actualLineMember
self.snapVertexIx=self.movIndexes[i]
if not bestSnappedPoint:
self.snapDeltas=self.snapFeat=self.snapFeatType=None
return (deltaX,deltaY)
self.snapDeltas=(bestSnappedPoint.x()-bestActualLineMember.x(),bestSnappedPoint.y()-bestActualLineMember.y())
# use snappingResults[0].layer in findFeature() ??? findFeatureInLayer() ???
(self.snapFeat,self.snapFeatType)=self.dbm.findFeature(bestSnappedPoint)
return (deltaX+self.snapDeltas[0],deltaY+self.snapDeltas[1])
def __finishFeatureMoving(self,deltaX,deltaY):
"""It finishes the whole moving process.
Function also refreshes map canvas.
@param deltaX distance from target position (of moving) to start position on X axis
@param deltaY distance from target position (of moving) to start position on Y axis
"""
affected=set()
if self.movFeatType=="Point":
self.ur.startAction("Move a point.")
affected=self.dbm.movePoint(self.movFeat,deltaX,deltaY,self.snapFeat,self.snapFeatType)
elif self.movFeatType=="Line":
self.ur.startAction("Move a line.")
affected=self.dbm.moveLine(self.movFeat,deltaX,deltaY,self.snapFeat,self.snapFeatType,self.snapVertexIx)
elif self.movFeatType=="Polygon":
self.ur.startAction("Move a polygon.")
affected=self.dbm.movePolygon(self.movFeat,deltaX,deltaY,self.snapFeat,self.snapFeatType,self.snapVertexIx)
self.ur.stopAction(affected)
self.dbm.recacheAffectedNow(affected)
self.dockWidget.loadFeature(self.movFeat,self.movFeatType,0)
self.reinit()
# reload map canvas so that changes take effect
self.canvas.refresh()
def __onSelectDlgOK(self):
"""This function handles clicking on OK button of selection dialog.
"""
self.dlgSelect.close()
if not self.lw.currentItem():
return
self.ixFeature=self.lw.currentRow()
(feat,featType)=self.featuresFound[self.ixFeature]
if feat:
self.dockWidget.loadFeature(feat,featType,2)
def __onSelectDlgCancel(self):
"""This function handles clicking on Cancel button of selection dialog.
"""
self.dlgSelect.close()

View File

View File

@ -0,0 +1,333 @@
"""@package osm_plugin
This is the main module of the OSM Plugin.
It shows/hides all tool buttons, widgets and dialogs.
After closing dialogs it does all actions related with their return codes.
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
from qgis.core import *
from DlgLoadOSM import DlgLoadOSM
from DlgSaveOSM import DlgSaveOSM
from DlgDownloadOSM import DlgDownloadOSM
from DlgUploadOSM import DlgUploadOSM
from DlgImport import DlgImport
from DockWidget import *
from DockUndoRedo import *
# initialize Qt resources from file resouces.py
import resources
class OSMPlugin:
"""OSMPlugin is the main class OSM Plugin module.
It shows/hides all tool buttons, widgets and dialogs and after closing dialogs
it does all actions related with their return codes.
"""
def __init__(self, iface):
"""The constructor.
@param iface QgisInterface object
"""
self.iface=iface
self.canvas=self.iface.mapCanvas()
self.http=QHttp()
self.outFile=None
self.httpGetId=0
self.httpRequestAborted=False
self.fname=""
def initGui(self):
"""Function initalizes GUI of the OSM Plugin.
"""
self.dockWidgetVisible = False
# create action for loading OSM file
self.actionLoad=QAction(QIcon(":/plugins/osm_plugin/images/osm_load.png")
,"Load OSM from file", self.iface.mainWindow())
self.actionLoad.setWhatsThis("Load OpenStreetMap from file")
# create action for import of a layer into OSM
self.actionImport=QAction(QIcon(":/plugins/osm_plugin/images/osm_import.png")
,"Import data from a layer", self.iface.mainWindow())
self.actionImport.setWhatsThis("Import data from a layer to OpenStreetMap")
# create action for saving OSM file
self.actionSave=QAction(QIcon(":/plugins/osm_plugin/images/osm_save.png")
,"Save OSM to file", self.iface.mainWindow())
self.actionSave.setWhatsThis("Save OpenStreetMap to file")
# create action for OSM data downloading
self.actionDownload=QAction(QIcon(":/plugins/osm_plugin/images/osm_download.png")
,"Download OSM data", self.iface.mainWindow())
self.actionDownload.setWhatsThis("Download OpenStreetMap data")
# create action for OSM data downloading
self.actionUpload=QAction(QIcon(":/plugins/osm_plugin/images/osm_upload.png")
,"Upload OSM data", self.iface.mainWindow())
self.actionUpload.setWhatsThis("Upload OpenStreetMap data")
# create action for OSM dockable window
self.actionDockWidget=QAction(QIcon(":/plugins/osm_plugin/images/osm_featureManager.png")
,"Show/Hide OSM Feature Manager",self.iface.mainWindow())
self.actionDockWidget.setWhatsThis("Show/Hide OpenStreetMap Feature Manager")
self.actionDockWidget.setCheckable(True)
# connect new action to plugin function - when action is triggered
QObject.connect(self.actionLoad, SIGNAL("triggered()"), self.loadOsmFromFile)
QObject.connect(self.actionSave, SIGNAL("triggered()"), self.saveOsmToFile)
QObject.connect(self.actionDownload, SIGNAL("triggered()"), self.downloadOsmData)
QObject.connect(self.actionUpload, SIGNAL("triggered()"), self.uploadOsmData)
QObject.connect(self.actionDockWidget, SIGNAL("triggered()"), self.showHideDockWidget)
QObject.connect(self.actionImport, SIGNAL("triggered()"), self.importData)
# create a toolbar
self.toolBar=self.iface.addToolBar("OpenStreetMap")
self.toolBar.setObjectName("OpenStreetMap")
self.toolBar.addAction(self.actionLoad)
self.toolBar.addAction(self.actionDockWidget)
self.toolBar.addAction(self.actionDownload)
self.toolBar.addAction(self.actionUpload)
self.toolBar.addAction(self.actionImport)
self.toolBar.addAction(self.actionSave)
# populate plugins menu
self.iface.addPluginToMenu("&OpenStreetMap", self.actionLoad)
self.iface.addPluginToMenu("&OpenStreetMap", self.actionDockWidget)
self.iface.addPluginToMenu("&OpenStreetMap", self.actionDownload)
self.iface.addPluginToMenu("&OpenStreetMap", self.actionUpload)
self.iface.addPluginToMenu("&OpenStreetMap", self.actionImport)
self.iface.addPluginToMenu("&OpenStreetMap", self.actionSave)
# create manager of sqlite database(-s)
self.dbm=DatabaseManager(self)
self.undoredo=None
self.dockWidget=None
# create widget for undo/redo actions
self.undoredo=DockUndoRedo(self)
self.iface.addDockWidget(Qt.LeftDockWidgetArea,self.undoredo)
self.undoredo.hide()
QObject.connect(self.undoredo,SIGNAL("visibilityChanged(bool)"),self.__urVisibilityChanged)
self.undoredo.setContentEnabled(False)
# create widget for osm feature info
self.dockWidget=DockWidget(self)
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)
QObject.connect(self.dockWidget,SIGNAL("visibilityChanged(bool)"),self.__ofVisibilityChanged)
self.dockWidget.setContentEnabled(False)
def unload(self):
"""Function unloads the OSM Plugin.
"""
# remove the plugin menu items
self.iface.removePluginMenu("&OpenStreetMap",self.actionLoad)
self.iface.removePluginMenu("&OpenStreetMap",self.actionSave)
self.iface.removePluginMenu("&OpenStreetMap",self.actionDownload)
self.iface.removePluginMenu("&OpenStreetMap",self.actionUpload)
self.iface.removePluginMenu("&OpenStreetMap",self.actionImport)
self.iface.removePluginMenu("&OpenStreetMap",self.actionDockWidget)
self.dockWidget.close()
if self.dockWidget.rubBand:
self.dockWidget.rubBand.reset(False)
if self.dockWidget.rubBandPol:
self.dockWidget.rubBandPol.reset(True)
self.undoredo.clear()
self.undoredo.close()
del self.dockWidget
del self.undoredo
# remove toolbar
del self.toolBar
def loadOsmFromFile(self):
"""Function shows up the "Load OSM from file" dialog.
After closing it, function calls the appropriate actions
according to dialog's return code.
"""
# sanity check whether we're able to load osm data
if 'osm' not in QgsProviderRegistry.instance().providerList():
QMessageBox.critical(None, "Sorry", "You don't have OSM provider installed!")
return
# show modal dialog with OSM file selection
self.dlgLoad=DlgLoadOSM(self)
# continue only if OK button was clicked
if self.dlgLoad.exec_()==0:
return
self.fname=self.dlgLoad.OSMFileEdit.text()
self.dbFileName=self.fname+".db"
self.dbm.addDatabase(self.dbFileName,self.dlgLoad.pointLayer,self.dlgLoad.lineLayer,self.dlgLoad.polygonLayer)
self.undoredo.clear()
self.dockWidget.setContentEnabled(True)
self.undoredo.setContentEnabled(True)
self.dataLoaded=True
def saveOsmToFile(self):
"""Function shows up the "Save OSM to file" dialog.
After closing it, function calls the appropriate actions
according to dialog's return code.
"""
if not self.dbm.currentKey:
QMessageBox.information(QWidget(), QString("OSM Save to file")
,"No OSM data are loaded/downloaded or no OSM layer is selected in Layers panel. \
Please change this situation first, because OSM Plugin doesn't know what to save.")
return
# show modal dialog with OSM file selection
self.dlgSave=DlgSaveOSM(self)
# continue only if OK button was clicked
if self.dlgSave.exec_()==0:
return
def downloadOsmData(self):
"""Function shows up the "Download OSM data" dialog.
After closing it, function calls the appropriate actions
according to dialog's return code.
"""
self.dlgDownload=DlgDownloadOSM(self)
self.dlgDownload.exec_()
if not self.dlgDownload.httpSuccess:
return
if not self.dlgDownload.autoLoadCheckBox.isChecked():
return
# create loading dialog, submit it
self.dlgLoad=DlgLoadOSM(self)
self.dlgLoad.setModal(True)
self.dlgLoad.show()
self.dlgLoad.close()
self.dlgLoad.OSMFileEdit.setText(self.dlgDownload.destdirLineEdit.text())
self.dlgLoad.styleCombo.setCurrentIndex(self.dlgDownload.styleCombo.currentIndex())
if self.dlgDownload.chkCustomRenderer.isChecked():
self.dlgLoad.chkCustomRenderer.setChecked(True)
else:
self.dlgLoad.chkCustomRenderer.setChecked(False)
for row in xrange(self.dlgLoad.lstTags.count()):
self.dlgLoad.lstTags.item(row).setCheckState(Qt.Checked)
if self.dlgDownload.chkReplaceData.isChecked():
self.dlgLoad.chkReplaceData.setChecked(True)
else:
self.dlgLoad.chkReplaceData.setChecked(False)
self.dlgLoad.onOK()
self.fname=self.dlgLoad.OSMFileEdit.text()
self.dbFileName=self.fname+".db"
self.dbm.addDatabase(self.dbFileName,self.dlgLoad.pointLayer,self.dlgLoad.lineLayer,self.dlgLoad.polygonLayer)
def uploadOsmData(self):
"""Function shows up the "Upload OSM data" dialog.
After closing it, function calls the appropriate actions
according to dialog's return code.
"""
# first check if there are some data; if not upload doesn't have sense
if not self.dbm.currentKey:
QMessageBox.information(QWidget(), QString("OSM Upload")
,"No OSM data are loaded/downloaded or no OSM layer is selected in Layers panel. \
Please change this situation first, because OSM Plugin doesn't know what to upload.")
return
self.dlgUpload=DlgUploadOSM(self)
self.dlgUpload.exec_()
def importData(self):
"""Function shows up the "Import OSM data" dialog.
After closing it, function calls the appropriate actions
according to dialog's return code.
"""
if self.dbm.currentKey is None:
QMessageBox.information(self.iface.mainWindow(), "OSM Import"
,"No OSM data are loaded/downloaded or no OSM layer is selected in Layers panel. \
Please change this situation first, because OSM Plugin doesn't know what layer will be destination of the import.")
return
dlg=DlgImport(self)
if dlg.cboLayer.count()==0:
QMessageBox.information(self.iface.mainWindow(), "OSM Import", "There are currently no available vector layers.")
return
dlg.exec_()
def showHideDockWidget(self):
"""Function shows/hides main dockable widget of the plugin ("OSM Feature" widget)
"""
if self.dockWidget.isVisible():
self.dockWidget.hide()
else:
self.dockWidget.show()
def __urVisibilityChanged(self):
"""Function is called after visibilityChanged(...) signal is emitted on OSM Edit History widget.
Function changes state of related checkbox according to the fact
if widget is currently visible of not.
"""
if self.undoredo.isVisible():
self.dockWidget.urDetailsButton.setChecked(True)
else:
self.dockWidget.urDetailsButton.setChecked(False)
def __ofVisibilityChanged(self):
"""Function is called after visibilityChanged(...) signal is emitted on OSM Feature widget.
Function changes state of appropriate tool button according to the fact
if widget is currently visible of not.
"""
if self.dockWidget.isVisible():
self.actionDockWidget.setChecked(True)
else:
self.actionDockWidget.setChecked(False)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
<RCC>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_load.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_import.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_save.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_download.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_upload.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_move.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_identify.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_createPolygon.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_createPoint.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_createLine.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_featureManager.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_createRelation.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_remove.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_star.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_questionMark.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_undo.png</file>
</qresource>
<qresource prefix="/plugins/osm_plugin" >
<file>images/osm_redo.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,34 @@
#LINE
highway trunk 3 1 150,0,0
highway primary 2 1 219,112,147
highway secondary 1 1 255,120,0
highway tertiary 0 0 238,230,133
highway pedestrian 0 0 255,255,0
highway residential 0 0 100,100,100
highway footway 0 0 170,170,170
highway * 1 1 210,200,210
railway subway 1 2 131,111,255
railway rail 1 4 0,0,0
railway * 1 0 0,0,0
boundary administrative 1 3 85,26,139
power line 1 0 139,139,131
#POLYGON
leisure park 0 1 0,0,0 88,245,168
leisure garden 0 1 0,0,0 88,245,168
landuse forest 0 1 0,0,0 88,245,168
landuse allotments 0 1 0,0,0 222,184,135
tourism zoo 0 1 0,0,0 108,255,185
building yes 0 1 0,0,0 226,226,226
natural water 0 1 0,0,0 135,206,255
waterway riverbank 0 1 0,0,0 135,206,255
place island 0 1 0,0,0 255,255,255
highway trunk 3 1 150,0,0 255,255,255
highway primary 2 1 219,112,147 255,255,255
highway secondary 1 1 255,120,0 255,255,255
highway tertiary 0 0 238,230,133 255,255,255
highway pedestrian 0 0 255,255,0 255,255,255
highway residential 0 0 100,100,100 255,255,255
highway footway 0 0 170,170,170 255,255,255
* * 1 1 0,0,255 255,255,255
#POINT
amenity hospital emergency/amenity=hospital.svg 6

View File

@ -0,0 +1,45 @@
#LINE
highway trunk 6 1 150,0,0
highway primary 6 1 219,112,147
highway secondary 4.5 1 255,120,0
highway tertiary 3 1 238,230,133
highway pedestrian 1 1 255,255,0
highway residential 1 1 100,100,100
highway footway 2 3 170,170,170
highway * 1 1 0,255,0
railway subway 1 2 131,111,255
railway rail 2 4 0,0,0
railway * 1 0 0,0,0
boundary administrative 2 3 85,26,139
power line 2 1 139,139,131
#POLYGON
leisure park 0 1 0,0,0 88,245,168
leisure garden 0 1 0,0,0 88,245,168
landuse forest 0 1 0,0,0 88,245,168
landuse allotments 0 1 0,0,0 222,184,135
tourism zoo 0 1 0,0,0 108,255,
building yes 0.01 1 0,0,0 226,226,226
natural water 0 1 0,0,0 135,206,255
waterway riverbank 0 1 0,0,0 135,206,255
place island 1 1 0,0,0 255,255,255
highway trunk 6 1 150,0,0 255,255,255
highway primary 6 1 219,112,147 255,255,255
highway secondary 4.5 1 255,120,0 255,255,255
highway tertiary 3 1 238,230,133 255,255,255
highway pedestrian 1 1 255,255,0 255,255,255
highway residential 1 1 100,100,100 255,255,255
highway footway 2 3 170,170,170 255,255,255
* * 1 1 0,0,255 255,255,255
#POINT
source:addr uir_adr gpsicons/house.svg 15
power tower symbol/Cross4.svg 15
amenity hospital emergency/amenity=hospital.svg 15
amenity parking transport/amenity=parking.svg 15
amenity bus_station transport/highway=bus_stop.svg 15
amenity restaurant entertainment/amenity=restaurant.svg 15
amenity theatre entertainment/amenity=theatre.svg 15
amenity pub entertainment/amenity=pub.svg 15
amenity fast_food entertainment/amenity=fast_food.svg 15
amenity cinema entertainment/amenity=cinema.svg 15
amenity cafe entertainment/amenity=cafe.svg 15
amenity bar entertainment/amenity=bar.svg 15

View File

@ -0,0 +1,48 @@
#LINE
highway trunk 4.3 1 150,0,0
highway primary 4.3 1 219,112,147
highway secondary 3.5 1 255,120,0
highway tertiary 2.2 1 238,230,133
highway pedestrian 0.8 1 255,255,0
highway residential 0.8 1 100,100,100
highway footway 1.4 3 170,170,170
highway * 1 1 0,255,0
railway subway 0.7 2 131,111,255
railway rail 1 4 0,0,0
railway tram 1 4 175,0,0
railway * 0.7 0 0,0,0
boundary administrative 2 3 85,26,139
power line 2 1 139,139,131
* * 1 1 200,200,200
#POLYGON
leisure park 0 1 0,0,0 88,245,168
leisure garden 0 1 0,0,0 88,245,168
landuse forest 0 1 0,0,0 88,245,168
landuse allotments 0 1 0,0,0 222,184,135
tourism zoo 0 1 0,0,0 108,255,185
building yes 0.01 1 0,0,0 226,226,226
natural water 0 1 0,0,0 135,206,255
waterway riverbank 0 1 0,0,0 135,206,255
place island 1 1 0,0,0 255,255,255
highway trunk 6 1 150,0,0 255,255,255
highway primary 6 1 219,112,147 255,255,255
highway secondary 4.5 1 255,120,0 255,255,255
highway tertiary 3 1 238,230,133 255,255,255
highway pedestrian 1 1 255,255,0 255,255,255
highway residential 1 1 100,100,100 255,255,255
highway footway 2 3 170,170,170 255,255,255
* * 1 1 0,0,255 255,255,255
#POINT
source:addr uir_adr gpsicons/point.svg 7
power tower symbol/Cross4.svg 10
amenity hospital emergency/amenity=hospital.svg 10
amenity parking transport/amenity=parking.svg 10
amenity bus_station transport/highway=bus_stop.svg 10
amenity restaurant entertainment/amenity=restaurant.svg 10
amenity theatre entertainment/amenity=theatre.svg 10
amenity pub entertainment/amenity=pub.svg 10
amenity fast_food entertainment/amenity=fast_food.svg 10
amenity cinema entertainment/amenity=cinema.svg 10
amenity cafe entertainment/amenity=cafe.svg 10
amenity bar entertainment/amenity=bar.svg 10
* * gpsicons/point.svg 7

View File

@ -0,0 +1,289 @@
<ui version="4.0" >
<class>DlgAddRelation</class>
<widget class="QDialog" name="DlgAddRelation" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>620</width>
<height>461</height>
</rect>
</property>
<property name="windowTitle" >
<string>Create OSM relation</string>
</property>
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="modal" >
<bool>false</bool>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Relation type:</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>24</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="typeCombo" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>164</width>
<height>24</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>164</width>
<height>16777215</height>
</size>
</property>
<property name="editable" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="typeInfoButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Properties</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="loadStandardTagsButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeTagButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="relTagsTable" >
<property name="minimumSize" >
<size>
<width>240</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Members</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="chooseMemberButton" >
<property name="text" >
<string>...</string>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeMemberButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="relMembersTable" >
<property name="minimumSize" >
<size>
<width>346</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="tagInfoTextEdit" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>140</height>
</size>
</property>
<property name="readOnly" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="createRelButton" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text" >
<string>Create</string>
</property>
<property name="autoDefault" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stornoButton" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text" >
<string>Storno</string>
</property>
<property name="autoDefault" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,375 @@
<ui version="4.0" >
<class>DlgDownloadOSM</class>
<widget class="QDialog" name="DlgDownloadOSM" >
<property name="windowModality" >
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>595</width>
<height>357</height>
</rect>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::NoContextMenu</enum>
</property>
<property name="windowTitle" >
<string>Download OSM data</string>
</property>
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="title" >
<string>Extent</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QGridLayout" >
<item row="0" column="1" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Latitude:</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string> From</string>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QLineEdit" name="latFromLineEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="4" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>To</string>
</property>
</widget>
</item>
<item row="0" column="5" >
<widget class="QLineEdit" name="latToLineEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Longitude:</string>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string> From</string>
</property>
</widget>
</item>
<item row="1" column="3" >
<widget class="QLineEdit" name="lonFromLineEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>To</string>
</property>
</widget>
</item>
<item row="1" column="5" >
<widget class="QLineEdit" name="lonToLineEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="extentInfoLabel" >
<property name="text" >
<string>&lt;nothing></string>
</property>
<property name="margin" >
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="helpButton" >
<property name="maximumSize" >
<size>
<width>23</width>
<height>23</height>
</size>
</property>
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<item row="0" column="0" colspan="2" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Download to:</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLineEdit" name="destdirLineEdit" >
<property name="enabled" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="choosedirButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="autoLoadCheckBox" >
<property name="text" >
<string>Open data automatically after download</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>15</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="chkReplaceData" >
<property name="text" >
<string>Replace current data (current layer will be removed)</string>
</property>
<property name="checked" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>15</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="chkCustomRenderer" >
<property name="text" >
<string>Use custom renderer</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="styleCombo" >
<property name="minimumSize" >
<size>
<width>182</width>
<height>0</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>182</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="downloadButton" >
<property name="text" >
<string>Download</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton" >
<property name="text" >
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,122 @@
<ui version="4.0" >
<class>DlgImport</class>
<widget class="QDialog" name="DlgImport" >
<property name="windowModality" >
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>248</width>
<height>228</height>
</rect>
</property>
<property name="windowTitle" >
<string>Import data to OSM</string>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>In this dialog you can import a layer loaded in QGIS into active OSM data.</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>29</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboLayer" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="chkOnlySelection" >
<property name="text" >
<string>Import only current selection</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>cboLayer</tabstop>
<tabstop>chkOnlySelection</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgImport</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>238</x>
<y>213</y>
</hint>
<hint type="destinationlabel" >
<x>247</x>
<y>227</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,163 @@
<ui version="4.0" >
<class>DlgLoadOSM</class>
<widget class="QDialog" name="DlgLoadOSM" >
<property name="windowModality" >
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>508</width>
<height>309</height>
</rect>
</property>
<property name="windowTitle" >
<string>Load OSM</string>
</property>
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" colspan="2" >
<layout class="QGridLayout" >
<item row="0" column="0" colspan="2" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>OpenStreetMap file to load:</string>
</property>
<property name="indent" >
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLineEdit" name="OSMFileEdit" />
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="browseOSMButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Add columns for tags:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2" >
<layout class="QHBoxLayout" >
<item>
<widget class="QListWidget" name="lstTags" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0" >
<layout class="QHBoxLayout" >
<item>
<widget class="QCheckBox" name="chkCustomRenderer" >
<property name="text" >
<string>Use custom renderer</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="styleCombo" >
<property name="minimumSize" >
<size>
<width>182</width>
<height>0</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>182</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="maximumSize" >
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize" >
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QCheckBox" name="chkReplaceData" >
<property name="text" >
<string>Replace current data (current layers will be removed)</string>
</property>
<property name="checked" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>OSMFileEdit</tabstop>
<tabstop>browseOSMButton</tabstop>
<tabstop>lstTags</tabstop>
<tabstop>chkCustomRenderer</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgLoadOSM</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,226 @@
<ui version="4.0" >
<class>DlgSaveOSM</class>
<widget class="QDialog" name="DlgSaveOSM" >
<property name="windowModality" >
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>370</width>
<height>206</height>
</rect>
</property>
<property name="windowTitle" >
<string>Save OSM</string>
</property>
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QGridLayout" >
<item row="0" column="0" colspan="2" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Where to save:</string>
</property>
<property name="indent" >
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLineEdit" name="OSMFileEdit" />
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="browseOSMButton" >
<property name="maximumSize" >
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Features to save:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="leftMargin" >
<number>15</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>10</number>
</property>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QCheckBox" name="chkPoints" >
<property name="text" >
<string>Points</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkLines" >
<property name="text" >
<string>Lines</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkPolygons" >
<property name="text" >
<string>Polygons</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QCheckBox" name="chkRelations" >
<property name="text" >
<string>Relations</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkTags" >
<property name="text" >
<string>Tags</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="maximumSize" >
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize" >
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>OSMFileEdit</tabstop>
<tabstop>browseOSMButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgSaveOSM</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,229 @@
<ui version="4.0" >
<class>DlgUploadOSM</class>
<widget class="QDialog" name="DlgUploadOSM" >
<property name="windowModality" >
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>373</width>
<height>468</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle" >
<string>Upload OSM data</string>
</property>
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Ready for upload</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QTreeWidget" name="uploadChangesTable" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>330</width>
<height>90</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>330</width>
<height>90</height>
</size>
</property>
<property name="autoFillBackground" >
<bool>false</bool>
</property>
<property name="textElideMode" >
<enum>Qt::ElideLeft</enum>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<property name="columnCount" >
<number>5</number>
</property>
<column>
<property name="text" >
<string>1</string>
</property>
</column>
<column>
<property name="text" >
<string>2</string>
</property>
</column>
<column>
<property name="text" >
<string>3</string>
</property>
</column>
<column>
<property name="text" >
<string>4</string>
</property>
</column>
<column>
<property name="text" >
<string>5</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Comment on your changes:</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="commentTextEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>85</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="accountGroupBox" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="title" >
<string>OSM account</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Username:</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="userLineEdit" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Password:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="passwdLineEdit" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QCheckBox" name="chkShowPasswd" >
<property name="text" >
<string>Show password</string>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QCheckBox" name="chkSavePasswd" >
<property name="text" >
<string>Save password</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="standardButtons" >
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>userLineEdit</tabstop>
<tabstop>passwdLineEdit</tabstop>
<tabstop>chkShowPasswd</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgUploadOSM</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>308</x>
<y>337</y>
</hint>
<hint type="destinationlabel" >
<x>265</x>
<y>308</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OsmUndoRedoDockWidget</class>
<widget class="QDockWidget" name="OsmUndoRedoDockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>227</width>
<height>374</height>
</rect>
</property>
<property name="allowedAreas">
<set>Qt::AllDockWidgetAreas</set>
</property>
<property name="windowTitle">
<string>OSM Edit History</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QToolButton" name="clearButton">
<property name="toolTip">
<string>Clear all</string>
</property>
<property name="statusTip">
<string>Clear all</string>
</property>
<property name="whatsThis">
<string>Clear all</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="undoButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Undo</string>
</property>
<property name="statusTip">
<string>Undo</string>
</property>
<property name="whatsThis">
<string>Undo</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="redoButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Redo</string>
</property>
<property name="statusTip">
<string>Redo</string>
</property>
<property name="whatsThis">
<string>Redo</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="actionList"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,731 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OsmDockWidget</class>
<widget class="QDockWidget" name="OsmDockWidget">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>265</width>
<height>776</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>261</width>
<height>357</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>524287</width>
<height>524287</height>
</size>
</property>
<property name="windowTitle">
<string>OSM Feature</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>1</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="dummyButton">
<property name="minimumSize">
<size>
<width>1</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1</width>
<height>27</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="identifyButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Identify object</string>
</property>
<property name="statusTip">
<string>Identify object</string>
</property>
<property name="whatsThis">
<string>Identify object</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="moveButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Move object</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="createPointButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Create point</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="createLineButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Create line</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="createPolygonButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Create polygon</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="createRelationButton">
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Create relation</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="undoButton">
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="toolTip">
<string>Undo</string>
</property>
<property name="statusTip">
<string>Undo</string>
</property>
<property name="whatsThis">
<string>Undo</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="redoButton">
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="toolTip">
<string>Redo</string>
</property>
<property name="statusTip">
<string>Redo</string>
</property>
<property name="whatsThis">
<string>Redo</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="urDetailsButton">
<property name="maximumSize">
<size>
<width>25</width>
<height>26</height>
</size>
</property>
<property name="toolTip">
<string>Show/Hide OSM Edit History</string>
</property>
<property name="statusTip">
<string>Show/Hide OSM Edit History</string>
</property>
<property name="whatsThis">
<string>Show/Hide OSM Edit History</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="featInfoBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>95</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>95</height>
</size>
</property>
<property name="title">
<string>Feature:</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>18</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<layout class="QGridLayout">
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>TYPE, ID:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>CREATED:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>USER:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="typeIdLabel">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="createdLabel">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="userLabel">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QToolButton" name="removeButton">
<property name="maximumSize">
<size>
<width>25</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="propRelBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>175</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="Properties">
<attribute name="title">
<string>Properties</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QTableWidget" name="tagsTableWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>205</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="deleteTagsButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="Relations">
<attribute name="title">
<string>Relations</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QListWidget" name="relListWidget">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>104</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout">
<item>
<widget class="QPushButton" name="addRelationButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="toolTip">
<string>Add new relation</string>
</property>
<property name="statusTip">
<string>Add new relation</string>
</property>
<property name="whatsThis">
<string>Add new relation</string>
</property>
<property name="text">
<string>A</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editRelationButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="toolTip">
<string>Edit selected relation</string>
</property>
<property name="statusTip">
<string>Edit selected relation</string>
</property>
<property name="whatsThis">
<string>Edit selected relation</string>
</property>
<property name="text">
<string>E</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeRelationButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>26</width>
<height>25</height>
</size>
</property>
<property name="toolTip">
<string>Remove selected relation</string>
</property>
<property name="statusTip">
<string>Remove selected relation</string>
</property>
<property name="whatsThis">
<string>Remove selected relation</string>
</property>
<property name="text">
<string>R</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>26</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Relation tags:</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="relTagsTreeWidget">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>115</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="cursor" stdset="0">
<cursorShape>ForbiddenCursor</cursorShape>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="columnCount">
<number>1</number>
</property>
<column>
<property name="text">
<string>1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Relation members:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="relMembersList">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>115</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,5 +1,5 @@
SUBDIRS (memory ogr wms delimitedtext)
SUBDIRS (memory ogr wms delimitedtext osm)
IF (POSTGRES_FOUND)
SUBDIRS (postgres)

View File

@ -0,0 +1,45 @@
########################################################
# Files
SET(OSM_SRCS
osmhandler.cpp
osmprovider.cpp
osmrenderer.cpp
osmstyle.cpp
)
SET(OSM_MOC_HDRS
osmprovider.h
osmrenderer.h
osmstyle.h
osmhandler.h
)
########################################################
# Build
QT4_WRAP_CPP(OSM_MOC_SRCS ${OSM_MOC_HDRS})
INCLUDE_DIRECTORIES (
../../core
../../core/renderer
${GEOS_INCLUDE_DIR}
)
ADD_LIBRARY (osmprovider MODULE ${OSM_SRCS} ${OSM_MOC_SRCS})
TARGET_LINK_LIBRARIES (osmprovider
${QT_QTCORE_LIBRARY}
${QT_QTXML_LIBRARY}
qgis_core
)
########################################################
# Install
INSTALL(TARGETS osmprovider
RUNTIME DESTINATION ${QGIS_PLUGIN_DIR}
LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})

View File

@ -0,0 +1,382 @@
/***************************************************************************
osmhandler.cpp - handler for parsing OSM data
------------------
begin : October 2008
copyright : (C) 2008 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "osmhandler.h"
#include <iostream>
#include <cstring>
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgsgeometry.h"
#include <QtXml/QXmlSimpleReader>
#include <QtXml/QXmlInputSource>
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtXml/QXmlAttributes>
#include <QtCore/QFile>
#define MAX_FEATURE_ID 99999999
#define COMMIT_AFTER_TAGS 300000
// object construction
OsmHandler::OsmHandler(QFile *f, sqlite3 *database)
{
mDatabase = database;
mCnt=0;
mPointCnt = mLineCnt = mPolygonCnt = 0;
mPosId = 1;
xMin = yMin = MAX_FEATURE_ID;
xMax = yMax = -MAX_FEATURE_ID;
firstWayMemberId = "";
mFirstMemberAppeared=0;
char sqlInsertNode[] = "INSERT INTO node ( id, lat, lon, timestamp, user, usage ) VALUES (?,?,?,?,?,'0');";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertNode, sizeof(sqlInsertNode), &mStmtInsertNode, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertNode!!!");
}
char sqlInsertWay[] = "INSERT INTO way ( id, timestamp, user, closed ) VALUES (?,?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertWay, sizeof(sqlInsertWay), &mStmtInsertWay, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertWay!!!");
}
char sqlInsertTag[] = "INSERT INTO tag ( key, val, object_id, object_type ) VALUES (?,?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertTag, sizeof(sqlInsertTag), &mStmtInsertTag, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertTag!!!");
}
char sqlInsertWayMember[] = "INSERT INTO way_member ( way_id, pos_id, node_id ) VALUES (?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertWayMember, sizeof(sqlInsertWayMember), &mStmtInsertWayMember, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertWayMember!!!");
}
char sqlInsertRelation[] = "INSERT INTO relation ( id, timestamp, user, type ) VALUES (?,?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertRelation, sizeof(sqlInsertRelation), &mStmtInsertRelation, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertRelation!!!");
}
char sqlInsertRelationMember[] = "INSERT INTO relation_member ( relation_id, pos_id, member_id, member_type, role ) VALUES (?,?,?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertRelationMember, sizeof(sqlInsertRelationMember), &mStmtInsertRelationMember, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertRelationMember!!!");
}
char sqlInsertVersion[] = "INSERT INTO version (object_id,object_type,version_id) VALUES (?,?,?);";
if ( sqlite3_prepare_v2(mDatabase, sqlInsertVersion, sizeof(sqlInsertVersion), &mStmtInsertVersion, 0) != SQLITE_OK )
{
QgsDebugMsg("failed to prepare sqlInsertVersion!!!");
}
}
OsmHandler::~OsmHandler()
{
sqlite3_finalize(mStmtInsertTag);
sqlite3_finalize(mStmtInsertRelation);
sqlite3_finalize(mStmtInsertRelationMember);
sqlite3_finalize(mStmtInsertVersion);
}
bool OsmHandler::startDocument()
{
sqlite3_exec(mDatabase, "BEGIN;", 0, 0, 0);
return true;
}
QString OsmHandler::errorString()
{
return mError;
}
bool OsmHandler::startElement(const QString & pUri, const QString & pLocalName, const QString & pName, const QXmlAttributes & pAttrs)
{
QString name = pLocalName;
if (name == "osm")
{
if (pAttrs.value("version") != "0.6")
{
mError = "Invalid OSM version. Only files of v0.6 are supported.";
return false;
}
}
else if (name == "node")
{
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, node has to be ignored!
mObjectId = pAttrs.value("id");
mObjectType = "node";
double id = pAttrs.value("id").toInt();
double lat = pAttrs.value("lat").toDouble();
double lon = pAttrs.value("lon").toDouble();
QString timestamp = pAttrs.value("timestamp");
QString user = pAttrs.value("user");
if (lat<yMin) yMin=lat;
if (lat>yMax) yMax=lat;
if (lon<xMin) xMin=lon;
if (lon>xMax) xMax=lon;
sqlite3_bind_int(mStmtInsertNode, 1, id);
sqlite3_bind_double(mStmtInsertNode, 2, lat);
sqlite3_bind_double(mStmtInsertNode, 3, lon);
sqlite3_bind_text(mStmtInsertNode, 4, timestamp.toUtf8(), -1, SQLITE_TRANSIENT); // TODO: maybe static?
sqlite3_bind_text(mStmtInsertNode, 5, user.toUtf8(), -1, SQLITE_TRANSIENT); // TODO: maybe static?
if (sqlite3_step(mStmtInsertNode) != SQLITE_DONE)
{
QgsDebugMsg("Storing node information into database failed.");
return false;
}
sqlite3_reset(mStmtInsertNode); // make ready for next insert
// store version number of this object
sqlite3_bind_text(mStmtInsertVersion, 1, pAttrs.value("id").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 3, pAttrs.value("version").toUtf8(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(mStmtInsertVersion) != SQLITE_DONE)
{
QgsDebugMsg("Storing version information into database failed.");
return false;
}
sqlite3_reset(mStmtInsertVersion); // make ready for next insert
// increase node counter
mPointCnt++;
}
else if (name == "way")
{
if (mObjectType!="way")
{
sqlite3_finalize(mStmtInsertNode);
}
mObjectId = pAttrs.value("id");
mObjectType = "way";
mPosId = 1;
mFirstMemberAppeared=0;
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, way has to be ignored!
sqlite3_bind_text(mStmtInsertWay, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertWay, 2, pAttrs.value("timestamp").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertWay, 3, pAttrs.value("user").toUtf8(), -1, SQLITE_TRANSIENT);
// store version number of this object
sqlite3_bind_text(mStmtInsertVersion, 1, pAttrs.value("id").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 3, pAttrs.value("version").toUtf8(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(mStmtInsertVersion) != SQLITE_DONE)
{
QgsDebugMsg("Storing version information into database failed.");
return false;
}
sqlite3_reset(mStmtInsertVersion); // make ready for next insert
}
else if (name == "nd")
{
// store id of the first and last way member to be able to decide if the way is closed (polygon) or not
if (firstWayMemberId=="") {
firstWayMemberId = pAttrs.value("ref");
}
lastWayMemberId = pAttrs.value("ref");
if (firstWayMemberId==lastWayMemberId)
mFirstMemberAppeared++;
if ((firstWayMemberId!=lastWayMemberId) || (mFirstMemberAppeared<2))
{
sqlite3_bind_text(mStmtInsertWayMember, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT); // TODO: maybe static?
sqlite3_bind_int(mStmtInsertWayMember, 2, mPosId);
sqlite3_bind_text(mStmtInsertWayMember, 3, pAttrs.value("ref").toUtf8(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(mStmtInsertWayMember) != SQLITE_DONE)
{
QgsDebugMsg("Storing way-node relationship into database failed.");
return false;
};
sqlite3_reset(mStmtInsertWayMember);
}
mPosId++;
}
else if (name == "relation")
{
if (mObjectType!="relation")
{
sqlite3_finalize(mStmtInsertWay);
sqlite3_finalize(mStmtInsertWayMember);
}
mObjectId = pAttrs.value("id");
mRelationType = "";
mObjectType = "relation";
mPosId = 1;
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, relation has to be ignored!
sqlite3_bind_text(mStmtInsertRelation, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertRelation, 2, pAttrs.value("timestamp").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertRelation, 3, pAttrs.value("user").toUtf8(), -1, SQLITE_TRANSIENT);
// store version number of this object
sqlite3_bind_text(mStmtInsertVersion, 1, pAttrs.value("id").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertVersion, 3, pAttrs.value("version").toUtf8(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(mStmtInsertVersion) != SQLITE_DONE)
{
QgsDebugMsg("Storing version information into database failed.");
return false;
}
sqlite3_reset(mStmtInsertVersion); // make ready for next insert
}
else if (name == "member")
{
sqlite3_bind_text(mStmtInsertRelationMember, 1, mObjectId.toUtf8(),-1,SQLITE_TRANSIENT);
sqlite3_bind_int(mStmtInsertRelationMember, 2, mPosId);
sqlite3_bind_text(mStmtInsertRelationMember, 3, pAttrs.value("ref").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertRelationMember, 4, pAttrs.value("type").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertRelationMember, 5, pAttrs.value("role").toUtf8(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(mStmtInsertRelationMember) != SQLITE_DONE)
{
QgsDebugMsg("Storing relation-feature relationship into database failed.");
return false;
};
sqlite3_reset(mStmtInsertRelationMember);
mPosId++;
}
else if (name == "tag")
{
if (mCnt==COMMIT_AFTER_TAGS)
{
sqlite3_exec(mDatabase, "COMMIT;", 0, 0, 0);
sqlite3_exec(mDatabase, "BEGIN;", 0, 0, 0);
mCnt=0;
}
mCnt++;
sqlite3_bind_text(mStmtInsertTag, 1, pAttrs.value("k").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertTag, 2, pAttrs.value("v").toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertTag, 3, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(mStmtInsertTag, 4, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT);
// we've got node parameters -> let's create new database record
if ( sqlite3_step(mStmtInsertTag) != SQLITE_DONE )
{
QgsDebugMsg(QString("Storing tag into database failed. K:%1, V:%2.").arg(pAttrs.value("k")).arg(pAttrs.value("v")));
return false;
}
sqlite3_reset(mStmtInsertTag);
// if we are under xml tag <relation> and we reach xml tag <tag k="type" v="...">, lets insert prepared relation into DB
if ((mObjectType == "relation") && (pAttrs.value("k")=="type"))
{
mRelationType=pAttrs.value("v");
}
}
else if (name == "bounds")
{
// e.g. <bounds minlat="41.388625" minlon="2.15426" maxlat="41.391732" maxlon="2.158192"/>
// notice: getting boundaries from OSM file <bounds> tag was not correct for some maps - cannot be used
// xMin = pAttrs.value("minlon").toDouble();
// xMax = pAttrs.value("maxlon").toDouble();
// yMin = pAttrs.value("minlat").toDouble();
// yMax = pAttrs.value("maxlat").toDouble();
}
return true;
}
bool OsmHandler::endElement( const QString & pURI, const QString & pLocalName, const QString & pName )
{
QString name = pLocalName;
if (name == "way")
{
int isPolygon=false;
int cntMembers=mPosId-1;
if (firstWayMemberId==lastWayMemberId)
isPolygon=true;
// test if polygon is correct; it should have >2 member points
if ((isPolygon) && (cntMembers<4)) {
sqlite3_reset(mStmtInsertWay);
return true;
}
// test if way is correct; it should have more then 1 member point
if (cntMembers<2) {
sqlite3_reset(mStmtInsertWay);
return true;
}
// we should bind the last information needed for way insertion -> if the way is closed (polygon) or not
sqlite3_bind_int(mStmtInsertWay, 4, (isPolygon ? 1 : 0));
// well, insert new way
if (sqlite3_step(mStmtInsertWay) != SQLITE_DONE)
{
QgsDebugMsg("Storing way information into database failed.");
return false;
};
// make statement ready for next insert
sqlite3_reset(mStmtInsertWay);
if (isPolygon)
mPolygonCnt++;
else
mLineCnt++;
// make variables ready for next way parsing
firstWayMemberId="";
}
else if (name == "relation")
{
sqlite3_bind_text(mStmtInsertRelation, 4, mRelationType.toUtf8(), -1, SQLITE_TRANSIENT);
if ( sqlite3_step(mStmtInsertRelation) != SQLITE_DONE )
{
QgsDebugMsg(QString("Storing relation into database failed."));
return false;
}
sqlite3_reset(mStmtInsertRelation);
}
return true;
}
bool OsmHandler::endDocument()
{
// first commit all database actions connected to xml parsing
sqlite3_exec(mDatabase, "COMMIT;", 0, 0, 0);
}

View File

@ -0,0 +1,86 @@
/***************************************************************************
osmhandler.h - handler for parsing OSM data
------------------
begin : October 2008
copyright : (C) 2008 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QFile>
#include <QProgressDialog>
#include <QString>
#include <QXmlDefaultHandler>
#include <QXmlAttributes>
#include <sqlite3.h>
#include <iostream>
using namespace std;
/**
* XML SAX handler -> while processing XML file,
* stores data to specified sqlite database
*/
class OsmHandler: public QXmlDefaultHandler
{
public:
// member variables
QFile mFile;
sqlite3 *mDatabase;
int mCnt;
int mFileSize;
QString mError;
// xml processing information
QString mObjectId; //last node, way or relation id while parsing file
QString mObjectType; //one of strings "node", "way", "relation"
QString mRelationType;
float mLat;
float mLon;
double xMin, xMax, yMin, yMax;
int mPointCnt;
int mLineCnt;
int mPolygonCnt;
int mCurrent_way_id;
int mPosId;
QString firstWayMemberId;
QString lastWayMemberId;
int mFirstMemberAppeared;
//functions
// object construction
OsmHandler(QFile *f, sqlite3 *database);
~OsmHandler();
// xml processing
bool startDocument();
QString errorString();
bool startElement( const QString & pUri, const QString & pLocalName, const QString & pName, const QXmlAttributes & pAttrs );
bool endElement( const QString & pURI, const QString & pLocalName, const QString & pName );
bool endDocument();
private:
sqlite3_stmt *mStmtInsertNode;
sqlite3_stmt *mStmtInsertWay;
sqlite3_stmt *mStmtInsertTag;
sqlite3_stmt *mStmtInsertWayMember;
sqlite3_stmt *mStmtInsertRelation;
sqlite3_stmt *mStmtInsertRelationMember;
sqlite3_stmt *mStmtUpdateNode;
sqlite3_stmt *mStmtInsertVersion;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,302 @@
/***************************************************************************
osmprovider.h - provider for OSM; stores OSM data in sqlite3 DB
------------------
begin : October 2008
copyright : (C) 2008 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsvectordataprovider.h"
#include <sqlite3.h>
#include <QFile>
#include <QDateTime>
typedef QMap<int, QgsFeature> QgsFeatureMap;
class QgsOSMDataProvider: public QgsVectorDataProvider
{
public:
/**
* Constructor of the vector provider.
* @param uri uniform resource locator (URI) for a dataset
*/
QgsOSMDataProvider(QString uri);
/**
* Destructor.
*/
virtual ~QgsOSMDataProvider();
// Implementation of functions from QgsVectorDataProvider
/**
* Returns the permanent storage type for this layer as a friendly name.
*/
virtual QString storageType() const;
/** Select features based on a bounding rectangle. Features can be retrieved with calls to getNextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual void select(QgsAttributeList fetchAttributes = QgsAttributeList(),
QgsRectangle rect = QgsRectangle(),
bool fetchGeometry = true,
bool useIntersect = false);
/**
* Get the next feature resulting from a select operation.
* @param feature feature which will receive data from the provider
* @return true when there was a feature to fetch, false when end was hit
*/
virtual bool nextFeature(QgsFeature& feature);
/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
* @param feature feature which will receive the data
* @param fetchGeometry if true, geometry will be fetched from the provider
* @param fetchAttributes a list containing the indexes of the attribute fields to copy
* @return True when feature was found, otherwise false
*/
virtual bool featureAtId(int featureId,
QgsFeature& feature,
bool fetchGeometry = true,
QgsAttributeList fetchAttributes = QgsAttributeList());
/**
* Get feature type.
* @return int representing the feature type
*/
virtual QGis::WkbType geometryType() const;
/**
* Number of features in the layer
* @return long containing number of features
*/
virtual long featureCount() const;
/**
* Number of attribute fields for a feature in the layer
*/
virtual uint fieldCount() const;
/**
* Return a map of indexes with field names for this layer
* @return map of fields
*/
virtual const QgsFieldMap & fields() const;
/**
* Restart reading features from previous select operation.
*/
virtual void rewind();
/**
* Changes attribute values of existing features.
* @param attr_map a map containing changed attributes
* @return true in case of success and false in case of failure
*/
virtual bool changeAttributeValues(const QgsChangedAttributesMap & attr_map);
/**
* Returns a bitmask containing the supported capabilities
* Note, some capabilities may change depending on whether
* a spatial filter is active on this provider, so it may
* be prudent to check this value per intended operation.
*/
virtual int capabilities() const;
// Implementation of functions from QgsDataProvider
/**
* Returns a provider name.
*/
virtual QString name() const;
/**
* Returns a provider description.
*/
virtual QString description() const;
/**
* Return the extent for this data layer
*/
virtual QgsRectangle extent();
/**
* Returns true if this is a valid provider
*/
virtual bool isValid();
/**
* Get the QgsCoordinateReferenceSystem for this layer.
*/
virtual QgsCoordinateReferenceSystem crs();
private:
enum { PointType, LineType, PolygonType } mFeatureType;
enum Attribute { TimestampAttr = 0, UserAttr = 1, TagAttr, CustomTagAttr };
const static int DEFAULT_EXTENT = 100;
static const char* attr[];
QString mFileName;
QString mDatabaseFileName;
QDateTime mOsmFileLastModif;
bool mValid;
sqlite3 *mDatabase;
sqlite3_stmt *mDatabaseStmt;
char *mError;
//! object that receives notifications from init
QObject* mInitObserver;
double xMin, xMax, yMin, yMax; // boundary
// selection
QgsAttributeList mAttributesToFetch;
QgsFieldMap mAttributeFields;
QgsRectangle mSelectionRectangle;
QgsGeometry* mSelectionRectangleGeom;
// flags
bool mSelectUseIntersect;
// private methods
sqlite3_stmt *mTagsStmt;
bool mTagsRetrieval;
QString tagsForObject(const char* type, int id);
sqlite3_stmt *mCustomTagsStmt;
QStringList mCustomTagsList;
QString tagForObject(const char* type, int id, QString tagKey);
sqlite3_stmt *mWayStmt;
sqlite3_stmt *mNodeStmt;
QString mStyleFileName;
QString mStyle;
// manipulation with sqlite database
bool isDatabaseCompatibleWithInput(QString mFileName);
bool isDatabaseCompatibleWithPlugin();
/**
* Create Open Street Map database schema, using c++ library for attempt to sqlite database.
* @return true in case of success and false in case of failure
*/
bool createDatabaseSchema();
/**
* Create indexes for OSM database schema, using c++ library for attempt to sqlite database.
* @return true in case of success and false in case of failure
*/
bool createIndexes();
bool createTriggers();
/**
* Drop the whole OSM database schema, using c++ library for attempt to sqlite database.
* @return true in case of success and false in case of failure
*/
bool dropDatabaseSchema();
/**
* Open sqlite3 database.
* @return true in case of success and false in case of failure
*/
bool openDatabase();
/**
* Close opened sqlite3 database.
*/
bool closeDatabase();
/**
* Process Open Street Map file, parse it and store data in sqlite database.
* Function doesn't require much memory: uses simple SAX XML parser
* and stores data directly to database while processing OSM file.
* @param osm_filename name of file with OSM data to parse into sqlite3 database
* @return true in case of success and false in case of failure
*/
bool loadOsmFile(QString osm_filename);
bool updateWayWKB(int wayId, int isClosed, char **geo, int *geolen);
bool updateNodes();
bool removeIncorrectWays();
/**
* This function is part of postparsing. OpenStreetMaps nodes have to be divided in two categories here for better manipulation.
* First category is "significant OSM nodes" - these nodes are loaded to Point vector layer and hold some significant information (in tags),
* except the fact that they may be parts of ways geometries. The second category are "not significant OSM nodes". These are considered
* to be a part of some way geometry only but nothing more. These nodes are not loaded to Point layer, they don't have any significant tags
* like "name","ref",etc; OSM plugin even doesn't care of these nodes when some way geometry is changing. Plugin will just remove
* all not significant nodes of that way and will create new ones instead of them.
* @return true in case of success and false in case of failure
*/
bool splitNodes();
/**
* This function is postprocess after osm file parsing. Parsing stored all information into database, but
* such database schema is not optimal e.g. for way selection, that is called very often. It should be better
* to have way members (with their coordinates) store directly in way table - in WKB (well known binary) format
* @return true in case of success and false in case of failure
*/
bool postparsing();
/**
* Gets first free feature id in database. Searching for the biggest
* NEGATIVE integer that is not assigned to any feature.
* @return free id (negative) for feature, 0 if id cannot be returned
*/
int freeFeatureId();
/**
* Get number of members of specified way.
* @param wayId way identifier
* @return number of way members
*/
int wayMemberCount(int wayId);
int relationMemberCount(int relId);
// fetch node from current statement
bool fetchNode(QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs);
// fetch way from current statement
bool fetchWay(QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs);
// Change geometry of one feature (used by changeGeometryValues())
bool changeGeometryValue(const int & featid, QgsGeometry & geom);
struct wkbPoint {
char byteOrder;
unsigned wkbType;
double x;
double y;
};
wkbPoint mWKBpt;
};

View File

@ -0,0 +1,183 @@
/***************************************************************************
osmrenderer.cpp - handler for parsing OSM data
------------------
begin : April 2009
copyright : (C) 2009 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "osmrenderer.h"
#include <iostream>
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgsgeometry.h"
#include <QtXml/QXmlSimpleReader>
#include <QtXml/QXmlInputSource>
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QPainter>
#include <QtXml/QXmlAttributes>
#include <QtCore/QFile>
using namespace std;
OsmRenderer::OsmRenderer(QGis::GeometryType geometryType, QString styleFileName)
: QgsRenderer(), osmstyle(styleFileName), mGeomType(geometryType)
{
}
QMap<QString,QString> OsmRenderer::parse_tags(QString tags)
{
QMap<QString,QString> t;
if (tags.size()==0)
{
QgsDebugMsg("no tags for feature!");
return t;
}
// tags: "key1"="val1","key2"="val2","key3"="val3"
// -all original ; in keyX and valX are replaced by ;;
// -all original , in keyX and valX are replaced by ;
// -all original - in keyX and valX are replaced by --
// -all original = in keyX and valX are replaced by -
QStringList tag_pairs = tags.split(",");
for (int i = 0; i < tag_pairs.size(); ++i)
{
QStringList duo = tag_pairs.at(i).split("=");
if (duo.count() != 2)
{
QgsDebugMsg("invalid tag value: " + tag_pairs.at(i));
continue;
}
QString key = duo[0];
QString val = duo[1];
key=key.replace(';',",");
val=val.replace(';',",");
key=key.replace(";;",";");
val=val.replace(";;",";");
key=key.replace('-',"=");
val=val.replace('-',"=");
key=key.replace("--","-");
val=val.replace("--","-");
// dequoting
key = key.mid(1,key.size()-2);
val = val.mid(1,val.size()-2);
// put tag into map
t.insert(key,val);
}
return t;
}
bool OsmRenderer::willRenderFeature (QgsFeature *f)
{
// todo: return what?
return true;
}
void OsmRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* pic, bool selected )
{
// QgsDebugMsg("RENDERING FEAT:" + f.id());
QPainter* p = renderContext.painter();
QgsAttributeMap attr_map = f.attributeMap();
QMap<QString,QString> tags = parse_tags( attr_map[2].toString() );
if (mGeomType== QGis::Line)
{
QPen pen = osmstyle.get_pen(tags);
QColor penColor = pen.color();
int red = penColor.red();
int green = penColor.green();
int blue = penColor.blue();
p->setPen( osmstyle.get_pen(tags) );
p->setOpacity(1.0);
}
else if (mGeomType==QGis::Polygon)
{
QBrush br;
p->setPen( osmstyle.get_pen_brush(tags,br) );
p->setBrush(br);
p->setBackgroundMode( Qt::TransparentMode );
p->setOpacity(0.5);
}
else if (mGeomType==QGis::Point)
{
*pic = osmstyle.get_image(tags);
p->setOpacity(1.0);
}
}
int OsmRenderer::readXML(const QDomNode &rnode, QgsVectorLayer &vl)
{
return 0;
}
bool OsmRenderer::writeXML(QDomNode &layer_node, QDomDocument &document, const QgsVectorLayer &vl) const
{
return true;
}
bool OsmRenderer::needsAttributes() const
{
return true;
}
QgsAttributeList OsmRenderer::classificationAttributes() const
{
QgsAttributeList attr_list;
attr_list.append(2);
return attr_list;
}
QString OsmRenderer::name() const
{
return QString("OSM");
}
const QList< QgsSymbol * > OsmRenderer::symbols () const
{
const QList<QgsSymbol*> sym;
return sym;
}
QgsRenderer *OsmRenderer::clone () const
{
return 0;
}
bool OsmRenderer::containsPixmap () const
{
return false;
}
bool OsmRenderer::usesTransparency () const
{
return false;
}

View File

@ -0,0 +1,77 @@
/***************************************************************************
osmrenderer.h - Quantum GIS renderer for OpenStreetMap vector layers.
------------------
begin : April 2009
copyright : (C) 2009 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QFile>
#include <QString>
#include <sqlite3.h>
#include <iostream>
#include "qgsrenderer.h"
#include "qgsfeature.h"
#include "osmstyle.h"
using namespace std;
/**
* Quantum GIS renderer for OpenStreetMap vector layers.
*/
class OsmRenderer : public QgsRenderer
{
public:
// Object construction
OsmRenderer(QGis::GeometryType geometryType, QString styleFileName);
// ~OsmRenderer();
QMap<QString,QString> parse_tags(QString tags);
// ??? Determines if a feature will be rendered or not.
bool willRenderFeature (QgsFeature *f);
// A vector layer passes features to a renderer object to change the brush and pen of the qpainter.
void renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* pic, bool selected );
// Reads the renderer configuration from an XML file.
int readXML(const QDomNode &rnode, QgsVectorLayer &vl);
// Writes the contents of the renderer to a configuration file @ return true in case of success.
bool writeXML(QDomNode &layer_node, QDomDocument &document, const QgsVectorLayer &vl) const;
// Returns true, if attribute values are used by the renderer and false otherwise.
bool needsAttributes() const;
// Returns a list with indexes of classification attributes.
QgsAttributeList classificationAttributes () const;
// Returns the renderers name.
QString name() const;
// Return symbology items.
const QList< QgsSymbol * > symbols () const;
//Returns a copy of the renderer (a deep copy on the heap).
QgsRenderer *clone () const;
// ??? Returns true if this renderer returns a pixmap in the render method
bool containsPixmap () const;
// ??? Returns true if this renderer uses its own transparency settings
bool usesTransparency () const;
protected:
// member variables
OsmStyle osmstyle;
QGis::GeometryType mGeomType;
};

View File

@ -0,0 +1,206 @@
/***************************************************************************
osmstyle.cpp - Class representing OSM stylesheet.
------------------
begin : April 2009
copyright : (C) 2009 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "osmstyle.h"
#include "symbology/qgssymbol.h"
#include <qgsapplication.h>
#include <qgslogger.h>
OsmStyle::OsmStyle(QString filename)
{
rules_line.clear();
rules_polygon.clear();
rules_point.clear();
QString rule_type = "unknown";
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QgsDebugMsg("failed to open style file: " + filename);
return;
}
while (!file.atEnd())
{
QByteArray line_bytes = file.readLine();
QString line = line_bytes.data();
QgsDebugMsg("line: " + line);
if (line.at(0)=='#')
// change of rule type
rule_type = line.mid(1).trimmed();
else
{
if (rule_type == "LINE")
parse_rule_line(line);
if (rule_type == "POLYGON")
parse_rule_polygon(line);
if (rule_type == "POINT")
parse_rule_point(line);
}
}
QgsDebugMsg(QString("OSM style parsing done: %1 / %2 / %3")
.arg(rules_line.count()).arg(rules_polygon.count()).arg(rules_point.count()));
}
OsmStyle::~OsmStyle()
{
}
void OsmStyle::parse_rule_line(QString line)
{
// split line into "key","val","width","color" parts
QStringList line_parts = line.split(" ");
QString key = line_parts[0];
QString val = line_parts[1];
QString width = line_parts[2];
QString penStyle = line_parts[3];
QString color = line_parts[4];
// split color into its typical parts
QStringList color_parts = color.split(",");
QString r = color_parts[0];
QString g = color_parts[1];
QString b = color_parts[2];
// create pen
QPen pen = QPen(QColor(r.toInt(),g.toInt(),b.toInt()));
pen.setWidth(width.toFloat());
pen.setStyle((Qt::PenStyle) penStyle.toInt());
// add rule
rules_line.append( Rule(key,val,pen,QBrush(),QImage()) );
}
void OsmStyle::parse_rule_polygon(QString line)
{
// split line into "key","val","width","color","fill" parts
QStringList line_parts = line.split(" ");
QString key = line_parts[0];
QString val = line_parts[1];
QString width = line_parts[2];
QString penStyle = line_parts[3];
QString color = line_parts[4];
QString fill = line_parts[5];
// split color into red, green and blue parts
QStringList color_parts = color.split(",");
QString r = color_parts[0];
QString g = color_parts[1];
QString b = color_parts[2];
// create pen
QPen pen = QPen(QColor(r.toInt(),g.toInt(),b.toInt()));
pen.setWidth(width.toFloat());
pen.setStyle((Qt::PenStyle) penStyle.toInt());
// split fill into red, green and blue parts
color_parts = fill.split(",");
r = color_parts[0];
g = color_parts[1];
b = color_parts[2];
QColor col(r.toInt(),g.toInt(),b.toInt(),120);
QBrush brush = QBrush(col);
brush.setStyle(Qt::SolidPattern);
// add rule
rules_polygon.append( Rule(key,val,pen,brush,QImage()) );
}
void OsmStyle::parse_rule_point(QString line)
{
// split line into "key","val","width","color" parts
QStringList line_parts = line.split(" ");
QString key = line_parts[0];
QString val = line_parts[1];
QString name = line_parts[2];
QString size = line_parts[3];
double widthScale = 1.0;
bool selected = false;
QColor mSelectionColor(255,255,0);
double rasterScaleFactor = 1.0;
QgsSymbol sym(QGis::Point);
sym.setNamedPointSymbol(QString("svg:%1%2").arg(QgsApplication::svgPath()).arg(name));
sym.setPointSize(size.toFloat());
QImage img = sym.getPointSymbolAsImage(widthScale,selected,mSelectionColor);
// add rule
rules_point.append( Rule(key,val,QPen(),QBrush(),img) );
}
QPen OsmStyle::get_pen(QMap<QString,QString> tags)
{
// go through rules one by one. the valid rule is applied
for (int i = 0; i < rules_line.size(); ++i)
{
const Rule& rule = rules_line.at(i);
QString key=rule.key.trimmed();
QString val=rule.val.trimmed();
// todo: tmp comm, from python: if rule[0] == '*' or (tags.has_key(rule[0]) and (tags[rule[0]] == rule[1] or rule[1] == '*'))
if ((key=="*") || ((tags.find(key)!=tags.end()) && ((tags.value(key)==rule.val) || (val=="*"))))
{
return rule.pen;
}
}
QgsDebugMsg("not drawing.");
return QPen(Qt::NoPen);
}
QPen OsmStyle::get_pen_brush(QMap<QString,QString> tags, QBrush &brush) // todo: return both pen and brush
{
// go through rules one by one. the valid rule is applied
for (int i = 0; i < rules_polygon.size(); ++i)
{
const Rule& rule = rules_polygon.at(i);
QString key=rule.key.trimmed();
QString val=rule.val.trimmed();
// todo: tmp comm, from python: if rule[0] == '*' or (tags.has_key(rule[0]) and (tags[rule[0]] == rule[1] or rule[1] == '*'))
if ((key=="*") || ((tags.find(key)!=tags.end()) && ((tags.value(key)==val) || (val=="*")))) {
brush=rule.brush;
return rule.pen; // todo: and brush?
}
}
brush=Qt::NoBrush;
return QPen(Qt::NoPen); // todo: and brush?
}
QImage OsmStyle::get_image(QMap<QString,QString> tags)
{
// go through rules one by one. the valid rule is applied
for (int i = 0; i < rules_point.size(); ++i)
{
const Rule& rule = rules_point.at(i);
// todo: tmp comm, from python: if rule[0] == '*' or (tags.has_key(rule[0]) and (tags[rule[0]] == rule[1] or rule[1] == '*'))
if ((rule.key=="*") || ((tags.find(rule.key)!=tags.end()) && ((tags.value(rule.key)==rule.val) || (rule.val=="*"))))
return rule.img;
}
return QImage();
}

View File

@ -0,0 +1,73 @@
/***************************************************************************
osmstyle.h - Class representing OSM stylesheet.
------------------
begin : April 2009
copyright : (C) 2009 by Lukas Berka
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QFile>
#include <QMap>
#include <QProgressDialog>
#include <QString>
#include <QPen>
#include <QXmlDefaultHandler>
#include <QXmlAttributes>
#include <iostream>
using namespace std;
/**
* Class to represent a paint rule.
*/
class Rule
{
public:
// construction, destruction
Rule(QString pKey, QString pVal, QPen pPen, QBrush pBrush, QImage pImg)
:key(pKey), val(pVal), pen(pPen), brush(pBrush), img(pImg) {};
// class members
QString key;
QString val;
QPen pen;
QBrush brush;
QImage img;
};
/**
* Class representing OSM stylesheet.
*/
class OsmStyle
{
public:
OsmStyle(QString filename);
~OsmStyle();
QList<Rule> rules_line;
QList<Rule> rules_polygon;
QList<Rule> rules_point;
void parse_rule_line(QString line);
void parse_rule_polygon(QString line);
void parse_rule_point(QString line);
QPen get_pen(QMap<QString,QString> tags);
QPen get_pen_brush(QMap<QString,QString> tags, QBrush &brush); // todo: return both pen and brush
QImage get_image(QMap<QString,QString> tags);
};