Repository: biolab/orange3

Issue:
Neighbors: remove Info box and display data info in status bar
Follow an example where the change of this widget was already reported in [the blog](https://orange.biolab.si/blog/2019/3/8/the-changing-status-bar/). Change the documentation accordingly.

![changing-status-bar](https://user-images.githubusercontent.com/726604/67082844-3a7c6800-f19a-11e9-8ba4-f89c6ed7ab7e.png)



Discussion:
Check SOM widget for an example.

Resolving patch:
diff --git a/Orange/widgets/data/owneighbors.py b/Orange/widgets/data/owneighbors.py
--- a/Orange/widgets/data/owneighbors.py
+++ b/Orange/widgets/data/owneighbors.py
@@ -64,12 +64,6 @@ def __init__(self):
         self.reference = None
         self.distances = None
 
-        box = gui.vBox(self.controlArea, "Info")
-        self.data_info_label = gui.widgetLabel(box, "")
-        self.reference_info_label = gui.widgetLabel(box, "")
-        self._set_label_text("data")
-        self._set_label_text("reference")
-
         box = gui.vBox(self.controlArea, box=True)
         gui.comboBox(
             box, self, "distance_index", orientation=Qt.Horizontal,
@@ -87,29 +81,33 @@ def __init__(self):
             callback=lambda: self.apply())
 
         self.apply_button = gui.auto_apply(self.controlArea, self, commit=self.apply)
-
-    def _set_label_text(self, name):
-        data = getattr(self, name)
-        label = getattr(self, f"{name}_info_label")
-        if data is None:
-            label.setText(f"No {name} instances")
+        self.info.set_input_summary(self.info.NoInput)
+        self.info.set_output_summary(self.info.NoOutput)
+
+    def _set_input_summary(self):
+        n_data = len(self.data) if self.data else 0
+        n_refs = len(self.reference) if self.reference else 0
+
+        if n_data or n_refs:
+            details = \
+                f"{n_data if n_data else 'No'} data instance(s) on input\n" \
+                f"{n_refs if n_refs else 'No'} reference instance(s) on input "
+            self.info.set_input_summary(f"{n_data} | {n_refs} ", details)
         else:
-            pl = "s" if data else ""
-            label.setText(f"{len(data)} {name} instance{pl} on input.")
+            self.info.set_input_summary(self.info.NoInput)
 
     @Inputs.data
     def set_data(self, data):
         self.data = data
-        self._set_label_text("data")
 
     @Inputs.reference
     def set_ref(self, refs):
         self.reference = refs
-        self._set_label_text("reference")
 
     def handleNewSignals(self):
         self.compute_distances()
         self.unconditional_apply()
+        self._set_input_summary()
 
     def recompute(self):
         self.compute_distances()
@@ -141,10 +139,13 @@ def compute_distances(self):
 
     def apply(self):
         indices = self._compute_indices()
+
         if indices is None:
             neighbors = None
+            self.info.set_output_summary(self.info.NoOutput)
         else:
             neighbors = self._data_with_similarity(indices)
+            self.info.set_output_summary(str(len(neighbors)))
         self.Outputs.data.send(neighbors)
 
     def _compute_indices(self):


Test patch:
diff --git a/Orange/widgets/data/tests/test_owneighbors.py b/Orange/widgets/data/tests/test_owneighbors.py
--- a/Orange/widgets/data/tests/test_owneighbors.py
+++ b/Orange/widgets/data/tests/test_owneighbors.py
@@ -1,4 +1,4 @@
-# pylint: disable=missing-docstring,protected-access
+#pylint: disable=missing-docstring,protected-access,unsubscriptable-object
 import unittest
 from unittest.mock import Mock
 
@@ -122,21 +122,36 @@ def test_missing_values(self):
         widget.apply_button.button.click()
         self.assertIsNotNone(self.get_output("Neighbors"))
 
-    def test_labels(self):
-        """Check labels are updated when data is received"""
+    def test_input_summary(self):
+        """Check if status bar is updated when data is received"""
         widget = self.widget
+        input_sum = widget.info.set_input_summary = Mock()
         data = Table("iris")
+
+        input_sum.reset_mock()
+        self.send_signal(widget.Inputs.reference, data[:5])
+        input_sum.assert_called_with("0 | 5 ", "No data instance(s) on input\n"\
+                                               "5 reference instance(s) on input ")
+
+        input_sum.reset_mock()
         self.send_signal(widget.Inputs.data, data[:10])
-        self.assertIn("10", widget.data_info_label.text())
-        self.send_signal(widget.Inputs.reference, data[:12])
-        self.assertIn("12", widget.reference_info_label.text())
-        self.send_signal(widget.Inputs.reference, data[:15])
-        self.assertIn("15", widget.reference_info_label.text())
-        self.send_signal(widget.Inputs.data, None)
-        self.assertNotIn("10", widget.data_info_label.text())
-        self.assertIn("15", widget.reference_info_label.text())
-        self.send_signal(widget.Inputs.reference, None)
-        self.assertNotIn("15", widget.reference_info_label.text())
+        input_sum.assert_called_with("10 | 5 ", "10 data instance(s) on input\n"\
+                                                "5 reference instance(s) on input ")
+
+        input_sum.reset_mock()
+        self.send_signals([(widget.Inputs.data, None), (widget.Inputs.reference, None)])
+        input_sum.assert_called_once()
+        self.assertEqual(input_sum.call_args[0][0].brief, "")
+
+        input_sum.reset_mock()
+        self.send_signal(widget.Inputs.data, data[:15])
+        input_sum.assert_called_with("15 | 0 ", "15 data instance(s) on input\n" \
+                                                "No reference instance(s) on input ")
+
+        input_sum.reset_mock()
+        self.send_signals([(widget.Inputs.data, data[:12]), (widget.Inputs.reference, data[-1:])])
+        input_sum.assert_called_with("12 | 1 ", "12 data instance(s) on input\n"\
+                                                "1 reference instance(s) on input ")
 
     def test_compute_distances_apply_called(self):
         """Check compute distances and apply are called when receiving signal"""
@@ -314,6 +329,7 @@ def test_data_with_similarity(self):
 
     def test_apply(self):
         widget = self.widget
+        output_sum = widget.info.set_output_summary = Mock()
         widget.auto_apply = True
         data = Table("iris")
         indices = np.array([5, 10, 15, 100])
@@ -326,6 +342,7 @@ def test_apply(self):
         np.testing.assert_almost_equal(neigh.X, data.X[indices])
         np.testing.assert_almost_equal(
             neigh.metas.flatten(), widget.distances[indices])
+        output_sum.assert_called_with(str(len(neigh)))
 
     def test_all_equal_ref(self):
         widget = self.widget