diff --git a/soitool/media/phonetable.png b/soitool/media/phonetable.png new file mode 100644 index 0000000000000000000000000000000000000000..2e699d71b68a4b6f7ccb259efbbebd341dcdbdde Binary files /dev/null and b/soitool/media/phonetable.png differ diff --git a/soitool/modules/code_table_base.py b/soitool/modules/code_table_base.py index 0f26f31801d3d08f219d2324faab4800db97e709..73ba7f556cfe493146249291dee0966a0b1079ec 100644 --- a/soitool/modules/code_table_base.py +++ b/soitool/modules/code_table_base.py @@ -44,9 +44,7 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): # Resize table when headline changes self.cellChanged.connect( - lambda: resize_table( - self, rows=False, columns=False, has_headline=True, - ) + lambda: resize_table(self, columns=False, has_headline=True,) ) # If parameters are None, launch settings-dialog and generate new table if size is None and data is None: @@ -81,7 +79,7 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): self.insert_headline(self.start_headline) resize_table( - self, columns=False, rows=False, has_headline=True, + self, columns=False, has_headline=True, ) else: self.code_length = data["code_length"] @@ -108,7 +106,7 @@ class CodeTableBase(ModuleBase, QTableWidget, metaclass=Meta): self.insert_headline(cells[0]) resize_table( - self, columns=False, rows=False, has_headline=True, + self, columns=False, has_headline=True, ) self.setFixedWidth(size["width"]) self.setFixedHeight(size["height"]) diff --git a/soitool/modules/config/module_phonebook.json b/soitool/modules/config/module_phonebook.json new file mode 100644 index 0000000000000000000000000000000000000000..57f60b0431c03637a7a3ebb4e184a0086bd9dc75 --- /dev/null +++ b/soitool/modules/config/module_phonebook.json @@ -0,0 +1,7 @@ +{ + "Funksjon": true, + "Telefon": true, + "FDN": false, + "Iridium": false, + "E-post": false +} diff --git a/soitool/modules/fit_to_contents_widgets.py b/soitool/modules/fit_to_contents_widgets.py index 460ec94ad2c2308d7e4466fb0164ed5407e5ffc5..4b4d7219445460b5c35a4f6656f044804720fefc 100644 --- a/soitool/modules/fit_to_contents_widgets.py +++ b/soitool/modules/fit_to_contents_widgets.py @@ -51,10 +51,12 @@ class TableWithSizeOfContent(QTableWidget): def __init__(self, *arg, **kwargs): super(TableWithSizeOfContent, self).__init__(*arg, **kwargs) - # Makes table fit content of cells + # Fixed size because resizing to contents causes size that depends on + # screen size, which we don't want.. self.verticalHeader().setSectionResizeMode( - QHeaderView.ResizeMode.ResizeToContents + QHeaderView.ResizeMode.Fixed ) + # Make columns fit size of content self.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeMode.ResizeToContents ) diff --git a/soitool/modules/module_authentication_board.py b/soitool/modules/module_authentication_board.py index 06ba84f67f0fee4b0a46b072c50bde45af22b0ea..2e3619ba9472cba204aaf1623de7d9989eaa6896 100644 --- a/soitool/modules/module_authentication_board.py +++ b/soitool/modules/module_authentication_board.py @@ -151,7 +151,7 @@ class AuthenticationBoardModule(CodeTableBase): self.resizeRowToContents(selected_row_index + 1) - resize_table(self, columns=False, rows=False, has_headline=True) + resize_table(self, columns=False, has_headline=True) def remove_row(self, row_index): """Remove selected row. @@ -168,7 +168,7 @@ 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, columns=False, rows=False, has_headline=True) + resize_table(self, columns=False, has_headline=True) def generate_authentication_numbers(self): """Generate two non-equal numbers between 1 and self.code_length. diff --git a/soitool/modules/module_base.py b/soitool/modules/module_base.py index 568c9fa952e7893592117732af26a9c7922d5f55..a762d4f3f5cfee0b7c5c8a158cc272e9e69c60d7 100644 --- a/soitool/modules/module_base.py +++ b/soitool/modules/module_base.py @@ -62,15 +62,16 @@ class ModuleBase(ABC): raise NotImplementedError -def resize_table(table, rows=True, columns=True, has_headline=False): +def resize_table(table, columns=True, has_headline=False): """Resize a given QTableWidget. + On purpose not resizing rows, as this causes different heights from screen + to screen. + Parameters ---------- table : QTableWidget QTablewidget-instance to resize. - rows : bool - Resizes rows to contents if True, by default True. columns : bool Resizes columns to contents if True, by default True. has_headline : bool @@ -79,8 +80,6 @@ def resize_table(table, rows=True, columns=True, has_headline=False): """ if columns: table.resizeColumnsToContents() - if rows: - table.resizeRowsToContents() # If table has a headline, make sure table is wide enough to fit it. if has_headline: @@ -175,10 +174,10 @@ def event_is_ctrl_minus(event): bool True if event is 'CTRL -'. """ - # Underline is in practice minus in this situation. We don't know why - return ( - event.modifiers() == Qt.ControlModifier - and event.key() == Qt.Key_Underscore + # Underline is in practice minus on some computers in this situation. We + # don't know why. For this reason we check both for underline and minus + return event.modifiers() == Qt.ControlModifier and ( + event.key() == Qt.Key_Underscore or event.key() == Qt.Key_Minus ) @@ -211,8 +210,8 @@ def event_is_shift_minus(event): bool True if event is 'SHIFT -'. """ - # Underline is in practice minus in this situation. We don't know why - return ( - event.modifiers() == Qt.ShiftModifier - and event.key() == Qt.Key_Underscore + # Underline is in practice minus on some computers in this situation. We + # don't know why. For this reason we check both for underline and minus + return event.modifiers() == Qt.ShiftModifier and ( + event.key() == Qt.Key_Underscore or event.key() == Qt.Key_Minus ) diff --git a/soitool/modules/module_code_phrase.py b/soitool/modules/module_code_phrase.py index 80bae32166bd9254ff14fa76869c1a66eaa9315f..7c74a0ee95357d18133be31e67afd5d18dc0f1a4 100644 --- a/soitool/modules/module_code_phrase.py +++ b/soitool/modules/module_code_phrase.py @@ -95,6 +95,9 @@ class CodePhraseModule(ModuleBase, QWidget, metaclass=Meta): self.table.setHorizontalHeaderItem(1, QTableWidgetItem("Frase")) self.table.horizontalHeader().setStyleSheet("font-weight: bold") + # Forcing height of the header because it changes from screen to screen + self.table.horizontalHeader().setFixedHeight(30) + # To ensure table is initially larger than title self.table.horizontalHeader().setMinimumSectionSize(100) self.table.verticalHeader().hide() diff --git a/soitool/modules/module_phonebook.py b/soitool/modules/module_phonebook.py new file mode 100644 index 0000000000000000000000000000000000000000..592aad18d41dbe2df17834145465904369f868da --- /dev/null +++ b/soitool/modules/module_phonebook.py @@ -0,0 +1,437 @@ +"""SOI module for functions and associated contact informations.""" + +from json import load +from PySide2.QtWidgets import ( + QWidget, + QDialog, + QLabel, + QVBoxLayout, + QTableWidget, + QPushButton, + QHBoxLayout, + QTableWidgetItem, + QCheckBox, +) +from PySide2.QtCore import Qt, QSize +from PySide2.QtGui import QBrush, QColor, QIcon +from soitool.modules.module_base import ( + ModuleBase, + HEADLINE_FONT, + resize_table, + get_table_size, + TABLE_CELL_DEFAULT_FONT, + event_is_ctrl_plus, + event_is_ctrl_minus, +) + + +class ColumnsChoicePopup(QDialog): + """A popup for selecting wich columns to hide/show in phonebook. + + Parameters + ---------- + QDialog : QDialog + Parent class for popup functionality. + selected_columns : dict + Table structure for columns to show/hide. + """ + + def __init__(self, selected_columns): + super().__init__() + self.selected_columns = selected_columns + self.setWindowTitle("Kolonner") + + # Layout + layout = QVBoxLayout() + + # Checkboxes + for header in self.selected_columns.keys(): + box = QCheckBox(header) + box.setChecked(self.selected_columns[header]) + layout.addWidget(box) + + # Button + btn_done = QPushButton("Bruk") + btn_done.clicked.connect(lambda: self.update_selected_columns(layout)) + layout.addWidget(btn_done) + + self.setLayout(layout) + + def update_selected_columns(self, layout): + """Update the dict for columns to hide/show based on checkboxes. + + Parameters + ---------- + layout : QLayout + Layout with checkboxes to loop trough. + """ + for item_index in range(layout.count()): + item = layout.itemAt(item_index).widget() + if isinstance(item, QCheckBox): + self.selected_columns[item.text()] = item.isChecked() + self.accept() + + def get_selected_columns(self): + """Getter for the table structure. + + Returns + ------- + dict + The table structure. + """ + return self.selected_columns + + +class Meta(type(ModuleBase), type(QWidget)): + """Used as a metaclass to enable multiple inheritance.""" + + +class PhonebookModule(ModuleBase, QWidget, metaclass=Meta): + """SOI module for functions and associated contact informations. + + # This module includes: + + ## Components + + * Header + * Table with predefined columns + * Buttons for editing module + * Popup (ColumnsChoicePopup) + + ## Features + + * Keybord shortcuts for editing module + * Buttons only visble when mouse in modules space + * Interface generated from config file + * Popup for editing columns + * Automatic resizing + * Able to be loaded from data parameter + + Parameters + ---------- + data : dict + Module content, used if not None. See self.get_data() + """ + + def __init__(self, data=None): + self.type = PhonebookModule.__name__ + QWidget.__init__(self) + ModuleBase.__init__(self) + + # Table structure + with open( + "soitool/modules/config/module_phonebook.json", "r" + ) as config_file: + self.selected_columns = load(config_file) + + # Header + self.header = QLabel("Telefonliste") + self.header.setFont(HEADLINE_FONT) + self.header.setFixedSize(QSize(160, 20)) + + # Table + self.table = self.__create_table() + self.table.cellChanged.connect(self.resize) + + # Buttons + self.buttons = self.__creat_buttons() + + # Layout + layout = QVBoxLayout() + layout.setAlignment(Qt.AlignTop | Qt.AlignLeft) + layout.setSpacing(0) + layout.setMargin(0) + layout.addWidget(self.header) + layout.addWidget(self.table) + layout.addWidget(self.buttons) + self.setLayout(layout) + + if data: + self.load_data_to_module(data) + else: + self.set_columns() + + # !!!!! CREATE MAIN COMPONENTS !!!!!! + + def __create_table(self): + """Add phonebook table. + + Returns + ------- + QTableWidget + The phonebook table. + """ + table = QTableWidget(2, len(self.selected_columns)) + table.setFont(TABLE_CELL_DEFAULT_FONT) + table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + table.horizontalHeader().hide() + table.verticalHeader().hide() + + # Headers - setup + column_index = 0 + for header in self.selected_columns: + header_item = QTableWidgetItem(header) + header_item.setFont(HEADLINE_FONT) + header_item.setFlags(header_item.flags() ^ Qt.ItemIsEditable) + header_item.setBackground(QBrush(QColor("black"))) + header_item.setForeground(QBrush(QColor("white"))) + table.setItem(0, column_index, header_item) + column_index += 1 + + return table + + def __creat_buttons(self): + """Add buttons for editing phonebook table. + + Returns + ------- + QWidget + Widget holding a layout with buttons. + """ + # Button for editing columns + btn_components = QPushButton("Kolonner", self) + btn_components.clicked.connect(self.open_popup) + btn_components.setFixedWidth(100) + + # Buttons for adding row + btn_add = QPushButton(" + ", self) + btn_add.clicked.connect(self.add_row) + btn_add.setFixedWidth(50) + + # Buttons for removing row + btn_remove = QPushButton(" - ", self) + btn_remove.clicked.connect(self.remove_row) + btn_remove.setFixedWidth(50) + + # Layout for structure + hbox = QHBoxLayout() + hbox.setSpacing(0) + hbox.setSpacing(0) + hbox.addWidget(btn_components) + hbox.addWidget(btn_add) + hbox.addWidget(btn_remove) + + # Widget wrapping buttons + wrapper = QWidget() + wrapper.setFixedSize(QSize(230, 50)) + wrapper.setLayout(hbox) + wrapper.hide() + + return wrapper + + # !!!!! EVENT HADNDLERS !!!!! + + def enterEvent(self, event): + """Eventhandler for showing buttons when mous enters widgets space. + + Parameters + ---------- + event : enterEvent + Called when mouse enters widgets space. + """ + self.buttons.show() + self.resize() + QTableWidget.enterEvent(self, event) + + def leaveEvent(self, event): + """Eventhandler for hiding buttons when mouse leaves widgets space. + + Parameters + ---------- + event : enterEvent + Called when mosue leaves widgets space. + """ + self.buttons.hide() + self.resize() + QTableWidget.enterEvent(self, event) + + def keyPressEvent(self, event): + """Keyboard shortcuts for adding/removing rows and selecting columns. + + Parameters + ---------- + event : keyPressEvent + Called when keys are pressed. + """ + if event_is_ctrl_plus(event): + self.add_row() + elif event_is_ctrl_minus(event): + self.remove_row() + elif ( + event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_R + ): + self.open_popup() + else: + super().keyPressEvent(event) + + # !!!!! TABLE OPERATIONS !!!!! + + def add_row(self): + """Add row to phonebook table.""" + self.table.insertRow(self.table.currentRow() + 1) + self.resize() + + def remove_row(self): + """Remove selected row from phonebook table.""" + if self.table.currentRow() > 0: + self.table.removeRow(self.table.currentRow()) + self.resize() + + def set_columns(self): + """Update table columns visibility based on selected_columns.""" + selected_item = self.table.currentItem() + for header in self.selected_columns.keys(): + self.table.setColumnHidden( + self.get_column_index_by_header(header), + not (self.selected_columns[header]), + ) + # Restore selected item, because the above operation sets the current + # selected item to the item in the last column of the first row. + self.table.setCurrentItem(selected_item) + self.resize() + + def get_column_index_by_header(self, header): + """Get index for column containing a spesific header. + + Parameters + ---------- + header : string + The header to search for. + + Returns + ------- + int + The column index for where the header was found. + + Raises + ------ + LookupError + Unable to find header in table headers. + """ + for column_index in range(self.table.columnCount()): + self.table.setCurrentCell(0, column_index) + if self.table.currentItem().text() == header: + return column_index + + raise LookupError("'" + header + "' not in table headers.") + + # !!!!! MODULE OPERATIONs !!!!! + + def resize(self): + """Resize whole module based on content.""" + resize_table(self.table) + + width = max(get_table_size(self.table)[0], self.header.minimumWidth()) + if self.buttons.isVisible(): + width = max(width, self.buttons.minimumWidth()) + + self.setFixedWidth(width) + + height = get_table_size(self.table)[1] + self.header.minimumHeight() + if self.buttons.isVisible(): + height += self.buttons.minimumHeight() + + self.setFixedHeight(height) + + def load_data_to_module(self, data): + """Load module content from data. + + Parameters + ---------- + data : dict + Module serialized as dict. + """ + for column_header in self.selected_columns.keys(): + if column_header in data.keys(): + self.selected_columns[column_header] = True + else: + self.selected_columns[column_header] = False + + self.set_columns() + + number_of_rows = len(list(data.values())[0]) + self.table.setRowCount(self.table.rowCount() + number_of_rows - 1) + + for column_header in data.keys(): + column_index = self.get_column_index_by_header(column_header) + for row_index in range(1, number_of_rows + 1): + current_item = QTableWidgetItem( + data[column_header][row_index - 1] + ) + self.table.setItem(row_index, column_index, current_item) + + # To stop the last column of the first row to be selected, which looks + # strange on windows + self.table.clearSelection() + + def open_popup(self): + """Open dialog for editing columns.""" + popup = ColumnsChoicePopup(self.selected_columns) + popup.exec_() + self.selected_columns = popup.get_selected_columns() + self.set_columns() + + # !!!!! MODULE BASE OPERATIONS !!!!! + + def get_size(self): + """Getter for module size. + + Returns + ------- + tuple + Size of the module (width, height) + """ + self.resize() + return (self.minimumWidth(), self.minimumHeight()) + + def get_data(self): + """Get module content as serialized data. + + Returns + ------- + dict + Serialized module content. + + Format: { + "header1" : ["row1", "row2", "row3"], + "header2": ["row1", ..] + } + """ + data = {} + + for column_index in range(self.table.columnCount()): + header = self.table.item(0, column_index).text() + if self.selected_columns[header]: + row_data = [] + for row_index in range(1, self.table.rowCount()): + row_item = self.table.item(row_index, column_index) + if row_item: + row_data.append(row_item.text()) + else: + row_data.append("") + data[header] = row_data + + return data + + @staticmethod + def get_user_friendly_name(): + """Get user-friendly name of module. + + Returns + ------- + string + User-friendly name. + """ + return "Telefonliste" + + @staticmethod + def get_icon(): + """Get icon. + + Returns + ------- + QIcon + Picture of module. + """ + return QIcon("soitool/media/phonetable.png") diff --git a/soitool/modules/module_predefined_codes.py b/soitool/modules/module_predefined_codes.py index 7c9ce9b4bc7b1ae6d9e4f89a3992a3261a11ccd2..7c92bbc4d3b20306e36072ffd2eb0ca119cddd5b 100644 --- a/soitool/modules/module_predefined_codes.py +++ b/soitool/modules/module_predefined_codes.py @@ -507,7 +507,7 @@ class PredefinedCodesTable(QTableWidget): # Insert headline and resize table self.insert_headline(headline) - resize_table(self, rows=False, columns=False, has_headline=True) + resize_table(self, columns=False, has_headline=True) def insert_headline(self, text): """Insert headline. diff --git a/soitool/modules/module_subtractorcodes.py b/soitool/modules/module_subtractorcodes.py index 89d3f5c479e4f153489101b426450849a5a3db59..8f3e0529af71be3818559149c6d599259ec0e438 100644 --- a/soitool/modules/module_subtractorcodes.py +++ b/soitool/modules/module_subtractorcodes.py @@ -130,7 +130,7 @@ class SubtractorcodesModule(CodeTableBase): self.setItem(selected_row_index + 1, 2, item_code) self.resizeRowToContents(selected_row_index + 1) - resize_table(self, columns=False, rows=False, has_headline=True) + resize_table(self, columns=False, has_headline=True) def remove_row(self, row_index): """Remove the selected row. @@ -143,7 +143,7 @@ class SubtractorcodesModule(CodeTableBase): self.removeRow(row_index) self.insert_row_identifiers(has_headline=True) - resize_table(self, columns=False, rows=False, has_headline=True) + resize_table(self, columns=False, has_headline=True) @staticmethod def get_user_friendly_name(): diff --git a/soitool/new_module_dialog.py b/soitool/new_module_dialog.py index 897172ead06d76cbd6b2ba901a04d2c792c8752f..a8796c2c1c0e1e13dccd1bcc41ee449a0986f40b 100644 --- a/soitool/new_module_dialog.py +++ b/soitool/new_module_dialog.py @@ -16,6 +16,7 @@ from soitool.modules.module_authentication_board import ( ) from soitool.modules.module_subtractorcodes import SubtractorcodesModule from soitool.modules.module_freetext import FreeTextModule +from soitool.modules.module_phonebook import PhonebookModule from soitool.modules.module_code_phrase import CodePhraseModule from soitool.modules.module_predefined_codes import PredefinedCodesModule from soitool.accept_reject_dialog import AcceptRejectDialog @@ -29,6 +30,7 @@ MODULE_CHOICES = [ AuthenticationBoardModule, SubtractorcodesModule, FreeTextModule, + PhonebookModule, CodePhraseModule, PredefinedCodesModule, ] diff --git a/soitool/serialize_export_import_soi.py b/soitool/serialize_export_import_soi.py index ac7eb865fe18d819e549830d8c1d013d947a2c8c..ad7d2904c076b74809120bf501554ac33be742b7 100644 --- a/soitool/serialize_export_import_soi.py +++ b/soitool/serialize_export_import_soi.py @@ -10,6 +10,7 @@ from soitool.modules.module_authentication_board import ( ) from soitool.modules.module_subtractorcodes import SubtractorcodesModule from soitool.modules.module_freetext import FreeTextModule +from soitool.modules.module_phonebook import PhonebookModule from soitool.modules.module_predefined_codes import PredefinedCodesModule from soitool.modules.module_code_phrase import CodePhraseModule @@ -322,6 +323,10 @@ def construct_modules_from_serialized(serialized_modules, database): modules.append( {"widget": FreeTextModule(size, data), "meta": module["meta"]} ) + elif module_type == "PhonebookModule": + modules.append( + {"widget": PhonebookModule(data), "meta": module["meta"]} + ) elif module_type == "PredefinedCodesModule": modules.append( { diff --git a/test/test_module_phonebook.py b/test/test_module_phonebook.py new file mode 100644 index 0000000000000000000000000000000000000000..87c2fbf5c50b91bb9ba2ee0c34bfae36c6abbcf7 --- /dev/null +++ b/test/test_module_phonebook.py @@ -0,0 +1,158 @@ +"""Test module_phonebook.py.""" + +import unittest +from PySide2.QtGui import qApp, QKeySequence +from PySide2.QtCore import Qt, QTimer +from PySide2.QtTest import QTest +from PySide2.QtWidgets import ( + QApplication, + QCheckBox, + QPushButton, + QTableWidgetItem, +) +from soitool.soi import SOI +from soitool.modules.module_phonebook import PhonebookModule + + +if isinstance(qApp, type(None)): + app = QApplication([]) +else: + app = qApp + + +class TestPhonebookModule(unittest.TestCase): + """TestCase for default PhonebookModule.""" + + def setUp(self): + """Prepare a plane PhonebookModule.""" + self.phonebook = PhonebookModule() + self.phonebook.show() + + def test_header(self): + """Test header is correct.""" + self.assertEqual(self.phonebook.header.text(), "Telefonliste") + + def test_resize_width(self): + """Test able to type in table and resize to content.""" + rambo_quote = "Live for nothing or die for something." + item = QTableWidgetItem(rambo_quote) + old_width = self.phonebook.minimumWidth() + self.phonebook.table.setItem(1, 0, item) + new_width = self.phonebook.minimumWidth() + self.assertGreater(new_width, old_width) + + def test_popup(self): + """Test popup is shown and i able to edit columns.""" + old_column_count = visible_columns_in(self.phonebook.table) + + def popup_action(): + popup = app.activeModalWidget().layout() + + for item_index in range(popup.count()): + current_item = popup.itemAt(item_index).widget() + if ( + isinstance(current_item, QCheckBox) + and current_item.text() == "E-post" + ): + current_item.setChecked(True) + elif isinstance(current_item, QPushButton): + QTest.mouseClick(current_item, Qt.LeftButton) + + QTimer.singleShot(0, popup_action) + + QTest.keySequence( + self.phonebook, QKeySequence(Qt.ControlModifier + Qt.Key_R) + ) + new_column_count = visible_columns_in(self.phonebook.table) + self.assertEqual(new_column_count, old_column_count + 1) + + def test_add_row_and_resize(self): + """Test adding row and resizes acordingly.""" + old_row_count = self.phonebook.table.rowCount() + old_height = self.phonebook.minimumHeight() + QTest.keySequence( + self.phonebook, QKeySequence(Qt.ControlModifier + Qt.Key_Plus) + ) + new_row_count = self.phonebook.table.rowCount() + new_height = self.phonebook.minimumHeight() + self.assertEqual(new_row_count, old_row_count + 1) + self.assertGreater(new_height, old_height) + + def test_remove_row(self): + """Test removing row.""" + self.phonebook.table.setRowCount(self.phonebook.table.rowCount() + 5) + old_row_count = self.phonebook.table.rowCount() + self.phonebook.table.setCurrentCell(1, 0) + QTest.keySequence( + self.phonebook, QKeySequence(Qt.ControlModifier + Qt.Key_Minus), + ) + new_row_count = self.phonebook.table.rowCount() + self.assertEqual(new_row_count, old_row_count - 1) + + def test_add_to_soi_smoke_test(self): + """Test that can add to SOI successfully.""" + soi = SOI() + test_name = "Test name" + soi.add_module(test_name, self.phonebook, False) + self.assertTrue(soi.module_name_taken(test_name)) + + +class TestPhonebookModuleWithDataParameter(unittest.TestCase): + """TestCase for PhoneBookModule with content preset.""" + + def setUp(self): + """Prepare a phonebook with preloaded content.""" + self.data = { + "Funksjon": ["Colonel Sam", "Rambo", ""], + "E-post": ["sam@usarmy.com", "muscle@guns.com", ""], + } + self.phonebook = PhonebookModule(data=self.data) + self.phonebook.show() + + def test_column_count(self): + """Test number of visible columns is correct.""" + self.assertEqual( + len(self.data), visible_columns_in(self.phonebook.table) + ) + + def test_content(self): + """Test content is loaded correctly.""" + for column_index in range(self.phonebook.table.columnCount()): + self.phonebook.table.setCurrentCell(0, column_index) + column_header = self.phonebook.table.currentItem().text() + if not self.phonebook.table.isColumnHidden(column_index): + for row_index in range(1, self.phonebook.table.rowCount()): + self.phonebook.table.setCurrentCell( + row_index, column_index + ) + current_text = self.phonebook.table.currentItem().text() + self.assertEqual( + current_text, self.data[column_header][row_index - 1] + ) + + def test_add_to_soi_smoketest(self): + """Test that can add to SOI successfully.""" + soi = SOI() + test_name = "Test name" + soi.add_module(test_name, self.phonebook, False) + self.assertTrue(soi.module_name_taken(test_name)) + + +def visible_columns_in(table): + """Count number of visible columns in a table. + + Parameters + ---------- + table : QTableWidget + The table to count visible columns in. + + Returns + ------- + counter : int + Number of visible columns in table. + """ + counter = 0 + for column_index in range(table.columnCount()): + if not table.isColumnHidden(column_index): + counter += 1 + return counter diff --git a/test/test_resolution_smoke_test.py b/test/test_resolution_smoke_test.py index 791bd65c4556dcf95369a973f2f770cc01ed47b6..d3b7b6b86314f79c3a89d1492f317be192a9b426 100644 --- a/test/test_resolution_smoke_test.py +++ b/test/test_resolution_smoke_test.py @@ -109,8 +109,9 @@ class TestModulesAcrossResolutions(unittest.TestCase): {"x": 664, "y": 0, "page": 1, "name": "AuthenticationBoardModule"}, {"x": 1081.5, "y": 0, "page": 1, "name": "SubtractorcodesModule"}, {"x": 1317.0, "y": 0, "page": 1, "name": "CodePhraseModule"}, - {"x": 1529.0, "y": 0, "page": 1, "name": "FreeTextModule"}, - {"x": 1639.0, "y": 0, "page": 1, "name": "TableModule"}, + {"x": 1529.0, "y": 0, "page": 1, "name": "PhonebookModule"}, + {"x": 1771.0, "y": 0, "page": 1, "name": "FreeTextModule"}, + {"x": 1881.0, "y": 0, "page": 1, "name": "TableModule"}, ] # For use with modules that require a database