Repository: biolab/orange3

Issue:
Color: No way to reset to default
**Describe the bug**
After making some changes in Color widget it should be possible to get back to default colors.
It would probably be enough to allow clearing all settings, but we might discuss undoing even individual changes?

**Orange version:**
3.25




Discussion:

Resolving patch:
diff --git a/Orange/widgets/data/owcolor.py b/Orange/widgets/data/owcolor.py
--- a/Orange/widgets/data/owcolor.py
+++ b/Orange/widgets/data/owcolor.py
@@ -35,6 +35,9 @@ def __init__(self, var):
         self.var = var
         self.new_name = None
 
+    def reset(self):
+        self.new_name = None
+
     @property
     def name(self):
         return self.new_name or self.var.name
@@ -61,6 +64,11 @@ def __init__(self, var):
         self.new_colors = None
         self.new_values = None
 
+    def reset(self):
+        super().reset()
+        self.new_colors = None
+        self.new_values = None
+
     @property
     def colors(self):
         if self.new_colors is None:
@@ -102,10 +110,17 @@ class ContAttrDesc(AttrDesc):
     """
     def __init__(self, var):
         super().__init__(var)
-        if var.palette.name not in colorpalettes.ContinuousPalettes:
-            self.new_palette_name = colorpalettes.DefaultContinuousPaletteName
+        self.new_palette_name = self._default_palette_name()
+
+    def reset(self):
+        super().reset()
+        self.new_palette_name = self._default_palette_name()
+
+    def _default_palette_name(self):
+        if self.var.palette.name not in colorpalettes.ContinuousPalettes:
+            return colorpalettes.DefaultContinuousPaletteName
         else:
-            self.new_palette_name = None
+            return None
 
     @property
     def palette_name(self):
@@ -170,6 +185,12 @@ def setData(self, index, value, role):
         self.dataChanged.emit(index, index)
         return True
 
+    def reset(self):
+        self.beginResetModel()
+        for desc in self.attrdescs:
+            desc.reset()
+        self.endResetModel()
+
 
 class DiscColorTableModel(ColorTableModel):
     """
@@ -460,7 +481,9 @@ def __init__(self):
 
         box = gui.auto_apply(self.controlArea, self, "auto_apply")
         box.button.setFixedWidth(180)
-        box.layout().insertStretch(0)
+        reset = gui.button(None, self, "Reset", callback=self.reset)
+        box.layout().insertWidget(0, reset)
+        box.layout().insertStretch(1)
 
         self.info.set_input_summary(self.info.NoInput)
         self.info.set_output_summary(self.info.NoOutput)
@@ -496,6 +519,11 @@ def set_data(self, data):
     def _on_data_changed(self):
         self.commit()
 
+    def reset(self):
+        self.disc_model.reset()
+        self.cont_model.reset()
+        self.commit()
+
     def commit(self):
         def make(variables):
             new_vars = []


Test patch:
diff --git a/Orange/widgets/data/tests/test_owcolor.py b/Orange/widgets/data/tests/test_owcolor.py
--- a/Orange/widgets/data/tests/test_owcolor.py
+++ b/Orange/widgets/data/tests/test_owcolor.py
@@ -28,11 +28,20 @@ def test_name(self):
         desc.name = None
         self.assertEqual(desc.name, "x")
 
+    def test_reset(self):
+        x = ContinuousVariable("x")
+        desc = owcolor.AttrDesc(x)
+        desc.reset()
+        self.assertEqual(desc.name, "x")
+        desc.name = "y"
+        desc.reset()
+        self.assertEqual(desc.name, "x")
+
 
 class DiscAttrTest(unittest.TestCase):
     def setUp(self):
-        x = DiscreteVariable("x", ["a", "b", "c"])
-        self.desc = owcolor.DiscAttrDesc(x)
+        self.var = DiscreteVariable("x", ["a", "b", "c"])
+        self.desc = owcolor.DiscAttrDesc(self.var)
 
     def test_colors(self):
         desc = self.desc
@@ -69,6 +78,16 @@ def test_create_variable(self):
         self.assertIsInstance(var.compute_value, Identity)
         self.assertIs(var.compute_value.variable, desc.var)
 
+    def test_reset(self):
+        desc = self.desc
+        desc.set_color(0, [1, 2, 3])
+        desc.set_color(1, [4, 5, 6])
+        desc.set_color(2, [7, 8, 9])
+        desc.set_value(1, "d")
+        desc.reset()
+        np.testing.assert_equal(desc.colors, self.var.colors)
+        self.assertEqual(desc.values, self.var.values)
+
 
 class ContAttrDesc(unittest.TestCase):
     def setUp(self):
@@ -104,6 +123,14 @@ def test_create_variable(self):
         self.assertIsInstance(var.compute_value, Identity)
         self.assertIs(var.compute_value.variable, desc.var)
 
+    def test_reset(self):
+        desc = self.desc
+        palette_name = desc.palette_name
+        desc.palette_name = _find_other_palette(
+            colorpalettes.ContinuousPalettes[palette_name]).name
+        desc.reset()
+        np.testing.assert_equal(desc.palette_name, palette_name)
+
 
 class BaseTestColorTableModel:
     def test_row_count(self):
@@ -150,6 +177,14 @@ def test_set_data(self):
         finally:
             self.model.dataChanged.disconnect(emit)
 
+    def test_reset(self):
+        for desc in self.descs:
+            desc.reset = Mock()
+        self.model.set_data(self.descs)
+        self.model.reset()
+        for desc in self.descs:
+            desc.reset.assert_called()
+
 
 class TestDiscColorTableModel(GuiTest, BaseTestColorTableModel):
     def setUp(self):
@@ -511,6 +546,22 @@ def test_summary(self):
         output_sum.assert_called_once()
         self.assertEqual(output_sum.call_args[0][0].brief, "")
 
+    def test_reset(self):
+        self.send_signal(self.widget.Inputs.data, self.iris)
+        cont_model = self.widget.cont_model
+        disc_model = self.widget.disc_model
+        cont_model.setData(cont_model.index(0, 0), "a", Qt.EditRole)
+        disc_model.setData(disc_model.index(0, 0), "b", Qt.EditRole)
+        outp = self.get_output(self.widget.Outputs.data)
+        self.assertEqual(outp.domain[0].name, "a")
+        self.assertEqual(outp.domain.class_var.name, "b")
+        self.widget.reset()
+        outp = self.get_output(self.widget.Outputs.data)
+        self.assertEqual(
+            outp.domain[0].name, self.iris.domain[0].name)
+        self.assertEqual(
+            outp.domain.class_var.name, self.iris.domain.class_var.name)
+
 
 if __name__ == "__main__":
     unittest.main()