Changeset 9323:476d1e232248 in orange


Ignore:
Timestamp:
12/07/11 19:12:17 (2 years ago)
Author:
ales_erjavec <ales.erjavec@…>
Branch:
default
Convert:
a2b85fcefbac8f8ae9e926df9261d05ac2bb4412
Message:

Added Add/Remove attribute's label actions.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • orange/OrangeWidgets/Data/OWEditDomain.py

    r9321 r9323  
    55<contact>Ales Erjavec (ales.erjavec(@ at @)fri.uni-lj.si)</contact> 
    66<priority>3125</priority> 
     7<keywords>change,name,variable,domain</keywords> 
    78""" 
    89 
     
    2122 
    2223def get_qualified(module, name): 
     24    """ Return a qualified module member ``name`` inside the named  
     25    ``module``. 
     26     
     27    The module (or package) firts gets imported and the name 
     28    is retrieved from the module's global namespace. 
     29      
     30    """ 
    2331    module = __import__(module) 
    2432    return getattr(module, name) 
    2533 
    2634def variable_description(var): 
     35    """ Return a variable descriptor. 
     36     
     37    A descriptor is a hashable tuple which should uniquely define  
     38    the variable i.e. (module, type_name, variable_name,  
     39    any_kwargs, attributes-labels). 
     40     
     41    """ 
    2742    var_type = type(var) 
    2843    if is_discrete(var): 
     
    4055 
    4156def variable_from_description(description): 
     57    """ Construct a variable from its description 
     58    (:ref:`variable_description`). 
     59     
     60    """ 
    4261    module, type_name, name, kwargs, attrs = description 
    4362    type = get_qualified(module, type_name) 
     
    5675     
    5776class DictItemsModel(QStandardItemModel): 
     77    """ A Qt Item Model class displaying the contents of a python 
     78    dictionary. 
     79     
     80    """ 
     81    # Implement a proper model with in-place editing. 
     82    # (Maybe it should be a TableModel with 2 columns) 
    5883    def __init__(self, parent=None, dict={}): 
    5984        QStandardItemModel.__init__(self, parent) 
     
    81106 
    82107class VariableEditor(QWidget): 
     108    """ An editor widget for a variable. 
     109     
     110    Can edit the variable name, and its attributes dictionary. 
     111      
     112    """ 
    83113    def __init__(self, parent=None): 
    84114        QWidget.__init__(self, parent) 
     
    102132         
    103133    def _setup_gui_labels(self): 
     134        vlayout = QVBoxLayout() 
     135        vlayout.setContentsMargins(0, 0, 0, 0) 
     136        vlayout.setSpacing(1) 
     137         
    104138        self.labels_edit = QTreeView() 
     139        self.labels_edit.setEditTriggers(QTreeView.DoubleClicked | \ 
     140                                         QTreeView.EditKeyPressed) 
     141        self.labels_edit.setRootIsDecorated(False) 
     142         
    105143        self.labels_model = DictItemsModel() 
    106144        self.labels_edit.setModel(self.labels_model) 
    107145         
     146        self.labels_edit.selectionModel().selectionChanged.connect(\ 
     147                                    self.on_label_selection_changed) 
     148         
     149        # Necessary signals to know when the labels change 
    108150        self.labels_model.dataChanged.connect(self.on_labels_changed) 
    109         self.main_form.addRow("Labels", self.labels_edit) 
    110          
    111         # TODO: add/remove label buttons  
     151        self.labels_model.rowsInserted.connect(self.on_labels_changed) 
     152        self.labels_model.rowsRemoved.connect(self.on_labels_changed) 
     153         
     154        vlayout.addWidget(self.labels_edit) 
     155        hlayout = QHBoxLayout() 
     156        hlayout.setContentsMargins(0, 0, 0, 0) 
     157        hlayout.setSpacing(1) 
     158        self.add_label_action = QAction("+", self, 
     159                        toolTip="Add a new label.", 
     160                        triggered=self.on_add_label, 
     161                        enabled=False, 
     162                        shortcut=QKeySequence(QKeySequence.New)) 
     163 
     164        self.remove_label_action = QAction("-", self, 
     165                        toolTip="Remove selected label.", 
     166                        triggered=self.on_remove_label, 
     167                        enabled=False, 
     168                        shortcut=QKeySequence(QKeySequence.Delete)) 
     169 
     170        button = QToolButton(self) 
     171        button.setDefaultAction(self.add_label_action) 
     172        hlayout.addWidget(button) 
     173         
     174        button = QToolButton(self) 
     175        button.setDefaultAction(self.remove_label_action) 
     176        hlayout.addWidget(button) 
     177        hlayout.addStretch(10) 
     178         
     179        vlayout.addLayout(hlayout) 
     180         
     181        self.main_form.addRow("Labels", vlayout) 
    112182         
    113183    def set_data(self, var): 
     184        """ Set the variable to edit. 
     185        """ 
    114186        self.clear() 
    115187        self.var = var 
     
    117189            self.name_edit.setText(var.name) 
    118190            self.labels_model.set_dict(dict(var.attributes)) 
     191            self.add_label_action.setEnabled(True) 
     192        else: 
     193            self.add_label_action.setEnabled(False) 
     194            self.remove_label_action.setEnabled(False) 
    119195             
    120196    def get_data(self): 
     197        """ Retrieve the modified variable. 
     198        """ 
    121199        name = str(self.name_edit.text()) 
    122200        labels = self.labels_model.get_dict() 
     
    141219             
    142220    def clear(self): 
     221        """ Clear the editor state. 
     222        """ 
    143223        self.var = None 
    144224        self.name_edit.setText("") 
     
    150230             
    151231    def commit(self): 
     232        """ Emit a ``variable_changed()`` signal. 
     233        """ 
    152234        self.emit(SIGNAL("variable_changed()")) 
    153235         
     
    157239         
    158240    @QtCore.Slot() 
    159     def on_labels_changed(self): 
     241    def on_labels_changed(self, *args): 
    160242        self.maybe_commit() 
    161243         
     244    @QtCore.Slot() 
     245    def on_add_label(self): 
     246        self.labels_model.appendRow([PyStandardItem(""), PyStandardItem("")]) 
     247        row = self.labels_model.rowCount() - 1 
     248        index = self.labels_model.index(row, 0) 
     249        self.labels_edit.edit(index) 
     250         
     251    @QtCore.Slot() 
     252    def on_remove_label(self): 
     253        rows = self.labels_edit.selectionModel().selectedRows() 
     254        if rows: 
     255            row = rows[0] 
     256            self.labels_model.removeRow(row.row()) 
     257     
     258    @QtCore.Slot() 
     259    def on_label_selection_changed(self): 
     260        selected = self.labels_edit.selectionModel().selectedRows() 
     261        self.remove_label_action.setEnabled(bool(len(selected))) 
     262         
    162263         
    163264class DiscreteVariableEditor(VariableEditor): 
     265    """ An editor widget for editing a discrete variable. 
     266     
     267    Extends the :class:`VariableEditor` to enable editing of 
     268    variables values. 
     269     
     270    """ 
    164271    def setup_gui(self): 
    165272        layout = QVBoxLayout() 
     
    176283    def _setup_gui_values(self): 
    177284        self.values_edit = QListView() 
     285        self.values_edit.setEditTriggers(QListView.DoubleClicked | \ 
     286                                         QListView.EditKeyPressed) 
    178287        self.values_model = PyListModel(flags=Qt.ItemIsSelectable | \ 
    179288                                        Qt.ItemIsEnabled | Qt.ItemIsEditable) 
     
    184293 
    185294    def set_data(self, var): 
     295        """ Set the variable to edit 
     296        """ 
    186297        VariableEditor.set_data(self, var) 
    187298        self.values_model.wrap([]) 
     
    191302                 
    192303    def get_data(self): 
     304        """ Retrieve the modified variable 
     305        """ 
    193306        name = str(self.name_edit.text()) 
    194307        labels = self.labels_model.get_dict() 
     
    211324     
    212325    def clear(self): 
     326        """ Clear the model state. 
     327        """ 
    213328        VariableEditor.clear(self) 
    214329        self.values_model.wrap([]) 
     
    220335         
    221336class ContinuousVariableEditor(VariableEditor): 
    222     pass 
     337    #TODO: enable editing of number_of_decimals, scientific format ... 
     338    pass  
    223339 
    224340 
    225341class OWEditDomain(OWWidget): 
    226342    contextHandlers = {"": DomainContextHandler("", ["domain_change_hints", "selected_index"])} 
    227     settingsList = [] 
     343    settingsList = ["auto_commit"] 
    228344     
    229345    def __init__(self, parent=None, signalManager=None, title="Edit Domain"): 
     
    235351        # Settings 
    236352         
     353        # Domain change hints maps from input variables description to 
     354        # the modified variables description as returned by 
     355        # `variable_description` function 
    237356        self.domain_change_hints = {} 
    238357        self.selected_index = 0 
     
    245364        # GUI 
    246365        ##### 
    247          
     366     
     367        # The list of domain's variables. 
    248368        box = OWGUI.widgetBox(self.controlArea, "Domain Features") 
    249369        self.domain_view = QListView() 
     
    260380        box.layout().addWidget(self.domain_view) 
    261381         
     382        # A stack for variable editor widgets. 
    262383        box = OWGUI.widgetBox(self.mainArea, "Edit Feature") 
    263384        self.editor_stack = QStackedWidget() 
    264385        box.layout().addWidget(self.editor_stack) 
     386         
    265387         
    266388        box = OWGUI.widgetBox(self.controlArea, "Reset") 
     
    276398                     ) 
    277399         
    278          
    279400        box = OWGUI.widgetBox(self.controlArea, "Commit") 
    280401         
     
    297418         
    298419    def clear(self): 
     420        """ Clear the widget state. 
     421        """ 
    299422        self.data = None 
    300423        self.domain_model[:] = [] 
     
    303426         
    304427    def clear_editor(self): 
     428        """ Clear the current editor widget 
     429        """ 
    305430        current = self.editor_stack.currentWidget() 
    306431        if current: 
     
    321446             
    322447            edited_vars = [] 
     448             
     449            # Apply any saved transformations as listed in  
     450            # `domain_change_hints` 
     451              
    323452            for var in all_vars: 
    324453                desc = variable_description(var) 
     
    326455                if changed is not None: 
    327456                    new = variable_from_description(changed) 
     457                     
     458                    # Make sure orange's domain transformations will work. 
    328459                    new.source_variable = var 
    329460                    new.get_value_from = Orange.core.ClassifierFromVar(whichVar=var) 
     
    334465            self.input_domain = input_domain 
    335466             
     467            # Sets the model to display in the 'Domain Features' view 
    336468            self.domain_model[:] = edited_vars 
    337469             
     
    350482             
    351483    def on_selection_changed(self, *args): 
     484        """ When selection in 'Domain Features' view changes.  
     485        """ 
    352486        i = self.selected_var_index() 
    353487        if i is not None: 
     
    356490         
    357491    def selected_var_index(self): 
     492        """ Return the selected row in 'Domain Features' view or None  
     493        if no row is selected. 
     494         
     495        """ 
    358496        rows = self.domain_view.selectionModel().selectedRows() 
    359497        if rows: 
     
    363501         
    364502    def select_variable(self, index): 
     503        """ Select the variable with ``index`` in the 'Domain Features' 
     504        view. 
     505         
     506        """ 
    365507        sel_model = self.domain_view.selectionModel() 
    366508        sel_model.select(self.domain_model.index(index, 0), 
     
    368510         
    369511    def open_editor(self, index): 
     512        """ Open the editor for variable at ``index`` and move it 
     513        to the top if the stack. 
     514         
     515        """ 
    370516        # First remove and clear the current editor if any 
    371517        self.clear_editor() 
     
    382528     
    383529    def editor_for_variable(self, var): 
     530        """ Return the editor for ``var``'s variable type. 
     531         
     532        The editors are cached and reused by type. 
     533           
     534        """ 
    384535        editor = None 
    385536        if is_discrete(var): 
     
    398549     
    399550    def on_variable_changed(self): 
     551        """ When the user edited the current variable in editor. 
     552        """ 
    400553        var = self.domain_model[self.edited_variable_index] 
    401554        editor = self.editor_stack.currentWidget() 
    402555        new_var = editor.get_data() 
    403556         
     557        # Replace the variable in the 'Domain Features' view/model 
    404558        self.domain_model[self.edited_variable_index] = new_var 
    405559        old_var = self.all_vars[self.edited_variable_index] 
    406560         
     561        # Store the transformation hint. 
    407562        self.domain_change_hints[variable_description(old_var)] = \ 
    408563                    variable_description(new_var) 
    409                      
     564 
     565        # Make orange's domain transformation work. 
    410566        new_var.source_variable = old_var 
    411567        new_var.get_value_from = Orange.core.ClassifierFromVar(whichVar=old_var) 
     568         
    412569        self.commit_if() 
    413570          
    414571    def reset_all(self): 
     572        """ Reset all variables to the input state. 
     573        """ 
    415574        self.domain_change_hints = {} 
    416575        if self.data is not None: 
     
    422581             
    423582    def reset_selected(self): 
     583        """ Reset the currently selected variable to its original 
     584        state. 
     585           
     586        """ 
    424587        if self.data is not None: 
    425588            var = self.all_vars[self.selected_index] 
     
    434597         
    435598    def commit(self): 
     599        """ Commit the changed data to output.  
     600        """ 
    436601        new_data = None 
    437602        if self.data is not None: 
     
    447612             
    448613            # Assumes getmetas().items() order has not changed. 
    449             # TODO: store them in set_data 
     614            # TODO: store metaids in set_data method 
    450615            for (mid, _), new in zip(self.input_domain.getmetas().items(),  
    451616                                       new_metas): 
Note: See TracChangeset for help on using the changeset viewer.