Index: src/sas/qtgui/Perspectives/PrInversion/PrInversionPerspective.py
===================================================================
--- src/sas/qtgui/Perspectives/PrInversion/PrInversionPerspective.py	(revision bde1a6b94f658489f375a768964ba8ea946b571c)
+++ src/sas/qtgui/Perspectives/PrInversion/PrInversionPerspective.py	(revision dab3351971756716957029d75b8419fd076c18b0)
@@ -1,2 +1,4 @@
+import sys
+import logging
 import numpy as np
 
@@ -13,5 +15,4 @@
 # pr inversion calculation elements
 from sas.sascalc.pr.invertor import Invertor
-from sas.sasgui.perspectives.pr import pr_thread as pr_thread
 
 
@@ -52,4 +53,7 @@
         # p(r) calculator
         self._calculator = Invertor()
+        self._last_calculator = None
+        self.calc_thread = None
+        self.estimation_thread = None
 
         self.model = QtGui.QStandardItemModel(self)
@@ -100,8 +104,9 @@
         # self.dataList.currentIndexChanged.connect(self.displayChange)
         self.calculateButton.clicked.connect(self._calculation)
-        self.statusButton.clicked.connect(self.status)
         self.helpButton.clicked.connect(self.help)
         self.estimateBgd.toggled.connect(self.toggleBgd)
         self.manualBgd.toggled.connect(self.toggleBgd)
+        self.regConstantSuggestionButton.clicked.connect(self.acceptAlpha)
+        self.noOfTermsSuggestionButton.clicked.connect(self.acceptNoTerms)
         self.explorerButton.clicked.connect(self.openExplorerWindow)
         self.model.itemChanged.connect(self.model_changed)
@@ -151,5 +156,4 @@
         # Main Buttons
         self.mapper.addMapping(self.calculateButton, WIDGETS.W_CALCULATE)
-        self.mapper.addMapping(self.statusButton, WIDGETS.W_STATUS)
         self.mapper.addMapping(self.helpButton, WIDGETS.W_HELP)
 
@@ -203,5 +207,4 @@
         """
         if self._has_data:
-            self.statusButton.setEnabled(True)
             self.explorerButton.setEnabled(True)
             self.calculateButton.setEnabled(True)
@@ -209,5 +212,4 @@
             self.calculateButton.setEnabled(False)
             self.explorerButton.setEnabled(False)
-            self.statusButton.setEnabled(False)
 
     def populateDataComboBox(self, filename):
@@ -219,6 +221,16 @@
         self.dataList.addItem(qt_item)
 
-    ######################################################################
-    # GUI Actions
+    def acceptNoTerms(self):
+        """Send estimated no of terms to input"""
+        self.model.setItem(WIDGETS.W_NO_TERMS, QtGui.QStandardItem(
+            self.noOfTermsSuggestionButton.text()))
+
+    def acceptAlpha(self):
+        """Send estimated alpha to input"""
+        self.model.setItem(WIDGETS.W_REGULARIZATION, QtGui.QStandardItem(
+            self.regConstantSuggestionButton.text()))
+
+    ######################################################################
+    # GUI Interaction Events
 
     def _calculation(self):
@@ -226,6 +238,8 @@
         Calculate the P(r) for every data set in the data list
         """
-        # TODO: Run the calculations
-        pass
+        # TODO: Set all invertor values before calculation
+        self._calculator.__setattr__("qmin", UI.TabbedPrInversionUI._fromUtf8(
+            self.minQInput.text()))
+        self.startThread()
 
     def model_changed(self):
@@ -235,11 +249,4 @@
         self.mapper.toFirst()
         # TODO: Update plots, etc.
-
-    def status(self):
-        """
-        Show the status of the calculations
-        """
-        # TODO: Status - is this even needed/wanted?
-        pass
 
     def help(self):
@@ -314,13 +321,200 @@
                                QtGui.QStandardItem(str(data_object.x.max())))
 
-            # TODO: Get value estimates
-            no_terms, alpha, _ = self._calculator.estimate_numterms(
-                self._calculator)
-            self.noOfTermsSuggestionButton.setText(
-                QtCore.QString(str(no_terms)))
-            self.noOfTermsSuggestionButton.setEnabled(True)
-            self.regConstantSuggestionButton.setText(QtCore.QString(str(alpha)))
-            self.regConstantSuggestionButton.setEnabled(True)
+            # Estimate initial values from data
+            self.performEstimate()
+
+            # TODO: Plot data on load
 
             # TODO: Only load in the 1st data until batch mode is working
+            # TODO: Thus, the break
             break
