Ignore:
Files:
4 added
26 deleted
21 edited

Legend:

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

    r11096 r11432  
    1515import Orange 
    1616 
     17 
    1718def is_discrete(var): 
    1819    return isinstance(var, Orange.feature.Discrete) 
    1920 
     21 
    2022def is_continuous(var): 
    2123    return isinstance(var, Orange.feature.Continuous) 
    2224 
     25 
    2326def get_qualified(module, name): 
    24     """Return a qualified module member ``name`` inside the named  
     27    """Return a qualified module member ``name`` inside the named 
    2528    ``module``. 
    26      
     29 
    2730    The module (or package) first gets imported and the name 
    2831    is retrieved from the module's global namespace. 
    29       
     32 
    3033    """ 
    3134    # see __import__.__doc__ for why 'fromlist' is used 
     
    3336    return getattr(module, name) 
    3437 
     38 
    3539def variable_description(var): 
    3640    """Return a variable descriptor. 
    37      
    38     A descriptor is a hashable tuple which should uniquely define  
    39     the variable i.e. (module, type_name, variable_name,  
     41 
     42    A descriptor is a hashable tuple which should uniquely define 
     43    the variable i.e. (module, type_name, variable_name, 
    4044    any_kwargs, sorted-attributes-items). 
    41      
     45 
    4246    """ 
    4347    var_type = type(var) 
     
    4549        return (var_type.__module__, 
    4650                var_type.__name__, 
    47                 var.name,  
    48                 (("values", tuple(var.values)),),  
     51                var.name, 
     52                (("values", tuple(var.values)),), 
    4953                tuple(sorted(var.attributes.items()))) 
    5054    else: 
    5155        return (var_type.__module__, 
    5256                var_type.__name__, 
    53                 var.name,  
    54                 (),  
     57                var.name, 
     58                (), 
    5559                tuple(sorted(var.attributes.items()))) 
    5660 
     61 
    5762def variable_from_description(description): 
    58     """Construct a variable from its description 
    59     (:ref:`variable_description`). 
    60      
     63    """Construct a variable from its description (see 
     64    :func:`variable_description`). 
     65 
    6166    """ 
    6267    module, type_name, name, kwargs, attrs = description 
     
    6469        type = get_qualified(module, type_name) 
    6570    except (ImportError, AttributeError), ex: 
    66         raise ValueError("""Invalid descriptor type '{}.{}\ 
    67         """.format(module, type_name)) 
    68          
     71        raise ValueError("Invalid descriptor type '{}.{}" 
     72                         "".format(module, type_name)) 
     73 
    6974    var = type(name, **dict(list(kwargs))) 
    7075    var.attributes.update(attrs) 
    7176    return var 
    72      
     77 
    7378from PyQt4 import QtCore, QtGui 
    7479 
    7580QtCore.Slot = QtCore.pyqtSlot 
    7681QtCore.Signal = QtCore.pyqtSignal 
     82 
    7783 
    7884class PyStandardItem(QStandardItem): 
    7985    def __lt__(self, other): 
    8086        return id(self) < id(other) 
    81      
     87 
     88 
    8289class DictItemsModel(QStandardItemModel): 
    8390    """A Qt Item Model class displaying the contents of a python 
    8491    dictionary. 
    85      
     92 
    8693    """ 
    8794    # Implement a proper model with in-place editing. 
     
    9198        self.setHorizontalHeaderLabels(["Key", "Value"]) 
    9299        self.set_dict(dict) 
    93          
     100 
    94101    def set_dict(self, dict): 
    95102        self._dict = dict 
     
    102109            value_item.setFlags(value_item.flags() | Qt.ItemIsEditable) 
    103110            self.appendRow([key_item, value_item]) 
    104              
     111 
    105112    def get_dict(self): 
    106113        dict = {} 
     
    111118        return dict 
    112119 
     120 
    113121class VariableEditor(QWidget): 
    114122    """An editor widget for a variable. 
    115      
     123 
    116124    Can edit the variable name, and its attributes dictionary. 
    117       
     125 
    118126    """ 
    119127    def __init__(self, parent=None): 
    120128        QWidget.__init__(self, parent) 
    121129        self.setup_gui() 
    122          
     130 
    123131    def setup_gui(self): 
    124132        layout = QVBoxLayout() 
    125133        self.setLayout(layout) 
    126          
     134 
    127135        self.main_form = QFormLayout() 
    128136        self.main_form.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) 
    129137        layout.addLayout(self.main_form) 
    130          
     138 
    131139        self._setup_gui_name() 
    132140        self._setup_gui_labels() 
    133          
     141 
    134142    def _setup_gui_name(self): 
    135143        self.name_edit = QLineEdit() 
    136144        self.main_form.addRow("Name", self.name_edit) 
    137145        self.name_edit.editingFinished.connect(self.on_name_changed) 
    138          
     146 
    139147    def _setup_gui_labels(self): 
    140148        vlayout = QVBoxLayout() 
    141149        vlayout.setContentsMargins(0, 0, 0, 0) 
    142150        vlayout.setSpacing(1) 
    143          
     151 
    144152        self.labels_edit = QTreeView() 
    145153        self.labels_edit.setEditTriggers(QTreeView.CurrentChanged) 
    146154        self.labels_edit.setRootIsDecorated(False) 
    147          
     155 
    148156        self.labels_model = DictItemsModel() 
    149157        self.labels_edit.setModel(self.labels_model) 
    150          
    151         self.labels_edit.selectionModel().selectionChanged.connect(\ 
    152                                     self.on_label_selection_changed) 
    153          
     158 
     159        self.labels_edit.selectionModel().selectionChanged.connect( 
     160            self.on_label_selection_changed) 
     161 
    154162        # Necessary signals to know when the labels change 
    155163        self.labels_model.dataChanged.connect(self.on_labels_changed) 
    156164        self.labels_model.rowsInserted.connect(self.on_labels_changed) 
    157165        self.labels_model.rowsRemoved.connect(self.on_labels_changed) 
    158          
     166 
    159167        vlayout.addWidget(self.labels_edit) 
    160168        hlayout = QHBoxLayout() 
     
    172180                        enabled=False, 
    173181                        shortcut=QKeySequence(QKeySequence.Delete)) 
    174          
     182 
    175183        button_size = OWGUI.toolButtonSizeHint() 
    176184        button_size = QSize(button_size, button_size) 
    177          
     185 
    178186        button = QToolButton(self) 
    179187        button.setFixedSize(button_size) 
    180188        button.setDefaultAction(self.add_label_action) 
    181189        hlayout.addWidget(button) 
    182          
     190 
    183191        button = QToolButton(self) 
    184192        button.setFixedSize(button_size) 
     
    187195        hlayout.addStretch(10) 
    188196        vlayout.addLayout(hlayout) 
    189          
     197 
    190198        self.main_form.addRow("Labels", vlayout) 
    191          
     199 
    192200    def set_data(self, var): 
    193201        """Set the variable to edit. 
     
    195203        self.clear() 
    196204        self.var = var 
    197          
     205 
    198206        if var is not None: 
    199207            self.name_edit.setText(var.name) 
     
    203211            self.add_label_action.setEnabled(False) 
    204212            self.remove_label_action.setEnabled(False) 
    205              
     213 
    206214    def get_data(self): 
    207215        """Retrieve the modified variable. 
     
    209217        name = str(self.name_edit.text()) 
    210218        labels = self.labels_model.get_dict() 
    211          
    212         # Is the variable actually changed.  
     219 
     220        # Is the variable actually changed. 
    213221        if not self.is_same(): 
    214222            var = type(self.var)(name) 
     
    217225        else: 
    218226            var = self.var 
    219          
     227 
    220228        return var 
    221      
     229 
    222230    def is_same(self): 
    223         """Is the current model state the same as the input.  
     231        """Is the current model state the same as the input. 
    224232        """ 
    225233        name = str(self.name_edit.text()) 
    226234        labels = self.labels_model.get_dict() 
    227          
     235 
    228236        return self.var and name == self.var.name and labels == self.var.attributes 
    229              
     237 
    230238    def clear(self): 
    231239        """Clear the editor state. 
     
    234242        self.name_edit.setText("") 
    235243        self.labels_model.set_dict({}) 
    236          
     244 
    237245    def maybe_commit(self): 
    238246        if not self.is_same(): 
    239247            self.commit() 
    240              
     248 
    241249    def commit(self): 
    242250        """Emit a ``variable_changed()`` signal. 
    243251        """ 
    244252        self.emit(SIGNAL("variable_changed()")) 
    245          
     253 
    246254    @QtCore.Slot() 
    247255    def on_name_changed(self): 
    248256        self.maybe_commit() 
    249          
     257 
    250258    @QtCore.Slot() 
    251259    def on_labels_changed(self, *args): 
    252260        self.maybe_commit() 
    253          
     261 
    254262    @QtCore.Slot() 
    255263    def on_add_label(self): 
     
    258266        index = self.labels_model.index(row, 0) 
    259267        self.labels_edit.edit(index) 
    260          
     268 
    261269    @QtCore.Slot() 
    262270    def on_remove_label(self): 
     
    265273            row = rows[0] 
    266274            self.labels_model.removeRow(row.row()) 
    267      
     275 
    268276    @QtCore.Slot() 
    269277    def on_label_selection_changed(self): 
    270278        selected = self.labels_edit.selectionModel().selectedRows() 
    271279        self.remove_label_action.setEnabled(bool(len(selected))) 
    272          
    273          
     280 
     281 
    274282class DiscreteVariableEditor(VariableEditor): 
    275283    """An editor widget for editing a discrete variable. 
    276      
     284 
    277285    Extends the :class:`VariableEditor` to enable editing of 
    278286    variables values. 
    279      
     287 
    280288    """ 
    281289    def setup_gui(self): 
    282290        layout = QVBoxLayout() 
    283291        self.setLayout(layout) 
    284          
     292 
    285293        self.main_form = QFormLayout() 
    286294        self.main_form.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) 
    287295        layout.addLayout(self.main_form) 
    288          
     296 
    289297        self._setup_gui_name() 
    290298        self._setup_gui_values() 
    291299        self._setup_gui_labels() 
    292          
     300 
    293301    def _setup_gui_values(self): 
    294302        self.values_edit = QListView() 
     
    297305                                        Qt.ItemIsEnabled | Qt.ItemIsEditable) 
    298306        self.values_edit.setModel(self.values_model) 
    299          
     307 
    300308        self.values_model.dataChanged.connect(self.on_values_changed) 
    301309        self.main_form.addRow("Values", self.values_edit) 
     
    309317            for v in var.values: 
    310318                self.values_model.append(v) 
    311                  
     319 
    312320    def get_data(self): 
    313321        """Retrieve the modified variable 
     
    316324        labels = self.labels_model.get_dict() 
    317325        values = map(str, self.values_model) 
    318          
     326 
    319327        if not self.is_same(): 
    320328            var = type(self.var)(name, values=values) 
     
    323331        else: 
    324332            var = self.var 
    325              
     333 
    326334        return var 
    327              
     335 
    328336    def is_same(self): 
    329         """Is the current model state the same as the input.  
     337        """Is the current model state the same as the input. 
    330338        """ 
    331339        values = map(str, self.values_model) 
    332340        return VariableEditor.is_same(self) and self.var.values == values 
    333      
     341 
    334342    def clear(self): 
    335343        """Clear the model state. 
     
    337345        VariableEditor.clear(self) 
    338346        self.values_model.wrap([]) 
    339          
     347 
    340348    @QtCore.Slot() 
    341349    def on_values_changed(self): 
    342350        self.maybe_commit() 
    343          
    344          
     351 
     352 
    345353class ContinuousVariableEditor(VariableEditor): 
    346     #TODO: enable editing of number_of_decimals, scientific format ... 
    347     pass  
     354    # TODO: enable editing of number_of_decimals, scientific format ... 
     355    pass 
    348356 
    349357 
    350358class OWEditDomain(OWWidget): 
    351     contextHandlers = {"": DomainContextHandler("", ["domain_change_hints", "selected_index"])} 
     359    contextHandlers = { 
     360        "": DomainContextHandler( 
     361            "", 
     362            ["domain_change_hints", "selected_index"] 
     363        ) 
     364    } 
    352365    settingsList = ["auto_commit"] 
    353      
     366 
    354367    def __init__(self, parent=None, signalManager=None, title="Edit Domain"): 
    355368        OWWidget.__init__(self, parent, signalManager, title) 
    356          
     369 
    357370        self.inputs = [("Data", Orange.data.Table, self.set_data)] 
    358371        self.outputs = [("Data", Orange.data.Table)] 
    359          
     372 
    360373        # Settings 
    361          
     374 
    362375        # Domain change hints maps from input variables description to 
    363376        # the modified variables description as returned by 
     
    367380        self.auto_commit = False 
    368381        self.changed_flag = False 
    369          
     382 
    370383        self.loadSettings() 
    371          
     384 
    372385        ##### 
    373386        # GUI 
    374387        ##### 
    375      
     388 
    376389        # The list of domain's variables. 
    377390        box = OWGUI.widgetBox(self.controlArea, "Domain Features") 
    378391        self.domain_view = QListView() 
    379392        self.domain_view.setSelectionMode(QListView.SingleSelection) 
    380          
     393 
    381394        self.domain_model = VariableListModel() 
    382          
     395 
    383396        self.domain_view.setModel(self.domain_model) 
    384          
     397 
    385398        self.connect(self.domain_view.selectionModel(), 
    386399                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), 
    387400                     self.on_selection_changed) 
    388          
     401 
    389402        box.layout().addWidget(self.domain_view) 
    390          
     403 
    391404        # A stack for variable editor widgets. 
    392405        box = OWGUI.widgetBox(self.mainArea, "Edit Feature") 
    393406        self.editor_stack = QStackedWidget() 
    394407        box.layout().addWidget(self.editor_stack) 
    395          
    396          
     408 
    397409        box = OWGUI.widgetBox(self.controlArea, "Reset") 
    398          
     410 
    399411        OWGUI.button(box, self, "Reset selected", 
    400412                     callback=self.reset_selected, 
    401413                     tooltip="Reset changes made to the selected feature" 
    402414                     ) 
    403          
     415 
    404416        OWGUI.button(box, self, "Reset all", 
    405417                     callback=self.reset_all, 
    406418                     tooltip="Reset all changes made to the domain" 
    407419                     ) 
    408          
     420 
    409421        box = OWGUI.widgetBox(self.controlArea, "Commit") 
    410          
     422 
    411423        b = OWGUI.button(box, self, "&Commit", 
    412424                         callback=self.commit, 
    413425                         tooltip="Commit the data with the changed domain", 
    414426                         ) 
    415          
     427 
    416428        cb = OWGUI.checkBox(box, self, "auto_commit", 
    417429                            label="Commit automatically", 
    418430                            tooltip="Commit the changed domain on any change", 
    419431                            callback=self.commit_if) 
    420          
     432 
    421433        OWGUI.setStopper(self, b, cb, "changed_flag", 
    422434                         callback=self.commit) 
    423          
     435 
    424436        self._editor_cache = {} 
    425          
     437 
    426438        self.resize(600, 500) 
    427          
     439 
    428440    def clear(self): 
    429441        """Clear the widget state. 
     
    433445        self.domain_change_hints = {} 
    434446        self.clear_editor() 
    435          
     447 
    436448    def clear_editor(self): 
    437449        """Clear the current editor widget 
     
    442454                               self.on_variable_changed) 
    443455            current.set_data(None) 
    444          
     456 
    445457    def set_data(self, data=None): 
    446458        self.closeContext("") 
     
    449461        if data is not None: 
    450462            input_domain = data.domain 
    451             all_vars = list(input_domain.variables) + \ 
    452                        input_domain.getmetas().values() 
    453              
     463            all_vars = (list(input_domain.variables) + 
     464                        list(input_domain.class_vars) + 
     465                        input_domain.getmetas().values()) 
     466 
    454467            self.openContext("", data) 
    455              
     468 
    456469            edited_vars = [] 
    457              
    458             # Apply any saved transformations as listed in  
     470 
     471            # Apply any saved transformations as listed in 
    459472            # `domain_change_hints` 
    460               
     473 
    461474            for var in all_vars: 
    462475                desc = variable_description(var) 
     
    468481#                        print ex 
    469482                        new = None 
    470                          
     483 
    471484                    if new is not None: 
    472485                        # Make sure orange's domain transformations will work. 
     
    474487                        new.get_value_from = Orange.core.ClassifierFromVar(whichVar=var) 
    475488                        var = new 
    476                          
     489 
    477490                edited_vars.append(var) 
    478              
     491 
    479492            self.all_vars = all_vars 
    480493            self.input_domain = input_domain 
    481              
     494 
    482495            # Sets the model to display in the 'Domain Features' view 
    483496            self.domain_model[:] = edited_vars 
    484              
     497 
    485498            # Try to restore the variable selection 
    486499            index = self.selected_index 
     
    489502            if index >= 0: 
    490503                self.select_variable(index) 
    491          
     504 
    492505            self.changed_flag = True 
    493506            self.commit_if() 
     
    495508            # To force send None on output 
    496509            self.commit() 
    497              
     510 
    498511    def on_selection_changed(self, *args): 
    499         """When selection in 'Domain Features' view changes.  
     512        """When selection in 'Domain Features' view changes. 
    500513        """ 
    501514        i = self.selected_var_index() 
     
    503516            self.open_editor(i) 
    504517            self.selected_index = i 
    505          
     518 
    506519    def selected_var_index(self): 
    507         """Return the selected row in 'Domain Features' view or None  
     520        """Return the selected row in 'Domain Features' view or None 
    508521        if no row is selected. 
    509          
     522 
    510523        """ 
    511524        rows = self.domain_view.selectionModel().selectedRows() 
     
    514527        else: 
    515528            return None 
    516          
     529 
    517530    def select_variable(self, index): 
    518531        """Select the variable with ``index`` in the 'Domain Features' 
    519532        view. 
    520          
     533 
    521534        """ 
    522535        sel_model = self.domain_view.selectionModel() 
    523536        sel_model.select(self.domain_model.index(index, 0), 
    524537                         QItemSelectionModel.ClearAndSelect) 
    525          
     538 
    526539    def open_editor(self, index): 
    527540        """Open the editor for variable at ``index`` and move it 
    528541        to the top if the stack. 
    529          
     542 
    530543        """ 
    531544        # First remove and clear the current editor if any 
    532545        self.clear_editor() 
    533              
     546 
    534547        var = self.domain_model[index] 
    535          
     548 
    536549        editor = self.editor_for_variable(var) 
    537550        editor.set_data(var) 
    538551        self.edited_variable_index = index 
    539          
     552 
    540553        QObject.connect(editor, SIGNAL("variable_changed()"), 
    541554                        self.on_variable_changed) 
    542555        self.editor_stack.setCurrentWidget(editor) 
    543      
     556 
    544557    def editor_for_variable(self, var): 
    545558        """Return the editor for ``var``'s variable type. 
    546          
     559 
    547560        The editors are cached and reused by type. 
    548            
     561 
    549562        """ 
    550563        editor = None 
     
    555568        else: 
    556569            editor = VariableEditor 
    557              
     570 
    558571        if type(var) not in self._editor_cache: 
    559572            editor = editor() 
    560573            self._editor_cache[type(var)] = editor 
    561574            self.editor_stack.addWidget(editor) 
    562              
     575 
    563576        return self._editor_cache[type(var)] 
    564      
     577 
    565578    def on_variable_changed(self): 
    566579        """When the user edited the current variable in editor. 
     
    569582        editor = self.editor_stack.currentWidget() 
    570583        new_var = editor.get_data() 
    571          
     584 
    572585        # Replace the variable in the 'Domain Features' view/model 
    573586        self.domain_model[self.edited_variable_index] = new_var 
    574587        old_var = self.all_vars[self.edited_variable_index] 
    575          
     588 
    576589        # Store the transformation hint. 
    577590        self.domain_change_hints[variable_description(old_var)] = \ 
     
    581594        new_var.source_variable = old_var 
    582595        new_var.get_value_from = Orange.core.ClassifierFromVar(whichVar=old_var) 
    583          
     596 
    584597        self.commit_if() 
    585           
     598 
    586599    def reset_all(self): 
    587600        """Reset all variables to the input state. 
     
    595608            self.select_variable(self.selected_index) 
    596609            self.commit_if() 
    597              
     610 
    598611    def reset_selected(self): 
    599612        """Reset the currently selected variable to its original 
    600613        state. 
    601            
     614 
    602615        """ 
    603616        if self.data is not None: 
     
    606619            if desc in self.domain_change_hints: 
    607620                del self.domain_change_hints[desc] 
    608              
     621 
    609622            # To invalidate stored hints 
    610623            self.closeContext("") 
    611624            self.openContext("", self.data) 
    612              
     625 
    613626            self.domain_model[self.selected_index] = var 
    614627            self.editor_stack.currentWidget().set_data(var) 
    615628            self.commit_if() 
    616              
     629 
    617630    def commit_if(self): 
    618631        if self.auto_commit: 
     
    620633        else: 
    621634            self.changed_flag = True 
    622          
     635 
    623636    def commit(self): 
    624         """Commit the changed data to output.  
     637        """Commit the changed data to output. 
    625638        """ 
    626639        new_data = None 
    627640        if self.data is not None: 
    628             new_vars = list(self.domain_model) 
    629             variables = new_vars[: len(self.input_domain.variables)] 
     641            n_vars = len(self.input_domain.variables) 
     642            n_class_vars = len(self.input_domain.class_vars) 
     643            all_new_vars = list(self.domain_model) 
     644            variables = all_new_vars[: n_vars] 
    630645            class_var = None 
    631646            if self.input_domain.class_var: 
    632647                class_var = variables[-1] 
    633                 variables = variables[:-1] 
    634              
    635             new_metas = new_vars[len(self.input_domain.variables) :] 
    636             new_domain = Orange.data.Domain(variables, class_var) 
    637              
     648                attributes = variables[:-1] 
     649            else: 
     650                attributes = variables 
     651 
     652            class_vars = all_new_vars[n_vars: n_vars + n_class_vars] 
     653            new_metas = all_new_vars[n_vars + n_class_vars:] 
     654            new_domain = Orange.data.Domain(attributes, class_var, 
     655                                            class_vars=class_vars) 
     656 
    638657            # Assumes getmetas().items() order has not changed. 
    639658            # TODO: store metaids in set_data method 
    640             for (mid, _), new in zip(self.input_domain.getmetas().items(),  
    641                                        new_metas): 
     659            for (mid, _), new in zip(self.input_domain.getmetas().items(), 
     660                                     new_metas): 
    642661                new_domain.addmeta(mid, new) 
    643                  
     662 
    644663            new_data = Orange.data.Table(new_domain, self.data) 
    645          
     664 
    646665        self.send("Data", new_data) 
    647666        self.changed_flag = False 
    648              
    649          
     667 
     668 
    650669def main(): 
    651670    import sys 
     
    660679    w.saveSettings() 
    661680    return rval 
    662          
     681 
    663682if __name__ == "__main__": 
    664683    import sys 
    665684    sys.exit(main()) 
    666      
  • Orange/OrangeWidgets/Data/OWPythonScript.py

    r11364 r11434  
    344344 
    345345    settingsList = ["codeFile", "libraryListSource", "currentScriptIndex", 
    346                     "splitterState"] 
     346                    "splitterState", "auto_execute"] 
    347347 
    348348    def __init__(self, parent=None, signalManager=None): 
    349349        OWWidget.__init__(self, parent, signalManager, 'Python Script') 
    350350 
    351         self.inputs = [("in_data", Orange.data.Table, self.setExampleTable), 
     351        self.inputs = [("in_data", Orange.data.Table, self.setExampleTable, 
     352                        Default), 
    352353                       ("in_distance", Orange.misc.SymMatrix, 
    353                         self.setDistanceMatrix), 
    354                        ("in_learner", Orange.core.Learner, self.setLearner), 
     354                        self.setDistanceMatrix, Default), 
     355                       ("in_learner", Orange.core.Learner, self.setLearner, 
     356                        Default), 
    355357                       ("in_classifier", Orange.core.Classifier, 
    356                         self.setClassifier), 
     358                        self.setClassifier, Default), 
    357359                       ("in_object", object, self.setObject)] 
    358360 
  • Orange/OrangeWidgets/OWDatabasesUpdate.py

    r10979 r11437  
    1 from __future__ import with_statement  
    2 import sys, os 
    3 import orngServerFiles 
    4 import orngEnviron 
    5 import threading 
     1from __future__ import with_statement 
     2 
     3import os 
     4import sys 
     5 
     6from datetime import datetime 
     7 
     8import Orange 
     9 
     10from Orange.utils import serverfiles, environ 
     11from Orange.utils.serverfiles import sizeformat as sizeof_fmt 
     12 
    613from OWWidget import * 
    7 from functools import partial 
    8 from datetime import datetime 
    9  
    10 import gzip, sys 
    11  
    12 def sizeof_fmt(num): 
    13     for x in ['bytes','KB','MB','GB','TB']: 
    14         if num < 1024.0: 
    15             return "%3.1f %s" % (num, x) if x <> 'bytes' else "%1.0f %s" % (num, x) 
    16         num /= 1024.0 
    17  
    18         
     14from OWConcurrent import * 
     15 
     16import OWGUIEx 
     17 
     18 
    1919class ItemProgressBar(QProgressBar): 
     20    """Progress Bar with and `advance()` slot. 
     21    """ 
    2022    @pyqtSignature("advance()") 
    2123    def advance(self): 
    2224        self.setValue(self.value() + 1) 
    23     
    24          
     25 
     26 
    2527class ProgressBarRedirect(QObject): 
    2628    def __init__(self, parent, redirect): 
     
    2830        self.redirect = redirect 
    2931        self._delay = False 
    30          
     32 
    3133    @pyqtSignature("advance()") 
    3234    def advance(self): 
    33         # delay OWBaseWidget.progressBarSet call, because it calls qApp.processEvents 
    34         #which can result in 'event queue climbing' and max. recursion error if GUI thread 
    35         #gets another advance signal before it finishes with this one 
     35        # delay OWBaseWidget.progressBarSet call, because it calls 
     36        # qApp.processEvents which can result in 'event queue climbing' 
     37        # and max. recursion error if GUI thread gets another advance 
     38        # signal before it finishes with this one 
    3639        if not self._delay: 
    3740            try: 
     
    4346            QTimer.singleShot(10, self.advance) 
    4447 
    45          
    46 from OWConcurrent import * 
    47          
     48_icons_dir = os.path.join(environ.canvas_install_dir, "icons") 
     49 
     50 
     51def icon(name): 
     52    return QIcon(os.path.join(_icons_dir, name)) 
     53 
     54 
    4855class UpdateOptionsWidget(QWidget): 
     56    """ 
     57    A Widget with download/update/remove options. 
     58    """ 
    4959    def __init__(self, updateCallback, removeCallback, state, *args): 
    5060        QWidget.__init__(self, *args) 
     
    5565        layout.setContentsMargins(1, 1, 1, 1) 
    5666        self.updateButton = QToolButton(self) 
    57         self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
     67        self.updateButton.setIcon(icon("update.png")) 
    5868        self.updateButton.setToolTip("Download") 
    59 #        self.updateButton.setIconSize(QSize(10, 10)) 
     69 
    6070        self.removeButton = QToolButton(self) 
    61         self.removeButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "delete.png"))) 
     71        self.removeButton.setIcon(icon("delete.png")) 
    6272        self.removeButton.setToolTip("Remove from system") 
    63 #        self.removeButton.setIconSize(QSize(10, 10)) 
    64         self.connect(self.updateButton, SIGNAL("released()"), self.updateCallback) 
    65         self.connect(self.removeButton, SIGNAL("released()"), self.removeCallback) 
     73 
     74        self.connect(self.updateButton, SIGNAL("released()"), 
     75                     self.updateCallback) 
     76        self.connect(self.removeButton, SIGNAL("released()"), 
     77                     self.removeCallback) 
     78 
    6679        self.setMaximumHeight(30) 
    6780        layout.addWidget(self.updateButton) 
     
    7386        self.state = state 
    7487        if state == 0: 
    75             self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update1.png"))) 
     88            self.updateButton.setIcon(icon("update1.png")) 
    7689            self.updateButton.setToolTip("Update") 
    7790            self.updateButton.setEnabled(False) 
    7891            self.removeButton.setEnabled(True) 
    7992        elif state == 1: 
    80             self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update1.png"))) 
     93            self.updateButton.setIcon(icon("update1.png")) 
    8194            self.updateButton.setToolTip("Update") 
    8295            self.updateButton.setEnabled(True) 
    8396            self.removeButton.setEnabled(True) 
    8497        elif state == 2: 
    85             self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
     98            self.updateButton.setIcon(icon("update.png")) 
    8699            self.updateButton.setToolTip("Download") 
    87100            self.updateButton.setEnabled(True) 
    88101            self.removeButton.setEnabled(False) 
    89102        elif state == 3: 
    90             self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
     103            self.updateButton.setIcon(icon("update.png")) 
    91104            self.updateButton.setToolTip("") 
    92105            self.updateButton.setEnabled(False) 
    93106            self.removeButton.setEnabled(True) 
     107        else: 
     108            raise ValueError("Invalid state %r" % state) 
    94109 
    95110 
    96111class UpdateTreeWidgetItem(QTreeWidgetItem): 
    97     stateDict = {0:"up-to-date", 1:"new version available", 2:"not downloaded", 3:"obsolete"} 
    98     def __init__(self, master, treeWidget, domain, filename, infoLocal, infoServer, *args): 
     112    stateDict = {0: "up-to-date", 
     113                 1: "new version available", 
     114                 2: "not downloaded", 
     115                 3: "obsolete"} 
     116 
     117    def __init__(self, master, treeWidget, domain, filename, infoLocal, 
     118                 infoServer, *args): 
     119        dateServer = dateLocal = None 
     120        if infoServer: 
     121            dateServer = datetime.strptime( 
     122                infoServer["datetime"].split(".")[0], "%Y-%m-%d %H:%M:%S" 
     123            ) 
     124        if infoLocal: 
     125            dateLocal = datetime.strptime( 
     126                infoLocal["datetime"].split(".")[0], "%Y-%m-%d %H:%M:%S" 
     127            ) 
    99128        if not infoLocal: 
    100129            self.state = 2 
     
    102131            self.state = 3 
    103132        else: 
    104             dateServer = datetime.strptime(infoServer["datetime"].split(".")[0], "%Y-%m-%d %H:%M:%S") 
    105             dateLocal = datetime.strptime(infoLocal["datetime"].split(".")[0], "%Y-%m-%d %H:%M:%S") 
    106133            self.state = 0 if dateLocal >= dateServer else 1 
     134 
    107135        title = infoServer["title"] if infoServer else (infoLocal["title"]) 
    108136        tags = infoServer["tags"] if infoServer else infoLocal["tags"] 
    109         specialTags = dict([tuple(tag.split(":")) for tag in tags if tag.startswith("#") and ":" in tag]) 
     137        specialTags = dict([tuple(tag.split(":")) 
     138                            for tag in tags 
     139                            if tag.startswith("#") and ":" in tag]) 
    110140        tags = ", ".join(tag for tag in tags if not tag.startswith("#")) 
    111141        self.size = infoServer["size"] if infoServer else infoLocal["size"] 
    112 #        if self.state == 2 or self.state == 1: 
    113 #            size = sizeof_fmt(float(self.size)) + (" (%s uncompressed)" % sizeof_fmt(float(specialTags["#uncompressed"])) if "#uncompressed" in specialTags else "") 
    114 #        else: 
    115 #            size = sizeof_fmt(float(specialTags.get("#uncompressed", self.size))) 
     142 
    116143        size = sizeof_fmt(float(self.size)) 
    117         state = self.stateDict[self.state] + (dateServer.strftime(" (%Y, %b, %d)") if self.state == 1 else "") 
     144        state = self.stateDict[self.state] 
     145        if self.state == 1: 
     146            state += dateServer.strftime(" (%Y, %b, %d)") 
     147 
    118148        QTreeWidgetItem.__init__(self, treeWidget, ["", title, size]) 
    119         self.updateWidget = UpdateOptionsWidget(self.StartDownload, self.Remove, self.state, treeWidget) 
     149        if dateServer is not None: 
     150            self.setData(3, Qt.DisplayRole, 
     151                         dateServer.date().isoformat()) 
     152 
     153        self.updateWidget = UpdateOptionsWidget( 
     154            self.StartDownload, self.Remove, self.state, treeWidget 
     155        ) 
     156 
    120157        self.treeWidget().setItemWidget(self, 0, self.updateWidget) 
    121158        self.updateWidget.show() 
     
    126163        self.domain = domain 
    127164        self.filename = filename 
    128 ##        for i in range(1, 5): 
    129 ##            self.setSizeHint(i, QSize(self.sizeHint(i).width(), self.sizeHint(0).height())) 
    130165        self.UpdateToolTip() 
    131166 
    132167    def UpdateToolTip(self): 
    133         state = {0:"local, updated", 1:"local, needs update", 2:"on server, download for local use", 3:"obsolete"} 
    134         tooltip = "State: %s\nTags: %s" % (state[self.state], ", ".join(self.tags)) 
     168        state = {0: "local, updated", 
     169                 1: "local, needs update", 
     170                 2: "on server, download for local use", 
     171                 3: "obsolete"} 
     172        tooltip = "State: %s\nTags: %s" % (state[self.state], 
     173                                           ", ".join(self.tags)) 
    135174        if self.state != 2: 
    136             tooltip += "\nFile: %s" % orngServerFiles.localpath(self.domain, self.filename) 
     175            tooltip += ("\nFile: %s" % 
     176                        serverfiles.localpath(self.domain, self.filename)) 
    137177        for i in range(1, 5): 
    138178            self.setToolTip(i, tooltip) 
    139          
     179 
    140180    def StartDownload(self): 
    141181        self.updateWidget.removeButton.setEnabled(False) 
    142182        self.updateWidget.updateButton.setEnabled(False) 
    143183        self.setData(2, Qt.DisplayRole, QVariant("")) 
    144         serverFiles = orngServerFiles.ServerFiles(access_code=self.master.accessCode if self.master.accessCode else None)  
    145          
     184        serverFiles = serverfiles.ServerFiles( 
     185            access_code=self.master.accessCode if self.master.accessCode 
     186            else None 
     187        ) 
     188 
    146189        pb = ItemProgressBar(self.treeWidget()) 
    147190        pb.setRange(0, 100) 
    148191        pb.setTextVisible(False) 
    149          
     192 
    150193        self.task = AsyncCall(threadPool=QThreadPool.globalInstance()) 
    151          
     194 
    152195        if not getattr(self.master, "_sum_progressBar", None): 
    153             self.master._sum_progressBar = OWGUI.ProgressBar(self.master,0) 
     196            self.master._sum_progressBar = OWGUI.ProgressBar(self.master, 0) 
    154197            self.master._sum_progressBar.in_progress = 0 
    155198        master_pb = self.master._sum_progressBar 
    156199        master_pb.iter += 100 
    157200        master_pb.in_progress += 1 
    158         self._progressBarRedirect = ProgressBarRedirect(QThread.currentThread(), master_pb) 
    159 #        QObject.connect(self.thread, SIGNAL("advance()"), lambda :(pb.setValue(pb.value()+1), master_pb.advance())) 
    160         QObject.connect(self.task, SIGNAL("advance()"), pb.advance, Qt.QueuedConnection) 
    161         QObject.connect(self.task, SIGNAL("advance()"), self._progressBarRedirect.advance, Qt.QueuedConnection) 
    162         QObject.connect(self.task, SIGNAL("finished(QString)"), self.EndDownload, Qt.QueuedConnection) 
     201        self._progressBarRedirect = \ 
     202            ProgressBarRedirect(QThread.currentThread(), master_pb) 
     203        QObject.connect(self.task, 
     204                        SIGNAL("advance()"), 
     205                        pb.advance, 
     206                        Qt.QueuedConnection) 
     207        QObject.connect(self.task, 
     208                        SIGNAL("advance()"), 
     209                        self._progressBarRedirect.advance, 
     210                        Qt.QueuedConnection) 
     211        QObject.connect(self.task, 
     212                        SIGNAL("finished(QString)"), 
     213                        self.EndDownload, 
     214                        Qt.QueuedConnection) 
    163215        self.treeWidget().setItemWidget(self, 2, pb) 
    164216        pb.show() 
    165          
    166         self.task.apply_async(orngServerFiles.download, args=(self.domain, self.filename, serverFiles), kwargs=dict(callback=self.task.emitAdvance)) 
     217 
     218        self.task.apply_async(serverfiles.download, 
     219                              args=(self.domain, self.filename, serverFiles), 
     220                              kwargs=dict(callback=self.task.emitAdvance)) 
    167221 
    168222    def EndDownload(self, exitCode=0): 
     
    171225            self.state = 0 
    172226            self.updateWidget.SetState(self.state) 
    173             self.setData(2, Qt.DisplayRole, QVariant(sizeof_fmt(float(self.size)))) 
     227            self.setData(2, Qt.DisplayRole, 
     228                         QVariant(sizeof_fmt(float(self.size)))) 
    174229            self.master.UpdateInfoLabel() 
    175230            self.UpdateToolTip() 
    176231        else: 
    177232            self.updateWidget.SetState(1) 
    178             self.setData(2, Qt.DisplayRole, QVariant("Error occured while downloading:" + str(exitCode))) 
    179              
     233            self.setData(2, Qt.DisplayRole, 
     234                         QVariant("Error occurred while downloading:" + 
     235                                  str(exitCode))) 
     236 
    180237        master_pb = self.master._sum_progressBar 
    181 #        print master_pb.in_progress 
     238 
    182239        if master_pb and master_pb.in_progress == 1: 
    183240            master_pb.finish() 
     
    185242        elif master_pb: 
    186243            master_pb.in_progress -= 1 
    187          
    188 #        self.thread, self._runnable = None, None 
    189              
     244 
    190245    def Remove(self): 
    191         orngServerFiles.remove(self.domain, self.filename) 
     246        serverfiles.remove(self.domain, self.filename) 
    192247        self.state = 2 
    193248        self.updateWidget.SetState(self.state) 
     
    196251 
    197252    def __contains__(self, item): 
    198         return any(item.lower() in tag.lower() for tag in self.tags + [self.title]) 
    199      
     253        return any(item.lower() in tag.lower() 
     254                   for tag in self.tags + [self.title]) 
     255 
    200256    def __lt__(self, other): 
    201         return getattr(self, "title", "") < getattr(other, "title", "")  
     257        return getattr(self, "title", "") < getattr(other, "title", "") 
     258 
    202259 
    203260class UpdateItemDelegate(QItemDelegate): 
     
    208265        widget = parent.itemWidget(item, 0) 
    209266        if widget: 
    210             size = QSize(size.width(), widget.sizeHint().height()/2) 
     267            size = QSize(size.width(), widget.sizeHint().height() / 2) 
    211268        return size 
    212      
     269 
     270 
    213271def retrieveFilesList(serverFiles, domains=None, advance=lambda: None): 
     272    """ 
     273    Retrieve and return serverfiles.allinfo for all domains. 
     274    """ 
    214275    domains = serverFiles.listdomains() if domains is None else domains 
    215276    advance() 
     
    217278    advance() 
    218279    return serverInfo 
    219      
     280 
     281 
    220282class OWDatabasesUpdate(OWWidget): 
    221     def __init__(self, parent=None, signalManager=None, name="Databases update", wantCloseButton=False, searchString="", showAll=True, domains=None, accessCode=""): 
     283    def __init__(self, parent=None, signalManager=None, 
     284                 name="Databases update", wantCloseButton=False, 
     285                 searchString="", showAll=True, domains=None, 
     286                 accessCode=""): 
    222287        OWWidget.__init__(self, parent, signalManager, name) 
    223288        self.searchString = searchString 
     
    225290        self.showAll = showAll 
    226291        self.domains = domains 
    227         self.serverFiles = orngServerFiles.ServerFiles() 
     292        self.serverFiles = serverfiles.ServerFiles() 
    228293        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    229         import OWGUIEx 
    230         self.lineEditFilter = OWGUIEx.lineEditHint(box, self, "searchString", "Filter", caseSensitive=False, delimiters=" ", matchAnywhere=True, listUpdateCallback=self.SearchUpdate, callbackOnType=True, callback=self.SearchUpdate) 
     294 
     295        self.lineEditFilter = \ 
     296            OWGUIEx.lineEditHint(box, self, "searchString", "Filter", 
     297                                 caseSensitive=False, 
     298                                 delimiters=" ", 
     299                                 matchAnywhere=True, 
     300                                 listUpdateCallback=self.SearchUpdate, 
     301                                 callbackOnType=True, 
     302                                 callback=self.SearchUpdate) 
    231303 
    232304        box = OWGUI.widgetBox(self.mainArea, "Files") 
    233305        self.filesView = QTreeWidget(self) 
    234         self.filesView.setHeaderLabels(["Options", "Title", "Size"]) 
     306        self.filesView.setHeaderLabels(["Options", "Title", "Size", 
     307                                        "Last Updated"]) 
    235308        self.filesView.setRootIsDecorated(False) 
    236309        self.filesView.setSelectionMode(QAbstractItemView.NoSelection) 
    237310        self.filesView.setSortingEnabled(True) 
    238311        self.filesView.setItemDelegate(UpdateItemDelegate(self.filesView)) 
    239         self.connect(self.filesView.model(), SIGNAL("layoutChanged()"), self.SearchUpdate) 
     312        self.connect(self.filesView.model(), 
     313                     SIGNAL("layoutChanged()"), 
     314                     self.SearchUpdate) 
    240315        box.layout().addWidget(self.filesView) 
    241316 
    242317        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    243         OWGUI.button(box, self, "Update all local files", callback=self.UpdateAll, tooltip="Update all updatable files") 
    244         OWGUI.button(box, self, "Download filtered", callback=self.DownloadFiltered, tooltip="Download all filtered files shown") 
     318        OWGUI.button(box, self, "Update all local files", 
     319                     callback=self.UpdateAll, 
     320                     tooltip="Update all updatable files") 
     321        OWGUI.button(box, self, "Download filtered", 
     322                     callback=self.DownloadFiltered, 
     323                     tooltip="Download all filtered files shown") 
    245324        OWGUI.rubber(box) 
    246         OWGUI.lineEdit(box, self, "accessCode", "Access Code", orientation="horizontal", callback=self.RetrieveFilesList) 
    247         self.retryButton = OWGUI.button(box, self, "Retry", callback=self.RetrieveFilesList) 
     325        OWGUI.lineEdit(box, self, "accessCode", "Access Code", 
     326                       orientation="horizontal", 
     327                       callback=self.RetrieveFilesList) 
     328        self.retryButton = OWGUI.button(box, self, "Retry", 
     329                                        callback=self.RetrieveFilesList) 
    248330        self.retryButton.hide() 
    249331        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    250332        OWGUI.rubber(box) 
    251333        if wantCloseButton: 
    252             OWGUI.button(box, self, "Close", callback=self.accept, tooltip="Close") 
    253  
    254 ##        statusBar = QStatusBar() 
     334            OWGUI.button(box, self, "Close", 
     335                         callback=self.accept, 
     336                         tooltip="Close") 
     337 
    255338        self.infoLabel = QLabel() 
    256339        self.infoLabel.setAlignment(Qt.AlignCenter) 
    257 ##        statusBar.addWidget(self.infoLabel) 
    258 ##        self.mainArea.layout().addWidget(statusBar) 
     340 
    259341        self.mainArea.layout().addWidget(self.infoLabel) 
    260342        self.infoLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 
     
    262344        self.updateItems = [] 
    263345        self.allTags = [] 
    264          
     346 
    265347        self.resize(800, 600) 
    266          
    267 #        QTimer.singleShot(50, self.UpdateFilesList) 
     348 
    268349        QTimer.singleShot(50, self.RetrieveFilesList) 
    269          
     350 
    270351    def RetrieveFilesList(self): 
    271         self.serverFiles = orngServerFiles.ServerFiles(access_code=self.accessCode) 
     352        self.serverFiles = serverfiles.ServerFiles(access_code=self.accessCode) 
    272353        self.pb = ProgressBar(self, 3) 
    273         self.async_retrieve = createTask(retrieveFilesList, (self.serverFiles, self.domains, self.pb.advance), onResult=self.SetFilesList, onError=self.HandleError) 
    274          
     354        self.async_retrieve = createTask(retrieveFilesList, 
     355                                         (self.serverFiles, self.domains, 
     356                                          self.pb.advance), 
     357                                         onResult=self.SetFilesList, 
     358                                         onError=self.HandleError) 
     359 
    275360        self.setEnabled(False) 
    276          
    277          
     361 
    278362    def SetFilesList(self, serverInfo): 
    279363        self.setEnabled(True) 
    280         domains = serverInfo.keys() or orngServerFiles.listdomains() 
    281         localInfo = dict([(dom, orngServerFiles.allinfo(dom)) for dom in domains]) 
     364        domains = serverInfo.keys() or serverfiles.listdomains() 
     365        localInfo = dict([(dom, serverfiles.allinfo(dom)) 
     366                          for dom in domains]) 
    282367        items = [] 
    283          
     368 
    284369        self.allTags = set() 
    285370        allTitles = set() 
    286371        self.updateItems = [] 
    287          
    288         for i, domain in enumerate(set(domains) - set(["test", "demo"])): 
    289             local = localInfo.get(domain, {})  
    290             server =  serverInfo.get(domain, {}) 
     372 
     373        for domain in set(domains) - set(["test", "demo"]): 
     374            local = localInfo.get(domain, {}) 
     375            server = serverInfo.get(domain, {}) 
    291376            files = sorted(set(server.keys() + local.keys())) 
    292             for j, file in enumerate(files): 
    293                 infoServer = server.get(file, None) 
    294                 infoLocal = local.get(file, None) 
    295                  
    296                 items.append((self.filesView, domain, file, infoLocal, infoServer)) 
    297                  
     377            for filename in files: 
     378                infoServer = server.get(filename, None) 
     379                infoLocal = local.get(filename, None) 
     380 
     381                items.append((self.filesView, domain, filename, infoLocal, 
     382                              infoServer)) 
     383 
    298384                displayInfo = infoServer if infoServer else infoLocal 
    299385                self.allTags.update(displayInfo["tags"]) 
    300386                allTitles.update(displayInfo["title"].split()) 
    301          
    302         for i, item in enumerate(items): 
     387 
     388        for item in items: 
    303389            self.updateItems.append(UpdateTreeWidgetItem(self, *item)) 
    304390        self.pb.advance() 
    305         self.filesView.resizeColumnToContents(0) 
    306         self.filesView.resizeColumnToContents(1) 
    307         self.filesView.resizeColumnToContents(2) 
    308         self.lineEditFilter.setItems([hint for hint in sorted(self.allTags) if not hint.startswith("#")]) 
     391        for column in range(4): 
     392            whint = self.filesView.sizeHintForColumn(column) 
     393            width = min(whint, 400) 
     394            self.filesView.setColumnWidth(column, width) 
     395 
     396        self.lineEditFilter.setItems([hint for hint in sorted(self.allTags) 
     397                                      if not hint.startswith("#")]) 
    309398        self.SearchUpdate() 
    310399        self.UpdateInfoLabel() 
    311400        self.pb.finish() 
    312          
     401 
    313402    def HandleError(self, (exc_type, exc_value, tb)): 
    314403        if exc_type >= IOError: 
    315             self.error(0, "Could not connect to server! Press the Retry button to try again.") 
     404            self.error(0, 
     405                       "Could not connect to server! Press the Retry " 
     406                       "button to try again.") 
    316407            self.SetFilesList({}) 
    317408        else: 
     
    319410            self.pb.finish() 
    320411            self.setEnabled(True) 
    321              
    322          
    323 #    def UpdateFilesList(self): 
    324 #        self.retryButton.hide() 
    325 ##        self.progressBarInit() 
    326 #        pb = OWGUI.ProgressBar(self, 3) 
    327 #        self.filesView.clear() 
    328 ##        self.tagsWidget.clear() 
    329 #        self.allTags = set() 
    330 #        allTitles = set() 
    331 #        self.updateItems = [] 
    332 #        if self.accessCode: 
    333 #            self.serverFiles = orngServerFiles.ServerFiles(access_code=self.accessCode) 
    334 #             
    335 #        self.error(0)     
    336 #        try: 
    337 #            domains = self.serverFiles.listdomains() if self.domains is None else self.domains 
    338 #            pb.advance() 
    339 #            serverInfo = dict([(dom, self.serverFiles.allinfo(dom)) for dom in domains]) 
    340 #            pb.advance() 
    341 #        except IOError, ex: 
    342 #            self.error(0, "Could not connect to server! Press the Retry button to try again.") 
    343 #            self.retryButton.show() 
    344 #            domains =orngServerFiles.listdomains() if self.domains is None else self.domains 
    345 #            pb.advance() 
    346 #            serverInfo = {} 
    347 #            pb.advance() 
    348 #             
    349 #        localInfo = dict([(dom, orngServerFiles.allinfo(dom)) for dom in domains]) 
    350 #        items = [] 
    351 #         
    352 #        for i, domain in enumerate(set(domains) - set(["test", "demo"])): 
    353 #            local = localInfo.get(domain, {}) #orngServerFiles.listfiles(domain) or [] 
    354 ##                files = self.serverFiles.listfiles(domain) 
    355 #            server =  serverInfo.get(domain, {}) #self.serverFiles.allinfo(domain) 
    356 #            files = sorted(set(server.keys() + local.keys())) 
    357 #            for j, file in enumerate(files): 
    358 #                infoServer = server.get(file, None) 
    359 #                infoLocal = local.get(file, None) 
    360 #                 
    361 #                items.append((self.filesView, domain, file, infoLocal, infoServer)) 
    362 #                 
    363 #                displayInfo = infoServer if infoServer else infoLocal 
    364 #                self.allTags.update(displayInfo["tags"]) 
    365 #                allTitles.update(displayInfo["title"].split()) 
    366 # 
    367 ##                    self.progressBarSet(100.0 * i / len(domains) + 100.0 * j / (len(files) * len(domains))) 
    368 #         
    369 #        for i, item in enumerate(items): 
    370 #            self.updateItems.append(UpdateTreeWidgetItem(self, *item)) 
    371 #        pb.advance() 
    372 #        self.filesView.resizeColumnToContents(0) 
    373 #        self.filesView.resizeColumnToContents(1) 
    374 #        self.filesView.resizeColumnToContents(2) 
    375 #        self.lineEditFilter.setItems([hint for hint in sorted(self.allTags) if not hint.startswith("#")]) 
    376 #        self.SearchUpdate() 
    377 #        self.UpdateInfoLabel() 
    378 # 
    379 #        self.progressBarFinished() 
    380412 
    381413    def UpdateInfoLabel(self): 
    382414        local = [item for item in self.updateItems if item.state != 2] 
    383415        onServer = [item for item in self.updateItems] 
     416        size = sum(float(item.specialTags.get("#uncompressed", item.size)) 
     417                   for item in local) 
     418        sizeOnServer = sum(float(item.size) for item in self.updateItems) 
     419 
    384420        if self.showAll: 
    385             self.infoLabel.setText("%i items, %s (data on server: %i items, %s)" % (len(local), sizeof_fmt(sum(float(item.specialTags.get("#uncompressed", item.size)) for item in local)), 
    386                                                                             len(onServer), sizeof_fmt(sum(float(item.size) for item in self.updateItems)))) 
    387         else: 
    388             self.infoLabel.setText("%i items, %s" % (len(local), sizeof_fmt(sum(float(item.specialTags.get("#uncompressed", item.size)) for item in local)))) 
    389          
     421 
     422            text = ("%i items, %s (data on server: %i items, %s)" % 
     423                    (len(local), 
     424                     sizeof_fmt(size), 
     425                     len(onServer), 
     426                     sizeof_fmt(sizeOnServer))) 
     427        else: 
     428            text = "%i items, %s" % (len(local), sizeof_fmt(size)) 
     429 
     430        self.infoLabel.setText(text) 
     431 
    390432    def UpdateAll(self): 
    391433        for item in self.updateItems: 
    392434            if item.state == 1: 
    393435                item.StartDownload() 
    394                  
     436 
    395437    def DownloadFiltered(self): 
    396438        for item in self.updateItems: 
     
    399441 
    400442    def SearchUpdate(self, searchString=None): 
    401         strings = unicode(self.lineEditFilter.text()).split() #self.searchString.split() if searchString is None else unicode(searchString).split() 
     443        strings = unicode(self.lineEditFilter.text()).split() 
    402444        tags = set() 
    403445        for item in self.updateItems: 
     
    406448            if not hide: 
    407449                tags.update(item.tags) 
    408 #        self.lineEditFilter.setItems(sorted(tags, key=lambda tag: chr(1) + tag.lower() if strings and tag.lower().startswith(strings[-1].lower()) else tag.lower())) 
    409 #        self.tagsWidget.setText(", ".join(sorted(tags, key=lambda tag: chr(1) + tag.lower() if strings and tag.lower().startswith(strings[-1].lower()) else tag.lower()))) 
    410          
     450 
     451 
    411452if __name__ == "__main__": 
    412453    app = QApplication(sys.argv) 
  • Orange/classification/svm/__init__.py

    r11397 r11423  
    11931193 
    11941194class RFE(object): 
    1195  
    1196     """Iterative feature elimination based on weights computed by 
     1195    """ 
     1196    Iterative feature elimination based on weights computed by a 
    11971197    linear SVM. 
    11981198 
    1199     Example:: 
     1199    Example: 
    12001200 
    12011201        >>> table = Orange.data.Table("promoters.tab") 
     
    12121212    def __init__(self, learner=None): 
    12131213        """ 
    1214         :param learner: A linear svm learner for use with 
    1215             :class:`ScoreSVMWeights`. 
     1214        :param learner: A linear svm learner for use for scoring (this 
     1215            learner is passed to :class:`ScoreSVMWeights`) 
     1216 
     1217        :type learner: :class:`LinearSVMLearner` or :class:`SVMLearner` with 
     1218            linear kernel 
     1219 
     1220        .. seealso:: :class:`ScoreSVMWeights` 
    12161221 
    12171222        """ 
  • Orange/utils/serverfiles.py

    r11396 r11438  
    305305 
    306306        readb = 0 
    307         while 1: 
     307        # in case size == 0 skip the loop 
     308        while size > 0: 
    308309            buf = fdown.read(chunksize) 
    309310            readb += len(buf) 
    310311 
    311             while float(readb)/size > lastchunkreport+0.01: 
     312            while float(readb) / size > lastchunkreport+0.01: 
    312313                #print float(readb)/size, lastchunkreport + 0.01, float(readb)/size - lastchunkreport  
    313314                lastchunkreport += 0.01 
     
    670671    def getstring(self): 
    671672        elapsed = max(time.time() - self.starttime, 0.1) 
    672         speed = int(self.state * self.size / 100.0 / elapsed) 
     673        speed = max(int(self.state * self.size / 100.0 / elapsed), 1) 
    673674        eta = (100 - self.state) * self.size / 100.0 / speed 
    674675        return ConsoleProgressBar.getstring(self) + \ 
  • docs/extend-widgets/rst/api.rst

    r11049 r11424  
    1818Following is an example that defines two output channels:: 
    1919 
    20     self.outputs = [("Sampled Data", orange.ExampleTable), ("Learner", orange.Learner)] 
     20    self.outputs = [("Sampled Data", orange.ExampleTable), 
     21                    ("Learner", orange.Learner)] 
    2122 
    2223:obj:`self.outputs` should thus be a list of tuples, within 
     
    6263 
    6364    def receiveData(self, data): 
    64     # handle data in some way 
     65        # handle data in some way 
     66 
    6567 
    6668Any time our widget would receive a token, :obj:`receiveData` 
     
    7678deleted, Orange Canvas would automatically send :obj:`None` to 
    7779the receiving widget. Make sure your widget handles :obj:`None` 
    78 tokens appropriately!` 
     80tokens appropriately! 
    7981 
    8082There are cases when widget would like to know about the origin of 
     
    9395 
    9496   def learner(self, learnertoken, tokenid): 
    95    # handle learnertoken and tokeid in some way 
     97       # handle learnertoken and tokeid in some way 
    9698 
    9799Widgets such as :obj:`OWTestLearners` and alike use such 
     
    102104 
    103105    self.inputs = [("Data", orange.ExampleTable, self.maindata), 
    104                ("Additional Data", orange.ExampleTable, self.otherdata)] 
     106                   ("Additional Data", orange.ExampleTable, self.otherdata)] 
    105107 
    106108and we connect this widget in Orange Canvas to a sending widget 
    107109that has a single orange.ExampleTable output channel, Canvas would 
    108 bring up Set Channels dialog. There, a sending widget's channel could 
     110bring up *Set Channels* dialog. There, a sending widget's channel could 
    109111be connected to both receiving channels. As we would often prefer to 
    110112connect to a single (default) channel instead (still allowing user of 
     
    114116 
    115117    self.inputs = [("Data", orange.ExampleTable, self.maindata, Default), 
    116                ("Additional Data", orange.ExampleTable, self.otherdata)] 
     118                   ("Additional Data", orange.ExampleTable, self.otherdata)] 
  • docs/extend-widgets/rst/basics.rst

    r11408 r11424  
    4242categories. For instance, under windows and default settings, a 
    4343directory that stores all the widgets displayed in the Evaluate pane is 
    44 C:\Python23\Lib\site-packages\orange\OrangeWidgets\Evaluate. Figure 
     44*C:\\Python23\\Lib\\site-packages\\Orange\\OrangeWidgets\\Evaluate*. Figure 
    4545above shows that at the time of writing of this text there were five 
    4646widgets for evaluation of classifiers, and this is how my Evaluate 
     
    8080something like:: 
    8181 
    82     self.inputs = [("Test Data Set", ExampleTable, self.cdata), ("Learner", orange.Learner, self.learner, 0)] 
     82    self.inputs = [("Test Data Set", ExampleTable, self.cdata), 
     83                   ("Learner", orange.Learner, self.learner, 0)] 
    8384    self.outputs = [("Evaluation Results", orngTest.ExperimentResults)] 
    8485 
     
    9192now the following is important: 
    9293 
    93    -  Widgets are defined in a Python files. 
    94    - For Orange and Orange canvas to find them, they reside in subdirectories in OrangeWidgets directory of Orange installation. The name of the subdirectory matters, as this is the name of the widget category. Widgets in the same directory will be grouped in the same pane of widget toolbox in Orange Canvas. 
    95    - A file describing a widget starts with a header. This, given in sort of XMLish style, tells about the name, short description, location of an icon and priority of the widget. 
    96    - The sole role of priority is to specify the placement (order) of widgets in the Orange Canvas toolbox. 
    97    - Somewhere in the code (where we will learn later) there are two lines which tell which channels the widgets uses for communication. These, together with the header information, completely specify the widget as it is seen from the outside. 
     94   - Widgets are defined in a Python files. 
     95   - For Orange and Orange canvas to find them, they reside in subdirectories 
     96     in OrangeWidgets directory of Orange installation. The name of the 
     97     subdirectory matters, as this is the name of the widget category. Widgets 
     98     in the same directory will be grouped in the same pane of widget toolbox 
     99     in Orange Canvas. 
     100   - A file describing a widget starts with a header. This, given in sort of 
     101     XMLish style, tells about the name, short description, location of an 
     102     icon and priority of the widget. 
     103   - The sole role of priority is to specify the placement (order) of widgets 
     104     in the Orange Canvas toolbox. 
     105   - Somewhere in the code (where we will learn later) there are two lines 
     106     which tell which channels the widgets uses for communication. These, 
     107     together with the header information, completely specify the widget as it 
     108     is seen from the outside. 
    98109 
    99110Oh, by the way. Orange caches widget descriptions to achieve a faster 
  • docs/extend-widgets/rst/channels.rst

    r11408 r11424  
    2626Say we want to build a widget that takes a data set and test 
    2727various predictive modelling techniques on it. A widget has to have an 
    28 input data channel, and this we know how to deal with from our :doc:`previous <settings>` 
    29 lesson. But, somehow differently, we 
     28input data channel, and this we know how to deal with from our 
     29:doc:`previous <settings>` lesson. But, somehow differently, we 
    3030want to connect any number of widgets which define learners to our 
    3131testing widget. Just like in a schema below, where three different 
  • docs/extend-widgets/rst/graphing.rst

    r11408 r11424  
    3939    self.setGraphGrid() 
    4040 
    41 :obj:`OWGrap` is a convenience subclass of QwtPlot and is imported from OWGraph module. For the graph, we use :obj:`setAxisAutoScale` to 
     41:obj:`OWGrap` is a convenience subclass of QwtPlot and is imported from 
     42OWGraph module. For the graph, we use :obj:`setAxisAutoScale` to 
    4243request that the axis are automatically set in regard to the data that 
    4344is plotted in the graph. We plot the graph in using the following 
  • docs/extend-widgets/rst/owgui.rst

    r11408 r11424  
    3434`value` (required) 
    3535   String with the name of the master's attribute that synchronizes with the 
    36    state of the control (and vice-versa - when this attribute is changed, the control changes as well). This attribute should usually be also included the master's :obj:`settingsList`, so that it is automatically saved and retrieved. 
     36   state of the control (and vice-versa - when this attribute is changed, the 
     37   control changes as well). This attribute should usually be also included 
     38   the master's :obj:`settingsList`, so that it is automatically saved and 
     39   retrieved. 
    3740 
    3841`box` (default: None) 
    39    Indicates if there should be a box that is drawn around the control. If `box` is ``None``, no box is drawn; if it is a string, it is also used as box's name. If `box` is any other true value (such as ``True`` :), an unlabeled box is drawn. 
     42   Indicates if there should be a box that is drawn around the control. 
     43   If `box` is ``None``, no box is drawn; if it is a string, it is also used 
     44   as box's name. If `box` is any other true value (such as ``True`` :), 
     45   an unlabeled box is drawn. 
    4046 
    4147`callback` (default: None) 
     
    5157 
    5258`tooltip` (default: None) 
    53    A string that is displayed in a tooltip that appears when mouse is over the control. 
     59   A string that is displayed in a tooltip that appears when mouse is over the 
     60   control. 
    5461 
    5562`label` (default: None) 
     
    6067 
    6168`orientation` (default: "vertical") 
    62    When label is used, determines the relative placement of the label and the control. Label can be above the control, "vertical", or in the same line with control, "horizontal". Instead of "vertical" and "horizontal" you can also use ``True`` and ``False`` or 1 and 0, respectively. (Remember this as "vertical" being the usual order of controls in the widgets, so vertical is "true".) 
     69   When label is used, determines the relative placement of the label and the 
     70   control. Label can be above the control, "vertical", or in the same line 
     71   with control, "horizontal". Instead of "vertical" and "horizontal" you can 
     72   also use ``True`` and ``False`` or 1 and 0, respectively. (Remember this 
     73   as "vertical" being the usual order of controls in the widgets, so vertical 
     74   is "true".) 
    6375 
    6476`disabled` (default: False) 
     
    6678 
    6779`addSpace` (default: False) 
    68    If true, a space of 8 pixels is added after the widget by calling :func:`separator`. `addSpace` can also be an integer specifying the height of the added space. 
     80   If true, a space of 8 pixels is added after the widget by calling 
     81   :func:`separator`. `addSpace` can also be an integer specifying the height 
     82   of the added space. 
    6983 
    7084 
     
    7589This section describes the OWGUI wrappers for controls like check boxes, buttons 
    7690and similar. All the important Qt's controls can be constructed through this 
    77 functions. You should always use them instead of calling Qt directly, not only 
    78 because they are convenient, but also because they set up a lot of things that happen in behind. 
     91functions. 
     92 
     93.. 
     94   You should always use them instead of calling Qt directly, not only 
     95   because they are convenient, but also because they set up a lot of things 
     96   that happen in behind. 
    7997 
    8098 
     
    88106 
    89107   `disables` (default: []) 
    90       If the check box needs to disable some other controls they can be given in list  `disables`, e.g. ``disables=[someOtherCheckBox, someLineEdit]``. If the other control should be disabled when the checkbox is checked, do it like this: ``disables=[someOtherCheckBox, (-1, someLineEdit)]`` - now `someOtherCheckBox` will be enabled when this check box is checked, while `someLineEdit` will be enabled when the check box is unchecked. 
     108      If the check box needs to disable some other controls they can be given 
     109      in list  `disables`, e.g. ``disables=[someOtherCheckBox, someLineEdit]``. 
     110      If the other control should be disabled when the checkbox is checked, do 
     111      it like this: ``disables=[someOtherCheckBox, (-1, someLineEdit)]`` - now 
     112      `someOtherCheckBox` will be enabled when this check box is checked, 
     113      while `someLineEdit` will be enabled when the check box is unchecked. 
    91114 
    92115   `labelWidth` (default: None) 
     
    102125 
    103126   `valueType` (default: str) 
    104       A type into which the value is cast. 
     127      A type into which the `value` is cast. 
    105128 
    106129   `validator` (default: None) 
     
    152175 
    153176   `items` (default: []) 
    154       A list of combo box's items. Unlike most OWGUI, `items` have one Orange-specific quirk: its element can be either a string, in which case it is used as a label, or a tuple, where the first element is a label name and the last is the attribute type which is used to create an icon. Most attribute lists in Orange Widgets are constructed this way. 
     177      A list of combo box's items. Unlike most OWGUI, `items` have one 
     178      Orange-specific quirk: its element can be either a string, in which 
     179      case it is used as a label, or a tuple, where the first element is a 
     180      label name and the last is the attribute type which is used to create 
     181      an icon. Most attribute lists in Orange Widgets are constructed this way. 
    155182 
    156183   `sendSelectedValue` (default: 0) 
    157       If false, attribute `value` will be assigned the index of the selected item. Otherwise, it is assigned the currently selected item's label. 
     184      If false, attribute `value` will be assigned the index of the selected 
     185      item. Otherwise, it is assigned the currently selected item's label. 
    158186 
    159187   `control2attributeDict` (default: {}) 
    160       A dictionary for translating the item's label into `value`. It is used only is `sendSelectedValue` is true, and even then a label is translated only if an item with such a key is found in the dictionary; otherwise, label is written to `value` as it is.  
     188      A dictionary for translating the item's label into `value`. It is used 
     189      only is `sendSelectedValue` is true, and even then a label is translated 
     190      only if an item with such a key is found in the dictionary; otherwise, 
     191      label is written to `value` as it is. 
    161192 
    162193   `emptyString` (default: "") 
    163       Tells which combo box's item corresponds to an empty `value`. This is typically used when combo box's labels are attribute names and an item "(none)", which allows user to select no attribute. If we give ``emptyString="(none)"``, `value` will be an empty string when the user selects "(none)". This is equivalent to specifying ``control2attributeDict={"(none)": ""}`` (and is actually implemented like that), but far more convenient. 
     194      Tells which combo box's item corresponds to an empty `value`. This is 
     195      typically used when combo box's labels are attribute names and an item 
     196      "(none)", which allows user to select no attribute. If we give 
     197      ``emptyString="(none)"``, `value` will be an empty string when the user 
     198      selects "(none)". This is equivalent to specifying 
     199      ``control2attributeDict={"(none)": ""}`` (and is actually implemented 
     200      like that), but far more convenient. 
    164201 
    165202   `valueType` (default: str or unicode) 
    166       A function through which the currently selected item's label is converted prior to looking into `control2attributeDict`. Needed to convert Qt's QString. 
     203      A function through which the currently selected item's label is  
     204      converted prior to looking into `control2attributeDict`. Needed to 
     205      convert Qt's QString. 
    167206 
    168207 
     
    171210 
    172211This control, which might be the most complicated control in OWGUI, is a 
    173 sophisticated wrapper around QListBox. It's complexity arises from synchronization. 
     212sophisticated wrapper around QListBox. It's complexity arises from 
     213synchronization. 
    174214 
    175215 
     
    180220 
    181221   `labels` (required) 
    182       The name of master's attribute containing the list box's labels. Similar to `items` in combo box, list `labels` have one Orange-specific quirk: its element can be either a string, in which case it is used as a label, or a tuple, where the first element is a label name and the second can be either an icon on an integer, representing the attribute type which is used to create an icon. Most attribute lists in Orange Widgets are constructed this way. 
     222      The name of master's attribute containing the list box's labels. Similar 
     223      to `items` in combo box, list `labels` have one Orange-specific quirk: 
     224      its element can be either a string, in which case it is used as a label 
     225      or a tuple, where the first element is a label name and the second can 
     226      be either an icon on an integer, representing the attribute type which 
     227      is used to create an icon. Most attribute lists in Orange Widgets are 
     228      constructed this way. 
    183229 
    184230   `selectionMode` (default: QListWidget.SingleSelection) 
    185       Tells whether the user can select a single item (:obj:`QListWidget.SingleSelection`), multiple items (:obj:`QListWidget.MultiSelection`, :obj:`QListWidget.ExtendedSelection`) or nothing (:obj:`QListWidget.NoSelection`). 
    186  
    187    `value` is automatically cast to :obj:`OWGUI.ControlledList` (this is needed because the list should report any changes to the control, the list box; :obj:`OWGUI.ControlledList` is like an ordinary Python :obj:`list` except that it triggers synchronization with the list box at every change). 
    188  
    189    `labels` is only partially synchronized with the list box: if a new list is assigning to `labels` attribute, the list will change. If elements of the existing list are changed or added, the list box won't budge. You should never change the list, but always assign a new list (or reassign the same after it's changed). If the labels are stored in ``self.listLabels`` and you write ``self.listLabels[1]="a new label"``, the list box won't change. To trigger the synchronization, you should continue by ``self.listLabels = self.listLabels``. This may seem awkward, but by our experience a list of selected items is seldom changed changed "per-item", so we were too lazy to write the annoyingly complex backward callbacks. 
    190  
     231      Tells whether the user can select a single item 
     232      (:obj:`QListWidget.SingleSelection`), multiple items 
     233      (:obj:`QListWidget.MultiSelection`, :obj:`QListWidget.ExtendedSelection`) 
     234      or nothing (:obj:`QListWidget.NoSelection`). 
     235 
     236   `value` is automatically cast to :obj:`OWGUI.ControlledList` (this is 
     237   needed because the list should report any changes to the control, the list 
     238   box; :obj:`OWGUI.ControlledList` is like an ordinary Python :obj:`list` 
     239   except that it triggers synchronization with the list box at every change). 
     240 
     241   `labels` is only partially synchronized with the list box: if a new list 
     242   is assigning to `labels` attribute, the list will change. If elements of 
     243   the existing list are changed or added, the list box won't budge. You 
     244   should never change the list, but always assign a new list (or reassign 
     245   the same after it's changed). If the labels are stored in 
     246   ``self.listLabels`` and you write ``self.listLabels[1]="a new label"``, 
     247   the list box won't change. To trigger the synchronization, you should 
     248   continue by ``self.listLabels = self.listLabels``. This may seem awkward, 
     249   but by our experience a list of selected items is seldom changed changed 
     250   "per-item", so we were too lazy to write the annoyingly complex backward 
     251   callbacks. 
    191252 
    192253 
     
    205266****** 
    206267 
    207 A wrapper around QSlider that allows user setting a numerical value between the given bounds. 
     268A wrapper around QSlider that allows user setting a numerical value between 
     269the given bounds. 
    208270 
    209271.. function:: hSlider(widget, master, value[, box, minValue, maxValue, step, callback, labelFormat, ticks, divideFactor]) 
     
    214276 
    215277   `ticks` (default: 0) 
    216       If non-zero, it gives the interval between two ticks. The ticks will appear below the groove. 
     278      If non-zero, it gives the interval between two ticks. The ticks will 
     279      appear below the groove. 
    217280 
    218281   `labelFormat` (default: " %d") 
    219       Defines the look of the label on the righthand side of the slider. It has to contain one format character (like %d in the default), but can contain other text as well. 
     282      Defines the look of the label on the righthand side of the slider. It 
     283      has to contain one format character (like %d in the default), but can 
     284      contain other text as well. 
    220285 
    221286   `divideFactor` (default: 1.0) 
     
    226291******************* 
    227292 
    228 Check box with spin, or, essentially, a wrapper around 
    229 OWGUI.checkBox and OWGUI.spin. 
     293Check box with spin, or, essentially, a wrapper around OWGUI.checkBox and 
     294OWGUI.spin. 
    230295 
    231296.. function:: checkWithSpin(widget, master, label, min, max, checked, value[, posttext, step, tooltip, checkCallback, spinCallback, labelWidth]) 
     
    250315****** 
    251316 
    252 There are two functions for constructing labels. The first is a simple wrapper around QLabel which differs only in allowing to specify a fixed width without needing an extra line. Note that unlike most other OWGUI widgets, this one does not have the argument `master`. 
     317There are two functions for constructing labels. The first is a simple wrapper 
     318around QLabel which differs only in allowing to specify a fixed width without 
     319needing an extra line. Note that unlike most other OWGUI widgets, this one 
     320does not have the argument `master`. 
    253321 
    254322.. function:: widgetLabel(widget, label[, labelWidth]) 
    255323 
    256    The second is a label which can synchronize with values of master widget's attributes. 
     324   The second is a label which can synchronize with values of master widget's 
     325   attributes. 
    257326 
    258327.. function:: label(widget, master, label[, labelWidth]) 
     
    326395************************* 
    327396 
    328 Many widgets have a "Send" button (perhaps named "Apply", "Commit"...) accompanied with a check box "Send automatically", having the same effect as if the user pressed the button after each change. A well behaved widget cares to: 
     397Many widgets have a "Send" button (perhaps named "Apply", "Commit"...) 
     398accompanied with a check box "Send automatically", having the same effect as 
     399if the user pressed the button after each change. A well behaved widget cares 
     400to: 
    329401 
    330402* disable the button, when the check box is checked; 
    331 * when the user checks the check box, the data needs to be send (or the changes applied), but only if there is any pending change which has not been (manually) sent yet. 
    332  
    333 Programming this into every widget is annoying and error-prone; at the time when the function described here was written, not many widgets actually did this properly. 
     403* when the user checks the check box, the data needs to be send (or the 
     404  changes applied), but only if there is any pending change which has not been 
     405  (manually) sent yet. 
     406 
     407Programming this into every widget is annoying and error-prone; at the time 
     408when the function described here was written, not many widgets actually did 
     409this properly. 
    334410 
    335411.. function:: setStopper(master, sendButton, stopCheckbox, changedFlag, callback) 
     
    339415 
    340416   `stopCheckbox` 
    341       Check box that decides whether the changes are sent/commited/applied automatically. 
     417      Check box that decides whether the changes are sent/commited/applied 
     418      automatically. 
    342419 
    343420   `changedFlag` 
    344       The name of the `master`'s attribute which tells whether there is a change which has not been sent/applied yet. 
     421      The name of the `master`'s attribute which tells whether there is a 
     422      change which has not been sent/applied yet. 
    345423 
    346424   `callback` 
    347       The function that sends the data or applies the changes. This is typically the function which is also used as the `sendButton`'s callback. 
    348  
    349  
    350 :obj:`setStopper` is a trivial three lines long function which connects a few signals. Its true importance is in enforcing the correct procedure for implementing such button-check box combinations. 
     425      The function that sends the data or applies the changes. This is 
     426      typically the function which is also used as the `sendButton`'s callback. 
     427 
     428 
     429:obj:`setStopper` is a trivial three lines long function which connects a few 
     430signals. Its true importance is in enforcing the correct procedure for 
     431implementing such button-check box combinations. 
    351432 
    352433.. 
     
    354435 
    355436   Missing, where did it go? 
    356  
  • docs/extend-widgets/rst/settings.rst

    r11408 r11424  
    176176state so that when the user changes a check box, the attribute changes 
    177177and vice-versa. Although you can create such a link manually, you 
    178 should always use the module :doc:`OWGUI <owgui.rst>` instead; 
     178should always use the module :doc:`OWGUI <owgui>` instead; 
    179179for instance, for a check box, use :obj:`OWGUI.checkBox` and not 
    180180simply the Qt's :obj:`QCheckBox`. 
     
    183183the data, while other are context-dependent. For the first to be saved 
    184184properly, you only need to list them in the :obj:`settingsList` 
    185 in the widget definition, as already described :doc:`elsewhere <settings.rst>` 
     185in the widget definition, as already described :doc:`elsewhere <settings>` 
    186186 
    187187************************** 
     
    237237In general, the function should go like this. 
    238238 
    239 * Do any clean-up you need, but without clearing any of the settings that need to be saved. Scatter plot needs none. 
    240 * Call :obj:`self.closeContext`; this ensures that all the context dependent settings (e.g. attribute names from the list boxes) are remembered. 
    241 * Get the data (or whatever you do) and set the controls to some defaults as if there were no context retrieving mechanism. Scatter plot does it by calling :obj:`initAttrValues()` which assigns the first two attributes to the x and y axis and the class attribute to the color. At this phase, you shouldn't call any functions that depend on the settings, such as drawing the graph. 
    242 * Call :obj:`self.openContext` (more about the arguments later). This will search for a suitable context and assign the controls new values if one is found. If there is no saved context that can be used, a new context is created and filled with the default values that were assigned at the previous point. 
    243 * Finally, adjust the widget according to the retrieved controls. Scatter plot now plots the graph by calling :obj:`updateGraph`. 
    244  
    245  
    246 :obj:`closeContext` has an argument, the name of the context. If omitted (like above), the default name (:obj:`""`) is used. When opening the context, we give the name and some arguments on which the context depends. In case of :obj:`DomainContextHandler`, which scatter plot uses, we can give it a domain or any object that has a field :obj:`domain` containing a domain. Whether a saved context can be reused is judged upon the presence of attributes in the domain. 
    247  
    248 If the widget is constructed appropriately (that is, if it strictly uses OWGUI controls instead of the Qt's), no other administration is needed to switch the context. 
    249  
    250 Except for declaring the context settings, that is. Scatter plot has this just below the :obj:`settingsList`:: 
     239* Do any clean-up you need, but without clearing any of the settings that need 
     240  to be saved. Scatter plot needs none. 
     241* Call :obj:`self.closeContext()`; this ensures that all the context dependent 
     242  settings (e.g. attribute names from the list boxes) are remembered. 
     243* Get the data (or whatever you do) and set the controls to some defaults as 
     244  if there were no context retrieving mechanism. Scatter plot does it by 
     245  calling :obj:`initAttrValues()` which assigns the first two attributes to 
     246  the x and y axis and the class attribute to the color. At this phase, you 
     247  shouldn't call any functions that depend on the settings, such as drawing 
     248  the graph. 
     249* Call :obj:`self.openContext` (more about the arguments later). This will 
     250  search for a suitable context and assign the controls new values if one is 
     251  found. If there is no saved context that can be used, a new context is 
     252  created and filled with the default values that were assigned at the previous 
     253  point. 
     254* Finally, adjust the widget according to the retrieved controls. Scatter plot 
     255  now plots the graph by calling :obj:`updateGraph`. 
     256 
     257 
     258:obj:`closeContext` has an argument, the name of the context. If omitted 
     259(like above), the default name (:obj:`""`) is used. When opening the context, 
     260we give the name and some arguments on which the context depends. In case of 
     261:obj:`DomainContextHandler`, which scatter plot uses, we can give it a domain 
     262or any object that has a field :obj:`domain` containing a domain. Whether a 
     263saved context can be reused is judged upon the presence of attributes in the 
     264domain. 
     265 
     266If the widget is constructed appropriately (that is, if it strictly uses OWGUI 
     267controls instead of the Qt's), no other administration is needed to switch the 
     268context. 
     269 
     270Except for declaring the context settings, that is. Scatter plot has this just 
     271below the :obj:`settingsList`:: 
    251272 
    252273    contextHandlers = {"": DomainContextHandler("", 
     
    257278       ("attrSize", DomainContextHandler.Optional)])} 
    258279 
    259 :obj:`contextHandlers` is a dictionary whose keys are contexts' names. Each widget can have multiple contexts; for an unrealistic example, consider a scatter plot which gets two data sets and uses one attribute from the first for the x axis, and an attribute from the other for y. Since we won't see this often, the default name for a context is an empty string. 
    260  
    261 The values in the dictionary are context handlers. Scatter plot declares that it has a DomainContextHandler with name "" (sorry for the repetition) with attributes "attrX", "attrY", "attrLabel", "attrShape" and "attrSize". The first two are required, while the other three are optional. 
     280:obj:`contextHandlers` is a dictionary whose keys are contexts' names. Each 
     281widget can have multiple contexts; for an unrealistic example, consider a 
     282scatter plot which gets two data sets and uses one attribute from the first 
     283for the x axis, and an attribute from the other for y. Since we won't see this 
     284often, the default name for a context is an empty string. 
     285 
     286The values in the dictionary are context handlers. Scatter plot declares that 
     287it has a DomainContextHandler with name "" (sorry for the repetition) with 
     288attributes "attrX", "attrY", "attrLabel", "attrShape" and "attrSize". The 
     289first two are required, while the other three are optional. 
    262290 
    263291********************************* 
     
    265293********************************* 
    266294 
    267 What we said above is not exactly 
    268 true. :obj:`DomainContextHandler.Required` is the default flag, 
    269 so :obj:`("attrX", DomainContextHandler.Required)` can be 
    270 replaced by simply :obj:`"attrX"`. And the latter three have the 
     295What we said above is not exactly true. :obj:`DomainContextHandler.Required` 
     296is the default flag, so :obj:`("attrX", DomainContextHandler.Required)` can 
     297be replaced by simply :obj:`"attrX"`. And the latter three have the 
    271298same flags, so they can be grouped into :obj:`(["attrLabel", 
    272299"attrShape", "attrSize"], DomainContextHandler.Optional)`. So 
     
    277304       (["attrLabel", "attrShape", "attrSize"], DomainContextHandler.Optional)])} 
    278305 
    279 What do "optional" and "required" mean? Say that you used the 
     306What do ``Optional`` and ``Required`` mean? Say that you used the 
    280307scatter plot on the data with attributes A, B, C and D; A and B are 
    281308used for the x and y axis and D defined the colors of examples. Now 
     
    295322:obj:`DomainContextHandler`. 
    296323 
    297 DomainContextHandler's constructor has the following arguments 
    298  
    299 contextName 
    300 The name of the context; it should consist of letters and digits (it is used as a prt of a variable name). In case the widget has multiple contexts, they should have unique names. In most cases there will be only one context, so you can leave it empty. 
    301  
    302 fields 
    303 The names of the attributes to be saved and the corresponding flags. They are described in more details below. 
    304  
    305 cloneIfImperfect 
    306 states that when the context doesn't match perfectly, that is, unless the domain is exactly the same as the domain from which the context was originally created, :obj:`openContext` shouldn't reuse a context but create a copy of the best matching context instead. Default is :obj:`True`. 
    307  
    308 loadImperfect 
    309 tells whether the contexts that do not match perfectly (see above) should be used or not. Default is :obj:`True`. 
    310  
    311 findImperfect 
    312 tells whether imperfect contexts match at all or not (this flag is somewhat confused with :obj:`loadImperfect`, but it may come useful some day. Default is :obj:`True` again. 
    313  
    314 syncWithGlobal 
    315 tells whether instances of this widget should have a shared list of contexts (default). The alternative is that each keeps its own list; each individual list is merged with the global when the widget is deleted from the canvas (or when the canvas is closed). This setting only applies to canvas, while in saved applications widgets always have separate settings lists. 
    316  
    317 maxAttributesToPickle 
    318 To keep the size of the context file small, settings for domains exceeding a certain number of attributes are not pickled. Default is 100, but you can increase (or decrease this) if you need to. 
     324:class:`DomainContextHandler`'s constructor has the following arguments 
     325 
     326`contextName` 
     327   The name of the context; it should consist of letters and digits (it is 
     328   used as a part of a variable name). In case the widget has multiple 
     329   contexts, they should have unique names. In most cases there will be only 
     330   one context, so you can leave it empty. 
     331 
     332`fields` 
     333   The names of the attributes to be saved and the corresponding flags. They 
     334   are described in more details below. 
     335 
     336`cloneIfImperfect` 
     337   States that when the context doesn't match perfectly, that is, unless the 
     338   domain is exactly the same as the domain from which the context was 
     339   originally created, :obj:`openContext` shouldn't reuse a context but create 
     340   a copy of the best matching context instead. Default is :obj:`True`. 
     341 
     342`loadImperfect` 
     343   tells whether the contexts that do not match perfectly (see above) should 
     344   be used or not. Default is :obj:`True`. 
     345 
     346`findImperfect` 
     347   Tells whether imperfect contexts match at all or not (this flag is 
     348   somewhat confused with :obj:`loadImperfect`, but it may come useful some 
     349   day). Default is :obj:`True` again. 
     350 
     351`syncWithGlobal` 
     352   Tells whether instances of this widget should have a shared list of 
     353   contexts (default). The alternative is that each keeps its own list; 
     354   each individual list is merged with the global when the widget is deleted 
     355   from the canvas (or when the canvas is closed). This setting only applies 
     356   to canvas, while in saved applications widgets always have separate settings 
     357   lists. 
     358 
     359`maxAttributesToPickle` 
     360   To keep the size of the context file small, settings for domains exceeding 
     361   a certain number of attributes are not pickled. Default is 100, but you can 
     362   increase (or decrease this) if you need to. 
    319363 
    320364 
     
    326370name (just like in :obj:`settingsList`) and a flag. Here are the possible flags: 
    327371 
    328 * :obj:`DomainContextHandler.Optional`, :obj:`DomainContextHandler.SelectedRequired` and :obj:`DomainContextHandler.Required` state whether the attribute is optional or required, as explained above. Default is :obj:`Required`. :obj:`DomainContextHandler.SelectedRequired` is applicable only if the control is a list box, where it means that the attributes that are selected are required while the other attributes from the list are not. 
    329 * :obj:`DomainContextHandler.NotAttribute` the setting is not an attribute name. You can essentially make a check box context dependent, but we very strongly dissuade from this since it can really confuse the user if some check boxes change with the data while most do not. 
    330 * :obj:`DomainContextHandler.List` tells that the attribute corresponds to a list box. 
     372* :obj:`DomainContextHandler.Optional`, 
     373  :obj:`DomainContextHandler.SelectedRequired` and 
     374  :obj:`DomainContextHandler.Required` state whether the attribute is optional 
     375  or required, as explained above. Default is :obj:`Required`. 
     376  :obj:`DomainContextHandler.SelectedRequired` is applicable only if the 
     377  control is a list box, where it means that the attributes that are selected 
     378  are required while the other attributes from the list are not. 
     379 
     380* :obj:`DomainContextHandler.NotAttribute` the setting is not an attribute 
     381  name. You can essentially make a check box context dependent, but we very 
     382  strongly dissuade from this since it can really confuse the user if some 
     383  check boxes change with the data while most do not. 
     384 
     385* :obj:`DomainContextHandler.List` tells that the attribute corresponds to a 
     386  list box. 
    331387 
    332388 
     
    348404But the tuples are actually a shortcut for instances of 
    349405:obj:`ContextField`. When you say :obj:`"attrX"` this is actually 
    350 :obj:`ContextField("attrX", DomainContextHandler.Required)` (you should 
    351 appreciate the shortcurt, right?). But see this monster from widget "Select 
    352 Attributes" (file OWDataDomain.py):: 
    353  
    354     contextHandlers = {"": DomainContextHandler("", 
    355         [ContextField("chosenAttributes", 
    356                        DomainContextHandler.RequiredList, 
    357                        selected="selectedChosen", reservoir="inputAttributes"), 
    358          ContextField("classAttribute", 
    359                        DomainContextHandler.RequiredList, 
    360                        selected="selectedClass", reservoir="inputAttributes"), 
    361          ContextField("metaAttributes", 
    362                        DomainContextHandler.RequiredList, 
    363                        selected="selectedMeta", reservoir="inputAttributes") 
    364     ])} 
    365  
    366  
    367 :obj:`ContextField`'s constructor gets the name and flags and a list of 
    368 arguments that are written directly into the object instance. To follow the 
    369 example, recall what Select Attributes looks like: it allows you to select a 
    370 subset of attributes, the class attribute and the meta attributes that you 
    371 want to use; the attributes in the corresponding three list boxes are stored 
    372 in the widget's variables :obj:`chosenAttributes`, :obj:`classAttribute` 
    373 and :obj:`metaAttributes` respectively. When the user selects some attributes 
    374 in any of these boxes, the selection is stored in :obj:`selectedChosen`, 
    375 :obj:`selectedClass` and :obj:`selectedMeta`. The remaining attributes 
    376 - those that are not in any of these three list boxes - are in the leftover 
    377 listbox on the left-hand side of the widget, and the content of the box is 
    378 stored in the widget's variable :obj:`inputAttributes`. 
    379  
    380 The above definition tells that the context needs to store the contents of 
    381 the three list boxes by specifying the corresponding variables; the list of 
    382 attributes is given as the name of the field and the list of selected 
    383 attributes is in the optional named attribute :obj:`selected`. By 
    384 :obj:`reservoir` we told the context handler that the attributes are taken 
    385 from :obj:`inputAttributes`. So, when a context is retrieved, all the 
    386 attributes that are not in any of the three list boxes are put into 
    387 :obj:`inputAttributes`. 
    388  
    389 Why the mess? Couldn't we just store :obj:`inputAttributes` as the fourth 
    390 list box? Imagine that the user first loads the data with attributes A, B, 
    391 C, D, E and F, puts A, B, C in chosen and D in class. E and F are left in 
    392 :obj:`inputAttributes`. Now she loads another data which has attributes A, 
    393 B, C, D, E, and G. The contexts should match (the new data has all the 
    394 attributes we need), but :obj:`inputAttributes` should now contain E and 
    395 G, not E and F, since F doesn't exist any more, while G needs to be made 
    396 available. 
    397  
    398 You can use :obj:`ContextField` (instead of tuples and strings) for 
    399 declaring any fields, but you will usually need them only for lists or, 
    400 maybe, some complicated future controls. 
     406:obj:`ContextField("attrX", DomainContextHandler.Required)` 
     407 
     408.. 
     409   But see this monster from widget "Select Attributes" (file OWDataDomain.py):: 
     410 
     411       contextHandlers = {"": DomainContextHandler("", 
     412           [ContextField("chosenAttributes", 
     413                          DomainContextHandler.RequiredList, 
     414                          selected="selectedChosen", reservoir="inputAttributes"), 
     415            ContextField("classAttribute", 
     416                          DomainContextHandler.RequiredList, 
     417                          selected="selectedClass", reservoir="inputAttributes"), 
     418            ContextField("metaAttributes", 
     419                          DomainContextHandler.RequiredList, 
     420                          selected="selectedMeta", reservoir="inputAttributes") 
     421       ])} 
     422 
     423 
     424   :obj:`ContextField`'s constructor gets the name and flags and a list of 
     425   arguments that are written directly into the object instance. To follow the 
     426   example, recall what Select Attributes looks like: it allows you to select a 
     427   subset of attributes, the class attribute and the meta attributes that you 
     428   want to use; the attributes in the corresponding three list boxes are stored 
     429   in the widget's variables :obj:`chosenAttributes`, :obj:`classAttribute` 
     430   and :obj:`metaAttributes` respectively. When the user selects some attributes 
     431   in any of these boxes, the selection is stored in :obj:`selectedChosen`, 
     432   :obj:`selectedClass` and :obj:`selectedMeta`. The remaining attributes 
     433   - those that are not in any of these three list boxes - are in the leftover 
     434   listbox on the left-hand side of the widget, and the content of the box is 
     435   stored in the widget's variable :obj:`inputAttributes`. 
     436 
     437   The above definition tells that the context needs to store the contents of 
     438   the three list boxes by specifying the corresponding variables; the list of 
     439   attributes is given as the name of the field and the list of selected 
     440   attributes is in the optional named attribute :obj:`selected`. By 
     441   :obj:`reservoir` we told the context handler that the attributes are taken 
     442   from :obj:`inputAttributes`. So, when a context is retrieved, all the 
     443   attributes that are not in any of the three list boxes are put into 
     444   :obj:`inputAttributes`. 
     445 
     446   Why the mess? Couldn't we just store :obj:`inputAttributes` as the fourth 
     447   list box? Imagine that the user first loads the data with attributes A, B, 
     448   C, D, E and F, puts A, B, C in chosen and D in class. E and F are left in 
     449   :obj:`inputAttributes`. Now she loads another data which has attributes A, 
     450   B, C, D, E, and G. The contexts should match (the new data has all the 
     451   attributes we need), but :obj:`inputAttributes` should now contain E and 
     452   G, not E and F, since F doesn't exist any more, while G needs to be made 
     453   available. 
     454 
     455   You can use :obj:`ContextField` (instead of tuples and strings) for 
     456   declaring any fields, but you will usually need them only for lists or, 
     457   maybe, some complicated future controls. 
    401458 
    402459 
     
    405462***************************** 
    406463 
    407 Avoid it if you can. If you can't, here's the list of the methods you may need to implement. You may want to copy as much from the :obj:`DomainContextHandler` as you can. 
    408  
    409  
    410 __init__ 
    411 Has the same arguments as the :obj:`DomainContextHandler`'s, except for the :obj:`fields`. 
    412  
    413 newContext 
    414 Creates and returns a new context. In :obj:`ContextHandler` is returns an instance of :obj:`Context`; you probably won't need to change this. 
    415  
    416 openContext 
    417 The method is given a widget and some additional arguments based on which the contexts are compared. In case of :obj:`DomainContextHandler` this is a domain. There can be one or more such arguments. Note that the method :obj:`openContext` which we talked about above is a method of :obj:`OWBaseWidget`, while here we describe a method of context handlers. Actually, :obj:`OWBaseWidget(self, contextName, *args)` calls the context handler's, passing it's :obj:`self` and :obj:`*args`. 
    418  
    419 It needs to find a matching context and copy its settings to the widget or construct a new context and copy the settings from the widget. Also, when an old context is reused, it should be moved to the beginning of the list. :obj:`ContextHandler` already defines this method, which should usually suffice. :obj:`DomainContextHandler` adds very little to it. 
    420  
    421 closeContext 
    422 Copies the settings from the widget by calling :obj:`settingsFromWidget`. You probably won't need to overwrite it. 
    423  
    424 match 
    425 The method is called by :obj:`openContext` to find a matching context. Given an existing context and the arguments that were given to :obj:`openContext` (for instance, a domain), it should decide whether the context matches or not. If it returns 2, it is a perfect match (e.g. domains are the same). If it returns 0, the context is not applicable (e.g. some of the required attributes are missing). In case it returns a number between 0 and 1 (excluding 0), the higher the number the better the match. :obj:`openContext` will use the best matching context (or the perfect one, if found). 
    426  
    427 settingsToWidget/settingsFromWidget 
    428 Copy the settings to and from the widget. 
    429  
    430 fastSave 
    431 This function is called by the widget's :obj:`__setattr__` each time any widget's variable is changed to immediately synchronize the context with the state of the widget. The method is really needed only when :obj:`syncWithGlobal` is set. When the context is closed, :obj:`closeContext` will save the settings anyway. 
    432  
    433 cloneContext 
    434 Given an existing context, it prepares and returns a copy. The method is optional; :obj:`copy.deepcopy` can be used instead. 
     464Avoid it if you can. If you can't, here's the list of the methods you may need 
     465to implement. You may want to copy as much from the :obj:`DomainContextHandler` 
     466as you can. 
     467 
     468 
     469:obj:`__init__` 
     470   Has the same arguments as the :obj:`DomainContextHandler`'s, except for the 
     471   :obj:`fields`. 
     472 
     473:obj:`newContext()` 
     474   Creates and returns a new context. In :obj:`ContextHandler` it returns an 
     475   instance of :obj:`Context`; you probably won't need to change this. 
     476 
     477:obj:`openContext(widget, *args)` 
     478   The method is given a widget and some additional arguments based on which 
     479   the contexts are compared. In case of :obj:`DomainContextHandler` this is 
     480   a domain. There can be one or more such arguments. Note that the method 
     481   :obj:`openContext` which we talked about above is a method of 
     482   :obj:`OWBaseWidget`, while here we describe a method of context handlers. 
     483   Actually, :obj:`OWBaseWidget.openContext(self,contextName, *args)` calls 
     484   the context handler's, passing it's :obj:`self` and :obj:`*args`. 
     485 
     486   It needs to find a matching context and copy its settings to the widget or 
     487   construct a new context and copy the settings from the widget. Also, when an 
     488   old context is reused, it should be moved to the beginning of the list. 
     489   :obj:`ContextHandler` already defines this method, which should usually 
     490   suffice. :obj:`DomainContextHandler` adds very little to it. 
     491 
     492:obj:`closeContext` 
     493   Copies the settings from the widget by calling :obj:`settingsFromWidget`. 
     494   You probably won't need to overwrite it. 
     495 
     496:obj:`match` 
     497   The method is called by :obj:`openContext` to find a matching context. 
     498   Given an existing context and the arguments that were given to 
     499   :obj:`openContext` (for instance, a domain), it should decide whether the 
     500   context matches or not. If it returns 2, it is a perfect match (e.g. 
     501   domains are the same). If it returns 0, the context is not applicable 
     502   (e.g. some of the required attributes are missing). In case it returns a 
     503   number between 0 and 1 (excluding 0), the higher the number the better the 
     504   match. :obj:`openContext` will use the best matching context (or the 
     505   perfect one, if found). 
     506 
     507:obj:`settingsToWidget` / :obj:`settingsFromWidget` 
     508   Copy the settings to and from the widget. 
     509 
     510:obj:`fastSave` 
     511   This function is called by the widget's :obj:`__setattr__` each time any 
     512   widget's variable is changed to immediately synchronize the context with 
     513   the state of the widget. The method is really needed only when 
     514   :obj:`syncWithGlobal` is set. When the context is closed, 
     515   :obj:`closeContext` will save the settings anyway. 
     516 
     517:obj:`cloneContext` 
     518   Given an existing context, it prepares and returns a copy. The method is 
     519   optional; :obj:`copy.deepcopy` can be used instead. 
    435520 
    436521 
     
    440525 
    441526Settings can be saved in two different places. Orange Canvas save 
    442 settings in .ini files in directory 
    443 Orange/OrangeWidgets/widgetSettings. Each widget type has its separate 
    444 file; for instance, the scatter plot's settings are saved in 
     527settings in .ini files in its application data directory. Each widget type has 
     528a separate file; for instance, the scatter plot's settings are saved in 
    445529:obj:`ScatterPlot.ini`. Saved schemas and applications save 
    446530settings in .sav files; the .sav file is placed in the same directory 
     
    451535Saving and loading is done automatically by canvas or the 
    452536application. In a very rare case you need it to run these operations 
    453 manually, the functions involved are :obj:`loadSettings(self, file = 
    454 None)`, :obj:`saveSettings(self, file = None)`, 
    455 :obj:`loadSettingsStr(self, str)`, 
     537manually, the functions involved are :obj:`loadSettings(self, file=None)`, 
     538:obj:`saveSettings(self, file=None)`, :obj:`loadSettingsStr(self, str)`, 
    456539:obj:`saveSettingsStr(self)`. The first two load and save from 
    457540the file; if not given, the default name (widget's name + 
  • docs/widgets/rst/index.rst

    r11312 r11433  
    2626    * - |Impute_icon| :ref:`Impute` 
    2727      - |Outliers_icon| :ref:`Outliers` 
     28      - |EditDomain_icon| :ref:`Edit Domain` 
     29    * - |PythonScript_icon| :ref:`Python Script` 
    2830      - 
     31      - 
    2932 
    3033.. |File_icon| image:: ../../../Orange/OrangeWidgets/Data/icons/File_48.png 
     
    111114    :width: 48 
    112115    :height: 48 
     116 
     117.. |EditDomain_icon| image:: ../../../Orange/OrangeWidgets/icons/Unknown.png 
     118   :align: middle 
     119   :alt: Edit Domain 
     120   :width: 48 
     121   :height: 48 
     122 
     123.. |PythonScript_icon| image:: ../../../Orange/OrangeWidgets/Data/icons/PythonScript_48.png 
     124   :align: middle 
     125   :alt: Edit Domain 
     126   :width: 48 
     127   :height: 48 
    113128 
    114129 
     
    601616   data/impute.rst 
    602617   data/outliers.rst 
     618   data/editdomain.rst 
    603619 
    604620   visualize/distributions.rst 
  • docs/widgets/rst/visualize/linearprojection.rst

    r11359 r11422  
    4444nicely characterizes mamals from the other organisms, and that laying eggs is 
    4545something that birds do. This specific visualization was obtained using FreeViz 
    46 ([Demsar2007]_), while the widget also implements an interface to supervised 
    47 principal component analysis ([Koren2003]_), partial least squares (for a nice 
    48 introduction, see [Boulesteix2007]_), and RadViz visualization and 
     46([1]_), while the widget also implements an interface to supervised 
     47principal component analysis ([2]_), partial least squares (for a nice 
     48introduction, see [3]_), and RadViz visualization and 
    4949associated intelligent data visualization technique called VizRank  
    50 ([Leban2006]_) 
     50([4]_) 
    5151 
    5252.. image:: images/LinearProjection-Zoo.png 
     
    7777order to understand how a change of one anchor affects the positions of the 
    7878data points. Controls in :obj:`Forces` box are used to set the parameters that 
    79 define the type of the forces between the data points (see [Demsar2007]_). 
     79define the type of the forces between the data points (see [1]_). 
    8080In any linear projection, projections of unit vector that are very short 
    8181compared to the others indicate that their associated attribute is not very 
     
    9393 
    9494The fourth projection search technique that can be accessed from this widget 
    95 is VizRank search algorithm with RadViz visualization ([Leban2006]_). This is 
     95is VizRank search algorithm with RadViz visualization ([4]_). This is 
    9696essentially the same visualization and projection search method as implemented 
    9797in :ref:`Radviz`. 
     
    107107---------- 
    108108 
    109 .. [Demsar2007] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
     109.. [1] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
    110110   visualization approach to explorative analysis of biomedical data. J Biomed 
    111111   Inform 40(6):661-71, 2007. 
    112112 
    113 .. [Koren2003] Koren Y, Carmel L. Visualization of labeled data using linear 
     113.. [2] Koren Y, Carmel L. Visualization of labeled data using linear 
    114114   transformations, in: Proceedings of IEEE Information Visualization 2003 
    115115   (InfoVis'03), 2003. `PDF <http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=3DDF0DB68D8AB9949820A19B0344C1F3?doi=10.1.1.13.8657&rep=rep1&type=pdf>`_ 
    116116 
    117 .. [Boulesteix2007] Boulesteix A-L, Strimmer K (2006) Partial least squares: 
     117.. [3] Boulesteix A-L, Strimmer K (2006) Partial least squares: 
    118118   a versatile tool for the analysis of high-dimensional genomic data, 
    119119   Briefings in Bioinformatics 8(1): 32-44.  
    120120   `Abstract <http://bib.oxfordjournals.org/cgi/content/abstract/8/1/32>`_ 
    121121 
    122 .. [Leban2006] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
     122.. [4] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
    123123   Guided by Machine Learning." Data Mining and Knowledge Discovery 13(2): 
    124124   119-136. 
  • docs/widgets/rst/visualize/radviz.rst

    r11359 r11422  
    3333----------- 
    3434 
    35 Radviz ([Hoffman1997]_) is a neat non-linear multi-dimensional visualization 
     35Radviz ([1]_) is a neat non-linear multi-dimensional visualization 
    3636technique that can display data on three or more attributes in a 2-dimensional 
    3737projection. The visualized attributes are presented as anchor points equally 
     
    4747 
    4848The snapshot shown below shows a Radviz widget with a visualization of the 
    49 data set from functional genomics ([Brown2000]_). In this particular 
     49data set from functional genomics ([2]_). In this particular 
    5050visualization the data instances are colored according to the corresponding 
    5151class, and the visualization space is colored according to the computed class 
     
    6464"spo mid") is quite characteristic for instance of class Ribo, which at the 
    6565same time have comparable lower value of other attributes. High values of 
    66 heat 20 and diau f are characteristic for Resp class. See [Leban2006]_ and 
    67 [Mramor2007]_ for further illustrations of utility of Radviz in analysis of 
     66heat 20 and diau f are characteristic for Resp class. See [3]_ and 
     67[5]_ for further illustrations of utility of Radviz in analysis of 
    6868this and similar data set from functional genomics. Other options in the 
    6969:obj:`Settings` tab are quite standard. The :obj:`Point size` controls the size 
     
    8686 
    8787Just like all point-based visualizations, this widget includes tools for 
    88 intelligent data visualization (VizRank and FreeViz, see [Leban2006]_) and 
    89 [Demsar2007]_) and interface for explorative data analysis - selection of data 
     88intelligent data visualization (VizRank and FreeViz, see [3]_) and 
     89[4]_) and interface for explorative data analysis - selection of data 
    9090points in visualization. Just like in :ref:`Scatter Plot` widget, intelligent 
    9191visualization can be used to find a set of attributes that would result in an 
     
    103103---------- 
    104104 
    105 .. [Hoffman1997] Hoffman,P.E. et al. (1997) DNA visual and analytic data mining. 
     105.. [1] Hoffman,P.E. et al. (1997) DNA visual and analytic data mining. 
    106106   In the Proceedings of the IEEE Visualization. Phoenix, AZ, pp. 437-441. 
    107107 
    108 .. [Brown2000] Brown, M. P., W. N. Grundy, et al. (2000). 
     108.. [2] Brown, M. P., W. N. Grundy, et al. (2000). 
    109109   "Knowledge-based analysis of microarray gene expression data by using 
    110110   support vector machines." Proc Natl Acad Sci U S A 97(1): 262-7. 
    111111 
    112 .. [Leban2006] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
     112.. [3] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
    113113   Guided by Machine Learning." Data Mining and Knowledge Discovery 13(2): 
    114114   119-136. 
    115115 
    116 .. [Demsar2007] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
     116.. [4] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
    117117   visualization approach to explorative analysis of biomedical data. J Biomed 
    118118   Inform 40(6):661-71, 2007. 
    119119 
    120 .. [Mramor2007] Mramor M, Leban G, Demsar J, Zupan B. Visualization-based 
     120.. [5] Mramor M, Leban G, Demsar J, Zupan B. Visualization-based 
    121121   cancer microarray data classification analysis. Bioinformatics 23(16): 
    122122   2147-2154, 2007. 
  • docs/widgets/rst/visualize/scatterplot.rst

    r11359 r11422  
    6868all the pairs of attributes to find interesting scatterplots. Intelligent data 
    6969visualizations techniques are about finding such visualizations automatically. 
    70 Orange's Scatterplot includes one such tool called VizRank ([Leban2006]_), that 
     70Orange's Scatterplot includes one such tool called VizRank ([1]_), that 
    7171can be in current implementation used only with classification data sets, that 
    7272is, data sets where instances are labeled with a discrete class. The task of 
     
    9898learning it would be best to leave them at their defaults. The options are 
    9999grouped according to the different aspects of the methods as described in 
    100 [Leban2006]_. The projections are evaluated through testing a selected 
     100[1]_. The projections are evaluated through testing a selected 
    101101classifier (:obj:`Projection evaluation method` default is k-nearest neighbor 
    102102classification) using some standard evaluation technique 
     
    202202---------- 
    203203 
    204 .. [Leban2006] Leban G, Zupan B, Vidmar G, Bratko I. VizRank: Data 
     204.. [1] Leban G, Zupan B, Vidmar G, Bratko I. VizRank: Data 
    205205   Visualization Guided by Machine Learning. Data Mining and Knowledge 
    206206   Discovery 13(2): 119-136, 2006. 
  • install-scripts/mac/bundle-daily-build-hg.sh

    r10789 r11427  
    33# ./bundle-daily-build-hg.sh 
    44# 
    5 # $1 Force 
     5# $1 workdir (directory where sources can be checked out and build) 
     6# $2 publishdir (directory where the resulting versioned bundle can be moved) 
     7# $3 force (force the build even if a bundle with the same revision exists at publishdir) 
     8# $4 local 
    69# 
    710 
    8 FORCE=$1 
     11WORK_DIR=${1:-"/private/tmp"} 
     12PUBLISH_DIR=${2:-"$WORK_DIR/download"} 
     13 
     14FORCE=$3 
     15LOCAL=$4 
     16 
     17ORANGE_REPO=$WORK_DIR/repos/orange 
    918 
    1019trap "echo \"Script failed\"" ERR 
    1120 
    1221# If possible get the orange tip revision number and check if the bundle already exists 
    13 if [ -e /private/tmp/repos/orange ]; then 
     22if [ -e $ORANGE_REPO ]; then 
    1423    # Try to pull and update (pull returns 1 if no changesets) 
    15     hg pull --update -R /private/tmp/repos/orange || true 
    16     DAILY_REVISION=`hg log -r tip -R /private/tmp/repos/orange | grep 'changeset:' | cut -d ' ' -f 4 | cut -d ':' -f 1` 
     24    hg pull --update -R $ORANGE_REPO || true 
     25    DAILY_REVISION=`hg log -r tip -R $ORANGE_REPO | grep 'changeset:' | cut -d ' ' -f 4 | cut -d ':' -f 1` 
    1726else 
    1827    DAILY_REVISION="tip" 
    1928fi 
    2029 
    21 BUNDLE="/private/tmp/orange-bundle-hg-$DAILY_REVISION.dmg" 
    22          
     30BUNDLE="$WORK_DIR/orange-bundle-hg-$DAILY_REVISION.dmg" 
     31PUBLISH_BUNDLE=$PUBLISH_DIR/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
     32 
     33 
    2334# Create the bundle if it does not yet exist 
    24 if [[ ! -e /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg || $DAILY_REVISION -eq "tip" || $FORCE ]]; then 
     35if [[ ! -e $PUBLISH_BUNDLE || $DAILY_REVISION -eq "tip" || $FORCE ]]; then 
    2536    echo "Building orange revision $DAILY_REVISION" 
    26     ./bundle-build-hg.sh /private/tmp tip $BUNDLE 
     37    ./bundle-build-hg.sh $WORK_DIR tip $BUNDLE 
    2738     
    2839    # Get the revision again in case it was "tip" 
    29     DAILY_REVISION=`hg log -r tip -R /private/tmp/repos/orange | grep 'changeset:' | cut -d ' ' -f 4 | cut -d ':' -f 1` 
     40    DAILY_REVISION=`hg log -r tip -R $ORANGE_REPO | grep 'changeset:' | cut -d ' ' -f 4 | cut -d ':' -f 1` 
     41    # And update the publish bundle filename 
     42    PUBLISH_BUNDLE=$PUBLISH_DIR/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
    3043 
    31     # TODO: Should be called only on a daily build server and not if building locally 
    32     /Users/ailabc/mount-dirs.sh 
     44    if [ ! $LOCAL ]; then 
     45        /Users/ailabc/mount-dirs.sh 
     46    fi 
    3347 
    3448    echo "Removing old versions of bundles." 
    3549    # (Keeps last 5 versions.) 
    36     perl -e 'unlink ((reverse sort </Volumes/download/orange-bundle-hg-0*.dmg>)[5..10000])' 
     50    perl -e "unlink ((reverse sort <$PUBLISH_DIR/orange-bundle-hg-0*.dmg>)[5..10000])" 
    3751 
    3852    MD5=`md5 -q $BUNDLE` 
    3953     
    4054    echo "Moving bundle to the download directory." 
    41     mv $BUNDLE /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
     55    mv $BUNDLE $PUBLISH_BUNDLE.new 
    4256 
    4357    echo "Setting permissions." 
    44     chmod +r /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
     58    chmod +r $PUBLISH_BUNDLE.new 
    4559 
    46     # Check integrity  
    47     MD5_D=`md5 -q /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg` 
     60    # Check integrity 
     61    MD5_D=`md5 -q $PUBLISH_BUNDLE.new` 
    4862    if [[ $MD5 != $MD5_D ]]; then 
    4963        echo "Error moving the bundle in place" 
    50         rm /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
     64        rm $PUBLISH_BUNDLE.new 
    5165        exit 1 
     66    else 
     67        mv $PUBLISH_BUNDLE.new $PUBLISH_BUNDLE 
    5268    fi 
    5369     
    5470    echo "Registering new bundles." 
    55     egrep -v '^(MAC_DAILY)=' /Volumes/download/filenames_mac.set > /Volumes/download/filenames_mac.set.new 
    56     echo "MAC_DAILY=orange-bundle-hg-0.0.$DAILY_REVISION.dmg" >> /Volumes/download/filenames_mac.set.new 
    57     mv /Volumes/download/filenames_mac.set.new /Volumes/download/filenames_mac.set 
     71    egrep -v '^(MAC_DAILY)=' $PUBLISH_DIR/filenames_mac.set > $PUBLISH_DIR/filenames_mac.set.new 
     72    echo "MAC_DAILY=orange-bundle-hg-0.0.$DAILY_REVISION.dmg" >> $PUBLISH_DIR/filenames_mac.set.new 
     73    mv $PUBLISH_DIR/filenames_mac.set.new $PUBLISH_DIR/filenames_mac.set 
    5874 
    5975else 
  • install-scripts/mac/dailyrun-bundleonly-hg.sh

    r10345 r11427  
    1212/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; } 
    1313 
    14 /Users/ailabc/bundle-daily-build-hg.sh /private/tmp &> /private/tmp/bundle-daily-build-hg.log 
     14/Users/ailabc/bundle-daily-build-hg.sh /private/tmp /Volumes/download &> /private/tmp/bundle-daily-build-hg.log 
    1515EXIT_VALUE=$? 
    1616 
  • install-scripts/mac/dailyrun.sh

    r10910 r11429  
    9090## Daily bundle build from hg (for now always until versioning is established). 
    9191if [[ true || $NEW_ORANGE || $NEW_BIOINFORMATICS || $NEW_TEXT || $FORCE ]]; then 
    92     ./bundle-daily-build-hg.sh $NEW_BUNDLE_ADDONS &> $WORK_DIR/bundle-daily-build.log 
     92    ./bundle-daily-build-hg.sh "$WORK_DIR" "$PUBLISH_DIR" $NEW_BUNDLE_ADDONS &> $WORK_DIR/bundle-daily-build.log 
    9393    EXIT_VALUE=$? 
    9494fi 
     
    104104 
    105105 
    106 MAC_VERSION=`sw_vers -productVersion | cut -d '.' -f 2` 
    107 ARCH=`perl -MFink::FinkVersion -e 'print Fink::FinkVersion::get_arch'` 
    108  
    109 FINK_ROOT=/sw 
    110  
    111 if [ ! $LOCAL ]; then 
    112     # Compare with the published info files 
    113     BASE="http://orange.biolab.si/fink/dists/$ARCH/main/finkinfo" 
    114 else 
    115     # Compare with the local info files 
    116     BASE="file://$FINK_ROOT/fink/dists/local/main/finkinfo" 
    117 fi 
    118  
    119  
    120 OLD_ORANGE_VERSION=`curl --silent $BASE/orange-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
    121 OLD_BIOINFORMATICS_VERSION=`curl --silent $BASE/orange-bioinformatics-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
    122 OLD_TEXT_VERSION=`curl --silent $BASE/orange-text-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
    123  
    124 if [[ $OLD_ORANGE_VERSION < $ORANGE_VERSION ]]; then 
    125     NEW_ORANGE=1 
    126 fi 
    127  
    128 if [[ $OLD_BIOINFORMATICS_VERSION < $BIOINFORMATICS_VERSION ]]; then 
    129     NEW_BIOINFORMATICS=1 
    130 fi 
    131  
    132 if [[ $OLD_TEXT_VERSION < $TEXT_VERSION ]]; then 
    133     NEW_TEXT=1 
    134 fi 
    135  
    136  
    137 # Base url for sources in fink .info files 
    138 if [ $LOCAL ]; then 
    139     BASE_URL="file://$PUBLISH_DIR/sources" 
    140 else 
    141     BASE_URL="http://orange.biolab.si/download/sources" 
    142 fi 
    143  
    144 # Update the local finkinfo  
    145 # Local info files will be moved to biolab/main/finkinfo in fink-daily-build-packages.sh 
    146 FINK_INFO_DIR="$FINK_ROOT/fink/dists/local/main/finkinfo" 
    147  
    148 if [ ! -e $FINK_INFO_DIR ]; then 
    149     mkdir -p $FINK_INFO_DIR 
    150 fi 
    151  
    152 # Remove any old remaining local .info files 
    153 rm -f $FINK_INFO_DIR/orange-*.info 
    154  
    155 # Directory where fink .info templates are 
    156 FINK_TEMPLATES=$WORK_DIR/orange/install-scripts/mac/fink 
    157  
    158 FINK_LOG=$WORK_DIR/fink-daily-build.log 
    159 echo "" > $FINK_LOG 
    160  
    161 if [[ $NEW_ORANGE || $FORCE ]]; then 
    162     FINK_ORANGE_SOURCE_TEMPLATE="Orange-%v.tar.gz" 
    163     ./fink-register-info.sh "$FINK_TEMPLATES/orange-gui-dev-py.info" $BASE_URL/$FINK_ORANGE_SOURCE_TEMPLATE $ORANGE_SOURCE_MD5 $ORANGE_VERSION $FINK_INFO_DIR/orange-gui-dev-py.info >> $FINK_LOG 2>&1 
    164     FINK_ORANGE_INFO_EXIT_VALUE=$? 
    165 fi 
    166  
    167 if [[ $NEW_BIOINFORMATICS || $FORCE ]]; then 
    168     FINK_BIOINFORMATICS_SOURCE_TEMPLATE="Orange-Bioinformatics-%v.tar.gz" 
    169     ./fink-register-info.sh "$FINK_TEMPLATES/orange-bioinformatics-gui-dev-py.info" $BASE_URL/$FINK_BIOINFORMATICS_SOURCE_TEMPLATE $BIOINFORMATICS_SOURCE_MD5 $BIOINFORMATICS_VERSION $FINK_INFO_DIR/orange-bioinformatics-gui-dev-py.info >> $FINK_LOG 2>&1 
    170     FINK_BIOINFORMATICS_INFO_EXIT_VALUE=$? 
    171 fi 
    172  
    173 if [[ $NEW_TEXT || $FORCE ]]; then 
    174     FINK_TEXT_SOURCE_TEMPLATE="Orange-Text-%v.tar.gz" 
    175     ./fink-register-info.sh "$FINK_TEMPLATES/orange-text-gui-dev-py.info" $BASE_URL/$FINK_TEXT_SOURCE_TEMPLATE $TEXT_SOURCE_MD5 $TEXT_VERSION $FINK_INFO_DIR/orange-text-gui-dev-py.info >> $FINK_LOG 2>&1 
    176     FINK_TEXT_INFO_EXIT_VALUE=$? 
    177 fi 
    178  
    179 if [ ! $LOCAL ]; then 
    180     /Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; } 
    181 fi 
    182  
    183 EXIT_VALUE=$(($FINK_ORANGE_INFO_EXIT_VALUE + $FINK_BIOINFORMATICS_INFO_EXIT_VALUE + $FINK_TEXT_INFO_EXIT_VALUE)) 
    184 if (($EXIT_VALUE)); then 
    185     echo "Running fink-register-info.sh failed" 
    186     rm -f $FINK_INFO_DIR/orange-*.info 
    187 fi 
    188  
    189 ## daily fink build 
    190  
    191 ./fink-daily-build-packages.sh &> $WORK_DIR/fink-daily-build-packages.log 
    192 EXIT_VALUE=$? 
    193  
    194 if [ ! $LOCAL ]; then 
    195     /Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; } 
    196 fi 
    197  
    198 echo "Orange (fink $MAC_VERSION $ARCH) [$EXIT_VALUE]" > "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
    199 date >> "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
    200 cat $WORK_DIR/fink-daily-build-packages.log >> "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
    201 (($EXIT_VALUE)) && echo "Running fink-daily-build.sh failed" 
     106#MAC_VERSION=`sw_vers -productVersion | cut -d '.' -f 2` 
     107#ARCH=`perl -MFink::FinkVersion -e 'print Fink::FinkVersion::get_arch'` 
     108# 
     109#FINK_ROOT=/sw 
     110# 
     111#if [ ! $LOCAL ]; then 
     112#   # Compare with the published info files 
     113#   BASE="http://orange.biolab.si/fink/dists/$ARCH/main/finkinfo" 
     114#else 
     115#   # Compare with the local info files 
     116#   BASE="file://$FINK_ROOT/fink/dists/local/main/finkinfo" 
     117#fi 
     118# 
     119# 
     120#OLD_ORANGE_VERSION=`curl --silent $BASE/orange-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
     121#OLD_BIOINFORMATICS_VERSION=`curl --silent $BASE/orange-bioinformatics-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
     122#OLD_TEXT_VERSION=`curl --silent $BASE/orange-text-gui-dev-py.info | grep "Version: " | cut -d" " -f 2` 
     123# 
     124#if [[ $OLD_ORANGE_VERSION < $ORANGE_VERSION ]]; then 
     125#   NEW_ORANGE=1 
     126#fi 
     127# 
     128#if [[ $OLD_BIOINFORMATICS_VERSION < $BIOINFORMATICS_VERSION ]]; then 
     129#   NEW_BIOINFORMATICS=1 
     130#fi 
     131# 
     132#if [[ $OLD_TEXT_VERSION < $TEXT_VERSION ]]; then 
     133#   NEW_TEXT=1 
     134#fi 
     135# 
     136# 
     137## Base url for sources in fink .info files 
     138#if [ $LOCAL ]; then 
     139#   BASE_URL="file://$PUBLISH_DIR/sources" 
     140#else 
     141#   BASE_URL="http://orange.biolab.si/download/sources" 
     142#fi 
     143# 
     144## Update the local finkinfo 
     145## Local info files will be moved to biolab/main/finkinfo in fink-daily-build-packages.sh 
     146#FINK_INFO_DIR="$FINK_ROOT/fink/dists/local/main/finkinfo" 
     147# 
     148#if [ ! -e $FINK_INFO_DIR ]; then 
     149#   mkdir -p $FINK_INFO_DIR 
     150#fi 
     151# 
     152## Remove any old remaining local .info files 
     153#rm -f $FINK_INFO_DIR/orange-*.info 
     154# 
     155## Directory where fink .info templates are 
     156#FINK_TEMPLATES=$WORK_DIR/orange/install-scripts/mac/fink 
     157# 
     158#FINK_LOG=$WORK_DIR/fink-daily-build.log 
     159#echo "" > $FINK_LOG 
     160# 
     161#if [[ $NEW_ORANGE || $FORCE ]]; then 
     162#   FINK_ORANGE_SOURCE_TEMPLATE="Orange-%v.tar.gz" 
     163#   ./fink-register-info.sh "$FINK_TEMPLATES/orange-gui-dev-py.info" $BASE_URL/$FINK_ORANGE_SOURCE_TEMPLATE $ORANGE_SOURCE_MD5 $ORANGE_VERSION $FINK_INFO_DIR/orange-gui-dev-py.info >> $FINK_LOG 2>&1 
     164#   FINK_ORANGE_INFO_EXIT_VALUE=$? 
     165#fi 
     166# 
     167#if [[ $NEW_BIOINFORMATICS || $FORCE ]]; then 
     168#   FINK_BIOINFORMATICS_SOURCE_TEMPLATE="Orange-Bioinformatics-%v.tar.gz" 
     169#   ./fink-register-info.sh "$FINK_TEMPLATES/orange-bioinformatics-gui-dev-py.info" $BASE_URL/$FINK_BIOINFORMATICS_SOURCE_TEMPLATE $BIOINFORMATICS_SOURCE_MD5 $BIOINFORMATICS_VERSION $FINK_INFO_DIR/orange-bioinformatics-gui-dev-py.info >> $FINK_LOG 2>&1 
     170#   FINK_BIOINFORMATICS_INFO_EXIT_VALUE=$? 
     171#fi 
     172# 
     173#if [[ $NEW_TEXT || $FORCE ]]; then 
     174#   FINK_TEXT_SOURCE_TEMPLATE="Orange-Text-%v.tar.gz" 
     175#   ./fink-register-info.sh "$FINK_TEMPLATES/orange-text-gui-dev-py.info" $BASE_URL/$FINK_TEXT_SOURCE_TEMPLATE $TEXT_SOURCE_MD5 $TEXT_VERSION $FINK_INFO_DIR/orange-text-gui-dev-py.info >> $FINK_LOG 2>&1 
     176#   FINK_TEXT_INFO_EXIT_VALUE=$? 
     177#fi 
     178# 
     179#if [ ! $LOCAL ]; then 
     180#   /Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; } 
     181#fi 
     182# 
     183#EXIT_VALUE=$(($FINK_ORANGE_INFO_EXIT_VALUE + $FINK_BIOINFORMATICS_INFO_EXIT_VALUE + $FINK_TEXT_INFO_EXIT_VALUE)) 
     184#if (($EXIT_VALUE)); then 
     185#   echo "Running fink-register-info.sh failed" 
     186#   rm -f $FINK_INFO_DIR/orange-*.info 
     187#fi 
     188# 
     189### daily fink build 
     190# 
     191#./fink-daily-build-packages.sh &> $WORK_DIR/fink-daily-build-packages.log 
     192#EXIT_VALUE=$? 
     193# 
     194#if [ ! $LOCAL ]; then 
     195#   /Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; } 
     196#fi 
     197# 
     198#echo "Orange (fink $MAC_VERSION $ARCH) [$EXIT_VALUE]" > "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
     199#date >> "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
     200#cat $WORK_DIR/fink-daily-build-packages.log >> "$LOG_DIR/fink-$MAC_VERSION-$ARCH-daily-build.log" 
     201#(($EXIT_VALUE)) && echo "Running fink-daily-build.sh failed" 
    202202 
    203203# Zero exit value 
  • install-scripts/mac/mount-dirs.sh

    r7862 r11429  
    55fi 
    66 
    7 umount /Volumes/fink/ 2> /dev/null || true 
    8 sleep 5 
    9 mkdir -p /Volumes/fink/ 
    10 /Users/ailabc/Downloads/sshfs-binaries/sshfs-static-leopard -o reconnect,workaround=nonodelay,uid=$(id -u),gid=$(id -g) fink@biolab.si:/files /Volumes/fink/ 
     7#umount /Volumes/fink/ 2> /dev/null || true 
     8#sleep 5 
     9#mkdir -p /Volumes/fink/ 
     10#/Users/ailabc/Downloads/sshfs-binaries/sshfs-static-leopard -o reconnect,workaround=nonodelay,uid=$(id -u),gid=$(id -g) fink@biolab.si:/files /Volumes/fink/ 
    1111 
    1212umount /Volumes/download/ 2> /dev/null || true 
  • install-scripts/mac/update-all-scripts.sh

    r10681 r11429  
    88curl --silent --output bundle-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/bundle-daily-build.sh 
    99curl --silent --output dailyrun.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun.sh 
    10 curl --silent --output dailyrun-finkonly-withsource.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-finkonly-withsource.sh 
    11 curl --silent --output dailyrun-finkonly.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-finkonly.sh 
     10#curl --silent --output dailyrun-finkonly-withsource.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-finkonly-withsource.sh 
     11#curl --silent --output dailyrun-finkonly.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-finkonly.sh 
    1212curl --silent --output dailyrun-bundleonly.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-bundleonly.sh 
    13 curl --silent --output fink-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build.sh 
    14 curl --silent --output fink-restore-selections.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-restore-selections.sh 
    15 curl --silent --output fink-selfupdate-orange.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-selfupdate-orange.sh 
    16 curl --silent --output force-fink-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/force-fink-daily-build.sh 
     13#curl --silent --output fink-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build.sh 
     14#curl --silent --output fink-restore-selections.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-restore-selections.sh 
     15#curl --silent --output fink-selfupdate-orange.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-selfupdate-orange.sh 
     16#curl --silent --output force-fink-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/force-fink-daily-build.sh 
    1717curl --silent --output mount-dirs.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/mount-dirs.sh 
    1818 
     
    2222curl --silent --output bundle-inject-pypi.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/bundle-inject-pypi.sh 
    2323curl --silent --output dailyrun-bundleonly-hg.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-bundleonly-hg.sh 
    24 curl --silent --output fink-daily-build-packages.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build-packages.sh 
    25 curl --silent --output fink-register-info.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-register-info.sh 
     24#curl --silent --output fink-daily-build-packages.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build-packages.sh 
     25#curl --silent --output fink-register-info.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-register-info.sh 
    2626curl --silent --output build-source.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/build-source.sh 
    2727curl --silent --output dailyrun-sources.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-sources.sh 
  • install-scripts/vmware/vmware-dailyrun-macosx-6.sh

    r8099 r11435  
    9191# WARNING: This is generally insecure as an attacker could change dailyrun-finkonly.sh file and ... 
    9292#          but we are using it in a VMware which is used only for this script, so ... 
    93 ssh ailabc@$IP_ADDRESS "sudo /Users/ailabc/dailyrun-finkonly.sh" 
     93#ssh ailabc@$IP_ADDRESS "sudo /Users/ailabc/dailyrun-finkonly.sh" 
    9494 
    9595stop_vmware 
Note: See TracChangeset for help on using the changeset viewer.