Source code for cute_mongo_forms.column.base

"""
base.py    : Basic column classes

* Copyright: 2017-2018 Sampsa Riikonen
* Authors  : Sampsa Riikonen
* Date     : 2018
* Version  : 0.2.3 

This file is part of the cute_mongo_forms library

License: LGPLv3+ (see the COPYING.LESSER file)
"""

import sys
# from PyQt5 import QtWidgets, QtCore, QtGui # Qt5
from PySide2 import QtWidgets, QtCore, QtGui
from cute_mongo_forms.tools import typeCheck, dictionaryCheck, objectCheck, parameterInitCheck, noCheck
# a string for aux debuggin purposes
pre_mod = "cute_mongo_forms.column.base : "


[docs]class Column: """Mother class for columns. Derive your own column class from this. The column class encapsulates a particular QWidget and restrictions on the QWidget (through Qt input masks) of the accepted values. The Row class uses Columns to read/set their values from/to a key-value document. Parameters at instantiation: :param key_name: The key to be used in the key/value pair of the document database """ parameter_defs = { "key_name": str, # name of the database key in key(value) "label_name": str # used to create the forms } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): """For child classes, set the QtWidget here """ raise(AssertionError("Virtual method"))
[docs] def getValue(self): """Get the value from QtWidget """ return None
[docs] def setValue(self, txt): # the value (in key(value)) """Set the value of the QtWidget """ return None
[docs] def setParent(self, parent): """Parent the QtWidget """ self.widget.setParent(parent)
[docs] def reset(self): """Set the column to its default empty value """ pass
[docs] def updateWidget(self): """This is for columns classes that have relations to a "foreign" collection (foreign keys). Check the foreign collection and keep values in the widget consistent. """ pass
[docs] def purge(self, value): """Check if value is ok for this column. If update is needed, return (True, updated_value), otherwise (False, original_value) """ return False, value
[docs] def getNotifySignal(self): """A notifying signal when this columns contents are changed """ return None
[docs]class LineEditColumn(Column): """Derived from Column. Unrestricted input text. """ parameter_defs = { "key_name": str, # name of the database key in key(value) "label_name": str # used to create the forms } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = QtWidgets.QLineEdit()
[docs] def getNotifySignal(self): return self.widget.editingFinished
[docs] def getValue(self): # Get the value from QtWidget return self.widget.text()
[docs] def setValue(self, txt): # Set the value of the QtWidget self.widget.setText(str(txt))
[docs] def reset(self): self.setValue("")
[docs]class LabelColumn(Column): """Column that does not create a key-value pair. No data here, just a label TODO: experimental, dont use """ parameter_defs = { "label_name": str } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = QtWidgets.QLabel(self.label_name)
[docs] def getValue(self): # Get the value from QtWidget return None
[docs] def setValue(self, txt): # Set the value of the QtWidget pass
[docs] def reset(self): pass
[docs]class ComboBoxColumn(Column): """A Column that can have a finite number of different values. The possible values are defined in a specific collection that is given as a parameter (let's call this "foreign collection"). The element in the QtWidget form corresponding to this column is a drop-down list (e.g. a QComboBox). The collection schema looks like this: :: principal collection foreign collection -------------------- ------------------ _id +---> _id key1 | label key2 --------+ key2 -------------------- ------------------ Parameters at instantiation: :param collection: Foreign collection that has all possible values for the drop-down list :param key_name: Key in the principal collection whose values correspond to keys in the foreign collection (in that example above key_name = key2) :param label_name: Name of the drop-down list in the form widget :param foreign_label_name: Name of the key in the foreign collection for a value shown in the pricipal collection. Default: "label" :param foreign_key_name: Name of the foreign key in the foreign collection. Default: "_id" """ # define here, where the foreign key is mapped.. parameter_defs = { "collection": None, "key_name": str, # name of the database key in key(value) "label_name": str, # used to create the forms # label corresponding to this foreign key "foreign_label_name": (str, "label"), # by default, use the object id as the foreign key "foreign_key_name": (str, "_id") } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = QtWidgets.QComboBox() self.updateWidget()
[docs] def updateWidget(self): self.widget.clear() it = self.collection.get() for i, item in enumerate(it): self.widget.insertItem(i, item[self.foreign_label_name], item[self.foreign_key_name])
[docs] def getValue(self): # Get the value from QtWidget # self.widget.currenText() # self.widget.currentData() return self.widget.currentData() # returns the foreign key
[docs] def setValue(self, foreign_key): # TODO: check that invalid foreign_key values are silently omitted # Set the value of the QtWidget # if foreign_key is not found (i.e. the row that's using this column has a database having incorrect foreign_key values), # findData returns -1 # setCurrentIndex(-1) sets the selection to void i = self.widget.findData(foreign_key) self.widget.setCurrentIndex(i)
[docs] def reset(self): self.widget.setCurrentIndex(-1)
[docs]class ForeignKeyColumn(Column): """A column that is a foreign key, referenced by another collection. Does not create any visible widget into forms. Basically, creates a key-value pair in the collection Row schema. Does not know anything about mapping the key to a foreign table. Parameters at instantiation: :param key_name: name of the key :param collection: the "foreign" collection :param foreign_key_name: the key in the foreign collection (default: "_id") """ parameter_defs = { "key_name": str, # database key in key(value) "collection": None, # the "foreign" collection, # by default, use the object id as the foreign key "foreign_key_name": (str, "_id") } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = None # does not create any visible widget
[docs] def getValue(self): # Get the value return self.value
[docs] def setValue(self, value): # Set the value self.value = value
[docs] def reset(self): self.value = None
[docs]class CheckBoxColumn(Column): """A column having a Qt checkbox and true/false value. """ # define here, where the foreign key is mapped.. parameter_defs = { "key_name": str, # name of the database key in key(value) "label_name": str, # used to create the forms "def_value": (bool, False) } class Signals(QtCore.QObject): notify = QtCore.Signal() def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.signals = self.Signals() self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = QtWidgets.QCheckBox() self.widget.stateChanged.connect(self.state_changed_slot)
[docs] def getNotifySignal(self): return self.signals.notify
# return self.widget.clicked
[docs] def getValue(self): # Get the value from QtWidget return self.widget.isChecked()
[docs] def setValue(self, val): # Set the value of the QtWidget self.widget.setChecked(val)
[docs] def reset(self): self.setValue(self.def_value)
# ** slots ** def state_changed_slot(self, i): print("QCheckBoxColumn: state_changed_slot :", self.key_name) self.signals.notify.emit()
[docs]class ListEditColumn(Column): """A Column that is a list. Possible values for the list element are defined in a specific collection that is given as a parameter (let's call this "foreign collection"). The element in the QtWidget form corresponding to this column is a QListWidget. The GUI user can enable/check several values. All these values are saved into the list. The collection schema looks like this: :: principal collection foreign collection -------------------- ------------------ _id +---> _id key1 | label key2: a list --------+ key2 -------------------- ------------------ Parameters at instantiation: :param collection: Foreign collection that has all possible values present in the list :param key_name: Key in the principal collection whose values correspond to keys in the foreign collection (in that example above key_name = key2) :param label_name: Name of the list in the form widget :param foreign_label_name: Name of the key in the foreign collection for a value shown in the pricipal collection. Default: "label" :param foreign_key_name: Name of the foreign key in the foreign collection. Default: "_id" """ # define here, where the foreign key is mapped.. parameter_defs = { "collection": None, "key_name": str, # name of the database key in key(value) "label_name": str, # used to create the forms # label corresponding to this foreign key "foreign_label_name": (str, "label"), # by default, use the object id as the foreign key "foreign_key_name": (str, "_id") } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check kwargs agains parameter_defs, attach ok'd parameters to this # object as attributes parameterInitCheck(self.parameter_defs, kwargs, self) self.makeWidget() self.reset()
[docs] def makeWidget(self): self.widget = QtWidgets.QListWidget() self.widget.setSelectionMode( QtWidgets.QAbstractItemView.MultiSelection) self.updateWidget()
[docs] def getValue(self): # TODO: check that invalid values are silently omitted # Returns list of keys corresponding to selected elements lis = [] for el in self.widget.selectedItems(): lis.append(el.key) return lis
[docs] def setValue(self, key_list): # Selects elements in the list, based on key list for el in self.items: if (el.key in key_list): el.setSelected(True) else: el.setSelected(False)
[docs] def updateWidget(self): self.widget.clear() self.items = [] it = self.collection.get() for i, item in enumerate(it): el = QtWidgets.QListWidgetItem() el.setText(item[self.foreign_label_name]) el.key = item[self.foreign_key_name] # attach an extra attribute self.widget.addItem(el) self.items.append(el)
[docs] def reset(self): for item in self.items: item.setSelected(False)
def test1(): st = """Empty test """ pre = pre_mod + "test1 :" print(pre, st) def test2(): st = """Empty test """ pre = pre_mod + "test2 :" print(pre, st) def main(): pre = pre_mod + "main :" print(pre, "main: arguments: ", sys.argv) if (len(sys.argv) < 2): print(pre, "main: needs test number") else: st = "test" + str(sys.argv[1]) + "()" exec(st) if (__name__ == "__main__"): main()