source: sasview/src/sas/guiframe/gui_statusbar.py @ fa6a8d1

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since fa6a8d1 was b3efb7d, checked in by krzywon, 10 years ago

Modified data loading error messages to be much more specific and
include information in the console log about the specific errors
generated.

The cansas reader is now loading non-standard units (ie counts), but
shows a specific error message about the issue.

  • Property mode set to 100644
File size: 14.3 KB
Line 
1import wx
2import sys
3from wx import StatusBar as wxStatusB
4from wx.lib import newevent
5import wx.richtext
6from sas.guiframe.gui_style import GUIFRAME_ICON
7
8# Number of fields on the status bar
9NB_FIELDS = 4
10#position of the status bar's fields
11ICON_POSITION = 0
12MSG_POSITION  = 1
13GAUGE_POSITION  = 2
14CONSOLE_POSITION  = 3
15BUTTON_SIZE = 40
16STATUS_BAR_ICON_SIZE = 12
17CONSOLE_WIDTH = 500
18CONSOLE_HEIGHT = 300
19if sys.platform.count("win32") > 0:
20    FONT_VARIANT = 0
21else:
22    FONT_VARIANT = 1
23
24GREEN = wx.Colour(95, 190, 95)
25YELLOW = wx.Colour(247, 214, 49)
26RED = wx.Colour(234, 89, 78)
27
28class ConsolePanel(wx.Panel):
29    """
30    """
31    def __init__(self, parent, *args, **kwargs):
32        """
33        """
34        wx.Panel.__init__(self, parent=parent, *args, **kwargs)
35        self.parent = parent
36        self.sizer = wx.BoxSizer(wx.VERTICAL)
37       
38        self.msg_txt = wx.richtext.RichTextCtrl(self, size=(CONSOLE_WIDTH-40,
39                                                CONSOLE_HEIGHT-60),
40                                   style=wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER)
41       
42        self.msg_txt.SetEditable(False)
43        self.msg_txt.SetValue('No message available')
44        self.sizer.Add(self.msg_txt, 1, wx.EXPAND|wx.ALL, 10)
45        self.SetSizer(self.sizer)
46       
47    def set_message(self, status="", event=None):
48        """
49        """
50        status = str(status)
51        if status.strip() == "":
52            return
53        color = (0, 0, 0) #black
54        icon_bmp =  wx.ArtProvider.GetBitmap(wx.ART_INFORMATION,
55                                             wx.ART_TOOLBAR)
56        if hasattr(event, "info"):
57            icon_type = event.info.lower()
58            if icon_type == "warning":
59                color = (0, 0, 255) # blue
60                icon_bmp =  wx.ArtProvider.GetBitmap(wx.ART_WARNING,
61                                                     wx.ART_TOOLBAR)
62            if icon_type == "error":
63                color = (255, 0, 0) # red
64                icon_bmp =  wx.ArtProvider.GetBitmap(wx.ART_ERROR, 
65                                                     wx.ART_TOOLBAR)
66            if icon_type == "info":
67                icon_bmp =  wx.ArtProvider.GetBitmap(wx.ART_INFORMATION,
68                                                     wx.ART_TOOLBAR)
69        self.msg_txt.Newline()
70        self.msg_txt.WriteBitmap(icon_bmp)
71        self.msg_txt.BeginTextColour(color)
72        self.msg_txt.WriteText("\t")
73        self.msg_txt.AppendText(status)
74        self.msg_txt.EndTextColour()
75       
76       
77class Console(wx.Frame):
78    """
79    """
80    def __init__(self, parent=None, status="", *args, **kwds):
81        kwds["size"] = (CONSOLE_WIDTH, CONSOLE_HEIGHT)
82        kwds["title"] = "Console"
83        wx.Frame.__init__(self, parent=parent, *args, **kwds)
84        self.SetWindowVariant(FONT_VARIANT)
85        self.panel = ConsolePanel(self)
86        self.panel.set_message(status=status)
87        wx.EVT_CLOSE(self, self.Close)
88       
89    def set_multiple_messages(self, messages=[]):
90        """
91        """
92        if messages:
93            for status in messages:
94                self.panel.set_message(status=status)
95               
96    def set_message(self, status, event=None):
97        """
98        """
99        self.panel.set_message(status=str(status), event=event)
100       
101    def Close(self, event):
102        """
103        """
104        self.Hide()
105       
106class StatusBar(wxStatusB):
107    """
108        Application status bar
109    """
110    def __init__(self, parent, id):
111        wxStatusB.__init__(self, parent, id)
112        self.parent = parent
113        self.parent.SetStatusBarPane(MSG_POSITION)
114
115        #Layout of status bar
116        width = STATUS_BAR_ICON_SIZE
117        height = STATUS_BAR_ICON_SIZE
118        self.SetFieldsCount(NB_FIELDS) 
119        # Leave some space for the resize handle in the last field
120        console_btn_width = 80
121        self.SetStatusWidths([width+4, -2, -1, width+console_btn_width])
122        self.SetMinHeight(height)
123       
124        #display default message
125        self.msg_position = MSG_POSITION
126       
127        # Create progress bar
128        gauge_width = 5 * width
129        self.gauge = wx.Gauge(self, size=(gauge_width, height),
130                               style=wx.GA_HORIZONTAL)
131        self.gauge.Hide()
132       
133        # Create status bar icon reflecting the type of status
134        # for the last message
135        self.status_color = wx.StaticText(self, id=wx.NewId(), label="   ", size=wx.Size(15,15))
136        self.status_color.SetBackgroundColour(GREEN)
137        self.status_color.SetForegroundColour(GREEN)
138
139        # Create the button used to show the console dialog
140        self.console_button = wx.Button(self, wx.NewId(), "Console", 
141                                 size=(console_btn_width, -1))
142        font = self.console_button.GetFont()
143        _, pixel_h = font.GetPixelSize()
144        font.SetPixelSize(wx.Size(0,int(pixel_h*0.9)))
145        self.console_button.SetFont(font)
146        self.console_button.SetToolTipString("History of status bar messages")
147        self.console_button.Bind(wx.EVT_BUTTON, self._onMonitor,
148                                id=self.console_button.GetId())
149       
150        self.reposition()
151        ## Current progress value of the bar
152        self.nb_start = 0
153        self.nb_progress = 0
154        self.nb_stop = 0
155        self.frame = None
156        self.list_msg = []
157        self.frame = Console(parent=self)
158        if hasattr(self.frame, "IsIconized"):
159            if not self.frame.IsIconized():
160                try:
161                    icon = self.parent.GetIcon()
162                    self.frame.SetIcon(icon)
163                except:
164                    try:
165                        FRAME_ICON = wx.Icon(GUIFRAME_ICON.FRAME_ICON_PATH,
166                                              wx.BITMAP_TYPE_ICON)
167                        self.frame.SetIcon(FRAME_ICON)
168                    except:
169                        pass
170        self.frame.set_multiple_messages(self.list_msg)
171        self.frame.Hide()
172        self.progress = 0
173        self.timer = wx.Timer(self, -1)
174        self.timer_stop = wx.Timer(self, -1)
175        self.thread = None
176        self.Bind(wx.EVT_TIMER, self._on_time, self.timer) 
177        self.Bind(wx.EVT_TIMER, self._on_time_stop, self.timer_stop) 
178        self.Bind(wx.EVT_SIZE, self.OnSize)
179        self.Bind(wx.EVT_IDLE, self.OnIdle)
180       
181    def reposition(self):
182        """
183            Place the various fields in their proper position
184        """
185        rect = self.GetFieldRect(GAUGE_POSITION)
186        self.gauge.SetPosition((rect.x, rect.y))
187        rect = self.GetFieldRect(ICON_POSITION)
188        self.status_color.SetPosition((rect.x, rect.y))
189        rect = self.GetFieldRect(CONSOLE_POSITION)
190        self.console_button.SetPosition((rect.x, rect.y))
191        self.sizeChanged = False
192       
193    def OnIdle(self, event):
194        """
195        """
196        if self.sizeChanged:
197            self.reposition()
198           
199    def OnSize(self, evt):
200        """
201        """
202        self.reposition() 
203        self.sizeChanged = True
204       
205    def get_msg_position(self):
206        """
207        """
208        return self.msg_position
209   
210    def SetStatusText(self, text="", number=MSG_POSITION, event=None):
211        """
212        """
213        wxStatusB.SetStatusText(self, text.split('\n',1)[0], number)
214        self.list_msg.append(text)
215        self.status_color.SetBackgroundColour(GREEN)
216        self.status_color.SetForegroundColour(GREEN)
217
218        if self.frame is not None :
219            self.frame.set_message(status=text, event=event)
220       
221    def PopStatusText(self, *args, **kwds):
222        """
223        Override status bar
224        """
225        wxStatusB.PopStatusText(self, field=MSG_POSITION)
226       
227    def PushStatusText(self, *args, **kwds):
228        """
229        PushStatusText
230        """
231        text = "PushStatusText: What is this string?"
232        wxStatusB.PushStatusText(self, field=MSG_POSITION, string=text)
233       
234    def enable_clear_gauge(self):
235        """
236        clear the progress bar
237        """
238        flag = True
239        # Why we do this?
240        #if (self.nb_start <= self.nb_stop) or \
241        #    (self.nb_progress <= self.nb_stop):
242        #    flag = True
243        return flag
244   
245    def _on_time_stop(self, evt): 
246        """
247        Clear the progress bar
248       
249        :param evt: wx.EVT_TIMER
250 
251        """ 
252        count = 0
253        while(count <= 100):
254            count += 1
255        self.timer_stop.Stop() 
256        self.clear_gauge(msg="")
257        self.nb_progress = 0 
258        self.nb_start = 0 
259        self.nb_stop = 0
260       
261    def _on_time(self, evt): 
262        """
263        Update the progress bar while the timer is running
264       
265        :param evt: wx.EVT_TIMER
266 
267        """ 
268        # Check stop flag that can be set from non main thread
269        if self.timer.IsRunning(): 
270            self.gauge.Pulse()
271   
272    def clear_gauge(self, msg=""):
273        """
274        Hide the gauge
275        """
276        self.progress = 0
277        self.gauge.SetValue(0)
278        self.gauge.Hide() 
279         
280    def set_icon(self, event):
281        """
282        Display icons related to the type of message sent to the statusbar
283        when available. No icon is displayed if the message is empty
284        """
285        if hasattr(event, "status"):
286            status = str(event.status)
287            if status.strip() == "":
288                return
289        else:
290            return
291        if not hasattr(event, "info"):
292            return 
293       
294        # Get the size of the button images
295        height = STATUS_BAR_ICON_SIZE
296       
297        msg = event.info.lower()
298        if msg == "warning":
299            self.status_color.SetBackgroundColour(YELLOW)
300            self.status_color.SetForegroundColour(YELLOW)
301        elif msg == "error":
302            self.status_color.SetBackgroundColour(RED)
303            self.status_color.SetForegroundColour(RED)
304        else:
305            self.status_color.SetBackgroundColour(GREEN)
306            self.status_color.SetForegroundColour(GREEN)
307   
308    def set_dialog(self, event):
309        """
310        Display dialogbox
311        """
312        if not hasattr(event, "info"):
313            return 
314        msg = event.info.lower()
315        if msg == "error":
316            e_msg = "Error(s) Occurred:\n"
317            e_msg += "\t" + event.status + "\n\n"
318            e_msg += "Further information might be available in "
319            e_msg += "the Console log (bottom right corner)."
320            wx.MessageBox(e_msg, style=wx.ICON_ERROR)
321
322    def set_message(self, event):
323        """
324        display received message on the statusbar
325        """
326        if hasattr(event, "status"):
327            self.SetStatusText(text=str(event.status), event=event)
328       
329    def set_gauge(self, event):
330        """
331        change the state of the gauge according the state of the current job
332        """
333        if not hasattr(event, "type"):
334            return
335        type = event.type
336        self.gauge.Show(True)
337        if type.lower() == "start":
338            self.nb_start += 1
339            #self.timer.Stop()
340            self.progress += 5
341            self.gauge.SetValue(int(self.progress)) 
342            self.progress += 5
343            if self.progress < self.gauge.GetRange() - 20:
344                self.gauge.SetValue(int(self.progress)) 
345        if type.lower() == "progress":
346            self.nb_progress += 1
347            self.timer.Start(1)
348            self.gauge.Pulse()
349        if type.lower() == "update":
350            self.progress += 5
351            if self.progress < self.gauge.GetRange()- 20:
352                self.gauge.SetValue(int(self.progress))   
353        if type.lower() == "stop":
354            self.nb_stop += 1
355            self.gauge.Show(True)
356            if self.enable_clear_gauge():
357                self.timer.Stop()
358                self.progress = 0
359                self.gauge.SetValue(100) 
360                self.timer_stop.Start(5) 
361                   
362    def set_status(self, event):
363        """
364        Update the status bar .
365       
366        :param type: type of message send.
367            type  must be in ["start","progress","update","stop"]
368        :param msg: the message itself  as string
369        :param thread: if updatting using a thread status
370       
371        """
372        self.set_message(event=event)
373        self.set_icon(event=event)
374        self.set_gauge(event=event)
375        # dialog on error
376        self.set_dialog(event=event)
377       
378    def _onMonitor(self, event):
379        """
380        Pop up a frame with messages sent to the status bar
381        """
382        self.frame.Show(False)
383        self.frame.Show(True)
384       
385       
386class SPageStatusbar(wxStatusB):
387    def __init__(self, parent, timeout=None, *args, **kwds):
388        wxStatusB.__init__(self, parent, *args, **kwds)
389        self.SetFieldsCount(1) 
390        self.timeout = timeout
391        width, height = parent.GetSizeTuple()
392        self.gauge = wx.Gauge(self, style=wx.GA_HORIZONTAL, 
393                              size=(width, height/10))
394        rect = self.GetFieldRect(0)
395        self.gauge.SetPosition((rect.x , rect.y ))
396        if self.timeout is not None:
397            self.gauge.SetRange(int(self.timeout))
398        self.timer = wx.Timer(self, -1) 
399        self.Bind(wx.EVT_TIMER, self._on_time, self.timer) 
400        self.timer.Start(1)
401        self.pos = 0
402       
403    def _on_time(self, evt): 
404        """
405        Update the progress bar while the timer is running
406       
407        :param evt: wx.EVT_TIMER
408 
409        """ 
410        # Check stop flag that can be set from non main thread
411        if self.timeout is None and self.timer.IsRunning(): 
412            self.gauge.Pulse()
413           
414       
415if __name__ == "__main__":
416    app = wx.PySimpleApp()
417    frame = wx.Frame(None, wx.ID_ANY, 'test frame')
418    #statusBar = StatusBar(frame, wx.ID_ANY)
419    statusBar = SPageStatusbar(frame)
420    frame.SetStatusBar(statusBar)
421    frame.Show(True)
422    #event = MessageEvent()
423    #event.type = "progress"
424    #event.status  = "statusbar...."
425    #event.info = "error"
426    #statusBar.set_status(event=event)
427    app.MainLoop()
428
Note: See TracBrowser for help on using the repository browser.