Skip to content

Commit eed39ef

Browse files
authored
Merge pull request #6865 from ales-erjavec/fixes/oweditdomain-hide-warning
[FIX] oweditdomain: Hide "categories mapping" warning on change
2 parents 60a2f61 + 31eb42a commit eed39ef

File tree

3 files changed

+85
-19
lines changed

3 files changed

+85
-19
lines changed

Orange/widgets/data/oweditdomain.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030
)
3131
from AnyQt.QtGui import (
3232
QStandardItemModel, QStandardItem, QKeySequence, QIcon, QBrush, QPalette,
33-
QHelpEvent
33+
QHelpEvent, QColor
3434
)
3535
from AnyQt.QtCore import (
3636
Qt, QSize, QModelIndex, QAbstractItemModel, QPersistentModelIndex, QRect,
3737
QPoint, QItemSelectionModel
3838
)
3939
from AnyQt.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
4040

41+
from orangecanvas.gui.utils import luminance
4142
from orangecanvas.utils import assocf
4243
from orangewidget.utils.listview import ListViewSearch
4344

@@ -1577,6 +1578,12 @@ def variable_icon(var):
15771578
#: (`List[Union[ReinterpretTransform, Transform]]`)
15781579
TransformRole = Qt.UserRole + 42
15791580

1581+
#: Any warnings applying to the transform (`list[tuple[Msg, str]]`)
1582+
RestoreWarningRole = TransformRole + 1
1583+
1584+
#: Hint key that was used to load stored settings.
1585+
RestoreHintKey = RestoreWarningRole + 1
1586+
15801587

