Module soitool.modules.code_table_base
Module containing superclass for code-table-modules, and it's setup-dialog.
Superclass for AuthenticationBoardModule and SubtractorCodesModule.
Expand source code
"""Module containing superclass for code-table-modules, and it's setup-dialog.
Superclass for AuthenticationBoardModule and SubtractorCodesModule.
"""
from PySide2.QtWidgets import (
QTableWidget,
QTableWidgetItem,
QDialog,
QVBoxLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QComboBox,
QFormLayout,
QPushButton,
)
from PySide2.QtCore import Qt
from soitool.coder import get_code_set, get_code
from soitool.modules.module_base import (
ModuleBase,
get_table_size,
resize_table,
prepare_table_for_pdf_export,
is_event_remove_row,
is_event_add_row,
)
AUTHENTICATIONBOARD_MODULE = "AuthenticationBoardModule"
SUBTRACTORCODES_MODULE = "SubtractorcodesModule"
class Meta(type(ModuleBase), type(QTableWidget)):
"""Used as a metaclass to enable multiple inheritance."""
class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta):
"""Parent-class for AuthenticationBoardModule and SubtractorcodesModule.
Inherits from ModuleBase and QTableWidget.
ModuleBase is used as an interface, it's methods are overridden.
"""
def __init__(self, data):
QTableWidget.__init__(self)
ModuleBase.__init__(self)
# Remove headers and scrollbars
self.horizontalHeader().hide()
self.verticalHeader().hide()
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# Resize table when headline changes
self.cellChanged.connect(
lambda: resize_table(self, columns=False, has_headline=True,)
)
# If parameter 'data' is None, launch settings-dialog
if data is None:
# Disabling pylint-error
# 'Access to member before its definition line'
# because the variable is defined in subclass.
# pylint: disable=E0203
if self.start_no_of_codes > self.maximum_no_of_codes:
raise ValueError(
"The value of module-constant 'START_NO_OF_CODES' "
"is larger than module-constant 'MAXIMUM_NO_OF_CODES': "
"{} > {}".format(
self.start_no_of_codes, self.maximum_no_of_codes
)
)
dialog = CodeTableSettings(self)
dialog.exec()
self.start_headline = dialog.edit_headline.text()
self.start_no_of_codes = int(
dialog.combo_no_of_codes.currentText()
)
self.code_length = int(dialog.combo_code_length.currentText())
self.space_interval = int(
dialog.combo_space_interval.currentText()
)
self.space_amount = int(dialog.combo_space_amount.currentText())
self.generate_table()
self.resizeColumnsToContents()
self.insert_headline(self.start_headline)
resize_table(
self, columns=False, has_headline=True,
)
else:
self.code_length = data["code_length"]
self.space_interval = data["space_interval"]
self.space_amount = data["space_amount"]
self.code_character_type = data["code_character_type"]
cells = data["cells"]
self.setColumnCount(len(cells[1]))
self.setRowCount(len(cells) - 1) # - 1 to skip headline
# Set cell-items
for i in range(self.rowCount()):
for j in range(self.columnCount()):
# + 1 skip headline
item = QTableWidgetItem(cells[i + 1][j])
item.setTextAlignment(Qt.AlignCenter)
if j == 2:
item.setFont(self.code_font)
self.setItem(i, j, item)
self.resizeColumnsToContents()
self.insert_headline(cells[0])
resize_table(
self, columns=False, has_headline=True,
)
def generate_table(self):
"""Insert row identifiers and codes."""
# Set number of rows and columns
self.setRowCount(self.start_no_of_codes)
self.setColumnCount(3)
self.insert_row_identifiers()
# Generate codes
codes = list(
get_code_set(
self.start_no_of_codes,
self.code_length,
self.code_character_type,
self.space_interval,
self.space_amount,
)
)
# Insert codes
for i in range(self.start_no_of_codes):
# Insert non-editable code in third column
item_third = QTableWidgetItem(codes[i])
item_third.setTextAlignment(Qt.AlignCenter)
item_third.setFont(self.code_font)
item_third.setFlags(item_third.flags() ^ Qt.ItemIsEditable)
self.setItem(i, 2, item_third)
def insert_headline(self, text=None):
"""Insert headline text.
Parameters
----------
text : string, optional
The headline text, self.start_headline is used if None,
by default None.
"""
headline = self.start_headline if text is None else text
item_headline = QTableWidgetItem(headline)
item_headline.setTextAlignment(Qt.AlignCenter)
item_headline.setFont(self.headline_font)
self.insertRow(0)
self.setItem(0, 0, item_headline)
self.setSpan(0, 0, 1, self.columnCount()) # Make cell span all columns
def generate_unique_code(self):
"""Generate code that does not already exist.
Returns
-------
string
Unique code.
"""
# Get existing codes
existing_codes = self.get_codes()
# Randomly generate a new code until it is unique
unique_code = False
while not unique_code:
code = get_code(
self.code_length,
self.code_character_type,
self.space_interval,
self.space_amount,
)
unique_code = code not in existing_codes
return code
def get_codes(self):
"""Get all codes in table.
Returns
-------
List
List containing codes.
"""
codes = []
# Start from 1 to skip headline-row
for i in range(1, self.rowCount()):
codes.append(self.item(i, 2).text())
return codes
def keyPressEvent(self, event):
"""Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed."""
if is_event_add_row(event):
# If a row is selected
row_index = self.currentRow()
if row_index != -1:
self.add_row(row_index)
elif is_event_remove_row(event):
# If at least two rows (+ headline-row) exists and a row other than
# headline-row is selected
row_index = self.currentRow()
if self.rowCount() > 3 and row_index != 0 and row_index != -1:
self.remove_row(row_index)
else:
super().keyPressEvent(event)
def get_size(self):
"""Return size of table."""
return get_table_size(self)
def get_data(self):
"""Return list containing all data.
Returns
-------
List
List[0] contains headline,
list[x][y] represents value of row x, column y.
"""
cells = []
item_headline = self.item(0, 0)
if item_headline is not None:
cells.append(item_headline.text())
else:
cells.append("")
for i in range(1, self.rowCount()):
row = []
for j in range(self.columnCount()):
item = self.item(i, j)
text = item.text() if item is not None else ""
row.append(text)
cells.append(row)
data = {
"cells": cells,
"code_length": self.code_length,
"space_interval": self.space_interval,
"space_amount": self.space_amount,
"code_character_type": self.code_character_type,
}
return data
def prepare_for_pdf_export(self):
"""Prepare for PDF-export."""
prepare_table_for_pdf_export(self)
@staticmethod
def get_icon():
"""Abstract method, should be implemented by derived class."""
raise NotImplementedError
@staticmethod
def get_user_friendly_name():
"""Abstract method, should be implemented by derived class."""
raise NotImplementedError
class CodeTableSettings(QDialog):
"""Setup of CodeTableBase.
Parameters
----------
code_table_base : soitool.modules.code_table_base.CodeTableBase
Is used to fetch the modules default values, so that these are
pre-selected.
"""
def __init__(self, code_table_base):
super().__init__()
# Hide help-button, disable close-button and set window width
self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
self.setWindowFlag(Qt.WindowCloseButtonHint, False)
self.setFixedWidth(350)
# Headline
self.label_headline = QLabel("Overskrift")
self.edit_headline = QLineEdit()
self.edit_headline.setText(code_table_base.start_headline)
# Number of codes
self.label_no_of_codes = QLabel("Antall koder")
self.combo_no_of_codes = QComboBox()
for i in range(2, code_table_base.maximum_no_of_codes + 1):
self.combo_no_of_codes.addItem(str(i))
self.combo_no_of_codes.setCurrentIndex(
code_table_base.start_no_of_codes - 2
)
# Code length
self.label_code_length = QLabel("Kodelengde")
self.combo_code_length = QComboBox()
for i in range(2, 31):
self.combo_code_length.addItem(str(i))
self.combo_code_length.setCurrentIndex(code_table_base.code_length - 2)
# Space interval
self.label_space_interval = QLabel("Intervall for kodemellomrom")
self.combo_space_interval = QComboBox()
for i in range(11):
self.combo_space_interval.addItem(str(i))
self.combo_space_interval.setCurrentIndex(
code_table_base.space_interval
)
# Space amount
self.label_space_amount = QLabel("Mellomrom per intervall")
self.combo_space_amount = QComboBox()
for i in range(6):
self.combo_space_amount.addItem(str(i))
self.combo_space_amount.setCurrentIndex(code_table_base.space_amount)
# Create-button
self.button_create = QPushButton("Opprett")
self.button_create.clicked.connect(self.accept)
self.create_and_set_layout()
def create_and_set_layout(self):
"""Create layouts, add widgets and set layout."""
# Layout for input-widgets
self.form_layout = QFormLayout()
self.form_layout.addRow(self.label_headline, self.edit_headline)
self.form_layout.addRow(self.label_no_of_codes, self.combo_no_of_codes)
self.form_layout.addRow(self.label_code_length, self.combo_code_length)
self.form_layout.addRow(
self.label_space_interval, self.combo_space_interval
)
self.form_layout.addRow(
self.label_space_amount, self.combo_space_amount
)
# Layout for create-button
self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.button_create)
# Main layout
self.main_layout = QVBoxLayout()
self.main_layout.addLayout(self.form_layout)
self.main_layout.addLayout(self.button_layout)
self.setLayout(self.main_layout)
Classes
class CodeTableBase (data)
-
Parent-class for AuthenticationBoardModule and SubtractorcodesModule.
Inherits from ModuleBase and QTableWidget. ModuleBase is used as an interface, it's methods are overridden.
Class-variable 'type' should be set by derived class.
Expand source code
class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): """Parent-class for AuthenticationBoardModule and SubtractorcodesModule. Inherits from ModuleBase and QTableWidget. ModuleBase is used as an interface, it's methods are overridden. """ def __init__(self, data): QTableWidget.__init__(self) ModuleBase.__init__(self) # Remove headers and scrollbars self.horizontalHeader().hide() self.verticalHeader().hide() self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Resize table when headline changes self.cellChanged.connect( lambda: resize_table(self, columns=False, has_headline=True,) ) # If parameter 'data' is None, launch settings-dialog if data is None: # Disabling pylint-error # 'Access to member before its definition line' # because the variable is defined in subclass. # pylint: disable=E0203 if self.start_no_of_codes > self.maximum_no_of_codes: raise ValueError( "The value of module-constant 'START_NO_OF_CODES' " "is larger than module-constant 'MAXIMUM_NO_OF_CODES': " "{} > {}".format( self.start_no_of_codes, self.maximum_no_of_codes ) ) dialog = CodeTableSettings(self) dialog.exec() self.start_headline = dialog.edit_headline.text() self.start_no_of_codes = int( dialog.combo_no_of_codes.currentText() ) self.code_length = int(dialog.combo_code_length.currentText()) self.space_interval = int( dialog.combo_space_interval.currentText() ) self.space_amount = int(dialog.combo_space_amount.currentText()) self.generate_table() self.resizeColumnsToContents() self.insert_headline(self.start_headline) resize_table( self, columns=False, has_headline=True, ) else: self.code_length = data["code_length"] self.space_interval = data["space_interval"] self.space_amount = data["space_amount"] self.code_character_type = data["code_character_type"] cells = data["cells"] self.setColumnCount(len(cells[1])) self.setRowCount(len(cells) - 1) # - 1 to skip headline # Set cell-items for i in range(self.rowCount()): for j in range(self.columnCount()): # + 1 skip headline item = QTableWidgetItem(cells[i + 1][j]) item.setTextAlignment(Qt.AlignCenter) if j == 2: item.setFont(self.code_font) self.setItem(i, j, item) self.resizeColumnsToContents() self.insert_headline(cells[0]) resize_table( self, columns=False, has_headline=True, ) def generate_table(self): """Insert row identifiers and codes.""" # Set number of rows and columns self.setRowCount(self.start_no_of_codes) self.setColumnCount(3) self.insert_row_identifiers() # Generate codes codes = list( get_code_set( self.start_no_of_codes, self.code_length, self.code_character_type, self.space_interval, self.space_amount, ) ) # Insert codes for i in range(self.start_no_of_codes): # Insert non-editable code in third column item_third = QTableWidgetItem(codes[i]) item_third.setTextAlignment(Qt.AlignCenter) item_third.setFont(self.code_font) item_third.setFlags(item_third.flags() ^ Qt.ItemIsEditable) self.setItem(i, 2, item_third) def insert_headline(self, text=None): """Insert headline text. Parameters ---------- text : string, optional The headline text, self.start_headline is used if None, by default None. """ headline = self.start_headline if text is None else text item_headline = QTableWidgetItem(headline) item_headline.setTextAlignment(Qt.AlignCenter) item_headline.setFont(self.headline_font) self.insertRow(0) self.setItem(0, 0, item_headline) self.setSpan(0, 0, 1, self.columnCount()) # Make cell span all columns def generate_unique_code(self): """Generate code that does not already exist. Returns ------- string Unique code. """ # Get existing codes existing_codes = self.get_codes() # Randomly generate a new code until it is unique unique_code = False while not unique_code: code = get_code( self.code_length, self.code_character_type, self.space_interval, self.space_amount, ) unique_code = code not in existing_codes return code def get_codes(self): """Get all codes in table. Returns ------- List List containing codes. """ codes = [] # Start from 1 to skip headline-row for i in range(1, self.rowCount()): codes.append(self.item(i, 2).text()) return codes def keyPressEvent(self, event): """Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed.""" if is_event_add_row(event): # If a row is selected row_index = self.currentRow() if row_index != -1: self.add_row(row_index) elif is_event_remove_row(event): # If at least two rows (+ headline-row) exists and a row other than # headline-row is selected row_index = self.currentRow() if self.rowCount() > 3 and row_index != 0 and row_index != -1: self.remove_row(row_index) else: super().keyPressEvent(event) def get_size(self): """Return size of table.""" return get_table_size(self) def get_data(self): """Return list containing all data. Returns ------- List List[0] contains headline, list[x][y] represents value of row x, column y. """ cells = [] item_headline = self.item(0, 0) if item_headline is not None: cells.append(item_headline.text()) else: cells.append("") for i in range(1, self.rowCount()): row = [] for j in range(self.columnCount()): item = self.item(i, j) text = item.text() if item is not None else "" row.append(text) cells.append(row) data = { "cells": cells, "code_length": self.code_length, "space_interval": self.space_interval, "space_amount": self.space_amount, "code_character_type": self.code_character_type, } return data def prepare_for_pdf_export(self): """Prepare for PDF-export.""" prepare_table_for_pdf_export(self) @staticmethod def get_icon(): """Abstract method, should be implemented by derived class.""" raise NotImplementedError @staticmethod def get_user_friendly_name(): """Abstract method, should be implemented by derived class.""" raise NotImplementedError
Ancestors
- ModuleBase
- abc.ABC
- PySide2.QtWidgets.QTableWidget
- PySide2.QtWidgets.QTableView
- PySide2.QtWidgets.QAbstractItemView
- PySide2.QtWidgets.QAbstractScrollArea
- PySide2.QtWidgets.QFrame
- PySide2.QtWidgets.QWidget
- PySide2.QtCore.QObject
- PySide2.QtGui.QPaintDevice
- Shiboken.Object
Subclasses
Class variables
var staticMetaObject
Methods
def generate_table(self)
-
Insert row identifiers and codes.
Expand source code
def generate_table(self): """Insert row identifiers and codes.""" # Set number of rows and columns self.setRowCount(self.start_no_of_codes) self.setColumnCount(3) self.insert_row_identifiers() # Generate codes codes = list( get_code_set( self.start_no_of_codes, self.code_length, self.code_character_type, self.space_interval, self.space_amount, ) ) # Insert codes for i in range(self.start_no_of_codes): # Insert non-editable code in third column item_third = QTableWidgetItem(codes[i]) item_third.setTextAlignment(Qt.AlignCenter) item_third.setFont(self.code_font) item_third.setFlags(item_third.flags() ^ Qt.ItemIsEditable) self.setItem(i, 2, item_third)
def generate_unique_code(self)
-
Generate code that does not already exist.
Returns
string
- Unique code.
Expand source code
def generate_unique_code(self): """Generate code that does not already exist. Returns ------- string Unique code. """ # Get existing codes existing_codes = self.get_codes() # Randomly generate a new code until it is unique unique_code = False while not unique_code: code = get_code( self.code_length, self.code_character_type, self.space_interval, self.space_amount, ) unique_code = code not in existing_codes return code
def get_codes(self)
-
Get all codes in table.
Returns
List
- List containing codes.
Expand source code
def get_codes(self): """Get all codes in table. Returns ------- List List containing codes. """ codes = [] # Start from 1 to skip headline-row for i in range(1, self.rowCount()): codes.append(self.item(i, 2).text()) return codes
def get_data(self)
-
Return list containing all data.
Returns
List
- List[0] contains headline, list[x][y] represents value of row x, column y.
Expand source code
def get_data(self): """Return list containing all data. Returns ------- List List[0] contains headline, list[x][y] represents value of row x, column y. """ cells = [] item_headline = self.item(0, 0) if item_headline is not None: cells.append(item_headline.text()) else: cells.append("") for i in range(1, self.rowCount()): row = [] for j in range(self.columnCount()): item = self.item(i, j) text = item.text() if item is not None else "" row.append(text) cells.append(row) data = { "cells": cells, "code_length": self.code_length, "space_interval": self.space_interval, "space_amount": self.space_amount, "code_character_type": self.code_character_type, } return data
def get_size(self)
-
Return size of table.
Expand source code
def get_size(self): """Return size of table.""" return get_table_size(self)
def insert_headline(self, text=None)
-
Insert headline text.
Parameters
text
:string
, optional- The headline text, self.start_headline is used if None, by default None.
Expand source code
def insert_headline(self, text=None): """Insert headline text. Parameters ---------- text : string, optional The headline text, self.start_headline is used if None, by default None. """ headline = self.start_headline if text is None else text item_headline = QTableWidgetItem(headline) item_headline.setTextAlignment(Qt.AlignCenter) item_headline.setFont(self.headline_font) self.insertRow(0) self.setItem(0, 0, item_headline) self.setSpan(0, 0, 1, self.columnCount()) # Make cell span all columns
def keyPressEvent(self, event)
-
Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed.
Expand source code
def keyPressEvent(self, event): """Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed.""" if is_event_add_row(event): # If a row is selected row_index = self.currentRow() if row_index != -1: self.add_row(row_index) elif is_event_remove_row(event): # If at least two rows (+ headline-row) exists and a row other than # headline-row is selected row_index = self.currentRow() if self.rowCount() > 3 and row_index != 0 and row_index != -1: self.remove_row(row_index) else: super().keyPressEvent(event)
def prepare_for_pdf_export(self)
-
Prepare for PDF-export.
Expand source code
def prepare_for_pdf_export(self): """Prepare for PDF-export.""" prepare_table_for_pdf_export(self)
Inherited members
class CodeTableSettings (code_table_base)
-
Setup of CodeTableBase.
Parameters
code_table_base
:CodeTableBase
- Is used to fetch the modules default values, so that these are pre-selected.
Expand source code
class CodeTableSettings(QDialog): """Setup of CodeTableBase. Parameters ---------- code_table_base : soitool.modules.code_table_base.CodeTableBase Is used to fetch the modules default values, so that these are pre-selected. """ def __init__(self, code_table_base): super().__init__() # Hide help-button, disable close-button and set window width self.setWindowFlag(Qt.WindowContextHelpButtonHint, False) self.setWindowFlag(Qt.WindowCloseButtonHint, False) self.setFixedWidth(350) # Headline self.label_headline = QLabel("Overskrift") self.edit_headline = QLineEdit() self.edit_headline.setText(code_table_base.start_headline) # Number of codes self.label_no_of_codes = QLabel("Antall koder") self.combo_no_of_codes = QComboBox() for i in range(2, code_table_base.maximum_no_of_codes + 1): self.combo_no_of_codes.addItem(str(i)) self.combo_no_of_codes.setCurrentIndex( code_table_base.start_no_of_codes - 2 ) # Code length self.label_code_length = QLabel("Kodelengde") self.combo_code_length = QComboBox() for i in range(2, 31): self.combo_code_length.addItem(str(i)) self.combo_code_length.setCurrentIndex(code_table_base.code_length - 2) # Space interval self.label_space_interval = QLabel("Intervall for kodemellomrom") self.combo_space_interval = QComboBox() for i in range(11): self.combo_space_interval.addItem(str(i)) self.combo_space_interval.setCurrentIndex( code_table_base.space_interval ) # Space amount self.label_space_amount = QLabel("Mellomrom per intervall") self.combo_space_amount = QComboBox() for i in range(6): self.combo_space_amount.addItem(str(i)) self.combo_space_amount.setCurrentIndex(code_table_base.space_amount) # Create-button self.button_create = QPushButton("Opprett") self.button_create.clicked.connect(self.accept) self.create_and_set_layout() def create_and_set_layout(self): """Create layouts, add widgets and set layout.""" # Layout for input-widgets self.form_layout = QFormLayout() self.form_layout.addRow(self.label_headline, self.edit_headline) self.form_layout.addRow(self.label_no_of_codes, self.combo_no_of_codes) self.form_layout.addRow(self.label_code_length, self.combo_code_length) self.form_layout.addRow( self.label_space_interval, self.combo_space_interval ) self.form_layout.addRow( self.label_space_amount, self.combo_space_amount ) # Layout for create-button self.button_layout = QHBoxLayout() self.button_layout.addWidget(self.button_create) # Main layout self.main_layout = QVBoxLayout() self.main_layout.addLayout(self.form_layout) self.main_layout.addLayout(self.button_layout) self.setLayout(self.main_layout)
Ancestors
- PySide2.QtWidgets.QDialog
- PySide2.QtWidgets.QWidget
- PySide2.QtCore.QObject
- PySide2.QtGui.QPaintDevice
- Shiboken.Object
Class variables
var staticMetaObject
Methods
def create_and_set_layout(self)
-
Create layouts, add widgets and set layout.
Expand source code
def create_and_set_layout(self): """Create layouts, add widgets and set layout.""" # Layout for input-widgets self.form_layout = QFormLayout() self.form_layout.addRow(self.label_headline, self.edit_headline) self.form_layout.addRow(self.label_no_of_codes, self.combo_no_of_codes) self.form_layout.addRow(self.label_code_length, self.combo_code_length) self.form_layout.addRow( self.label_space_interval, self.combo_space_interval ) self.form_layout.addRow( self.label_space_amount, self.combo_space_amount ) # Layout for create-button self.button_layout = QHBoxLayout() self.button_layout.addWidget(self.button_create) # Main layout self.main_layout = QVBoxLayout() self.main_layout.addLayout(self.form_layout) self.main_layout.addLayout(self.button_layout) self.setLayout(self.main_layout)
class Meta (name, bases, namespace, **kwargs)
-
Used as a metaclass to enable multiple inheritance.
Expand source code
class Meta(type(ModuleBase), type(QTableWidget)): """Used as a metaclass to enable multiple inheritance."""
Ancestors
- abc.ABCMeta
- Shiboken.ObjectType
- builtins.type