diff --git a/Orange/widgets/data/owcreateclass.py b/Orange/widgets/data/owcreateclass.py
index ffefb558054..60ae07fe2f9 100644
--- a/Orange/widgets/data/owcreateclass.py
+++ b/Orange/widgets/data/owcreateclass.py
@@ -13,7 +13,7 @@
from Orange.statistics.util import bincount
from Orange.preprocess.transformation import Transformation, Lookup
from Orange.widgets import gui, widget
-from Orange.widgets.settings import DomainContextHandler, ContextSetting
+from Orange.widgets.settings import DomainContextHandler, ContextSetting, Setting
from Orange.widgets.utils.itemmodels import DomainModel
from Orange.widgets.utils.localization import pl
from Orange.widgets.utils.widgetpreview import WidgetPreview
@@ -229,12 +229,14 @@ class Outputs:
buttons_area_orientation = Qt.Vertical
settingsHandler = DomainContextHandler()
- attribute = ContextSetting(None)
- class_name = ContextSetting("class")
- rules = ContextSetting({})
- match_beginning = ContextSetting(False)
- case_sensitive = ContextSetting(False)
- regular_expressions = ContextSetting(False)
+ attribute = ContextSetting(None, schema_only=True)
+ class_name = Setting("class", schema_only=True)
+ rules = Setting({}, schema_only=True)
+ match_beginning = Setting(False, schema_only=True)
+ case_sensitive = Setting(False, schema_only=True)
+ regular_expressions = Setting(False, schema_only=True)
+
+ settings_version = 2
TRANSFORMERS = {StringVariable: ValueFromStringSubstring,
DiscreteVariable: ValueFromDiscreteSubstring}
@@ -270,15 +272,15 @@ def __init__(self):
#: list of list of QLabel: pairs of labels with counts
self.counts = []
- gui.lineEdit(
+ le = gui.lineEdit(
self.controlArea, self, "class_name",
orientation=Qt.Horizontal, box="New Class Name")
+ le.setStyleSheet("QLineEdit { padding-left: 4px; }")
- variable_select_box = gui.vBox(self.controlArea, "Match by Substring")
+ variable_select_box = gui.vBox(self.controlArea, box="Source column and patterns")
combo = gui.comboBox(
- variable_select_box, self, "attribute", label="From column:",
- orientation=Qt.Horizontal, searchable=True,
+ variable_select_box, self, "attribute", searchable=True,
callback=self.update_rules,
model=DomainModel(valid_types=(StringVariable, DiscreteVariable)))
# Don't use setSizePolicy keyword argument here: it applies to box,
@@ -328,8 +330,8 @@ def __init__(self):
gui.button(self.buttonsArea, self, "Apply", callback=self.apply)
- # TODO: Resizing upon changing the number of rules does not work
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
+ self.update_dynamic_height(initial=True)
@property
def active_rules(self):
@@ -347,11 +349,16 @@ def rules_to_edits(self):
for edit, text in zip(editr, textr):
edit.setText(text)
+ def update_dynamic_height(self, initial=False):
+ self.updateGeometry()
+ current_width = 350 if initial else self.width()
+ target_height = self.layout().sizeHint().height()
+ self.resize(current_width, target_height)
+
@Inputs.data
def set_data(self, data):
"""Input data signal handler."""
self.closeContext()
- self.rules = {}
self.data = data
model = self.controls.attribute.model()
model.set_domain(data.domain if data is not None else None)
@@ -693,6 +700,18 @@ def _count_part():
self.report_items("Output", [("Class name", self.class_name)])
self.report_raw(f"
{output}
")
+ @classmethod
+ def migrate_settings(cls, settings, version):
+ if version < 2:
+ contexts = settings.pop("context_settings", [])
+ if contexts:
+ print(contexts[0].values)
+ print(settings)
+ settings.update(
+ {name: contexts[0].values[name][0]
+ for name in ("class_name", "rules", "match_beginning",
+ "case_sensitive")})
+
if __name__ == "__main__": # pragma: no cover
WidgetPreview(OWCreateClass).run(Table("zoo"))
diff --git a/Orange/widgets/data/tests/test_owcreateclass.py b/Orange/widgets/data/tests/test_owcreateclass.py
index f265011820e..a63a1dfe30a 100644
--- a/Orange/widgets/data/tests/test_owcreateclass.py
+++ b/Orange/widgets/data/tests/test_owcreateclass.py
@@ -5,6 +5,7 @@
import numpy as np
+from orangewidget.settings import Context
from Orange.data import Table, StringVariable, DiscreteVariable, Domain
from Orange.widgets.data.owcreateclass import (
OWCreateClass,
@@ -503,7 +504,7 @@ def _check_thal(self):
np.testing.assert_equal(classes[fixed], 1)
self.assertTrue(np.all(np.isnan(classes[~(reversable | fixed)])))
- def test_flow_and_context_handling(self):
+ def test_flow(self):
widget = self.widget
self.send_signal(self.widget.Inputs.data, self.heart)
self._test_default_rules()
@@ -545,27 +546,6 @@ def test_flow_and_context_handling(self):
self._set_attr(thal)
self._check_thal()
- prev_rules = widget.rules
- self.send_signal(self.widget.Inputs.data, self.zoo)
- self.assertIsNot(widget.rules, prev_rules)
-
- self.send_signal(self.widget.Inputs.data, self.heart)
- self._check_thal()
-
- # Check that sending None as data does not ruin the context, and that
- # the empty context does not match the true one later
- self.send_signal(self.widget.Inputs.data, None)
- self.assertIsNot(widget.rules, prev_rules)
-
- self.send_signal(self.widget.Inputs.data, self.heart)
- self._check_thal()
-
- self.send_signal(self.widget.Inputs.data, self.no_attributes)
- self.assertIsNot(widget.rules, prev_rules)
-
- self.send_signal(self.widget.Inputs.data, self.heart)
- self._check_thal()
-
def test_add_remove_lines(self):
widget = self.widget
self.send_signal(self.widget.Inputs.data, self.heart)
@@ -690,6 +670,32 @@ def test_same_class(self):
self.get_output(widget2.Outputs.data, widget=widget2).domain.class_var
)
+ def test_migrate_settings_1_2(self):
+ settings = {"__version__": 1, "context_settings": [Context(
+ values= {
+ 'attribute': ('type', 101),
+ 'case_sensitive': (True, -2),
+ 'class_name': ('class', -2),
+ 'match_beginning': (True, -2),
+ 'regular_expressions': (False, -2),
+ 'rules': ({'type': [['cam', 'am'], ['cer', 'er'], ['', '']],
+ 'eggs': [['de', 'e1'], ['', '']]},
+ -2),
+ '__version__': 1},
+ attributes = {'hair': 1, 'feathers': 1, 'eggs': 1, 'type': 1},
+ metas = {'name': 3})]}
+ w = self.create_widget(OWCreateClass, stored_settings=settings)
+ self.send_signal(w.Inputs.data, self.zoo, widget=w)
+ self.assertEqual(w.active_rules, [['cam', 'am'], ['cer', 'er'], ['', '']])
+ self.assertEqual(w.class_name, "class")
+ self.assertTrue(w.case_sensitive)
+ self.assertTrue(w.match_beginning)
+ self.assertFalse(w.regular_expressions)
+
+ w.attribute = self.zoo.domain["eggs"]
+ self.assertEqual(w.active_rules, [['de', 'e1'], ['', '']])
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/i18n/si/msgs.jaml b/i18n/si/msgs.jaml
index 6fc02647808..c6ea8843085 100644
--- a/i18n/si/msgs.jaml
+++ b/i18n/si/msgs.jaml
@@ -4820,9 +4820,9 @@ widgets/data/owcreateclass.py:
def `__init__`:
class_name: false
New Class Name: Ime novega razreda
- Match by Substring: Vzorci in razredi
+ 'QLineEdit { padding-left: 4px; }': false
+ Source column and patterns: Izvorni stolpec in vzorci
attribute: false
- From column:: Iz stolpca:
Name: Ime
Substring: Vzorec
Count: Primerov
@@ -4873,6 +4873,12 @@ widgets/data/owcreateclass.py:
Output: Izhod
Class name: Ime razreda
{output}
: false
+ def `migrate_settings`:
+ context_settings: false
+ class_name: false
+ rules: false
+ match_beginning: false
+ case_sensitive: false
__main__: false
zoo: false
widgets/data/owcreateinstance.py: