本文整理汇总了Python中qgis.core.QgsGeometry.fromMultiPointXY方法的典型用法代码示例。如果您正苦于以下问题:Python QgsGeometry.fromMultiPointXY方法的具体用法?Python QgsGeometry.fromMultiPointXY怎么用?Python QgsGeometry.fromMultiPointXY使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类qgis.core.QgsGeometry
的用法示例。
在下文中一共展示了QgsGeometry.fromMultiPointXY方法的7个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Python代码示例。
示例1: _swap_qgs_geometry
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
def _swap_qgs_geometry(qgsgeom):
if qgsgeom.wkbType() == QgsWkbTypes.Point:
p = qgsgeom.asPoint()
qgsgeom = QgsGeometry.fromPointXY(QgsPointXY(p[1], p[0]))
elif qgsgeom.wkbType() == QgsWkbTypes.MultiPoint:
mp = qgsgeom.asMultiPoint()
qgsgeom = QgsGeometry.fromMultiPointXY([QgsPointXY(p[1], p[0]) for p in mp])
elif qgsgeom.wkbType() == QgsWkbTypes.LineString:
pl = qgsgeom.asPolyline()
qgsgeom = QgsGeometry.fromPolylineXY([QgsPointXY(p[1],p[0]) for p in pl])
elif qgsgeom.wkbType() == QgsWkbTypes.MultiLineString:
mls = qgsgeom.asMultiPolyline()
qgsgeom = QgsGeometry.fromMultiPolylineXY([[QgsPointXY(p[1],p[0]) for p in pl] for pl in mls])
elif qgsgeom.wkbType() == QgsWkbTypes.Polygon:
pl = qgsgeom.asPolygon()
qgsgeom = QgsGeometry.fromPolygonXY([[QgsPointXY(p[1],p[0]) for p in r] for r in pl])
elif qgsgeom.wkbType() == QgsWkbTypes.MultiPolygon:
mp = qgsgeom.asMultiPolygon()
qgsgeom = QgsGeometry.fromMultiPolygonXY([[[QgsPointXY(p[1],p[0]) for p in r] for r in pl] for pl in mp])
return qgsgeom
示例2: processAlgorithm
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
#.........这里部分代码省略.........
idxStart = graph.findVertex(snappedPoints[0])
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
vertices = set()
points = []
lines = []
for vertex, start_vertex_cost in enumerate(cost):
inbound_edge_index = tree[vertex]
if inbound_edge_index == -1 and vertex != idxStart:
# unreachable vertex
continue
if start_vertex_cost > travelCost:
# vertex is too expensive, discard
continue
vertices.add(vertex)
start_point = graph.vertex(vertex).point()
# find all edges coming from this vertex
for edge_id in graph.vertex(vertex).outgoingEdges():
edge = graph.edge(edge_id)
end_vertex_cost = start_vertex_cost + edge.cost(0)
end_point = graph.vertex(edge.toVertex()).point()
if end_vertex_cost <= travelCost:
# end vertex is cheap enough to include
vertices.add(edge.toVertex())
lines.append([start_point, end_point])
else:
# travelCost sits somewhere on this edge, interpolate position
interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue(start_point.x(), start_point.y(), start_vertex_cost,
end_point.x(), end_point.y(), end_vertex_cost, travelCost)
points.append(interpolated_end_point)
lines.append([start_point, interpolated_end_point])
for i in vertices:
points.append(graph.vertex(i).point())
feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…'))
fields = QgsFields()
fields.append(QgsField('type', QVariant.String, '', 254, 0))
fields.append(QgsField('start', QVariant.String, '', 254, 0))
feat = QgsFeature()
feat.setFields(fields)
(point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.MultiPoint, network.sourceCrs())
results = {}
if point_sink is not None:
results[self.OUTPUT] = dest_id
geomPoints = QgsGeometry.fromMultiPointXY(points)
feat.setGeometry(geomPoints)
feat['type'] = 'within'
feat['start'] = startPoint.toString()
point_sink.addFeature(feat, QgsFeatureSink.FastInsert)
if include_bounds:
upperBoundary = []
lowerBoundary = []
vertices = []
for i, v in enumerate(cost):
if v > travelCost and tree[i] != -1:
vertexId = graph.edge(tree[i]).fromVertex()
if cost[vertexId] <= travelCost:
vertices.append(i)
for i in vertices:
upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point())
geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)
feat.setGeometry(geomUpper)
feat['type'] = 'upper'
feat['start'] = startPoint.toString()
point_sink.addFeature(feat, QgsFeatureSink.FastInsert)
feat.setGeometry(geomLower)
feat['type'] = 'lower'
feat['start'] = startPoint.toString()
point_sink.addFeature(feat, QgsFeatureSink.FastInsert)
(line_sink, line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES, context,
fields, QgsWkbTypes.MultiLineString, network.sourceCrs())
if line_sink is not None:
results[self.OUTPUT_LINES] = line_dest_id
geom_lines = QgsGeometry.fromMultiPolylineXY(lines)
feat.setGeometry(geom_lines)
feat['type'] = 'lines'
feat['start'] = startPoint.toString()
line_sink.addFeature(feat, QgsFeatureSink.FastInsert)
return results
示例3: processAlgorithm
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
buf = self.parameterAsDouble(parameters, self.BUFFER, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), QgsWkbTypes.Polygon, source.sourceCrs())
outFeat = QgsFeature()
extent = source.sourceExtent()
extraX = extent.height() * (buf / 100.0)
extraY = extent.width() * (buf / 100.0)
height = extent.height()
width = extent.width()
c = voronoi.Context()
pts = []
ptDict = {}
ptNdx = -1
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
break
geom = inFeat.geometry()
point = geom.asPoint()
x = point.x() - extent.xMinimum()
y = point.y() - extent.yMinimum()
pts.append((x, y))
ptNdx += 1
ptDict[ptNdx] = inFeat.id()
feedback.setProgress(int(current * total))
if len(pts) < 3:
raise QgsProcessingException(
self.tr('Input file should contain at least 3 points. Choose '
'another file and try again.'))
uniqueSet = set(item for item in pts)
ids = [pts.index(item) for item in uniqueSet]
sl = voronoi.SiteList([voronoi.Site(i[0], i[1], sitenum=j) for (j,
i) in enumerate(uniqueSet)])
voronoi.voronoi(sl, c)
inFeat = QgsFeature()
current = 0
if len(c.polygons) == 0:
raise QgsProcessingException(
self.tr('There were no polygons created.'))
total = 100.0 / len(c.polygons)
for (site, edges) in list(c.polygons.items()):
if feedback.isCanceled():
break
request = QgsFeatureRequest().setFilterFid(ptDict[ids[site]])
inFeat = next(source.getFeatures(request))
lines = self.clip_voronoi(edges, c, width, height, extent, extraX, extraY)
geom = QgsGeometry.fromMultiPointXY(lines)
geom = QgsGeometry(geom.convexHull())
outFeat.setGeometry(geom)
outFeat.setAttributes(inFeat.attributes())
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
current += 1
feedback.setProgress(int(current * total))
return {self.OUTPUT: dest_id}
示例4: processAlgorithm
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(
self.invalidSourceError(parameters, self.INPUT))
buf = self.parameterAsDouble(parameters, self.BUFFER, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
context, source.fields(),
QgsWkbTypes.Polygon,
source.sourceCrs())
if sink is None:
raise QgsProcessingException(
self.invalidSinkError(parameters, self.OUTPUT))
outFeat = QgsFeature()
extent = source.sourceExtent()
extraX = extent.width() * (buf / 100.0)
# Adjust the extent
extent.setXMinimum(extent.xMinimum() - extraX)
extent.setXMaximum(extent.xMaximum() + extraX)
extraY = extent.height() * (buf / 100.0)
extent.setYMinimum(extent.yMinimum() - extraY)
extent.setYMaximum(extent.yMaximum() + extraY)
height = extent.height()
width = extent.width()
c = voronoi.Context()
pts = []
ptDict = {}
ptNdx = -1
# Find the minimum and maximum x and y for the input points
xmin = width
xmax = 0
ymin = height
ymax = 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
break
geom = inFeat.geometry()
point = geom.asPoint()
x = point.x() - extent.xMinimum()
y = point.y() - extent.yMinimum()
pts.append((x, y))
ptNdx += 1
ptDict[ptNdx] = inFeat.id()
if x < xmin:
xmin = x
if y < ymin:
ymin = y
if x > xmax:
xmax = x
if y > ymax:
ymax = y
feedback.setProgress(int(current * total))
if xmin == xmax or ymin == ymax:
raise QgsProcessingException('The extent of the input points is '
'not a polygon (all the points are '
'on a vertical or horizontal line) '
'- cannot make a Voronoi diagram!')
xyminmax = [xmin, ymin, xmax, ymax]
if len(pts) < 3:
raise QgsProcessingException(
self.tr('Input file should contain at least 3 points. Choose '
'another file and try again.'))
# Eliminate duplicate points
uniqueSet = set(item for item in pts)
ids = [pts.index(item) for item in uniqueSet]
sl = voronoi.SiteList([voronoi.Site(i[0], i[1], sitenum=j)
for (j, i) in enumerate(uniqueSet)])
voronoi.voronoi(sl, c)
if len(c.polygons) == 0:
raise QgsProcessingException(
self.tr('There were no polygons created.'))
inFeat = QgsFeature()
current = 0
total = 100.0 / len(c.polygons)
# Clip each of the generated "polygons"
for (site, edges) in list(c.polygons.items()):
if feedback.isCanceled():
break
request = QgsFeatureRequest().setFilterFid(ptDict[ids[site]])
inFeat = next(source.getFeatures(request))
boundarypoints = self.clip_voronoi(edges, c, width,
height, extent,
inFeat.geometry().asPoint(),
xyminmax)
ptgeom = QgsGeometry.fromMultiPointXY(boundarypoints)
geom = QgsGeometry(ptgeom.convexHull())
outFeat.setGeometry(geom)
outFeat.setAttributes(inFeat.attributes())
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
current += 1
feedback.setProgress(int(current * total))
return {self.OUTPUT: dest_id}
示例5: processAlgorithm
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
#.........这里部分代码省略.........
if speedFieldName:
speedField = network.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(network,
directionField,
forwardValue,
backwardValue,
bothValue,
defaultDirection)
distUnit = context.project().crs().mapUnits()
multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
if strategy == 0:
strategy = QgsNetworkDistanceStrategy()
else:
strategy = QgsNetworkSpeedStrategy(speedField,
defaultSpeed,
multiplier * 1000.0 / 3600.0)
director.addStrategy(strategy)
builder = QgsGraphBuilder(network.sourceCrs(),
True,
tolerance)
feedback.pushInfo(self.tr('Loading start points...'))
request = QgsFeatureRequest()
request.setDestinationCrs(network.sourceCrs())
features = startPoints.getFeatures(request)
total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0
points = []
source_attributes = {}
i = 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
if not f.hasGeometry():
continue
for p in f.geometry().vertices():
points.append(QgsPointXY(p))
source_attributes[i] = f.attributes()
i += 1
feedback.setProgress(int(current * total))
feedback.pushInfo(self.tr('Building graph...'))
snappedPoints = director.makeGraph(builder, points, feedback)
feedback.pushInfo(self.tr('Calculating service areas...'))
graph = builder.graph()
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.MultiPoint, network.sourceCrs())
vertices = []
upperBoundary = []
lowerBoundary = []
total = 100.0 / len(snappedPoints) if snappedPoints else 1
for i, p in enumerate(snappedPoints):
if feedback.isCanceled():
break
idxStart = graph.findVertex(snappedPoints[i])
origPoint = points[i].toString()
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
for j, v in enumerate(cost):
if v > travelCost and tree[j] != -1:
vertexId = graph.edge(tree[j]).fromVertex()
if cost[vertexId] <= travelCost:
vertices.append(j)
for j in vertices:
upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point())
geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)
feat.setGeometry(geomUpper)
attrs = source_attributes[i]
attrs.extend(['upper', origPoint])
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feat.setGeometry(geomLower)
attrs[-2] = 'lower'
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
vertices[:] = []
upperBoundary[:] = []
lowerBoundary[:] = []
feedback.setProgress(int(i * total))
return {self.OUTPUT: dest_id}
示例6: processAlgorithm
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
def processAlgorithm(self, parameters, context, feedback):
network = self.parameterAsSource(parameters, self.INPUT, context)
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
directionField = -1
if directionFieldName:
directionField = network.fields().lookupField(directionFieldName)
speedField = -1
if speedFieldName:
speedField = network.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(network,
directionField,
forwardValue,
backwardValue,
bothValue,
defaultDirection)
distUnit = context.project().crs().mapUnits()
multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
if strategy == 0:
strategy = QgsNetworkDistanceStrategy()
else:
strategy = QgsNetworkSpeedStrategy(speedField,
defaultSpeed,
multiplier * 1000.0 / 3600.0)
director.addStrategy(strategy)
builder = QgsGraphBuilder(network.sourceCrs(),
True,
tolerance)
feedback.pushInfo(self.tr('Building graph...'))
snappedPoints = director.makeGraph(builder, [startPoint], feedback)
feedback.pushInfo(self.tr('Calculating service area...'))
graph = builder.graph()
idxStart = graph.findVertex(snappedPoints[0])
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
vertices = []
for i, v in enumerate(cost):
if v > travelCost and tree[i] != -1:
vertexId = graph.edge(tree[i]).fromVertex()
if cost[vertexId] <= travelCost:
vertices.append(i)
upperBoundary = []
lowerBoundary = []
for i in vertices:
upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point())
feedback.pushInfo(self.tr('Writing results...'))
fields = QgsFields()
fields.append(QgsField('type', QVariant.String, '', 254, 0))
fields.append(QgsField('start', QVariant.String, '', 254, 0))
feat = QgsFeature()
feat.setFields(fields)
geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.MultiPoint, network.sourceCrs())
feat.setGeometry(geomUpper)
feat['type'] = 'upper'
feat['start'] = startPoint.toString()
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feat.setGeometry(geomLower)
feat['type'] = 'lower'
feat['start'] = startPoint.toString()
sink.addFeature(feat, QgsFeatureSink.FastInsert)
upperBoundary.append(startPoint)
lowerBoundary.append(startPoint)
geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)
return {self.OUTPUT: dest_id}
示例7: run
# 需要导入模块: from qgis.core import QgsGeometry [as 别名]
# 或者: from qgis.core.QgsGeometry import fromMultiPointXY [as 别名]
#.........这里部分代码省略.........
title = QTableWidgetItem(record['data']['title'])
self.dlgTable.tableWidget_Zotero.setItem(i, 3, title)
title_str = record['data']['title']
########## Putting the Extra field into the table
# pre-populate the table with anything already in the Extra field
if 'extra' in record['data']:
#extra = QTableWidgetItem(record['data']['extra'])
extra_zotero = record['data']['extra']
#example of how to pull out the geojson string from a messy Extra field:
#geojson_str = text_extra[text_extra.find("<geojson>")+9:text_extra.find("</geojson>")]
if '<geojson>' in extra_zotero:
extra_str = extra_zotero[extra_zotero.find('<geojson>')+9:extra_zotero.find('</geojson>')]
#before_geojson = extra_zotero[0 : extra_zotero.find("<geojson>")]
#after_geojson = extra_zotero[extra_zotero.find("</geojson>")+10:]
elif '{"type":' in extra_zotero:
extra_str = extra_zotero[extra_zotero.find('{'):extra_zotero.find('}')]
else: extra_str = ''
extra = QTableWidgetItem(extra_str)
#prints the extra string to the log
QgsMessageLog.logMessage("Extra String: %s" % extra_str, 'LiteratureMapper', Qgis.Info)
check_point = '"type": "Point"'
check_multipoint = '"type": "Multip'
if extra_str[1:16] == check_point:
coords = extra_str[extra_str.find('['): extra_str.find(']')+1]
x = float(coords[1:coords.find(',')])
y = float(coords[coords.find(',')+1:coords.find(']')])
#put records with existing geometries into the virtual Point shapefile attribute table
self.fet = QgsFeature()
self.fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x,y)))
self.fet.setAttributes([key_str, year_str, author_list, title_str, extra_str])
self.pointProvider.addFeatures([self.fet])
self.pointLayer.updateExtents()
elif extra_str[1:16] == check_multipoint:
#Alter to make a multipoint
#Needs a loop to run through all the points?
QgsMessageLog.logMessage("Made it into Multipoint Elif", 'LiteratureMapper', Qgis.Info)
# Coords needs to be formatted this way: gPolygon = QgsGeometry.fromPolygon([[QgsPoint(1, 1), QgsPoint(2, 2), QgsPoint(2, 1)]])
coords = extra_str[(extra_str.find('[')+1): (len(extra_str)-2)]
#looks like this: [-132.58038861948805, 36.36773760268237], [-126.90494519104253, 33.262306292778206], [-124.28139115336488, 36.84961487490887]
QgsMessageLog.logMessage("Coords: %s" % coords, 'LiteratureMapper', Qgis.Info)
#Replace [ with [( and add QgsPoint
p=re.compile( '\[' )
c = p.sub('QgsPointXY(', str(coords))
#Replace ] with )]
q = re.compile( '\]' )
coords_list = q.sub(')', str(c))
coords_list = '['+coords_list+']'
QgsMessageLog.logMessage("Coords_List: %s" % coords_list, 'LiteratureMapper', Qgis.Info)
#put records with existing geometries into the virtual Multipoint shapefile attribute table
self.fet = QgsFeature()
#does QgsPoint make a multipoint or do you need another command?
self.fet.setGeometry(QgsGeometry.fromMultiPointXY(eval(coords_list)))
#^change 1,1 back to x,y
self.fet.setAttributes([key_str, year_str, author_list, title_str, extra_str])
self.multipointProvider.addFeatures([self.fet])
self.multipointLayer.updateExtents()
else:
x = ''
QgsMessageLog.logMessage("Not a point or multipoint", 'LiteratureMapper', Qgis.Info)
else:
extra = QTableWidgetItem("")
self.dlgTable.tableWidget_Zotero.setItem(i, 4, extra)
# Reize the cells to fit the contents - behaves badly with the title column
#self.dlgTable.tableWidget_Zotero.resizeRowsToContents()
# Resize the Key and Year columns to fit the width of the contents
self.dlgTable.tableWidget_Zotero.resizeColumnToContents(0)
self.dlgTable.tableWidget_Zotero.resizeColumnToContents(1)
# FUNCTIONALITY
# TODO: Put points on the map canvas: http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/canvas.html#rubber-bands-and-vertex-markers Memory Layers: http://gis.stackexchange.com/questions/72877/how-to-load-a-memory-layer-into-map-canvas-an-zoom-to-it-with-pyqgis http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#memory-provider
# TODO: Transform coordinates if not in WGS84: http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/crs.html
# TODO: update points in the memory shp don't just add new ones
# USABILITY
# TODO: Speed up saving to Zotero - will sending one query be quicker? How does the version stuff work?
# TODO: Make other table columns uneditable: http://stackoverflow.com/questions/2574115/qt-how-to-make-a-column-in-qtablewidget-read-only
# TODO: Documentation
else:
self.iface.messageBar().pushMessage("Zotero cannot connect. Check the IDs you entered and try again.", level=1)