diff --git a/__init__.py b/__init__.py old mode 100755 new mode 100644 index cac41f7..a3a22d0 --- a/__init__.py +++ b/__init__.py @@ -52,5 +52,5 @@ def email(): def classFactory(iface): # load SMLSurveyor class from file SMLSurveyor - from plugin import SMLSurveyor + from .plugin import SMLSurveyor return SMLSurveyor(iface) diff --git a/PyQt4Dialogs.py b/cogo_dialogs.py similarity index 95% rename from PyQt4Dialogs.py rename to cogo_dialogs.py index 4573cc1..80f9863 100755 --- a/PyQt4Dialogs.py +++ b/cogo_dialogs.py @@ -15,17 +15,24 @@ * * ***************************************************************************/ """ +from __future__ import absolute_import + +from builtins import range from collections import OrderedDict -import __init__ as metadata -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.gui import * -from qgis.core import * -from qgisToolbox import FeatureSelector -from PyQt4Widgets import XQPushButton, XQDialogButtonBox -from database import * -from utilities import images_path, get_ui_class, get_path, ExtendedComboBox +from PyQt5.QtCore import QSettings, QMetaObject, QStringListModel +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QCursor, QIcon +from PyQt5.QtWidgets import QDialog, QMessageBox, QGridLayout, QVBoxLayout, QLabel, QFormLayout, QComboBox, QHBoxLayout, \ + QPushButton, QSpacerItem, QApplication, QDialogButtonBox, QLayout, QSplitter, QWidget, QLineEdit, QCheckBox, \ + QRadioButton, QFrame, QCompleter, QSizePolicy, QListWidget, QToolBox +from qgis.core import QgsCredentials, QgsDataSourceUri +from qgis.gui import QgsAuthConfigSelect + +from .cogo_widgets import XQPushButton, XQDialogButtonBox +from .database import * +from .qgisToolbox import FeatureSelector +from .utilities import images_path, get_ui_class, get_path, ExtendedComboBox UI_CLASS = get_ui_class("ui_pgnewconnection.ui") @@ -33,6 +40,7 @@ def _from_utf8(s): return s + # All dialogs using selector tool have a captured function # All dialogs have a get_return function @@ -117,7 +125,7 @@ def accept(self): if settings.contains(base_key + self.txtName.text() + "/service") or \ settings.contains(base_key + self.txtName.text() + "/host"): - message = ("Should the existing connection %s be overwritten?") + message = "Should the existing connection %s be overwritten?" answer = QMessageBox.question(self, "Saving connection", message % (self.txtName.text()), @@ -202,7 +210,7 @@ def populate_database_choices(self): settings_postgres = QSettings() settings_postgres.beginGroup('PostgreSQL/connections') settings_plugin = QSettings() - settings_plugin.beginGroup(metadata.name().replace(" ", "_")) + settings_plugin.beginGroup('CoGo Plugin') for index, database in enumerate(settings_postgres.childGroups()): self.cmbbx_conn.addItem(database) @@ -251,7 +259,7 @@ def test_database_schema(self): db_username = settings_postgis.value(self.connection + '/username') db_password = settings_postgis.value(self.connection + '/password') - uri = QgsDataSourceURI() + uri = QgsDataSourceUri() uri.setConnection( db_host, db_port, @@ -310,7 +318,7 @@ def test_database_schema(self): if crs: query = open( - get_path("scripts","database_setup.sql"), "r").read() + get_path("scripts", "database_setup.sql"), "r").read() query = query.replace(":CRS", "{CRS}") cursor = self.db_connection.cursor() cursor.execute(query.format(CRS=crs)) @@ -373,8 +381,7 @@ def setup_ui(self): self.setWindowTitle(QApplication.translate( "DatabaseConnectionDialog", "Database Connection", - None, - QApplication.UnicodeUTF8 + None )) self.lbl_conn.setText(QApplication.translate( "DatabaseConnectionDialog", @@ -409,6 +416,7 @@ def create_new_connection(self): dialog = NewDatabaseConnectionDialog(self) dialog.exec_() + UI_CLASS = get_ui_class("ui_crsselector.ui") @@ -454,7 +462,7 @@ def populate_combobox(self): ordered_dict_of_crs = OrderedDict(sorted(dict_of_crs.items())) self.crs_combobox.setInsertPolicy(QComboBox.InsertAlphabetically) - for key, item in ordered_dict_of_crs.iteritems(): + for key, item in ordered_dict_of_crs.items(): self.crs_combobox.addItem(item, key) def accept(self): @@ -659,24 +667,21 @@ def setup_ui(self, layer, mode): QApplication.translate( "SelectorDialog", "%s %s" % (layer.name.title(), mode.actor.title()), - None, - QApplication.UnicodeUTF8)) + None)) self.lbl_featID.setText( QApplication.translate( "SelectorDialog", "%s ID" % (layer.name.title()), - None, - QApplication.UnicodeUTF8)) + None)) self.pshbtn_re.setText( QApplication.translate( - "SelectorDialog", "Re-select", None, QApplication.UnicodeUTF8)) + "SelectorDialog", "Re-select", None)) self.chkbx_confirm.setText( QApplication.translate( "SelectorDialog", "I am sure I want to %s this %s" % ( mode.action.lower(), layer.name.lower()), - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.pshbtn_re.clicked.connect(self.reselect) self.chkbx_confirm.stateChanged.connect(self.confirm) @@ -761,26 +766,22 @@ def setup_ui(self, layer): QApplication.translate( "ManagerDialog", "%s Manager" % (layer.name.title()), - None, - QApplication.UnicodeUTF8)) + None)) self.rdbtn_add.setText( QApplication.translate( "ManagerDialog", "Create New %s" % (layer.name.title()), - None, - QApplication.UnicodeUTF8)) + None)) self.rdbtn_edit.setText( QApplication.translate( "ManagerDialog", "Edit Existing %s" % (layer.name.title()), - None, - QApplication.UnicodeUTF8)) + None)) self.rdbtn_del.setText( QApplication.translate( "ManagerDialog", "Delete Existing %s" % (layer.name.title()), - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.btnbx_options.clicked.connect(self.execute_option) QMetaObject.connectSlotsByName(self) @@ -871,13 +872,13 @@ def execute_option(self, button): if str(line_edit.text()).strip() is "": continue if bool(line_edit.property("UNIQUE")): - if self.fields[index].name in self.old_values.keys() and \ - values_new[self.fields[index].name] == \ - self.old_values[self.fields[index].name]: + if self.fields[index].name in list(self.old_values.keys()) and \ + values_new[self.fields[index].name] == \ + self.old_values[self.fields[index].name]: line_edit.setStyleSheet("") elif bool(int(self.db.query(self.query % ( self.fields[index].name, "%s"), - (values_new[self.fields[index].name],))[0][0])): + (values_new[self.fields[index].name],))[0][0])): line_edit.setStyleSheet(self.colours["UNIQUE"]) valid = False else: @@ -929,15 +930,13 @@ def setup_ui(self, fields): "FormBeaconDialog", ("*" if bool(self.lnedts[index].property("REQUIRED")) else "") + f.name.title(), - None, - QApplication.UnicodeUTF8)) + None)) lnedt.setProperty( "TYPE", QApplication.translate( "FormBeaconDialog", str(f.type), - None, - QApplication.UnicodeUTF8)) + None)) self.verticalLayout.addLayout(self.formLayout) self.line_1 = QFrame(self) self.line_1.setFrameShape(QFrame.HLine) @@ -964,15 +963,13 @@ def setup_ui(self, fields): QApplication.translate( "FormBeaconDialog", "Beacon Form", - None, - QApplication.UnicodeUTF8)) + None)) self.label.setText( QApplication.translate( "FormBeaconDialog", "

