From 807efb1e10b664c295d5b9a627c39084281eec6d Mon Sep 17 00:00:00 2001
From: Chris PeBenito <cpebenito@tresys.com>
Date: Thu, 31 Mar 2016 11:29:15 -0400
Subject: [PATCH] ApolMainWindow: handle closing the policy

* Close all tabs when closing the policy
* Close the policy if using the "open policy" action and policy load
  succeeds.
* Warn the user the above actions will close analysis tabs
  (if any tabs are open)
* Set analysis widgets to delete on close since widgets are not deleted
  by QTabWidget.clear() or .removeTab()
---
 data/apol.ui                   | 15 +++++++++++---
 setoolsgui/apol/mainwindow.py  | 36 +++++++++++++++++++++++++++++++++-
 setoolsgui/apol/terulequery.py |  4 +++-
 3 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/data/apol.ui b/data/apol.ui
index 7011f74..3cbc27e 100644
--- a/data/apol.ui
+++ b/data/apol.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
+ <class>ApolMainWindow_ui</class>
+ <widget class="QMainWindow" name="ApolMainWindow_ui">
   <property name="geometry">
    <rect>
     <x>0</x>
@@ -68,6 +68,7 @@
      <string>&amp;File</string>
     </property>
     <addaction name="open_policy"/>
+    <addaction name="close_policy_action"/>
     <addaction name="separator"/>
     <addaction name="exit_apol"/>
    </widget>
@@ -204,13 +205,21 @@
     <string>Ctrl+W</string>
    </property>
   </action>
+  <action name="close_policy_action">
+   <property name="text">
+    <string>Close Policy</string>
+   </property>
+   <property name="toolTip">
+    <string>Close the current policy. Closes all analyses too.</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections>
   <connection>
    <sender>exit_apol</sender>
    <signal>triggered()</signal>
-   <receiver>MainWindow</receiver>
+   <receiver>ApolMainWindow_ui</receiver>
    <slot>close()</slot>
    <hints>
     <hint type="sourcelabel">
diff --git a/setoolsgui/apol/mainwindow.py b/setoolsgui/apol/mainwindow.py
index d232461..4e7d822 100644
--- a/setoolsgui/apol/mainwindow.py
+++ b/setoolsgui/apol/mainwindow.py
@@ -85,6 +85,7 @@ class ApolMainWindow(SEToolsWidget, QMainWindow):
 
         # connect signals
         self.open_policy.triggered.connect(self.select_policy)
+        self.close_policy_action.triggered.connect(self.close_policy)
         self.open_permmap.triggered.connect(self.select_permmap)
         self.new_analysis.triggered.connect(self.choose_analysis)
         self.AnalysisTabs.tabCloseRequested.connect(self.close_tab)
@@ -105,10 +106,26 @@ class ApolMainWindow(SEToolsWidget, QMainWindow):
             self.setWindowTitle("apol")
 
     def select_policy(self):
+        old_policy = self._policy
+
+        if old_policy and self.AnalysisTabs.count() > 0:
+            reply = QMessageBox.question(
+                self, "Continue?",
+                "Loading a policy will close all existing analyses.  Continue?",
+                QMessageBox.Yes | QMessageBox.No)
+
+            if reply == QMessageBox.No:
+                return
+
         filename = QFileDialog.getOpenFileName(self, "Open policy file", ".")[0]
         if filename:
             self.load_policy(filename)
 
+        if self._policy != old_policy:
+            # policy loading succeeded, clear any
+            # existing tabs
+            self.AnalysisTabs.clear()
+
     def load_policy(self, filename):
         try:
             self._policy = SELinuxPolicy(filename)
@@ -121,6 +138,20 @@ class ApolMainWindow(SEToolsWidget, QMainWindow):
             if self._permmap:
                 self._permmap.map_policy(self._policy)
 
+    def close_policy(self):
+        if self.AnalysisTabs.count() > 0:
+            reply = QMessageBox.question(
+                self, "Continue?",
+                "Loading a policy will close all existing analyses.  Continue?",
+                QMessageBox.Yes | QMessageBox.No)
+
+            if reply == QMessageBox.No:
+                return
+
+        self.AnalysisTabs.clear()
+        self._policy = None
+        self.update_window_title()
+
     def select_permmap(self):
         filename = QFileDialog.getOpenFileName(self, "Open permission map file", ".")[0]
         if filename:
@@ -159,6 +190,7 @@ class ApolMainWindow(SEToolsWidget, QMainWindow):
         newtab.setObjectName(counted_name)
 
         newanalysis = tabclass(newtab, self._policy, self._permmap)
+        newanalysis.setAttribute(Qt.WA_DeleteOnClose)
 
         # create a vertical layout in the tab, place the analysis ui inside.
         tabLayout = QVBoxLayout()
@@ -180,19 +212,21 @@ class ApolMainWindow(SEToolsWidget, QMainWindow):
             self.tab_editor.setFocus()
 
     def close_active_tab(self):
+        """Close the active tab. This is called from the context menu."""
         index = self.AnalysisTabs.currentIndex()
         if index >= 0:
             self.close_tab(index)
 
     def rename_active_tab(self):
+        """Rename the active tab."""
         index = self.AnalysisTabs.currentIndex()
         if index >= 0:
             self.tab_name_editor(index)
 
     def close_tab(self, index):
+        """Close a tab specified by index."""
         widget = self.AnalysisTabs.widget(index)
         widget.close()
-        widget.deleteLater()
         self.AnalysisTabs.removeTab(index)
 
     def rename_tab(self):
diff --git a/setoolsgui/apol/terulequery.py b/setoolsgui/apol/terulequery.py
index ae71654..3dafddc 100644
--- a/setoolsgui/apol/terulequery.py
+++ b/setoolsgui/apol/terulequery.py
@@ -377,7 +377,9 @@ class TERuleQueryTab(SEToolsWidget, QScrollArea):
 
         # if query is broad, show warning.
         if not any((self.query.source, self.query.target, self.query.tclass, self.query.perms,
-                    self.query.xperms, self.query.default, self.query.boolean)):
+                    self.query.xperms, self.query.default, self.query.boolean)) \
+                and max_results > 1000:
+
             reply = QMessageBox.question(
                 self, "Continue?",
                 "This is a broad query, estimated to return {0} results.  Continue?".