275 lines
8.8 KiB
Python
275 lines
8.8 KiB
Python
|
##
|
||
|
# This software was developed and / or modified by Raytheon Company,
|
||
|
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||
|
#
|
||
|
# U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||
|
# This software product contains export-restricted data whose
|
||
|
# export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||
|
# to non-U.S. persons whether in the United States or abroad requires
|
||
|
# an export license or other authorization.
|
||
|
#
|
||
|
# Contractor Name: Raytheon Company
|
||
|
# Contractor Address: 6825 Pine Street, Suite 340
|
||
|
# Mail Stop B8
|
||
|
# Omaha, NE 68106
|
||
|
# 402.291.0100
|
||
|
#
|
||
|
# See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||
|
# further licensing information.
|
||
|
##
|
||
|
#
|
||
|
# Name:
|
||
|
# MessageBar.py
|
||
|
# GFS1-NHD:A7804.0000-SCRIPT;1.3
|
||
|
#
|
||
|
# Status:
|
||
|
# DELIVERED
|
||
|
#
|
||
|
# History:
|
||
|
# Revision 1.3 (DELIVERED)
|
||
|
# Created: 07-MAY-2005 11:35:24 OBERFIEL
|
||
|
# Added Item Header Block
|
||
|
#
|
||
|
# Revision 1.2 (DELIVERED)
|
||
|
# Created: 15-FEB-2005 18:23:19 TROJAN
|
||
|
# spr 6529
|
||
|
#
|
||
|
# Revision 1.1 (APPROVED)
|
||
|
# Created: 01-JUL-2004 14:41:32 OBERFIEL
|
||
|
# date and time created -2147483647/-2147483648/-2147481748
|
||
|
# -2147483648:-2147483648:-2147483648 by oberfiel
|
||
|
#
|
||
|
# Change Document History:
|
||
|
# 1:
|
||
|
# Change Document: GFS1-NHD_SPR_6832
|
||
|
# Action Date: 07-JUN-2005 13:13:53
|
||
|
# Relationship Type: In Response to
|
||
|
# Status: CLOSED
|
||
|
# Title: AvnFPS: Add PVCS doc blocks
|
||
|
#
|
||
|
#
|
||
|
# Class to display messages in an information line.
|
||
|
# code derived derived from Pmw.MessageBar
|
||
|
# implements blinking label, history display and logging capabilities
|
||
|
# last update: 02/01/05
|
||
|
|
||
|
import Tkinter
|
||
|
import Pmw
|
||
|
import logging, time
|
||
|
import Balloon
|
||
|
|
||
|
class MessageBar(Pmw.MegaWidget):
|
||
|
def __init__(self, parent = None, **kw):
|
||
|
|
||
|
# Define the megawidget options.
|
||
|
INITOPT = Pmw.INITOPT
|
||
|
defaultMessageTypes = {
|
||
|
# (priority, showtime, flash, loglevel)
|
||
|
'systemerror' : (5, 20, 'red', logging.ERROR),
|
||
|
'usererror' : (4, 12, 'orange', logging.WARNING),
|
||
|
'busy' : (3, 0, None, 0),
|
||
|
'systemevent' : (3, 8, 'green', logging.INFO),
|
||
|
'userevent' : (2, 5, 'green', logging.INFO),
|
||
|
'help' : (1, 5, None, 0),
|
||
|
'state' : (0, 0, None, 0),
|
||
|
}
|
||
|
optiondefs = (
|
||
|
('labelmargin', 0, INITOPT),
|
||
|
('labelpos', 'w', INITOPT),
|
||
|
('label_width', 2, INITOPT),
|
||
|
('messagetypes', defaultMessageTypes, INITOPT),
|
||
|
('silent', 0, None),
|
||
|
('sticky', 'ew', INITOPT),
|
||
|
('logname', '', INITOPT),
|
||
|
('history', 0, INITOPT),
|
||
|
)
|
||
|
self.defineoptions(kw, optiondefs)
|
||
|
|
||
|
# Initialise the base class (after defining the options).
|
||
|
Pmw.MegaWidget.__init__(self, parent)
|
||
|
|
||
|
# Create the components.
|
||
|
interior = self.interior()
|
||
|
self._messageBarEntry = self.createcomponent('entry',
|
||
|
(), None,
|
||
|
Tkinter.Entry, (interior,))
|
||
|
|
||
|
# somehow readonly background is not processed correctly
|
||
|
bg = self._messageBarEntry.cget('background')
|
||
|
self._messageBarEntry.configure(readonlybackground=bg, state='readonly')
|
||
|
|
||
|
self._messageBarEntry.grid(column=2, row=2, sticky=self['sticky'])
|
||
|
interior.grid_columnconfigure(2, weight=1)
|
||
|
interior.grid_rowconfigure(2, weight=1)
|
||
|
if self['history']:
|
||
|
self._textDialog = Pmw.TextDialog(interior, \
|
||
|
scrolledtext_labelpos = 'n', \
|
||
|
label_text = 'Past messages', \
|
||
|
defaultbutton=0, \
|
||
|
)
|
||
|
self._textDialog.withdraw()
|
||
|
self._textDialog.configure(text_state='disabled')
|
||
|
self._pushButton = self.createcomponent('button', \
|
||
|
(), None, \
|
||
|
Tkinter.Button, (interior,), \
|
||
|
command=self._showHistory, \
|
||
|
)
|
||
|
self._pushButton.grid(column=3, row=2, sticky=self['sticky'])
|
||
|
Balloon.Balloon().bind(self._pushButton, 'Show past messages')
|
||
|
|
||
|
self.createlabel(interior)
|
||
|
Balloon.Balloon().bind(self.component('label'), 'New message indicator')
|
||
|
|
||
|
# Initialise instance variables.
|
||
|
self._numPriorities = 0
|
||
|
for info in self['messagetypes'].values():
|
||
|
if self._numPriorities < info[0]:
|
||
|
self._numPriorities = info[0]
|
||
|
|
||
|
self._numPriorities = self._numPriorities + 1
|
||
|
self._timer = [None] * self._numPriorities
|
||
|
self._messagetext = [''] * self._numPriorities
|
||
|
self._activemessage = [0] * self._numPriorities
|
||
|
self._activebackground = [0] * self._numPriorities
|
||
|
self._flashtimer = None
|
||
|
self._flash = {'off': self.component('label').cget('background')}
|
||
|
if self['logname']:
|
||
|
self._logger = logging.getLogger(self['logname'])
|
||
|
else:
|
||
|
self._logger = None
|
||
|
|
||
|
# Check keywords and initialise options.
|
||
|
self.initialiseoptions()
|
||
|
|
||
|
def createlabel(self, parent, childCols = 1, childRows = 1):
|
||
|
labelpos = self['labelpos']
|
||
|
labelmargin = self['labelmargin']
|
||
|
if labelpos is None:
|
||
|
return
|
||
|
frame = Tkinter.Frame(parent, relief='groove', bd=2)
|
||
|
label = self.createcomponent('label',
|
||
|
(), None,
|
||
|
Tkinter.Label, (frame,))
|
||
|
label.pack()
|
||
|
if labelpos[0] in 'ns':
|
||
|
# vertical layout
|
||
|
if labelpos[0] == 'n':
|
||
|
row = 0
|
||
|
margin = 1
|
||
|
else:
|
||
|
row = childRows + 3
|
||
|
margin = row - 1
|
||
|
frame.grid(column=2, row=row, columnspan=childCols, sticky=labelpos)
|
||
|
parent.grid_rowconfigure(margin, minsize=labelmargin)
|
||
|
else:
|
||
|
# horizontal layout
|
||
|
if labelpos[0] == 'w':
|
||
|
col = 0
|
||
|
margin = 1
|
||
|
else:
|
||
|
col = childCols + 3
|
||
|
margin = col - 1
|
||
|
frame.grid(column=col, row=2, rowspan=childRows, sticky=labelpos)
|
||
|
parent.grid_columnconfigure(margin, minsize=labelmargin)
|
||
|
|
||
|
def destroy(self):
|
||
|
for timerId in self._timer:
|
||
|
if timerId is not None:
|
||
|
self.after_cancel(timerId)
|
||
|
self._timer = [None] * self._numPriorities
|
||
|
Pmw.MegaWidget.destroy(self)
|
||
|
|
||
|
def message(self, type, text):
|
||
|
# Display a message in the message bar.
|
||
|
|
||
|
(priority, showtime, flashbg, loglevel) = self['messagetypes'][type]
|
||
|
|
||
|
self._activemessage[priority] = 1
|
||
|
self._activebackground[priority] = flashbg
|
||
|
if text is None:
|
||
|
text = ''
|
||
|
self._messagetext[priority] = text.replace('\n', ' ')
|
||
|
self._redisplayInfoMessage()
|
||
|
|
||
|
if loglevel and self._logger:
|
||
|
self._logger.log(loglevel, text)
|
||
|
|
||
|
if self['history']:
|
||
|
# FIXME: implement circular buffer
|
||
|
self._textDialog.appendtext('%s: %s\n' % \
|
||
|
(time.strftime('%x %X'), text.rstrip()))
|
||
|
|
||
|
if showtime > 0:
|
||
|
if self._timer[priority] is not None:
|
||
|
self.after_cancel(self._timer[priority])
|
||
|
|
||
|
# Define a callback to clear this message after a time.
|
||
|
def _clearmessage(self=self, priority=priority):
|
||
|
self._clearActivemessage(priority)
|
||
|
|
||
|
mseconds = int(showtime * 1000)
|
||
|
self._timer[priority] = self.after(mseconds, _clearmessage)
|
||
|
|
||
|
def helpmessage(self, text):
|
||
|
if text is None:
|
||
|
self.resetmessages('help')
|
||
|
else:
|
||
|
self.message('help', text)
|
||
|
|
||
|
def resetmessages(self, type):
|
||
|
priority = self['messagetypes'][type][0]
|
||
|
self._clearActivemessage(priority)
|
||
|
for messagetype, info in self['messagetypes'].items():
|
||
|
thisPriority = info[0]
|
||
|
showtime = info[1]
|
||
|
if thisPriority < priority and showtime != 0:
|
||
|
self._clearActivemessage(thisPriority)
|
||
|
|
||
|
def _clearActivemessage(self, priority):
|
||
|
self._activemessage[priority] = 0
|
||
|
self._activebackground[priority] = None
|
||
|
if self._timer[priority] is not None:
|
||
|
self.after_cancel(self._timer[priority])
|
||
|
self._timer[priority] = None
|
||
|
self._redisplayInfoMessage()
|
||
|
|
||
|
def _flashLabel(self):
|
||
|
label = self.component('label')
|
||
|
bg = label.cget('background')
|
||
|
if bg == self._flash['off']:
|
||
|
label.configure(background=self._flash['on'])
|
||
|
else:
|
||
|
label.configure(background=self._flash['off'])
|
||
|
self._flashtimer = self.after(500, self._flashLabel)
|
||
|
|
||
|
def _redisplayInfoMessage(self):
|
||
|
text = ''
|
||
|
for priority in range(self._numPriorities - 1, -1, -1):
|
||
|
if self._activemessage[priority]:
|
||
|
text = self._messagetext[priority]
|
||
|
flashbg = self._activebackground[priority]
|
||
|
break
|
||
|
else:
|
||
|
flashbg = None
|
||
|
self._messageBarEntry.configure(state = 'normal')
|
||
|
self._messageBarEntry.delete(0, 'end')
|
||
|
self._messageBarEntry.insert('end', text)
|
||
|
|
||
|
if self._flashtimer is not None:
|
||
|
self.after_cancel(self._flashtimer)
|
||
|
self._flashtimer = None
|
||
|
self.component('label').configure(background=self._flash['off'])
|
||
|
|
||
|
if not self['silent'] and flashbg:
|
||
|
self._flash['on'] = flashbg
|
||
|
self._flashtimer = self.after(100, self._flashLabel)
|
||
|
else:
|
||
|
self._flashtimer = None
|
||
|
|
||
|
self._messageBarEntry.configure(state = 'readonly')
|
||
|
|
||
|
def _showHistory(self):
|
||
|
self._textDialog.show()
|
||
|
|
||
|
Pmw.forwardmethods(MessageBar, Tkinter.Entry, '_messageBarEntry')
|