source: orange/Orange/OrangeCanvas/preview/previewbrowser.py @ 11139:3cab9e06f6e5

Revision 11139:3cab9e06f6e5, 7.2 KB checked in by Ales Erjavec <ales.erjavec@…>, 18 months ago (diff)

Fixes for unicode support.

Line 
1"""
2Preview Browser Widget.
3
4"""
5
6from PyQt4.QtGui import (
7    QWidget, QLabel, QListView, QAction, QVBoxLayout, QHBoxLayout, QSizePolicy
8)
9
10from PyQt4.QtSvg import QSvgWidget
11
12from PyQt4.QtCore import (
13    Qt, QSize, QByteArray, QModelIndex
14)
15
16from PyQt4.QtCore import pyqtSignal as Signal
17
18from ..gui.dropshadow import DropShadowFrame
19from . import previewmodel
20
21
22NO_PREVIEW_SVG = """
23
24"""
25
26
27# Default description template
28DESCRIPTION_TEMPLATE = u"""
29<h3 class=item-heading>{name}</h3>
30<p class=item-description>
31{description}
32</p>
33
34"""
35
36PREVIEW_SIZE = (440, 295)
37
38
39class LinearIconView(QListView):
40    def __init__(self, *args, **kwargs):
41        QListView.__init__(self, *args, **kwargs)
42
43        self.setViewMode(QListView.IconMode)
44        self.setWrapping(False)
45        self.setSelectionMode(QListView.SingleSelection)
46        self.setEditTriggers(QListView.NoEditTriggers)
47        self.setMovement(QListView.Static)
48        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
49        self.setSizePolicy(QSizePolicy.Expanding,
50                           QSizePolicy.Fixed)
51
52        self.setIconSize(QSize(120, 80))
53
54    def sizeHint(self):
55        if not self.model().rowCount():
56            return QSize(200, 140)
57        else:
58            scrollHint = self.horizontalScrollBar().sizeHint()
59            height = self.sizeHintForRow(0) + scrollHint.height()
60            _, top, _, bottom = self.getContentsMargins()
61            return QSize(200, height + top + bottom + self.verticalOffset())
62
63
64class PreviewBrowser(QWidget):
65    """A Preview Browser for recent/premade scheme selection.
66    """
67    # Emitted when the current previewed item changes
68    currentIndexChanged = Signal(int)
69
70    def __init__(self, *args):
71        QWidget.__init__(self, *args)
72        self.__model = None
73        self.__currentIndex = -1
74        self.__template = DESCRIPTION_TEMPLATE
75        self.__setupUi()
76
77    def __setupUi(self):
78        vlayout = QVBoxLayout()
79        vlayout.setContentsMargins(0, 0, 0, 0)
80        top_layout = QHBoxLayout()
81        top_layout.setContentsMargins(12, 12, 12, 12)
82
83        # Top row with full text description and a large preview
84        # image.
85        self.__label = QLabel(self, objectName="description-label",
86                              wordWrap=True,
87                              alignment=Qt.AlignTop | Qt.AlignLeft)
88
89        self.__label.setWordWrap(True)
90        self.__label.setFixedSize(220, PREVIEW_SIZE[1])
91
92        self.__image = QSvgWidget(self, objectName="preview-image")
93        self.__image.setFixedSize(*PREVIEW_SIZE)
94
95        self.__imageFrame = DropShadowFrame(self)
96        self.__imageFrame.setWidget(self.__image)
97
98        self.__path = QLabel(self, objectName="path-label")
99        self.__path.setWordWrap(False)
100        self.__path.setContentsMargins(12, 0, 12, 0)
101
102        self.__selectAction = \
103            QAction(self.tr("Select"), self,
104                    objectName="select-action",
105                    )
106
107        top_layout.addWidget(self.__label, 1,
108                             alignment=Qt.AlignTop | Qt.AlignLeft)
109        top_layout.addWidget(self.__image, 1,
110                             alignment=Qt.AlignTop | Qt.AlignRight)
111
112        vlayout.addLayout(top_layout)
113        vlayout.addWidget(self.__path)
114
115        # An list view with small preview icons.
116        self.__previewList = LinearIconView(objectName="preview-list-view")
117
118        vlayout.addWidget(self.__previewList)
119        self.setLayout(vlayout)
120
121    def setModel(self, model):
122        """Set the item model for preview.
123        """
124        if self.__model != model:
125            if self.__model:
126                s_model = self.__previewList.selectionModel()
127                s_model.selectionChanged.disconnect(self.__onSelectionChanged)
128                self.__model.dataChanged.disconnect(self.__onDataChanged)
129
130            self.__model = model
131            self.__previewList.setModel(model)
132
133            if model:
134                s_model = self.__previewList.selectionModel()
135                s_model.selectionChanged.connect(self.__onSelectionChanged)
136                self.__model.dataChanged.connect(self.__onDataChanged)
137
138            if model and model.rowCount():
139                self.setCurrentIndex(0)
140
141    def model(self):
142        """Return the item model.
143        """
144        return self.__model
145
146    def setPreviewDelegate(self, delegate):
147        """Set the delegate to render the preview images.
148        """
149        raise NotImplementedError
150
151    def setDescriptionTemplate(self, template):
152        self.__template = template
153        self.__update()
154
155    def setCurrentIndex(self, index):
156        """Set the selected preview item index.
157        """
158        if self.__model is not None and self.__model.rowCount():
159            index = min(index, self.__model.rowCount() - 1)
160            index = self.__model.index(index, 0)
161            sel_model = self.__previewList.selectionModel()
162            # This emits selectionChanged signal and triggers
163            # __onSelectionChanged, currentIndex is updated there.
164            sel_model.select(index, sel_model.ClearAndSelect)
165
166        elif self.__currentIndex != -1:
167            self.__currentIndex = -1
168            self.__update()
169            self.currentIndexChanged.emit(-1)
170
171    def currentIndex(self):
172        """Return the current selected index.
173        """
174        return self.__currentIndex
175
176    def __onSelectionChanged(self, *args):
177        """Selected item in the preview list has changed.
178        Set the new description and large preview image.
179
180        """
181        rows = self.__previewList.selectedIndexes()
182        if rows:
183            index = rows[0]
184            self.__currentIndex = index.row()
185        else:
186            index = QModelIndex()
187            self.__currentIndex = -1
188
189        self.__update()
190        self.currentIndexChanged.emit(self.__currentIndex)
191
192    def __onDataChanged(self, topleft, bottomRight):
193        """Data changed, update the preview if current index in the changed
194        range.
195
196        """
197        if self.__currentIndex <= topleft.row() and \
198                self.__currentIndex >= bottomRight.row():
199            self.__update()
200
201    def __update(self):
202        """Update the description.
203        """
204        if self.__currentIndex != -1:
205            index = self.model().index(self.__currentIndex, 0)
206        else:
207            index = QModelIndex()
208
209        if not index.isValid():
210            description = ""
211            name = ""
212            path = ""
213            svg = NO_PREVIEW_SVG
214        else:
215            description = unicode(index.data(Qt.WhatsThisRole).toString())
216            if not description:
217                description = "No description."
218
219            name = unicode(index.data(Qt.DisplayRole).toString())
220            if not name:
221                name = "Untitled"
222
223            path = unicode(index.data(Qt.StatusTipRole).toString())
224
225            svg = unicode(index.data(previewmodel.ThumbnailSVGRole).toString())
226
227        desc_text = self.__template.format(description=description, name=name)
228
229        self.__label.setText(desc_text)
230
231        path_text = u"<b>Path:</b><div class=item-path>{0}</div>".format(path)
232        self.__path.setText(path_text)
233
234        if not svg:
235            svg = NO_PREVIEW_SVG
236
237        if svg:
238            self.__image.load(QByteArray(svg))
Note: See TracBrowser for help on using the repository browser.