Repository: biolab/orange3

Issue:
File: Mark modifications in DomainEditor
There is no clear indication whether the header has been modified after the file has been loaded. (in the Columns part of the widget)

The least we could do is to indicate which rows have been modified, either with color or some other indicator (checkbox?). We could also use a Reset button which resets variables to their default values, it should be disabled if no modifications have been made.

Modifications are done manually by the user or restored from settings (when a dataset that has been modified is loaded again).

Domain Editor in File widget should have a Reset button



Discussion:
Checkbox is not meant to be an indicator, it's used for input. I'd prefer colors, but these are already used for placement (X, y, meta). Would printing the modified lines in bold help? This should be trivial to implement through a model. It just needs to store the original values and implement the `FontRole` to make the font bold when the values in the models differ from the stored originals.

The Reset button just needs to call `set_domain` again, AFAIK. This part should be in the widget.
Bold or italics for the whole line could be ok. An asterisk in front of the field that was changed could be another (more specific) option, but might not look as good.
I agree that some sort of an indicator would be welcome. Someone probably needs to try a few different options and see how they look.
We decided to mark changed variables by using **bold** font.


Resolving patch:
diff --git a/Orange/widgets/data/owfile.py b/Orange/widgets/data/owfile.py
--- a/Orange/widgets/data/owfile.py
+++ b/Orange/widgets/data/owfile.py
@@ -215,6 +215,8 @@ def __init__(self):
             callback=lambda: self.browse_file(True), autoDefault=False)
         gui.rubber(box)
 
+        gui.button(
+            box, self, "Reset", callback=self.reset_domain_edit)
         self.apply_button = gui.button(
             box, self, "Apply", callback=self.apply_domain_edit)
         self.apply_button.setEnabled(False)
@@ -440,6 +442,10 @@ def retrieveSpecificSettings(self):
         if hasattr(self.current_context, "modified_variables"):
             self.variables[:] = self.current_context.modified_variables
 
+    def reset_domain_edit(self):
+        self.domain_editor.reset_domain()
+        self.apply_domain_edit()
+
     def apply_domain_edit(self):
         if self.data is None:
             table = None
diff --git a/Orange/widgets/utils/domaineditor.py b/Orange/widgets/utils/domaineditor.py
--- a/Orange/widgets/utils/domaineditor.py
+++ b/Orange/widgets/utils/domaineditor.py
@@ -1,10 +1,11 @@
 from itertools import chain
+from copy import deepcopy
 
 import numpy as np
 import scipy.sparse as sp
 
 from AnyQt.QtCore import Qt, QAbstractTableModel
-from AnyQt.QtGui import QColor
+from AnyQt.QtGui import QColor, QFont
 from AnyQt.QtWidgets import QComboBox, QTableView, QSizePolicy
 
 from Orange.data import DiscreteVariable, ContinuousVariable, StringVariable, \
@@ -43,6 +44,14 @@ class VarTableModel(QAbstractTableModel):
     def __init__(self, variables, *args):
         super().__init__(*args)
         self.variables = variables
+        self.orig_variables = None
+        self.set_orig_variables(variables)
+
+    def set_orig_variables(self, variables):
+        self.orig_variables = deepcopy(variables)
+
+    def reset_variables(self):
+        self.set_variables(deepcopy(self.orig_variables))
 
     def set_variables(self, variables):
         self.modelAboutToBeReset.emit()
@@ -76,6 +85,11 @@ def data(self, index, role):
             place = self.variables[row][Column.place]
             mapping = [Place.meta, Place.feature, Place.class_var, None]
             return TableModel.ColorForRole.get(mapping[place], None)
+        if role == Qt.FontRole:
+            if self.variables[row] != self.orig_variables[row]:
+                font = QFont()
+                font.setBold(True)
+                return font
 
     def setData(self, index, value, role):
         row, col = index.row(), index.column()
@@ -342,6 +356,11 @@ def _get_column(self, data, source_var, source_place):
 
     def set_domain(self, domain):
         self.variables = self.parse_domain(domain)
+        self.model().set_orig_variables(self.variables)
+
+    def reset_domain(self):
+        self.model().reset_variables()
+        self.variables = self.model().variables
 
     @staticmethod
     def parse_domain(domain):


Test patch: