# This code is a part of program Manual Lichen identification
# Copyright (C) 2022 contributors Manual Lichen identification
# The full list is available at the link
# https://github.com/tagezi/mli/blob/master/contributors.txt
#
# 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 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from gettext import gettext as _
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout
from mli.gui.dialog_elements import ADialogApplyButtons, VComboBox, VLineEdit
from mli.gui.message_box import warning_no_synonyms, warning_lat_name,\
warning_this_exist
from mli.lib.str import str_sep_name_taxon
[docs]class ATaxonDialog(ADialogApplyButtons):
""" Creates abstract class that contain common elements for Dialogs of
taxon."""
def __init__(self, oConnector, oParent=None):
""" Initiating a class. """
super(ATaxonDialog, self).__init__(oConnector, oParent)
self.iOldMainTaxonID = None
self.sOldMainTaxonName = None
self.sOldMainTaxonAuthor = None
self.iOldTaxonRankID = None
self.sOldTaxonRankName = None
self.iOldTaxonID = None
self.sOldTaxonName = None
self.sOldAuthor = None
self.sOldYear = None
self.sOldStatus = None
self.init_UI()
self.fill_combobox()
self.connect_actions()
[docs] def init_UI(self):
""" initiating a dialog view """
self.oComboStatus = VComboBox(_('Taxon status:'), 180)
self.oComboTaxRank = VComboBox(_('Taxon rank:'), 180)
self.oLineEditLatName = VLineEdit(_('Latin name:'))
self.oLineEditAuthor = VLineEdit(_('Author:'), 240)
self.oLineEditYear = VLineEdit(_('Year:'), 50)
self.oComboTaxNames = VComboBox(_('Taxon name:'), 500)
self.oComboBoxSynonym = VComboBox(_('Synonym:'), 500)
self.oComboMainTaxon = VComboBox(_('Main taxon:'), 500)
self.oLineEditLocaleName = VLineEdit(_('Local name:'))
oHLayoutAuthor = QHBoxLayout()
oHLayoutAuthor.addLayout(self.oLineEditAuthor)
oHLayoutAuthor.addStretch()
oHLayoutAuthor.addLayout(self.oLineEditYear)
oVLayoutRank = QVBoxLayout()
oVLayoutRank.addLayout(self.oComboTaxRank)
oVLayoutRank.addLayout(self.oComboStatus)
oVLayoutTaxon = QVBoxLayout()
oVLayoutTaxon.addLayout(self.oLineEditLatName)
oVLayoutTaxon.addLayout(oHLayoutAuthor)
self.oHLayoutTaxon = QHBoxLayout()
self.oHLayoutTaxon.addLayout(oVLayoutRank)
self.oHLayoutTaxon.addLayout(oVLayoutTaxon)
[docs] def connect_actions(self):
""" Connects buttons with actions they should perform. """
(self.oComboMainTaxon.get_widget()).currentTextChanged.connect(
self.onCurrentMainTaxonChanged)
[docs] def clean_field(self):
""" Clears all fields after use. """
self.oComboMainTaxon.clear_list()
self.oComboTaxRank.clear_list()
self.oComboStatus.clear_list()
self.oLineEditLatName.set_text('')
self.oLineEditAuthor.set_text('')
self.oLineEditYear.set_text('')
self.oLineEditLocaleName.set_text('')
self.oComboTaxNames.clear_list()
[docs] def create_level_list(self, sTaxon='', bGetAll=None):
""" Generates a list of taxon levels depending on a condition. At the
first list initialization and using button Apply, all taxon levels are
collected, at choosing Main taxon, only those that are below the
selected taxon name.
:param sTaxon: A name of main taxon.
:type sTaxon: str
:param bGetAll: It is needed to choose all levels.
:type bGetAll: bool
:return: list of taxon levels.
:rtype: list[str]
"""
oCursor = self.oConnector.sql_get_all('TaxonRanks')
lValues = [tRow[3] for tRow in oCursor]
if bGetAll is None:
sRankMainTaxon = sTaxon.split('(')[1].split(')')[0]
sRow = lValues[0]
while sRow != sRankMainTaxon:
lValues.pop(0)
sRow = lValues[0]
lRanks = lValues
lRanks.pop(0)
return lRanks
[docs] def create_status_list(self):
""" Creates a list of statuses.
:return: list[str]
"""
tRows = self.oConnector.get_statuses()
lList = []
for Row in tRows:
lList.append(Row[2])
return lList
[docs] def create_taxon_list(self):
""" Creates a list of taxon names for further use in dialog elements.
:return: A list in form - (Taxon Rank) Taxon Name
:type: list[str]
"""
tRows = self.oConnector.get_taxon_list('accepted')
return [f'({tRow[1]}) {tRow[2]}' for tRow in tRows]
[docs] def fill_combobox(self):
""" Fills the fields with the drop-down list during the first
initialization and after applying the Apply button."""
lStatuses = self.create_status_list()
self.oComboStatus.set_combo_list(lStatuses)
self.oComboTaxRank.set_text(lStatuses[1])
lTaxonRank = self.create_level_list(bGetAll=True)
self.oComboTaxRank.set_combo_list(lTaxonRank)
self.oComboTaxRank.set_text(lTaxonRank[0])
self.oComboMainTaxon.set_combo_list(self.create_taxon_list())
self.oComboTaxNames.set_combo_list(self.create_taxon_list())
[docs] def onClickApply(self):
sMainTaxon = self.oComboMainTaxon.get_text()
sTaxonRank = self.oComboTaxRank.get_text()
sLatName = self.oLineEditLatName.get_text()
sAuthor = self.oLineEditAuthor.get_text()
sYear = self.oLineEditYear.get_text()
sStatus = self.oComboStatus.get_text()
if not sLatName and not sLatName.isalpha() and not sLatName.isascii():
warning_lat_name()
return
if self.sOldTaxonName != sLatName:
self.save_('taxon_name', sLatName, self.iOldTaxonID)
sMainSciName = str_sep_name_taxon(sMainTaxon)
if sMainSciName != self.sOldMainTaxonName:
iMainTaxonID = self.oConnector.get_taxon_id(sMainSciName)
self.save_('mainTaxonID', iMainTaxonID, self.iOldTaxonID)
if sTaxonRank != self.sOldTaxonRankName:
iRankID = self.oConnector.get_rank_id('rankLocalName', sTaxonRank)
self.save_('rankID', iRankID, self.iOldTaxonID)
if sAuthor and sAuthor != self.sOldAuthor:
self.save_('authorship', sAuthor, self.iOldTaxonID)
if sYear and sYear != self.sOldYear:
self.save_('yearPublishing', sYear, self.iOldTaxonID)
if sStatus != self.sOldStatus:
iStatusID = self.oConnector.get_status_id(sStatus)
self.save_('statusID', iStatusID, self.iOldTaxonID)
self.clean_field()
self.fill_combobox()
[docs] def onCurrentMainTaxonChanged(self, sTaxon=''):
""" The slot that should fire after the taxon name in the Main taxon
drop-down list.
:param sTaxon: A name of main taxon.
:type sTaxon: str
"""
# If the user enters the name by hand, there will be an error.
if sTaxon.find("(") >= 0 and sTaxon.find(")") > 1:
lTaxonRank = self.create_level_list(sTaxon)
self.oComboTaxRank.clear_list()
self.oComboTaxRank.set_combo_list(lTaxonRank)
self.oComboTaxRank.set_text(lTaxonRank[0])
[docs] def save_(self, sSetCol, sUpdate, sWhere,
sTable='Taxa', sWhereCol='taxonID'):
tValues = (sUpdate, sWhere,)
self.oConnector.update(sTable, sSetCol, sWhereCol, tValues)
[docs]class EditSynonymDialog(ATaxonDialog):
def __init__(self, oConnector, oParent=None):
""" Initiating a class. """
super(EditSynonymDialog, self).__init__(oConnector, oParent)
self.lSynonym = None
self.iTaxonID = None
[docs] def init_UI(self):
""" Creating a dialog window. """
super().init_UI()
self.setWindowTitle(_('Editing an existing taxon'))
self.setModal(Qt.ApplicationModal)
self.oLineEditLatName.set_label(_('New synonym name:'))
self.oComboMainTaxon.set_text(_('New main taxon:'))
oVLayout = QVBoxLayout()
oVLayout.addLayout(self.oComboTaxNames)
oVLayout.addLayout(self.oComboBoxSynonym)
oVLayout.addLayout(self.oComboMainTaxon)
oVLayout.addLayout(self.oHLayoutTaxon)
oVLayout.addLayout(self.oHLayoutButtons)
self.setLayout(oVLayout)
[docs] def connect_actions(self):
super().connect_actions()
(self.oComboTaxNames.get_widget()).currentTextChanged.connect(
self.onCurrentTaxonNamesChanged)
self.oComboBoxSynonym.get_widget().currentTextChanged.connect(
self.onCurrentSynonymChanged)
[docs] def onCurrentSynonymChanged(self, sSynonym):
self.fill_form(sSynonym)
[docs] def onCurrentTaxonNamesChanged(self, sTaxonName):
sSciName = str_sep_name_taxon(sTaxonName)
self.iTaxonID = self.oConnector.get_taxon_id(sSciName)
tSynonyms = self.oConnector.get_synonyms(self.iTaxonID)
if not tSynonyms:
if not sTaxonName or sSciName.find('Biota') != -1:
return
# if sAuthor:
# warning_no_synonyms(f'{sName}, {sAuthor}')
# else:
# warning_no_synonyms(f'{sName}')
return
lSynonyms = [f'({lRow[0]}) {lRow[1]}' for lRow in tSynonyms]
# for lRow in tSynonyms:
# lSynonyms.append(f'({lRow[0]}) {lRow[1]}, {lRow[2]}')
self.oComboBoxSynonym.set_combo_list(lSynonyms)
[docs]class EditTaxonDialog(ATaxonDialog):
def __init__(self, oConnector, oParent=None):
""" Initiating a class. """
super(EditTaxonDialog, self).__init__(oConnector, oParent)
[docs] def init_UI(self):
""" Creating a dialog window. """
super().init_UI()
self.setWindowTitle(_('Editing of a taxon'))
self.setModal(Qt.ApplicationModal)
oVLayout = QVBoxLayout()
oVLayout.addLayout(self.oComboTaxNames)
oVLayout.addLayout(self.oComboMainTaxon)
oVLayout.addLayout(self.oHLayoutTaxon)
oVLayout.addLayout(self.oHLayoutButtons)
self.setLayout(oVLayout)
[docs] def connect_actions(self):
super().connect_actions()
(self.oComboTaxNames.get_widget()).currentTextChanged.connect(
self.onCurrentTaxonNamesChanged)
[docs] def onCurrentTaxonNamesChanged(self, sTaxonName):
self.fill_form(sTaxonName)
[docs]class NewTaxonDialog(ATaxonDialog):
""" Dialog window which adds information on new taxon. """
def __init__(self, oConnector, oParent=None):
""" Initiating a class. """
super(NewTaxonDialog, self).__init__(oConnector, oParent)
[docs] def init_UI(self):
""" Creating a dialog window. """
super().init_UI()
self.setWindowTitle(_('Add new taxon to tree'))
self.setModal(Qt.ApplicationModal)
oVLayout = QVBoxLayout()
oVLayout.addLayout(self.oComboMainTaxon)
oVLayout.addLayout(self.oHLayoutTaxon)
oVLayout.addLayout(self.oHLayoutButtons)
self.setLayout(oVLayout)
[docs] def onClickApply(self):
""" Actions to be taken when adding a new taxon. """
sRank = self.oComboTaxRank.get_text()
sMainTaxon = str_sep_name_taxon(self.oComboMainTaxon.get_text())
sName = self.oLineEditLatName.get_text()
sAuthor = self.oLineEditAuthor.get_text()
iYear = self.oLineEditYear.get_text()
sStatus = self.oComboStatus.get_text()
if not sName and sName.isalpha() and sName.isascii():
warning_lat_name()
return
bTaxonName = self.oConnector.get_taxon_id(sName, sAuthor)
if sName and bTaxonName:
warning_this_exist(_('taxon name'), f'<i>{sName}</i>, {sAuthor}')
return
if sName and not bTaxonName:
iRank = self.oConnector.get_rank_id('rankLocalName', sRank)
iStatus = self.oConnector.get_status_id(sStatus)
iMainTax = self.oConnector.get_taxon_id(sMainTaxon)
PublishedIn = ''
self.oConnector.insert_taxon(sName, sAuthor, iYear, PublishedIn,
iRank, iMainTax, iStatus)
self.clean_field()
self.fill_combobox()
if __name__ == '__main__':
pass