diff --git a/soitool/codebook.py b/soitool/codebook.py index 48860f9541efe1c252aa558516767368e402cf50..6bcf314dfc9694cb945539ea0ad1cd9bdb8bc79f 100644 --- a/soitool/codebook.py +++ b/soitool/codebook.py @@ -1,4 +1,4 @@ -"""Codebook. +"""GUI-interface towards database-table 'CodeBook'. Contains functionality for viewing, editing and inserting new rows in the database-table 'CodeBook'. @@ -6,7 +6,6 @@ in the database-table 'CodeBook'. from PySide2.QtWidgets import QTableView from PySide2.QtSql import QSqlDatabase, QSqlTableModel from PySide2.QtCore import Qt -from soitool.database import DBPATH # , Database from soitool.style import CODEBOOK_HEADER_FONT, CODEBOOK_HEADER_BACKGROUND_CSS # Name and type of database @@ -17,17 +16,20 @@ DBTYPE = "QSQLITE" class CodeBookTableView(QTableView): """TableView with a model of the 'codebook'-table from database. - This modified QTableView creates a CodeBookTableModel, - which reads the codebook-table. - User can add, edit and insert entries to the database through this View. + This modified QTableView creates a CodeBookTableModel, which reads the + codebook-table. User can add, edit, delete and insert entries through this + view. + + Parameter 'database' should be an instance of soitool.database.Database, + and is used to create a QSqlDatabase from the database-file. Raises RuntimeError if database does not open. """ - def __init__(self): + def __init__(self, database): super().__init__() db = QSqlDatabase.addDatabase(DBTYPE, CONNAME) - db.setDatabaseName(DBPATH) + db.setDatabaseName(database.db_path) if not db.open(): raise RuntimeError("Could not open database.") @@ -106,7 +108,7 @@ class CodeBookTableModel(QSqlTableModel): when a value is changed by the view. The last row is used by the view to insert a new database record, - therefore, only column 'word' (Primary key) is editable in this row. + therefore, only column 'Word' (Primary key) is editable in this row. All columns except 'Code' are editable. This class initializes by connecting to database and selecting table. diff --git a/soitool/codebook_to_pdf.py b/soitool/codebook_to_pdf.py index 94d6bed396b6db093b89bf86edc631598e80238e..90130e44c017e6d0bdfa8385824ff19bba3f1e09 100644 --- a/soitool/codebook_to_pdf.py +++ b/soitool/codebook_to_pdf.py @@ -14,7 +14,6 @@ from reportlab.lib.styles import ParagraphStyle from reportlab.lib import colors from reportlab.lib.pagesizes import A4, portrait from reportlab.lib.units import cm -from soitool.database import Database from soitool.enumerates import CodebookSort A4_WIDTH, A4_HEIGHT = A4 @@ -53,11 +52,15 @@ TABLE_STYLE = TableStyle( ) -def generate_codebook_pdf(small=False, page_size=A4, orientation=portrait): +def generate_codebook_pdf( + database, small=False, page_size=A4, orientation=portrait +): """Generate PDF with data from database-table 'CodeBook'. Parameters ---------- + database : soitool.database.Database + Reference to database-instance. small : bool, optional Data is from full codebook if False (default), from small codebook if True. @@ -75,7 +78,7 @@ def generate_codebook_pdf(small=False, page_size=A4, orientation=portrait): title_decode = Paragraph(TITLE_FULL_DECODE, TITLE_STYLE) # Get data from database - data_code, data_decode = get_codebook_data(small) + data_code, data_decode = get_codebook_data(database, small) # Create Tables with data sorted by Word/Code and set predefined style table_code = Table(data_code, repeatRows=1) @@ -130,11 +133,13 @@ def generate_filename(small=False): return f"Kodebok_{date}.pdf" -def get_codebook_data(small=False): +def get_codebook_data(database, small=False): """Read and format codebook-data from database sorted by Word and Code. Parameters ---------- + database : soitool.database.Database + Reference to database-instance. small : bool Retrieves full codebook if False (default), small codebook if True. @@ -145,9 +150,8 @@ def get_codebook_data(small=False): the second list is a decodebook (sorted by Code). """ # Get data from CodeBook-table - db = Database() - db_data_code = db.get_codebook(small, sort=CodebookSort.WORD) - db_data_decode = db.get_codebook(small, sort=CodebookSort.CODE) + db_data_code = database.get_codebook(small, sort=CodebookSort.WORD) + db_data_decode = database.get_codebook(small, sort=CodebookSort.CODE) # Lists to append column-headers and formatted data data_code = [] diff --git a/soitool/database.py b/soitool/database.py index 7cbca53fae41914765c7206ac2d6317425812578..cc0c69d8655e819c504d083de14bca65daf7a5b1 100644 --- a/soitool/database.py +++ b/soitool/database.py @@ -6,7 +6,7 @@ from datetime import datetime import soitool.coder from soitool.enumerates import CodebookSort -# Set name and path to (future) database +# Set name and path to default (future) database DBNAME = "database" CURDIR = os.path.dirname(__file__) DBPATH = os.path.join(CURDIR, DBNAME) @@ -16,14 +16,16 @@ SECONDS_IN_24H = 24 * 60 * 60 # DDL-statements for creating tables CODEBOOK = ( - "CREATE TABLE CodeBook" - "(Word VARCHAR PRIMARY KEY NOT NULL CHECK(length(Word) > 0), " + "CREATE TABLE CodeBook(" + "Word VARCHAR PRIMARY KEY NOT NULL CHECK(length(Word) > 0), " "Category VARCHAR, " "Type VARCHAR DEFAULT 'Stor' CHECK(Type='Stor' OR Type='Liten'), " "Code VARCHAR UNIQUE)" ) CATEGORYWORDS = ( - "CREATE TABLE CategoryWords" "(Word VARCHAR PRIMARY KEY, Category VARCHAR)" + "CREATE TABLE CategoryWords(" + "Word VARCHAR PRIMARY KEY, " + "Category VARCHAR NOT NULL CHECK(length(Category) > 0))" ) BYHEART = "CREATE TABLE ByHeart(Word VARCHAR PRIMARY KEY)" @@ -31,34 +33,36 @@ LASTUPDATED = "CREATE TABLE LastUpdated(Timestamp DATETIME PRIMARY KEY)" class Database: - """ - Holds database-connection and related functions. + """Holds database-connection and related functions. - Connects to existing db if found, creates new db if not. + Uses default database unless parameter 'db_path', path to a database-file, + is given. Connects to existing db if found, creates new db if not. If db is created, tables are created and filled. Holds a QTimer that requests an update of CodeBook on every timeout. """ - def __init__(self): + def __init__(self, db_path=DBPATH): + + self.db_path = db_path - db_exists = os.path.exists(DBPATH) + db_exists = os.path.exists(self.db_path) if db_exists: print("Connecting to existing DB.") - self.conn = sqlite3.connect(DBPATH) + self.conn = sqlite3.connect(db_path) print("DB-connection established.") else: print("Creating new DB.") - self.conn = sqlite3.connect(DBPATH) + self.conn = sqlite3.connect(db_path) self.create_tables() print("DB created.") self.fill_tables() print("Tables filled with data.") - self.conn.row_factory = sqlite3.Row # Enables row['columnName'] + self.conn.row_factory = sqlite3.Row # Enables row["columnName"] def create_tables(self): """Create tables CodeBook, CategoryWords and ByHeart.""" @@ -144,6 +148,7 @@ class Database: """Update Timestamp in LastUpdated to current time.""" stmt = "UPDATE LastUpdated SET Timestamp = ?" self.conn.execute(stmt, (str(datetime.now()),)) + self.conn.commit() def get_categories(self): """ @@ -230,6 +235,8 @@ class Database: self.conn.execute(stmt, (codes.pop(), words[i][0])) # Updates LastUpdated with current time self.update_last_updated() + # Save changes in db + self.conn.commit() print("Code in CodeBook updated") @@ -329,3 +336,4 @@ class Database: # Insert code to the param word in db stmt = "UPDATE CodeBook SET Code = ? WHERE Word = ?" self.conn.execute(stmt, (code, word)) + self.conn.commit() diff --git a/soitool/main_window.py b/soitool/main_window.py index 73d0ab233de1a4a18b0c679cc08ca631789b8867..bfb194a5b29ae3d3c1fb4d7bb474714a41fc4c5c 100644 --- a/soitool/main_window.py +++ b/soitool/main_window.py @@ -1,7 +1,6 @@ """Inclues the main window of our application. Built up by widgets implemented in other modules. - """ import sys import os @@ -24,7 +23,7 @@ from soitool.codebook import CodeBookTableView from soitool.codebook_row_adder import CodebookRowAdder from soitool.codebook_to_pdf import generate_codebook_pdf from soitool.dialog_wrappers import exec_info_dialog -from soitool.database import Database +from soitool.database import Database, DBPATH from soitool.serialize_export_import_soi import ( export_soi, import_soi, @@ -39,24 +38,27 @@ class ModuleType(Enum): class MainWindow(QMainWindow): - """MainWindow, skallet til hele applikasjonen.""" + """MainWindow, shell of the entire application. + + Parameter 'db_path' is the path to an existing or future database-file. + """ - def __init__(self): # pylint: disable = R0914, R0915 + def __init__(self, db_path=DBPATH): # pylint: disable = R0914, R0915 super().__init__() self.setGeometry(100, 100, 800, 800) self.setWindowTitle("SOI-tool") self.statusBar() # Database instance - database = Database() + self.database = Database(db_path) # Timer for automatic update of codes in CodeBook self.timer = QTimer() # Interval i set to msec since last 24h update self.timer.setInterval( - database.seconds_to_next_update(60 * 60 * 24) * 1000 + self.database.seconds_to_next_update(60 * 60 * 24) * 1000 ) self.timer.timeout.connect( - lambda: database.update_codebook_auto(self.timer) + lambda: self.database.update_codebook_auto(self.timer) ) self.timer.start() @@ -145,6 +147,7 @@ class MainWindow(QMainWindow): # Regenerate codebook-codes: regenerate_codes = QAction("Nye koder i db", self) regenerate_codes.setStatusTip("Nye koder lages tilfeldig") + regenerate_codes.triggered.connect(self.database.update_codebook) codebook_menu.addAction(regenerate_codes) # Export codebook as PDF @@ -153,14 +156,16 @@ class MainWindow(QMainWindow): # Export full codebook export_codebook_full = QAction("Stor kodebok", self) export_codebook_full.setStatusTip("Eksporter stor kodebok som PDF") - export_codebook_full.triggered.connect(generate_codebook_pdf) + export_codebook_full.triggered.connect( + partial(generate_codebook_pdf, database=self.database) + ) export_codebook.addAction(export_codebook_full) # Export small codebook export_codebook_small = QAction("Liten kodebok", self) export_codebook_small.setStatusTip("Eksporter liten kodebok som PDF") export_codebook_small.triggered.connect( - partial(generate_codebook_pdf, small=True) + partial(generate_codebook_pdf, database=self.database, small=True) ) export_codebook.addAction(export_codebook_small) @@ -189,7 +194,7 @@ class MainWindow(QMainWindow): else: # Create widgets tab = QWidget() - view = CodeBookTableView() + view = CodeBookTableView(self.database) row_adder = CodebookRowAdder(view) # Add widgets to layouts diff --git a/soitool/setup_settings.py b/soitool/setup_settings.py index 1f23448163ae9224e83db8ac1d9ffbecb4fcd7e4..9e19b468cea539fc23027de3799ee1a50fa6b646 100644 --- a/soitool/setup_settings.py +++ b/soitool/setup_settings.py @@ -13,81 +13,236 @@ from PySide2.QtWidgets import ( QLineEdit, QRadioButton, QPushButton, + QComboBox, + QGroupBox, ) class Setup(QDialog): # pylint: disable = R0902 - """Contains the settings for the SOI.""" - - def __init__(self): # pylint: disable = R0915 + """Contains the settings for the SOI. + + This class is used to change the settings for the SOI. + There are 4 different settings-groups; headerdata, orientation, placement + and algorithm. In headerdata you can change the text that appears in the + header of the SOI. Orientation is whether you want the SOI in landscape or + portrait. Placement is if you want to move the modules yourself or let the + program do it. And algorithm is which algorithms should be used to place + the modules on the SOI. + + Parameters + ---------- + soi : soitool.soi.SOI + The SOI-instance to change + """ + + def __init__(self, soi): # pylint: disable = R0915 super().__init__() + + self.soi = soi + + # layouts self.layout_setup = QVBoxLayout() self.layout_buttons = QHBoxLayout() self.layout_header = QFormLayout() - self.layout_paper_orientation = QFormLayout() - self.layout_algorithm = QFormLayout() - self.layout_module_placement = QFormLayout() - - # Labels for headings - self.label_setup = QLabel("Oppsett") - # setup.setStyleSheet("font: 12pt") + self.layout_orientation_button = QVBoxLayout() + self.layout_alg_button_bin = QVBoxLayout() + self.layout_alg_button_pack = QVBoxLayout() + self.layout_alg_button_sort = QVBoxLayout() + self.layout_placement_button = QVBoxLayout() + + # groupbox for radiobuttons + self.group_orientation = QGroupBox() + self.group_placement = QGroupBox() + self.group_algorithm_bin = QGroupBox() + self.group_algorithm_pack = QGroupBox() + self.group_algorithm_sort = QGroupBox() + + # labels for mainheadings self.label_header = QLabel("Headerdata") self.label_paper_orientation = QLabel("Papirretning") - self.label_algorithm = QLabel("Plasseringsalgoritme") + self.label_algorithm = QLabel("Plasseringsalgoritmer") self.label_module_placement = QLabel("Modulplassering") - self.layout_setup.addWidget(self.label_setup) - - # Headerdata + # headerdata self.layout_setup.addWidget(self.label_header) - self.head1 = QLabel("Header1") # Change variablename later - self.head2 = QLabel("Header2") # Change variablename later - self.hline1 = QLineEdit() # Change variablename later - self.hline2 = QLineEdit() # Change variablename later - self.layout_header.addRow(self.head1, self.hline1) - self.layout_header.addRow(self.head2, self.hline2) + self.label_title = QLabel("Tittel:") + self.label_description = QLabel("Beskrivelse:") + self.label_version = QLabel("Versjon:") + self.label_date = QLabel("Dato:") + self.label_valid_from = QLabel("Gyldig fra:") + self.label_valid_to = QLabel("Gyldig til:") + self.label_classification = QLabel("Klassifisering") + + self.edit_title = QLineEdit() + self.edit_description = QLineEdit() + self.edit_version = QLineEdit() + self.edit_date = QLineEdit() + self.edit_valid_from = QLineEdit() + self.edit_valid_to = QLineEdit() + + self.edit_classification = QComboBox() + self.edit_classification.addItem("UGRADERT") + self.edit_classification.addItem("BEGRENSET") + self.edit_classification.addItem("KONFIDENSIELT") + self.edit_classification.addItem("HEMMELIG") + self.edit_classification.addItem("STRENGT HEMMELIG") + + self.layout_header.addRow(self.label_title, self.edit_title) + self.layout_header.addRow( + self.label_description, self.edit_description + ) + self.layout_header.addRow(self.label_version, self.edit_version) + self.layout_header.addRow(self.label_date, self.edit_date) + self.layout_header.addRow(self.label_valid_from, self.edit_valid_from) + self.layout_header.addRow(self.label_valid_to, self.edit_valid_to) + self.layout_header.addRow( + self.label_classification, self.edit_classification + ) self.layout_setup.addLayout(self.layout_header) - # Paperorientation + # paperorientation self.layout_setup.addWidget(self.label_paper_orientation) - self.pob1 = QRadioButton() # Change variablename later - self.pob2 = QRadioButton() # Change variablename later - self.layout_paper_orientation.addRow(self.pob1, QLabel("Horisontal")) - self.layout_paper_orientation.addRow(self.pob2, QLabel("Vertikal")) - self.layout_setup.addLayout(self.layout_paper_orientation) - - # Placement algorithm - self.layout_setup.addWidget(self.label_algorithm) - self.pb1 = QRadioButton() # Change variablename later - self.pb2 = QRadioButton() # Change variablename later - self.pb3 = QRadioButton() # Change variablename later - self.pb4 = QRadioButton() # Change variablename later - self.layout_algorithm.addRow(self.pb1, QLabel("Alg1")) - self.layout_algorithm.addRow(self.pb2, QLabel("Alg2")) - self.layout_algorithm.addRow(self.pb3, QLabel("Alg3")) - self.layout_algorithm.addRow(self.pb4, QLabel("Alg4")) - self.layout_setup.addLayout(self.layout_algorithm) - - # Moduleplacement + self.rbutton_landscape = QRadioButton("Horisontal") + self.rbutton_portrait = QRadioButton("Vertikal") + self.layout_orientation_button.addWidget(self.rbutton_landscape) + self.layout_orientation_button.addWidget(self.rbutton_portrait) + self.group_orientation.setLayout(self.layout_orientation_button) + self.layout_setup.addWidget(self.group_orientation) + + # moduleplacement self.layout_setup.addWidget(self.label_module_placement) - self.mb1 = QRadioButton() # Change variablename later - self.mb2 = QRadioButton() # Change variablename later - self.layout_module_placement.addRow(self.mb1, QLabel("Automatisk")) - self.layout_module_placement.addRow(self.mb2, QLabel("Manuelt")) - self.layout_setup.addLayout(self.layout_module_placement) - - # Exit-buttons - self.button_cancel = QPushButton("Avbryt") + self.rbutton_auto = QRadioButton("Automatisk") + self.rbutton_manual = QRadioButton("Manuelt") + self.layout_placement_button.addWidget(self.rbutton_auto) + self.layout_placement_button.addWidget(self.rbutton_manual) + self.group_placement.setLayout(self.layout_placement_button) + self.layout_setup.addWidget(self.group_placement) + + # placement algorithm + self.layout_setup.addWidget(self.label_algorithm) + self.rbutton_bin1 = QRadioButton("BFF") + self.rbutton_bin2 = QRadioButton("BBF") + self.rbutton_pack1 = QRadioButton("MaxRectsBI") + self.rbutton_pack2 = QRadioButton("SkylinBl") + self.rbutton_pack3 = QRadioButton("GuillotineBssfSas") + self.rbutton_sort1 = QRadioButton("none") + self.rbutton_sort2 = QRadioButton("area") + self.rbutton_sort3 = QRadioButton("width") + self.rbutton_sort4 = QRadioButton("height") + + self.layout_alg_button_bin.addWidget(QLabel("Bin")) + self.layout_alg_button_bin.addWidget(self.rbutton_bin1) + self.layout_alg_button_bin.addWidget(self.rbutton_bin2) + self.layout_alg_button_pack.addWidget(QLabel("Pack")) + self.layout_alg_button_pack.addWidget(self.rbutton_pack1) + self.layout_alg_button_pack.addWidget(self.rbutton_pack2) + self.layout_alg_button_pack.addWidget(self.rbutton_pack3) + self.layout_alg_button_sort.addWidget(QLabel("Sort")) + self.layout_alg_button_sort.addWidget(self.rbutton_sort1) + self.layout_alg_button_sort.addWidget(self.rbutton_sort2) + self.layout_alg_button_sort.addWidget(self.rbutton_sort3) + self.layout_alg_button_sort.addWidget(self.rbutton_sort4) + + self.group_algorithm_bin.setLayout(self.layout_alg_button_bin) + self.group_algorithm_pack.setLayout(self.layout_alg_button_pack) + self.group_algorithm_sort.setLayout(self.layout_alg_button_sort) + + self.layout_setup.addWidget(self.group_algorithm_bin) + self.layout_setup.addWidget(self.group_algorithm_pack) + self.layout_setup.addWidget(self.group_algorithm_sort) + + # save and cancel self.button_save = QPushButton("Lagre") - self.layout_buttons.addWidget(self.button_cancel) + self.button_cancel = QPushButton("Avbryt") self.layout_buttons.addWidget(self.button_save) + self.layout_buttons.addWidget(self.button_cancel) self.layout_setup.addLayout(self.layout_buttons) self.setLayout(self.layout_setup) - self.button_cancel.clicked.connect(self.reject) # esc-key (default) - self.button_save.clicked.connect(self.accept) # enter-key (default) - - # need two functions, save and cancel - # when cancel, clear lineedits and set radiobuttons to default or SOI-parts - # when save, lineedits writes to labels and find a way to get radiobuttons + self.button_cancel.clicked.connect(self.cancel) # esc-key (default) + self.button_save.clicked.connect(self.save) # enter-key (default) + + def cancel(self): + """Close the dialog without saving.""" + self.reject() + + def save(self): + """Save and update the SOI with the given changes.""" + self.soi.title = self.edit_title.text() + self.soi.description = self.edit_description.text() + self.soi.version = self.edit_version.text() + self.soi.date = self.edit_date.text() + self.soi.valid_from = self.edit_valid_from.text() + self.soi.valid_to = self.edit_valid_to.text() + self.soi.classification = ( + self.edit_classification.currentText().lower() + ) + + # find which radiobutton that is checked + if self.rbutton_landscape.isChecked(): + self.soi.orientation = "landscape" + else: + self.soi.orientation = "portrait" + + if self.rbutton_auto.isChecked(): + self.soi.placement_strategy = "auto" + else: + self.soi.placement_strategy = "manual" + + # loop through groupbox to find checked radiobuttons + for i in self.group_algorithm_bin.findChildren(QRadioButton): + if i.isChecked(): + self.soi.algorithm_bin = i.text() + break + + for i in self.group_algorithm_pack.findChildren(QRadioButton): + if i.isChecked(): + self.soi.algorithm_pack = i.text() + break + + for i in self.group_algorithm_sort.findChildren(QRadioButton): + if i.isChecked(): + self.soi.algorithm_sort = i.text() + break + + self.accept() + + def get_from_soi(self): + """Get data from the SOI and update the dialog with the data.""" + self.edit_title.setText(self.soi.title) + self.edit_description.setText(self.soi.description) + self.edit_version.setText(self.soi.version) + self.edit_date.setText(self.soi.date) + self.edit_valid_from.setText(self.soi.valid_from) + self.edit_valid_to.setText(self.soi.valid_to) + self.edit_classification.setCurrentText( + self.soi.classification.upper() + ) + + # check radiobuttons according to current SOI settings + if self.soi.orientation == "landscape": + self.rbutton_landscape.setChecked(True) + else: + self.rbutton_portrait.setChecked(True) + + if self.soi.placement_strategy == "auto": + self.rbutton_auto.setChecked(True) + else: + self.rbutton_manual.setChecked(True) + + # loops through the groupbox to find children that are radiobuttons + for i in self.group_algorithm_bin.findChildren(QRadioButton): + if i.text() == self.soi.algorithm_bin: + i.setChecked(True) + break + + for i in self.group_algorithm_pack.findChildren(QRadioButton): + if i.text() == self.soi.algorithm_pack: + i.setChecked(True) + break + + for i in self.group_algorithm_sort.findChildren(QRadioButton): + if i.text() == self.soi.algorithm_sort: + i.setChecked(True) + break diff --git a/soitool/soi_workspace_widget.py b/soitool/soi_workspace_widget.py index be9e027449e2a1a8bdf198bcea96a3390415ab58..97168ff0ac808d15c45614f17c6acf8d8a61d392 100644 --- a/soitool/soi_workspace_widget.py +++ b/soitool/soi_workspace_widget.py @@ -11,6 +11,7 @@ from PySide2.QtWidgets import ( QLabel, QDialog, ) +from PySide2 import QtCore from soitool.soi import SOI, ModuleType, ModuleNameTaken from soitool.module_list import ModuleList from soitool.inline_editable_soi_view import InlineEditableSOIView @@ -37,6 +38,8 @@ class SOIWorkspaceWidget(QWidget): else: self.soi = soi + self.popup = Setup(self.soi) + self.layout_wrapper = QHBoxLayout() self.layout_sidebar = QVBoxLayout() @@ -45,6 +48,7 @@ class SOIWorkspaceWidget(QWidget): self.button_new_module.setShortcut("Ctrl+m") self.button_new_module.setStatusTip("Legg til en ny modul") self.button_setup = QPushButton("Oppsett") + self.button_setup.setStatusTip("Endre oppsett på SOI") self.list_modules = ModuleList(ModuleType.MAIN_MODULE, self) self.list_attachments = ModuleList(ModuleType.ATTACHMENT_MODULE, self) @@ -52,7 +56,7 @@ class SOIWorkspaceWidget(QWidget): self.view = InlineEditableSOIView(self.soi) self.widget_sidebar = QWidget() self.widget_sidebar.setFixedWidth(200) - self.popup = Setup() + self.popup.setWindowTitle("Oppsett") # build layouts self.layout_sidebar.addWidget(QLabel("Moduler:")) @@ -72,13 +76,18 @@ class SOIWorkspaceWidget(QWidget): def open_setup(self): """Open setup_settings.""" - self.popup.setGeometry(150, 150, 200, 200) - self.popup.exec() # exec = modal dialog, show = modeless dialog + self.popup.resize(300, 300) + self.popup.setWindowFlag(QtCore.Qt.WindowContextHelpButtonHint, False) + self.popup.get_from_soi() + self.popup.exec() def new_module(self): """Add new module to SOI using new_module dialog.""" new_module_dialog = NewModuleDialog() new_module_dialog.resize(350, 350) + new_module_dialog.setWindowFlag( + QtCore.Qt.WindowContextHelpButtonHint, False + ) dialogcode = new_module_dialog.exec() if dialogcode == QDialog.DialogCode.Accepted: diff --git a/test/test_codebook_to_pdf.py b/test/test_codebook_to_pdf.py index 155d8feaa12a33fab34e56c6f825ad878db7466f..ca6bd30f45a18b5ec5fd505b010b6c0d08345684 100644 --- a/test/test_codebook_to_pdf.py +++ b/test/test_codebook_to_pdf.py @@ -4,6 +4,11 @@ import os from pathlib import Path from datetime import datetime from soitool import codebook_to_pdf +from soitool.database import Database + +TESTDBNAME = "testDatabase" +SOITOOL_DIR = Path(__file__).parent.parent / "soitool" +TESTDBPATH = os.path.join(SOITOOL_DIR, TESTDBNAME) SOITOOL_ROOT_PATH = Path(__file__).parent.parent @@ -28,20 +33,23 @@ class ExportTest(unittest.TestCase): def test_generate_codebook_pdf(self): """Test generated PDF-file exist.""" + database = Database(TESTDBPATH) + # Test full codebook (default) - codebook_to_pdf.generate_codebook_pdf() + codebook_to_pdf.generate_codebook_pdf(database=database) file_name = codebook_to_pdf.generate_filename(small=False) file_path_full = os.path.join(SOITOOL_ROOT_PATH, file_name) # Assert file exists self.assertTrue(os.path.exists(file_path_full)) # Test small codebook - codebook_to_pdf.generate_codebook_pdf(small=True) + codebook_to_pdf.generate_codebook_pdf(database=database, small=True) file_name = codebook_to_pdf.generate_filename(small=True) file_path_small = os.path.join(SOITOOL_ROOT_PATH, file_name) # Assert file exists self.assertTrue(os.path.exists(file_path_small)) - # Delete files + # Delete generated files os.remove(file_path_full) os.remove(file_path_small) + os.remove(TESTDBPATH) diff --git a/test/test_database.py b/test/test_database.py index 5f020b5e963d622c02d68b6088a9cf1673035257..c9a6598e63977ff4e3fa145ee2a00d63e4757cb9 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -8,6 +8,10 @@ from datetime import datetime from soitool.database import Database from soitool.coder import get_code_length_needed +TESTDBNAME = "testDatabase" +SOITOOL_DIR = Path(__file__).parent.parent / "soitool" +TESTDBPATH = os.path.join(SOITOOL_DIR, TESTDBNAME) + TESTDATA_PATH = Path(__file__).parent.parent / "soitool/testdata" @@ -16,7 +20,8 @@ class DatabaseTest(unittest.TestCase): def setUp(self): """Connect to/create database.""" - self.database = Database() + self.database = Database(db_path=TESTDBPATH) + self.addCleanup(self.delete_db) def test_connection(self): """Assert connection is not None.""" @@ -288,6 +293,12 @@ class DatabaseTest(unittest.TestCase): ] self.assertRegex(code, "[A-Z0-9]") + def delete_db(self): + """Delete generated database-file.""" + del self.database + if os.path.exists(TESTDBPATH): + os.remove(TESTDBPATH) + if __name__ == "__main__": unittest.main() diff --git a/test/test_main_window.py b/test/test_main_window.py index 894f10cfe69f9b803ad1bb558db9d559f5ed1de8..dc6691d86bf8df1c21785ac7c09601378e6ebc62 100644 --- a/test/test_main_window.py +++ b/test/test_main_window.py @@ -1,6 +1,7 @@ """Test main_window.py.""" - +import os import unittest +from test.test_database import TESTDBPATH from PySide2 import QtWidgets, QtGui from soitool import main_window @@ -15,7 +16,8 @@ class TestMainWindow(unittest.TestCase): def setUp(self): """Set up main_window_widget for testing.""" - self.test_mw = main_window.MainWindow() + self.test_mw = main_window.MainWindow(db_path=TESTDBPATH) + self.addCleanup(self.delete_db) def test_window_title(self): """Test window title is correct.""" @@ -30,6 +32,13 @@ class TestMainWindow(unittest.TestCase): actual = self.test_mw.tabs.currentWidget().button_new_module.text() self.assertEqual(expected, actual) + def delete_db(self): + """Delete generated 'testDatabase'-file.""" + del self.test_mw.timer + del self.test_mw + if os.path.exists(TESTDBPATH): + os.remove(TESTDBPATH) + if __name__ == "__main__": unittest.main()