diff --git a/soitool/main_window.py b/soitool/main_window.py
index 7ce14b1bf0b89e6ec5258e4944687042a4d5595c..38759e20a72f31092e4f857794a4705783c5045e 100644
--- a/soitool/main_window.py
+++ b/soitool/main_window.py
@@ -317,7 +317,7 @@ class MainWindow(QMainWindow):
             soi = import_soi(file_path)
 
             # Create and select tab
-            tab = SOIWorkspaceWidget(soi)
+            tab = SOIWorkspaceWidget(self.database, soi)
             self.tabs.addTab(tab, soi.title)
             self.tabs.setCurrentWidget(tab)
 
diff --git a/soitool/modules/module_predefined_codes.py b/soitool/modules/module_predefined_codes.py
index cd509db2e4be803dd3d9ef47801375dc6c147e4a..3d27b0fabd37da2b578fda75dfa46e0121a5c6b3 100644
--- a/soitool/modules/module_predefined_codes.py
+++ b/soitool/modules/module_predefined_codes.py
@@ -1,5 +1,6 @@
-"""..."""
+"""SOI-module 'Forhåndsavtalte koder'."""
 import string
+from random import sample
 from PySide2.QtWidgets import (
     QWidget,
     QTableWidget,
@@ -8,12 +9,21 @@ from PySide2.QtWidgets import (
     QVBoxLayout,
     QLabel,
     QLineEdit,
+    QDialog,
+    QListWidget,
+    QListWidgetItem,
+    QAbstractItemView,
+    QFormLayout,
+    QPushButton,
+    QSpinBox,
 )
 from PySide2 import QtGui
 from PySide2.QtCore import Qt
 from soitool.modules.module_base import ModuleBase, HEADLINE_FONT, resize_table
+from soitool.dialog_wrappers import exec_critical_dialog
 
 ALPHABET = string.ascii_uppercase
+DEFAULT_HEADLINE = "FORHÅNDSAVTALTE KODER"
 
 
 class Meta(type(ModuleBase), type(QWidget)):
@@ -21,106 +31,178 @@ class Meta(type(ModuleBase), type(QWidget)):
 
 
 class PredefinedCodesModule(ModuleBase, QWidget, metaclass=Meta):
-    """..."""
+    """QWidget representing SOI-module 'Forhåndsavtalte koder'.
 
-    def __init__(self, size=None, data=None, database=None):
-        self.type = "PredefinedCodesModule"
-        QWidget.__init__(self)
+    This widget has a headline and a layout with x amount of
+    PredefinedCodesTable-objects.
 
-        if size is None and data is None:
-            # module_headline = QLabel("FORHÅNDSAVTALTE KODER")
-            self.module_headline = QLineEdit("FORHÅNDSAVTALTE KODER")
-            data = self.get_data_from_database(database)
-            self.create_tables(data)
-            self.create_and_set_layout()
-        else:
-            self.generate_from_data(data)
-            self.setFixedSize(size["width"], size["height"])
+    It is initialized using only one of it's
+    parameters:
 
-        self.resize_module_headline()
-        self.module_headline.setFont(HEADLINE_FONT)
-        self.module_headline.setAlignment(Qt.AlignCenter)
-        self.module_headline.textChanged.connect(self.resize_module_headline)
+    If only parameter 'database' is given, the widget reads from
+    database-table 'Codebook' all expressions where column 'Type'='Liten'.
+    It then creates one PredefinedCodesTable per category and inserts all
+    expressions in the category.
 
-    def get_data_from_database(self, database):
-        """..."""
-        stmt = "SELECT Category FROM Codebook WHERE Type='Liten' GROUP BY Category"
+    If only parameter 'data' is given, the widget creates
+    PredefinedCodesTables based on 'data'.
+    'data' is a dict: {"module_headline": string, "tables": list}, where
+    "tables": [{"table_headline": string, "expressions": list of strings}]
 
-        queried = database.conn.execute(stmt).fetchall()
-        categories = [row["Category"] for row in queried]
+    The widget does not use more room than needed, and resizes dynamically.
 
-        data = []
-        for category in categories:
+    Raises
+    ------
+    ValueError
+        If none or both parameters are given.
+    """
 
-            stmt = (
-                "SELECT Word FROM Codebook WHERE Category=? AND Type='Liten'"
-            )
-            queried = database.conn.execute(stmt, (category,)).fetchall()
-            expressions = [row["Word"] for row in queried]
+    def __init__(self, database=None, data=None):
+        self.type = "PredefinedCodesModule"
+        QWidget.__init__(self)
+        ModuleBase.__init__(self)
+
+        if database is not None and data is None:
+            warning_word = get_warning_word(database)
 
-            data.append(
-                {"Category": category, "Expressions": expressions,}
+            categories_unsorted = get_categories(database)
+            dialog = PredefinedCodesSettings(
+                DEFAULT_HEADLINE, warning_word, categories_unsorted
             )
+            dialog.exec_()
 
-        return data
+            self.module_headline = QLabel(dialog.edit_headline.text())
+            self.warning_word = QLabel(dialog.edit_warning_word.text())
+            self.maximum_height = dialog.edit_module_height.value()
 
-    def create_tables(self, data):
-        """..."""
+            categories = []
+            for i in range(dialog.list_category_order.count()):
+                categories.append(dialog.list_category_order.item(i).text())
+
+            expressions = []
+            for category in categories:
+                expressions_in_category = get_expressions_in_category(
+                    database, category
+                )
+                expressions.append(
+                    sample(
+                        expressions_in_category, len(expressions_in_category)
+                    )
+                )
+
+            self.create_tables(categories, expressions)
+
+        elif data is not None and database is None:
+            self.module_headline = QLabel(data["module_headline"])
+            self.warning_word = QLabel(data["warning_word"])
+            self.create_tables_from_data(data)
+        else:
+            raise ValueError(
+                "Exactly one parameter needs to be given: "
+                + "('database' or 'data')."
+            )
+
+        self.create_and_set_layout()
+        self.module_headline.setFont(HEADLINE_FONT)
+        self.module_headline.setAlignment(Qt.AlignCenter)
+        self.warning_word.setFont(HEADLINE_FONT)
+        self.warning_word.setAlignment(Qt.AlignCenter)
+        # resize_text_container(self.module_headline)
+        # resize_text_container(self.warning_word)
+        # self.module_headline.textChanged.connect(
+        #    lambda: resize_text_container(self.module_headline)
+        # )
+        # self.warning_word.textChanged.connect(
+        #    lambda: resize_text_container(self.warning_word)
+        # )
+
+    def create_tables(self, categories, expressions):
+        """Create PredefinedCodesTable-objects."""
         self.tables = []
 
-        for i, element in enumerate(data):
-            category = element["Category"]
-            expressions = element["Expressions"]
-            headline = ALPHABET[i] + ": " + category
-            table = PredefinedCodesTable(headline, expressions)
+        for i, category in enumerate(categories):
+            headline = " " + ALPHABET[i] + "   " + category
+            table = PredefinedCodesTable(headline, expressions[i])
 
             self.tables.append(table)
 
+    def create_tables_from_data(self, data):
+        """Create PredefinedCodesTable-objects from data."""
+        self.tables = []
+
+        for table_data in data["tables"]:
+            table_headline = table_data["table_headline"]
+            expressions = table_data["expressions"]
+            table = PredefinedCodesTable(table_headline, expressions)
+            self.tables.append(table)
+
     def create_and_set_layout(self):
-        """..."""
-        table_layout = QHBoxLayout()
+        """Create, fill and set layout."""
+        vbox_layouts = []
+        i = 0
+        filled_height = 0
+
         for table in self.tables:
-            table_layout.addWidget(table)
-            table_layout.setAlignment(table, Qt.AlignTop)
+            if table.height() > self.maximum_height:
+                exec_critical_dialog(
+                    "Forhåndsavtalte koder kunne ikke lages.",
+                    "Én eller flere tabeller er høyere enn valgt "
+                    + "maksimalhøyde.",
+                )
+                raise ValueError(
+                    "One or more tables are taller than the chosen "
+                    "maximum height: "
+                    "{} > {}".format(table.height(), self.maximum_height)
+                )
+
+        while i < len(self.tables):
+            vbox_layout = QVBoxLayout()
+            while (
+                i < len(self.tables)
+                and filled_height + self.tables[i].height()
+                <= self.maximum_height
+            ):
+                vbox_layout.addWidget(self.tables[i])
+                vbox_layout.setAlignment(self.tables[i], Qt.AlignTop)
+                filled_height += self.tables[i].height()
+                i += 1
+            vbox_layouts.append(vbox_layout)
+            filled_height = 0
+
+        table_layout = QHBoxLayout()
+        for vbox_layout in vbox_layouts:
+            table_layout.addLayout(vbox_layout)
 
         main_layout = QVBoxLayout()
         main_layout.addWidget(self.module_headline)
         main_layout.setAlignment(self.module_headline, Qt.AlignHCenter)
-        main_layout.addLayout(table_layout)
-
-        self.setLayout(main_layout)
 
-    def resize_module_headline(self):
-        """..."""
-        headline = self.module_headline.text()
-
-        headline_width = (
-            QtGui.QFontMetricsF(HEADLINE_FONT).horizontalAdvance(headline) + 5
-        )
-        self.module_headline.setFixedWidth(headline_width)
+        warning_word_layout = QHBoxLayout()
+        warning_word_label = QLabel("Varslingsord: ")
+        warning_word_layout.addWidget(warning_word_label)
+        warning_word_layout.addWidget(self.warning_word)
 
-    def generate_from_data(self, data):
-        """..."""
-        self.module_headline = QLineEdit(data["module_headline"])
-        self.tables = []
-
-        for table_data in data["tables"]:
-            table_headline = table_data["table_headline"]
-            expressions = table_data["expressions"]
-            table = PredefinedCodesTable(table_headline, expressions)
-            self.tables.append(table)
+        main_layout.addLayout(warning_word_layout)
+        main_layout.setAlignment(warning_word_layout, Qt.AlignHCenter)
+        main_layout.addLayout(table_layout)
 
-        self.create_and_set_layout()
+        self.setLayout(main_layout)
 
     def get_size(self):
         """Return size of table."""
         return self.width(), self.height()
 
     def get_data(self):
-        """..."""
+        """Return dict containing all module-data.
+
+        Returns
+        -------
+        Dict
+            With keys 'table_headline': str and "expressions": list of str.
+        """
         tables = []
+
         for table in self.tables:
-            # rows = []
 
             item_headline = table.item(0, 0)
             if item_headline is not None:
@@ -130,10 +212,6 @@ class PredefinedCodesModule(ModuleBase, QWidget, metaclass=Meta):
 
             expressions = []
             for i in range(1, table.rowCount()):
-                # row = []
-                # for j in range(table.columnCount()):
-                # row.append(table.item(i, 1).text())
-                # rows.append(row)
                 expressions.append(table.item(i, 1).text())
 
             table = {
@@ -144,6 +222,7 @@ class PredefinedCodesModule(ModuleBase, QWidget, metaclass=Meta):
 
         data = {
             "module_headline": self.module_headline.text(),
+            "warning_word": self.warning_word.text(),
             "tables": tables,
         }
 
@@ -258,3 +337,136 @@ class PredefinedCodesTable(QTableWidget):
         self.set_codes(selected_row_index)
 
         resize_table(self, columns=False, rows=False, has_headline=True)
+
+
+class PredefinedCodesSettings(QDialog):
+    """..."""
+
+    def __init__(self, headline, warning_word, categories):
+        super().__init__()
+
+        # Hide help-button, disable close-button and set window width
+        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
+        self.setWindowFlag(Qt.WindowCloseButtonHint, False)
+        self.setFixedWidth(350)
+
+        # Headline
+        self.label_headline = QLabel("Overskrift")
+        self.edit_headline = QLineEdit()
+        self.edit_headline.setText(headline)
+
+        # Warning-word
+        self.label_warning_word = QLabel("Varslingsord")
+        self.edit_warning_word = QLineEdit()
+        self.edit_warning_word.setText(warning_word)
+
+        # Module-height
+        self.label_module_height = QLabel("Maksimal modulhøyde")
+        self.edit_module_height = QSpinBox()
+        self.edit_module_height.setRange(50, 1000)
+        self.edit_module_height.setSingleStep(50)
+        self.edit_module_height.setValue(200)
+
+        # Category-order
+        self.label_category_order = QLabel("Kategori-rekkefølge")
+        self.list_category_order = QListWidget()
+        # Enable drag-and-drop
+        self.list_category_order.setDragEnabled(True)
+        self.list_category_order.viewport().setAcceptDrops(True)
+        self.list_category_order.setDragDropMode(
+            QAbstractItemView.InternalMove
+        )
+        # Remove horizontal scrollbar
+        self.list_category_order.setHorizontalScrollBarPolicy(
+            Qt.ScrollBarAlwaysOff
+        )
+        for i, category in enumerate(categories):
+            item = QListWidgetItem(category)
+            item.setFlags(item.flags() ^ Qt.ItemIsEditable)
+            self.list_category_order.insertItem(i, item)
+
+        # Create-button
+        self.button_create = QPushButton("Opprett")
+        self.button_create.clicked.connect(self.accept)
+
+        self.create_and_set_layout()
+
+    def create_and_set_layout(self):
+        """Create layouts, add widgets and set layout."""
+        # Layout for input-widgets
+        self.form_layout = QFormLayout()
+        self.form_layout.addRow(self.label_headline, self.edit_headline)
+        self.form_layout.addRow(
+            self.label_warning_word, self.edit_warning_word
+        )
+        self.form_layout.addRow(
+            self.label_module_height, self.edit_module_height
+        )
+        self.form_layout.addRow(
+            self.label_category_order, self.list_category_order
+        )
+
+        # Layout for create-button
+        self.button_layout = QHBoxLayout()
+        self.button_layout.addWidget(self.button_create)
+
+        # Main layout
+        self.main_layout = QVBoxLayout()
+        self.main_layout.addLayout(self.form_layout)
+        self.main_layout.addLayout(self.button_layout)
+
+        self.setLayout(self.main_layout)
+
+
+def get_warning_word(database):
+    """..."""
+    stmt = "SELECT Word FROM CategoryWords ORDER BY RANDOM() LIMIT 1"
+
+    warning_word = database.conn.execute(stmt).fetchone()[0]
+
+    return warning_word
+
+
+def get_categories(database):
+    """..."""
+    stmt = (
+        "SELECT Category FROM Codebook " "WHERE Type='Liten' GROUP BY Category"
+    )
+    queried = database.conn.execute(stmt).fetchall()
+
+    categories = [row["Category"] for row in queried]
+
+    return categories
+
+
+def get_expressions_in_category(database, category):
+    """Read categories and expressions from database.
+
+    Categories and expressions are from small codebook ('Type'='Liten').
+
+    Parameters
+    ----------
+    database : soitool.database.Database
+        Connection to database.
+
+    Returns
+    -------
+    list
+        Containing dicts
+        with keys 'Category': string and 'Expressions': list of strings.
+    """
+    stmt = "SELECT Word FROM Codebook WHERE Category=? AND Type='Liten'"
+    queried = database.conn.execute(stmt, (category,)).fetchall()
+    expressions = [row["Word"] for row in queried]
+
+    return expressions
+
+
+# def resize_text_container(container):
+#    """Adjust width of a text-widget to fit it's text.""""
+#    headline = container.text()
+#
+#    width = (
+#        QtGui.QFontMetricsF(HEADLINE_FONT).horizontalAdvance(headline) + 5
+#    )
+#    container.setFixedWidth(width)
diff --git a/soitool/serialize_export_import_soi.py b/soitool/serialize_export_import_soi.py
index e1ad84d4cd084775ec407cf808630f9808b92402..3bbb8fb8914db30c18c6a2671cc2e858f38a8284 100644
--- a/soitool/serialize_export_import_soi.py
+++ b/soitool/serialize_export_import_soi.py
@@ -312,7 +312,7 @@ def construct_modules_from_serialized(serialized_modules):
         elif module_type == "PredefinedCodesModule":
             modules.append(
                 {
-                    "widget": PredefinedCodesModule(size, data),
+                    "widget": PredefinedCodesModule(data=data),
                     "meta": module["meta"],
                 }
             )