source: orange/orange/OrangeWidgets/OWWidget.py @ 8849:5be9d5bacce7

Revision 8849:5be9d5bacce7, 12.8 KB checked in by ales_erjavec <ales.erjavec@…>, 3 years ago (diff)

Added a widget box to show errors, warnings (fixes #659).

Line 
1#
2# OWWidget.py
3# Orange Widget
4# A General Orange Widget, from which all the Orange Widgets are derived
5#
6
7from OWBaseWidget import *
8
9class OWWidget(OWBaseWidget):
10    def __init__(self, parent=None, signalManager=None, title="Orange Widget", wantGraph=False, wantStatusBar=False, savePosition=True, wantMainArea=1, noReport=False, showSaveGraph=1, resizingEnabled=1, wantStateInfoWidget=None, **args):
11        """
12        Initialization
13        Parameters:
14            title - The title of the\ widget, including a "&" (for shortcut in about box)
15            wantGraph - displays a save graph button or not
16        """
17
18        OWBaseWidget.__init__(self, parent, signalManager, title, savePosition=savePosition, resizingEnabled=resizingEnabled, **args)
19
20        self.setLayout(QVBoxLayout())
21        self.layout().setMargin(2)
22
23        self.topWidgetPart = OWGUI.widgetBox(self, orientation="horizontal", margin=0)
24        self.leftWidgetPart = OWGUI.widgetBox(self.topWidgetPart, orientation="vertical", margin=0)
25        if wantMainArea:
26            self.leftWidgetPart.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding))
27            self.leftWidgetPart.updateGeometry()
28            self.mainArea = OWGUI.widgetBox(self.topWidgetPart, orientation="vertical", sizePolicy=QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding), margin=0)
29            self.mainArea.layout().setMargin(4)
30            self.mainArea.updateGeometry()
31           
32        self.controlArea = OWGUI.widgetBox(self.leftWidgetPart, orientation="vertical", margin=4)# if wantMainArea else 1)
33
34        self.space = self.controlArea
35
36        self.buttonBackground = OWGUI.widgetBox(self.leftWidgetPart, orientation="horizontal", margin=4)# if wantMainArea else 1)
37        self.buttonBackground.hide()
38       
39        if wantGraph and showSaveGraph:
40            self.buttonBackground.show()
41            self.graphButton = OWGUI.button(self.buttonBackground, self, "&Save Graph")
42            self.graphButton.setAutoDefault(0)
43           
44        if wantStateInfoWidget is None:
45            wantStateInfoWidget = self._owShowStatus
46           
47        if wantStateInfoWidget:
48            # Widget for error, warnings, info.
49            self.widgetStateInfoBox = OWGUI.widgetBox(self.leftWidgetPart, "Widget state")
50            self.widgetStateInfo = OWGUI.widgetLabel(self.widgetStateInfoBox, "\n")
51            self.widgetStateInfo.setWordWrap(True)
52            self.widgetStateInfo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
53            self.widgetStateInfo.setFixedHeight(self.widgetStateInfo.height())
54            self.widgetStateInfoBox.hide()
55            def updateWidgetStateInfo(stateType, id, text):
56                html = self.widgetStateToHtml(self._owInfo, self._owWarning, self._owError)
57                if html:
58                    self.widgetStateInfoBox.show()
59                    self.widgetStateInfo.setText(html)
60                    self.widgetStateInfo.setToolTip(html)
61                else:
62                    if not self.widgetStateInfoBox.isVisible():
63                        dHeight = - self.widgetStateInfoBox.height()
64                    else:
65                        dHeight = 0
66                    self.widgetStateInfoBox.hide()
67                    self.widgetStateInfo.setText("")
68                    self.widgetStateInfo.setToolTip("")
69                    width, height = self.width(), self.height() + dHeight
70                    QTimer.singleShot(50, lambda :self.resize(width, height))
71                   
72            self.connect(self, SIGNAL("widgetStateChanged(QString, int, QString)"), updateWidgetStateInfo)
73       
74
75        self.__reportData = None
76        if OWReport.report and not noReport and hasattr(self, "sendReport"):
77            self.buttonBackground.show()
78            self.reportButton = OWGUI.button(self.buttonBackground, self, "&Report", self.reportAndFinish, debuggingEnabled=0)
79            self.reportButton.setAutoDefault(0)
80
81        if wantStatusBar:
82            #self.widgetStatusArea = OWGUI.widgetBox(self, orientation = "horizontal", margin = 2)
83            self.widgetStatusArea = QFrame(self) 
84            self.statusBarIconArea = QFrame(self)
85            self.widgetStatusBar = QStatusBar(self) 
86           
87            self.layout().addWidget(self.widgetStatusArea)
88           
89            self.widgetStatusArea.setLayout(QHBoxLayout(self.widgetStatusArea))
90            self.widgetStatusArea.layout().addWidget(self.statusBarIconArea)
91            self.widgetStatusArea.layout().addWidget(self.widgetStatusBar)
92            self.widgetStatusArea.layout().setMargin(0)
93            self.widgetStatusArea.setFrameShape(QFrame.StyledPanel)
94                       
95            self.statusBarIconArea.setLayout(QHBoxLayout())
96            self.widgetStatusBar.setSizeGripEnabled(0) 
97            #self.statusBarIconArea.setFrameStyle (QFrame.Panel + QFrame.Sunken)
98            #self.widgetStatusBar.setFrameStyle (QFrame.Panel + QFrame.Sunken)
99            #self.widgetStatusBar.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
100            #self.widgetStatusBar.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred))
101            #self.widgetStatusBar.updateGeometry()
102            #self.statusBarIconArea.setFixedSize(16*2,18)
103            self.statusBarIconArea.hide()
104           
105
106            # create pixmaps used in statusbar to show info, warning and error messages
107            #self._infoWidget, self._infoPixmap = self.createPixmapWidget(self.statusBarIconArea, os.path.join(self.widgetDir + "icons/triangle-blue.png"))
108            self._warningWidget = self.createPixmapWidget(self.statusBarIconArea, os.path.join(self.widgetDir + "icons/triangle-orange.png"))
109            self._errorWidget = self.createPixmapWidget(self.statusBarIconArea, os.path.join(self.widgetDir + "icons/triangle-red.png"))
110       
111       
112
113    # status bar handler functions
114    def createPixmapWidget(self, parent, iconName):
115        w = QLabel(parent)
116        parent.layout().addWidget(w)
117        w.setFixedSize(16, 16)
118        w.hide()
119        if os.path.exists(iconName):
120            w.setPixmap(QPixmap(iconName))
121        return w
122
123    def setState(self, stateType, id, text):
124        stateChanged = OWBaseWidget.setState(self, stateType, id, text)
125        if not stateChanged or not hasattr(self, "widgetStatusArea"):
126            return
127
128        iconsShown = 0
129        #for state, widget, icon, use in [("Info", self._infoWidget, self._owInfo), ("Warning", self._warningWidget, self._owWarning), ("Error", self._errorWidget, self._owError)]:
130        for state, widget, use in [("Warning", self._warningWidget, self._owWarning), ("Error", self._errorWidget, self._owError)]:
131            if not widget: continue
132            if use and self.widgetState[state] != {}:
133                widget.setToolTip("\n".join(self.widgetState[state].values()))
134                widget.show()
135                iconsShown = 1
136            else:
137                widget.setToolTip("")
138                widget.hide()
139
140        if iconsShown:
141            self.statusBarIconArea.show()
142        else:
143            self.statusBarIconArea.hide()
144
145        #if (stateType == "Info" and self._owInfo) or (stateType == "Warning" and self._owWarning) or (stateType == "Error" and self._owError):
146        if (stateType == "Warning" and self._owWarning) or (stateType == "Error" and self._owError):
147            if text:
148                self.setStatusBarText(stateType + ": " + text)
149            else:
150                self.setStatusBarText("")
151        self.updateStatusBarState()
152        #qApp.processEvents()
153
154    def updateStatusBarState(self):
155        if not hasattr(self, "widgetStatusArea"):
156            return
157        if self._owShowStatus and (self.widgetState["Warning"] != {} or self.widgetState["Error"] != {}):
158            self.widgetStatusArea.show()
159        else:
160            self.widgetStatusArea.hide()
161
162    def setStatusBarText(self, text, timeout=5000):
163        if hasattr(self, "widgetStatusBar"):
164            self.widgetStatusBar.showMessage(" " + text, timeout)
165
166    def reportAndFinish(self):
167        self.sendReport()
168        self.finishReport()
169       
170    def startReport(self, name=None, needDirectory=False):
171        if self.__reportData is not None:
172            print "Cannot open a new report when an old report is still active"
173            return False
174        self.reportName = name or self.windowTitle()
175        self.__reportData = ""
176        if needDirectory:
177            return OWReport.report.createDirectory()
178        else:
179            return True
180
181    def reportSection(self, title):
182        if self.__reportData is None:
183            self.startReport()
184        self.__reportData += "\n\n<h2>%s</h2>\n\n" % title
185
186    def reportSubsection(self, title):
187        if self.__reportData is None:
188            self.startReport()
189        self.__reportData += "\n\n  <h3>%s</h3>\n\n" % title
190
191    def reportList(self, items):
192        if self.__reportData is None:
193            self.startReport()
194        self.startReportList()
195        for item in items:
196            self.addToReportList(item)
197        self.finishReportList()
198
199    def getUniqueFileName(self, patt):
200        return OWReport.report.getUniqueFileName(patt)
201
202    def getUniqueImageName(self, nm="img", ext=".png"):
203        return OWReport.report.getUniqueFileName(nm + "%06i" + ext)
204
205    def reportImage(self, filenameOrFunc, *args):
206        if self.__reportData is None:
207            self.startReport()
208           
209        if type(filenameOrFunc) in [str, unicode]:
210            self.__reportData += '    <IMG src="%s"/>\n' % filenameOrFunc
211        else:
212            sfn, ffn = self.getUniqueImageName()
213            filenameOrFunc(ffn, *args)
214            self.reportImage(sfn)
215
216    svg_type = "image/svg+xml"
217    def reportObject(self, type, data, **attrs):
218        if self.__reportData is None:
219            self.startReport()
220        self.__reportData += '<object type="%s" data="%s" %s></object>' % (type, data, " ".join('%s="%s"' % attr for attr in attrs.items()))
221
222    def startReportList(self):
223        if self.__reportData is None:
224            self.startReport()
225        self.__reportData += "    <UL>\n"
226
227    def addToReportList(self, item):
228        self.__reportData += "      <LI>%s</LI>\n" % item
229
230    def finishReportList(self):
231        self.__reportData += "    </UL>\n"
232
233    def reportSettings(self, sectionName="", settingsList=None, closeList=True):
234        if sectionName:
235            self.reportSection(sectionName)
236        elif self.__reportData is None:
237            self.startReport()
238        self.__reportData += "    <ul>%s</ul>\n" % "".join("<b>%s: </b>%s<br/>" % item for item in settingsList if item) 
239
240    def reportRaw(self, text):
241        if self.__reportData is None:
242            self.startReport()
243        self.__reportData += text
244
245    def prepareDataReport(self, data, listAttributes=True, exampleCount=True):
246        if data:
247            res = []
248            if exampleCount:
249                res.append(("Examples", str(len(data))))
250            if listAttributes:
251                if data.domain.attributes:
252                    res.append(("Attributes", "%i %s" % ( 
253                                len(data.domain.attributes), 
254                                 "(%s%s)" % (", ".join(x.name for foo, x in zip(xrange(30), data.domain.attributes)), "..." if len(data.domain.attributes) > 30 else "")
255                              )))
256                else:
257                    res.append(("Attributes", "0"))
258                metas = data.domain.getmetas()
259                if metas:
260                  if len(metas) <= 100:
261                      res.append(("Meta attributes", "%i (%s)" % (len(metas), ", ".join(x.name for x in metas.values()))))
262                  else:
263                      res.append(("Meta attributes", str(len(metas))))
264                res.append(("Class", data.domain.classVar.name if data.domain.classVar else "<none>"))
265            return res
266           
267    def reportData(self, settings, sectionName="Data", ifNone="None", listAttributes = True, exampleCount=True):
268        haveSettings = False
269        try:
270            haveSettings = isinstance(settings, list) and len(settings[0])==2
271        except:
272            pass
273        if not haveSettings:
274            settings = self.prepareDataReport(settings, listAttributes, exampleCount)
275        if not self.__reportData:
276            self.startReport()
277        if sectionName is not None:
278            self.reportSection(sectionName)
279        if settings:
280            self.reportSettings("", settings)
281        elif ifNone is not None:
282            self.reportRaw(ifNone)
283       
284
285       
286    def finishReport(self):
287        if self.__reportData is not None:
288            OWReport.report(self.reportName, self.__reportData or "", self.widgetId, self.windowIcon())#, self.getSettings(False))
289            self.__reportData = None
290
291import OWReport
292
293if __name__ == "__main__":
294    a = QApplication(sys.argv)
295    ow = OWWidget()
296    ow.show()
297    a.exec_()
Note: See TracBrowser for help on using the repository browser.