From ddca4536ee66531b7ab508cb0582b733a0560863 Mon Sep 17 00:00:00 2001
From: Chris PeBenito <pebenito@ieee.org>
Date: Sat, 9 Jul 2016 13:22:09 -0400
Subject: [PATCH] apol: Tabs raise exceptions if trying to save while there are
 errors.

Closes #97
Closes #98
---
 setoolsgui/apol/boolquery.py        | 5 +++++
 setoolsgui/apol/boundsquery.py      | 5 +++++
 setoolsgui/apol/categoryquery.py    | 5 +++++
 setoolsgui/apol/commonquery.py      | 5 +++++
 setoolsgui/apol/constraintquery.py  | 5 +++++
 setoolsgui/apol/dta.py              | 5 +++++
 setoolsgui/apol/fsusequery.py       | 5 +++++
 setoolsgui/apol/genfsconquery.py    | 5 +++++
 setoolsgui/apol/infoflow.py         | 5 +++++
 setoolsgui/apol/initsidquery.py     | 5 +++++
 setoolsgui/apol/mlsrulequery.py     | 5 +++++
 setoolsgui/apol/netifconquery.py    | 5 +++++
 setoolsgui/apol/nodeconquery.py     | 5 +++++
 setoolsgui/apol/objclassquery.py    | 5 +++++
 setoolsgui/apol/portconquery.py     | 5 +++++
 setoolsgui/apol/rbacrulequery.py    | 5 +++++
 setoolsgui/apol/rolequery.py        | 5 +++++
 setoolsgui/apol/sensitivityquery.py | 5 +++++
 setoolsgui/apol/terulequery.py      | 5 +++++
 setoolsgui/apol/typeattrquery.py    | 5 +++++
 setoolsgui/apol/typequery.py        | 5 +++++
 setoolsgui/apol/userquery.py        | 5 +++++
 22 files changed, 110 insertions(+)

diff --git a/setoolsgui/apol/boolquery.py b/setoolsgui/apol/boolquery.py
index 34b7cc4..993e4b4 100644
--- a/setoolsgui/apol/boolquery.py
+++ b/setoolsgui/apol/boolquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..boolmodel import BooleanTableModel, boolean_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -139,6 +140,10 @@ class BoolQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "default_any", "default_true", "default_false",
diff --git a/setoolsgui/apol/boundsquery.py b/setoolsgui/apol/boundsquery.py
index 395ddfc..27b7b6f 100644
--- a/setoolsgui/apol/boundsquery.py
+++ b/setoolsgui/apol/boundsquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..boundsmodel import BoundsTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -144,6 +145,10 @@ class BoundsQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "typebounds",
diff --git a/setoolsgui/apol/categoryquery.py b/setoolsgui/apol/categoryquery.py
index fcf47b0..f404c70 100644
--- a/setoolsgui/apol/categoryquery.py
+++ b/setoolsgui/apol/categoryquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..mlsmodel import MLSComponentTableModel, category_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -139,6 +140,10 @@ class CategoryQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"])
         save_lineedits(self, settings, ["name"])
diff --git a/setoolsgui/apol/commonquery.py b/setoolsgui/apol/commonquery.py
index 3c989da..7eaf6bc 100644
--- a/setoolsgui/apol/commonquery.py
+++ b/setoolsgui/apol/commonquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..commonmodel import CommonTableModel, common_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -163,6 +164,10 @@ class CommonQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "perms_equal"])
diff --git a/setoolsgui/apol/constraintquery.py b/setoolsgui/apol/constraintquery.py
index 2d4a68b..d30a64c 100644
--- a/setoolsgui/apol/constraintquery.py
+++ b/setoolsgui/apol/constraintquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import PermListModel, SEToolsListModel, invert_list_selection
 from ..constraintmodel import ConstraintTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -264,6 +265,10 @@ class ConstraintQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain",
                                          "mlsconstrain", "validatetrans", "mlsvalidatetrans",
diff --git a/setoolsgui/apol/dta.py b/setoolsgui/apol/dta.py
index d77b38f..c331e2a 100644
--- a/setoolsgui/apol/dta.py
+++ b/setoolsgui/apol/dta.py
@@ -28,6 +28,7 @@ from setools import DomainTransitionAnalysis
 from ..logtosignal import LogHandlerToSignal
 from .analysistab import AnalysisTab
 from .excludetypes import ExcludeTypes
