[FEATURE] Imported OpenStreetMap provider and plugin.
git-svn-id: http://svn.osgeo.org/qgis/trunk@11210 c8812cc2-4d05-0410-92ff-de0c093fc19c
@ -1 +1 @@
|
||||
SUBDIRS(plugin_installer mapserver_export fTools)
|
||||
SUBDIRS(plugin_installer mapserver_export fTools osm)
|
||||
|
12
python/plugins/osm/CMakeLists.txt
Normal 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)
|
2589
python/plugins/osm/DatabaseManager.py
Normal file
798
python/plugins/osm/DlgAddRelation.py
Executable 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))
|
||||
|
||||
|
||||
|
140
python/plugins/osm/DlgAddRelation_ui.py
Normal 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))
|
||||
|
491
python/plugins/osm/DlgDownloadOSM.py
Executable 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)
|
||||
|
||||
|
||||
|
162
python/plugins/osm/DlgDownloadOSM_ui.py
Normal 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))
|
||||
|
252
python/plugins/osm/DlgImport.py
Normal 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
|
||||
|
62
python/plugins/osm/DlgImport_ui.py
Normal 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))
|
||||
|
320
python/plugins/osm/DlgLoadOSM.py
Normal 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)
|
||||
|
||||
|
86
python/plugins/osm/DlgLoadOSM_ui.py
Normal 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))
|
||||
|
314
python/plugins/osm/DlgSaveOSM.py
Normal 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()
|
||||
|
||||
|
||||
|
99
python/plugins/osm/DlgSaveOSM_ui.py
Normal 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
118
python/plugins/osm/DlgUploadOSM_ui.py
Normal 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))
|
||||
|
441
python/plugins/osm/DockUndoRedo.py
Normal 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)
|
||||
|
||||
|
59
python/plugins/osm/DockUndoRedo_ui.py
Normal 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))
|
||||
|
1243
python/plugins/osm/DockWidget.py
Normal file
290
python/plugins/osm/DockWidget_ui.py
Normal 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))
|
||||
|
37
python/plugins/osm/Makefile
Normal 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
|
65
python/plugins/osm/__init__.py
Normal 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)
|
||||
|
4016
python/plugins/osm/images/osmIconsMaster.svg
Normal file
After Width: | Height: | Size: 275 KiB |
BIN
python/plugins/osm/images/osm_createLine.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
python/plugins/osm/images/osm_createPoint.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
python/plugins/osm/images/osm_createPolygon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
python/plugins/osm/images/osm_createRelation.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
python/plugins/osm/images/osm_download.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/plugins/osm/images/osm_featureManager.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/plugins/osm/images/osm_identify.png
Normal file
After Width: | Height: | Size: 982 B |
BIN
python/plugins/osm/images/osm_import.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/plugins/osm/images/osm_load.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/plugins/osm/images/osm_move.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
python/plugins/osm/images/osm_questionMark.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
python/plugins/osm/images/osm_redo.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
python/plugins/osm/images/osm_remove.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
python/plugins/osm/images/osm_save.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/plugins/osm/images/osm_star.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
python/plugins/osm/images/osm_undo.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
python/plugins/osm/images/osm_upload.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
337
python/plugins/osm/map_tools/CreateLineMapTool.py
Normal 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()
|
||||
|
||||
|
||||
|
||||
|
265
python/plugins/osm/map_tools/CreatePointMapTool.py
Normal 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)
|
||||
|
||||
|
||||
|
336
python/plugins/osm/map_tools/CreatePolygonMapTool.py
Normal 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()
|
||||
|
||||
|
||||
|
292
python/plugins/osm/map_tools/IdentifyMapTool.py
Normal 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
|
||||
|
||||
|
768
python/plugins/osm/map_tools/MoveMapTool.py
Normal 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()
|
||||
|
||||
|
||||
|
0
python/plugins/osm/map_tools/__init__.py
Normal file
333
python/plugins/osm/osm_plugin.py
Normal 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)
|
||||
|
||||
|
1693
python/plugins/osm/resources.py
Normal file
53
python/plugins/osm/resources.qrc
Normal 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>
|
34
python/plugins/osm/styles/big_scale.style
Normal 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
|
45
python/plugins/osm/styles/medium_scale.style
Normal 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
|
48
python/plugins/osm/styles/small_scale.style
Normal 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
|
289
python/plugins/osm/ui_files/DlgAddRelation.ui
Executable 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>
|
375
python/plugins/osm/ui_files/DlgDownloadOSM.ui
Normal 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><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>
|
122
python/plugins/osm/ui_files/DlgImport.ui
Normal 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>
|
163
python/plugins/osm/ui_files/DlgLoadOSM.ui
Normal 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>
|
226
python/plugins/osm/ui_files/DlgSaveOSM.ui
Normal 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>
|
229
python/plugins/osm/ui_files/DlgUploadOSM.ui
Normal 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>
|
100
python/plugins/osm/ui_files/DockUndoRedo.ui
Normal 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>
|
731
python/plugins/osm/ui_files/DockWidget.ui
Normal 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>
|
@ -1,5 +1,5 @@
|
||||
|
||||
SUBDIRS (memory ogr wms delimitedtext)
|
||||
SUBDIRS (memory ogr wms delimitedtext osm)
|
||||
|
||||
IF (POSTGRES_FOUND)
|
||||
SUBDIRS (postgres)
|
||||
|
45
src/providers/osm/CMakeLists.txt
Normal 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})
|
382
src/providers/osm/osmhandler.cpp
Normal 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);
|
||||
}
|
||||
|
86
src/providers/osm/osmhandler.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
1672
src/providers/osm/osmprovider.cpp
Normal file
302
src/providers/osm/osmprovider.h
Normal 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;
|
||||
};
|
||||
|
183
src/providers/osm/osmrenderer.cpp
Normal 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;
|
||||
}
|
||||
|
77
src/providers/osm/osmrenderer.h
Normal 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;
|
||||
};
|
||||
|
206
src/providers/osm/osmstyle.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
73
src/providers/osm/osmstyle.h
Normal 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);
|
||||
};
|
||||
|
||||
|