Ignore:
Files:
26 added
4 deleted
21 edited

Legend:

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

    r11432 r11096  
    1515import Orange 
    1616 
    17  
    1817def is_discrete(var): 
    1918    return isinstance(var, Orange.feature.Discrete) 
    2019 
    21  
    2220def is_continuous(var): 
    2321    return isinstance(var, Orange.feature.Continuous) 
    2422 
    25  
    2623def get_qualified(module, name): 
    27     """Return a qualified module member ``name`` inside the named 
     24    """Return a qualified module member ``name`` inside the named  
    2825    ``module``. 
    29  
     26     
    3027    The module (or package) first gets imported and the name 
    3128    is retrieved from the module's global namespace. 
    32  
     29      
    3330    """ 
    3431    # see __import__.__doc__ for why 'fromlist' is used 
     
    3633    return getattr(module, name) 
    3734 
    38  
    3935def variable_description(var): 
    4036    """Return a variable descriptor. 
    41  
    42     A descriptor is a hashable tuple which should uniquely define 
    43     the variable i.e. (module, type_name, variable_name, 
     37     
     38    A descriptor is a hashable tuple which should uniquely define  
     39    the variable i.e. (module, type_name, variable_name,  
    4440    any_kwargs, sorted-attributes-items). 
    45  
     41     
    4642    """ 
    4743    var_type = type(var) 
     
    4945        return (var_type.__module__, 
    5046                var_type.__name__, 
    51                 var.name, 
    52                 (("values", tuple(var.values)),), 
     47                var.name,  
     48                (("values", tuple(var.values)),),  
    5349                tuple(sorted(var.attributes.items()))) 
    5450    else: 
    5551        return (var_type.__module__, 
    5652                var_type.__name__, 
    57                 var.name, 
    58                 (), 
     53                var.name,  
     54                (),  
    5955                tuple(sorted(var.attributes.items()))) 
    6056 
    61  
    6257def variable_from_description(description): 
    63     """Construct a variable from its description (see 
    64     :func:`variable_description`). 
    65  
     58    """Construct a variable from its description 
     59    (:ref:`variable_description`). 
     60     
    6661    """ 
    6762    module, type_name, name, kwargs, attrs = description 
     
    6964        type = get_qualified(module, type_name) 
    7065    except (ImportError, AttributeError), ex: 
    71         raise ValueError("Invalid descriptor type '{}.{}" 
    72                          "".format(module, type_name)) 
    73  
     66        raise ValueError("""Invalid descriptor type '{}.{}\ 
     67        """.format(module, type_name)) 
     68         
    7469    var = type(name, **dict(list(kwargs))) 
    7570    var.attributes.update(attrs) 
    7671    return var 
    77  
     72     
    7873from PyQt4 import QtCore, QtGui 
    7974 
    8075QtCore.Slot = QtCore.pyqtSlot 
    8176QtCore.Signal = QtCore.pyqtSignal 
    82  
    8377 
    8478class PyStandardItem(QStandardItem): 
    8579    def __lt__(self, other): 
    8680        return id(self) < id(other) 
    87  
    88  
     81     
    8982class DictItemsModel(QStandardItemModel): 
    9083    """A Qt Item Model class displaying the contents of a python 
    9184    dictionary. 
    92  
     85     
    9386    """ 
    9487    # Implement a proper model with in-place editing. 
     
    9891        self.setHorizontalHeaderLabels(["Key", "Value"]) 
    9992        self.set_dict(dict) 
    100  
     93         
    10194    def set_dict(self, dict): 
    10295        self._dict = dict 
     
    109102            value_item.setFlags(value_item.flags() | Qt.ItemIsEditable) 
    110103            self.appendRow([key_item, value_item]) 
    111  
     104             
    112105    def get_dict(self): 
    113106        dict = {} 
     
    118111        return dict 
    119112 
    120  
    121113class VariableEditor(QWidget): 
    122114    """An editor widget for a variable. 
    123  
     115     
    124116    Can edit the variable name, and its attributes dictionary. 
    125  
     117      
    126118    """ 
    127119    def __init__(self, parent=None): 
    128120        QWidget.__init__(self, parent) 
    129121        self.setup_gui() 
    130  
     122         
    131123    def setup_gui(self): 
    132124        layout = QVBoxLayout() 
    133125        self.setLayout(layout) 
    134  
     126         
    135127        self.main_form = QFormLayout() 
    136128        self.main_form.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) 
    137129        layout.addLayout(self.main_form) 
    138  
     130         
    139131        self._setup_gui_name() 
    140132        self._setup_gui_labels() 
    141  
     133         
    142134    def _setup_gui_name(self): 
    143135        self.name_edit = QLineEdit() 
    144136        self.main_form.addRow("Name", self.name_edit) 
    145137        self.name_edit.editingFinished.connect(self.on_name_changed) 
    146  
     138         
    147139    def _setup_gui_labels(self): 
    148140        vlayout = QVBoxLayout() 
    149141        vlayout.setContentsMargins(0, 0, 0, 0) 
    150142        vlayout.setSpacing(1) 
    151  
     143         
    152144        self.labels_edit = QTreeView() 
    153145        self.labels_edit.setEditTriggers(QTreeView.CurrentChanged) 
    154146        self.labels_edit.setRootIsDecorated(False) 
    155  
     147         
    156148        self.labels_model = DictItemsModel() 
    157149        self.labels_edit.setModel(self.labels_model) 
    158  
    159         self.labels_edit.selectionModel().selectionChanged.connect( 
    160             self.on_label_selection_changed) 
    161  
     150         
     151        self.labels_edit.selectionModel().selectionChanged.connect(\ 
     152                                    self.on_label_selection_changed) 
     153         
    162154        # Necessary signals to know when the labels change 
    163155        self.labels_model.dataChanged.connect(self.on_labels_changed) 
    164156        self.labels_model.rowsInserted.connect(self.on_labels_changed) 
    165157        self.labels_model.rowsRemoved.connect(self.on_labels_changed) 
    166  
     158         
    167159        vlayout.addWidget(self.labels_edit) 
    168160        hlayout = QHBoxLayout() 
     
    180172                        enabled=False, 
    181173                        shortcut=QKeySequence(QKeySequence.Delete)) 
    182  
     174         
    183175        button_size = OWGUI.toolButtonSizeHint() 
    184176        button_size = QSize(button_size, button_size) 
    185  
     177         
    186178        button = QToolButton(self) 
    187179        button.setFixedSize(button_size) 
    188180        button.setDefaultAction(self.add_label_action) 
    189181        hlayout.addWidget(button) 
    190  
     182         
    191183        button = QToolButton(self) 
    192184        button.setFixedSize(button_size) 
     
    195187        hlayout.addStretch(10) 
    196188        vlayout.addLayout(hlayout) 
    197  
     189         
    198190        self.main_form.addRow("Labels", vlayout) 
    199  
     191         
    200192    def set_data(self, var): 
    201193        """Set the variable to edit. 
     
    203195        self.clear() 
    204196        self.var = var 
    205  
     197         
    206198        if var is not None: 
    207199            self.name_edit.setText(var.name) 
     
    211203            self.add_label_action.setEnabled(False) 
    212204            self.remove_label_action.setEnabled(False) 
    213  
     205             
    214206    def get_data(self): 
    215207        """Retrieve the modified variable. 
     
    217209        name = str(self.name_edit.text()) 
    218210        labels = self.labels_model.get_dict() 
    219  
    220         # Is the variable actually changed. 
     211         
     212        # Is the variable actually changed.  
    221213        if not self.is_same(): 
    222214            var = type(self.var)(name) 
     
    225217        else: 
    226218            var = self.var 
    227  
     219         
    228220        return var 
    229  
     221     
    230222    def is_same(self): 
    231         """Is the current model state the same as the input. 
     223        """Is the current model state the same as the input.  
    232224        """ 
    233225        name = str(self.name_edit.text()) 
    234226        labels = self.labels_model.get_dict() 
    235  
     227         
    236228        return self.var and name == self.var.name and labels == self.var.attributes 
    237  
     229             
    238230    def clear(self): 
    239231        """Clear the editor state. 
     
    242234        self.name_edit.setText("") 
    243235        self.labels_model.set_dict({}) 
    244  
     236         
    245237    def maybe_commit(self): 
    246238        if not self.is_same(): 
    247239            self.commit() 
    248  
     240             
    249241    def commit(self): 
    250242        """Emit a ``variable_changed()`` signal. 
    251243        """ 
    252244        self.emit(SIGNAL("variable_changed()")) 
    253  
     245         
    254246    @QtCore.Slot() 
    255247    def on_name_changed(self): 
    256248        self.maybe_commit() 
    257  
     249         
    258250    @QtCore.Slot() 
    259251    def on_labels_changed(self, *args): 
    260252        self.maybe_commit() 
    261  
     253         
    262254    @QtCore.Slot() 
    263255    def on_add_label(self): 
     
    266258        index = self.labels_model.index(row, 0) 
    267259        self.labels_edit.edit(index) 
    268  
     260         
    269261    @QtCore.Slot() 
    270262    def on_remove_label(self): 
     
    273265            row = rows[0] 
    274266            self.labels_model.removeRow(row.row()) 
    275  
     267     
    276268    @QtCore.Slot() 
    277269    def on_label_selection_changed(self): 
    278270        selected = self.labels_edit.selectionModel().selectedRows() 
    279271        self.remove_label_action.setEnabled(bool(len(selected))) 
    280  
    281  
     272         
     273         
    282274class DiscreteVariableEditor(VariableEditor): 
    283275    """An editor widget for editing a discrete variable. 
    284  
     276     
    285277    Extends the :class:`VariableEditor` to enable editing of 
    286278    variables values. 
    287  
     279     
    288280    """ 
    289281    def setup_gui(self): 
    290282        layout = QVBoxLayout() 
    291283        self.setLayout(layout) 
    292  
     284         
    293285        self.main_form = QFormLayout() 
    294286        self.main_form.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) 
    295287        layout.addLayout(self.main_form) 
    296  
     288         
    297289        self._setup_gui_name() 
    298290        self._setup_gui_values() 
    299291        self._setup_gui_labels() 
    300  
     292         
    301293    def _setup_gui_values(self): 
    302294        self.values_edit = QListView() 
     
    305297                                        Qt.ItemIsEnabled | Qt.ItemIsEditable) 
    306298        self.values_edit.setModel(self.values_model) 
    307  
     299         
    308300        self.values_model.dataChanged.connect(self.on_values_changed) 
    309301        self.main_form.addRow("Values", self.values_edit) 
     
    317309            for v in var.values: 
    318310                self.values_model.append(v) 
    319  
     311                 
    320312    def get_data(self): 
    321313        """Retrieve the modified variable 
     
    324316        labels = self.labels_model.get_dict() 
    325317        values = map(str, self.values_model) 
    326  
     318         
    327319        if not self.is_same(): 
    328320            var = type(self.var)(name, values=values) 
     
    331323        else: 
    332324            var = self.var 
    333  
     325             
    334326        return var 
    335  
     327             
    336328    def is_same(self): 
    337         """Is the current model state the same as the input. 
     329        """Is the current model state the same as the input.  
    338330        """ 
    339331        values = map(str, self.values_model) 
    340332        return VariableEditor.is_same(self) and self.var.values == values 
    341  
     333     
    342334    def clear(self): 
    343335        """Clear the model state. 
     
    345337        VariableEditor.clear(self) 
    346338        self.values_model.wrap([]) 
    347  
     339         
    348340    @QtCore.Slot() 
    349341    def on_values_changed(self): 
    350342        self.maybe_commit() 
    351  
    352  
     343         
     344         
    353345class ContinuousVariableEditor(VariableEditor): 
    354     # TODO: enable editing of number_of_decimals, scientific format ... 
    355     pass 
     346    #TODO: enable editing of number_of_decimals, scientific format ... 
     347    pass  
    356348 
    357349 
    358350class OWEditDomain(OWWidget): 
    359     contextHandlers = { 
    360         "": DomainContextHandler( 
    361             "", 
    362             ["domain_change_hints", "selected_index"] 
    363         ) 
    364     } 
     351    contextHandlers = {"": DomainContextHandler("", ["domain_change_hints", "selected_index"])} 
    365352    settingsList = ["auto_commit"] 
    366  
     353     
    367354    def __init__(self, parent=None, signalManager=None, title="Edit Domain"): 
    368355        OWWidget.__init__(self, parent, signalManager, title) 
    369  
     356         
    370357        self.inputs = [("Data", Orange.data.Table, self.set_data)] 
    371358        self.outputs = [("Data", Orange.data.Table)] 
    372  
     359         
    373360        # Settings 
    374  
     361         
    375362        # Domain change hints maps from input variables description to 
    376363        # the modified variables description as returned by 
     
    380367        self.auto_commit = False 
    381368        self.changed_flag = False 
    382  
     369         
    383370        self.loadSettings() 
    384  
     371         
    385372        ##### 
    386373        # GUI 
    387374        ##### 
    388  
     375     
    389376        # The list of domain's variables. 
    390377        box = OWGUI.widgetBox(self.controlArea, "Domain Features") 
    391378        self.domain_view = QListView() 
    392379        self.domain_view.setSelectionMode(QListView.SingleSelection) 
    393  
     380         
    394381        self.domain_model = VariableListModel() 
    395  
     382         
    396383        self.domain_view.setModel(self.domain_model) 
    397  
     384         
    398385        self.connect(self.domain_view.selectionModel(), 
    399386                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), 
    400387                     self.on_selection_changed) 
    401  
     388         
    402389        box.layout().addWidget(self.domain_view) 
    403  
     390         
    404391        # A stack for variable editor widgets. 
    405392        box = OWGUI.widgetBox(self.mainArea, "Edit Feature") 
    406393        self.editor_stack = QStackedWidget() 
    407394        box.layout().addWidget(self.editor_stack) 
    408  
     395         
     396         
    409397        box = OWGUI.widgetBox(self.controlArea, "Reset") 
    410  
     398         
    411399        OWGUI.button(box, self, "Reset selected", 
    412400                     callback=self.reset_selected, 
    413401                     tooltip="Reset changes made to the selected feature" 
    414402                     ) 
    415  
     403         
    416404        OWGUI.button(box, self, "Reset all", 
    417405                     callback=self.reset_all, 
    418406                     tooltip="Reset all changes made to the domain" 
    419407                     ) 
    420  
     408         
    421409        box = OWGUI.widgetBox(self.controlArea, "Commit") 
    422  
     410         
    423411        b = OWGUI.button(box, self, "&Commit", 
    424412                         callback=self.commit, 
    425413                         tooltip="Commit the data with the changed domain", 
    426414                         ) 
    427  
     415         
    428416        cb = OWGUI.checkBox(box, self, "auto_commit", 
    429417                            label="Commit automatically", 
    430418                            tooltip="Commit the changed domain on any change", 
    431419                            callback=self.commit_if) 
    432  
     420         
    433421        OWGUI.setStopper(self, b, cb, "changed_flag", 
    434422                         callback=self.commit) 
    435  
     423         
    436424        self._editor_cache = {} 
    437  
     425         
    438426        self.resize(600, 500) 
    439  
     427         
    440428    def clear(self): 
    441429        """Clear the widget state. 
     
    445433        self.domain_change_hints = {} 
    446434        self.clear_editor() 
    447  
     435         
    448436    def clear_editor(self): 
    449437        """Clear the current editor widget 
     
    454442                               self.on_variable_changed) 
    455443            current.set_data(None) 
    456  
     444         
    457445    def set_data(self, data=None): 
    458446        self.closeContext("") 
     
    461449        if data is not None: 
    462450            input_domain = data.domain 
    463             all_vars = (list(input_domain.variables) + 
    464                         list(input_domain.class_vars) + 
    465                         input_domain.getmetas().values()) 
    466  
     451            all_vars = list(input_domain.variables) + \ 
     452                       input_domain.getmetas().values() 
     453             
    467454            self.openContext("", data) 
    468  
     455             
    469456            edited_vars = [] 
    470  
    471             # Apply any saved transformations as listed in 
     457             
     458            # Apply any saved transformations as listed in  
    472459            # `domain_change_hints` 
    473  
     460              
    474461            for var in all_vars: 
    475462                desc = variable_description(var) 
     
    481468#                        print ex 
    482469                        new = None 
    483  
     470                         
    484471                    if new is not None: 
    485472                        # Make sure orange's domain transformations will work. 
     
    487474                        new.get_value_from = Orange.core.ClassifierFromVar(whichVar=var) 
    488475                        var = new 
    489  
     476                         
    490477                edited_vars.append(var) 
    491  
     478             
    492479            self.all_vars = all_vars 
    493480            self.input_domain = input_domain 
    494  
     481             
    495482            # Sets the model to display in the 'Domain Features' view 
    496483            self.domain_model[:] = edited_vars 
    497  
     484             
    498485            # Try to restore the variable selection 
    499486            index = self.selected_index 
     
    502489            if index >= 0: 
    503490                self.select_variable(index) 
    504  
     491         
    505492            self.changed_flag = True 
    506493            self.commit_if() 
     
    508495            # To force send None on output 
    509496            self.commit() 
    510  
     497             
    511498    def on_selection_changed(self, *args): 
    512         """When selection in 'Domain Features' view changes. 
     499        """When selection in 'Domain Features' view changes.  
    513500        """ 
    514501        i = self.selected_var_index() 
     
    516503            self.open_editor(i) 
    517504            self.selected_index = i 
    518  
     505         
    519506    def selected_var_index(self): 
    520         """Return the selected row in 'Domain Features' view or None 
     507        """Return the selected row in 'Domain Features' view or None  
    521508        if no row is selected. 
    522  
     509         
    523510        """ 
    524511        rows = self.domain_view.selectionModel().selectedRows() 
     
    527514        else: 
    528515            return None 
    529  
     516         
    530517    def select_variable(self, index): 
    531518        """Select the variable with ``index`` in the 'Domain Features' 
    532519        view. 
    533  
     520         
    534521        """ 
    535522        sel_model = self.domain_view.selectionModel() 
    536523        sel_model.select(self.domain_model.index(index, 0), 
    537524                         QItemSelectionModel.ClearAndSelect) 
    538  
     525         
    539526    def open_editor(self, index): 
    540527        """Open the editor for variable at ``index`` and move it 
    541528        to the top if the stack. 
    542  
     529         
    543530        """ 
    544531        # First remove and clear the current editor if any 
    545532        self.clear_editor() 
    546  
     533             
    547534        var = self.domain_model[index] 
    548  
     535         
    549536        editor = self.editor_for_variable(var) 
    550537        editor.set_data(var) 
    551538        self.edited_variable_index = index 
    552  
     539         
    553540        QObject.connect(editor, SIGNAL("variable_changed()"), 
    554541                        self.on_variable_changed) 
    555542        self.editor_stack.setCurrentWidget(editor) 
    556  
     543     
    557544    def editor_for_variable(self, var): 
    558545        """Return the editor for ``var``'s variable type. 
    559  
     546         
    560547        The editors are cached and reused by type. 
    561  
     548           
    562549        """ 
    563550        editor = None 
     
    568555        else: 
    569556            editor = VariableEditor 
    570  
     557             
    571558        if type(var) not in self._editor_cache: 
    572559            editor = editor() 
    573560            self._editor_cache[type(var)] = editor 
    574561            self.editor_stack.addWidget(editor) 
    575  
     562             
    576563        return self._editor_cache[type(var)] 
    577  
     564     
    578565    def on_variable_changed(self): 
    579566        """When the user edited the current variable in editor. 
     
    582569        editor = self.editor_stack.currentWidget() 
    583570        new_var = editor.get_data() 
    584  
     571         
    585572        # Replace the variable in the 'Domain Features' view/model 
    586573        self.domain_model[self.edited_variable_index] = new_var 
    587574        old_var = self.all_vars[self.edited_variable_index] 
    588  
     575         
    589576        # Store the transformation hint. 
    590577        self.domain_change_hints[variable_description(old_var)] = \ 
     
    594581        new_var.source_variable = old_var 
    595582        new_var.get_value_from = Orange.core.ClassifierFromVar(whichVar=old_var) 
    596  
     583         
    597584        self.commit_if() 
    598  
     585          
    599586    def reset_all(self): 
    600587        """Reset all variables to the input state. 
     
    608595            self.select_variable(self.selected_index) 
    609596            self.commit_if() 
    610  
     597             
    611598    def reset_selected(self): 
    612599        """Reset the currently selected variable to its original 
    613600        state. 
    614  
     601           
    615602        """ 
    616603        if self.data is not None: 
     
    619606            if desc in self.domain_change_hints: 
    620607                del self.domain_change_hints[desc] 
    621  
     608             
    622609            # To invalidate stored hints 
    623610            self.closeContext("") 
    624611            self.openContext("", self.data) 
    625  
     612             
    626613            self.domain_model[self.selected_index] = var 
    627614            self.editor_stack.currentWidget().set_data(var) 
    628615            self.commit_if() 
    629  
     616             
    630617    def commit_if(self): 
    631618        if self.auto_commit: 
     
    633620        else: 
    634621            self.changed_flag = True 
    635  
     622         
    636623    def commit(self): 
    637         """Commit the changed data to output. 
     624        """Commit the changed data to output.  
    638625        """ 
    639626        new_data = None 
    640627        if self.data is not None: 
    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] 
     628            new_vars = list(self.domain_model) 
     629            variables = new_vars[: len(self.input_domain.variables)] 
    645630            class_var = None 
    646631            if self.input_domain.class_var: 
    647632                class_var = variables[-1] 
    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  
     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             
    657638            # Assumes getmetas().items() order has not changed. 
    658639            # TODO: store metaids in set_data method 
    659             for (mid, _), new in zip(self.input_domain.getmetas().items(), 
    660                                      new_metas): 
     640            for (mid, _), new in zip(self.input_domain.getmetas().items(),  
     641                                       new_metas): 
    661642                new_domain.addmeta(mid, new) 
    662  
     643                 
    663644            new_data = Orange.data.Table(new_domain, self.data) 
    664  
     645         
    665646        self.send("Data", new_data) 
    666647        self.changed_flag = False 
    667  
    668  
     648             
     649         
    669650def main(): 
    670651    import sys 
     
    679660    w.saveSettings() 
    680661    return rval 
    681  
     662         
    682663if __name__ == "__main__": 
    683664    import sys 
    684665    sys.exit(main()) 
     666     
  • Orange/OrangeWidgets/Data/OWPythonScript.py

    r11434 r11364  
    344344 
    345345    settingsList = ["codeFile", "libraryListSource", "currentScriptIndex", 
    346                     "splitterState", "auto_execute"] 
     346                    "splitterState"] 
    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, 
    352                         Default), 
     351        self.inputs = [("in_data", Orange.data.Table, self.setExampleTable), 
    353352                       ("in_distance", Orange.misc.SymMatrix, 
    354                         self.setDistanceMatrix, Default), 
    355                        ("in_learner", Orange.core.Learner, self.setLearner, 
    356                         Default), 
     353                        self.setDistanceMatrix), 
     354                       ("in_learner", Orange.core.Learner, self.setLearner), 
    357355                       ("in_classifier", Orange.core.Classifier, 
    358                         self.setClassifier, Default), 
     356                        self.setClassifier), 
    359357                       ("in_object", object, self.setObject)] 
    360358 
  • Orange/OrangeWidgets/OWDatabasesUpdate.py

    r11437 r10979  
    1 from __future__ import with_statement 
    2  
    3 import os 
    4 import sys 
    5  
     1from __future__ import with_statement  
     2import sys, os 
     3import orngServerFiles 
     4import orngEnviron 
     5import threading 
     6from OWWidget import * 
     7from functools import partial 
    68from datetime import datetime 
    79 
    8 import Orange 
    9  
    10 from Orange.utils import serverfiles, environ 
    11 from Orange.utils.serverfiles import sizeformat as sizeof_fmt 
    12  
    13 from OWWidget import * 
    14 from OWConcurrent import * 
    15  
    16 import OWGUIEx 
    17  
    18  
     10import gzip, sys 
     11 
     12def 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        
    1919class ItemProgressBar(QProgressBar): 
    20     """Progress Bar with and `advance()` slot. 
    21     """ 
    2220    @pyqtSignature("advance()") 
    2321    def advance(self): 
    2422        self.setValue(self.value() + 1) 
    25  
    26  
     23    
     24         
    2725class ProgressBarRedirect(QObject): 
    2826    def __init__(self, parent, redirect): 
     
    3028        self.redirect = redirect 
    3129        self._delay = False 
    32  
     30         
    3331    @pyqtSignature("advance()") 
    3432    def advance(self): 
    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 
     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 
    3936        if not self._delay: 
    4037            try: 
     
    4643            QTimer.singleShot(10, self.advance) 
    4744 
    48 _icons_dir = os.path.join(environ.canvas_install_dir, "icons") 
    49  
    50  
    51 def icon(name): 
    52     return QIcon(os.path.join(_icons_dir, name)) 
    53  
    54  
     45         
     46from OWConcurrent import * 
     47         
    5548class UpdateOptionsWidget(QWidget): 
    56     """ 
    57     A Widget with download/update/remove options. 
    58     """ 
    5949    def __init__(self, updateCallback, removeCallback, state, *args): 
    6050        QWidget.__init__(self, *args) 
     
    6555        layout.setContentsMargins(1, 1, 1, 1) 
    6656        self.updateButton = QToolButton(self) 
    67         self.updateButton.setIcon(icon("update.png")) 
     57        self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
    6858        self.updateButton.setToolTip("Download") 
    69  
     59#        self.updateButton.setIconSize(QSize(10, 10)) 
    7060        self.removeButton = QToolButton(self) 
    71         self.removeButton.setIcon(icon("delete.png")) 
     61        self.removeButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "delete.png"))) 
    7262        self.removeButton.setToolTip("Remove from system") 
    73  
    74         self.connect(self.updateButton, SIGNAL("released()"), 
    75                      self.updateCallback) 
    76         self.connect(self.removeButton, SIGNAL("released()"), 
    77                      self.removeCallback) 
    78  
     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) 
    7966        self.setMaximumHeight(30) 
    8067        layout.addWidget(self.updateButton) 
     
    8673        self.state = state 
    8774        if state == 0: 
    88             self.updateButton.setIcon(icon("update1.png")) 
     75            self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update1.png"))) 
    8976            self.updateButton.setToolTip("Update") 
    9077            self.updateButton.setEnabled(False) 
    9178            self.removeButton.setEnabled(True) 
    9279        elif state == 1: 
    93             self.updateButton.setIcon(icon("update1.png")) 
     80            self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update1.png"))) 
    9481            self.updateButton.setToolTip("Update") 
    9582            self.updateButton.setEnabled(True) 
    9683            self.removeButton.setEnabled(True) 
    9784        elif state == 2: 
    98             self.updateButton.setIcon(icon("update.png")) 
     85            self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
    9986            self.updateButton.setToolTip("Download") 
    10087            self.updateButton.setEnabled(True) 
    10188            self.removeButton.setEnabled(False) 
    10289        elif state == 3: 
    103             self.updateButton.setIcon(icon("update.png")) 
     90            self.updateButton.setIcon(QIcon(os.path.join(orngEnviron.canvasDir, "icons", "update.png"))) 
    10491            self.updateButton.setToolTip("") 
    10592            self.updateButton.setEnabled(False) 
    10693            self.removeButton.setEnabled(True) 
    107         else: 
    108             raise ValueError("Invalid state %r" % state) 
    10994 
    11095 
    11196class UpdateTreeWidgetItem(QTreeWidgetItem): 
    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             ) 
     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): 
    12899        if not infoLocal: 
    129100            self.state = 2 
     
    131102            self.state = 3 
    132103        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") 
    133106            self.state = 0 if dateLocal >= dateServer else 1 
    134  
    135107        title = infoServer["title"] if infoServer else (infoLocal["title"]) 
    136108        tags = infoServer["tags"] if infoServer else infoLocal["tags"] 
    137         specialTags = dict([tuple(tag.split(":")) 
    138                             for tag in tags 
    139                             if tag.startswith("#") and ":" in tag]) 
     109        specialTags = dict([tuple(tag.split(":")) for tag in tags if tag.startswith("#") and ":" in tag]) 
    140110        tags = ", ".join(tag for tag in tags if not tag.startswith("#")) 
    141111        self.size = infoServer["size"] if infoServer else infoLocal["size"] 
    142  
     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))) 
    143116        size = sizeof_fmt(float(self.size)) 
    144         state = self.stateDict[self.state] 
    145         if self.state == 1: 
    146             state += dateServer.strftime(" (%Y, %b, %d)") 
    147  
     117        state = self.stateDict[self.state] + (dateServer.strftime(" (%Y, %b, %d)") if self.state == 1 else "") 
    148118        QTreeWidgetItem.__init__(self, treeWidget, ["", title, size]) 
    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  
     119        self.updateWidget = UpdateOptionsWidget(self.StartDownload, self.Remove, self.state, treeWidget) 
    157120        self.treeWidget().setItemWidget(self, 0, self.updateWidget) 
    158121        self.updateWidget.show() 
     
    163126        self.domain = domain 
    164127        self.filename = filename 
     128##        for i in range(1, 5): 
     129##            self.setSizeHint(i, QSize(self.sizeHint(i).width(), self.sizeHint(0).height())) 
    165130        self.UpdateToolTip() 
    166131 
    167132    def UpdateToolTip(self): 
    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)) 
     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)) 
    174135        if self.state != 2: 
    175             tooltip += ("\nFile: %s" % 
    176                         serverfiles.localpath(self.domain, self.filename)) 
     136            tooltip += "\nFile: %s" % orngServerFiles.localpath(self.domain, self.filename) 
    177137        for i in range(1, 5): 
    178138            self.setToolTip(i, tooltip) 
    179  
     139         
    180140    def StartDownload(self): 
    181141        self.updateWidget.removeButton.setEnabled(False) 
    182142        self.updateWidget.updateButton.setEnabled(False) 
    183143        self.setData(2, Qt.DisplayRole, QVariant("")) 
    184         serverFiles = serverfiles.ServerFiles( 
    185             access_code=self.master.accessCode if self.master.accessCode 
    186             else None 
    187         ) 
    188  
     144        serverFiles = orngServerFiles.ServerFiles(access_code=self.master.accessCode if self.master.accessCode else None)  
     145         
    189146        pb = ItemProgressBar(self.treeWidget()) 
    190147        pb.setRange(0, 100) 
    191148        pb.setTextVisible(False) 
    192  
     149         
    193150        self.task = AsyncCall(threadPool=QThreadPool.globalInstance()) 
    194  
     151         
    195152        if not getattr(self.master, "_sum_progressBar", None): 
    196             self.master._sum_progressBar = OWGUI.ProgressBar(self.master, 0) 
     153            self.master._sum_progressBar = OWGUI.ProgressBar(self.master,0) 
    197154            self.master._sum_progressBar.in_progress = 0 
    198155        master_pb = self.master._sum_progressBar 
    199156        master_pb.iter += 100 
    200157        master_pb.in_progress += 1 
    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) 
     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) 
    215163        self.treeWidget().setItemWidget(self, 2, pb) 
    216164        pb.show() 
    217  
    218         self.task.apply_async(serverfiles.download, 
    219                               args=(self.domain, self.filename, serverFiles), 
    220                               kwargs=dict(callback=self.task.emitAdvance)) 
     165         
     166        self.task.apply_async(orngServerFiles.download, args=(self.domain, self.filename, serverFiles), kwargs=dict(callback=self.task.emitAdvance)) 
    221167 
    222168    def EndDownload(self, exitCode=0): 
     
    225171            self.state = 0 
    226172            self.updateWidget.SetState(self.state) 
    227             self.setData(2, Qt.DisplayRole, 
    228                          QVariant(sizeof_fmt(float(self.size)))) 
     173            self.setData(2, Qt.DisplayRole, QVariant(sizeof_fmt(float(self.size)))) 
    229174            self.master.UpdateInfoLabel() 
    230175            self.UpdateToolTip() 
    231176        else: 
    232177            self.updateWidget.SetState(1) 
    233             self.setData(2, Qt.DisplayRole, 
    234                          QVariant("Error occurred while downloading:" + 
    235                                   str(exitCode))) 
    236  
     178            self.setData(2, Qt.DisplayRole, QVariant("Error occured while downloading:" + str(exitCode))) 
     179             
    237180        master_pb = self.master._sum_progressBar 
    238  
     181#        print master_pb.in_progress 
    239182        if master_pb and master_pb.in_progress == 1: 
    240183            master_pb.finish() 
     
    242185        elif master_pb: 
    243186            master_pb.in_progress -= 1 
    244  
     187         
     188#        self.thread, self._runnable = None, None 
     189             
    245190    def Remove(self): 
    246         serverfiles.remove(self.domain, self.filename) 
     191        orngServerFiles.remove(self.domain, self.filename) 
    247192        self.state = 2 
    248193        self.updateWidget.SetState(self.state) 
     
    251196 
    252197    def __contains__(self, item): 
    253         return any(item.lower() in tag.lower() 
    254                    for tag in self.tags + [self.title]) 
    255  
     198        return any(item.lower() in tag.lower() for tag in self.tags + [self.title]) 
     199     
    256200    def __lt__(self, other): 
    257         return getattr(self, "title", "") < getattr(other, "title", "") 
    258  
     201        return getattr(self, "title", "") < getattr(other, "title", "")  
    259202 
    260203class UpdateItemDelegate(QItemDelegate): 
     
    265208        widget = parent.itemWidget(item, 0) 
    266209        if widget: 
    267             size = QSize(size.width(), widget.sizeHint().height() / 2) 
     210            size = QSize(size.width(), widget.sizeHint().height()/2) 
    268211        return size 
    269  
    270  
     212     
    271213def retrieveFilesList(serverFiles, domains=None, advance=lambda: None): 
    272     """ 
    273     Retrieve and return serverfiles.allinfo for all domains. 
    274     """ 
    275214    domains = serverFiles.listdomains() if domains is None else domains 
    276215    advance() 
     
    278217    advance() 
    279218    return serverInfo 
    280  
    281  
     219     
    282220class OWDatabasesUpdate(OWWidget): 
    283     def __init__(self, parent=None, signalManager=None, 
    284                  name="Databases update", wantCloseButton=False, 
    285                  searchString="", showAll=True, domains=None, 
    286                  accessCode=""): 
     221    def __init__(self, parent=None, signalManager=None, name="Databases update", wantCloseButton=False, searchString="", showAll=True, domains=None, accessCode=""): 
    287222        OWWidget.__init__(self, parent, signalManager, name) 
    288223        self.searchString = searchString 
     
    290225        self.showAll = showAll 
    291226        self.domains = domains 
    292         self.serverFiles = serverfiles.ServerFiles() 
     227        self.serverFiles = orngServerFiles.ServerFiles() 
    293228        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    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) 
     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) 
    303231 
    304232        box = OWGUI.widgetBox(self.mainArea, "Files") 
    305233        self.filesView = QTreeWidget(self) 
    306         self.filesView.setHeaderLabels(["Options", "Title", "Size", 
    307                                         "Last Updated"]) 
     234        self.filesView.setHeaderLabels(["Options", "Title", "Size"]) 
    308235        self.filesView.setRootIsDecorated(False) 
    309236        self.filesView.setSelectionMode(QAbstractItemView.NoSelection) 
    310237        self.filesView.setSortingEnabled(True) 
    311238        self.filesView.setItemDelegate(UpdateItemDelegate(self.filesView)) 
    312         self.connect(self.filesView.model(), 
    313                      SIGNAL("layoutChanged()"), 
    314                      self.SearchUpdate) 
     239        self.connect(self.filesView.model(), SIGNAL("layoutChanged()"), self.SearchUpdate) 
    315240        box.layout().addWidget(self.filesView) 
    316241 
    317242        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    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") 
     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") 
    324245        OWGUI.rubber(box) 
    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) 
     246        OWGUI.lineEdit(box, self, "accessCode", "Access Code", orientation="horizontal", callback=self.RetrieveFilesList) 
     247        self.retryButton = OWGUI.button(box, self, "Retry", callback=self.RetrieveFilesList) 
    330248        self.retryButton.hide() 
    331249        box = OWGUI.widgetBox(self.mainArea, orientation="horizontal") 
    332250        OWGUI.rubber(box) 
    333251        if wantCloseButton: 
    334             OWGUI.button(box, self, "Close", 
    335                          callback=self.accept, 
    336                          tooltip="Close") 
    337  
     252            OWGUI.button(box, self, "Close", callback=self.accept, tooltip="Close") 
     253 
     254##        statusBar = QStatusBar() 
    338255        self.infoLabel = QLabel() 
    339256        self.infoLabel.setAlignment(Qt.AlignCenter) 
    340  
     257##        statusBar.addWidget(self.infoLabel) 
     258##        self.mainArea.layout().addWidget(statusBar) 
    341259        self.mainArea.layout().addWidget(self.infoLabel) 
    342260        self.infoLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 
     
    344262        self.updateItems = [] 
    345263        self.allTags = [] 
    346  
     264         
    347265        self.resize(800, 600) 
    348  
     266         
     267#        QTimer.singleShot(50, self.UpdateFilesList) 
    349268        QTimer.singleShot(50, self.RetrieveFilesList) 
    350  
     269         
    351270    def RetrieveFilesList(self): 
    352         self.serverFiles = serverfiles.ServerFiles(access_code=self.accessCode) 
     271        self.serverFiles = orngServerFiles.ServerFiles(access_code=self.accessCode) 
    353272        self.pb = ProgressBar(self, 3) 
    354         self.async_retrieve = createTask(retrieveFilesList, 
    355                                          (self.serverFiles, self.domains, 
    356                                           self.pb.advance), 
    357                                          onResult=self.SetFilesList, 
    358                                          onError=self.HandleError) 
    359  
     273        self.async_retrieve = createTask(retrieveFilesList, (self.serverFiles, self.domains, self.pb.advance), onResult=self.SetFilesList, onError=self.HandleError) 
     274         
    360275        self.setEnabled(False) 
    361  
     276         
     277         
    362278    def SetFilesList(self, serverInfo): 
    363279        self.setEnabled(True) 
    364         domains = serverInfo.keys() or serverfiles.listdomains() 
    365         localInfo = dict([(dom, serverfiles.allinfo(dom)) 
    366                           for dom in domains]) 
     280        domains = serverInfo.keys() or orngServerFiles.listdomains() 
     281        localInfo = dict([(dom, orngServerFiles.allinfo(dom)) for dom in domains]) 
    367282        items = [] 
    368  
     283         
    369284        self.allTags = set() 
    370285        allTitles = set() 
    371286        self.updateItems = [] 
    372  
    373         for domain in set(domains) - set(["test", "demo"]): 
    374             local = localInfo.get(domain, {}) 
    375             server = serverInfo.get(domain, {}) 
     287         
     288        for i, domain in enumerate(set(domains) - set(["test", "demo"])): 
     289            local = localInfo.get(domain, {})  
     290            server =  serverInfo.get(domain, {}) 
    376291            files = sorted(set(server.keys() + local.keys())) 
    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  
     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                 
    384298                displayInfo = infoServer if infoServer else infoLocal 
    385299                self.allTags.update(displayInfo["tags"]) 
    386300                allTitles.update(displayInfo["title"].split()) 
    387  
    388         for item in items: 
     301         
     302        for i, item in enumerate(items): 
    389303            self.updateItems.append(UpdateTreeWidgetItem(self, *item)) 
    390304        self.pb.advance() 
    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("#")]) 
     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("#")]) 
    398309        self.SearchUpdate() 
    399310        self.UpdateInfoLabel() 
    400311        self.pb.finish() 
    401  
     312         
    402313    def HandleError(self, (exc_type, exc_value, tb)): 
    403314        if exc_type >= IOError: 
    404             self.error(0, 
    405                        "Could not connect to server! Press the Retry " 
    406                        "button to try again.") 
     315            self.error(0, "Could not connect to server! Press the Retry button to try again.") 
    407316            self.SetFilesList({}) 
    408317        else: 
     
    410319            self.pb.finish() 
    411320            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() 
    412380 
    413381    def UpdateInfoLabel(self): 
    414382        local = [item for item in self.updateItems if item.state != 2] 
    415383        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  
    420384        if self.showAll: 
    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))) 
     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)))) 
    427387        else: 
    428             text = "%i items, %s" % (len(local), sizeof_fmt(size)) 
    429  
    430         self.infoLabel.setText(text) 
    431  
     388            self.infoLabel.setText("%i items, %s" % (len(local), sizeof_fmt(sum(float(item.specialTags.get("#uncompressed", item.size)) for item in local)))) 
     389         
    432390    def UpdateAll(self): 
    433391        for item in self.updateItems: 
    434392            if item.state == 1: 
    435393                item.StartDownload() 
    436  
     394                 
    437395    def DownloadFiltered(self): 
    438396        for item in self.updateItems: 
     
    441399 
    442400    def SearchUpdate(self, searchString=None): 
    443         strings = unicode(self.lineEditFilter.text()).split() 
     401        strings = unicode(self.lineEditFilter.text()).split() #self.searchString.split() if searchString is None else unicode(searchString).split() 
    444402        tags = set() 
    445403        for item in self.updateItems: 
     
    448406            if not hide: 
    449407                tags.update(item.tags) 
    450  
    451  
     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         
    452411if __name__ == "__main__": 
    453412    app = QApplication(sys.argv) 
  • Orange/classification/svm/__init__.py

    r11423 r11397  
    11931193 
    11941194class RFE(object): 
    1195     """ 
    1196     Iterative feature elimination based on weights computed by a 
     1195 
     1196    """Iterative feature elimination based on weights computed by 
    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 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` 
     1214        :param learner: A linear svm learner for use with 
     1215            :class:`ScoreSVMWeights`. 
    12211216 
    12221217        """ 
  • Orange/utils/serverfiles.py

    r11438 r11396  
    305305 
    306306        readb = 0 
    307         # in case size == 0 skip the loop 
    308         while size > 0: 
     307        while 1: 
    309308            buf = fdown.read(chunksize) 
    310309            readb += len(buf) 
    311310 
    312             while float(readb) / size > lastchunkreport+0.01: 
     311            while float(readb)/size > lastchunkreport+0.01: 
    313312                #print float(readb)/size, lastchunkreport + 0.01, float(readb)/size - lastchunkreport  
    314313                lastchunkreport += 0.01 
     
    671670    def getstring(self): 
    672671        elapsed = max(time.time() - self.starttime, 0.1) 
    673         speed = max(int(self.state * self.size / 100.0 / elapsed), 1) 
     672        speed = int(self.state * self.size / 100.0 / elapsed) 
    674673        eta = (100 - self.state) * self.size / 100.0 / speed 
    675674        return ConsoleProgressBar.getstring(self) + \ 
  • docs/extend-widgets/rst/api.rst

    r11424 r11049  
    1818Following is an example that defines two output channels:: 
    1919 
    20     self.outputs = [("Sampled Data", orange.ExampleTable), 
    21                     ("Learner", orange.Learner)] 
     20    self.outputs = [("Sampled Data", orange.ExampleTable), ("Learner", orange.Learner)] 
    2221 
    2322:obj:`self.outputs` should thus be a list of tuples, within 
     
    6362 
    6463    def receiveData(self, data): 
    65         # handle data in some way 
    66  
     64    # handle data in some way 
    6765 
    6866Any time our widget would receive a token, :obj:`receiveData` 
     
    7876deleted, Orange Canvas would automatically send :obj:`None` to 
    7977the receiving widget. Make sure your widget handles :obj:`None` 
    80 tokens appropriately! 
     78tokens appropriately!` 
    8179 
    8280There are cases when widget would like to know about the origin of 
     
    9593 
    9694   def learner(self, learnertoken, tokenid): 
    97        # handle learnertoken and tokeid in some way 
     95   # handle learnertoken and tokeid in some way 
    9896 
    9997Widgets such as :obj:`OWTestLearners` and alike use such 
     
    104102 
    105103    self.inputs = [("Data", orange.ExampleTable, self.maindata), 
    106                    ("Additional Data", orange.ExampleTable, self.otherdata)] 
     104               ("Additional Data", orange.ExampleTable, self.otherdata)] 
    107105 
    108106and we connect this widget in Orange Canvas to a sending widget 
    109107that has a single orange.ExampleTable output channel, Canvas would 
    110 bring up *Set Channels* dialog. There, a sending widget's channel could 
     108bring up Set Channels dialog. There, a sending widget's channel could 
    111109be connected to both receiving channels. As we would often prefer to 
    112110connect to a single (default) channel instead (still allowing user of 
     
    116114 
    117115    self.inputs = [("Data", orange.ExampleTable, self.maindata, Default), 
    118                    ("Additional Data", orange.ExampleTable, self.otherdata)] 
     116               ("Additional Data", orange.ExampleTable, self.otherdata)] 
  • docs/extend-widgets/rst/basics.rst

    r11424 r11408  
    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 
     44C:\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), 
    83                    ("Learner", orange.Learner, self.learner, 0)] 
     82    self.inputs = [("Test Data Set", ExampleTable, self.cdata), ("Learner", orange.Learner, self.learner, 0)] 
    8483    self.outputs = [("Evaluation Results", orngTest.ExperimentResults)] 
    8584 
     
    9291now the following is important: 
    9392 
    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. 
     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. 
    10998 
    11099Oh, by the way. Orange caches widget descriptions to achieve a faster 
  • docs/extend-widgets/rst/channels.rst

    r11424 r11408  
    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 
    29 :doc:`previous <settings>` lesson. But, somehow differently, we 
     28input data channel, and this we know how to deal with from our :doc:`previous <settings>` 
     29lesson. 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

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

    r11424 r11408  
    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 
    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. 
     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. 
    4037 
    4138`box` (default: None) 
    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. 
     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. 
    4640 
    4741`callback` (default: None) 
     
    5751 
    5852`tooltip` (default: None) 
    59    A string that is displayed in a tooltip that appears when mouse is over the 
    60    control. 
     53   A string that is displayed in a tooltip that appears when mouse is over the control. 
    6154 
    6255`label` (default: None) 
     
    6760 
    6861`orientation` (default: "vertical") 
    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".) 
     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".) 
    7563 
    7664`disabled` (default: False) 
     
    7866 
    7967`addSpace` (default: False) 
    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. 
     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. 
    8369 
    8470 
     
    8975This section describes the OWGUI wrappers for controls like check boxes, buttons 
    9076and similar. All the important Qt's controls can be constructed through this 
    91 functions. 
    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. 
     77functions. You should always use them instead of calling Qt directly, not only 
     78because they are convenient, but also because they set up a lot of things that happen in behind. 
    9779 
    9880 
     
    10688 
    10789   `disables` (default: []) 
    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. 
     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. 
    11491 
    11592   `labelWidth` (default: None) 
     
    125102 
    126103   `valueType` (default: str) 
    127       A type into which the `value` is cast. 
     104      A type into which the value is cast. 
    128105 
    129106   `validator` (default: None) 
     
    175152 
    176153   `items` (default: []) 
    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. 
     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. 
    182155 
    183156   `sendSelectedValue` (default: 0) 
    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. 
     157      If false, attribute `value` will be assigned the index of the selected item. Otherwise, it is assigned the currently selected item's label. 
    186158 
    187159   `control2attributeDict` (default: {}) 
    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. 
     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.  
    192161 
    193162   `emptyString` (default: "") 
    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. 
     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. 
    201164 
    202165   `valueType` (default: str or unicode) 
    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. 
     166      A function through which the currently selected item's label is converted prior to looking into `control2attributeDict`. Needed to convert Qt's QString. 
    206167 
    207168 
     
    210171 
    211172This control, which might be the most complicated control in OWGUI, is a 
    212 sophisticated wrapper around QListBox. It's complexity arises from 
    213 synchronization. 
     173sophisticated wrapper around QListBox. It's complexity arises from synchronization. 
    214174 
    215175 
     
    220180 
    221181   `labels` (required) 
    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. 
     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. 
    229183 
    230184   `selectionMode` (default: QListWidget.SingleSelection) 
    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. 
     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 
    252191 
    253192 
     
    266205****** 
    267206 
    268 A wrapper around QSlider that allows user setting a numerical value between 
    269 the given bounds. 
     207A wrapper around QSlider that allows user setting a numerical value between the given bounds. 
    270208 
    271209.. function:: hSlider(widget, master, value[, box, minValue, maxValue, step, callback, labelFormat, ticks, divideFactor]) 
     
    276214 
    277215   `ticks` (default: 0) 
    278       If non-zero, it gives the interval between two ticks. The ticks will 
    279       appear below the groove. 
     216      If non-zero, it gives the interval between two ticks. The ticks will appear below the groove. 
    280217 
    281218   `labelFormat` (default: " %d") 
    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. 
     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. 
    285220 
    286221   `divideFactor` (default: 1.0) 
     
    291226******************* 
    292227 
    293 Check box with spin, or, essentially, a wrapper around OWGUI.checkBox and 
    294 OWGUI.spin. 
     228Check box with spin, or, essentially, a wrapper around 
     229OWGUI.checkBox and OWGUI.spin. 
    295230 
    296231.. function:: checkWithSpin(widget, master, label, min, max, checked, value[, posttext, step, tooltip, checkCallback, spinCallback, labelWidth]) 
     
    315250****** 
    316251 
    317 There are two functions for constructing labels. The first is a simple wrapper 
    318 around QLabel which differs only in allowing to specify a fixed width without 
    319 needing an extra line. Note that unlike most other OWGUI widgets, this one 
    320 does not have the argument `master`. 
     252There 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`. 
    321253 
    322254.. function:: widgetLabel(widget, label[, labelWidth]) 
    323255 
    324    The second is a label which can synchronize with values of master widget's 
    325    attributes. 
     256   The second is a label which can synchronize with values of master widget's attributes. 
    326257 
    327258.. function:: label(widget, master, label[, labelWidth]) 
     
    395326************************* 
    396327 
    397 Many widgets have a "Send" button (perhaps named "Apply", "Commit"...) 
    398 accompanied with a check box "Send automatically", having the same effect as 
    399 if the user pressed the button after each change. A well behaved widget cares 
    400 to: 
     328Many 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: 
    401329 
    402330* disable the button, when the check box is checked; 
    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  
    407 Programming this into every widget is annoying and error-prone; at the time 
    408 when the function described here was written, not many widgets actually did 
    409 this properly. 
     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 
     333Programming 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. 
    410334 
    411335.. function:: setStopper(master, sendButton, stopCheckbox, changedFlag, callback) 
     
    415339 
    416340   `stopCheckbox` 
    417       Check box that decides whether the changes are sent/commited/applied 
    418       automatically. 
     341      Check box that decides whether the changes are sent/commited/applied automatically. 
    419342 
    420343   `changedFlag` 
    421       The name of the `master`'s attribute which tells whether there is a 
    422       change which has not been sent/applied yet. 
     344      The name of the `master`'s attribute which tells whether there is a change which has not been sent/applied yet. 
    423345 
    424346   `callback` 
    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 
    430 signals. Its true importance is in enforcing the correct procedure for 
    431 implementing such button-check box combinations. 
     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. 
    432351 
    433352.. 
     
    435354 
    436355   Missing, where did it go? 
     356 
  • docs/extend-widgets/rst/settings.rst

    r11424 r11408  
    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>` instead; 
     178should always use the module :doc:`OWGUI <owgui.rst>` 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>` 
     185in the widget definition, as already described :doc:`elsewhere <settings.rst>` 
    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 
    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, 
    260 we 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 
    262 or any object that has a field :obj:`domain` containing a domain. Whether a 
    263 saved context can be reused is judged upon the presence of attributes in the 
    264 domain. 
    265  
    266 If the widget is constructed appropriately (that is, if it strictly uses OWGUI 
    267 controls instead of the Qt's), no other administration is needed to switch the 
    268 context. 
    269  
    270 Except for declaring the context settings, that is. Scatter plot has this just 
    271 below the :obj:`settingsList`:: 
     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 
     248If 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 
     250Except for declaring the context settings, that is. Scatter plot has this just below the :obj:`settingsList`:: 
    272251 
    273252    contextHandlers = {"": DomainContextHandler("", 
     
    278257       ("attrSize", DomainContextHandler.Optional)])} 
    279258 
    280 :obj:`contextHandlers` is a dictionary whose keys are contexts' names. Each 
    281 widget can have multiple contexts; for an unrealistic example, consider a 
    282 scatter plot which gets two data sets and uses one attribute from the first 
    283 for the x axis, and an attribute from the other for y. Since we won't see this 
    284 often, the default name for a context is an empty string. 
    285  
    286 The values in the dictionary are context handlers. Scatter plot declares that 
    287 it has a DomainContextHandler with name "" (sorry for the repetition) with 
    288 attributes "attrX", "attrY", "attrLabel", "attrShape" and "attrSize". The 
    289 first two are required, while the other three are optional. 
     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 
     261The 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. 
    290262 
    291263********************************* 
     
    293265********************************* 
    294266 
    295 What we said above is not exactly true. :obj:`DomainContextHandler.Required` 
    296 is the default flag, so :obj:`("attrX", DomainContextHandler.Required)` can 
    297 be replaced by simply :obj:`"attrX"`. And the latter three have the 
     267What we said above is not exactly 
     268true. :obj:`DomainContextHandler.Required` is the default flag, 
     269so :obj:`("attrX", DomainContextHandler.Required)` can be 
     270replaced by simply :obj:`"attrX"`. And the latter three have the 
    298271same flags, so they can be grouped into :obj:`(["attrLabel", 
    299272"attrShape", "attrSize"], DomainContextHandler.Optional)`. So 
     
    304277       (["attrLabel", "attrShape", "attrSize"], DomainContextHandler.Optional)])} 
    305278 
    306 What do ``Optional`` and ``Required`` mean? Say that you used the 
     279What do "optional" and "required" mean? Say that you used the 
    307280scatter plot on the data with attributes A, B, C and D; A and B are 
    308281used for the x and y axis and D defined the colors of examples. Now 
     
    322295:obj:`DomainContextHandler`. 
    323296 
    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. 
     297DomainContextHandler's constructor has the following arguments 
     298 
     299contextName 
     300The 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 
     302fields 
     303The names of the attributes to be saved and the corresponding flags. They are described in more details below. 
     304 
     305cloneIfImperfect 
     306states 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 
     308loadImperfect 
     309tells whether the contexts that do not match perfectly (see above) should be used or not. Default is :obj:`True`. 
     310 
     311findImperfect 
     312tells 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 
     314syncWithGlobal 
     315tells 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 
     317maxAttributesToPickle 
     318To 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. 
    363319 
    364320 
     
    370326name (just like in :obj:`settingsList`) and a flag. Here are the possible flags: 
    371327 
    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. 
     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. 
    387331 
    388332 
     
    404348But the tuples are actually a shortcut for instances of 
    405349:obj:`ContextField`. When you say :obj:`"attrX"` this is actually 
    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. 
     350:obj:`ContextField("attrX", DomainContextHandler.Required)` (you should 
     351appreciate the shortcurt, right?). But see this monster from widget "Select 
     352Attributes" (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 
     368arguments that are written directly into the object instance. To follow the 
     369example, recall what Select Attributes looks like: it allows you to select a 
     370subset of attributes, the class attribute and the meta attributes that you 
     371want to use; the attributes in the corresponding three list boxes are stored 
     372in the widget's variables :obj:`chosenAttributes`, :obj:`classAttribute` 
     373and :obj:`metaAttributes` respectively. When the user selects some attributes 
     374in 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 
     377listbox on the left-hand side of the widget, and the content of the box is 
     378stored in the widget's variable :obj:`inputAttributes`. 
     379 
     380The above definition tells that the context needs to store the contents of 
     381the three list boxes by specifying the corresponding variables; the list of 
     382attributes is given as the name of the field and the list of selected 
     383attributes is in the optional named attribute :obj:`selected`. By 
     384:obj:`reservoir` we told the context handler that the attributes are taken 
     385from :obj:`inputAttributes`. So, when a context is retrieved, all the 
     386attributes that are not in any of the three list boxes are put into 
     387:obj:`inputAttributes`. 
     388 
     389Why the mess? Couldn't we just store :obj:`inputAttributes` as the fourth 
     390list box? Imagine that the user first loads the data with attributes A, B, 
     391C, 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, 
     393B, C, D, E, and G. The contexts should match (the new data has all the 
     394attributes we need), but :obj:`inputAttributes` should now contain E and 
     395G, not E and F, since F doesn't exist any more, while G needs to be made 
     396available. 
     397 
     398You can use :obj:`ContextField` (instead of tuples and strings) for 
     399declaring any fields, but you will usually need them only for lists or, 
     400maybe, some complicated future controls. 
    458401 
    459402 
     
    462405***************************** 
    463406 
    464 Avoid it if you can. If you can't, here's the list of the methods you may need 
    465 to implement. You may want to copy as much from the :obj:`DomainContextHandler` 
    466 as 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. 
     407Avoid 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__ 
     411Has the same arguments as the :obj:`DomainContextHandler`'s, except for the :obj:`fields`. 
     412 
     413newContext 
     414Creates and returns a new context. In :obj:`ContextHandler` is returns an instance of :obj:`Context`; you probably won't need to change this. 
     415 
     416openContext 
     417The 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 
     419It 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 
     421closeContext 
     422Copies the settings from the widget by calling :obj:`settingsFromWidget`. You probably won't need to overwrite it. 
     423 
     424match 
     425The 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 
     427settingsToWidget/settingsFromWidget 
     428Copy the settings to and from the widget. 
     429 
     430fastSave 
     431This 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 
     433cloneContext 
     434Given an existing context, it prepares and returns a copy. The method is optional; :obj:`copy.deepcopy` can be used instead. 
    520435 
    521436 
     
    525440 
    526441Settings can be saved in two different places. Orange Canvas save 
    527 settings in .ini files in its application data directory. Each widget type has 
    528 a separate file; for instance, the scatter plot's settings are saved in 
     442settings in .ini files in directory 
     443Orange/OrangeWidgets/widgetSettings. Each widget type has its separate 
     444file; for instance, the scatter plot's settings are saved in 
    529445:obj:`ScatterPlot.ini`. Saved schemas and applications save 
    530446settings in .sav files; the .sav file is placed in the same directory 
     
    535451Saving and loading is done automatically by canvas or the 
    536452application. In a very rare case you need it to run these operations 
    537 manually, the functions involved are :obj:`loadSettings(self, file=None)`, 
    538 :obj:`saveSettings(self, file=None)`, :obj:`loadSettingsStr(self, str)`, 
     453manually, the functions involved are :obj:`loadSettings(self, file = 
     454None)`, :obj:`saveSettings(self, file = None)`, 
     455:obj:`loadSettingsStr(self, str)`, 
    539456:obj:`saveSettingsStr(self)`. The first two load and save from 
    540457the file; if not given, the default name (widget's name + 
  • docs/widgets/rst/index.rst

    r11433 r11312  
    2626    * - |Impute_icon| :ref:`Impute` 
    2727      - |Outliers_icon| :ref:`Outliers` 
    28       - |EditDomain_icon| :ref:`Edit Domain` 
    29     * - |PythonScript_icon| :ref:`Python Script` 
    3028      - 
    31       - 
    3229 
    3330.. |File_icon| image:: ../../../Orange/OrangeWidgets/Data/icons/File_48.png 
     
    114111    :width: 48 
    115112    :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 
    128113 
    129114 
     
    616601   data/impute.rst 
    617602   data/outliers.rst 
    618    data/editdomain.rst 
    619603 
    620604   visualize/distributions.rst 
  • docs/widgets/rst/visualize/linearprojection.rst

    r11422 r11359  
    4444nicely characterizes mamals from the other organisms, and that laying eggs is 
    4545something that birds do. This specific visualization was obtained using FreeViz 
    46 ([1]_), while the widget also implements an interface to supervised 
    47 principal component analysis ([2]_), partial least squares (for a nice 
    48 introduction, see [3]_), and RadViz visualization and 
     46([Demsar2007]_), while the widget also implements an interface to supervised 
     47principal component analysis ([Koren2003]_), partial least squares (for a nice 
     48introduction, see [Boulesteix2007]_), and RadViz visualization and 
    4949associated intelligent data visualization technique called VizRank  
    50 ([4]_) 
     50([Leban2006]_) 
    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 [1]_). 
     79define the type of the forces between the data points (see [Demsar2007]_). 
    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 ([4]_). This is 
     95is VizRank search algorithm with RadViz visualization ([Leban2006]_). This is 
    9696essentially the same visualization and projection search method as implemented 
    9797in :ref:`Radviz`. 
     
    107107---------- 
    108108 
    109 .. [1] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
     109.. [Demsar2007] 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 .. [2] Koren Y, Carmel L. Visualization of labeled data using linear 
     113.. [Koren2003] 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 .. [3] Boulesteix A-L, Strimmer K (2006) Partial least squares: 
     117.. [Boulesteix2007] 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 .. [4] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
     122.. [Leban2006] 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

    r11422 r11359  
    3333----------- 
    3434 
    35 Radviz ([1]_) is a neat non-linear multi-dimensional visualization 
     35Radviz ([Hoffman1997]_) 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 ([2]_). In this particular 
     49data set from functional genomics ([Brown2000]_). 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 [3]_ and 
    67 [5]_ for further illustrations of utility of Radviz in analysis of 
     66heat 20 and diau f are characteristic for Resp class. See [Leban2006]_ and 
     67[Mramor2007]_ 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 [3]_) and 
    89 [4]_) and interface for explorative data analysis - selection of data 
     88intelligent data visualization (VizRank and FreeViz, see [Leban2006]_) and 
     89[Demsar2007]_) 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 .. [1] Hoffman,P.E. et al. (1997) DNA visual and analytic data mining. 
     105.. [Hoffman1997] 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 .. [2] Brown, M. P., W. N. Grundy, et al. (2000). 
     108.. [Brown2000] 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 .. [3] Leban, G., B. Zupan, et al. (2006). "VizRank: Data Visualization 
     112.. [Leban2006] 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 .. [4] Demsar J, Leban G, Zupan B. FreeViz-An intelligent multivariate 
     116.. [Demsar2007] 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 .. [5] Mramor M, Leban G, Demsar J, Zupan B. Visualization-based 
     120.. [Mramor2007] 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

    r11422 r11359  
    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 ([1]_), that 
     70Orange's Scatterplot includes one such tool called VizRank ([Leban2006]_), 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 [1]_. The projections are evaluated through testing a selected 
     100[Leban2006]_. 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 .. [1] Leban G, Zupan B, Vidmar G, Bratko I. VizRank: Data 
     204.. [Leban2006] 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

    r11427 r10789  
    33# ./bundle-daily-build-hg.sh 
    44# 
    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 
     5# $1 Force 
    96# 
    107 
    11 WORK_DIR=${1:-"/private/tmp"} 
    12 PUBLISH_DIR=${2:-"$WORK_DIR/download"} 
    13  
    14 FORCE=$3 
    15 LOCAL=$4 
    16  
    17 ORANGE_REPO=$WORK_DIR/repos/orange 
     8FORCE=$1 
    189 
    1910trap "echo \"Script failed\"" ERR 
    2011 
    2112# If possible get the orange tip revision number and check if the bundle already exists 
    22 if [ -e $ORANGE_REPO ]; then 
     13if [ -e /private/tmp/repos/orange ]; then 
    2314    # Try to pull and update (pull returns 1 if no changesets) 
    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` 
     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` 
    2617else 
    2718    DAILY_REVISION="tip" 
    2819fi 
    2920 
    30 BUNDLE="$WORK_DIR/orange-bundle-hg-$DAILY_REVISION.dmg" 
    31 PUBLISH_BUNDLE=$PUBLISH_DIR/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
    32  
    33  
     21BUNDLE="/private/tmp/orange-bundle-hg-$DAILY_REVISION.dmg" 
     22         
    3423# Create the bundle if it does not yet exist 
    35 if [[ ! -e $PUBLISH_BUNDLE || $DAILY_REVISION -eq "tip" || $FORCE ]]; then 
     24if [[ ! -e /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg || $DAILY_REVISION -eq "tip" || $FORCE ]]; then 
    3625    echo "Building orange revision $DAILY_REVISION" 
    37     ./bundle-build-hg.sh $WORK_DIR tip $BUNDLE 
     26    ./bundle-build-hg.sh /private/tmp tip $BUNDLE 
    3827     
    3928    # Get the revision again in case it was "tip" 
    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 
     29    DAILY_REVISION=`hg log -r tip -R /private/tmp/repos/orange | grep 'changeset:' | cut -d ' ' -f 4 | cut -d ':' -f 1` 
    4330 
    44     if [ ! $LOCAL ]; then 
    45         /Users/ailabc/mount-dirs.sh 
    46     fi 
     31    # TODO: Should be called only on a daily build server and not if building locally 
     32    /Users/ailabc/mount-dirs.sh 
    4733 
    4834    echo "Removing old versions of bundles." 
    4935    # (Keeps last 5 versions.) 
    50     perl -e "unlink ((reverse sort <$PUBLISH_DIR/orange-bundle-hg-0*.dmg>)[5..10000])" 
     36    perl -e 'unlink ((reverse sort </Volumes/download/orange-bundle-hg-0*.dmg>)[5..10000])' 
    5137 
    5238    MD5=`md5 -q $BUNDLE` 
    5339     
    5440    echo "Moving bundle to the download directory." 
    55     mv $BUNDLE $PUBLISH_BUNDLE.new 
     41    mv $BUNDLE /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
    5642 
    5743    echo "Setting permissions." 
    58     chmod +r $PUBLISH_BUNDLE.new 
     44    chmod +r /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
    5945 
    60     # Check integrity 
    61     MD5_D=`md5 -q $PUBLISH_BUNDLE.new` 
     46    # Check integrity  
     47    MD5_D=`md5 -q /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg` 
    6248    if [[ $MD5 != $MD5_D ]]; then 
    6349        echo "Error moving the bundle in place" 
    64         rm $PUBLISH_BUNDLE.new 
     50        rm /Volumes/download/orange-bundle-hg-0.0.$DAILY_REVISION.dmg 
    6551        exit 1 
    66     else 
    67         mv $PUBLISH_BUNDLE.new $PUBLISH_BUNDLE 
    6852    fi 
    6953     
    7054    echo "Registering new bundles." 
    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 
     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 
    7458 
    7559else 
  • install-scripts/mac/dailyrun-bundleonly-hg.sh

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

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

    r11429 r7862  
    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/ 
     7umount /Volumes/fink/ 2> /dev/null || true 
     8sleep 5 
     9mkdir -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

    r11429 r10681  
    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 
     10curl --silent --output dailyrun-finkonly-withsource.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-finkonly-withsource.sh 
     11curl --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 
     13curl --silent --output fink-daily-build.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build.sh 
     14curl --silent --output fink-restore-selections.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-restore-selections.sh 
     15curl --silent --output fink-selfupdate-orange.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-selfupdate-orange.sh 
     16curl --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 
     24curl --silent --output fink-daily-build-packages.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build-packages.sh 
     25curl --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

    r11435 r8099  
    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" 
     93ssh ailabc@$IP_ADDRESS "sudo /Users/ailabc/dailyrun-finkonly.sh" 
    9494 
    9595stop_vmware 
Note: See TracChangeset for help on using the changeset viewer.