+from .exception import TabFieldError
 from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_spinboxes, save_lineedits, save_textedits
 
@@ -202,6 +203,10 @@ class DomainTransitionAnalysisTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths",
                                          "all_shortest_paths", "flows_in", "flows_out", "reverse"])
diff --git a/setoolsgui/apol/fsusequery.py b/setoolsgui/apol/fsusequery.py
index c30fe76..7613276 100644
--- a/setoolsgui/apol/fsusequery.py
+++ b/setoolsgui/apol/fsusequery.py
@@ -27,6 +27,7 @@ from setools import FSUseQuery
 from ..logtosignal import LogHandlerToSignal
 from ..fsusemodel import FSUseTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -257,6 +258,10 @@ class FSUseQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task",
diff --git a/setoolsgui/apol/genfsconquery.py b/setoolsgui/apol/genfsconquery.py
index c9dfbe5..4265585 100644
--- a/setoolsgui/apol/genfsconquery.py
+++ b/setoolsgui/apol/genfsconquery.py
@@ -27,6 +27,7 @@ from setools import GenfsconQuery
 from ..logtosignal import LogHandlerToSignal
 from ..genfsconmodel import GenfsconTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -264,6 +265,10 @@ class GenfsconQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "fs_regex", "path_regex",
diff --git a/setoolsgui/apol/infoflow.py b/setoolsgui/apol/infoflow.py
index dde49b4..099dddf 100644
--- a/setoolsgui/apol/infoflow.py
+++ b/setoolsgui/apol/infoflow.py
@@ -30,6 +30,7 @@ from setools.exception import UnmappedClass, UnmappedPermission
 
 from ..logtosignal import LogHandlerToSignal
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .excludetypes import ExcludeTypes
 from .permmapedit import PermissionMapEditor
 from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \
@@ -229,6 +230,10 @@ class InfoFlowAnalysisTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths",
                                          "all_shortest_paths", "flows_in", "flows_out"])
diff --git a/setoolsgui/apol/initsidquery.py b/setoolsgui/apol/initsidquery.py
index ed19eb8..ad0a062 100644
--- a/setoolsgui/apol/initsidquery.py
+++ b/setoolsgui/apol/initsidquery.py
@@ -27,6 +27,7 @@ from setools import InitialSIDQuery
 from ..logtosignal import LogHandlerToSignal
 from ..initsidmodel import InitialSIDTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -241,6 +242,10 @@ class InitialSIDQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "user_regex", "role_regex", "type_regex", "range_exact",
diff --git a/setoolsgui/apol/mlsrulequery.py b/setoolsgui/apol/mlsrulequery.py
index 7619880..2f5490b 100644
--- a/setoolsgui/apol/mlsrulequery.py
+++ b/setoolsgui/apol/mlsrulequery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..mlsrulemodel import MLSRuleTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -212,6 +213,10 @@ class MLSRuleQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "range_transition",
diff --git a/setoolsgui/apol/netifconquery.py b/setoolsgui/apol/netifconquery.py
index 3d75462..c48ceff 100644
--- a/setoolsgui/apol/netifconquery.py
+++ b/setoolsgui/apol/netifconquery.py
@@ -27,6 +27,7 @@ from setools import NetifconQuery
 from ..logtosignal import LogHandlerToSignal
 from ..netifconmodel import NetifconTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -241,6 +242,10 @@ class NetifconQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "user_regex", "role_regex", "type_regex", "range_exact",
diff --git a/setoolsgui/apol/nodeconquery.py b/setoolsgui/apol/nodeconquery.py
index e71e128..301941a 100644
--- a/setoolsgui/apol/nodeconquery.py
+++ b/setoolsgui/apol/nodeconquery.py
@@ -28,6 +28,7 @@ from setools import NodeconQuery
 from ..logtosignal import LogHandlerToSignal
 from ..nodeconmodel import NodeconTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \
                        save_checkboxes, save_lineedits, save_textedits, save_comboboxes
@@ -244,6 +245,10 @@ class NodeconQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "network_exact", "network_overlap",
diff --git a/setoolsgui/apol/objclassquery.py b/setoolsgui/apol/objclassquery.py
index fe4e5b6..25563ec 100644
--- a/setoolsgui/apol/objclassquery.py
+++ b/setoolsgui/apol/objclassquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import PermListModel, SEToolsListModel, invert_list_selection
 from ..objclassmodel import ObjClassTableModel, class_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -174,6 +175,10 @@ class ObjClassQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "perms_equal"])