" "*Required Field

", - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.options_buttonbox.clicked.connect(self.execute_option) QMetaObject.connectSlotsByName(self) @@ -1022,9 +1019,10 @@ def get_values(self): def populate_form(self, data): """ Populate form with values given """ + # get values def checker(data, key): - func = lambda data, key: data[key] if key in data.keys() else None + func = lambda data, key: data[key] if key in list(data.keys()) else None return func(data, key) feat_id = checker(data, "parcel_id") @@ -1090,18 +1088,18 @@ def execute_option(self, button): "Please enter a number for the parcel ID.") return # check that parcel id is valid (i.e. current, unique, available) - if "parcel_id" in self.old_values.keys() and \ + if "parcel_id" in list(self.old_values.keys()) and \ str(self.old_values["parcel_id"]) == parcel_id: pass elif not bool( self.database.query( self.SQL_PARCELS["UNIQUE"], (int(parcel_id),))[0][0]): if not self.new_accepted and QMessageBox.question( - self, - 'Confirm New Parcel ID', - "Are you sure you want to create a new parcel ID?", - QMessageBox.Yes, - QMessageBox.No + self, + 'Confirm New Parcel ID', + "Are you sure you want to create a new parcel ID?", + QMessageBox.Yes, + QMessageBox.No ) == QMessageBox.No: return self.new_accepted = True @@ -1152,9 +1150,9 @@ def new_beacon(self): # get fields fields = self.database.get_schema( self.layers[0].table, [ - self.layers[0].geometry_column, - self.layers[0].primary_key - ]) + self.layers[0].geometry_column, + self.layers[0].primary_key + ]) # display form form = FormBeaconDialog( self.database, @@ -1169,7 +1167,7 @@ def new_beacon(self): id = self.database.query( self.SQL_BEACONS["INSERT"].format( fields=", ".join(sorted(new_values.keys())), - values=", ".join(["%s" for k in new_values.keys()])), + values=", ".join(["%s" for k in list(new_values.keys())])), [new_values[k] for k in sorted(new_values.keys())])[0][0] self.iface.mapCanvas().refresh() self.highlight_feature(self.layers[0].layer, id) @@ -1303,44 +1301,37 @@ def setup_ui(self, autocomplete): QApplication.translate( "FormParcelDialog", "Parcel Form", - None, - QApplication.UnicodeUTF8)) + None)) self.parcel_id_label.setText( QApplication.translate( "FormParcelDialog", "Parcel ID", - None, - QApplication.UnicodeUTF8)) + None)) self.sequence_label.setText( QApplication.translate( "FormParcelDialog", "Beacon Sequence", - None, - QApplication.UnicodeUTF8)) + None)) self.new_pushbutton.setText( QApplication.translate( "FormParcelDialog", "New Beacon", - None, - QApplication.UnicodeUTF8)) + None)) self.start_pushbutton.setText( QApplication.translate( "FormParcelDialog", "Start", - None, - QApplication.UnicodeUTF8)) + None)) self.stop_pushbutton.setText( QApplication.translate( "FormParcelDialog", "Stop", - None, - QApplication.UnicodeUTF8)) + None)) self.reset_pushbutton.setText( QApplication.translate( "FormParcelDialog", "Reset", - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.new_pushbutton.clicked.connect(self.new_beacon) self.start_pushbutton.clicked.connect(self.start_sequence) @@ -1362,7 +1353,7 @@ def __init__( required_layers, parent=None): # initialize QDialog class - super(BearingDistanceFormDialog, self).\ + super(BearingDistanceFormDialog, self). \ __init__(parent, Qt.WindowStaysOnTopHint) # initialize ui self.setupUi() @@ -1373,17 +1364,17 @@ def __init__( self.auto = { "SURVEYPLAN": self.database.query( SQL_BEARDIST["AUTO_SURVEYPLAN"] - )[0][0], + )[0][0], "REFERENCEBEACON": self.database.query( SQL_BEARDIST["AUTO_REFERENCEBEACON"] - )[0][0], + )[0][0], "FROMBEACON": [] } self.survey_plan = None self.reference_beacon = None self.bearing_distance_chain = [] self.bearing_distance_string = ( - "%s" + u"\u00B0" + " and %sm from %s to %s") + "%s" + u"\u00B0" + " and %sm from %s to %s") # initialize initial step self.init_item_survey_plan() @@ -1534,7 +1525,7 @@ def check_item_reference_beacon(self, forward): self.SQL_BEACONS["INSERT"].format( fields=", ".join(sorted(new_values.keys())), values=", ".join( - ["%s" for index in new_values.keys()])), + ["%s" for index in list(new_values.keys())])), [new_values[index] for index in ( sorted(new_values.keys()))]) # set reference beacon @@ -1964,89 +1955,75 @@ def setupUi(self): QApplication.translate( "BearingDistanceFormDialog", "Bearings and Distances Form", - None, - QApplication.UnicodeUTF8)) + None)) self.plan_label.setText( QApplication.translate( "BearingDistanceFormDialog", "Survey Plan", - None, - QApplication.UnicodeUTF8)) + None)) self.plan_next_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Next", - None, - QApplication.UnicodeUTF8)) + None)) self.toolbox.setItemText( self.toolbox.indexOf(self.plan_widget), QApplication.translate( "BearingDistanceFormDialog", "Step 1: Define Survey Plan", - None, - QApplication.UnicodeUTF8)) + None)) self.reference_layout.setText( QApplication.translate( "BearingDistanceFormDialog", "Reference Beacon", - None, - QApplication.UnicodeUTF8)) + None)) self.reference_back_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Back", - None, - QApplication.UnicodeUTF8)) + None)) self.reference_next_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Next", - None, - QApplication.UnicodeUTF8)) + None)) self.toolbox.setItemText( self.toolbox.indexOf(self.reference_widget), QApplication.translate( "BearingDistanceFormDialog", "Step 2: Define Reference Beacon", - None, - QApplication.UnicodeUTF8)) + None)) self.chain_add_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Add Link", - None, - QApplication.UnicodeUTF8)) + None)) self.chain_edit_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Edit Link", - None, - QApplication.UnicodeUTF8)) + None)) self.chain_delete_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Delete Link", - None, - QApplication.UnicodeUTF8)) + None)) self.chain_back_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Back", - None, - QApplication.UnicodeUTF8)) + None)) self.chain_finish_pushbutton.setText( QApplication.translate( "BearingDistanceFormDialog", "Finish", - None, - QApplication.UnicodeUTF8)) + None)) self.toolbox.setItemText( self.toolbox.indexOf(self.chain_widget), QApplication.translate( "BearingDistanceFormDialog", "Step 3: Define Bearings and Distances Chain", - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.options_buttonbox.accepted.connect(self.accept) self.options_buttonbox.rejected.connect(self.reject) @@ -2059,7 +2036,7 @@ def setupUi(self): self.reference_back_pushbutton.clicked.connect( lambda: self.check_item_reference_beacon(False)) self.plan_next_pushbutton.clicked.connect( - lambda : self.check_item_survey_plan(True)) + lambda: self.check_item_survey_plan(True)) self.chain_add_pushbutton.clicked.connect(self.add_link) self.chain_edit_pushbutton.clicked.connect(self.edit_link) self.chain_delete_pushbutton.clicked.connect(self.delete_link) @@ -2080,7 +2057,7 @@ class BearingDistanceLinkFormDialog(QDialog): def __init__(self, database, from_beacons, query, values=[], parent=None): # initialize QDialog class - super(BearingDistanceLinkFormDialog, self).\ + super(BearingDistanceLinkFormDialog, self). \ __init__(parent, Qt.WindowStaysOnTopHint) # initialize ui self.setup_ui(from_beacons) @@ -2182,8 +2159,8 @@ def execute_option(self, button): valid = False break if bool(int(self.database.query( - self.query % ('beacon', "%s"), - (str(line_edit.text()),))[0][0])): + self.query % ('beacon', "%s"), + (str(line_edit.text()),))[0][0])): line_edit.setStyleSheet(self.colours["UNIQUE"]) valid = False break @@ -2225,8 +2202,7 @@ def setup_ui(self, from_beacons): label.setText(QApplication.translate( "dlg_FormBearDistEntry", ("*" if field.required else "") + field.name.title(), - None, - QApplication.UnicodeUTF8)) + None)) self.labels.append(label) line_edit = QLineEdit(self) self.form_layout.setWidget(index, QFormLayout.FieldRole, line_edit) @@ -2248,8 +2224,7 @@ def setup_ui(self, from_beacons): self.setWindowTitle(QApplication.translate( "dlg_FormBearDistEntry", "Link Form", - None, - QApplication.UnicodeUTF8)) + None)) # connect ui widgets self.options_buttonbox.clicked.connect(self.execute_option) QMetaObject.connectSlotsByName(self) diff --git a/PyQt4Widgets.py b/cogo_widgets.py similarity index 90% rename from PyQt4Widgets.py rename to cogo_widgets.py index 147e7ce..f6a43a6 100755 --- a/PyQt4Widgets.py +++ b/cogo_widgets.py @@ -16,10 +16,9 @@ ***************************************************************************/ """ -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.gui import * -from qgis.core import * +from PyQt5.QtGui import QCursor +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QPushButton, QDialogButtonBox class XQPushButton(QPushButton): diff --git a/database.py b/database.py index 6802432..17d202d 100755 --- a/database.py +++ b/database.py @@ -15,10 +15,12 @@ * * ***************************************************************************/ """ +from builtins import str +from builtins import object import psycopg2 -class Field: +class Field(object): def __init__(self, name, type, required, unique): self.name = name @@ -27,7 +29,7 @@ def __init__(self, name, type, required, unique): self.unique = unique -class Manager: +class Manager(object): def __init__(self, parameters): # test db settings @@ -156,7 +158,7 @@ def get_schema(self, table_name, field_ignore): "ON u.column_name = c.column_name " "WHERE c.table_name = '{table}' " "AND c.column_name NOT IN ({ignore});" - .format( + .format( table=table_name, ignore=", ".join( "'%s'" % (i,) for i in field_ignore))))] diff --git a/metadata.txt b/metadata.txt index d8fbbb4..ceb5af3 100755 --- a/metadata.txt +++ b/metadata.txt @@ -3,8 +3,8 @@ [general] name=CoGo Plugin description=A plugin to capture coordinates, bearings and distances and to use these to construct and manage land parcels. -qgisMinimumVersion=2.14 -qgisMaximumVersion=2.99 +qgisMinimumVersion=2.99 +qgisMaximumVersion=3.99 version=3.0 author=Kartoza email=gavin@kartoza.com diff --git a/plugin.py b/plugin.py old mode 100644 new mode 100755 index e8fcdcd..206104c --- a/plugin.py +++ b/plugin.py @@ -20,23 +20,28 @@ * * ***************************************************************************/ """ +from __future__ import absolute_import -# qgis imports -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.core import * # python imports import os -# user imports -import __init__ as metadata -from PyQt4Dialogs import * -import database -from constants import * from datetime import datetime -from utilities import validate_plugin_actions +# qgis imports +from PyQt5.QtCore import QSettings, Qt +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QToolBar, QAction, QMessageBox +from qgis.core import QgsCoordinateReferenceSystem, QgsProject, QgsVectorLayer, QgsCredentials, QgsDataSourceUri + +# user imports + +from .cogo_dialogs import BearingDistanceFormDialog, SelectorDialog, FormParcelDialog, ManagerDialog, FormBeaconDialog, \ + DatabaseConnectionDialog +from . import database +from .constants import * +from .utilities import validate_plugin_actions -class RequiredLayer: + +class RequiredLayer(object): def __init__( self, @@ -58,14 +63,14 @@ def __init__( self.layer = layer -class Mode: +class Mode(object): def __init__(self, actor, action): self.actor = actor self.action = action -class SMLSurveyor: +class SMLSurveyor(object): def __init__(self, iface): # save reference to the QGIS interface @@ -102,14 +107,15 @@ def unload(self): self.refresh_layers() for l in self.required_layers: if bool(l.layer): - QgsMapLayerRegistry.instance().removeMapLayers([l.layer.id()]) + QgsProject.instance().removeMapLayers([l.layer.id()]) def create_plugin_toolbar(self): """ Create plugin toolbar to house buttons """ # create plugin toolbar - self.plugin_toolbar = QToolBar(metadata.name()) - self.plugin_toolbar.setObjectName(metadata.name()) + + self.plugin_toolbar = QToolBar('Parcel Plugin') + self.plugin_toolbar.setObjectName('Parcel Plugin') # create Database Selection button self.select_database_action = QAction( QIcon(os.path.join(self.plugin_dir, "images", "database.png")), @@ -170,7 +176,7 @@ def set_database_connection(self, connection=None, crs=None): # fetch settings settings_plugin = QSettings() settings_postgis = QSettings() - settings_plugin.beginGroup(metadata.name().replace(" ", "_")) + settings_plugin.beginGroup('CoGo Plugin') settings_postgis.beginGroup('PostgreSQL/connections') self.connection = connection if not bool(self.connection): @@ -201,7 +207,7 @@ def set_database_connection(self, connection=None, crs=None): db_password = settings_postgis.value(self.connection + '/password') max_attempts = 3 - self.uri = QgsDataSourceURI() + self.uri = QgsDataSourceUri() self.uri.setConnection( db_host, db_port, @@ -307,7 +313,7 @@ def refresh_layers(self): target_group = root.findGroup(group_name) if not bool(target_group): target_group = root.insertGroup(0, group_name) - target_group.setVisible(Qt.Checked) + target_group.setItemVisibilityChecked(Qt.Checked) for required_layer in reversed(self.required_layers): for layer_node in target_group.findLayers(): @@ -325,14 +331,13 @@ def refresh_layers(self): required_layer.primary_key) added_layer = QgsVectorLayer( self.uri.uri(), required_layer.name_plural, "postgres") - QgsMapLayerRegistry.instance().addMapLayer( - added_layer, False) + QgsProject.instance().addMapLayer(added_layer, False) target_group.addLayer(added_layer) for layer_node in target_group.findLayers(): layer = layer_node.layer() if required_layer.name_plural == layer.name(): required_layer.layer = layer - layer_node.setVisible(Qt.Checked) + layer_node.setItemVisibilityChecked(Qt.Checked) if self.crs: layer.setCrs(self.crs) self.iface.zoomToActiveLayer() @@ -395,10 +400,11 @@ def manage_database_connection(self): if connection: self.set_database_connection(connection=connection, crs=crs) self.refresh_layers() - validate_plugin_actions(self, self.database) + if self.database: + validate_plugin_actions(self, self.database) -class DatabaseManager(): +class DatabaseManager(object): def __init__(self): self.dialog = DatabaseConnectionDialog() @@ -409,20 +415,18 @@ def __init__(self): self.current_connection = self.dialog.get_database_connection() self.current_crs = self.dialog.get_crs() settings_plugin = QSettings() - settings_plugin.beginGroup(metadata.name().replace(" ", "_")) + settings_plugin.beginGroup('CoGo Plugin') settings_plugin.setValue( "DatabaseConnection", self.current_connection) def get_current_connection(self): - return self.current_connection def get_current_crs(self): - return self.current_crs -class BeaconManager(): +class BeaconManager(object): def __init__(self, iface, database, required_layers): self.iface = iface @@ -444,9 +448,9 @@ def run(self): # get fields fields = self.database.get_schema( self.required_layers[0].table, [ - self.required_layers[0].geometry_column, - self.required_layers[0].primary_key - ]) + self.required_layers[0].geometry_column, + self.required_layers[0].primary_key + ]) # display form form_dialog = FormBeaconDialog( self.database, @@ -462,7 +466,7 @@ def run(self): SQL_BEACONS["INSERT"].format( fields=", ".join(sorted(new_values.keys())), values=", ".join( - ["%s" for k in new_values.keys()])), + ["%s" for k in list(new_values.keys())])), [new_values[k] for k in sorted(new_values.keys())]) self.iface.mapCanvas().refresh() else: @@ -498,9 +502,9 @@ def run(self): # get fields fields = self.database.get_schema( self.required_layers[0].table, [ - self.required_layers[0].geometry_column, - self.required_layers[0].primary_key - ]) + self.required_layers[0].geometry_column, + self.required_layers[0].primary_key + ]) # get values values = [value for value in self.database.query( SQL_BEACONS["EDIT"].format( @@ -577,7 +581,7 @@ def run(self): required_layer.layer.removeSelection() -class ParcelManager(): +class ParcelManager(object): def __init__(self, iface, database, required_layers): self.iface = iface @@ -620,9 +624,9 @@ def run(self): beacon, i)) sql = self.database.preview_query( - SQL_PARCELS["INSERT_GENERAL"], - data=points, - multi_data=True) + SQL_PARCELS["INSERT_GENERAL"], + data=points, + multi_data=True) self.database.query(sql) self.iface.mapCanvas().refresh() else: @@ -677,9 +681,9 @@ def run(self): beacon, i)) sql = self.database.preview_query( - SQL_PARCELS["INSERT_GENERAL"], - data=points, - multi_data=True) + SQL_PARCELS["INSERT_GENERAL"], + data=points, + multi_data=True) self.database.query(sql) for required_layer in self.required_layers: required_layer.layer.removeSelection() @@ -710,7 +714,7 @@ def run(self): required_layer.layer.removeSelection() -class BearDistManager(): +class BearDistManager(object): def __init__(self, iface, database, required_layers): self.iface = iface @@ -732,8 +736,8 @@ def run(self): survey_plan, reference_beacon, beardist_chain = dialog.get_return() # check whether survey plan is defined otherwise define it if not self.database.query( - SQL_BEARDIST["IS_SURVEYPLAN"], - (survey_plan,))[0][0]: + SQL_BEARDIST["IS_SURVEYPLAN"], + (survey_plan,))[0][0]: self.database.query( SQL_BEARDIST["INSERT_SURVEYPLAN"], (survey_plan, reference_beacon)) diff --git a/plugin_upload.py b/plugin_upload.py index 5106560..15f298f 100755 --- a/plugin_upload.py +++ b/plugin_upload.py @@ -1,9 +1,15 @@ -#!/usr/bin/env python +from __future__ import print_function + +from future import standard_library + +standard_library.install_aliases() +from builtins import input +# !/usr/bin/env python # This script uploads a plugin package on the server # # Author: A. Pasotti, V. Picavet -import xmlrpclib +from xmlrpc.client import (ServerProxy, Binary, ProtocolError, Fault) import sys import getpass from optparse import OptionParser @@ -24,32 +30,40 @@ def main(options, args): options.server, options.port, ENDPOINT) - print "Connecting to: %s" % hide_password(address) + print("Connecting to: %s" % hide_password(address)) - server = xmlrpclib.ServerProxy(address, verbose=VERBOSE) + server = ServerProxy(address, verbose=VERBOSE) try: plugin_id, version_id = server.plugin.upload( - xmlrpclib.Binary(open(args[0]).read())) - print "Plugin ID: %s" % plugin_id - print "Version ID: %s" % version_id - except xmlrpclib.ProtocolError, err: - print "A protocol error occurred" - print "URL: %s" % hide_password(err.url, 0) - print "HTTP/HTTPS headers: %s" % err.headers - print "Error code: %d" % err.errcode - print "Error message: %s" % err.errmsg - except xmlrpclib.Fault, err: - print "A fault occurred" - print "Fault code: %d" % err.faultCode - print "Fault string: %s" % err.faultString + Binary(open(args[0]).read())) + print("Plugin ID: %s" % plugin_id) + print("Version ID: %s" % version_id) + + except ProtocolError as err: + print() + "A protocol error occurred" + print("URL: %s" % hide_password(err.url, 0)) + + print("HTTP/HTTPS headers: %s" % err.headers) + + print("Error code: %d" % err.errcode) + + print("Error message: %s" % err.errmsg) + + except Fault as err: + print("A fault occurred") + + print("Fault code: %d" % err.faultCode) + + print("Fault string: %s" % err.faultString) def hide_password(url, start=6): """Returns the http url with password part replaced with '*'.""" - passdeb = url.find(':', start) + 1 - passend = url.find('@') - return "%s%s%s" % (url[:passdeb], '*' * (passend - passdeb), url[passend:]) + pass_deb = url.find(':', start) + 1 + pass_end = url.find('@') + return "%s%s%s" % (url[:pass_deb], '*' * (pass_end - pass_deb), url[pass_end:]) if __name__ == "__main__": @@ -80,7 +94,8 @@ def hide_password(url, start=6): metavar="plugins.qgis.org") (options, args) = parser.parse_args() if len(args) != 1: - print "Please specify zip file.\n" + print() + "Please specify zip file.\n" parser.print_help() sys.exit(1) if not options.server: @@ -90,8 +105,9 @@ def hide_password(url, start=6): if not options.username: # interactive mode username = getpass.getuser() - print "Please enter user name [%s] :" % username, - res = raw_input() + print("Please enter user name [%s] :" % username, ) + + res = input() if res != "": options.username = res else: diff --git a/qgisToolbox.py b/qgisToolbox.py index 7e8e269..1a2e537 100755 --- a/qgisToolbox.py +++ b/qgisToolbox.py @@ -15,14 +15,12 @@ * * ***************************************************************************/ """ +from builtins import object +from qgis.core import QgsGeometry +from qgis.gui import QgsMapToolEmitPoint -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.gui import * -from qgis.core import* - -class FeatureSelector(): +class FeatureSelector(object): """ This tool enables the selection of a single feature or multiple features from a vector layer, returning the feature's id or features' ids after each selection via the captured method in the @@ -78,18 +76,18 @@ def capture(self, point, button): """ # check that capturing has been enabled if self.capturing: - point_geometry = QgsGeometry.fromPoint(point) + point_geometry = QgsGeometry.fromPointXY(point) point_buffer = point_geometry.buffer( (self.iface.mapCanvas().mapUnitsPerPixel() * 4), 0) point_rectangle = point_buffer.boundingBox() self.layer.invertSelectionInRectangle(point_rectangle) - if bool(self.layer.selectedFeaturesIds()): - for id in self.layer.selectedFeaturesIds(): + if bool(self.layer.selectedFeatureIds()): + for id in self.layer.selectedFeatureIds(): if id not in self.selected: self.selected.append(id) selected = self.selected for id in selected: - if id not in self.layer.selectedFeaturesIds(): + if id not in self.layer.selectedFeatureIds(): self.selected.remove(id) self.parent.captured(self.selected) diff --git a/test_suite.py b/test_suite.py old mode 100644 new mode 100755 index 26bf42a..c76252b --- a/test_suite.py +++ b/test_suite.py @@ -7,12 +7,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ +from __future__ import print_function +from builtins import str import sys import os import unittest from osgeo import gdal -from qgis.core import QGis +from qgis.core import Qgis __author__ = 'etiennetrimaille' __revision__ = '$Format:%H$' @@ -23,12 +25,18 @@ def _run_tests(test_suite, package_name): """Core function to test a test suite.""" count = test_suite.countTestCases() - print '########' - print '%s tests has been discovered in %s' % (count, package_name) - print 'QGIS : %s' % unicode(QGis.QGIS_VERSION_INT) - print 'Python GDAL : %s' % gdal.VersionInfo('VERSION_NUM') - print 'Run slow tests : %s' % (not os.environ.get('ON_TRAVIS', False)) - print '########' + # fix_print_with_import + print('########') + # fix_print_with_import + print('%s tests has been discovered in %s' % (count, package_name)) + # fix_print_with_import + print('QGIS : %s' % str(Qgis.QGIS_VERSION_INT)) + # fix_print_with_import + print('Python GDAL : %s' % gdal.VersionInfo('VERSION_NUM')) + # fix_print_with_import + print('Run slow tests : %s' % (not os.environ.get('ON_TRAVIS', False))) + # fix_print_with_import + print('########') unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(test_suite) diff --git a/tests/test_qgis_environment.py b/tests/test_qgis_environment.py index 04ae19f..8453598 100644 --- a/tests/test_qgis_environment.py +++ b/tests/test_qgis_environment.py @@ -46,5 +46,6 @@ def test_projection(self): auth_id = layer.crs().authid() self.assertEqual(auth_id, expected_auth_id) + if __name__ == '__main__': unittest.main() diff --git a/utilities.py b/utilities.py old mode 100644 new mode 100755 index 14fb499..a38ca1e --- a/utilities.py +++ b/utilities.py @@ -1,17 +1,19 @@ # coding=utf-8 """This module contains utilities.""" +from builtins import str import os -from PyQt4 import uic -from PyQt4.QtCore import Qt -from PyQt4.QtGui import QCompleter, QComboBox, QSortFilterProxyModel - +from qgis.PyQt import uic +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import QCompleter, QComboBox +from qgis.PyQt.QtCore import QSortFilterProxyModel crs_options = { 'Minna / UTM zone 31N': 26331, 'Minna / UTM zone 32N': 26332 } + def images_path(*args): """Get the path to our resources folder. @@ -34,6 +36,7 @@ def images_path(*args): return path + def get_path(*args): """Get the path to our specific folder from plugin folder. @@ -54,6 +57,7 @@ def get_path(*args): return path + def get_ui_class(ui_file): """Get UI Python class from .ui file. @@ -71,6 +75,7 @@ def get_ui_class(ui_file): ) return uic.loadUiType(ui_file_path, from_imports=True)[0] + def validate_plugin_actions(toolbar, database): """Check DB schema for actions availability. eg: Manage bearing and distance action needs Beacon to be created first. @@ -100,6 +105,7 @@ def validate_plugin_actions(toolbar, database): class ExtendedComboBox(QComboBox): """Extended class of QComboBox so we can perform a filtering of items. """ + def __init__(self, parent=None): super(ExtendedComboBox, self).__init__(parent) @@ -118,11 +124,10 @@ def __init__(self, parent=None): self.setCompleter(self.completer) # connect signals - self.lineEdit().textEdited[unicode].connect( + self.lineEdit().textEdited[str].connect( self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.on_completer_activated) - # on selection of an item from the completer, # select the corresponding item from combobox def on_completer_activated(self, text): @@ -130,14 +135,12 @@ def on_completer_activated(self, text): index = self.findText(text) self.setCurrentIndex(index) - # on model change, update the models of the filter and completer as well def setModel(self, model): super(ExtendedComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) - # on model column change, update the model column of # the filter and completer as well def setModelColumn(self, column):