15811588
class VariableEditDelegate(QStyledItemDelegate):
15821589
ReinterpretNames = {
@@ -1624,9 +1631,24 @@ def initStyleOption(self, option, index):
16241631
option.font.setItalic(True)
16251632

16261633
multiplicity = index.data(MultiplicityRole)
1634+
warnings_ = index.data(RestoreWarningRole)
1635+
1636+
def set_color(palette: QPalette, color):
1637+
palette.setBrush(QPalette.Text, QBrush(color))
1638+
palette.setBrush(QPalette.HighlightedText, QBrush(color))
1639+
16271640
if isinstance(multiplicity, int) and multiplicity > 1:
1628-
option.palette.setBrush(QPalette.Text, QBrush(Qt.red))
1629-
option.palette.setBrush(QPalette.HighlightedText, QBrush(Qt.red))
1641+
set_color(option.palette, Qt.red)
1642+
elif warnings_:
1643+
set_color(option.palette, self.warning_text_color(option.palette))
1644+
1645+
@staticmethod
1646+
def warning_text_color(palette: QPalette):
1647+
background = palette.color(QPalette.ColorRole.Base)
1648+
if luminance(background) > 0.5:
1649+
return QColor(255, 148, 11)
1650+
else:
1651+
return QColor(Qt.GlobalColor.yellow)
16301652

16311653
def helpEvent(self, event: QHelpEvent, view: QAbstractItemView,
16321654
option: QStyleOptionViewItem, index: QModelIndex) -> bool:
@@ -2123,16 +2145,18 @@ def reset_selected(self):
21232145
modified = []
21242146
for ind in self.selected_var_indices():
21252147
midx = model.index(ind)
2126-
if midx.data(TransformRole):
2127-
model.setData(midx, [], TransformRole)
2128-
var = midx.data(Qt.EditRole)
2129-
self._store_transform(var, [])
2130-
modified.append(var)
2148+
model.setData(midx, [], TransformRole)
2149+
model.setData(midx, None, RestoreWarningRole)
2150+
key = model.data(midx, RestoreHintKey)
2151+
var = midx.data(Qt.EditRole)
2152+
self._domain_change_hints.pop(key, None)
2153+
modified.append(var)
21312154
if modified:
21322155
with disconnected(editor.variable_changed,
21332156
self._on_variable_changed):
21342157
self._editor.set_data(modified)
21352158
self._invalidate()
2159+
self._update_restore_warnings()
21362160

21372161
def reset_all(self):
21382162
"""Reset all variables to their original state."""
@@ -2141,8 +2165,12 @@ def reset_all(self):
21412165
for i in range(model.rowCount()):
21422166
midx = model.index(i)
21432167
model.setData(midx, [], TransformRole)
2168+
model.setData(midx, None, RestoreWarningRole)
2169+
key = model.data(midx, RestoreHintKey)
2170+
self._domain_change_hints.pop(key, None)
21442171
self.open_editor()
21452172
self._invalidate()
2173+
self._update_restore_warnings()
21462174

21472175
def selected_var_indices(self):
21482176
"""Return the current selected variable indices."""
@@ -2199,7 +2227,6 @@ def _restore(self):
21992227
model = self.variables_model
22002228
hints = self._domain_change_hints
22012229
first_key = None
2202-
msgs = []
22032230
for i in range(model.rowCount()):
22042231
midx = model.index(i, 0)
22052232
coldesc = model.data(midx, Qt.EditRole) # type: DataVector
@@ -2208,9 +2235,10 @@ def _restore(self):
22082235
key, tr = res
22092236
if tr:
22102237
self._store_transform(coldesc.vtype, tr, key)
2211-
tr, msgs_ = self._sanitize_transform(coldesc.vtype, tr)
2238+
tr, msgs = self._sanitize_transform(coldesc.vtype, tr)
22122239
model.setData(midx, tr, TransformRole)
2213-
msgs.extend(msgs_)
2240+
model.setData(midx, msgs, RestoreWarningRole)
2241+
model.setData(midx, key, RestoreHintKey)
22142242
if first_key is None:
22152243
first_key = key
22162244
# Reduce the number of hints to MAX_HINTS, but keep all current hints
@@ -2219,9 +2247,7 @@ def _restore(self):
22192247
(key := next(iter(hints))) != first_key:
22202248
del hints[key] # pylint: disable=unsupported-delete-operation
22212249

2222-
# Show warnings for non-applicable transforms
2223-
for msg, names in groupby(msgs, key=itemgetter(0)):
2224-
msg(", ".join(map(itemgetter(1), names)))
2250+
self._update_restore_warnings()
22252251

22262252
# Restore the current variable selection
22272253
selected_rows = [i for i, vec in enumerate(model)
@@ -2230,6 +2256,19 @@ def _restore(self):
22302256
selected_rows = [0]
22312257
itemmodels.select_rows(self.variables_view, selected_rows)
22322258

2259+
def _update_restore_warnings(self):
2260+
def messages(midx):
2261+
msgs = model.data(midx, RestoreWarningRole)
2262+
return msgs or []
2263+
model = self.variables_model
2264+
msgs = chain.from_iterable(
2265+
messages(model.index(i)) for i in range(model.rowCount())
2266+
)
2267+
self.Warning.cat_mapping_does_not_apply.clear()
2268+
# Show warnings for non-applicable transforms
2269+
for msg, names in groupby(sorted(msgs), key=itemgetter(0)):
2270+
msg(", ".join(map(itemgetter(1), names)))
2271+
22332272
def _on_selection_changed(self, _, deselected):
22342273
# If the user deselected the last item, select it back with disabled
22352274
# signals, so nothing happens
@@ -2278,19 +2317,22 @@ def _on_variable_changed(self):
22782317
*editor.get_data()):
22792318
midx = model.index(idx, 0)
22802319
model.setData(midx, transform, TransformRole)
2320+
model.setData(midx, None, RestoreWarningRole)
22812321
self._store_transform(var, transform)
22822322
self._invalidate()
2323+
self._update_restore_warnings()
22832324

22842325
def _store_transform(
2285-
self, var: Variable, transform: Iterable[Transform], deconvar=None
2326+
self, var: Variable, transform: Sequence[Transform] | None, deconvar=None
22862327
) -> None:
22872328
deconvar = deconvar or deconstruct(var)
22882329
# Remove the existing key (if any) to put the new one at the end,
22892330
# to make sure it comes after the sentinel
22902331
self._domain_change_hints.pop(deconvar, None)
22912332
# pylint: disable=unsupported-assignment-operation
2292-
self._domain_change_hints[deconvar] = \
2293-
[deconstruct(t) for t in transform]
2333+
if transform:
2334+
self._domain_change_hints[deconvar] = \
2335+
[deconstruct(t) for t in transform]
22942336

22952337
def _find_stored_transform(
22962338
self, var: Variable

Orange/widgets/data/tests/test_oweditdomain.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
VariableEditDelegate, TransformRole,
3636
RealVector, TimeVector, StringVector, make_dict_mapper,
3737
LookupMappingTransform, as_float_or_nan, column_str_repr,
38-
GroupItemsDialog, VariableListModel, StrpTime, RestoreOriginal, BaseEditor
38+
GroupItemsDialog, VariableListModel, StrpTime, RestoreOriginal, BaseEditor,
39+
RestoreWarningRole
3940
)
4041
from Orange.widgets.data.owcolor import OWColor, ColorRole
4142
from Orange.widgets.tests.base import WidgetTest, GuiTest
4243
from Orange.widgets.tests.utils import contextMenu
44+
from Orange.widgets.utils.itemmodels import select_row
4345
from Orange.widgets.utils import colorpalettes
4446
from Orange.tests import test_filename, assert_array_nanequal
4547

@@ -382,6 +384,16 @@ def restore(state):
382384
self.assertEqual(output.domain.class_var.values,
383385
("Iris-setosa", "Iris-versicolor", "Iris-virginica"))
384386

387+
restore({viris_1: [("Rename", ("K",),),
388+
("CategoriesMapping", ([("A", "AA")],))]})
389+
self.assertTrue(w.Warning.cat_mapping_does_not_apply.is_shown())
390+
w.reset_all()
391+
self.assertFalse(w.Warning.cat_mapping_does_not_apply.is_shown())
392+
393+
select_row(w.variables_view, 4)
394+
w.reset_selected()
395+
self.assertFalse(w.Warning.cat_mapping_does_not_apply.is_shown())
396+
385397
restore({viris: [("Rename", ("A")), ("NonexistantTransform", ("AA",))]})
386398
tr = model.data(model.index(4), TransformRole)
387399
self.assertEqual(tr, [Rename("A")])
@@ -1222,6 +1234,16 @@ def get_style_option(row: int) -> QStyleOptionViewItem:
12221234
)
12231235
p.assert_called_once()
12241236

1237+
set_item(1, {
1238+
TransformRole: Rename("bb"),
1239+
RestoreWarningRole: ("bb", "aa"),
1240+
})
1241+
opt = get_style_option(1)
1242+
self.assertIn(
1243+
opt.palette.color(QPalette.Text),
1244+
(QColor(Qt.yellow), QColor(255, 148, 11))
1245+
)
1246+
12251247

12261248
class TestTransforms(TestCase):
12271249
def _test_common(self, var):

Orange/widgets/utils/itemmodels.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
__all__ = [
3838
"PyListModel", "VariableListModel", "PyListModelTooltip", "DomainModel",
3939
"AbstractSortTableModel", "PyTableModel", "TableModel",
40-
"ModelActionsWidget", "ListSingleSelectionModel"
40+
"ModelActionsWidget", "ListSingleSelectionModel",
41+
"select_row", "select_rows", "signal_blocking"
4142
]
4243

44+
4345
@contextmanager
4446
def signal_blocking(obj):
4547
blocked = obj.signalsBlocked()

0 commit comments

Comments
 (0)