+
+    ######################################################################
+    # Thread Creators
+
+    def startThread(self):
+        """
+            Start a calculation thread
+        """
+        from PrThread import CalcPr
+
+        # If a thread is already started, stop it
+        if self.calc_thread is not None and self.calc_thread.isrunning():
+            self.calc_thread.stop()
+        pr = self._calculator.clone()
+        nfunc = int(UI.TabbedPrInversionUI._fromUtf8(
+            self.noOfTermsInput.text()))
+        self.calc_thread = CalcPr(pr, nfunc,
+                                  error_func=self._threadError,
+                                  completefn=self._completed, updatefn=None)
+        self.calc_thread.queue()
+        self.calc_thread.ready(2.5)
+
+    def performEstimateNT(self):
+        """
+            Perform parameter estimation
+        """
+        from PrThread import EstimateNT
+
+        # If a thread is already started, stop it
+        if (self.estimation_thread is not None and
+                self.estimation_thread.isrunning()):
+            self.estimation_thread.stop()
+        pr = self._calculator.clone()
+        # Skip the slit settings for the estimation
+        # It slows down the application and it doesn't change the estimates
+        pr.slit_height = 0.0
+        pr.slit_width = 0.0
+        nfunc = int(UI.TabbedPrInversionUI._fromUtf8(
+            self.noOfTermsInput.text()))
+        self.estimation_thread = EstimateNT(pr, nfunc,
+                                            error_func=self._threadError,
+                                            completefn=self._estimateNTCompleted,
+                                            updatefn=None)
+        self.estimation_thread.queue()
+        self.estimation_thread.ready(2.5)
+
+    def performEstimate(self):
+        """
+            Perform parameter estimation
+        """
+        from PrThread import EstimatePr
+
+        # If a thread is already started, stop it
+        if (self.estimation_thread is not None and
+                self.estimation_thread.isrunning()):
+            self.estimation_thread.stop()
+        pr = self._calculator.clone()
+        nfunc = int(UI.TabbedPrInversionUI._fromUtf8(
+            self.noOfTermsInput.text()))
+        self.estimation_thread = EstimatePr(pr, nfunc,
+                                            error_func=self._threadError,
+                                            completefn=self._estimateCompleted,
+                                            updatefn=None)
+        self.estimation_thread.queue()
+        self.estimation_thread.ready(2.5)
+
+    ######################################################################
+    # Thread Complete
+
+    def _estimateCompleted(self, alpha, message, elapsed):
+        """
+        Parameter estimation completed,
+        display the results to the user
+
+        :param alpha: estimated best alpha
+        :param elapsed: computation time
+        """
+        # Save useful info
+        self.model.setItem(WIDGETS.W_COMP_TIME,
+                           QtGui.QStandardItem(str(elapsed)))
+        self.regConstantSuggestionButton.setText(QtCore.QString(str(alpha)))
+        self.regConstantSuggestionButton.setEnabled(True)
+        if message is not None:
+            logging.info(message)
+        self.performEstimateNT()
+
+    def _estimateNTCompleted(self, nterms, alpha, message, elapsed):
+        """
+        Parameter estimation completed,
+        display the results to the user
+
+        :param alpha: estimated best alpha
+        :param nterms: estimated number of terms
+        :param elapsed: computation time
+
+        """
+        # Save useful info
+        self.noOfTermsSuggestionButton.setText(QtCore.QString(str(nterms)))
+        self.noOfTermsSuggestionButton.setEnabled(True)
+        self.regConstantSuggestionButton.setText(QtCore.QString(str(alpha)))
+        self.regConstantSuggestionButton.setEnabled(True)
+        self.model.setItem(WIDGETS.W_COMP_TIME,
+                           QtGui.QStandardItem(str(elapsed)))
+        if message is not None:
+            logging.info(message)
+            pass
+
+    def _completed(self, out, cov, pr, elapsed):
+        """
+        Method called with the results when the inversion is done
+
+        :param out: output coefficient for the base functions
+        :param cov: covariance matrix
+        :param pr: Invertor instance
+        :param elapsed: time spent computing
+
+        """
+        # Save useful info
+        # Keep a copy of the last result
+        self._last_calculator = pr.clone()
+
+        # TODO: Append to data dictionary
+        # self._data_list.append({s})
+
+        # Save Pr invertor
+        self._calculator = pr
+        cov = np.ascontiguousarray(cov)
+
+        # Show result on control panel
+
+        self.model.setItem(WIDGETS.W_RG, QtGui.QStandardItem(str(pr.rg(out))))
+        self.model.setItem(WIDGETS.W_I_ZERO,
+                           QtGui.QStandardItem(str(pr.iq0(out))))
+        self.model.setItem(WIDGETS.W_BACKGROUND_INPUT,
+                           QtGui.QStandardItem("{:.2g}".format(pr.background)))
+        self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT,
+                           QtGui.QStandardItem(str(pr.background)))
+        self.model.setItem(WIDGETS.W_CHI_SQUARED,
+                           QtGui.QStandardItem(str(pr.chi2)))
+        self.model.setItem(WIDGETS.W_COMP_TIME,
+                           QtGui.QStandardItem(str(elapsed)))
+        self.model.setItem(WIDGETS.W_OSCILLATION,
+                           QtGui.QStandardItem(str(pr.oscillations(out))))
+        self.model.setItem(WIDGETS.W_POS_FRACTION,
+                           QtGui.QStandardItem(str(pr.get_positive(out))))
+        self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION,
+                           QtGui.QStandardItem(str(pr.get_pos_err(out, cov))))
+
+        # TODO: Show plots
+        # Show I(q) fit
+        # self.show_iq(out, self._calculator)
+        # Show P(r) fit
+        # self.show_pr(out, self._calculator, cov)
+
+    def _threadError(self, error):
+        """
+            Call-back method for calculation errors
+        """
+        logging.warning(error)
+
+    def show_data(self, path=None, data=None, reset=False):
+        """
+        Show data read from a file
+
+        :param path: file path
+        :param reset: if True all other plottables will be cleared
+
+        """
+        if data is not None:
+            try:
+                pr = self._create_file_pr(data)
+            except:
+                status = "Problem reading data: %s" % sys.exc_value
+                raise RuntimeError, status
+
+            # If the file contains nothing, just return
+            if pr is None:
+                raise RuntimeError, "Loaded data is invalid"
+
+            self._calculator = pr
+
+        # Make a plot of I(q) data
+        if self._calculator.err is None:
+            logging.log(self._calculator.err)
+        else:
+            # TODO: Do something
+            pass
+        # Get Q range
+        #self.control_panel.q_min = min(self._calculator.x)
+        #self.control_panel.q_max = max(self._calculator.x)
