awips2/cave/com.raytheon.viz.avnconfig/localization/aviation/python/EditorTools.py
Max Schenkelberg 6f60751ec6 Issue #2033 moved avnfps and text workstation files into respective plugins.
Change-Id: If95cb839ad81ca2a842ff7f6926847ac3928d8f2

Former-commit-id: 77e1a4d8f5237e5fae930c1e00589c752f8b3738
2013-08-15 12:21:43 -05:00

400 lines
14 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:
# EditorTools.py
# GFS1-NHD:A6834.0000-SCRIPT;19
#
# Status:
# DELIVERED
#
# History:
# Revision 19 (DELIVERED)
# Created: 18-DEC-2008 17:31:05 OBERFIEL
# Changed label on default button in the QC dialog.
#
# Revision 18 (DELIVERED)
# Created: 01-OCT-2008 22:07:36 OBERFIEL
# Simplified layout now that customization can be found in
# the info.cfg files.
#
# Revision 17 (DELIVERED)
# Created: 23-SEP-2008 08:44:54 GILMOREDM
# Changed so that all TAFs are QC'd regardless of a user's
# selection in the QC dialog
#
# Revision 16 (REVIEW)
# Created: 19-SEP-2008 12:41:17 GILMOREDM
# minor change to TafQC
#
# Revision 15 (INITIALIZE)
# Created: 19-SEP-2008 12:20:46 GILMOREDM
# Slight fix for TafQC
#
# Revision 14 (REVIEW)
# Created: 16-SEP-2008 11:34:37 GILMOREDM
# Refreshed changes where needed for TafQC
#
# Revision 13 (DELIVERED)
# Created: 18-AUG-2008 12:49:28 OBERFIEL
# Remove obsolete CM info
#
# Revision 12 (REVIEW)
# Created: 15-MAY-2008 15:11:29 GILMOREDM
# Configured QC dialog to handle individual site QC
# configurations
#
# Revision 11 (DELIVERED)
# Created: 27-FEB-2008 10:26:09 GILMOREDM
# Added functionality to overcome a bug with the
# Pmw.TimeCounter object
#
# Revision 10 (DELIVERED)
# Created: 23-JAN-2007 12:36:15 OBERFIEL
# Further dereference of the fcstr information was needed to
# return forecaster ID.
#
# Revision 9 (DELIVERED)
# Created: 09-SEP-2005 13:53:20 TROJAN
# spr 7011
#
# Revision 8 (DELIVERED)
# Created: 07-JUL-2005 12:27:35 TROJAN
# spr 6911
#
# Revision 7 (DELIVERED)
# Created: 07-MAY-2005 11:32:43 OBERFIEL
# Added Item Header Block
#
# Revision 6 (DELIVERED)
# Created: 04-APR-2005 15:51:05 TROJAN
# spr 6775
#
# Revision 5 (DELIVERED)
# Created: 24-JAN-2005 15:51:13 TROJAN
# spr 6259
#
# Revision 4 (APPROVED)
# Created: 01-OCT-2004 13:42:40 TROJAN
# spr 6400
#
# Revision 3 (APPROVED)
# Created: 09-JUL-2004 19:10:54 OBERFIEL
# Replaced busy dialogs
#
# Revision 2 (APPROVED)
# Created: 01-JUL-2004 14:59:21 OBERFIEL
# Update
#
# Revision 1 (DELIVERED)
# Created: 08-JAN-2004 21:29:52 PCMS
# Initial version
#
# Change Document History:
# 1:
# Change Document: GFS1-NHD_SPR_7407
# Action Date: 03-JAN-2009 09:26:51
# Relationship Type: In Response to
# Status: TEST
# Title: AvnFPS: Allow WFOs to update HDF5 climate files
#
#
import logging, time
from Tkinter import *
import Pmw
import Avn, AvnLib, AvnParser, Busy, Globals
Help = {
'title': 'Editor Help',
'content': """
The text window key bindings are essentially the same as documented in Tcl/Tk
text widget manual. See also Brent B. Welch, Practical Programming in Tcl and
Tk, second edition, pp 385-387). Note, however, that some of the key
combination may be intercepted by the window manager.
Any-Key Insert normal printing characters.
Control-u Undo changes
Control-r Redo changes
Button-1 Sets the insert point, clear the selection, set focus.
Control-Button-1 Set the insert point without affecting the selection.
B1-Motion Sweep out a selection from the insert point.
Double-Button-1 Select the word under the mouse.
Triple-Button-1 Select the line under the mouse.
Shift-Button-1 Adjust the end of selection closest to the mouse.
Shift-B1-Motion Continue to adjust the selection.
Button-2 Paste the selection, or set the scrolling anchor.
B2-Motion Scroll the window.
Key-Left or Control-b Move the cursor left one character. Clear selection.
Shift-Left Move the cursor and extend the selection.
Control-Left Move the cursor by words. Clear the selection.
Control-Shift-Left Move the cursor by words. Extend the selection.
Key-Right or Control-f Right bindings are analogous to Left bindings.
Alt-b or Alt-f Same as Control-Left, Control-Right.
Key-Up or Control-p Move the cursor up one line. Clear the selection.
Control-Up Move the cursor by paragraph which are group of lines
separated by a blank line.
Control-Shift-Up Move the cursor by paragraph. Extend selection.
Key-Down or Control-n All Down bindings are analogous to Up bindings.
PageUp, PageDown Move the cursor by one screen. Clear the selection.
Shift-PageUp, PageDown Move the cursor by one screen. Extend the selection.
Home or Control-a Move the cursor to line start. Clear the selection.
Shift-Home Move the cursor to line start. Extend the selection.
End or Control-e Move the cursor to line end. Clear the selection.
Shift-End Move the cursor to line end. Extend the selection.
Control-Home Move the cursor to the beginning of text. Clear the
selection.
Control-End Move the cursor to the beginning of text. Extend the
selection.
Control-slash Select everything in the text widget.
Control-backslash Clear the selection.
Delete Delete the selection, if any. Otherwise delete the
character to the right of the cursor.
BackSpace or Control-h Delete the selection, if any. Otherwise delete the
character to the left of the cursor.
Control-d Delete character to the right of the cursor.
Alt-d Delete word to the right of the cursor.
Control-k Delete from cursor to the end of the line. If you are
at the end of the line, delete the newline character.
Control-o Insert a newline but do not advance the cursor.
Alt-Delete Delete the word to the left of the cursor.
Alt-Backspace
Control-t Transpose the characters on either side of the cursor.
"""
}
_Logger = logging.getLogger(__name__)
#############################################################################
class SendDialog(Pmw.Dialog):
def __init__(self, parent, **kw):
Pmw.Dialog.__init__(self, parent.interior())
self.title(Avn.Name + ' Send')
self.withdraw()
self.configure(buttons=('OK', 'Cancel'),
defaultbutton='OK',
command=self.__execute)
self._time = Pmw.TimeCounter(self.interior(),
labelpos='w',
label_text='Transmit at:\nHH:MM:SS',
min='00:00:00',
max='23:59:59',
value='00:00:00',
)
self._time.pack(padx=10, pady=5)
self._slist = Pmw.ScrolledListBox(self.interior(),
labelpos='n',
label_text='Responsible for this forecast',
)
self._slist.pack()
self.__load()
self._position = 'first+%d+%d' % (parent.winfo_rootx()+30, \
parent.winfo_rooty()+30)
def __load(self):
try:
self._fcstdict = AvnParser.getForecasters()
if not self._fcstdict:
raise ValueError, 'Empty file'
fcstnames = self._fcstdict.keys()
fcstnames.sort()
self._slist.setlist(fcstnames)
except IOError:
msg = 'Cannot open forecaster file'
_Logger.exception(msg)
Busy.showerror(msg, self.interior())
raise SystemExit
except (ValueError, IndexError):
msg = 'Invalid entry in forecaster file'
_Logger.exception(msg)
Busy.showerror(msg, self.interior())
raise SystemExit
def __execute(self, result=None):
if result == 'OK':
now = time.time()
self.time = self._getTime() + (now//86400.0)*86400.0
if self.time < now - 43200:
self.time += 86400
if not (now - 600 < self.time < now + 10800):
if not Busy.askokcancel('Are you sure?', self.interior()):
return
try:
fcstname = self._slist.getcurselection()[0]
self.id = self._fcstdict[fcstname].get('id',0)
except IndexError:
Busy.showerror('Select name', self.interior())
else:
self.time, self.id = None, 0
self.deactivate()
def _getTime(self):
# this solves a bug in the Pmw.TimeCounter object not returning correct
# time if values are updated in the entryfield only (no arrows are clicked)
if self.thetime != self._time.getint():
inttime = self._time.getint()
else:
thetime = [int(self._time.component(comp).get()) for comp in ['hourentry','minuteentry','secondentry']]
inttime = thetime[0]*3600 + thetime[1]*60 + thetime[2]
return inttime
def activate(self, kind, headertime, bbb):
if bbb and bbb[0] != ' ':
t = time.time()
else:
t = AvnLib.getXmitTime(kind, headertime)
self._time.setvalue(time.strftime('%H:%M:00', time.gmtime(t)))
self.thetime = self._time.getint() # used in self._getTime() method
ix = list(self._slist.get()).index(Globals.Forecaster)
self._slist.selection_set(ix)
self._slist.see(ix)
Busy.Manager.busy(None, self.component('hull'))
Pmw.Dialog.activate(self, geometry=self._position)
Busy.Manager.notbusy()
return self.time, self.id
#############################################################################
class QCDialog(Pmw.Dialog):
def __init__(self, parent, **kw):
Pmw.Dialog.__init__(self, parent)
self.withdraw()
self.title(Avn.Name + ' QC')
self.configure(buttons=('Apply', 'Close'),
defaultbutton='Apply',
command=self.__execute,
)
self.parent = parent
self._tkProduct = StringVar()
self.radiobuttons = Pmw.RadioSelect(self.interior(),
buttontype='checkbutton',
orient='vertical',
labelpos='n',
label_text='QC Options ',
hull_borderwidth=0,
padx=5,
pady=1,
hull_relief='ridge',
)
self.KeysLabels = [('currentwx', 'Current Wx'), ('climate', 'Climate'), ('impact', 'Impact')]
self.radiobuttons.pack(side='left', expand='no', padx=5)
for item, label in self.KeysLabels:
self.radiobuttons.add(item, text=label)
self.radiobuttons.invoke(item)
self.resizable(width='false', height='true')
self._position = 'first+%d+%d' % (parent.winfo_rootx()+30, \
parent.winfo_rooty()+30)
def __execute(self, result):
self.items = dict([(a[0],0) for a in self.KeysLabels])
if result == 'Apply':
for item in self.radiobuttons.getcurselection():
self.items[item] = 1
self.deactivate()
def activate(self):
Busy.Manager.busy(None, self.component('hull'))
Pmw.Dialog.activate(self, geometry=self._position)
Busy.Manager.notbusy()
return self.items
###############################################################################
class TkIndex:
# Used to convert offsets to Tk text indices
def __init__(self, text):
self.newlines = []
self.length = len(text)
i = 0
while 1:
try:
k = text.index('\n', i)
self.newlines.append((i, k))
i = k+1
except ValueError:
break
def ix(self, offset, length):
if offset < 0 or length <= 0 or offset > self.length:
raise ValueError, 'Invalid arguments %d %d' % (offset, length)
start, end = '1.0', None
n = 1
for i, k in self.newlines:
if i <= offset <= k:
start = '%d.%d' % (n, offset-i)
break
n += 1
offset += length
for i, k in self.newlines[n-1:]:
if i <= offset <= k:
end = '%d.%d' % (n, offset-i)
break
n += 1
if end is None:
end = 'end'
return start, end
#############################################################################
def validateBBB(text):
# validator used by Pmw.EntryField
if not text:
return Pmw.OK
if len(text) < 3:
return Pmw.PARTIAL
elif len(text) > 3:
return Pmw.ERROR
try:
bb = text[:2].upper()
if not bb in ('AA', 'CC', 'RR'):
return Pmw.ERROR
if not text[2].isalpha():
return Pmw.ERROR
return Pmw.OK
except:
return Pmw.ERROR
#############################################################################
def validateHeaderTime(text):
# validator used by Pmw.EntryField
if len(text) < 6:
return Pmw.PARTIAL
try:
day = int(text[:2])
hour = int(text[2:4])
minute = int(text[4:])
if day < 1 or day > 31:
return Pmw.ERROR
if hour < 0 or hour > 23:
return Pmw.ERROR
if minute < 0 or minute > 59:
return Pmw.ERROR
return Pmw.OK
except:
return Pmw.ERROR
def xmitServerOK():
# find server name
for key in Globals.ServerStatus:
if key.startswith('XMIT'):
return time.time() - Globals.ServerStatus[key] < 60.0
else:
return False