source: sasview/src/sas/guiframe/gui_statusbar.py @ 4e080980

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 4e080980 was 4342107f, checked in by Paul Kienzle <pkienzle@…>, 10 years ago

fix .ico image handler error on windows startup (see #383)

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