Changeset 11827:746f5c391a27 in orange


Ignore:
Timestamp:
01/06/14 17:59:30 (3 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Children:
11828:6266629a6575, 11833:59d18133e0ff
Message:

'Paint Data' widget code cleanup.

File:
1 edited

Legend:

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

    r11780 r11827  
     1import itertools 
    12import unicodedata 
    23import copy 
    3  
    4 import orange 
     4import random 
     5 
     6 
     7from PyQt4 import QtCore 
     8from PyQt4.QtCore import pyqtSignal as Signal 
     9 
     10import Orange 
     11 
    512import OWToolbars 
    613import OWColorPalette 
    7 import Orange.data 
    8 from PyQt4 import QtCore 
    914from OWWidget import * 
    1015from OWGraph import * 
    1116from OWItemModels import VariableListModel, PyListModel, ModelActionsWidget 
    1217 
     18 
    1319NAME = "Paint Data" 
    14 DESCRIPTION = """Paints the data on a 2D plane. Place individual data 
    15 points or use brush to paint a larger data sets.""" 
     20DESCRIPTION = """ 
     21Paints the data on a 2D plane. Place individual data 
     22points or use brush to paint a larger data sets. 
     23""" 
    1624LONG_DESCRIPTION = "" 
    1725ICON = "icons/PaintData.svg" 
    1826PRIORITY = 40 
    19 AUTHOR = "Ales Erjavec" 
    20 AUTHOR_EMAIL = "ales.erjavec(@at@)fri.uni-lj.si" 
    2127OUTPUTS = [("Data", Orange.data.Table, )] 
    2228 
     
    3238 
    3339class PaintDataGraph(OWGraph): 
     40    def __init__(self, *args, **kwargs): 
     41        OWGraph.__init__(self, *args, **kwargs) 
     42        self.toolPixmap = QPixmap() 
     43 
     44    def setToolPixmap(self, pixmap): 
     45        self.toolPixmap = pixmap 
     46        self.update() 
     47 
    3448    def setData(self, data, attr1, attr2): 
    35         """ Set the data to display. 
    36          
     49        """ 
     50        Set the data to display. 
     51 
    3752        :param data: data 
    3853        :param attr1: attr for X axis 
     
    4459        self.attr2 = attr2 
    4560        self.updateGraph() 
    46          
     61 
    4762    def updateGraph(self, dataInterval=None): 
    4863        if dataInterval: 
     
    5368            data = self.data 
    5469 
    55         clsValues, hasCls = (self.data.domain.classVar.values, True) if self.data.domain.classVar else ([0], False) 
    56          
     70        domain = self.data.domain 
     71        clsValues = domain.class_var.values if domain.class_var else [0] 
     72 
    5773        palette = ColorPaletteGenerator(len(clsValues)) 
    5874        for i, cls in enumerate(clsValues): 
    5975            x = [float(ex[self.attr1]) for ex in data if ex.getclass() == cls] 
    6076            y = [float(ex[self.attr2]) for ex in data if ex.getclass() == cls] 
    61             self.addCurve("data points", xData=x, yData=y, brushColor=palette[i], penColor=palette[i]) 
     77            self.addCurve("data points", xData=x, yData=y, 
     78                          brushColor=palette[i], penColor=palette[i]) 
    6279        self.replot() 
    63          
     80 
    6481    def drawCanvas(self, painter): 
    6582        OWGraph.drawCanvas(self, painter) 
    66         pixmap = getattr(self, "_tool_pixmap", None) 
    67         if pixmap: 
     83        pixmap = self.toolPixmap 
     84        if not pixmap.isNull(): 
    6885            painter.drawPixmap(0, 0, pixmap) 
    69          
    70          
     86 
     87 
    7188class DataTool(QObject): 
    72     """ A base class for data tools that operate on PaintDataGraph 
     89    """ 
     90    A base class for data tools that operate on PaintDataGraph 
    7391    widget by installing itself as its event filter. 
    74       
     92 
    7593    """ 
     94    editing = Signal() 
     95    editingFinished = Signal() 
     96 
    7697    cursor = Qt.ArrowCursor 
     98 
    7799    class optionsWidget(QFrame): 
    78         """ An options (parameters) widget for the tool (this will 
     100        """ 
     101        An options (parameters) widget for the tool (this will 
    79102        be put in the "Options" box in the main OWPaintData widget 
    80103        when this tool is selected. 
    81          
     104 
    82105        """ 
    83106        def __init__(self, tool, parent=None): 
    84107            QFrame.__init__(self, parent) 
    85108            self.tool = tool 
    86              
     109 
    87110    def __init__(self, graph, parent=None): 
    88111        QObject.__init__(self, parent) 
    89112        self.setGraph(graph) 
    90          
     113 
    91114    def setGraph(self, graph): 
    92         """ Install this tool to operate on ``graph``. If another tool 
    93         is already operating on the graph it will first be removed. 
    94          
     115        """ 
     116        Install this tool to operate on ``graph``. 
     117 
     118        If another tool is already operating on the graph it will first 
     119        be removed. 
     120 
    95121        """ 
    96122        self.graph = graph 
     
    103129            self.graph.canvas().installEventFilter(self) 
    104130            self.graph._data_tool_event_filter = self 
    105             self.graph._tool_pixmap = None 
     131            self.graph.setToolPixmap(QPixmap()) 
    106132            self.graph.setCursor(self.cursor) 
    107133            self.graph.replot() 
    108134            self.installed() 
    109              
     135 
    110136    def removed(self): 
    111         """ Called when the tool is removed from a graph. 
     137        """Called when the tool is removed from a graph. 
    112138        """ 
    113139        pass 
    114      
     140 
    115141    def installed(self): 
    116         """ Called when the tool is installed on a graph. 
     142        """Called when the tool is installed on a graph. 
    117143        """ 
    118144        pass 
    119          
     145 
    120146    def eventFilter(self, obj, event): 
    121147        if event.type() == QEvent.MouseButtonPress: 
     
    134160            return self.enterEvent(event) 
    135161        return False 
    136      
     162 
    137163    # These are actually event filters (note the return values) 
    138164    def paintEvent(self, event): 
    139165        return False 
    140      
     166 
    141167    def mousePressEvent(self, event): 
    142168        return False 
    143      
     169 
    144170    def mouseMoveEvent(self, event): 
    145171        return False 
    146      
     172 
    147173    def mouseReleaseEvent(self, event): 
    148174        return False 
    149      
     175 
    150176    def mouseDoubleClickEvent(self, event): 
    151177        return False 
    152      
     178 
    153179    def enterEvent(self, event): 
    154180        return False 
    155      
     181 
    156182    def leaveEvent(self, event): 
    157183        return False 
    158      
     184 
    159185    def keyPressEvent(self, event): 
    160186        return False 
    161      
     187 
    162188    def transform(self, point): 
    163         x, y = point.x(), point.y() 
    164         x = self.graph.transform(QwtPlot.xBottom, x) 
    165         y = self.graph.transform(QwtPlot.yLeft, x) 
     189        x = self.graph.transform(QwtPlot.xBottom, point.x()) 
     190        y = self.graph.transform(QwtPlot.yLeft, point.y()) 
    166191        return QPoint(x, y) 
    167      
     192 
    168193    def invTransform(self, point): 
    169         x, y = point.x(), point.y() 
    170         x = self.graph.invTransform(QwtPlot.xBottom, x) 
    171         y = self.graph.invTransform(QwtPlot.yLeft, y) 
     194        x = self.graph.invTransform(QwtPlot.xBottom, point.x()) 
     195        y = self.graph.invTransform(QwtPlot.yLeft, point.y()) 
    172196        return QPointF(x, y) 
    173      
     197 
    174198    def attributes(self): 
    175199        return self.graph.attr1, self.graph.attr2 
    176      
     200 
    177201    def dataTransform(self, *args): 
    178202        pass 
    179      
    180      
     203 
     204 
    181205class GraphSelections(QObject): 
     206    selectionRegionAdded = Signal(int, QPainterPath) 
     207    selectionRegionUpdated = Signal(int, QPainterPath) 
     208    selectionRegionRemoved = Signal(int, QPainterPath) 
     209 
     210    selectionRegionMoveStarted = Signal(int, QPointF, QPainterPath) 
     211    selectionRegionMoved = Signal(int, QPointF, QPainterPath) 
     212    selectionRegionMoveFinished = Signal(int, QPointF, QPainterPath) 
     213    selectionGeometryChanged = Signal() 
     214 
    182215    def __init__(self, parent, movable=True, multipleSelection=False): 
    183216        QObject.__init__(self, parent) 
     
    185218        self.movable = movable 
    186219        self.multipleSelection = multipleSelection 
    187          
    188         self._moving_index, self._moving_pos, self._selection_region = -1, QPointF(), (QPointF(), QPointF()) 
    189          
     220 
     221        self._moving_index, self._moving_pos, self._selection_region = \ 
     222            (-1, QPointF(), (QPointF(), QPointF())) 
     223 
    190224    def getPos(self, event): 
    191225        graph = self.parent() 
     
    194228        y = graph.invTransform(QwtPlot.yLeft, pos.y()) 
    195229        return QPointF(x, y) 
    196      
     230 
    197231    def toPath(self, region): 
    198232        path = QPainterPath() 
    199233        if isinstance(region, QRectF) or isinstance(region, QRect): 
    200             path.addRect(rect.normalized()) 
     234            path.addRect(region.normalized()) 
    201235        elif isinstance(region, tuple): 
    202236            path.addRect(QRectF(*region).normalized()) 
     
    204238            path.addPolygon(QPolygonF(region + [region[0]])) 
    205239        return path 
    206              
    207      
     240 
    208241    def addSelectionRegion(self, region): 
    209242        self.selection.append(region) 
    210         self.emit(SIGNAL("selectionRegionAdded(int, QPainterPath)"), len(self.selection) - 1, self.toPath(region)) 
    211          
     243        self.selectionRegionAdded.emit( 
     244            len(self.selection) - 1, self.toPath(region)) 
     245 
    212246    def setSelectionRegion(self, index, region): 
    213247        self.selection[index] = region 
    214         self.emit(SIGNAL("selectionRegionUpdated(int, QPainterPath)"), index, self.toPath(region)) 
    215          
     248        self.selectionRegionUpdated.emit(index, self.toPath(region)) 
     249 
    216250    def clearSelection(self): 
    217251        for i, region in enumerate(self.selection): 
    218             self.emit(SIGNAL("selectionRegionRemoved(int, QPainterPath)"), i, self.toPath(region)) 
     252            self.selectionRegionRemoved.emit(i, self.toPath(region)) 
    219253        self.selection = [] 
    220          
     254 
    221255    def start(self, event): 
    222256        pos = self.getPos(event) 
    223257        index = self.regionAt(event) 
    224258        if index == -1 or not self.movable: 
    225             if event.modifiers() & Qt.ControlModifier and self.multipleSelection: 
     259            if event.modifiers() & Qt.ControlModifier and \ 
     260                    self.multipleSelection: 
    226261                self.addSelectionRegion((pos, pos)) 
    227262            else: 
     
    230265            self._moving_index = -1 
    231266        else: 
    232             self._moving_index, self._moving_pos, self._selection_region = index, pos, self.selection[index] 
    233             self.emit(SIGNAL("selectionRegionMoveStarted(int, QPointF, QPainterPath)"), 
    234                       index, pos, self.toPath(self.selection[index])) 
    235         self.emit(SIGNAL("selectionGeometryChanged()")) 
    236      
     267            self._moving_index, self._moving_pos, self._selection_region = \ 
     268                (index, pos, self.selection[index]) 
     269 
     270            self.selectionRegionMoveStarted.emit( 
     271                index, pos, self.toPath(self.selection[index]) 
     272            ) 
     273        self.selectionGeometryChanged.emit() 
     274 
    237275    def update(self, event): 
    238276        pos = self.getPos(event) 
     
    240278        if index == -1: 
    241279            self.selection[-1] = self.selection[-1][:-1] + (pos,) 
    242             self.emit(SIGNAL("selectionRegionUpdated(int, QPainterPath)"), len(self.selection) - 1, 
    243                       self.toPath(self.selection[-1])) 
     280            self.selectionRegionUpdated.emit( 
     281                len(self.selection) - 1, self.toPath(self.selection[-1])) 
     282 
    244283        else: 
    245284            diff = self._moving_pos - pos 
    246             self.selection[index] = tuple([p - diff for p in self._selection_region]) 
    247             self.emit(SIGNAL("selectionRegionMoved(int, QPointF, QPainterPath)"), 
    248                       index, pos, self.toPath(self.selection[index])) 
    249              
    250         self.emit(SIGNAL("selectionGeometryChanged()")) 
    251      
     285            self.selection[index] = \ 
     286                tuple([p - diff for p in self._selection_region]) 
     287            self.selectionRegionMoved.emit( 
     288                index, pos, self.toPath(self.selection[index]) 
     289            ) 
     290        self.selectionGeometryChanged.emit() 
     291 
    252292    def end(self, event): 
    253293        self.update(event) 
    254294        if self._moving_index != -1: 
    255             self.emit(SIGNAL("selectionRegionMoveFinished(int, QPointF, QPainterPath)"),  
    256                       self._moving_index, self.getPos(event), 
    257                       self.toPath(self.selection[self._moving_index])) 
     295            self.selectionRegionMoveFinished.emit( 
     296                self._moving_index, self.getPos(event), 
     297                self.toPath(self.selection[self._moving_index]) 
     298            ) 
    258299        self._moving_index = -1 
    259                        
     300 
    260301    def regionAt(self, event): 
    261302        pos = self.getPos(event) 
     
    264305                return i 
    265306        return -1 
    266          
     307 
    267308    def testSelection(self, data): 
    268309        data = numpy.asarray(data) 
     
    274315        test = numpy.apply_along_axis(test, 1, data) 
    275316        return test 
    276      
     317 
    277318    def __nonzero__(self): 
    278319        return bool(self.selection) 
    279      
     320 
    280321    def __bool__(self): 
    281322        return bool(self.selection) 
    282      
     323 
    283324    def path(self): 
    284325        path = QPainterPath() 
     
    286327            path = path.united(self.toPath(region)) 
    287328        return path 
    288      
     329 
    289330    def qTransform(self): 
    290331        graph = self.parent() 
    291332        invTransform = graph.invTransform 
    292         e1 = graph.canvas().mapFrom(graph, QPoint(1, 0)) 
    293         e2 = graph.canvas().mapFrom(graph, QPoint(0, 1)) 
    294         e1x, e1y = e1.x(), e1.y() 
    295         e2x, e2y = e2.x(), e2.y() 
    296333        sx = invTransform(QwtPlot.xBottom, 1) - invTransform(QwtPlot.xBottom, 0) 
    297334        sy = invTransform(QwtPlot.yLeft, 1) - invTransform(QwtPlot.yLeft, 0) 
     
    299336        dy = invTransform(QwtPlot.yLeft, 0) 
    300337        return QTransform(sx, 0.0, 0.0, sy, dx, dy) 
    301      
    302      
     338 
     339 
    303340class SelectTool(DataTool): 
    304341    class optionsWidget(QFrame): 
     
    307344            self.tool = tool 
    308345            layout = QHBoxLayout() 
    309             delete = QToolButton(self) 
    310             delete.pyqtConfigure(text="Delete", toolTip="Delete selected instances") 
    311             self.connect(delete, SIGNAL("clicked()"), self.tool.deleteSelected) 
    312              
     346            delete = QToolButton(self, text="Delete", 
     347                                toolTip="Delete selected instances") 
     348            delete.clicked.connect(self.tool.deleteSelected) 
     349 
    313350            layout.addWidget(delete) 
    314351            layout.addStretch(10) 
    315352            self.setLayout(layout) 
    316          
     353 
    317354    def __init__(self, graph, parent=None, graphSelection=None): 
    318355        DataTool.__init__(self, graph, parent) 
     
    321358        else: 
    322359            self.selection = graphSelection 
    323              
     360 
    324361        self.pen = QPen(Qt.black, 1, Qt.DashDotLine) 
    325362        self.pen.setCosmetic(True) 
    326363        self.pen.setJoinStyle(Qt.RoundJoin) 
    327364        self.pen.setCapStyle(Qt.RoundCap) 
    328         self.connect(self.selection, SIGNAL("selectionRegionMoveStarted(int, QPointF, QPainterPath)"), 
    329                      self.onMoveStarted) 
    330         self.connect(self.selection, SIGNAL("selectionRegionMoved(int, QPointF, QPainterPath)"), 
    331                      self.onMove) 
    332         self.connect(self.selection, SIGNAL("selectionRegionMoveFinished(int, QPointF, QPainterPath)"), 
    333                      self.onMoveFinished) 
    334         self.connect(self.selection, SIGNAL("selectionRegionUpdated(int, QPainterPath)"), 
    335                      self.invalidateMoveSelection) 
     365 
     366        self.selection.selectionRegionMoveStarted.connect(self.onMoveStarted) 
     367        self.selection.selectionRegionMoved.connect(self.onMove) 
     368        self.selection.selectionRegionMoveFinished.connect(self.onMoveFinished) 
     369        self.selection.selectionRegionUpdated.connect( 
     370                self.invalidateMoveSelection) 
     371 
    336372        self._validMoveSelection = False 
    337373        self._moving = None 
    338          
     374 
    339375    def setGraph(self, graph): 
    340376        DataTool.setGraph(self, graph) 
     
    345381        DataTool.installed(self) 
    346382        self.invalidateMoveSelection() 
    347          
     383 
    348384    def paintEvent(self, event): 
    349385        if self.selection: 
     
    354390            inverted, singular = self.selection.qTransform().inverted() 
    355391            painter.setPen(self.pen) 
    356              
     392 
    357393            painter.setTransform(inverted) 
    358394            for region in self.selection.selection: 
    359395                painter.drawPath(self.selection.toPath(region)) 
    360             del painter 
    361             self.graph._tool_pixmap = pixmap 
    362         return False 
    363          
     396            painter.end() 
     397            self.graph.setToolPixmap(pixmap) 
     398        return False 
     399 
    364400    def mousePressEvent(self, event): 
    365401        if event.button() == Qt.LeftButton: 
     
    367403            self.graph.replot() 
    368404        return True 
    369      
     405 
    370406    def mouseMoveEvent(self, event): 
    371407        index = self.selection.regionAt(event) 
     
    374410        else: 
    375411            self.graph.canvas().setCursor(self.graph._cursor) 
    376              
     412 
    377413        if event.buttons() & Qt.LeftButton: 
    378414            self.selection.update(event) 
    379415            self.graph.replot() 
    380416        return True 
    381      
     417 
    382418    def mouseReleaseEvent(self, event): 
    383419        if event.button() == Qt.LeftButton: 
     
    385421            self.graph.replot() 
    386422        return True 
    387      
     423 
    388424    def invalidateMoveSelection(self, *args): 
    389425        self._validMoveSelection = False 
    390426        self._moving = None 
    391          
     427 
    392428    def onMoveStarted(self, index, pos, path): 
    393429        data = self.graph.data 
    394430        attr1, attr2 = self.graph.attr1, self.graph.attr2 
    395431        if not self._validMoveSelection: 
    396             self._moving = [(i, float(ex[attr1]), float(ex[attr2])) for i, ex in enumerate(data)] 
    397             self._moving = [(i, x, y) for i, x, y in self._moving if path.contains(QPointF(x, y))] 
     432            self._moving = [(i, float(ex[attr1]), float(ex[attr2])) 
     433                            for i, ex in enumerate(data)] 
     434            self._moving = [(i, x, y) for i, x, y in self._moving 
     435                            if path.contains(QPointF(x, y))] 
    398436            self._validMoveSelection = True 
    399437        self._move_anchor = pos 
    400          
     438 
    401439    def onMove(self, index, pos, path): 
    402440        data = self.graph.data 
    403441        attr1, attr2 = self.graph.attr1, self.graph.attr2 
    404          
    405         diff = pos - self._move_anchor  
     442 
     443        diff = pos - self._move_anchor 
    406444        for i, x, y in self._moving: 
    407445            ex = data[i] 
     
    409447            ex[attr2] = y + diff.y() 
    410448        self.graph.updateGraph() 
    411         self.emit(SIGNAL("editing()")) 
    412          
     449        self.editing.emit() 
     450 
    413451    def onMoveFinished(self, index, pos, path): 
    414452        self.onMove(index, pos, path) 
     
    416454        self._moving = [(i, x + diff.x(), y + diff.y()) \ 
    417455                        for i, x, y in self._moving] 
    418          
    419         self.emit(SIGNAL("editingFinished()")) 
    420          
     456 
     457        self.editingFinished.emit() 
     458 
    421459    def deleteSelected(self, *args): 
    422460        data = self.graph.data 
    423461        attr1, attr2 = self.graph.attr1, self.graph.attr2 
    424462        path = self.selection.path() 
    425         selected = [i for i, ex in enumerate(data) if path.contains(QPointF(float(ex[attr1]) , float(ex[attr2])))] 
     463        selected = [i for i, ex in enumerate(data) 
     464                    if path.contains(QPointF(float(ex[attr1]), 
     465                                             float(ex[attr2])))] 
     466        if selected: 
     467            self.editing.emit() 
     468 
    426469        for i in reversed(selected): 
    427470            del data[i] 
    428471        self.graph.updateGraph() 
     472 
    429473        if selected: 
    430             self.emit(SIGNAL("editing()")) 
    431             self.emit(SIGNAL("editingFinished()")) 
     474            self.editingFinished.emit() 
    432475 
    433476 
     
    440483            self.addSelectionRegion([pos]) 
    441484        else: 
    442             self._moving_index, self._moving_pos, self._selection_region = index, pos, self.selection[index] 
    443             self.emit(SIGNAL("selectionRegionMoveStarted(int, QPointF, QPainterPath)"), 
    444                       index, pos, self.toPath(self.selection[index])) 
    445         self.emit(SIGNAL("selectionGeometryChanged()")) 
    446          
     485            self._moving_index, self._moving_pos, self._selection_region = \ 
     486                index, pos, self.selection[index] 
     487 
     488            self.selectionRegionMoveStarted.emit( 
     489                index, pos, self.toPath(self.selection[index]) 
     490            ) 
     491 
     492        self.selectionGeometryChanged.emit() 
     493 
    447494    def update(self, event): 
    448495        pos = self.getPos(event) 
     
    450497        if index == -1: 
    451498            self.selection[-1].append(pos) 
    452             self.emit(SIGNAL("selectionRegionUpdated(int, QPainterPath)"), 
    453                       len(self.selection) - 1, self.toPath(self.selection[-1])) 
     499            self.selectionRegionUpdated.emit( 
     500                len(self.selection) - 1, self.toPath(self.selection[-1]) 
     501            ) 
    454502        else: 
    455503            diff = self._moving_pos - pos 
    456504            self.selection[index] = [p - diff for p in self._selection_region] 
    457             self.emit(SIGNAL("selectionRegionMoved(int, QPointF, QPainterPath)"), 
    458                       index, pos, self.toPath(self.selection[index])) 
    459              
    460         self.emit(SIGNAL("selectionGeometryChanged()")) 
    461          
     505            self.selectionRegionMoved.emit( 
     506                index, pos, self.toPath(self.selection[index]) 
     507            ) 
     508 
     509        self.selectionGeometryChanged.emit() 
     510 
    462511    def end(self, event): 
    463512        self.update(event) 
    464513        if self._moving_index != -1: 
    465             self.emit(SIGNAL("selectionRegionMoveFinished(int, QPointF, QPainterPath)"),  
    466                       self._moving_index, self.getPos(event), 
    467                       self.toPath(self.selection[self._moving_index])) 
     514            self.selectionRegionMoveFinished.emit( 
     515                self._moving_index, self.getPos(event), 
     516                self.toPath(self.selection[self._moving_index]) 
     517            ) 
    468518        self._moving_index = -1 
    469          
    470          
     519 
     520 
    471521class LassoTool(SelectTool): 
    472522    def __init__(self, graph, parent=None): 
    473         SelectTool.__init__(self, graph, parent,  
     523        SelectTool.__init__(self, graph, parent, 
    474524                            graphSelection=GraphLassoSelections(graph)) 
    475 #        self.selection = GraphLassoSelections(graph) 
    476 #        self.pen = QPen(Qt.black, 1, Qt.DashDotLine) 
    477 #        self.pen.setCosmetic(True) 
    478 #        self.pen.setJoinStyle(Qt.RoundJoin) 
    479 #        self.pen.setCapStyle(Qt.RoundCap) 
    480 #        self.connect(self.selection, SIGNAL("selectionRegionMoveStarted(int, QPointF, QPainterPath)"), self.onMoveStarted) 
    481 #        self.connect(self.selection, SIGNAL("selectionRegionMoved(int, QPointF, QPainterPath)"), self.onMove) 
    482 #        self.connect(self.selection, SIGNAL("selectionRegionMoveFinished(int, QPointF, QPainterPath)"), self.onMoveFinished) 
    483      
    484      
     525 
     526 
    485527class ZoomTool(DataTool): 
    486528    def __init__(self, graph, parent=None): 
    487529        DataTool.__init__(self, graph, parent) 
    488          
     530 
    489531    def paintEvent(self, event): 
    490532        return False 
    491      
     533 
    492534    def mousePressEvent(self, event): 
    493535        return False 
    494      
     536 
    495537    def mouseMoveEvent(self, event): 
    496538        return False 
    497      
     539 
    498540    def mouseReleaseEvent(self, event): 
    499541        return False 
    500      
     542 
    501543    def mouseDoubleClickEvent(self, event): 
    502544        return False 
    503      
     545 
    504546    def keyPressEvent(self, event): 
    505547        return False 
    506      
    507      
     548 
     549 
    508550class PutInstanceTool(DataTool): 
    509551    cursor = Qt.CrossCursor 
     552 
    510553    def mousePressEvent(self, event): 
    511554        if event.buttons() & Qt.LeftButton: 
     
    513556            val1, val2 = coord.x(), coord.y() 
    514557            attr1, attr2 = self.attributes() 
     558            self.editing.emit() 
    515559            self.dataTransform(attr1, val1, attr2, val2) 
    516             self.emit(SIGNAL("editing()")) 
    517             self.emit(SIGNAL("editingFinished()")) 
     560            self.editingFinished.emit() 
    518561        return True 
    519          
     562 
    520563    def dataTransform(self, attr1, val1, attr2, val2): 
    521         example = orange.Example(self.graph.data.domain) 
    522         example[attr1] = val1 
    523         example[attr2] = val2 
    524         example.setclass(self.graph.data.domain.classVar(self.graph.data.domain.classVar.baseValue)) 
     564        domain = self.graph.data.domain 
     565        example = Orange.data.Instance( 
     566            domain, [val1, val2, domain.class_var.base_value] 
     567        ) 
     568 
    525569        self.graph.data.append(example) 
    526570        self.graph.updateGraph(dataInterval=(-1, sys.maxint)) 
    527          
    528          
     571 
     572 
    529573class BrushTool(DataTool): 
    530574    brushRadius = 20 
    531575    density = 5 
    532576    cursor = Qt.CrossCursor 
    533      
     577 
    534578    class optionsWidget(QFrame): 
    535579        def __init__(self, tool, parent=None): 
     
    537581            self.tool = tool 
    538582            layout = QFormLayout() 
    539             self.radiusSlider = QSlider(Qt.Horizontal) 
    540             self.radiusSlider.pyqtConfigure(minimum=10, maximum=30, value=self.tool.brushRadius) 
    541             self.densitySlider = QSlider(Qt.Horizontal) 
    542             self.densitySlider.pyqtConfigure(minimum=3, maximum=10, value=self.tool.density) 
    543              
     583            self.radiusSlider = QSlider(Qt.Horizontal, minimum=10, maximum=30, 
     584                                        value=self.tool.brushRadius) 
     585            self.densitySlider = QSlider(Qt.Horizontal, minimum=3, maximum=10, 
     586                                        value=self.tool.density) 
     587 
    544588            layout.addRow("Radius", self.radiusSlider) 
    545589            layout.addRow("Density", self.densitySlider) 
    546590            self.setLayout(layout) 
    547              
    548             self.connect(self.radiusSlider, SIGNAL("valueChanged(int)"), 
    549                          lambda value: setattr(self.tool, "brushRadius", value)) 
    550              
    551             self.connect(self.densitySlider, SIGNAL("valueChanged(int)"), 
    552                          lambda value: setattr(self.tool, "density", value)) 
    553      
     591 
     592            self.radiusSlider.valueChanged[int].connect( 
     593                lambda value: setattr(self.tool, "brushRadius", value) 
     594            ) 
     595 
     596            self.densitySlider.valueChanged[int].connect( 
     597                lambda value: setattr(self.tool, "density", value) 
     598            ) 
     599 
    554600    def __init__(self, graph, parent=None): 
    555601        DataTool.__init__(self, graph, parent) 
    556602        self.brushState = -20, -20, 0, 0 
    557      
     603 
    558604    def mousePressEvent(self, event): 
    559         self.brushState = event.pos().x(), event.pos().y(), self.brushRadius, self.brushRadius 
     605        self.brushState = (event.pos().x(), event.pos().y(), 
     606                           self.brushRadius, self.brushRadius) 
     607        x, y, rx, ry = self.brushGeometry(event.pos()) 
     608        if event.buttons() & Qt.LeftButton: 
     609            attr1, attr2 = self.attributes() 
     610            self.editing.emit() 
     611            self.dataTransform(attr1, x, rx, attr2, y, ry) 
     612 
     613        self.graph.replot() 
     614        return True 
     615 
     616    def mouseMoveEvent(self, event): 
     617        self.brushState = (event.pos().x(), event.pos().y(), 
     618                           self.brushRadius, self.brushRadius) 
    560619        x, y, rx, ry = self.brushGeometry(event.pos()) 
    561620        if event.buttons() & Qt.LeftButton: 
    562621            attr1, attr2 = self.attributes() 
    563622            self.dataTransform(attr1, x, rx, attr2, y, ry) 
    564             self.emit(SIGNAL("editing()")) 
    565623        self.graph.replot() 
    566624        return True 
    567          
    568     def mouseMoveEvent(self, event): 
    569         self.brushState = event.pos().x(), event.pos().y(), self.brushRadius, self.brushRadius 
    570         x, y, rx, ry = self.brushGeometry(event.pos()) 
    571         if event.buttons() & Qt.LeftButton: 
    572             attr1, attr2 = self.attributes() 
    573             self.dataTransform(attr1, x, rx, attr2, y, ry) 
    574             self.emit(SIGNAL("editing()")) 
    575         self.graph.replot() 
    576         return True 
    577      
     625 
    578626    def mouseReleaseEvent(self, event): 
    579627        self.graph.replot() 
    580628        if event.button() & Qt.LeftButton: 
    581             self.emit(SIGNAL("editingFinished()")) 
     629            self.editingFinished.emit() 
    582630        return True 
    583      
     631 
    584632    def leaveEvent(self, event): 
    585         self.graph._tool_pixmap = None 
     633        self.graph.setToolPixmap(QPixmap()) 
    586634        self.graph.replot() 
    587635        return False 
    588          
     636 
    589637    def paintEvent(self, event): 
    590638        if not self.graph.canvas().underMouse(): 
    591             self.graph._tool_pixmap = None 
    592             return False  
    593              
     639            self.graph.setToolPixmap(QPixmap()) 
     640            return False 
     641 
    594642        pixmap = QPixmap(self.graph.canvas().size()) 
    595643        pixmap.fill(QColor(255, 255, 255, 0)) 
    596644        painter = QPainter(pixmap) 
    597645        painter.setRenderHint(QPainter.Antialiasing) 
    598         try: 
    599             painter.setPen(QPen(Qt.black, 1)) 
    600             x, y, w, h = self.brushState 
    601             painter.drawEllipse(QPoint(x, y), w, h) 
    602         except Exception, ex: 
    603             print ex 
    604         del painter 
    605         self.graph._tool_pixmap = pixmap 
    606         return False 
    607          
     646        painter.setPen(QPen(Qt.black, 1)) 
     647        x, y, w, h = self.brushState 
     648        painter.drawEllipse(QPoint(x, y), w, h) 
     649 
     650        painter.end() 
     651 
     652        self.graph.setToolPixmap(pixmap) 
     653        return False 
     654 
    608655    def brushGeometry(self, point): 
    609656        coord = self.invTransform(point) 
    610         dcoord = self.invTransform(QPoint(point.x() + self.brushRadius, point.y() + self.brushRadius)) 
     657        dcoord = self.invTransform(QPoint(point.x() + self.brushRadius, 
     658                                          point.y() + self.brushRadius)) 
    611659        x, y = coord.x(), coord.y() 
    612660        rx, ry = dcoord.x() - x, -(dcoord.y() - y) 
    613661        return x, y, rx, ry 
    614      
     662 
    615663    def dataTransform(self, attr1, x, rx, attr2, y, ry): 
    616         import random 
    617664        new = [] 
     665        domain = self.graph.data.domain 
     666 
    618667        for i in range(self.density): 
    619             ex = orange.Example(self.graph.data.domain) 
    620             ex[attr1] = random.normalvariate(x, rx) 
    621             ex[attr2] = random.normalvariate(y, ry) 
    622             ex.setclass(self.graph.data.domain.classVar(self.graph.data.domain.classVar.baseValue)) 
     668            ex = Orange.data.Instance( 
     669                domain, [random.normalvariate(x, rx), 
     670                         random.normalvariate(y, ry), 
     671                         domain.class_var.base_value] 
     672            ) 
     673 
    623674            new.append(ex) 
    624675        self.graph.data.extend(new) 
    625676        self.graph.updateGraph(dataInterval=(-len(new), sys.maxint)) 
    626      
    627      
     677 
     678 
    628679class MagnetTool(BrushTool): 
    629680    cursor = Qt.ArrowCursor 
     681 
    630682    def dataTransform(self, attr1, x, rx, attr2, y, ry): 
    631683        for ex in self.graph.data: 
    632684            x1, y1 = float(ex[attr1]), float(ex[attr2]) 
    633             distsq = (x1 - x)**2 + (y1 - y)**2 
     685            distsq = (x1 - x) ** 2 + (y1 - y) ** 2 
    634686            dist = math.sqrt(distsq) 
    635687            attraction = self.density / 100.0 
    636688            advance = 0.005 
    637             dx = -(x1 - x)/dist * attraction / max(distsq, rx) * advance 
    638             dy = -(y1 - y)/dist * attraction / max(distsq, ry) * advance 
     689            dx = -(x1 - x) / dist * attraction / max(distsq, rx) * advance 
     690            dy = -(y1 - y) / dist * attraction / max(distsq, ry) * advance 
    639691            ex[attr1] = x1 + dx 
    640692            ex[attr2] = y1 + dy 
    641693        self.graph.updateGraph() 
    642      
    643      
     694 
     695 
    644696class JitterTool(BrushTool): 
    645697    cursor = Qt.ArrowCursor 
     698 
    646699    def dataTransform(self, attr1, x, rx, attr2, y, ry): 
    647         import random 
    648700        for ex in self.graph.data: 
    649701            x1, y1 = float(ex[attr1]), float(ex[attr2]) 
    650             distsq = (x1 - x)**2 + (y1 - y)**2 
     702            distsq = (x1 - x) ** 2 + (y1 - y) ** 2 
    651703            dist = math.sqrt(distsq) 
    652704            attraction = self.density / 100.0 
    653705            advance = 0.005 
    654             dx = -(x1 - x)/dist * attraction / max(distsq, rx) * advance 
    655             dy = -(y1 - y)/dist * attraction / max(distsq, ry) * advance 
     706            dx = -(x1 - x) / dist * attraction / max(distsq, rx) * advance 
     707            dy = -(y1 - y) / dist * attraction / max(distsq, ry) * advance 
    656708            ex[attr1] = x1 - random.normalvariate(0, dx)    # *self.density) 
    657709            ex[attr2] = y1 - random.normalvariate(0, dy)    # *self.density) 
    658710        self.graph.updateGraph() 
    659          
    660          
     711 
     712 
    661713class EnumVariableModel(PyListModel): 
    662714    def __init__(self, var, parent=None, **kwargs): 
     
    664716        self.wrap(var.values) 
    665717        self.colorPalette = OWColorPalette.ColorPaletteHSV(len(self)) 
    666         self.connect(self, SIGNAL("columnsInserted(QModelIndex, int, int)"), self.updateColors) 
    667         self.connect(self, SIGNAL("columnsRemoved(QModelIndex, int, int)"), self.updateColors) 
    668718 
    669719    def __delitem__(self, index): 
    670         raise TypeErorr("Cannot delete EnumVariable value") 
    671      
     720        raise TypeError("Cannot delete EnumVariable value") 
     721 
    672722    def __delslice__(self, i, j): 
    673         raise TypeErorr("Cannot delete EnumVariable values") 
    674      
     723        raise TypeError("Cannot delete EnumVariable values") 
     724 
    675725    def __setitem__(self, index, item): 
    676726        self._list[index] = str(item) 
    677          
     727 
    678728    def data(self, index, role=Qt.DisplayRole): 
    679729        if role == Qt.DecorationRole: 
     
    682732        else: 
    683733            return PyListModel.data(self, index, role) 
    684          
    685     def updateColors(self, index, start, end): 
    686         self.colorPalette = OWColorPalette.ColorPaletteHSV(len(self)) 
    687         self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.index(0), self.index(len(self) - 1)) 
    688          
     734 
    689735    def itemQIcon(self, i): 
    690736        pixmap = QPixmap(64, 64) 
     
    696742        painter.end() 
    697743        return QIcon(pixmap) 
    698     
    699     
     744 
     745 
    700746class OWPaintData(OWWidget): 
    701     TOOLS = [("Brush", "Create multiple instances", BrushTool,  icon_brush), 
     747    TOOLS = [("Brush", "Create multiple instances", BrushTool, icon_brush), 
    702748             ("Put", "Put individual instances", PutInstanceTool, icon_put), 
    703749             ("Select", "Select and move instances", SelectTool, icon_select), 
     
    705751             ("Jitter", "Jitter instances", JitterTool, icon_jitter), 
    706752             ("Magnet", "Move (drag) multiple instances", MagnetTool, icon_magnet), 
    707              ("Zoom", "Zoom", ZoomTool, OWToolbars.dlg_zoom) #"GenerateDataZoomTool.png") 
     753             ("Zoom", "Zoom", ZoomTool, OWToolbars.dlg_zoom) 
    708754             ] 
    709755    settingsList = ["commitOnChange"] 
     756 
    710757    def __init__(self, parent=None, signalManager=None, name="Data Generator"): 
    711758        OWWidget.__init__(self, parent, signalManager, name) 
    712          
     759 
    713760        self.outputs = [("Data", ExampleTable)] 
    714          
     761 
    715762        self.addClassAsMeta = False 
    716763        self.attributes = [] 
    717764        self.cov = [] 
    718765        self.commitOnChange = False 
    719          
     766 
    720767        self.loadSettings() 
    721          
    722         self.variablesModel = VariableListModel([orange.FloatVariable(name) for name in ["X", "Y"]], self, 
    723                                                 flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) 
    724  
    725         self.classVariable = orange.EnumVariable("Class label", values=["Class 1", "Class 2"], baseValue=0) 
     768 
     769        self.variablesModel = VariableListModel( 
     770            [Orange.feature.Continuous(name) for name in ["X", "Y"]], self, 
     771            flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable 
     772        ) 
     773 
     774        self.classVariable = Orange.feature.Discrete( 
     775            "Class label", values=["Class 1", "Class 2"], baseValue=0 
     776        ) 
    726777 
    727778        w = OWGUI.widgetBox(self.controlArea, "Class Label") 
    728          
    729         self.classValuesView = listView = QListView() 
    730         listView.setSelectionMode(QListView.SingleSelection) 
    731          
    732         self.classValuesModel = EnumVariableModel(self.classVariable, self, 
    733                                                   flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled| Qt.ItemIsEditable) 
     779        w.layout().setSpacing(1) 
     780 
     781        self.classValuesView = listView = QListView( 
     782            selectionMode=QListView.SingleSelection, 
     783            sizePolicy=QSizePolicy(QSizePolicy.Ignored, 
     784                                   QSizePolicy.Maximum) 
     785        ) 
     786 
     787        self.classValuesModel = EnumVariableModel( 
     788            self.classVariable, self, 
     789            flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable 
     790        ) 
    734791        self.classValuesModel.wrap(self.classVariable.values) 
    735          
     792 
    736793        listView.setModel(self.classValuesModel) 
    737         listView.selectionModel().select(self.classValuesModel.index(0), QItemSelectionModel.ClearAndSelect) 
    738         self.connect(listView.selectionModel(), 
    739                      SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), 
    740                      self.onClassLabelSelection) 
    741         listView.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum) 
     794        listView.selectionModel().select(self.classValuesModel.index(0), 
     795                                         QItemSelectionModel.ClearAndSelect) 
     796        listView.selectionModel().selectionChanged.connect( 
     797            self.onClassLabelSelection 
     798        ) 
    742799        w.layout().addWidget(listView) 
    743          
    744         self.addClassLabel = addClassLabel = QAction("+", self) 
    745         addClassLabel.pyqtConfigure(toolTip="Add class label")#, icon=QIcon(icon_put)) 
    746         self.connect(addClassLabel, SIGNAL("triggered()"), self.addNewClassLabel) 
    747          
    748         self.removeClassLabel = removeClassLabel = QAction( 
    749             unicodedata.lookup("MINUS SIGN"), self) 
    750         removeClassLabel.pyqtConfigure(toolTip="Remove class label")#, icon=QIcon(icon_remove)) 
    751         self.connect(removeClassLabel, SIGNAL("triggered()"), self.removeSelectedClassLabel) 
    752          
    753         actionsWidget =  ModelActionsWidget([addClassLabel, removeClassLabel], self) 
     800 
     801        self.addClassLabel = QAction( 
     802            "+", self, toolTip="Add class label" 
     803        ) 
     804        self.addClassLabel.triggered.connect(self.addNewClassLabel) 
     805 
     806        self.removeClassLabel = QAction( 
     807            unicodedata.lookup("MINUS SIGN"), self, 
     808            toolTip="Remove selected class label" 
     809        ) 
     810        self.removeClassLabel.triggered.connect(self.removeSelectedClassLabel) 
     811 
     812        actionsWidget = ModelActionsWidget( 
     813            [self.addClassLabel, self.removeClassLabel], self 
     814        ) 
    754815        actionsWidget.layout().addStretch(10) 
    755816        actionsWidget.layout().setSpacing(1) 
    756          
     817 
    757818        w.layout().addWidget(actionsWidget) 
    758          
    759         toolbox = OWGUI.widgetBox(self.controlArea, "Tools", orientation=QGridLayout()) 
    760         self.toolActions = QActionGroup(self) 
    761         self.toolActions.setExclusive(True) 
     819 
     820        toolbox = OWGUI.widgetBox(self.controlArea, "Tools", 
     821                                  orientation=QGridLayout()) 
     822        self.toolActions = QActionGroup(self, exclusive=True) 
     823 
    762824        for i, (name, tooltip, tool, icon) in enumerate(self.TOOLS): 
    763             action = QAction(name, self) 
    764             action.setToolTip(tooltip) 
    765             action.setCheckable(True) 
     825            action = QAction(name, self, toolTip=tooltip, checkable=True) 
    766826            if os.path.exists(icon): 
    767827                action.setIcon(QIcon(icon)) 
    768             self.connect(action, SIGNAL("triggered()"), lambda tool=tool: self.onToolAction(tool)) 
    769             button = QToolButton() 
     828 
     829            action.triggered[()].connect( 
     830                lambda tool=tool: self.onToolAction(tool) 
     831            ) 
     832 
     833            button = QToolButton( 
     834                iconSize=QSize(24, 24), 
     835                toolButtonStyle=Qt.ToolButtonTextUnderIcon, 
     836                sizePolicy=QSizePolicy(QSizePolicy.MinimumExpanding, 
     837                                       QSizePolicy.Fixed) 
     838            ) 
    770839            button.setDefaultAction(action) 
    771             button.setIconSize(QSize(24, 24)) 
    772             button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) 
    773             button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) 
    774840            toolbox.layout().addWidget(button, i / 3, i % 3) 
    775841            self.toolActions.addAction(action) 
    776              
     842 
     843        # TODO: Columns should have uniform widths 
    777844        for column in range(3): 
    778845            toolbox.layout().setColumnMinimumWidth(column, 10) 
    779846            toolbox.layout().setColumnStretch(column, 1) 
    780              
     847 
    781848        self.optionsLayout = QStackedLayout() 
    782849        self.toolsStackCache = {} 
    783         optionsbox = OWGUI.widgetBox(self.controlArea, "Options", orientation=self.optionsLayout) 
    784  
     850        OWGUI.widgetBox(self.controlArea, "Options", 
     851                        orientation=self.optionsLayout) 
    785852 
    786853        ur = OWGUI.widgetBox(self.controlArea, "") 
    787         undo = QAction("Undo", self) 
    788         undo.pyqtConfigure(toolTip="Undo action") 
    789         undo.setShortcut("Ctrl+Z") 
    790         self.connect(undo, SIGNAL("triggered()"), self.undoAction) 
    791  
    792         redo = QAction("Redo", self) 
    793         redo.pyqtConfigure(toolTip="Redo action") 
    794         redo.setShortcut("Ctrl+Shift+Z") 
    795         self.connect(redo, SIGNAL("triggered()"), self.redoAction) 
    796  
    797         actionsWidget =  ModelActionsWidget([undo, redo], self) 
     854        undo = QAction("Undo", self, toolTip="Undo action", 
     855                       shortcut=QKeySequence.Undo) 
     856        undo.triggered.connect(self.undo) 
     857 
     858        redo = QAction("Redo", self, toolTip="Redo action", 
     859                       shortcut=QKeySequence.Redo) 
     860        redo.triggered.connect(self.redo) 
     861 
     862        actionsWidget = ModelActionsWidget([undo, redo], self) 
    798863        actionsWidget.layout().addStretch(10) 
    799864        actionsWidget.layout().setSpacing(1) 
     
    803868        OWGUI.rubber(self.controlArea) 
    804869        box = OWGUI.widgetBox(self.controlArea, "Commit") 
    805          
     870 
    806871        cb = OWGUI.checkBox(box, self, "commitOnChange", "Commit on change", 
    807872                            tooltip="Send the data on any change.", 
    808873                            callback=self.commitIf,) 
    809         b = OWGUI.button(box, self, "Commit",  
     874        b = OWGUI.button(box, self, "Commit", 
    810875                         callback=self.commit, default=True) 
    811876        OWGUI.setStopper(self, b, cb, "dataChangedFlag", callback=self.commit) 
    812          
     877 
    813878        self.graph = PaintDataGraph(self) 
    814879        self.graph.setAxisScale(QwtPlot.xBottom, 0.0, 1.0) 
     
    819884        self.currentOptionsWidget = None 
    820885        self.data = [] 
    821         self.dataChangedFlag = False  
     886        self.dataChangedFlag = False 
    822887        self.domain = None 
    823          
     888 
    824889        self.onDomainChanged() 
    825890        self.toolActions.actions()[0].trigger() 
    826891 
    827         self.dataHistory = [(orange.ExampleTable(self.domain), ["Class 1", "Class 2"])] 
     892        self.dataHistory = [(Orange.data.Table(self.domain), 
     893                             ["Class 1", "Class 2"])] 
    828894        self.historyCounter = 0 
    829895        self.updateHistoryBool = True 
    830          
     896 
    831897        self.resize(800, 600) 
    832898 
    833899    def addNewClassLabel(self): 
    834         i = 1 
    835         while True: 
    836             newlabel = "Class %i" % i 
    837             if newlabel not in self.classValuesModel: 
    838 #                self.classValuesModel.append(newlabel) 
    839                 break 
    840             i += 1 
     900        """ 
     901        Create and add a new class label 
     902        """ 
     903        labels = ("Class %i" % i for i in itertools.count(1)) 
     904        newlabel = next(label for label in labels 
     905                        if not label in self.classValuesModel) 
     906 
    841907        values = list(self.classValuesModel) + [newlabel] 
    842         newclass = orange.EnumVariable("Class label", values=values) 
    843         newdomain = orange.Domain(self.graph.data.domain.attributes, newclass) 
    844         newdata = orange.ExampleTable(newdomain) 
    845         for ex in self.graph.data: 
    846             newdata.append(orange.Example(newdomain, [ex[a] for a in ex.domain.attributes] + [str(ex.getclass())])) 
    847          
     908        newclass = Orange.feature.Discrete("Class label", values=values) 
     909        newdomain = Orange.data.Domain(self.graph.data.domain.attributes, 
     910                                       newclass) 
     911        newdata = Orange.data.Table(newdomain) 
     912 
     913        newdata.extend( 
     914            [Orange.data.Instance( 
     915                newdomain, [ex[a] for a in ex.domain.attributes] + 
     916                           [str(ex.getclass())]) 
     917             for ex in self.graph.data] 
     918        ) 
    848919        self.classVariable = newclass 
    849920        self.classValuesModel.wrap(self.classVariable.values) 
    850          
     921 
    851922        self.graph.data = newdata 
    852923        self.graph.updateGraph() 
    853          
     924 
    854925        newindex = self.classValuesModel.index(len(self.classValuesModel) - 1) 
    855         self.classValuesView.selectionModel().select(newindex, QItemSelectionModel.ClearAndSelect) 
    856          
     926        self.classValuesView.selectionModel().select( 
     927            newindex, QItemSelectionModel.ClearAndSelect 
     928        ) 
     929 
    857930        self.removeClassLabel.setEnabled(len(self.classValuesModel) > 1) 
    858931 
    859932        self.updateHistory() 
    860          
     933 
    861934    def removeSelectedClassLabel(self, label=None): 
    862935        index = self.selectedClassLabelIndex() 
     
    864937            if not label: 
    865938                label = self.classValuesModel[index] 
    866             examples = [ex for ex in self.graph.data if str(ex.getclass()) != label] 
    867              
     939            examples = [ex for ex in self.graph.data 
     940                        if str(ex.getclass()) != label] 
     941 
    868942            values = [val for val in self.classValuesModel if val != label] 
    869943 
    870             newclass = orange.EnumVariable("Class label", values=values) 
    871             newdomain = orange.Domain(self.graph.data.domain.attributes, newclass) 
    872             newdata = orange.ExampleTable(newdomain) 
     944            newclass = Orange.feature.Discrete("Class label", values=values) 
     945            newdomain = Orange.data.Domain(self.graph.data.domain.attributes, 
     946                                           newclass) 
     947            newdata = Orange.data.Table(newdomain) 
    873948            for ex in examples: 
    874                 if ex[self.classVariable] != label and ex[self.classVariable] in values: 
    875                     newdata.append(orange.Example(newdomain, [ex[a] for a in ex.domain.attributes] + 
    876                                                              [str(ex.getclass())])) 
     949                if ex[self.classVariable] != label and \ 
     950                        ex[self.classVariable] in values: 
     951                    values = ([ex[a] for a in ex.domain.attributes] + 
     952                              [str(ex.getclass())]) 
     953                    newdata.append(Orange.data.Instance(newdomain, values)) 
    877954 
    878955            self.classVariable = newclass 
    879956            self.classValuesModel.wrap(self.classVariable.values) 
    880              
     957 
    881958            self.graph.data = newdata 
    882959            self.graph.updateGraph() 
    883              
     960 
    884961            newindex = self.classValuesModel.index(max(0, index - 1)) 
    885             self.classValuesView.selectionModel().select(newindex, QItemSelectionModel.ClearAndSelect) 
    886              
     962            self.classValuesView.selectionModel().select( 
     963                newindex, QItemSelectionModel.ClearAndSelect 
     964            ) 
     965 
    887966            self.removeClassLabel.setEnabled(len(self.classValuesModel) > 1) 
    888967 
    889968            self.updateHistory() 
    890          
     969 
    891970    def selectedClassLabelIndex(self): 
    892         rows = [i.row() for i in self.classValuesView.selectionModel().selectedRows()] 
     971        rows = self.classValuesView.selectionModel().selectedRows() 
    893972        if rows: 
    894             return rows[0] 
     973            return rows[0].row() 
    895974        else: 
    896975            return None 
    897          
     976 
    898977    def onClassLabelSelection(self, selected, unselected): 
    899978        index = self.selectedClassLabelIndex() 
    900979        if index is not None: 
    901980            self.classVariable.baseValue = index 
    902      
     981 
    903982    def onToolAction(self, tool): 
    904983        self.setCurrentTool(tool) 
    905          
     984 
    906985    def setCurrentTool(self, tool): 
    907986        if tool not in self.toolsStackCache: 
     
    909988            option = newtool.optionsWidget(newtool, self) 
    910989            self.optionsLayout.addWidget(option) 
    911 #            self.connect(newtool, SIGNAL("dataChanged()"), self.graph.updateGraph) 
    912 #            self.connect(newtool, SIGNAL("dataChanged()"), self.onDataChanged) 
    913             self.connect(newtool, SIGNAL("editing()"), self.onDataChanged) 
    914             self.connect(newtool, SIGNAL("editingFinished()"), self.commitIf) 
    915             self.connect(newtool, SIGNAL("editingFinished()"), self.updateHistory) 
     990            newtool.editing.connect(self.onDataChanged) 
     991            newtool.editingFinished.connect(self.commitIf) 
     992            newtool.editingFinished.connect(self.updateHistory) 
     993 
    916994            self.toolsStackCache[tool] = (newtool, option) 
    917          
    918         self.currentTool, self.currentOptionsWidget = tool, option = self.toolsStackCache[tool] 
    919         self.optionsLayout.setCurrentWidget(option) 
     995 
     996        self.currentTool, self.currentOptionsWidget = self.toolsStackCache[tool] 
     997        self.optionsLayout.setCurrentWidget(self.currentOptionsWidget) 
    920998        self.currentTool.setGraph(self.graph) 
    921999 
     
    9241002            return 
    9251003        # if we start updating from previously undone actions, we cut off redos in our history 
    926         if not self.historyCounter == len(self.dataHistory)-1: 
    927             self.dataHistory = self.dataHistory[:self.historyCounter+1] 
     1004        if not self.historyCounter == len(self.dataHistory) - 1: 
     1005            self.dataHistory = self.dataHistory[:self.historyCounter + 1] 
    9281006        # append an update of labels and data 
    9291007        labels = list(self.classValuesModel) 
     
    9351013        self.historyCounter += 1 
    9361014 
    937     def undoAction(self): 
     1015    def undo(self): 
    9381016        # check to see if we are at the end of the stack 
    9391017        if self.historyCounter > 0: 
     
    9541032            self.updateHistoryBool = True 
    9551033 
    956     def redoAction(self): 
    957         if self.historyCounter < len(self.dataHistory)-1: 
     1034    def redo(self): 
     1035        if self.historyCounter < len(self.dataHistory) - 1: 
    9581036            self.historyCounter += 1 
    9591037            data, labels = self.dataHistory[self.historyCounter] 
     
    9711049    def onDomainChanged(self, *args): 
    9721050        if self.variablesModel: 
    973             self.domain = orange.Domain(list(self.variablesModel), self.classVariable) 
     1051            self.domain = Orange.data.Domain(list(self.variablesModel), 
     1052                                             self.classVariable) 
    9741053            if self.data: 
    975                 self.data = orange.ExampleTable(self.domain, self.data) 
     1054                self.data = Orange.data.Table(self.domain, self.data) 
    9761055            else: 
    977                 self.data = orange.ExampleTable(self.domain) 
     1056                self.data = Orange.data.Table(self.domain) 
    9781057            self.graph.setData(self.data, 0, 1) 
    979              
     1058 
    9801059    def onDataChanged(self): 
    9811060        self.dataChangedFlag = True 
    9821061 
    9831062    def keyPressEvent(self, event): 
    984         if event.key() == QtCore.Qt.Key_Delete and isinstance(self.currentTool, SelectTool): 
     1063        if event.key() == QtCore.Qt.Key_Delete and \ 
     1064                isinstance(self.currentTool, SelectTool): 
    9851065            self.currentTool.deleteSelected() 
    986      
     1066 
    9871067    def commitIf(self): 
    9881068        if self.commitOnChange and self.dataChangedFlag: 
     
    9901070        else: 
    9911071            self.dataChangedFlag = True 
    992              
     1072 
    9931073    def commit(self): 
    9941074        data = self.graph.data 
     
    9961076        if len(values) == 1: 
    9971077            # Remove the useless class variable. 
    998             domain = orange.Domain(data.domain.attributes, None) 
    999             data = orange.ExampleTable(domain, data) 
     1078            domain = Orange.data.Domain(data.domain.attributes, None) 
     1079            data = Orange.data.Table(domain, data) 
    10001080        self.send("Data", data) 
     1081 
    10011082 
    10021083if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.