diff --git a/soitool/modules/code_table_base.py b/soitool/modules/code_table_base.py index ff219f4062f50561849a31791bb6660723a8a3e8..7f3e2b9ec47cec3e23689b4d67a2f70847128a36 100644 --- a/soitool/modules/code_table_base.py +++ b/soitool/modules/code_table_base.py @@ -1,5 +1,8 @@ """...""" from PySide2.QtWidgets import QTableWidget, QTableWidgetItem +from PySide2 import QtGui +from PySide2.QtCore import Qt +from soitool.coder import get_code_set, get_code from soitool.modules.module_base import ( ModuleBase, get_table_size, @@ -7,6 +10,9 @@ from soitool.modules.module_base import ( HEADLINE_FONT, ) +AUTHENTICATIONBOARDMODULE = "AuthenticationBoardModule" +SUBTRACTORCODESMODULE = "SubtractorcodesModule" + class Meta(type(ModuleBase), type(QTableWidget)): """Used as a metaclass to enable multiple inheritance.""" @@ -15,6 +21,154 @@ class Meta(type(ModuleBase), type(QTableWidget)): class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): """...""" - def __init__(self): + def __init__(self, size, data): + if self.type not in [ + AUTHENTICATIONBOARDMODULE, + SUBTRACTORCODESMODULE, + ]: + raise ValueError( + "Invalid value for class-variable type: " + "'{}'".format(self.type) + ) QTableWidget.__init__(self) ModuleBase.__init__(self) + + # Remove headers and scrollbars + self.horizontalHeader().hide() + self.verticalHeader().hide() + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + + # If parameters are None, generate new table + if size is None and data is None: + self.generate_table() + self.resizeColumnsToContents() + self.insert_headline() + + # Resize height of rows and set size of window + resize_table(self, resize_column=False) + else: + self.setColumnCount(len(data[1])) + self.setRowCount(len(data) - 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 + self.setItem(i, j, item) + + self.resizeColumnsToContents() + resize_table(self, resize_column=False) + self.setFixedWidth(size["width"]) + self.setFixedHeight(size["height"]) + + self.insert_headline(data[0]) + + def generate_table(self): + """Insert row identifiers and authentication codes...........""" + # Set number of rows and columns + self.setRowCount(self.start_no_of_codes) + self.setColumnCount(3) + + # Generate codes + codes = list( + get_code_set( + self.start_no_of_codes, + self.code_length, + self.code_character_type, + self.space_interval, + ) + ) + + # Insert table data + for i in range(self.start_no_of_codes): + if self.type == AUTHENTICATIONBOARDMODULE: + # Insert non-editable row identifier in first column + item_first = QTableWidgetItem(self.row_identifiers[i]) + item_first.setFlags(item_first.flags() ^ Qt.ItemIsEditable) + self.setItem(i, 0, item_first) + + # Insert non-editable row identifier (int) in second column + item_second = QTableWidgetItem(str(i)) + item_second.setFlags(item_second.flags() ^ Qt.ItemIsEditable) + self.setItem(i, 1, item_second) + + # Insert non-editable code in third column + item_third = QTableWidgetItem(codes[i]) + item_third.setFlags(item_third.flags() ^ Qt.ItemIsEditable) + self.setItem(i, 2, item_third) + elif self.type == SUBTRACTORCODESMODULE: + print("NOPE") + + def insert_headline(self): + """Insert headline text.""" + item_headline = QTableWidgetItem(self.headline) + item_headline.setTextAlignment(Qt.AlignHCenter) + item_headline.setFont(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_authentication_code(self): + """Generate authentication-code that does not already exist. + + Returns + ------- + string + Generated, unique authentication-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 + ) + unique_code = code not in existing_codes + + return code + + def get_codes(self): + """Get all authentication-codes in table. + + Returns + ------- + List + List containing authentication-codes. + """ + codes = [] + + # Start with row 1 to skip headline-row + for i in range(1, self.rowCount()): + codes.append(self.item(i, 2).text()) + + return codes + + def get_size(self): + """Return size of widget.""" + 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. + """ + data = [] + item_headline = self.item(0, 0) + if item_headline is not None: + data.append(item_headline.text()) + + for i in range(1, self.rowCount()): + row = [] + for j in range(self.columnCount()): + row.append(self.item(i, j).text()) + data.append(row) + + return data diff --git a/soitool/modules/module_authentication_board.py b/soitool/modules/module_authentication_board.py index 260a0f919ba432ed7329781047ecc86186074550..6dc6912475e5c7a1315a0df3e904513b982fdf69 100644 --- a/soitool/modules/module_authentication_board.py +++ b/soitool/modules/module_authentication_board.py @@ -1,20 +1,14 @@ """Module containing SOI-module 'Autentifiseringstavle'.""" import string -from PySide2.QtWidgets import QTableWidget, QTableWidgetItem +from PySide2.QtWidgets import QTableWidgetItem from PySide2 import QtGui 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, - HEADLINE_FONT, -) +from soitool.modules.module_base import resize_table from soitool.modules.code_table_base import CodeTableBase -START_NO_OF_AUTHENTICATION_CODES = 10 +START_NO_OF_CODES = 10 # Maximum value is len(ROW_IDENTIFIERS) CODE_LENGTH = 25 -CODE_CHARACTERS = "ascii" # Has to be 'ascii', 'digits' or 'combo' +CODE_CHARACTER_TYPE = "ascii" # Has to be 'ascii', 'digits' or 'combo' # Codes will consist of A-Z if 'ascii', 0-9 if 'digits' and A-Z+0-9 if 'combo'. ROW_IDENTIFIERS = string.ascii_uppercase # Characters for first column, # it's length determines maximum number of codes (rows). @@ -24,10 +18,6 @@ SPACE_INTERVAL = 5 # Adds space between sets of characters, 0 => no spaces HEADLINE_TEXT = "Autentiseringstavle" -# class Meta(type(ModuleBase), type(QTableWidget)): -# """Used as a metaclass to enable multiple inheritance.""" - - class AuthenticationBoardModule(CodeTableBase): """Modified QTableWidget representing a 'Autentifiseringstavle'. @@ -51,120 +41,27 @@ class AuthenticationBoardModule(CodeTableBase): def __init__(self, size=None, data=None): self.type = "AuthenticationBoardModule" - # QTableWidget.__init__(self) - # ModuleBase.__init__(self) - CodeTableBase.__init__(self) - if CODE_CHARACTERS == "ascii": + self.start_no_of_codes = START_NO_OF_CODES + self.code_length = CODE_LENGTH + self.space_interval = SPACE_INTERVAL + self.row_identifiers = ROW_IDENTIFIERS + + if CODE_CHARACTER_TYPE == "ascii": self.code_characters = string.ascii_uppercase - elif CODE_CHARACTERS == "digits": + elif CODE_CHARACTER_TYPE == "digits": self.code_characters = string.digits - elif CODE_CHARACTERS == "combo": + elif CODE_CHARACTER_TYPE == "combo": self.code_characters = string.ascii_uppercase + string.digits else: raise ValueError( - "Invalid value for CONSTANT 'CODE_CHARACTERS': " - "'{}'".format(CODE_CHARACTERS) + "Invalid value for CONSTANT 'CODE_CHARACTER_TYPE': " + "'{}'".format(CODE_CHARACTER_TYPE) ) + self.code_character_type = CODE_CHARACTER_TYPE + self.headline = HEADLINE_TEXT - # Remove headers and scrollbars - self.horizontalHeader().hide() - self.verticalHeader().hide() - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - - # If parameters are None, generate new table - if size is None and data is None: - self.generate_table() - self.resizeColumnsToContents() - self.insert_headline() - - # Resize height of rows and set size of window - resize_table(self, resize_column=False) - else: - self.setColumnCount(len(data[1])) - self.setRowCount(len(data) - 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 - self.setItem(i, j, item) - - self.resizeColumnsToContents() - resize_table(self, resize_column=False) - self.setFixedWidth(size["width"]) - self.setFixedHeight(size["height"]) - - self.insert_headline(data[0]) - - def generate_table(self): - """Insert row identifiers and authentication codes.""" - # Set number of rows and columns - self.setRowCount(START_NO_OF_AUTHENTICATION_CODES) - self.setColumnCount(3) - - # Generate codes - codes = list( - get_code_set( - START_NO_OF_AUTHENTICATION_CODES, - CODE_LENGTH, - CODE_CHARACTERS, - SPACE_INTERVAL, - ) - ) - - # Insert table data - for i in range(START_NO_OF_AUTHENTICATION_CODES): - # Insert non-editable row identifier in first column - item_first = QTableWidgetItem(ROW_IDENTIFIERS[i]) - item_first.setFlags(item_first.flags() ^ Qt.ItemIsEditable) - self.setItem(i, 0, item_first) - - # Insert non-editable row identifier (int) in second column - item_second = QTableWidgetItem(str(i)) - item_second.setFlags(item_second.flags() ^ Qt.ItemIsEditable) - self.setItem(i, 1, item_second) - - # Insert non-editable code in third column - item_third = QTableWidgetItem(codes[i]) - item_third.setFlags(item_third.flags() ^ Qt.ItemIsEditable) - self.setItem(i, 2, item_third) - - def insert_headline(self, text=HEADLINE_TEXT): - """Insert headline text. - - Parameters - ---------- - text : string, optional - The headline text, by default HEADLINE_TEXT - """ - item_headline = QTableWidgetItem(text) - item_headline.setTextAlignment(Qt.AlignHCenter) - item_headline.setFont(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_authentication_code(self): - """Generate authentication-code that does not already exist. - - Returns - ------- - string - Generated, unique authentication-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(CODE_LENGTH, CODE_CHARACTERS, SPACE_INTERVAL) - unique_code = code not in existing_codes - - return code + CodeTableBase.__init__(self, size, data) def keyPressEvent(self, event): """Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed.""" @@ -228,48 +125,6 @@ class AuthenticationBoardModule(CodeTableBase): self.item(i, 1).setText(str(i - 1)) resize_table(self, resize_column=False) - def get_codes(self): - """Get all authentication-codes in table. - - Returns - ------- - List - List containing authentication-codes. - """ - codes = [] - - # Start with row 1 to skip headline-row - for i in range(1, self.rowCount()): - codes.append(self.item(i, 2).text()) - - return codes - - def get_size(self): - """Return size of widget.""" - 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. - """ - content = [] - item_headline = self.item(0, 0) - if item_headline is not None: - content.append(item_headline.text()) - - for i in range(1, self.rowCount()): - row = [] - for j in range(self.columnCount()): - row.append(self.item(i, j).text()) - content.append(row) - - return content - @staticmethod def get_user_friendly_name(): """Get user-friendly name of module.""" diff --git a/soitool/modules/module_subtractorcodes.py b/soitool/modules/module_subtractorcodes.py new file mode 100644 index 0000000000000000000000000000000000000000..3233b65ed8a476c624a638b7392bdf4931e972f6 --- /dev/null +++ b/soitool/modules/module_subtractorcodes.py @@ -0,0 +1,41 @@ +"""Module containing SOI-module 'Subtraktorkoder'.""" +import string +from PySide2.QtWidgets import QTableWidgetItem +from PySide2 import QtGui +from PySide2.QtCore import Qt +from soitool.modules.module_base import resize_table +from soitool.modules.code_table_base import CodeTableBase + +START_NO_OF_CODES = 7 +CODE_LENGTH = 8 +SPACE_INTERVAL = 4 + +HEADLINE_TEXT = "Subtraktorkoder" + + +class SubtractorcodesModule(CodeTableBase): + """...""" + + def __init__(self, size=None, data=None): + self.type = "SubtractorcodesModule" + + self.start_no_of_codes = START_NO_OF_CODES + self.code_length = CODE_LENGTH + self.space_interval = SPACE_INTERVAL + # Characters for first and second column, + # it's length/2 it the maximum number of codes (rows). + self.row_identifiers = string.ascii_uppercase + self.code_character_type = "digits" + self.headline = HEADLINE_TEXT + + CodeTableBase.__init__(self, size, data) + + @staticmethod + def get_user_friendly_name(): + """Get user-friendly name of module.""" + return "Autentiseringstavle" + + @staticmethod + def get_icon(): + """Get icon of module.""" + return QtGui.QIcon("soitool/media/authenticationboardmodule.png") diff --git a/soitool/new_module_dialog.py b/soitool/new_module_dialog.py index acc3746ca017a7d8869694a71d58ee7788843338..c0b33101cbae9df2a79d25d94c3bd22933575236 100644 --- a/soitool/new_module_dialog.py +++ b/soitool/new_module_dialog.py @@ -16,6 +16,7 @@ from soitool.modules.module_table import TableModule from soitool.modules.module_authentication_board import ( AuthenticationBoardModule, ) +from soitool.modules.module_subtractorcodes import SubtractorcodesModule from soitool.modules.module_freetext import FreeTextModule @@ -25,6 +26,7 @@ from soitool.modules.module_freetext import FreeTextModule MODULE_CHOICES = [ TableModule, AuthenticationBoardModule, + SubtractorcodesModule, FreeTextModule, ]