source: orange/Orange/OrangeCanvas/gui/lineedit.py @ 11366:7f9332b11252

Revision 11366:7f9332b11252, 6.2 KB checked in by Ales Erjavec <ales.erjavec@…>, 14 months ago (diff)

Added rst documentation for the canvas gui package.

Fixing docstrings in the process.

Line 
1"""
2A LineEdit class with a button on left/right side.
3"""
4from collections import namedtuple
5
6from PyQt4.QtGui import (
7    QLineEdit, QToolButton, QStyleOptionToolButton, QStylePainter,
8    QStyle, QPalette, QFontMetrics, QAction
9)
10
11from PyQt4.QtCore import Qt, QSize, QRect, qVersion
12from PyQt4.QtCore import pyqtSignal as Signal, pyqtProperty as Property
13
14
15_ActionSlot = \
16    namedtuple(
17        "_AcitonSlot",
18        ["position",  # Left/Right position
19         "action",    # QAction
20         "button",    # LineEditButton instance
21         "autoHide"]  # Auto hide when line edit is empty.
22        )
23
24
25class LineEditButton(QToolButton):
26    """
27    A button in the :class:`LineEdit`.
28    """
29    def __init__(self, parent=None, flat=True, **kwargs):
30        QToolButton.__init__(self, parent, **kwargs)
31
32        self.__flat = flat
33
34    def setFlat(self, flat):
35        if self.__flat != flat:
36            self.__flat = flat
37            self.update()
38
39    def flat(self):
40        return self.__flat
41
42    flat_ = Property(bool, fget=flat, fset=setFlat,
43                     designable=True)
44
45    def paintEvent(self, event):
46        if self.__flat:
47            opt = QStyleOptionToolButton()
48            self.initStyleOption(opt)
49            p = QStylePainter(self)
50            p.drawControl(QStyle.CE_ToolButtonLabel, opt)
51        else:
52            QToolButton.paintEvent(self, event)
53
54
55class LineEdit(QLineEdit):
56    """
57    A line edit widget with support for adding actions (buttons) to
58    the left/right of the edited text
59
60    """
61    #: Position flags
62    LeftPosition, RightPosition = 1, 2
63
64    #: Emitted when the action is triggered.
65    triggered = Signal(QAction)
66
67    #: The left action was triggered.
68    leftTriggered = Signal()
69
70    #: The right action was triggered.
71    rightTriggered = Signal()
72
73    def __init__(self, parent=None, **kwargs):
74        QLineEdit.__init__(self, parent, **kwargs)
75        self.__actions = [None, None]
76
77    def setAction(self, action, position=LeftPosition):
78        """
79        Set `action` to be displayed at `position`. Existing action
80        (if present) will be removed.
81
82        Parameters
83        ----------
84        action : :class:`QAction`
85        position : int
86            Position where to set the action (default: ``LeftPosition``).
87
88        """
89
90        curr = self.actionAt(position)
91        if curr is not None:
92            self.removeAction(position)
93
94        # Add the action using QWidget.addAction (for shortcuts)
95        QLineEdit.addAction(self, action)
96
97        button = LineEditButton(self)
98        button.setToolButtonStyle(Qt.ToolButtonIconOnly)
99        button.setDefaultAction(action)
100        button.setVisible(self.isVisible())
101        button.show()
102        button.setCursor(Qt.ArrowCursor)
103
104        button.triggered.connect(self.triggered)
105        button.triggered.connect(self.__onTriggered)
106
107        slot = _ActionSlot(position, action, button, False)
108        self.__actions[position - 1] = slot
109        self.__layoutActions()
110
111    def actionAt(self, position):
112        """
113        Return :class:`QAction` at `position`.
114        """
115        self._checkPosition(position)
116        slot = self.__actions[position - 1]
117        if slot:
118            return slot.action
119        else:
120            return None
121
122    def removeActionAt(self, position):
123        """
124        Remove the action at position.
125        """
126        self._checkPosition(position)
127
128        slot = self.__actions[position - 1]
129        self.__actions[position - 1] = None
130
131        slot.button.hide()
132        slot.button.deleteLater()
133        QLineEdit.removeAction(self, slot.action)
134        self.__layoutActions()
135
136    def button(self, position):
137        """
138        Return the button (:class:`LineEditButton`) for the action
139        at `position`.
140
141        """
142        self._checkPosition(position)
143        slot = self.__actions[position - 1]
144        if slot:
145            return slot.button
146        else:
147            return None
148
149    def _checkPosition(self, position):
150        if position not in [self.LeftPosition, self.RightPosition]:
151            raise ValueError("Invalid position")
152
153    def resizeEvent(self, event):
154        QLineEdit.resizeEvent(self, event)
155        self.__layoutActions()
156
157    if qVersion() < "4.7":
158        # Qt 4.6 does not yet have placeholder text
159        def setPlaceholderText(self, text):
160            self.__placeholderText = text
161            self.update()
162
163        def placeholderText(self):
164            try:
165                return self.__placeholderText
166            except AttributeError:
167                return ""
168
169        def paintEvent(self, event):
170            QLineEdit.paintEvent(self, event)
171            if not self.text() and self.placeholderText() and \
172                    not self.hasFocus():
173                p = QStylePainter(self)
174                font = self.font()
175                metrics = QFontMetrics(font)
176                p.setFont(font)
177                color = self.palette().color(QPalette.Mid)
178                p.setPen(color)
179                left, top, right, bottom = self.getTextMargins()
180                contents = self.contentsRect()
181                contents = contents.adjusted(left, top, -right, -bottom)
182                text = metrics.elidedText(self.placeholderText(),
183                                          Qt.ElideMiddle,
184                                          contents.width())
185                p.drawText(contents, Qt.AlignLeft | Qt.AlignVCenter, text)
186
187    def __layoutActions(self):
188        left, right = self.__actions
189
190        contents = self.contentsRect()
191        buttonSize = QSize(contents.height(), contents.height())
192
193        margins = self.textMargins()
194
195        if left:
196            geom = QRect(contents.topLeft(), buttonSize)
197            left.button.setGeometry(geom)
198            margins.setLeft(buttonSize.width())
199
200        if right:
201            geom = QRect(contents.topRight(), buttonSize)
202            right.button.setGeometry(geom.translated(-buttonSize.width(), 0))
203            margins.setLeft(buttonSize.width())
204
205        self.setTextMargins(margins)
206
207    def __onTriggered(self, action):
208        left, right = self.__actions
209        if left and action == left.action:
210            self.leftTriggered.emit()
211        elif right and action == right.action:
212            self.rightTriggered.emit()
Note: See TracBrowser for help on using the repository browser.