source: sasview/src/sas/sasgui/guiframe/gui_statusbar.py @ 77d92cd

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 77d92cd was d85c194, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 8 years ago

Remaining modules refactored

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