diff --git a/setoolsgui/apol/portconquery.py b/setoolsgui/apol/portconquery.py
index 28f00fa..3ca18f4 100644
--- a/setoolsgui/apol/portconquery.py
+++ b/setoolsgui/apol/portconquery.py
@@ -27,6 +27,7 @@ from setools import PortconQuery
 from ..logtosignal import LogHandlerToSignal
 from ..portconmodel import PortconTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \
                        save_checkboxes, save_lineedits, save_textedits, save_comboboxes
@@ -248,6 +249,10 @@ class PortconQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "ports_exact",
                                          "ports_overlap", "ports_subset", "ports_superset",
diff --git a/setoolsgui/apol/rbacrulequery.py b/setoolsgui/apol/rbacrulequery.py
index f7698bb..a4d86fc 100644
--- a/setoolsgui/apol/rbacrulequery.py
+++ b/setoolsgui/apol/rbacrulequery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..rbacrulemodel import RBACRuleTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -233,6 +234,10 @@ class RBACRuleQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "allow", "role_transition",
diff --git a/setoolsgui/apol/rolequery.py b/setoolsgui/apol/rolequery.py
index d5f3794..c46b4e9 100644
--- a/setoolsgui/apol/rolequery.py
+++ b/setoolsgui/apol/rolequery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..rolemodel import RoleTableModel, role_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -160,6 +161,10 @@ class RoleQueryTab(AnalysisTab):
     def save(self):
         """Return a dictionary of settings."""
         settings = {}
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "types_any", "types_equal"])
         save_lineedits(self, settings, ["name"])
diff --git a/setoolsgui/apol/sensitivityquery.py b/setoolsgui/apol/sensitivityquery.py
index faffc1d..881b068 100644
--- a/setoolsgui/apol/sensitivityquery.py
+++ b/setoolsgui/apol/sensitivityquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..mlsmodel import MLSComponentTableModel, sensitivity_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_textedits, \
                        save_checkboxes, save_lineedits, save_textedits
@@ -139,6 +140,10 @@ class SensitivityQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"])
         save_lineedits(self, settings, ["name"])
diff --git a/setoolsgui/apol/terulequery.py b/setoolsgui/apol/terulequery.py
index 87fbb1d..7b6fe4e 100644
--- a/setoolsgui/apol/terulequery.py
+++ b/setoolsgui/apol/terulequery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import PermListModel, SEToolsListModel, invert_list_selection
 from ..terulemodel import TERuleTableModel
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -327,6 +328,10 @@ class TERuleQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                          "allow", "allowxperm",
diff --git a/setoolsgui/apol/typeattrquery.py b/setoolsgui/apol/typeattrquery.py
index 031107e..8eae7a2 100644
--- a/setoolsgui/apol/typeattrquery.py
+++ b/setoolsgui/apol/typeattrquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..typeattrmodel import TypeAttributeTableModel, typeattr_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -159,6 +160,10 @@ class TypeAttributeQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "types_any", "types_equal"])
diff --git a/setoolsgui/apol/typequery.py b/setoolsgui/apol/typequery.py
index 0e72587..1588b93 100644
--- a/setoolsgui/apol/typequery.py
+++ b/setoolsgui/apol/typequery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..typemodel import TypeTableModel, type_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -159,6 +160,10 @@ class TypeQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "attrs_any", "attrs_equal", "permissive"])
diff --git a/setoolsgui/apol/userquery.py b/setoolsgui/apol/userquery.py
index 03b9432..f332da3 100644
--- a/setoolsgui/apol/userquery.py
+++ b/setoolsgui/apol/userquery.py
@@ -28,6 +28,7 @@ from ..logtosignal import LogHandlerToSignal
 from ..models import SEToolsListModel, invert_list_selection
 from ..usermodel import UserTableModel, user_detail
 from .analysistab import AnalysisTab
+from .exception import TabFieldError
 from .queryupdater import QueryResultsUpdater
 from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \
                        save_checkboxes, save_lineedits, save_listviews, save_textedits
@@ -208,6 +209,10 @@ class UserQueryTab(AnalysisTab):
     #
     def save(self):
         """Return a dictionary of settings."""
+        if self.errors:
+            raise TabFieldError("Field(s) are in error: {0}".
+                                format(" ".join(o.objectName() for o in self.errors)))
+
         settings = {}
         save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex",
                                          "roles_any", "roles_equal", "level_exact", "level_dom",