# -*- coding: utf-8 -*-
"""
/***************************************************************************
InsMw
A QGIS plugin
Insert fish occurrence data to NOFA DB
-------------------
begin : 2017-01-09
git sha : $Format:%H$
copyright : (C) 2017 by NINA
contributors : stefan.blumentrath@nina.no
matteo.destefano@nina.no
jakob.miksch@nina.no
ondrej.svoboda@nina.no
***************************************************************************/
/***************************************************************************
* *
* 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 qgis.core import (
QgsApplication, QgsMessageLog, QgsCoordinateReferenceSystem,
QgsCoordinateTransform, QgsPoint, QgsRasterLayer, QgsMapLayerRegistry,
QgsVectorLayer, QgsDataSourceURI, QgsProject, QgsFeature, QgsGeometry)
from qgis.gui import QgsMapToolEmitPoint
from PyQt4 import QtGui, uic
from PyQt4.QtCore import (
QSettings, QCoreApplication, Qt, QObject, QDate, QDateTime, QObject,
QSignalMapper)
from PyQt4.QtGui import (
QMessageBox, QTreeWidgetItem, QListWidgetItem, QTableWidget,
QTableWidgetItem, QMainWindow, QDoubleValidator, QIntValidator, QComboBox,
QLineEdit, QDateEdit, QAbstractItemView, QValidator, QBrush, QColor,
QPlainTextEdit, QTextCursor, QWidget)
from collections import defaultdict, OrderedDict
import os
import psycopg2
import psycopg2.extras
import datetime
import uuid
import sys
import de
import dtst_dlg
import prj_dlg
import ref_dlg
import vald
from .. import db, ordered_set
class ActLyrExc(Exception):
"""
A custom exception when there is no active layer.
"""
pass
class LocLyrSrcExc(Exception):
"""
A custom exception when a layer source is not `nofa.location`.
"""
pass
class SelFeatExc(Exception):
"""
A custom exception when there are no selected features.
"""
pass
class MtdtNotFldExc(Exception):
"""
A custom exception when a metadata mandatory widget is not filled.
"""
def __init__(self, wdg):
"""
Constructor.
:param nf_nvl: A widget that is not filled/selected.
:type nf_nvl: QWidget
"""
self.wdg = wdg
class OccNotFldExc(Exception):
"""
A custom exception when a mandatory field in occurrence row is not filled.
"""
pass
class NoLocExc(Exception):
"""
A custom exception when no location is provided.
"""
pass
class LocidTxtExc(Exception):
"""
A custom exception when there is a problem
with format of `locationID` location text.
"""
pass
class NvlTxtExc(Exception):
"""
A custom exception when there is a problem
with format of `Norwegian VatLnr` location text.
"""
pass
class CoorTxtExc(Exception):
"""
A custom exception when there is a problem
with format of `coordinates` location text.
"""
pass
class LocidMtyExc(Exception):
"""
A custom exception when location ID is empty.
"""
def __init__(self, m):
"""
Constructor.
:param m: A location table row.
:type m: int
"""
self.m = m
class LocidFmtExc(Exception):
"""
A custom exception when format of location ID is not *uuid.UUID*.
"""
def __init__(self, m, locid):
"""
Constructor.
:param m: A location table row.
:type m: int
:param locid: A location ID.
:type locid: str
"""
self.m = m
self.locid = locid
class LocidNfExc(Exception):
"""
A custom exception when location ID was not found.
"""
def __init__(self, m, locid):
"""
Constructor.
:param m: A location table row.
:type m: int
:param locid: A location ID.
:type locid: str
"""
self.m = m
self.locid = locid
class CoorMtyExc(Exception):
"""
A custom exception when coordinate is empty.
"""
def __init__(self, m):
"""
Constructor.
:param m: A location table row.
:type m: int
"""
self.m = m
class NvlMtyExc(Exception):
"""
A custom exception when Norwegian VatLnr is empty.
"""
def __init__(self, m):
"""
Constructor.
:param m: A location table row.
:type m: int
"""
self.m = m
class NvlNfExc(Exception):
"""
A custom exception when Norwegian VatLnr was not found.
"""
def __init__(self, m, nvl):
"""
Constructor.
:param m: A location table row.
:type m: int
:param nvl: Norwegian VatLnr(s) that was/were not found.
:type nvl: tuple
"""
self.m = m
self.nvl = nvl
FORM_CLASS, _ = uic.loadUiType(
os.path.join(os.path.dirname(__file__), 'ins_mw.ui'))
[docs]class InsMw(QMainWindow, FORM_CLASS):
"""
A main window for inserting data into NOFA database.
"""
def __init__(self, iface, mc, plugin_dir):
"""
Constructor.
:param iface: A reference to the QgisInterface.
:type iface: QgisInterface
:param mc: A reference to the main class.
:type mc: object
:param plugin_dir: A plugin directory.
:type plugin_dir: str
"""
super(InsMw, self).__init__()
# set up the user interface from Designer.
self.setupUi(self)
self.iface = iface
self.mc = mc
self.plugin_dir = plugin_dir
self._setup_self()
def _setup_self(self):
"""
Sets up self.
"""
self.org = u'NINA'
self.app_name = u'NOFAInsert - {}'.format(
self.mc.con_info[self.mc.db_str])
self.settings = QSettings(self.org, self.app_name)
self.setWindowTitle(self.app_name)
self.loctp_dict = {
u'Norwegian VatnLnr': 'no_vatn_lnr',
u'coordinates UTM32': 25832,
u'coordinates UTM33': 25833}
self.crs_dict = OrderedDict([
(u'UTM32', QgsCoordinateReferenceSystem('EPSG:25832')),
(u'UTM33', QgsCoordinateReferenceSystem('EPSG:25833'))])
self.loc_met_list = [
u'locationID',
u'coordinates',
u'Norwegian VatLnr']
self.opt_list = [
u'new',
u'nearest']
self.dash_split_str = u' - '
self.at_split_str = u'@'
self.mty_str = u''
self.all_str = u'<all>'
self.sel_str = u'<select>'
self.forbi_str_list = [
self.mty_str,
self.sel_str]
self.today_dt = datetime.datetime.today().date()
self.nxt_week_dt = self.today_dt + datetime.timedelta(days=7)
self.fltr_str_dt = datetime.datetime(2017, 1, 1)
# self.def_clr = self.ins_btn.palette().background().color()
self.grn_clr = QColor(177, 234, 177)
self.red_clr = QColor(234, 177, 177)
self.yel_clr = QColor(234, 234, 177)
self._build_wdgs()
def _build_wdgs(self):
"""
Builds and sets up own widgets.
"""
self._build_main_tab_wdgs()
self._build_hist_tab_wdgs()
self.main_tabwdg.setCurrentIndex(0)
self.loc_tabwdg.setCurrentIndex(0)
self.loc_manual_swdg.setCurrentIndex(0)
self._create_loc_tbl()
self._create_occ_tbl()
self._con_main_tab_wdgs()
self._con_hist_tab_wdgs()
def _build_main_tab_wdgs(self):
"""
Builds and sets up widgets in main tab.
"""
# event - dateStart
self.dtstrt_mde = de.MtyDe(self)
self.dtstrt_mde.setObjectName(u'dtstrt_mde')
self.dtstrt_mde.setDisplayFormat('yyyy-MM-dd')
self.event_grid_lyt.addWidget(self.dtstrt_mde, 4, 1, 1, 1)
# event - dateEnd
self.dtend_mde = de.MtyDe(self)
self.dtend_mde.setObjectName(u'dtend_mde')
self.dtend_mde.setDisplayFormat('yyyy-MM-dd')
self.event_grid_lyt.addWidget(self.dtend_mde, 5, 1, 1, 1)
# occurrence - verifiedDate
self.verdt_mde = de.MtyDe(self)
self.verdt_mde.setObjectName(u'verdt_mde')
self.verdt_mde.setDisplayFormat('yyyy-MM-dd')
self.occ_grid_lyt.addWidget(self.verdt_mde, 8, 3, 1, 1)
# dictionary - widget: occurrence table header
self.loc_tbl_wdg_hdr_dict = OrderedDict([
(self.loc_edit_met_cb, u'method'),
(self.loc_edit_locid_le, u'locationID'),
(self.loc_edit_crs_cb, u'CRS'),
(self.loc_edit_opt_cb, u'option'),
(self.loc_edit_x_coor_le, u'X'),
(self.loc_edit_y_coor_le, u'Y'),
(self.loc_edit_verloc_le, u'verbatimLocality'),
(self.loc_edit_nvl_le, u'NVL')])
# validators
self.smpsv_le.setValidator(QIntValidator(None))
self.smpe_le.setValidator(QIntValidator(None))
self.oq_le.setValidator(QDoubleValidator(None))
self.loc_edit_x_coor_le.setValidator(QDoubleValidator(None))
self.loc_edit_y_coor_le.setValidator(QDoubleValidator(None))
self.loc_edit_nvl_le.setValidator(QIntValidator(None))
self.event_input_wdgs = [
self.smpp_cb,
self.smpsu_cb,
self.smpsv_le,
self.smpe_le,
self.dtstrt_mde,
self.dtend_mde,
self.fldnum_le,
self.rcdby_le,
self.eventrmk_le,
self.relia_cb]
# dictionary - widget: occurrence table header
self.occ_tbl_wdg_hdr_dict = OrderedDict([
(self.txn_cb, u'taxon'),
(self.ectp_cb, u'ecotype'),
(self.oqt_cb, u'organismQuantityType'),
(self.oq_le, u'organismQuantity'),
(self.occstat_cb, u'occurrenceStatus'),
(self.poptrend_cb, u'populationTrend'),
(self.recnum_le, u'recordNumber'),
(self.occrmk_le, u'occurrenceRemarks'),
(self.estm_cb, u'establishmentMeans'),
(self.estrmk_le, u'establishmentRemarks'),
(self.spwnc_cb, u'spawningCondition'),
(self.spwnl_cb, u'spawningLocation'),
(self.vfdby_le, u'verifiedBy'),
(self.verdt_mde, u'verifiedDate')])
# tool for setting coordinates by left mouse click
self.cnvs = self.iface.mapCanvas()
self.coord_cnvs_tool = QgsMapToolEmitPoint(self.cnvs)
self.coord_cnvs_tool.canvasClicked.connect(
self._set_cnvs_coord_to_loc_tbl)
self.loc_load_btn.setEnabled(False)
self.occ_mand_wdgs = [
self.txn_cb,
self.occstat_cb,
self.estm_cb]
self.mtdt_mand_wdgs = [
self.smpp_cb,
self.dtend_mde,
self.rcdby_le,
self.dtst_cb,
self.prj_cb]
self.all_mand_wdgs = self.occ_mand_wdgs + self.mtdt_mand_wdgs
self.set_mand_wdgs(self.all_mand_wdgs)
# self.main_hspltr.setStretchFactor(0, 1)
# self.main_hspltr.setStretchFactor(1, 2)
self.occ_hspltr.setStretchFactor(0, 1)
self.occ_hspltr.setStretchFactor(1, 2)
def _build_hist_tab_wdgs(self):
"""
Builds and sets up widgets in history tab.
"""
# connect date edits min and max dates
self.hist_ins_dtstrt_de.dateChanged.connect(
self.hist_ins_dtend_de.setMinimumDate)
self.hist_ins_dtend_de.dateChanged.connect(
self.hist_ins_dtstrt_de.setMaximumDate)
self.hist_upd_dtstrt_de.dateChanged.connect(
self.hist_upd_dtend_de.setMinimumDate)
self.hist_upd_dtend_de.dateChanged.connect(
self.hist_upd_dtstrt_de.setMaximumDate)
# set date edits' dates
self.hist_ins_dtstrt_de.setDate(self.fltr_str_dt)
self.hist_ins_dtend_de.setDate(self.today_dt)
self.hist_upd_dtstrt_de.setDate(self.fltr_str_dt)
self.hist_upd_dtend_de.setDate(self.today_dt)
# dictionary for updating history tables
self.hist_tbls_fnc_dict = {
self.hist_occ_tbl: db.get_hist_occ_list,
self.hist_loc_tbl: db.get_hist_loc_list,
self.hist_event_tbl: db.get_hist_event_list,
self.hist_dtst_tbl: db.get_hist_dtst_list,
self.hist_prj_tbl: db.get_hist_prj_list,
self.hist_ref_tbl: db.get_hist_ref_list}
self.hist_input_wdgs = [
self.usr_cb,
self.hist_ins_dtstrt_de,
self.hist_ins_dtend_de,
self.hist_upd_dtstrt_de,
self.hist_upd_dtend_de]
def _create_loc_tbl(self):
"""
Creates an occurrence table with one row.
"""
self._create_tbl_main_tab(
self.loc_tbl,
self.loc_tbl_wdg_hdr_dict.values(),
self.loc_tbl_wdg_hdr_dict.keys(),
self._upd_loc_tbl_item)
def _create_occ_tbl(self):
"""
Creates an occurrence table with one row.
"""
self._create_tbl_main_tab(
self.occ_tbl,
self.occ_tbl_wdg_hdr_dict.values(),
self.occ_tbl_wdg_hdr_dict.keys(),
self._upd_occ_tbl_item)
def _con_main_tab_wdgs(self):
"""
Connects main tab widgets.
"""
self.main_tabwdg.currentChanged.connect(self._fetch_schema)
self._con_loc_wdgs()
self._con_mtdt_wdgs()
self._con_occ_wdgs()
self.txncvg_tw.itemChanged.connect(self._upd_txncvg_tw_chldn)
self.rst_btn.clicked.connect(self._rst)
self.ins_btn.clicked.connect(self._ins)
def _con_loc_wdgs(self):
"""
Connects location widgets.
"""
self.wb_le.returnPressed.connect(self._srch_loc)
self.cntry_code_cb.currentIndexChanged.connect(self._pop_cnty_cb)
self.cnty_cb.currentIndexChanged.connect(self._pop_muni_cb)
self.loc_srch_btn.clicked.connect(self._srch_loc)
self.loc_load_btn.clicked.connect(self._load_loc_lyr)
self.add_seld_feats_btn.clicked.connect(self._add_locid_seld_feats)
self.osm_basemap_btn.clicked.connect(self._add_osm_wms_lyr)
self.loc_edit_coord_cnvs_btn.clicked.connect(self._act_coord_cnvs_tool)
self.loc_manual_met_cb.currentIndexChanged.connect(
self._upd_loc_manual_swdg)
self.loc_manual_met_cb.currentIndexChanged.emit(
self.loc_manual_met_cb.currentIndex())
self.loc_manual_locid_add_btn.clicked.connect(self._add_manual_locid)
self.loc_manual_coor_add_btn.clicked.connect(self._add_manual_coor)
self.loc_manual_nvl_add_btn.clicked.connect(self._add_manual_nvl)
self.loc_edit_met_cb.currentIndexChanged.connect(self._upd_loc_tbl_row)
self.loc_tbl.itemSelectionChanged.connect(self._upd_loc_tbl_wdgs)
self.loc_tabwdg.currentChanged.connect(self._upd_loc_tbl_wdgs)
# table buttons - connect
self.loc_rowup_btn.clicked.connect(self._sel_row_up)
self.loc_rowdwn_btn.clicked.connect(self._sel_row_dwn)
self.loc_addrow_btn.clicked.connect(self._add_tbl_row)
self.loc_delrow_btn.clicked.connect(self._del_tbl_row)
self.loc_rstrow_btn.clicked.connect(self._rst_tbl_row)
self.loc_rstallrows_btn.clicked.connect(self._rst_all_tbl_rows)
self.loc_del_btn.clicked.connect(self._del_all_tbl_rows)
self.preview_btn.clicked.connect(self._preview_loc)
def _con_mtdt_wdgs(self):
"""
Connects metadata widgets.
"""
self.adddtst_btn.clicked.connect(self._open_dtst_dlg)
self.addprj_btn.clicked.connect(self._open_prj_dlg)
self.addref_btn.clicked.connect(self._open_ref_dlg)
self.dtst_cb.activated.connect(self._upd_mtdt_lw)
self.prj_cb.activated.connect(self._upd_mtdt_lw)
self.ref_cb.activated.connect(self._upd_mtdt_lw)
def _con_occ_wdgs(self):
"""
Connects occurrence widgets.
"""
self.txn_cb.currentIndexChanged.connect(self._pop_ectp_cb)
self.occ_tbl.itemSelectionChanged.connect(self._upd_occ_tbl_wdgs)
# table buttons - connect
self.occ_rowup_btn.clicked.connect(self._sel_row_up)
self.occ_rowdwn_btn.clicked.connect(self._sel_row_dwn)
self.occ_addrow_btn.clicked.connect(self._add_tbl_row)
self.occ_delrow_btn.clicked.connect(self._del_tbl_row)
self.occ_rstrow_btn.clicked.connect(self._rst_tbl_row)
self.occ_rstallrows_btn.clicked.connect(self._rst_all_tbl_rows)
self.occ_del_btn.clicked.connect(self._del_all_tbl_rows)
def _con_hist_tab_wdgs(self):
"""
Connects history tab widgets.
"""
self._con_wdgs_sgnls_to_met(self.hist_input_wdgs, self._fill_hist_tbls)
[docs] def set_mand_wdgs(self, wdgs):
"""
Sets mandatory widgets. Mandatory widgets have predefined color
when they are not filled/selected.
- *QLineEdit* -- must contain at least one
- *QComboBox* -- selected value can not be in list of forbidden
strings
- *QDateEdit* -- user must edit (click) on it at least once
:param wdgs: A list of widgets to be set as mandatory.
:type wdgs: list
"""
for wdg in wdgs:
if isinstance(wdg, QLineEdit):
wdg.setValidator(vald.LenTxtVald(wdg))
wdg.textChanged.connect(self._chck_state_text)
wdg.textChanged.emit(wdg.text())
elif isinstance(wdg, QComboBox):
wdg.currentIndexChanged.connect(self._chck_state_text)
wdg.currentIndexChanged.emit(wdg.currentIndex())
elif isinstance(wdg, QDateEdit):
wdg.dateChanged.connect(self._chck_state_text)
wdg.dateChanged.emit(wdg.date())
def _chck_state_text(self):
"""
Checks a sender's state or text and sets its background color
accordingly.
"""
sndr = self.sender()
if isinstance(sndr, QLineEdit):
valr = sndr.validator()
state = valr.validate(sndr.text(), 0)[0]
elif isinstance(sndr, QComboBox):
txt = sndr.currentText()
if txt == self.sel_str:
state = QValidator.Invalid
else:
state = QValidator.Acceptable
elif isinstance(sndr, QDateEdit):
txt = sndr.findChild(QLineEdit).text()
if txt == self.mty_str:
state = QValidator.Invalid
else:
state = QValidator.Acceptable
if state == QValidator.Intermediate or state == QValidator.Invalid:
clr = self.red_clr
stl = 'background-color: {}'.format(clr.name())
else:
stl = ''
sndr.setStyleSheet(stl)
[docs] def chck_mand_wdgs(self, mand_wdgs, exc):
"""
Checks if the given mandatory widgets are filled.
:param mand_wdgs: A list of mandatory widgets.
:type mand_wdgs: list
:param exc: An exception that should be raised.
:type exc: Exception
"""
for wdg in mand_wdgs:
if isinstance(wdg, QLineEdit):
valr = wdg.validator()
if valr.validate(wdg.text(), 0)[0] != QValidator.Acceptable:
raise exc(wdg)
elif isinstance(wdg, QComboBox):
if wdg.currentText() == self.sel_str:
raise exc(wdg)
elif isinstance(wdg, QDateEdit):
if wdg.findChild(QLineEdit).text() == self.mty_str:
raise exc(wdg)
def _upd_loc_manual_swdg(self, idx):
"""
Sets index of location manual stacked widget.
Also resets all input widgets.
:param idx: A current index of location manual method combo box.
:type idx: int
"""
self.loc_manual_swdg.setCurrentIndex(idx)
self._rst_wdgs(self._cur_loc_manual_tbl_wdgs)
def _add_osm_wms_lyr(self):
"""
Adds OpenStreetMap WMS layer.
"""
xml_fp = os.path.join(self.plugin_dir, 'nofa', 'wms', 'osm.xml')
lyr = QgsRasterLayer(xml_fp, 'OSM')
if lyr.isValid():
QgsMapLayerRegistry.instance().addMapLayer(lyr, False)
lyr_count = QgsMapLayerRegistry.instance().count()
lyr_root = QgsProject.instance().layerTreeRoot()
lyr_root.insertLayer(lyr_count, lyr)
def _srch_loc(self):
"""
Searches for location.
Data are filtered based on information in widgets.
"""
wb, cntry_code, cnty, muni = self._loc_fltrs
self.loc_load_btn.setEnabled(False)
locid_list = db.get_loc_by_fltrs(
self.mc.con, wb, cntry_code, cnty, muni)
loc_count = len(locid_list)
if loc_count != 0:
self.loc_load_btn.setEnabled(True)
self.locid_list = locid_list
self.loc_lyr_name = u'location-{}-{}-{}-{}'.format(
wb, cntry_code, cnty, muni)
else:
self.loc_load_btn.setEnabled(False)
self.lake_name_statlbl.setText(
u'Found {} location(s).'.format(loc_count))
def _get_val_txt(self, txt, forbi=False, all=False):
"""
Returns a validated text.
:param txt: A text to be validated.
:type txt: str
:param forbi: True to allow forbidden text, False otherwise.
:type forbi: bool
:param all: True to allow all text, False otherwise.
:type all: bool
:returns: A filter, None when text is in list of forbidden strings
or when length of text is zero.
:rtype: str
"""
if forbi is False and txt in self.forbi_str_list:
val_txt = None
elif all is False and txt == self.all_str:
val_txt = None
elif len(txt) == 0:
val_txt = None
else:
val_txt = txt
return val_txt
@property
def _loc_fltrs(self):
"""
Returns location filters.
It is used to filter locations.
:returns:
| A tuple containing:
| - *str* -- water body
| - *str* -- country code
| - *str* -- county
| - *str* -- municipality
:rtype: tuple
"""
wb = self._wb
cntry_code = self._cntry_code
cnty = self._cnty
muni = self._muni
return (wb, cntry_code, cnty, muni)
@property
def _wb(self):
"""
Returns a water body from water body line edit.
Returns None when there is no text in the line edit.
:returns: A water body, None when there is no text in the line edit.
:rtype: str
"""
txt = self.wb_le.text()
wb = self._get_val_txt(txt, all=True)
return wb
@property
def _cntry_code(self):
"""
Returns a country code from country code combo box.
:returns: A country code, None when text is equal to `<all>` string
or when length of text is zero.
:rtype: str
"""
txt = self.cntry_code_cb.currentText()
cntry_code = self._get_val_txt(txt)
return cntry_code
@property
def _cnty(self):
"""
Returns a county from county combo box.
:returns: A county, None when text is equal to `<all>` string
or when length of text is zero.
:rtype: str
"""
txt = self.cnty_cb.currentText()
cnty = self._get_val_txt(txt)
return cnty
@property
def _muni(self):
"""
Returns a municipality from municipality combo box.
:returns: A municipality, None when text is equal to `<all>` string
or when length of text is zero.
:rtype: str
"""
txt = self.muni_cb.currentText()
muni = self._get_val_txt(txt)
return muni
@property
def _txn(self):
"""
Returns a taxon from taxon combo box.
:returns: A taxon, None when text is equal to `<all>` string
or when length of text is zero.
:rtype: str
"""
txt = self.txn_cb.currentText()
txn = self._get_val_txt(txt)
return txn
def _load_loc_lyr(self):
"""
Loads a layer containing found locations.
"""
wb, cntry_code, cnty, muni = self._loc_fltrs
loc_lyr = self._get_loc_lyr(
self.locid_list,
u'search_location-{}-{}-{}-{}'.format(wb, cntry_code, cnty, muni))
if loc_lyr.isValid():
QgsMapLayerRegistry.instance().addMapLayer(loc_lyr)
def _get_loc_lyr(self, locid_list, loc_lyr_name):
"""
Returns a location layer containing features with the given
location IDs.
The name of the returned location layer is set according to the given
name.
:param locid_list: A list of location IDs.
:type locid_list: list
:param loc_lyr_name: A location layer name.
:type loc_lyr_name: str
:returns: A location layer containing features with the given
location IDs.
:rtype: QgsVectorLayer
"""
uri = QgsDataSourceURI()
con_info = self.mc.con_info
uri.setConnection(
con_info[self.mc.host_str],
con_info[self.mc.port_str],
con_info[self.mc.db_str],
con_info[self.mc.usr_str],
con_info[self.mc.pwd_str])
uri.setDataSource(
'nofa',
'location',
'geom',
'"locationID" IN ({})'.format(
', '.join(['\'{}\''.format(str(l)) for l in locid_list])),
'locationID')
loc_lyr = QgsVectorLayer(uri.uri(), loc_lyr_name, u'postgres')
return loc_lyr
def _add_locid_seld_feats(self):
"""
Adds location IDs of selected features to the location table.
"""
try:
lyr = self.iface.activeLayer()
self._chck_lyr(lyr)
if lyr.selectedFeatureCount() == 0:
raise SelFeatExc()
sel_feats = lyr.selectedFeaturesIterator()
for feat in sel_feats:
id = str(feat.attribute('locationID'))
self._set_loc_tbl_row(self._get_locid_list(id))
except ActLyrExc:
QMessageBox.warning(
self,
u'No Active Layer',
u'There is no active layer.')
except LocLyrSrcExc:
QMessageBox.warning(
self,
u'Layer Source',
u'Source of active layer is not "nofa.location".')
except SelFeatExc:
QMessageBox.warning(
self,
u'Selected Features',
u'There are no selected features.')
def _chck_lyr(self, lyr):
"""
Checks if the given layer is a from `nofa.location` table.
:param lyr: A layer to be checked.
:type lyr: QgsVectorLayer
"""
try:
uri = QgsDataSourceURI(lyr.source())
except AttributeError:
raise ActLyrExc()
if uri.schema() != 'nofa' or uri.table() != 'location':
raise LocLyrSrcExc()
def _get_locid_list(self, id):
"""
Returns a location ID list that is used to populate location table.
:param id: A location ID.
:type id: str
:returns: A location ID list.
:rtype: list
"""
locid_list = [None] * len(self.loc_tbl_wdg_hdr_dict)
locid_list[0] = self.loc_met_list[0]
locid_list[1] = id
return locid_list
def _extr_locid_list(self, locid_list):
"""
Extracts data from location ID list.
:param locid_list: A location ID list.
:type locid_list: list
:returns: A location ID.
:rtype: str
"""
locid = locid_list[1]
return locid
def _get_coor_list(self, crs_desc, opt, x, y, verb_loc=None):
"""
Returns a coordinates list that is used to populate location table.
:param crs_desc: A CRS description.
:type crs_desc: str
:param opt: An option.
:type opt: str
:param x: X coordinate.
:type x: float
:param y: Y coordinate.
:type y: float.
:param verb_loc: A verbatim locality.
:type verb_loc: str
:returns: A coordinates list.
:rtype: list.
"""
coor_list = [None] * len(self.loc_tbl_wdg_hdr_dict)
coor_list[0] = self.loc_met_list[1]
coor_list[2] = crs_desc
coor_list[3] = opt
coor_list[4] = str(x)
coor_list[5] = str(y)
coor_list[6] = verb_loc
return coor_list
def _extr_coor_list(self, coor_list):
"""
Extracts data from coordinates list.
:param coor_list: A coordinates list.
:type coor_list: list
:returns:
| A tuple containing:
| - *str* -- CRS description,
| - *str* -- option
| - *float* -- X coordinate
| - *float* -- Y coordinate
| - *str* -- verbatim locality
:rtype: tuple
"""
crs_desc = coor_list[2]
opt = coor_list[3]
x = float(coor_list[4])
y = float(coor_list[5])
verb_loc = coor_list[6]
return (crs_desc, opt, x, y, verb_loc)
def _get_nvl_list(self, nvl):
"""
Returns a `Norwegian VatnLnr` list that is used to populate location
table.
:param nvl: A `Norwegian VatnLnr`.
:type nvl: int
:returns: A `Norwegian VatnLnr` list.
:rtype: list
"""
nvl_list = [None] * len(self.loc_tbl_wdg_hdr_dict)
nvl_list[0] = self.loc_met_list[2]
nvl_list[7] = str(nvl)
return nvl_list
def _extr_nvl_list(self, nvl_list):
"""
Extracts data from `Norwegian VatnLnr` list.
:param nvl_list: A `Norwegian VatnLnr` list.
:type nvl_list: list
:returns: A `Norwegian VatnLnr`.
:rtype: int
"""
nvl = int(nvl_list[7])
return nvl
[docs] def dsc_from_iface(self):
"""
Disconnects the plugin from the QGIS interface.
"""
if self.iface.mapCanvas().mapTool() == self.coord_cnvs_tool:
self.iface.mapCanvas().unsetMapTool(self.coord_cnvs_tool)
self.iface.mapCanvas().setMapTool(self.last_map_tool)
def _act_coord_cnvs_tool(self):
"""
Activates a tool that allows user to set coordinates by mouse click.
"""
self.last_map_tool = self.iface.mapCanvas().mapTool()
self.iface.mapCanvas().setMapTool(self.coord_cnvs_tool)
def _set_cnvs_coord_to_loc_tbl(self, pnt, btn):
"""
Sets canvas coordinates to the location table.
It transforms coordinates to the current CRS.
Coordinates are set only on left mouse click.
:param pnt: A point.
:type pnt: QgsPoint
:param btn: A mouse button.
:type btn: QtCore.MouseButton
"""
row_data = self._get_row_data(self.loc_tbl, self.loc_tbl.currentRow())
# set coordinates only on left mouse click
# and when method of current row is 'coordinates'
if btn == Qt.LeftButton and row_data[0] == self.loc_met_list[1]:
in_crs = self.cnvs.mapSettings().destinationCrs()
crs_desc = self._edit_crs_desc
out_crs = self.crs_dict[crs_desc]
in_x = pnt.x()
in_y = pnt.y()
out_x, out_y = self._trf_coord(in_crs, out_crs, in_x, in_y)
self.loc_edit_x_coor_le.setText(str(out_x))
self.loc_edit_y_coor_le.setText(str(out_y))
@property
def _edit_crs_desc(self):
"""
Returns an edit CRS description.
:returns: An edit CRS description.
:rtype: str
"""
crs_desc = self.loc_edit_crs_cb.currentText()
return crs_desc
@property
def _manual_crs_desc(self):
"""
Returns a manual CRS description.
:returns: A manual CRS description.
:rtype: str
"""
crs_desc = self.loc_manual_coor_crs_cb.currentText()
return crs_desc
@property
def _edit_opt(self):
"""
Returns an edit option.
:returns: An edit option.
:rtype: str
"""
opt = self.loc_edit_opt_cb.currentText()
return opt
@property
def _manual_opt(self):
"""
Returns a manual option.
:returns: A manual option.
:rtype: str
"""
opt = self.loc_manual_coor_opt_cb.currentText()
return opt
def _trf_coord(self, in_crs, out_crs, in_x, in_y):
"""
Transforms the given X and Y coordinates from the input CRS
to the output CRS.
:param in_crs: An input CRS.
:type in_crs: QgsCoordinateReferenceSystem
:param out_crs: An Output CRS.
:type out_crs: QgsCoordinateReferenceSystem
:param in_x: An input X coordinate.
:type in_x: float
:param in_y: An input Y coordinate.
:type in_y: float
:returns: X and Y coordinates in the output CRS.
:rtype: tuple
"""
trf = QgsCoordinateTransform(in_crs, out_crs)
out_x, out_y = trf.transform(QgsPoint(in_x, in_y))
return (out_x, out_y)
def _add_manual_locid(self):
"""
Adds location IDs from text to location table.
"""
try:
locid_input_set = self._get_locid_input_set()
for locid in locid_input_set:
self._set_loc_tbl_row(self._get_locid_list(*locid))
except NoLocExc:
QMessageBox.warning(
self, u'No Location', u'Enter at least one location.')
except LocidTxtExc:
QMessageBox.warning(
self,
u'locationID',
u'Enter valid UUID separated by commas.\n'
u'For example:\n'
u'0001b8f3-65fb-4877-8808-ca67094e1cbb, '
u'0002bdc7-b232-4c5b-bd4d-3d4f21da24b6')
def _get_locid_input_set(self):
"""
Returns a location ID input set.
:returns: A location ID input set.
:rtype: ordered_set.OrderedSet
"""
locid_txt = self.loc_manual_locid_pte.toPlainText()
if len(locid_txt) == 0:
raise NoLocExc()
locid_txt = locid_txt.strip(',')
locid_input_list = [locid.strip() for locid in locid_txt.split(',')]
for i, locid in enumerate(locid_input_list):
try:
uuid.UUID(locid)
locid_input_list[i] = [locid]
except ValueError:
raise LocidTxtExc()
locid_input_set = ordered_set.OrderedSet(map(tuple, locid_input_list))
return locid_input_set
def _add_manual_coor(self):
"""
Adds coordinates from text to location table.
"""
try:
crs_desc = self._manual_crs_desc
opt = self._manual_opt
coor_input_set = self._get_coor_input_set()
for coor in coor_input_set:
self._set_loc_tbl_row(
self._get_coor_list(crs_desc, opt, *coor))
except NoLocExc:
QMessageBox.warning(
self, u'No Location', u'Enter at least one location.')
except CoorTxtExc:
QMessageBox.warning(
self,
u'Coordinates',
u'Enter location in this format separated by commas '
u'(verbatimLocality is optional):\n'
u'"<X> <Y> <verbatimLocality>"\n'
u'For example:\n'
u'601404.85 6644928.24 Hovinbk, '
u'580033.12 6633807.99 Drengsrudbk')
def _get_coor_input_set(self):
"""
Returns a coordinates input set.
:returns: A coordinates input set.
:rtype: ordered_set.OrderedSet
"""
coor_txt = self.loc_manual_coor_pte.toPlainText()
if len(coor_txt) == 0:
raise NoLocExc()
coor_txt = coor_txt.strip(',')
coor_input_list = \
[loc.strip().split(' ') for loc in coor_txt.split(',')]
for m in range(len(coor_input_list)):
for n in range(2):
try:
coor_input_list[m][n] = float(coor_input_list[m][n])
except ValueError:
raise CoorTxtExc()
coor_input_set = ordered_set.OrderedSet(map(tuple, coor_input_list))
return coor_input_set
def _add_manual_nvl(self):
"""
Adds `Norwegian VatnLnr` from text to location table.
"""
try:
nvl_input_set = self._get_nvl_input_set()
for nvl in nvl_input_set:
self._set_loc_tbl_row(self._get_nvl_list(*nvl))
except NoLocExc:
QMessageBox.warning(
self, u'No Location', u'Enter at least one location.')
except NvlTxtExc:
QMessageBox.warning(
self,
u'Norwegian VatLnr',
u'Enter integers separated by commas.\n'
u'For example:\n'
u'3067, 5616, 5627')
def _get_nvl_input_set(self):
"""
Returns a `Norwegian VatnLnr` input set.
:returns: A `Norwegian VatnLnr` input set.
:rtype: ordered_set.OrderedSet
"""
nvl_txt = self.loc_manual_nvl_pte.toPlainText()
if len(nvl_txt) == 0:
raise NoLocExc()
nvl_txt = nvl_txt.strip(',')
nvl_input_list = [nvl.strip() for nvl in nvl_txt.split(',')]
for i, nvl in enumerate(nvl_input_list):
try:
nvl_input_list[i] = [int(nvl)]
except ValueError:
raise NvlTxtExc()
nvl_input_set = ordered_set.OrderedSet(map(tuple, nvl_input_list))
return nvl_input_set
def _preview_loc(self):
"""
Previews all locations in the location table.
It adds two layer to map canvas:
- layer of existing locations
- layer of new locations.
"""
try:
locid_list = []
tbl = self.loc_tbl
new_loc_feat_list = []
for m in range(tbl.rowCount()):
row_data = self._get_row_data(tbl, m)
loc_met = row_data[0]
# locationID
if loc_met == self.loc_met_list[0]:
locid = self._get_locid_locid(m, row_data)
# coordinates
elif loc_met == self.loc_met_list[1]:
new_loc_feat, locid = self._get_new_loc_feat_locid_coor(
m, row_data)
if new_loc_feat:
new_loc_feat_list.append(new_loc_feat)
# nvl
elif loc_met == self.loc_met_list[2]:
locid = self._get_locid_nvl(m, row_data)
if locid:
locid_list.append(locid)
if len(locid_list) != 0:
exg_loc_lyr = self._get_loc_lyr(
locid_list, u'preview_location-existing')
if exg_loc_lyr.isValid():
QgsMapLayerRegistry.instance().addMapLayer(exg_loc_lyr)
if len(new_loc_feat_list) != 0:
new_loc_lyr = QgsVectorLayer(
u'Point?crs={}'.format(self._utm33_crs.authid()),
u'preview_location-new',
u'memory')
dp = new_loc_lyr.dataProvider()
dp.addFeatures(new_loc_feat_list)
new_loc_lyr.updateExtents()
if new_loc_lyr.isValid():
QgsMapLayerRegistry.instance().addMapLayer(new_loc_lyr)
except LocidMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID of selected row is empty.')
except LocidFmtExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID "{}" is not UUID.'.format(e.locid))
except LocidNfExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID "{}" was not found.'.format(e.locid))
except CoorMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 5)
QMessageBox.warning(
self,
u'coordinates',
u'Both X and Y coordinates must be entered.')
except NvlMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 7)
QMessageBox.warning(
self,
u'Norwegian VatLnr',
u'Norwegian VatLnr of selected row is empty.')
except NvlNfExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 7)
QMessageBox.warning(
self,
u'Norwegian VatLnr',
u'Norwegian VatLnr code "{}" was not found.'.format(e.nvl))
def _get_new_loc_feat_locid_coor(self, m, row_data):
"""
Returns a new location feature or a location ID.
It is used for 'coordinates' method.
Checks if both X and Y coordinates are entered.
Based on option it returns a new location feature
or returns location ID of the nearest location.
:param m: A location table row.
:type m: int
:param row_data: Data in location table row.
:type row_data: list
:returns: A location ID of new location or the nearest location.
:rtype: str
"""
try:
crs_desc, opt, x, y, verb_loc = self._extr_coor_list(row_data)
except TypeError:
raise CoorMtyExc(m)
crs = self.crs_dict[crs_desc]
srid = crs.authid().split(u':')[1]
new_loc_feat = None
locid = None
# new
if opt == self.opt_list[0]:
out_crs = self._utm33_crs
out_x, out_y = self._trf_coord(crs, out_crs, x, y)
pnt_geom = QgsGeometry.fromPoint(QgsPoint(out_x, out_y))
new_loc_feat = QgsFeature()
new_loc_feat.setGeometry(pnt_geom)
# nearest
elif opt == self.opt_list[1]:
locid = self._get_nrst_locid(x, y, srid)
return (new_loc_feat, locid)
@property
def _utm33_crs(self):
"""
Return UTM33 CRS.
:returns: UTM33 CRS.
:rtype: QgsCoordinateReferenceSystem
"""
utm33_crs = self.crs_dict[u'UTM33']
return utm33_crs
def _fetch_schema(self):
"""
Fetches a schema based on what tab is active.
If the main tab is active it fetches data from `NOFA` schema,
otherwise it fetches data from `plugin` schema.
"""
idx = self.main_tabwdg.currentIndex()
if idx == 0:
self._fetch_nofa_schema()
elif idx == 1:
self._fetch_plugin_schema()
def _fetch_plugin_schema(self):
"""
Fetches data from the `plugin` schema and populates tables.
"""
self._pop_usr_cb()
self._fill_hist_tbls()
self.hist_tabwdg.setCurrentIndex(0)
def _pop_usr_cb(self):
"""
Populates the user combo box.
"""
usr_list = db.get_usr_list(self.mc.con)
usr_list.insert(0, self.all_str)
self.usr_cb.clear()
self.usr_cb.addItems(usr_list)
self.usr_cb.setCurrentIndex(
usr_list.index(self.mc.con_info[self.mc.usr_str]))
def _fill_hist_tbls(self):
"""
Fills all history tables.
"""
hist_fltrs = self._hist_fltrs
for tbl, fnc in self.hist_tbls_fnc_dict.items():
tbl_list, tbl_hdrs = fnc(self.mc.con, *hist_fltrs)
self._create_tbl_hist_tab(tbl, tbl_list, tbl_hdrs)
@property
def _hist_fltrs(self):
"""
Returns history filters.
It is used to filter entries in history tab.
:returns:
| A tuple containing:
| - *str* -- user
| - *datetime.date* -- insert start date
| - *datetime.date* -- insert end date
| - *datetime.date* -- update start date
| - *datetime.date* -- update end date
:rtype: tuple
"""
usr_txt = self.usr_cb.currentText()
usr = self._get_val_txt(usr_txt)
ins_dt_strt = self.hist_ins_dtstrt_de.date().toPyDate()
ins_dt_end = self.hist_ins_dtend_de.date().toPyDate()
upd_dt_strt = self.hist_upd_dtstrt_de.date().toPyDate()
upd_dt_end = self.hist_upd_dtend_de.date().toPyDate()
return (usr, ins_dt_strt, ins_dt_end, upd_dt_strt, upd_dt_end)
def _open_dtst_dlg(self):
"""
Opens a dialog for adding a new dataset.
"""
self.dtst_dlg = dtst_dlg.DtstDlg(self.mc, self)
self.dtst_dlg.show()
def _open_prj_dlg(self):
"""
Opens a dialog for adding a new project.
"""
self.prj_dlg = prj_dlg.PrjDlg(self.mc, self)
self.prj_dlg.show()
def _open_ref_dlg(self):
"""
Opens a dialog for adding a new reference.
"""
self.ref_dlg = ref_dlg.RefDlg(self.mc, self)
self.ref_dlg.show()
def _upd_txncvg_tw_chldn(self, par):
"""
Updates children in the taxonomic coverage tree widget
based on the state of its parent.
:param par: A changed item.
:type par: QTableWidgetItem
"""
chck_state = par.checkState(0)
for i in range(par.childCount()):
chld = par.child(i)
chld.setCheckState(0, chck_state)
self._upd_txncvg_tw_chldn(chld)
def _rst(self):
"""
Resets all widgets in the main tab.
"""
self._rst_loc_tbl()
self._rst_loc_wdgs()
self._rst_event_wdgs()
self._rst_mtdt_wdgs()
self._rst_occ_tbl()
self._rst_txncvg_tw()
def _rst_loc_tbl(self):
"""
Resets location table.
"""
self.loc_del_btn.click()
self.loc_rstrow_btn.click()
def _rst_loc_wdgs(self):
"""
Resets location widgets.
"""
self._rst_cb_by_cb_dict(self._loc_cb_dict)
self._rst_cb_by_cb_dict(self._loc_edit_met_cb_dict)
self._rst_cb_by_cb_dict(self._loc_manual_met_cb_dict)
self.wb_le.clear()
self.lake_name_statlbl.setText(u'Search for locations.')
def _rst_event_wdgs(self):
"""
Resets all event widgets.
"""
self._rst_wdgs(self.event_input_wdgs)
self._rst_cb_by_cb_dict(self._event_cb_dict)
def _rst_mtdt_wdgs(self):
"""
Resets all metadata widgets.
"""
sel_str = self.sel_str
self.upd_dtst(sel_str)
self.upd_prj(sel_str)
self.upd_ref(sel_str)
def _rst_occ_tbl(self):
"""
Resets occurrence table.
Also resets occurrence widgets because it is connected to the table.
"""
self.occ_del_btn.click()
self.occ_rstrow_btn.click()
def _rst_txncvg_tw(self):
"""
Resets taxonomic coverage tree widget.
"""
txncvg_root_item = self.txncvg_tw.invisibleRootItem().child(0)
if txncvg_root_item.checkState(0) == Qt.Unchecked:
txncvg_root_item.setCheckState(0, Qt.Checked)
txncvg_root_item.setCheckState(0, Qt.Unchecked)
self.txncvg_tw.expandToDepth(0)
def _ins(self):
"""
Inserts the data into the database.
"""
try:
self.chck_mand_wdgs(self.mtdt_mand_wdgs, MtdtNotFldExc)
self._chck_occ_tbl()
locid_list = self._get_loc_list()
event_list = self.get_wdg_list(self.event_input_wdgs)
dtst_id = self._get_dtst_id()
prj_id = self._get_prj_id()
ref_id = self._get_ref_id()
for loc_id in locid_list:
event_id = uuid.uuid4()
db.ins_event(
self.mc.con,
loc_id, event_id, event_list, dtst_id, prj_id, ref_id)
db.ins_event_log(
self.mc.con,
loc_id, event_id, dtst_id, prj_id, ref_id,
self.mc.con_info[self.mc.usr_str])
self._ins_txncvg(event_id)
for m in range(self.occ_tbl.rowCount()):
occ_id = uuid.uuid4()
occ_row_list = self._get_occ_row_list(m)
txn_id = db.get_txn_id(self.mc.con, occ_row_list[0])
ectp = occ_row_list[1]
ectp_id = db.get_ectp_id(self.mc.con, ectp)
db.ins_occ(
self.mc.con,
occ_id, txn_id, ectp_id, occ_row_list, event_id)
db.ins_occ_log(
self.mc.con,
occ_id, event_id, dtst_id, prj_id, ref_id, loc_id,
self.mc.con_info[self.mc.usr_str])
QMessageBox.information(self, u'Saved', u'Data correctly saved.')
except MtdtNotFldExc as e:
self.main_tb.setCurrentWidget(e.wdg.parent())
e.wdg.setFocus()
QMessageBox.warning(
self,
u'Mandatory Metadata Fields',
u'Fill/select all mandatory metadata fields.')
except OccNotFldExc:
QMessageBox.warning(
self, u'Taxon', u'Select taxon.')
except LocidMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID of selected row is empty.')
except LocidFmtExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID "{}" is not UUID.'.format(e.locid))
except LocidNfExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 1)
QMessageBox.warning(
self,
u'locationID',
u'locationID "{}" was not found.'.format(e.locid))
except CoorMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 5)
QMessageBox.warning(
self,
u'coordinates',
u'Both X and Y coordinates must be entered.')
except NvlMtyExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 7)
QMessageBox.warning(
self,
u'Norwegian VatLnr',
u'Norwegian VatLnr of selected row is empty.')
except NvlNfExc as e:
self.main_tb.setCurrentWidget(self.loc_wdg)
self.loc_tbl.setCurrentCell(e.m, 7)
QMessageBox.warning(
self,
u'Norwegian VatLnr',
u'Norwegian VatLnr code "{}" was not found.'.format(e.nvl))
def _chck_occ_tbl(self):
"""
Checks if all rows in the occurrence are filled.
"""
for m in range(self.occ_tbl.rowCount()):
occ_row_list = self._get_occ_row_list(m)
if occ_row_list[0] is None:
self.occ_tbl.selectRow(m)
raise OccNotFldExc()
def _get_loc_list(self):
"""
Returns a location ID list.
:returns: A location ID list.
:rtype: list
"""
locid_list = []
tbl = self.loc_tbl
for m in range(tbl.rowCount()):
row_data = self._get_row_data(tbl, m)
loc_met = row_data[0]
# locationID
if loc_met == self.loc_met_list[0]:
locid = self._get_locid_locid(m, row_data)
# coordinates
elif loc_met == self.loc_met_list[1]:
locid = self._get_locid_coor(m, row_data)
# nvl
elif loc_met == self.loc_met_list[2]:
locid = self._get_locid_nvl(m, row_data)
locid_list.append(locid)
return locid_list
def _get_locid_locid(self, m, row_data):
"""
Returns a location ID. It is used for 'locationID' method.
Checks if location ID is empty, if it a valid *UUID*
and if it exists in the database.
:param m: A location table row.
:type m: int
:param row_data: Data in location table row.
:type row_data: list
:returns: A location ID.
:rtype: str
"""
locid = self._extr_locid_list(row_data)
if not locid:
raise LocidMtyExc(m)
try:
uuid.UUID(locid)
except ValueError:
raise LocidFmtExc(m, locid)
if not db.chck_locid(self.mc.con, locid):
raise LocidNfExc(m, locid)
return locid
def _get_locid_coor(self, m, row_data):
"""
Returns a location ID. It is used for 'coordinates' method.
Checks if both X and Y coordinates are entered.
Based on option it inserts new location or returns location ID
of the nearest location.
:param m: A location table row.
:type m: int
:param row_data: Data in location table row.
:type row_data: list
:returns: A location ID of new location or the nearest location.
:rtype: str
"""
try:
crs_desc, opt, x, y, verb_loc = self._extr_coor_list(row_data)
except TypeError:
raise CoorMtyExc(m)
srid = self.crs_dict[crs_desc].authid().split(u':')[1]
# new
if opt == self.opt_list[0]:
locid = uuid.uuid4()
mpt_str = db.get_mpt_str(x, y)
utm33_geom = db.get_utm33_geom(self.mc.con, mpt_str, srid)
db.ins_new_loc(self.mc.con, locid, utm33_geom, verb_loc)
db.ins_loc_log(
self.mc.con,
locid,
verb_loc,
self.mc.con_info[self.mc.usr_str])
# nearest
elif opt == self.opt_list[1]:
locid = self._get_nrst_locid(x, y, srid)
return locid
def _get_nrst_locid(self, x, y, srid):
"""
Returns a location ID of the nearest location.
:param x: X coordinate.
:type x: float
:param y: Y coordinate.
:type y: float
:param srid: SRID.
:type srid: int
:returns: A location ID of the nearest location.
:rtype: str
"""
pt_str = db.get_pt_str(x, y)
utm33_geom = db.get_utm33_geom(self.mc.con, pt_str, srid)
locid = db.get_nrst_locid(self.mc.con, utm33_geom)
locid = str(locid)
return locid
def _get_locid_nvl(self, m, row_data):
"""
Returns a location ID. It is used for 'Norwegian VatLnr' method.
Checks if Norwegian VatLnr is empty.
It searches for location ID with the given Norwegian VatLnr.
:param m: A location table row.
:type m: int
:param row_data: Data in location table row.
:type row_data: list
:returns: A location ID with the given Norwegian VatLnr.
:rtype: str
"""
try:
nvl = self._extr_nvl_list(row_data)
except TypeError:
raise NvlMtyExc(m)
try:
locid = db.get_locid_from_nvl(self.mc.con, nvl)
except TypeError:
raise NvlNfExc(m, nvl)
return locid
[docs] def get_wdg_list(self, wdgs, pydate=True, forbi=False):
"""
Returns the data from the given list of widgets.
:param wdgs: A list of widgets whose data should be returned.
:type wdgs: list
:param pydate: True to convert *QDate* to *datetime.date*,
False otherwise.
:type pydate: bool
:param forbi: True to allow forbidden text, False otherwise.
:type forbi: bool
:returns: A list of data from event input widgets.
:rtype: list
"""
wdg_list = []
for wdg in wdgs:
if isinstance(wdg, QLineEdit):
txt = wdg.text()
wdg_vald = wdg.validator()
if not vald:
wdg_data = self._get_val_txt(txt, forbi)
elif isinstance(wdg_vald, (QIntValidator, vald.LenIntVald)):
try:
wdg_data = int(txt)
except ValueError:
wdg_data = None
elif isinstance(wdg_vald, QDoubleValidator):
try:
wdg_data = float(txt)
except ValueError:
wdg_data = None
else:
wdg_data = self._get_val_txt(txt, forbi)
elif isinstance(wdg, QComboBox):
txt = wdg.currentText()
wdg_data = self._get_val_txt(txt, forbi)
elif isinstance(wdg, QDateEdit):
if wdg.findChild(QLineEdit).text() == self.mty_str:
wdg_data = None
else:
wdg_data = wdg.date()
if pydate:
wdg_data = wdg_data.toPyDate()
elif isinstance(wdg, QPlainTextEdit):
txt = wdg.toPlainText()
wdg_data = self._get_val_txt(txt, forbi)
wdg_list.append(wdg_data)
return wdg_list
def _rst_wdgs(self, wdgs):
"""
Resets the given widgets.
- *QLineEdit* -- clear
- *QPlainTextEdit* -- clear
- *QComboBox* -- set current index to 0
- *QDateEdit* -- set date to minimum
:param wdgs: Widgets to be cleared.
:type wdgs: list
"""
for wdg in wdgs:
if isinstance(wdg, QLineEdit):
wdg.clear()
elif isinstance(wdg, QPlainTextEdit):
wdg.clear()
elif isinstance(wdg, QComboBox):
wdg.setCurrentIndex(0)
elif isinstance(wdg, QDateEdit):
wdg.setDate(wdg.minimumDate())
def _get_occ_row_list(self, m, forbi=False):
"""
Returns an occurrence row list.
:param m: A row number.
:type m: int
:param forbi: True to allow forbidden text, False otherwise.
:type forbi: bool
:returns: A list of data in the given row in the occurrence table.
:rtype: list
"""
occ_row_list = []
# OS.NINA
# depends on the order in the table
for n in range(self.occ_tbl.columnCount()):
wdg_data = self.occ_tbl.item(m, n).data(Qt.EditRole)
if isinstance(wdg_data, (str, unicode)):
wdg_data = self._get_val_txt(wdg_data, forbi)
if isinstance(wdg_data, QDate):
wdg_data = wdg_data.toPyDate()
occ_row_list.append(wdg_data)
return occ_row_list
def _ins_txncvg(self, event_id):
"""
Inserts all checked taxons into the database.
:param event_id: An event ID.
:type event_id: uuid.UUID
"""
for txn in self._ckd_txns:
txn_id = db.get_txn_id(self.mc.con, txn)
db.ins_txncvg(self.mc.con, txn_id, event_id)
@property
def _ckd_txns(self):
"""
Returns all checked taxons from the taxon coverage tree widget.
:returns: A list of all checked taxons.
:rtype: list
"""
txn_list = []
all_item = self.txncvg_tw.invisibleRootItem().child(0)
for i in range(all_item.childCount()):
fam_item = all_item.child(i)
for j in range(fam_item.childCount()):
txn_item = fam_item.child(j)
if txn_item.checkState(0) == Qt.Checked:
txn_list.append(txn_item.text(0))
return txn_list
[docs] def upd_dtst(self, dtst_str=None):
"""
Updates a dataset according to the last selected.
:param dtst_str: A dataset string `<ID> - <name>`.
:type dtst_str: str
"""
self._upd_mtdt(self.dtst_cb, dtst_str)
[docs] def upd_prj(self, prj_str=None):
"""
Updates a project according to the last selected.
:param prj_str: A project string `<name> - <organisation>`.
:type prj_str: str
"""
self._upd_mtdt(self.prj_cb, prj_str)
[docs] def upd_ref(self, ref_str=None):
"""
Updates a reference according to the last selected.
:param ref_str: A reference string `<author>: <title> (<year>) @<ID>`.
:type ref_str: str
"""
self._upd_mtdt(self.ref_cb, ref_str)
def _upd_mtdt(self, cb, cb_str=None):
"""
Updates a metadata according to the last selected.
"""
if not cb_str:
cb_str = self.settings.value(cb.objectName())
if cb_str:
cb_idx = cb.findText(cb_str)
cb.setCurrentIndex(cb_idx)
else:
cb_str = cb.currentText()
self._upd_mtdt_lw(cb_str, cb)
def _upd_mtdt_lw(self, cb_str, cb=None):
"""
Updates a metadata list widget.
:param cb_str: A combob box string.
:type cb_str: str
:param cb: A combo box.
:type cb: QComboBox
"""
if isinstance(cb_str, int):
cb = self.sender()
cb_str = cb.currentText()
idx = self.main_tb.indexOf(cb.parentWidget())
mdtd_base_txt = self.main_tb.itemText(idx).split(
self.dash_split_str)[0]
lw, id_met, info_fnc, mtdt_str_fnc = self._mtdt_lw_cb_dict[cb]
lw.clear()
if cb_str in self.forbi_str_list:
mtdt_txt = cb_str
else:
items, hdrs = info_fnc(self.mc.con, id_met())
self._pop_lw(lw, items, hdrs)
mtdt_txt = mtdt_str_fnc(cb_str)
self._set_mtdt_item_txt(
idx, u'{}{}{}'
.format(mdtd_base_txt, self.dash_split_str, mtdt_txt))
self.settings.setValue(cb.objectName(), cb_str)
def _set_mtdt_item_txt(self, item_index, text):
"""
Sets metadata item text.
:param item_index: An item index.
:type item_index: int
:param text: A text.
:type text: str
"""
self.main_tb.setItemText(item_index, text)
@property
def _mtdt_lw_cb_dict(self):
"""
Returns a metadata list widget combo box dictionary.
:returns:
| A metadata combo box dictionary:
| - key - <combo box name>
| - value - [
| <list widget>,
| <method that returns ID>,
| <function that returns information>,
| <function that returns metadata string>]
:rtype: dict.
"""
mtdt_cb_dict = {
self.dtst_cb: [
self.dtst_lw,
self._get_dtst_id,
db.get_dtst_info,
db.get_dtst_mtdt_str],
self.prj_cb: [
self.prj_lw,
self._get_prj_id,
db.get_prj_info,
db.get_prj_mtdt_str],
self.ref_cb: [
self.ref_lw,
self._get_ref_id,
db.get_ref_info,
db.get_ref_mtdt_str]}
return mtdt_cb_dict
def _pop_lw(self, lw, items, hdrs):
"""
Populates the given list widget.
Adds all items with their corresponding headers `<header>: <item>`.
:param lw: A list widget.
:type lw: QListWidget
:param items: Items to be added.
:type items: list
:param hdrs: Headers to be added.
:type hdrs: list
"""
for hdr, item in zip(hdrs, items):
lw_item = QListWidgetItem(
u'{}: {}'.format(hdr, unicode(item) if item else u''))
lw.addItem(lw_item)
[docs] def prep(self):
"""
Prepares the whole plugin to be shown.
"""
self._fetch_nofa_schema()
self._rst_loc_tbl()
self._rst_loc_wdgs()
self._rst_event_wdgs()
self._rst_occ_tbl()
self._rst_txncvg_tw()
def _fetch_nofa_schema(self):
"""
Fetches data from the `NOFA` schema and populates widgets.
"""
nofa_cb_dict = self._nofa_cb_dict
self.pop_cb(nofa_cb_dict)
self.upd_dtst()
self.upd_prj()
self.upd_ref()
self._pop_txncvg_tw()
[docs] def pop_cb(self, cb_dict):
"""
Populates combo boxe(s) and/or list widget(s).
:param cb_dict:
| A combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:type cb_dict: dict
"""
for cb, cb_list in cb_dict.items():
fnc = cb_list[0]
args = cb_list[1]
def_val = cb_list[2]
item_list = fnc(*args)
if def_val not in item_list:
item_list.insert(0, def_val)
self._add_cb_items(cb, item_list)
cb.setCurrentIndex(item_list.index(def_val))
def _pop_cnty_cb(self):
"""
Populates the county combo box according to the currently selected
country.
"""
self.pop_cb(self._cnty_cb_dict)
def _pop_muni_cb(self):
"""
Populates the municipality combo box according to the currently
selected country and county.
"""
self.pop_cb(self._muni_cb_dict)
def _pop_ectp_cb(self):
"""
Populates the ecotype combo box according to the currently selected
taxon.
"""
self.pop_cb(self._ectp_cb_dict)
[docs] def pop_dtst_cb(self):
"""
Populates the dataset combo box.
"""
self.pop_cb(self._dtst_cb_dict)
[docs] def pop_prj_cb(self):
"""
Populates the project combo box.
"""
self.pop_cb(self._prj_cb_dict)
[docs] def pop_ref_cb(self):
"""
Populates the reference combo box.
"""
self.pop_cb(self._ref_cb_dict)
def _add_cb_items(self, cb, item_list):
"""
Adds items from the item list to the combo box.
:param cb: A combob box.
:type cb: QComboBox
:param item_list: An item list.
:type item_list: list
"""
cb.clear()
for i, item in enumerate(item_list):
cb.addItem(item)
# if item in self.forbi_str_list:
# clr = self.red_clr
# cb.setItemData(i, QBrush(clr), Qt.BackgroundRole)
def _rst_cb_by_cb_dict(self, cb_dict):
"""
Resets combo boxes by the given combo box dictionary.
:param cb_dict:
| A combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:type cb_dict: dict
"""
for cb, cb_list in cb_dict.items():
def_val = cb_list[2]
cb.setCurrentIndex(cb.findText(def_val))
# ensure that signal is emitted
cb.currentIndexChanged.emit(cb.currentIndex())
@property
def _nofa_cb_dict(self):
"""
Returns a `NOFA` combo box dictionary.
:returns:
| A `NOFA` combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
nofa_cb_dict = {
self.oqt_cb: [
db.get_oqt_list,
[self.mc.con],
self.mty_str],
self.poptrend_cb: [
db.get_poptrend_list,
[self.mc.con],
self.mty_str],
self.spwnc_cb: [
db.get_spwnc_list,
[self.mc.con],
self.mty_str],
self.spwnl_cb: [
db.get_spwnl_list,
[self.mc.con],
self.mty_str]}
nofa_cb_dict = self._get_mrgd_dict(
nofa_cb_dict,
self._loc_cb_dict,
self._loc_edit_met_cb_dict,
self._loc_manual_met_cb_dict,
self._event_cb_dict,
self._ectp_cb_dict,
self._mtdt_cb_dict,
self._occ_mand_cb_dict)
return nofa_cb_dict
def _get_mrgd_dict(self, *dicts):
"""
Returns a merged dictionary of all given dictionaries.
"""
mrgd_dict = {}
for dict in dicts:
for key, val in dict.items():
mrgd_dict[key] = val
return mrgd_dict
@property
def _loc_cb_dict(self):
"""
Returns a combo box dictionary for all location combo boxes.
:returns:
| A combo box dictionary for all location combo boxes:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
loc_cb_dict = {
self.cntry_code_cb: [
db.get_cntry_code_list,
[self.mc.con],
self.all_str],
self.loc_edit_crs_cb: [
self._get_srs_desc_list,
[],
self.crs_dict.items()[0][0]],
self.loc_edit_opt_cb: [
self._get_opt_list,
[],
self.opt_list[0]],
self.loc_manual_coor_crs_cb: [
self._get_srs_desc_list,
[],
self.crs_dict.items()[0][0]],
self.loc_manual_coor_opt_cb: [
self._get_opt_list,
[],
self.opt_list[0]]}
loc_cb_dict = self._get_mrgd_dict(
loc_cb_dict,
self._cnty_cb_dict,
self._muni_cb_dict)
return loc_cb_dict
@property
def _cnty_cb_dict(self):
"""
Returns a county combo box dictionary.
:returns:
| A county combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
cnty_cb_dict = {
self.cnty_cb: [
db.get_cnty_list,
[self.mc.con, self._cntry_code],
self.all_str]}
return cnty_cb_dict
@property
def _muni_cb_dict(self):
"""
Returns a municipality combo box dictionary.
:returns:
| A municipality combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
muni_cb_dict = {
self.muni_cb: [
db.get_muni_list,
[self.mc.con, self._cntry_code, self._cnty],
self.all_str]}
return muni_cb_dict
@property
def _event_cb_dict(self):
"""
Returns a combo box dictionary for all event combo boxes.
:returns:
| A combo box dictionary for all event combo boxes:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
event_cb_dict = {
self.smpp_cb: [
db.get_smpp_list,
[self.mc.con],
self.sel_str],
self.smpsu_cb: [
db.get_smpsu_list,
[self.mc.con],
self.mty_str],
self.relia_cb: [
db.get_reliab_list,
[self.mc.con],
self.mty_str]}
return event_cb_dict
@property
def _ectp_cb_dict(self):
"""
Returns an ecotype combo box dictionary.
:returns:
| An ecotype combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
ectp_cb_dict = {
self.ectp_cb: [
db.get_ectp_list,
[self.mc.con, self._txn],
self.mty_str]}
return ectp_cb_dict
@property
def _mtdt_cb_dict(self):
"""
Returns a metadata combo box dictionary.
:returns: A metadata combo box dictionary.
| A metadata combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
mtdt_cb_dict = self._get_mrgd_dict(
self._dtst_cb_dict,
self._prj_cb_dict,
self._ref_cb_dict)
return mtdt_cb_dict
@property
def _dtst_cb_dict(self):
"""
Returns a dataset combo box dictionary.
:returns:
| A dataset combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
dtst_cb_dict = {
self.dtst_cb: [
db.get_dtst_list,
[self.mc.con],
self.sel_str]}
return dtst_cb_dict
@property
def _prj_cb_dict(self):
"""
Returns a project combo box dictionary.
:returns:
| A project combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
prj_cb_dict = {
self.prj_cb: [
db.get_prj_list,
[self.mc.con],
self.sel_str]}
return prj_cb_dict
@property
def _ref_cb_dict(self):
"""
Returns a reference combo box dictionary.
:returns:
| A reference combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
ref_cb_dict = {
self.ref_cb: [
db.get_ref_list,
[self.mc.con],
self.sel_str]}
return ref_cb_dict
@property
def _loc_edit_met_cb_dict(self):
"""
Returns a location edit method combo box dictionary.
:returns:
| A location edit method combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
loc_edit_met_cb_dict = {
self.loc_edit_met_cb: [
self._get_loc_met_list,
[],
self.loc_met_list[2]]}
return loc_edit_met_cb_dict
@property
def _loc_manual_met_cb_dict(self):
"""
Returns a location manual method combo box dictionary.
:returns:
| A location manual method combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
loc_manual_met_cb_dict = {
self.loc_manual_met_cb: [
self._get_loc_met_list,
[],
self.loc_met_list[2]]}
return loc_manual_met_cb_dict
@property
def _occ_mand_cb_dict(self):
"""
Returns an occurrence mandatory combo box dictionary.
:returns:
| An occurrence mandatory combo box dictionary:
| - key - <combo box name>
| - value - [<fill method>, [<arguments>], <default value>]
:rtype: dict
"""
occ_mand_cb_dict = {
self.txn_cb: [
db.get_txn_list,
[self.mc.con],
self.sel_str],
self.occstat_cb: [
db.get_occstat_list,
[self.mc.con],
db.get_col_def_val(
self.mc.con,
'nofa',
'occurrence',
'occurrenceStatus').split("'")[1]],
self.estm_cb: [
db.get_estbms_list,
[self.mc.con],
db.get_col_def_val(
self.mc.con,
'nofa',
'occurrence',
'establishmentMeans').split("'")[1]]}
return occ_mand_cb_dict
def _pop_txncvg_tw(self):
"""
Populates the taxon coverage tree widget.
"""
self.txncvg_tw.clear()
fam_dict = db.get_fam_dict(self.mc.con)
root_item = QTreeWidgetItem(self.txncvg_tw, ["All"])
root_item.setCheckState(0, Qt.Unchecked)
root_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
for fam in fam_dict.keys():
family_item = QTreeWidgetItem(root_item, [fam])
family_item.setCheckState(0, Qt.Unchecked)
family_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
for txn in fam_dict[fam]:
txn_item = QTreeWidgetItem(family_item, [txn])
txn_item.setCheckState(0, Qt.Unchecked)
txn_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
self.txncvg_tw.sortByColumn(0, Qt.AscendingOrder)
self.txncvg_tw.expandToDepth(0)
def _get_dtst_id(self):
"""
Returns a dataset ID from the dataset combo box.
:returns: A dataset ID.
:rtype: str
"""
dtst_str = self.dtst_cb.currentText()
id, name = db.split_dtst_str(dtst_str)
return id
def _get_prj_id(self):
"""
Returns a project ID based on name and organization.
:returns: A project ID.
:rtype: str
"""
prj_str = self.prj_cb.currentText()
prj_name, prj_org = db.split_prj_str(prj_str)
prj_id = db.get_prj_id(self.mc.con, prj_name, prj_org)
return prj_id
def _get_ref_id(self):
"""
Returns a reference ID from the reference combo box.
:returns: A reference ID.
:rtype: str
"""
ref_str = self.ref_cb.currentText()
if self._get_val_txt(ref_str):
au, ttl, yr, id = db.split_ref_str(ref_str)
else:
id = None
return id
def _get_srs_desc_list(self):
"""
Returns a list of SRS descriptions.
:returns: A list of SRS descriptions.
:rtype: list
"""
srs_desc_list = self.crs_dict.keys()
return srs_desc_list
def _get_loc_met_list(self):
"""
Returns a list of methods.
:returns: A list of methods.
:rtype: list
"""
met_list = self.loc_met_list
return met_list
def _get_opt_list(self):
"""
Returns a list of options.
:returns: A list of options.
:rtype: list
"""
opt_list = self.opt_list
return opt_list
def _create_tbl_main_tab(self, tbl, tbl_hdrs, tbl_wdgs, met):
"""
Creates a table with one row.
This method is used for creating tables in the main tab.
:param tbl: A table.
:type tbl: QTableWidget
:param tbl_hdrs: Table headers.
:type tbl_hdrs: list
:param tbl_wdgs: Table widgets.
:type tbl_wdgs: list
:param met: A method for updating table.
:type met: function
"""
tbl.itemChanged.connect(tbl.resizeColumnsToContents)
tbl.setColumnCount(len(tbl_hdrs))
tbl.setSelectionBehavior(QTableWidget.SelectRows)
tbl.setSelectionMode(QTableWidget.SingleSelection)
tbl.setEditTriggers(QAbstractItemView.NoEditTriggers)
tbl.setSortingEnabled(True)
tbl.setHorizontalHeaderLabels(tbl_hdrs)
tbl.setRowCount(1)
m = 0
tbl.selectRow(m)
for n, tbl_hdr in enumerate(tbl_hdrs):
tbl_item = QTableWidgetItem()
tbl_item.setData(Qt.EditRole, None)
tbl.setItem(m, n, tbl_item)
self._con_wdgs_sgnls_to_met(tbl_wdgs, met)
def _con_wdgs_sgnls_to_met(self, wdgs, met):
"""
Connects signals of the given widgets to the given method.
- *QLineEdit* - textChanged
- *QComboBox* - currentIndexChanged
- *QDateEdit* - dateChanged
:param wdgs: Widgets.
:type wdgs: list
:param met: A method.
:type met: function
"""
for wdg in wdgs:
if isinstance(wdg, QLineEdit):
wdg.textChanged.connect(met)
elif isinstance(wdg, QComboBox):
wdg.currentIndexChanged.connect(met)
elif isinstance(wdg, QDateEdit):
wdg.dateChanged.connect(met)
def _emit_wdgs_sgnls(self, tbl_wdgs):
"""
Emits signals of the given widgets.
- *QLineEdit* - textChanged
- *QComboBox* - currentIndexChanged
- *QDateEdit* - dateChanged
:param tbl_wdgs: Widgets.
:type tbl_wdgs: list
"""
for wdg in tbl_wdgs:
if isinstance(wdg, QLineEdit):
wdg.textChanged.emit(wdg.text())
elif isinstance(wdg, QComboBox):
wdg.currentIndexChanged.emit(wdg.currentIndex())
elif isinstance(wdg, QDateEdit):
wdg.dateChanged.emit(wdg.date())
def _upd_loc_tbl_row(self, idx):
"""
Adjusts the current location table row according to the current
location method.
Also sets index of location method stacked widget.
:param idx: A current index of location edit method combo box.
:type idx: int
"""
self.loc_edit_met_swdg.setCurrentIndex(idx)
tbl = self.loc_tbl
m = tbl.currentRow()
# skip first column
for n in range(1, tbl.columnCount()):
tbl.item(m, n).setData(Qt.EditRole, None)
cur_loc_edit_tbl_wdgs = self._cur_loc_edit_tbl_wdgs
self._rst_wdgs(cur_loc_edit_tbl_wdgs)
self._emit_wdgs_sgnls(cur_loc_edit_tbl_wdgs)
def _create_tbl_hist_tab(self, tbl, tbl_list, tbl_hdrs):
"""
Creates a table with one row.
This method is used for creating tables in the history tab.
:param tbl: A table.
:type tbl: QTableWidget
:param tbl_list: Table list.
:type tbl_list: list
:param tbl_hdrs: Table headers.
:type tbl_hdrs: list
"""
tbl.setColumnCount(len(tbl_hdrs))
tbl.setSelectionBehavior(QTableWidget.SelectItems)
tbl.setSelectionMode(QTableWidget.ExtendedSelection)
tbl.setEditTriggers(QAbstractItemView.NoEditTriggers)
tbl.setSortingEnabled(True)
tbl.setHorizontalHeaderLabels(tbl_hdrs)
tbl.setRowCount(len(tbl_list))
for m, row in enumerate(tbl_list):
for n, item in enumerate(row):
if isinstance(item, datetime.datetime):
item = QDateTime(item)
elif isinstance(item, uuid.UUID):
item = str(item)
tbl_item = QTableWidgetItem()
tbl_item.setData(Qt.EditRole, item)
tbl.setItem(m, n, tbl_item)
tbl.resizeColumnsToContents()
def _add_tbl_mty_row_items(self, tbl, tbl_hdrs, m):
"""
Adds a row at the given position of a table with empty items.
:param tbl: A table.
:type tbl: QTableWidget
:param tbl_hdrs: Table headers.
:type tbl_hdrs: list
:param m: A row number.
:type m: int
"""
for n, tbl_hdr in enumerate(tbl_hdrs):
tbl_item = QTableWidgetItem()
tbl_item.setData(Qt.EditRole, None)
tbl.setItem(m, n, tbl_item)
def _upd_loc_tbl_item(self):
"""
Updates the corresponding item in the location table's current row
with the values in the sender widget.
"""
self._upd_tbl_item(self.loc_tbl, self.loc_tbl_wdg_hdr_dict.keys())
def _upd_occ_tbl_item(self):
"""
Updates the corresponding item in the occurrence table's current row
with the values in the sender widget.
"""
self._upd_tbl_item(self.occ_tbl, self.occ_tbl_wdg_hdr_dict.keys())
def _upd_tbl_item(self, tbl, tbl_wdgs):
"""
Updates the corresponding item in the table's current row
with the values in the sender widget.
:param tbl: A table.
:type tbl: QTableWidget
:param tbl_wdgs: A list of table widgets.
:type tbl_wdgs: list
"""
sndr = self.sender()
wdg_data = self.get_wdg_list([sndr], False, True)[0]
m = tbl.currentRow()
n = tbl_wdgs.index(sndr)
tbl_item = tbl.item(m, n)
tbl_item.setData(Qt.EditRole, wdg_data)
tbl.blockSignals(True)
tbl.selectRow(tbl_item.row())
tbl.blockSignals(False)
tbl.resizeColumnsToContents()
def _sel_row_up(self):
"""
Select one row up in a table.
"""
tbl = self._get_tbl()
m = tbl.currentRow()
if m > 0:
tbl.selectRow(m - 1)
def _sel_row_dwn(self):
"""
Select one row down in a table.
"""
tbl = self._get_tbl()
m = tbl.currentRow()
if m < (tbl.rowCount() - 1):
tbl.selectRow(m + 1)
def _upd_loc_tbl_wdgs(self):
"""
Updates the location table widgets according to the selected location
table row.
"""
tbl = self.loc_tbl
m = tbl.currentRow()
loc_met = tbl.item(m, 0).data(Qt.EditRole)
self.loc_edit_met_cb.blockSignals(True)
idx = self.loc_edit_met_cb.findText(loc_met)
self.loc_edit_met_cb.setCurrentIndex(idx)
self.loc_edit_met_swdg.setCurrentIndex(idx)
self.loc_edit_met_cb.blockSignals(False)
for wdg in self._cur_loc_edit_tbl_wdgs:
n = self.loc_tbl_wdg_hdr_dict.keys().index(wdg)
wdg_data = tbl.item(m, n).data(Qt.EditRole)
self._set_wdg_data(wdg, wdg_data)
def _upd_occ_tbl_wdgs(self):
"""
Updates the occurrence table widgets according to the selected
occurrence table row.
"""
tbl = self.occ_tbl
m = tbl.currentRow()
occ_row_list = self._get_occ_row_list(m, True)
for n, wdg in enumerate(self.occ_tbl_wdg_hdr_dict.keys()):
wdg_data = occ_row_list[n]
self._set_wdg_data(wdg, wdg_data)
def _set_wdg_data(self, wdg, wdg_data):
"""
Sets widget's data.
:param wdg: A Widget.
:type wdg: QWidget
:param wdg_data: A widget data.
:type wdg_data: QVariant
"""
if isinstance(wdg, QLineEdit):
if wdg_data:
if isinstance(wdg_data, float):
if wdg_data.is_integer():
wdg_data = int(wdg_data)
wdg.setText(str(wdg_data))
else:
wdg.clear()
elif isinstance(wdg, QComboBox):
wdg.setCurrentIndex(wdg.findText(wdg_data))
elif isinstance(wdg, QDateEdit):
if wdg_data:
wdg.setDate(wdg_data)
else:
wdg.setDate(wdg.minimumDateTime().date())
def _add_tbl_row(self):
"""
Adds a table row.
"""
tbl = self._get_tbl()
tbl_hdrs = self._get_tbl_hdrs()
tbl.setSortingEnabled(False)
m = tbl.currentRow() + 1
tbl.insertRow(m)
tbl.blockSignals(True)
tbl.selectRow(m)
tbl.blockSignals(False)
self._add_tbl_mty_row_items(tbl, tbl_hdrs, m)
self._rst_tbl_row()
tbl.setSortingEnabled(True)
def _del_tbl_row(self):
"""
Delete a row from a table.
"""
tbl = self._get_tbl()
m = tbl.currentRow()
if tbl.rowCount() > 1:
tbl.removeRow(m)
def _rst_tbl_row(self):
"""
Resets a current table row.
"""
self._rst_cb_by_cb_dict(self._get_tbl_mand_cb_dict())
tbl_wdgs = self._get_tbl_wdgs()
self._rst_wdgs(tbl_wdgs)
nofa_cb_dict = self._nofa_cb_dict
for wdg in tbl_wdgs:
if wdg in nofa_cb_dict.keys():
self._rst_cb_by_cb_dict({wdg: nofa_cb_dict[wdg]})
self._emit_wdgs_sgnls(tbl_wdgs)
def _rst_all_tbl_rows(self):
"""
Resets all table rows.
"""
tbl = self._get_tbl()
curr_item = tbl.currentItem()
for m in range(tbl.rowCount()):
tbl.setCurrentCell(m, 0)
self._rst_tbl_row()
tbl.selectRow(curr_item.row())
def _del_all_tbl_rows(self, tbl):
"""
Deletes all table rows except the currently selected one.
:param tbl: A table.
:type tbl: QTableWidget
"""
tbl = self._get_tbl()
orig_m = tbl.currentRow()
for m in range(tbl.rowCount(), -1, -1):
if m != orig_m:
tbl.removeRow(m)
def _get_row_data(self, tbl, m):
"""
Returns data from the given table in the given row.
:param tbl: A table.
:type tbl: QTableWidget
:param m: A row number.
:type m: int
:returns: Data from the given table in the given row.
:rtype: list
"""
row_data = []
for n in range(tbl.columnCount()):
row_item = tbl.item(m, n).data(Qt.EditRole)
row_data.append(row_item)
return row_data
def _set_loc_tbl_row(self, row_data):
"""
Sets data to the current row in the location table.
New row is added if the current row is not empty.
:param row_data: A data to be written. It has to have the same length
as number of columns in the table.
:type row_data: list
"""
tbl = self.loc_tbl
curr_row_data = self._get_row_data(tbl, tbl.currentRow())
if any(item is not None for item in curr_row_data[1:]):
self.loc_addrow_btn.click()
m = tbl.currentRow()
for n in range(tbl.columnCount()):
tbl.item(m, n).setData(Qt.EditRole, row_data[n])
def _get_tbl(self):
"""
Returns a table the sender works with.
:returns: A table the sender works with.
:rtype: QTableWidget
"""
if self.sender().objectName().startswith(u'occ_'):
return self.occ_tbl
else:
return self.loc_tbl
def _get_tbl_hdrs(self):
"""
Returns a table headers the sender works with.
:returns: A table headers the sender works with.
:rtype: list
"""
if self.sender().objectName().startswith(u'occ_'):
return self.occ_tbl_wdg_hdr_dict.values()
else:
return self.loc_tbl_wdg_hdr_dict.values()
def _get_tbl_wdgs(self):
"""
Returns a table widgets the sender works with.
:returns: A table widgets the sender works with.
:rtype: list
"""
if self.sender().objectName().startswith(u'occ_'):
return self.occ_tbl_wdg_hdr_dict.keys()
else:
return self._cur_loc_edit_tbl_wdgs
@property
def _cur_loc_edit_tbl_wdgs(self):
"""
Returns a list of current location edit table widgets.
:returns: A list of current location table widgets.
:rtype: list
"""
cur_loc_edit_tbl_wdgs = self.loc_edit_met_swdg.currentWidget()\
.findChildren((QLineEdit, QPlainTextEdit, QComboBox, QDateEdit))
return cur_loc_edit_tbl_wdgs
@property
def _cur_loc_manual_tbl_wdgs(self):
"""
Returns a list of current location manual table widgets.
:returns: A list of current location table widgets.
:rtype: list
"""
cur_loc_manual_tbl_wdgs = self.loc_manual_swdg.currentWidget()\
.findChildren((QLineEdit, QPlainTextEdit, QComboBox, QDateEdit))
return cur_loc_manual_tbl_wdgs
def _get_tbl_mand_cb_dict(self):
"""
Returns a table mandatory combo box dictionary the sender works with.
:returns: A table mandatory combo box dictionary the sender works with.
:rtype: dict
"""
if self.sender().objectName().startswith(u'occ_'):
return self._occ_mand_cb_dict
else:
return self._loc_edit_met_cb_dict