diff --git a/soitool/modules/code_table_base.py b/soitool/modules/code_table_base.py index 0124328e5808da22d02efabd3eac8c120056dea8..68a0e3b80a348b16a3ba40508397d9431c7210af 100644 --- a/soitool/modules/code_table_base.py +++ b/soitool/modules/code_table_base.py @@ -58,25 +58,47 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): if size is None and data is None: self.generate_table() self.resizeColumnsToContents() - self.insert_headline(self.headline) + self.resizeRowsToContents() + self.insert_headline(self.start_headline) - # Resize height of rows and set size of window - resize_table(self, resize_columns=False, has_headline=True) + resize_table( + self, + resize_columns=False, + resize_rows=False, + has_headline=True, + ) else: - self.setColumnCount(len(data[1])) - self.setRowCount(len(data) - 1) # - 1 to skip headline + 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()): - item = QTableWidgetItem(data[i + 1][j]) # +1 skip headline - item.setTextAlignment(Qt.AlignCenter) + item = QTableWidgetItem( + cells[i + 1][j] + ) # +1 skip headline + if j == 2 and self.type == AUTHENTICATIONBOARDMODULE: + item.setTextAlignment(Qt.AlignLeft) + else: + item.setTextAlignment(Qt.AlignCenter) self.setItem(i, j, item) self.resizeColumnsToContents() - self.insert_headline(data[0]) + self.resizeRowsToContents() + self.insert_headline(cells[0]) - resize_table(self, resize_columns=False, has_headline=True) + resize_table( + self, + resize_columns=False, + resize_rows=False, + has_headline=True, + ) self.setFixedWidth(size["width"]) self.setFixedHeight(size["height"]) @@ -112,10 +134,10 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): Parameters ---------- text : string, optional - The headline text, self.headline is used if None, + The headline text, self.start_headline is used if None, by default None. """ - headline = self.headline if text is None else text + headline = self.start_headline if text is None else text item_headline = QTableWidgetItem(headline) item_headline.setTextAlignment(Qt.AlignHCenter) @@ -200,16 +222,26 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): List[0] contains headline, list[x][y] represents value of row x, column y. """ - data = [] + cells = [] item_headline = self.item(0, 0) if item_headline is not None: - data.append(item_headline.text()) + cells.append(item_headline.text()) + else: + cells.append("") for i in range(1, self.rowCount()): row = [] for j in range(self.columnCount()): row.append(self.item(i, j).text()) - data.append(row) + 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 diff --git a/soitool/modules/module_authentication_board.py b/soitool/modules/module_authentication_board.py index e1dc99965b92e0c85d5c973da40d8a504b96c4e3..a9e10cd46baaeda4e0be6d71ce52a56d793bdc33 100644 --- a/soitool/modules/module_authentication_board.py +++ b/soitool/modules/module_authentication_board.py @@ -1,5 +1,6 @@ """Module containing SOI-module 'Autentiseringstavle'.""" import string +from secrets import choice from PySide2.QtWidgets import QTableWidgetItem from PySide2 import QtGui from PySide2.QtCore import Qt @@ -39,8 +40,10 @@ class AuthenticationBoardModule(CodeTableBase): If parameters are given, the widget initializes accordingly: 'size' is a dict: {"width": int, "height": int}, - 'data' is a 2D list where data[0] is the headline, - and data[x][y] represents the value in row x, column y. + 'data' is a dict with keys "cells", "code_length", "space_interval", + "space_amount" and "code_character_type". "cells" is a 2D list where + cells[0] is the headline and cells[x][y] represents the value in row x, + column y. The other keys contain an integer. The widget does not use more room than needed, and resizes dynamically. It has shortcuts for adding and removing rows. @@ -63,12 +66,23 @@ class AuthenticationBoardModule(CodeTableBase): "Invalid value for CONSTANT 'CODE_CHARACTER_TYPE': " "'{}'".format(CODE_CHARACTER_TYPE) ) - self.start_no_of_codes = START_NO_OF_CODES - self.code_length = CODE_LENGTH - self.space_interval = SPACE_INTERVAL - self.space_amount = SPACE_AMOUNT - self.code_character_type = CODE_CHARACTER_TYPE - self.headline = HEADLINE_TEXT + # Set default values for table to be generated + if size is None and data is None: + self.start_no_of_codes = START_NO_OF_CODES + self.code_length = CODE_LENGTH + self.space_interval = SPACE_INTERVAL + self.space_amount = SPACE_AMOUNT + self.code_character_type = CODE_CHARACTER_TYPE + + numbers = self.generate_authentication_numbers() + self.start_headline = ( + HEADLINE_TEXT + + " (" + + str(numbers[0]) + + " & " + + str(numbers[1]) + + ")" + ) CodeTableBase.__init__(self, size, data) @@ -123,7 +137,13 @@ class AuthenticationBoardModule(CodeTableBase): # Resize code-column in case it got wider # Example: 'BGD' is wider than 'III' (depending on font) self.resizeColumnToContents(2) - resize_table(self, resize_columns=False, has_headline=True) + self.resizeRowToContents(selected_row_index + 1) + resize_table( + self, + resize_columns=False, + resize_rows=False, + has_headline=True, + ) def remove_row(self, row_index): """Remove selected row. @@ -140,7 +160,30 @@ class AuthenticationBoardModule(CodeTableBase): for i in range(row_index, self.rowCount()): self.item(i, 0).setText(self.code_characters[i - 1]) self.item(i, 1).setText(str(i - 1)) - resize_table(self, resize_columns=False, has_headline=True) + resize_table( + self, resize_columns=False, resize_rows=False, has_headline=True + ) + + def generate_authentication_numbers(self): + """Generate two non-equal numbers between 1 and CODE_LENGTH. + + Returns + ------- + list + Containing two integers, sorted in ascending order. + """ + available_numbers = list(range(1, self.code_length)) + + numbers = [] + numbers.append(choice(available_numbers)) + numbers.append(choice(available_numbers)) + + while numbers[0] == numbers[1]: + numbers[1] = choice(available_numbers) + + numbers.sort() + + return numbers @staticmethod def get_user_friendly_name(): diff --git a/soitool/modules/module_subtractorcodes.py b/soitool/modules/module_subtractorcodes.py index 3b04ab28ef7d67fcb7944d731c9ed37e989d4988..569deab641ac1a2d8e6bec93c7106aa287769d36 100644 --- a/soitool/modules/module_subtractorcodes.py +++ b/soitool/modules/module_subtractorcodes.py @@ -33,8 +33,10 @@ class SubtractorcodesModule(CodeTableBase): If parameters are given, the widget initializes accordingly: 'size' is a dict: {"width": int, "height": int}, - 'data' is a 2D list where data[0] is the headline, - and data[x][y] represents the value in row x, column y. + 'data' is a dict with keys "cells", "code_length", "space_interval", + "space_amount" and "code_character_type". "cells" is a 2D list where + cells[0] is the headline and cells[x][y] represents the value in row x, + column y. The other keys contain an integer. The widget does not use more room than needed, and resizes dynamically. It has shortcuts for adding and removing rows. @@ -48,7 +50,7 @@ class SubtractorcodesModule(CodeTableBase): "Invalid value for CONSTANT 'START_NO_OF_CODES': " "'{}'".format(START_NO_OF_CODES) ) - self.headline = HEADLINE_TEXT + self.start_headline = HEADLINE_TEXT self.code_length = CODE_LENGTH self.start_no_of_codes = START_NO_OF_CODES self.space_interval = SPACE_INTERVAL @@ -115,7 +117,13 @@ class SubtractorcodesModule(CodeTableBase): item_code.setFlags(item_code.flags() ^ Qt.ItemIsEditable) self.setItem(selected_row_index + 1, 2, item_code) - resize_table(self, resize_columns=False, has_headline=True) + self.resizeRowToContents(selected_row_index + 1) + resize_table( + self, + resize_columns=False, + resize_rows=False, + has_headline=True, + ) def remove_row(self, row_index): """Remove the selected row. @@ -128,7 +136,9 @@ class SubtractorcodesModule(CodeTableBase): self.removeRow(row_index) self.insert_row_identifiers(has_headline=True) - resize_table(self, resize_columns=False, has_headline=True) + resize_table( + self, resize_columns=False, resize_rows=False, has_headline=True + ) @staticmethod def get_user_friendly_name(): diff --git a/test/test_module_authentication_and_subtractor.py b/test/test_module_authentication_and_subtractor.py index 412bab95d15d7ca830fc5d445e2bd3bbc9ba936d..b7add13a9c313317cc4167f8cdcdef7abf5e34c6 100644 --- a/test/test_module_authentication_and_subtractor.py +++ b/test/test_module_authentication_and_subtractor.py @@ -45,8 +45,9 @@ class TestDefaultAuthenticationBoardAndSubtractorcodesModule( def test_default_module(self): """Test that module is initialized properly.""" # Assert correct headline - self.assertEqual( - self.authentication.item(0, 0).text(), HEADLINE_TEXT_AUTHENTICATION + self.assertTrue( + HEADLINE_TEXT_AUTHENTICATION + in self.authentication.item(0, 0).text() ) self.assertEqual( self.subtractor.item(0, 0).text(), HEADLINE_TEXT_SUBTRACTOR @@ -224,11 +225,17 @@ class TestAuthenticationBoardModuleFromData(unittest.TestCase): def test_create_from_data(self): """Test creating AuthenticationBoardModule from data.""" - test_data = [ - "Headline text", - ["A", "0", "TEST CODE ONE"], - ["B", "1", "TEST CODE TWO"], - ] + test_data = { + "cells": [ + "Headline text", + ["A", "0", "TEST CODE ONE"], + ["B", "1", "TEST CODE TWO"], + ], + "code_length": 11, + "space_interval": 4, + "space_amount": 1, + "code_character_type": "ascii", + } test_size = {"width": 100, "height": 100} module = AuthenticationBoardModule(size=test_size, data=test_data)