Module soitool.main_window
Inclues the main window of our application.
Built up by widgets implemented in other modules.
Expand source code
"""Inclues the main window of our application.
Built up by widgets implemented in other modules.
"""
import sys
import os
from enum import Enum
from PySide2.QtWidgets import (
QTabWidget,
QMainWindow,
QApplication,
QAction,
QFileDialog,
QDialog,
)
from PySide2.QtGui import QIcon
from PySide2.QtCore import QTimer
from soitool.soi import SOI
from soitool.soi_workspace_widget import SOIWorkspaceWidget
from soitool.codebook_to_pdf import generate_codebook_pdf
from soitool.dialog_wrappers import exec_info_dialog
from soitool.codebook_widget import CodebookWidget
from soitool.codebook_model_view import CodebookTableModel
from soitool.soi_db_widget import SOIDbWidget
from soitool.soi_model_view import SOITableModel
from soitool.database import Database, DBPATH
from soitool.help_actions import ShortcutsHelpDialog, BasicUsageHelpDialog
from soitool.pdf_export_options_dialog import PdfExportOptionsDialog
from soitool.serialize_export_import_soi import (
export_soi,
import_soi,
)
class ExportMedium(Enum):
"""Enumerate with mediums possible for export."""
COMPRESSED = 0
UNCOMPRESSED = 1
PDF = 2
class MainWindow(QMainWindow):
"""MainWindow, shell of the entire application.
Parameter 'db_path' is the path to an existing or future database-file.
"""
def __init__(self, db_path=DBPATH): # pylint: disable = R0914, R0915
super().__init__()
self.setGeometry(100, 100, 800, 800)
self.setWindowTitle("SOI-tool")
self.statusBar()
self.popup_shortcut_help = ShortcutsHelpDialog()
self.popup_basic_use_help = BasicUsageHelpDialog()
# Database instance
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(
self.database.seconds_to_next_update(60 * 60 * 24) * 1000
)
self.timer.timeout.connect(lambda: self.regenerate_codes(auto=True))
self.timer.start()
self.setup_menubar()
# Add tab-widget with closeable tabs
self.tabs = QTabWidget()
self.tabs.setTabsClosable(True)
self.tabs.tabCloseRequested.connect(
lambda index: self.close_tab(index) # pylint: disable=W0108
)
self.setCentralWidget(self.tabs)
# Add HV logo
filename = "media/HVlogo.PNG"
dirname = os.path.dirname(__file__)
filepath = os.path.join(dirname, filename)
self.setWindowIcon(QIcon(filepath))
self.action_shortcut_help.triggered.connect(self.open_shortcut_help)
self.action_basic_use_help.triggered.connect(self.open_basic_use_help)
# Add SOIWorkspaceWidget-tab
self.open_soi_workspace_tab()
# pylint: disable=R0914, R0915
# Ignoring "Too many local variables" and "Too many statements"
def setup_menubar(self):
"""Set up menubar with submenus and actions."""
menu = self.menuBar()
file_menu = menu.addMenu("SOI")
codebook_menu = menu.addMenu("Kodebok")
help_menu = menu.addMenu("Hjelp")
# New SOI
new_soi = QAction("Ny", self)
new_soi.setShortcut("Ctrl+n")
new_soi.setStatusTip("Opprett en ny SOI")
file_menu.addAction(new_soi)
new_soi.triggered.connect(self.open_soi_workspace_tab)
# Open file
open_file = QAction("Åpne fra fil", self)
open_file.setShortcut("Ctrl+o")
open_file.setStatusTip("Åpne en SOI fra fil")
open_file.triggered.connect(self.import_soi)
file_menu.addAction(open_file)
# Open file from DB
open_file_db = QAction("Åpne fra database", self)
open_file_db.setShortcut("Ctrl+d")
open_file_db.setStatusTip("Åpne en SOI fra databasen")
open_file_db.triggered.connect(self.show_soi_db)
file_menu.addAction(open_file_db)
# Preview SOI
preview_soi = QAction("Forhåndsvis")
preview_soi.setShortcut("Ctrl+p")
preview_soi.setStatusTip("Forhåndsvis SOI som PDF")
file_menu.addAction(preview_soi)
# Save to DB
save_soi = QAction("Lagre i database", self)
save_soi.setShortcut("Ctrl+s")
save_soi.setStatusTip("Lagre SOI i databasen")
save_soi.triggered.connect(self.save_soi_db)
file_menu.addAction(save_soi)
# Export SOI
export_serialized_soi = file_menu.addMenu("Eksporter")
# Compressed SOI
export_compressed = QAction("Komprimert", self)
export_compressed.setShortcut("Ctrl+e")
export_compressed.setStatusTip("Eksporter komprimert SOI")
export_compressed.triggered.connect(
lambda: self.try_export_soi(medium=ExportMedium.COMPRESSED)
)
# Uncompressed SOI
export_uncompressed = QAction("Ukomprimert", self)
export_uncompressed.setStatusTip("Eksporter ukomprimert SOI")
export_uncompressed.triggered.connect(
lambda: self.try_export_soi(medium=ExportMedium.UNCOMPRESSED)
)
# SOI PDF
export_pdf = QAction("PDF", self)
export_pdf.setStatusTip("Eksporter til PDF klar for utskrift")
export_pdf.setShortcut("Ctrl+p")
export_pdf.triggered.connect(
lambda: self.try_export_soi(medium=ExportMedium.PDF)
)
export_serialized_soi.addAction(export_compressed)
export_serialized_soi.addAction(export_uncompressed)
export_serialized_soi.addAction(export_pdf)
file_menu.addMenu(export_serialized_soi)
# View/edit Codebook
codebook = QAction("Se/rediger kodebok", self)
codebook.setStatusTip("Se/rediger kodebok")
codebook.triggered.connect(self.open_codebook_tab)
codebook_menu.addAction(codebook)
# Regenerate codebook-codes:
regenerate_codes = QAction("Nye koder i kodebok", self)
regenerate_codes.setStatusTip("Nye koder lages tilfeldig")
regenerate_codes.triggered.connect(self.regenerate_codes)
codebook_menu.addAction(regenerate_codes)
# Export codebook as PDF
export_codebook = codebook_menu.addMenu("Eksporter")
# Export full codebook
export_codebook_full = QAction("Stor kodebok", self)
export_codebook_full.setStatusTip("Eksporter stor kodebok som PDF")
export_codebook_full.triggered.connect(
lambda: 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(
lambda: generate_codebook_pdf(database=self.database, small=True)
)
export_codebook.addAction(export_codebook_small)
# Hot keys
self.action_shortcut_help = QAction("Hurtigtaster", self)
self.action_shortcut_help.setStatusTip(
"Vis oversikt over hurtigtaster"
)
help_menu.addAction(self.action_shortcut_help)
# Easy use
self.action_basic_use_help = QAction("Enkel bruk", self)
self.action_basic_use_help.setStatusTip(
"Vis enkel bruk av programvaren"
)
help_menu.addAction(self.action_basic_use_help)
def open_codebook_tab(self):
"""Open tab containing CodebookWidget.
Select codebook-tab if it is already open,
create and select codebook-tab if not open.
"""
# Loop through tabs to look for existing codebook-tab:
for i in range(self.tabs.count()):
if self.tabs.tabText(i) == "Kodebok":
self.tabs.setCurrentIndex(i)
break
# Codebook-tab does not exist, create, add and select tab
else:
tab = CodebookWidget(self.database)
self.tabs.addTab(tab, "Kodebok")
self.tabs.setCurrentWidget(tab)
def open_soi_workspace_tab(self):
"""Open and select tab containing a SOIWorkspaceWidget.
Tab will have newly created SOI.
"""
soi = SOI()
self.add_soi_tab(soi)
def close_tab(self, index):
"""Close tab at given index.
Parameters
----------
index : int
Index of the tab to close.
"""
widget_in_tab = self.tabs.widget(index)
# Close db-connection if tab is a CodebookWidget or SOIDbWidget
if isinstance(widget_in_tab, (CodebookWidget, SOIDbWidget)):
widget_in_tab.view.close_db_connection()
self.tabs.removeTab(index)
def try_export_soi(self, medium=ExportMedium.COMPRESSED):
"""Export the SOI in the current tab.
Feedback is given through a dialog if the current tab does not contain
an SOI (tab is not a SOIWorkspaceWidget).
Parameters
----------
medium : ExportMedium
Which medium to export SOI to. Must be one of the enums in
ExportMedium.
Raises
------
ValueError
If export medium is unknown.
"""
tab_widget = self.tabs.currentWidget()
# If tab contains an SOI
if isinstance(tab_widget, SOIWorkspaceWidget):
if medium == ExportMedium.COMPRESSED:
export_soi(tab_widget.soi, True)
elif medium == ExportMedium.UNCOMPRESSED:
export_soi(tab_widget.soi, False)
elif medium == ExportMedium.PDF:
self.prompt_user_and_produce_pdf()
else:
raise ValueError(f"Unknown medium for export '{medium}'")
else:
exec_info_dialog(
"Valgt tab er ingen SOI-tab",
"Den valgte taben inneholder ingen SOI.\n"
"For å eksportere en SOI må riktig tab velges.",
)
def prompt_user_and_produce_pdf(self):
"""Prompt user for PDF options and produce PDF."""
dialog_pdf_options = PdfExportOptionsDialog()
dialog_code = dialog_pdf_options.exec()
if dialog_code == QDialog.DialogCode.Accepted:
chosen_number_of_copies = (
dialog_pdf_options.spinbox_number_of_copies.value()
)
chosen_resolution = dialog_pdf_options.spinbox_resolution.value()
tab_widget = self.tabs.currentWidget()
tab_widget.view.produce_pdf(
chosen_number_of_copies, chosen_resolution
)
def import_soi(self):
"""Import serialized SOI.
Launches a QFileDialog with a name-filter, where .txt and .json are
accepted file extensions.
A SOIWorkspaceWidget containing the SOI-object is created and opened
in a new tab, which is selected.
"""
# Get file-path from dialog
file_path = QFileDialog().getOpenFileName(
self,
"Åpne SOI",
os.getcwd(),
"Text/JSON-filer (SOI_*.txt SOI_*.json)",
)[0]
if len(file_path) > 0:
soi = import_soi(file_path, self.database)
self.add_soi_tab(soi)
def add_soi_tab(self, soi):
"""Add SOI tab with given SOI.
Parameters
----------
soi : soitool.soi.SOI
SOI to populate tab with.
"""
# Create and select tab
tab = SOIWorkspaceWidget(self.database, soi)
self.tabs.addTab(tab, soi.title)
self.tabs.setCurrentWidget(tab)
# Update tab-title when SOI-title changes
soi.add_update_property_listener(
lambda: self.tabs.setTabText(self.tabs.indexOf(tab), soi.title)
)
def regenerate_codes(self, auto=False):
"""Regenerate codebook-codes and update codebook-tab if open.
Parameters
----------
auto : bool, optional
True if self.timer called this function, by default False.
"""
if auto:
def regenerate():
self.database.update_codebook_auto(self.timer)
else:
def regenerate():
self.database.update_codebook()
for i in range(self.tabs.count()):
if self.tabs.tabText(i) == "Kodebok":
view = self.tabs.widget(i).view
view.setModel(None)
regenerate()
view.setModel(CodebookTableModel())
break
else:
regenerate()
def save_soi_db(self):
"""Save the SOI of the current tab in the database."""
tab_widget = self.tabs.currentWidget()
# If tab contains an SOI
if isinstance(tab_widget, SOIWorkspaceWidget):
# Update tab showing SOI's in db if it is open,
# and pause database-lock by codebook-tab if it is open
soi_db_view = None
codebook_db_view = None
for i in range(self.tabs.count()):
if self.tabs.tabText(i) == "SOI-er i database":
soi_db_view = self.tabs.widget(i).view
soi_db_view.setModel(None)
elif self.tabs.tabText(i) == "Kodebok":
codebook_db_view = self.tabs.widget(i).view
codebook_db_view.setModel(None)
self.database.insert_or_update_soi(tab_widget.soi)
if soi_db_view is not None:
soi_db_view.setModel(SOITableModel())
if codebook_db_view is not None:
codebook_db_view.setModel(CodebookTableModel())
else:
exec_info_dialog(
"Valgt tab er ingen SOI-tab",
"Den valgte taben inneholder ingen SOI.\n"
"Riktig tab må velges for å lagre en SOI i database.",
)
def show_soi_db(self):
"""Open and select tab containing SOIDbWidget.
Select tab if it is already open,
create and select tab if not open.
"""
# Loop through tabs to look for existing SOI-db-tab:
for i in range(self.tabs.count()):
if self.tabs.tabText(i) == "SOI-er i database":
self.tabs.setCurrentIndex(i)
break
# SOI-db-tab does not exist, create, add and select tab
else:
tab = SOIDbWidget(self.database, self.tabs)
self.tabs.addTab(tab, "SOI-er i database")
self.tabs.setCurrentWidget(tab)
def open_shortcut_help(self):
"""Open shortcut dialog."""
self.popup_shortcut_help.setWindowTitle("Hurtigtaster")
self.popup_shortcut_help.exec()
def open_basic_use_help(self):
"""Open basic usage dialog."""
self.popup_basic_use_help.setWindowTitle("Enkel bruk")
self.popup_basic_use_help.exec()
if __name__ == "__main__":
app = QApplication(sys.argv)
WINDOW = MainWindow()
WINDOW.showMaximized()
app.exec_()
Classes
class ExportMedium (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
Enumerate with mediums possible for export.
Expand source code
class ExportMedium(Enum): """Enumerate with mediums possible for export.""" COMPRESSED = 0 UNCOMPRESSED = 1 PDF = 2
Ancestors
- enum.Enum
Class variables
var COMPRESSED
-
Enumerate with mediums possible for export.
var PDF
-
Enumerate with mediums possible for export.
var UNCOMPRESSED
-
Enumerate with mediums possible for export.
class MainWindow (db_path='/builds/bachelor-paa-bittet/soitool/soitool/database')
-
MainWindow, shell of the entire application.
Parameter 'db_path' is the path to an existing or future database-file.
Expand source code
class MainWindow(QMainWindow): """MainWindow, shell of the entire application. Parameter 'db_path' is the path to an existing or future database-file. """ def __init__(self, db_path=DBPATH): # pylint: disable = R0914, R0915 super().__init__() self.setGeometry(100, 100, 800, 800) self.setWindowTitle("SOI-tool") self.statusBar() self.popup_shortcut_help = ShortcutsHelpDialog() self.popup_basic_use_help = BasicUsageHelpDialog() # Database instance 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( self.database.seconds_to_next_update(60 * 60 * 24) * 1000 ) self.timer.timeout.connect(lambda: self.regenerate_codes(auto=True)) self.timer.start() self.setup_menubar() # Add tab-widget with closeable tabs self.tabs = QTabWidget() self.tabs.setTabsClosable(True) self.tabs.tabCloseRequested.connect( lambda index: self.close_tab(index) # pylint: disable=W0108 ) self.setCentralWidget(self.tabs) # Add HV logo filename = "media/HVlogo.PNG" dirname = os.path.dirname(__file__) filepath = os.path.join(dirname, filename) self.setWindowIcon(QIcon(filepath)) self.action_shortcut_help.triggered.connect(self.open_shortcut_help) self.action_basic_use_help.triggered.connect(self.open_basic_use_help) # Add SOIWorkspaceWidget-tab self.open_soi_workspace_tab() # pylint: disable=R0914, R0915 # Ignoring "Too many local variables" and "Too many statements" def setup_menubar(self): """Set up menubar with submenus and actions.""" menu = self.menuBar() file_menu = menu.addMenu("SOI") codebook_menu = menu.addMenu("Kodebok") help_menu = menu.addMenu("Hjelp") # New SOI new_soi = QAction("Ny", self) new_soi.setShortcut("Ctrl+n") new_soi.setStatusTip("Opprett en ny SOI") file_menu.addAction(new_soi) new_soi.triggered.connect(self.open_soi_workspace_tab) # Open file open_file = QAction("Åpne fra fil", self) open_file.setShortcut("Ctrl+o") open_file.setStatusTip("Åpne en SOI fra fil") open_file.triggered.connect(self.import_soi) file_menu.addAction(open_file) # Open file from DB open_file_db = QAction("Åpne fra database", self) open_file_db.setShortcut("Ctrl+d") open_file_db.setStatusTip("Åpne en SOI fra databasen") open_file_db.triggered.connect(self.show_soi_db) file_menu.addAction(open_file_db) # Preview SOI preview_soi = QAction("Forhåndsvis") preview_soi.setShortcut("Ctrl+p") preview_soi.setStatusTip("Forhåndsvis SOI som PDF") file_menu.addAction(preview_soi) # Save to DB save_soi = QAction("Lagre i database", self) save_soi.setShortcut("Ctrl+s") save_soi.setStatusTip("Lagre SOI i databasen") save_soi.triggered.connect(self.save_soi_db) file_menu.addAction(save_soi) # Export SOI export_serialized_soi = file_menu.addMenu("Eksporter") # Compressed SOI export_compressed = QAction("Komprimert", self) export_compressed.setShortcut("Ctrl+e") export_compressed.setStatusTip("Eksporter komprimert SOI") export_compressed.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.COMPRESSED) ) # Uncompressed SOI export_uncompressed = QAction("Ukomprimert", self) export_uncompressed.setStatusTip("Eksporter ukomprimert SOI") export_uncompressed.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.UNCOMPRESSED) ) # SOI PDF export_pdf = QAction("PDF", self) export_pdf.setStatusTip("Eksporter til PDF klar for utskrift") export_pdf.setShortcut("Ctrl+p") export_pdf.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.PDF) ) export_serialized_soi.addAction(export_compressed) export_serialized_soi.addAction(export_uncompressed) export_serialized_soi.addAction(export_pdf) file_menu.addMenu(export_serialized_soi) # View/edit Codebook codebook = QAction("Se/rediger kodebok", self) codebook.setStatusTip("Se/rediger kodebok") codebook.triggered.connect(self.open_codebook_tab) codebook_menu.addAction(codebook) # Regenerate codebook-codes: regenerate_codes = QAction("Nye koder i kodebok", self) regenerate_codes.setStatusTip("Nye koder lages tilfeldig") regenerate_codes.triggered.connect(self.regenerate_codes) codebook_menu.addAction(regenerate_codes) # Export codebook as PDF export_codebook = codebook_menu.addMenu("Eksporter") # Export full codebook export_codebook_full = QAction("Stor kodebok", self) export_codebook_full.setStatusTip("Eksporter stor kodebok som PDF") export_codebook_full.triggered.connect( lambda: 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( lambda: generate_codebook_pdf(database=self.database, small=True) ) export_codebook.addAction(export_codebook_small) # Hot keys self.action_shortcut_help = QAction("Hurtigtaster", self) self.action_shortcut_help.setStatusTip( "Vis oversikt over hurtigtaster" ) help_menu.addAction(self.action_shortcut_help) # Easy use self.action_basic_use_help = QAction("Enkel bruk", self) self.action_basic_use_help.setStatusTip( "Vis enkel bruk av programvaren" ) help_menu.addAction(self.action_basic_use_help) def open_codebook_tab(self): """Open tab containing CodebookWidget. Select codebook-tab if it is already open, create and select codebook-tab if not open. """ # Loop through tabs to look for existing codebook-tab: for i in range(self.tabs.count()): if self.tabs.tabText(i) == "Kodebok": self.tabs.setCurrentIndex(i) break # Codebook-tab does not exist, create, add and select tab else: tab = CodebookWidget(self.database) self.tabs.addTab(tab, "Kodebok") self.tabs.setCurrentWidget(tab) def open_soi_workspace_tab(self): """Open and select tab containing a SOIWorkspaceWidget. Tab will have newly created SOI. """ soi = SOI() self.add_soi_tab(soi) def close_tab(self, index): """Close tab at given index. Parameters ---------- index : int Index of the tab to close. """ widget_in_tab = self.tabs.widget(index) # Close db-connection if tab is a CodebookWidget or SOIDbWidget if isinstance(widget_in_tab, (CodebookWidget, SOIDbWidget)): widget_in_tab.view.close_db_connection() self.tabs.removeTab(index) def try_export_soi(self, medium=ExportMedium.COMPRESSED): """Export the SOI in the current tab. Feedback is given through a dialog if the current tab does not contain an SOI (tab is not a SOIWorkspaceWidget). Parameters ---------- medium : ExportMedium Which medium to export SOI to. Must be one of the enums in ExportMedium. Raises ------ ValueError If export medium is unknown. """ tab_widget = self.tabs.currentWidget() # If tab contains an SOI if isinstance(tab_widget, SOIWorkspaceWidget): if medium == ExportMedium.COMPRESSED: export_soi(tab_widget.soi, True) elif medium == ExportMedium.UNCOMPRESSED: export_soi(tab_widget.soi, False) elif medium == ExportMedium.PDF: self.prompt_user_and_produce_pdf() else: raise ValueError(f"Unknown medium for export '{medium}'") else: exec_info_dialog( "Valgt tab er ingen SOI-tab", "Den valgte taben inneholder ingen SOI.\n" "For å eksportere en SOI må riktig tab velges.", ) def prompt_user_and_produce_pdf(self): """Prompt user for PDF options and produce PDF.""" dialog_pdf_options = PdfExportOptionsDialog() dialog_code = dialog_pdf_options.exec() if dialog_code == QDialog.DialogCode.Accepted: chosen_number_of_copies = ( dialog_pdf_options.spinbox_number_of_copies.value() ) chosen_resolution = dialog_pdf_options.spinbox_resolution.value() tab_widget = self.tabs.currentWidget() tab_widget.view.produce_pdf( chosen_number_of_copies, chosen_resolution ) def import_soi(self): """Import serialized SOI. Launches a QFileDialog with a name-filter, where .txt and .json are accepted file extensions. A SOIWorkspaceWidget containing the SOI-object is created and opened in a new tab, which is selected. """ # Get file-path from dialog file_path = QFileDialog().getOpenFileName( self, "Åpne SOI", os.getcwd(), "Text/JSON-filer (SOI_*.txt SOI_*.json)", )[0] if len(file_path) > 0: soi = import_soi(file_path, self.database) self.add_soi_tab(soi) def add_soi_tab(self, soi): """Add SOI tab with given SOI. Parameters ---------- soi : soitool.soi.SOI SOI to populate tab with. """ # Create and select tab tab = SOIWorkspaceWidget(self.database, soi) self.tabs.addTab(tab, soi.title) self.tabs.setCurrentWidget(tab) # Update tab-title when SOI-title changes soi.add_update_property_listener( lambda: self.tabs.setTabText(self.tabs.indexOf(tab), soi.title) ) def regenerate_codes(self, auto=False): """Regenerate codebook-codes and update codebook-tab if open. Parameters ---------- auto : bool, optional True if self.timer called this function, by default False. """ if auto: def regenerate(): self.database.update_codebook_auto(self.timer) else: def regenerate(): self.database.update_codebook() for i in range(self.tabs.count()): if self.tabs.tabText(i) == "Kodebok": view = self.tabs.widget(i).view view.setModel(None) regenerate() view.setModel(CodebookTableModel()) break else: regenerate() def save_soi_db(self): """Save the SOI of the current tab in the database.""" tab_widget = self.tabs.currentWidget() # If tab contains an SOI if isinstance(tab_widget, SOIWorkspaceWidget): # Update tab showing SOI's in db if it is open, # and pause database-lock by codebook-tab if it is open soi_db_view = None codebook_db_view = None for i in range(self.tabs.count()): if self.tabs.tabText(i) == "SOI-er i database": soi_db_view = self.tabs.widget(i).view soi_db_view.setModel(None) elif self.tabs.tabText(i) == "Kodebok": codebook_db_view = self.tabs.widget(i).view codebook_db_view.setModel(None) self.database.insert_or_update_soi(tab_widget.soi) if soi_db_view is not None: soi_db_view.setModel(SOITableModel()) if codebook_db_view is not None: codebook_db_view.setModel(CodebookTableModel()) else: exec_info_dialog( "Valgt tab er ingen SOI-tab", "Den valgte taben inneholder ingen SOI.\n" "Riktig tab må velges for å lagre en SOI i database.", ) def show_soi_db(self): """Open and select tab containing SOIDbWidget. Select tab if it is already open, create and select tab if not open. """ # Loop through tabs to look for existing SOI-db-tab: for i in range(self.tabs.count()): if self.tabs.tabText(i) == "SOI-er i database": self.tabs.setCurrentIndex(i) break # SOI-db-tab does not exist, create, add and select tab else: tab = SOIDbWidget(self.database, self.tabs) self.tabs.addTab(tab, "SOI-er i database") self.tabs.setCurrentWidget(tab) def open_shortcut_help(self): """Open shortcut dialog.""" self.popup_shortcut_help.setWindowTitle("Hurtigtaster") self.popup_shortcut_help.exec() def open_basic_use_help(self): """Open basic usage dialog.""" self.popup_basic_use_help.setWindowTitle("Enkel bruk") self.popup_basic_use_help.exec()
Ancestors
- PySide2.QtWidgets.QMainWindow
- PySide2.QtWidgets.QWidget
- PySide2.QtCore.QObject
- PySide2.QtGui.QPaintDevice
- Shiboken.Object
Class variables
var staticMetaObject
Methods
def add_soi_tab(self, soi)
-
Add SOI tab with given SOI.
Parameters
soi
:SOI
- SOI to populate tab with.
Expand source code
def add_soi_tab(self, soi): """Add SOI tab with given SOI. Parameters ---------- soi : soitool.soi.SOI SOI to populate tab with. """ # Create and select tab tab = SOIWorkspaceWidget(self.database, soi) self.tabs.addTab(tab, soi.title) self.tabs.setCurrentWidget(tab) # Update tab-title when SOI-title changes soi.add_update_property_listener( lambda: self.tabs.setTabText(self.tabs.indexOf(tab), soi.title) )
def close_tab(self, index)
-
Close tab at given index.
Parameters
index
:int
- Index of the tab to close.
Expand source code
def close_tab(self, index): """Close tab at given index. Parameters ---------- index : int Index of the tab to close. """ widget_in_tab = self.tabs.widget(index) # Close db-connection if tab is a CodebookWidget or SOIDbWidget if isinstance(widget_in_tab, (CodebookWidget, SOIDbWidget)): widget_in_tab.view.close_db_connection() self.tabs.removeTab(index)
def import_soi(self)
-
Import serialized SOI.
Launches a QFileDialog with a name-filter, where .txt and .json are accepted file extensions. A SOIWorkspaceWidget containing the SOI-object is created and opened in a new tab, which is selected.
Expand source code
def import_soi(self): """Import serialized SOI. Launches a QFileDialog with a name-filter, where .txt and .json are accepted file extensions. A SOIWorkspaceWidget containing the SOI-object is created and opened in a new tab, which is selected. """ # Get file-path from dialog file_path = QFileDialog().getOpenFileName( self, "Åpne SOI", os.getcwd(), "Text/JSON-filer (SOI_*.txt SOI_*.json)", )[0] if len(file_path) > 0: soi = import_soi(file_path, self.database) self.add_soi_tab(soi)
def open_basic_use_help(self)
-
Open basic usage dialog.
Expand source code
def open_basic_use_help(self): """Open basic usage dialog.""" self.popup_basic_use_help.setWindowTitle("Enkel bruk") self.popup_basic_use_help.exec()
def open_codebook_tab(self)
-
Open tab containing CodebookWidget.
Select codebook-tab if it is already open, create and select codebook-tab if not open.
Expand source code
def open_codebook_tab(self): """Open tab containing CodebookWidget. Select codebook-tab if it is already open, create and select codebook-tab if not open. """ # Loop through tabs to look for existing codebook-tab: for i in range(self.tabs.count()): if self.tabs.tabText(i) == "Kodebok": self.tabs.setCurrentIndex(i) break # Codebook-tab does not exist, create, add and select tab else: tab = CodebookWidget(self.database) self.tabs.addTab(tab, "Kodebok") self.tabs.setCurrentWidget(tab)
def open_shortcut_help(self)
-
Open shortcut dialog.
Expand source code
def open_shortcut_help(self): """Open shortcut dialog.""" self.popup_shortcut_help.setWindowTitle("Hurtigtaster") self.popup_shortcut_help.exec()
def open_soi_workspace_tab(self)
-
Open and select tab containing a SOIWorkspaceWidget.
Tab will have newly created SOI.
Expand source code
def open_soi_workspace_tab(self): """Open and select tab containing a SOIWorkspaceWidget. Tab will have newly created SOI. """ soi = SOI() self.add_soi_tab(soi)
def prompt_user_and_produce_pdf(self)
-
Prompt user for PDF options and produce PDF.
Expand source code
def prompt_user_and_produce_pdf(self): """Prompt user for PDF options and produce PDF.""" dialog_pdf_options = PdfExportOptionsDialog() dialog_code = dialog_pdf_options.exec() if dialog_code == QDialog.DialogCode.Accepted: chosen_number_of_copies = ( dialog_pdf_options.spinbox_number_of_copies.value() ) chosen_resolution = dialog_pdf_options.spinbox_resolution.value() tab_widget = self.tabs.currentWidget() tab_widget.view.produce_pdf( chosen_number_of_copies, chosen_resolution )
def regenerate_codes(self, auto=False)
-
Regenerate codebook-codes and update codebook-tab if open.
Parameters
auto
:bool
, optional- True if self.timer called this function, by default False.
Expand source code
def regenerate_codes(self, auto=False): """Regenerate codebook-codes and update codebook-tab if open. Parameters ---------- auto : bool, optional True if self.timer called this function, by default False. """ if auto: def regenerate(): self.database.update_codebook_auto(self.timer) else: def regenerate(): self.database.update_codebook() for i in range(self.tabs.count()): if self.tabs.tabText(i) == "Kodebok": view = self.tabs.widget(i).view view.setModel(None) regenerate() view.setModel(CodebookTableModel()) break else: regenerate()
def save_soi_db(self)
-
Save the SOI of the current tab in the database.
Expand source code
def save_soi_db(self): """Save the SOI of the current tab in the database.""" tab_widget = self.tabs.currentWidget() # If tab contains an SOI if isinstance(tab_widget, SOIWorkspaceWidget): # Update tab showing SOI's in db if it is open, # and pause database-lock by codebook-tab if it is open soi_db_view = None codebook_db_view = None for i in range(self.tabs.count()): if self.tabs.tabText(i) == "SOI-er i database": soi_db_view = self.tabs.widget(i).view soi_db_view.setModel(None) elif self.tabs.tabText(i) == "Kodebok": codebook_db_view = self.tabs.widget(i).view codebook_db_view.setModel(None) self.database.insert_or_update_soi(tab_widget.soi) if soi_db_view is not None: soi_db_view.setModel(SOITableModel()) if codebook_db_view is not None: codebook_db_view.setModel(CodebookTableModel()) else: exec_info_dialog( "Valgt tab er ingen SOI-tab", "Den valgte taben inneholder ingen SOI.\n" "Riktig tab må velges for å lagre en SOI i database.", )
-
Set up menubar with submenus and actions.
Expand source code
def setup_menubar(self): """Set up menubar with submenus and actions.""" menu = self.menuBar() file_menu = menu.addMenu("SOI") codebook_menu = menu.addMenu("Kodebok") help_menu = menu.addMenu("Hjelp") # New SOI new_soi = QAction("Ny", self) new_soi.setShortcut("Ctrl+n") new_soi.setStatusTip("Opprett en ny SOI") file_menu.addAction(new_soi) new_soi.triggered.connect(self.open_soi_workspace_tab) # Open file open_file = QAction("Åpne fra fil", self) open_file.setShortcut("Ctrl+o") open_file.setStatusTip("Åpne en SOI fra fil") open_file.triggered.connect(self.import_soi) file_menu.addAction(open_file) # Open file from DB open_file_db = QAction("Åpne fra database", self) open_file_db.setShortcut("Ctrl+d") open_file_db.setStatusTip("Åpne en SOI fra databasen") open_file_db.triggered.connect(self.show_soi_db) file_menu.addAction(open_file_db) # Preview SOI preview_soi = QAction("Forhåndsvis") preview_soi.setShortcut("Ctrl+p") preview_soi.setStatusTip("Forhåndsvis SOI som PDF") file_menu.addAction(preview_soi) # Save to DB save_soi = QAction("Lagre i database", self) save_soi.setShortcut("Ctrl+s") save_soi.setStatusTip("Lagre SOI i databasen") save_soi.triggered.connect(self.save_soi_db) file_menu.addAction(save_soi) # Export SOI export_serialized_soi = file_menu.addMenu("Eksporter") # Compressed SOI export_compressed = QAction("Komprimert", self) export_compressed.setShortcut("Ctrl+e") export_compressed.setStatusTip("Eksporter komprimert SOI") export_compressed.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.COMPRESSED) ) # Uncompressed SOI export_uncompressed = QAction("Ukomprimert", self) export_uncompressed.setStatusTip("Eksporter ukomprimert SOI") export_uncompressed.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.UNCOMPRESSED) ) # SOI PDF export_pdf = QAction("PDF", self) export_pdf.setStatusTip("Eksporter til PDF klar for utskrift") export_pdf.setShortcut("Ctrl+p") export_pdf.triggered.connect( lambda: self.try_export_soi(medium=ExportMedium.PDF) ) export_serialized_soi.addAction(export_compressed) export_serialized_soi.addAction(export_uncompressed) export_serialized_soi.addAction(export_pdf) file_menu.addMenu(export_serialized_soi) # View/edit Codebook codebook = QAction("Se/rediger kodebok", self) codebook.setStatusTip("Se/rediger kodebok") codebook.triggered.connect(self.open_codebook_tab) codebook_menu.addAction(codebook) # Regenerate codebook-codes: regenerate_codes = QAction("Nye koder i kodebok", self) regenerate_codes.setStatusTip("Nye koder lages tilfeldig") regenerate_codes.triggered.connect(self.regenerate_codes) codebook_menu.addAction(regenerate_codes) # Export codebook as PDF export_codebook = codebook_menu.addMenu("Eksporter") # Export full codebook export_codebook_full = QAction("Stor kodebok", self) export_codebook_full.setStatusTip("Eksporter stor kodebok som PDF") export_codebook_full.triggered.connect( lambda: 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( lambda: generate_codebook_pdf(database=self.database, small=True) ) export_codebook.addAction(export_codebook_small) # Hot keys self.action_shortcut_help = QAction("Hurtigtaster", self) self.action_shortcut_help.setStatusTip( "Vis oversikt over hurtigtaster" ) help_menu.addAction(self.action_shortcut_help) # Easy use self.action_basic_use_help = QAction("Enkel bruk", self) self.action_basic_use_help.setStatusTip( "Vis enkel bruk av programvaren" ) help_menu.addAction(self.action_basic_use_help)
def show_soi_db(self)
-
Open and select tab containing SOIDbWidget.
Select tab if it is already open, create and select tab if not open.
Expand source code
def show_soi_db(self): """Open and select tab containing SOIDbWidget. Select tab if it is already open, create and select tab if not open. """ # Loop through tabs to look for existing SOI-db-tab: for i in range(self.tabs.count()): if self.tabs.tabText(i) == "SOI-er i database": self.tabs.setCurrentIndex(i) break # SOI-db-tab does not exist, create, add and select tab else: tab = SOIDbWidget(self.database, self.tabs) self.tabs.addTab(tab, "SOI-er i database") self.tabs.setCurrentWidget(tab)
def try_export_soi(self, medium=ExportMedium.COMPRESSED)
-
Export the SOI in the current tab.
Feedback is given through a dialog if the current tab does not contain an SOI (tab is not a SOIWorkspaceWidget).
Parameters
medium
:ExportMedium
- Which medium to export SOI to. Must be one of the enums in ExportMedium.
Raises
ValueError
- If export medium is unknown.
Expand source code
def try_export_soi(self, medium=ExportMedium.COMPRESSED): """Export the SOI in the current tab. Feedback is given through a dialog if the current tab does not contain an SOI (tab is not a SOIWorkspaceWidget). Parameters ---------- medium : ExportMedium Which medium to export SOI to. Must be one of the enums in ExportMedium. Raises ------ ValueError If export medium is unknown. """ tab_widget = self.tabs.currentWidget() # If tab contains an SOI if isinstance(tab_widget, SOIWorkspaceWidget): if medium == ExportMedium.COMPRESSED: export_soi(tab_widget.soi, True) elif medium == ExportMedium.UNCOMPRESSED: export_soi(tab_widget.soi, False) elif medium == ExportMedium.PDF: self.prompt_user_and_produce_pdf() else: raise ValueError(f"Unknown medium for export '{medium}'") else: exec_info_dialog( "Valgt tab er ingen SOI-tab", "Den valgte taben inneholder ingen SOI.\n" "For å eksportere en SOI må riktig tab velges.", )