Change-Id: If95cb839ad81ca2a842ff7f6926847ac3928d8f2 Former-commit-id: 77e1a4d8f5237e5fae930c1e00589c752f8b3738
813 lines
29 KiB
Python
813 lines
29 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:
|
|
# SiteInfoEditor.py
|
|
# GFS1-NHD:A8060.0000-SCRIPT;24
|
|
#
|
|
# Status:
|
|
# DELIVERED
|
|
#
|
|
# History:
|
|
# Revision 24 (DELIVERED)
|
|
# Created: 12-SEP-2008 12:28:21 OBERFIEL
|
|
# Greatly improved visual layout of the new QC Check section.
|
|
#
|
|
# Revision 23 (REVIEW)
|
|
# Created: 19-AUG-2008 14:26:40 GILMOREDM
|
|
# added section to configure qc checks
|
|
#
|
|
# Revision 22 (DELIVERED)
|
|
# Created: 15-JUL-2008 07:30:45 OBERFIEL
|
|
# By default TAF duration is 24 hours for any new TAF. Also
|
|
# added first guess for ACARS ID.
|
|
#
|
|
# Revision 21 (DELIVERED)
|
|
# Created: 06-NOV-2007 07:56:49 OBERFIEL
|
|
# Change to allow user to enter a mixed-cased identifier
|
|
#
|
|
# Revision 20 (REVIEW)
|
|
# Created: 02-NOV-2007 08:01:27 OBERFIEL
|
|
# Checked in code to support ACARS field.
|
|
#
|
|
# Revision 19 (DELIVERED)
|
|
# Created: 04-MAY-2007 15:26:57 OBERFIEL
|
|
# Updated to write and read tafduration attribute from the
|
|
# TAF info.cfg file.
|
|
#
|
|
# Revision 18 (REVIEW)
|
|
# Created: 03-MAY-2007 08:28:43 OBERFIEL
|
|
# Removed obsolete cruft, added new TAF duration field.
|
|
# Added code to switch TAF to different template format on
|
|
# certain date.
|
|
#
|
|
# Revision 17 (DELIVERED)
|
|
# Created: 27-APR-2007 08:48:52 OBERFIEL
|
|
# Fixed WMO validator to accept alphanumeric identifiers in
|
|
# the GUI text field.
|
|
#
|
|
# Revision 16 (DELIVERED)
|
|
# Created: 29-JUN-2006 07:50:32 TROJAN
|
|
# spr 7181: modified "Update" action logic
|
|
#
|
|
# Revision 15 (DELIVERED)
|
|
# Created: 14-APR-2006 13:25:17 TROJAN
|
|
# spr 7117
|
|
#
|
|
# Revision 14 (DELIVERED)
|
|
# Created: 14-APR-2006 13:17:49 TROJAN
|
|
# spr 7118
|
|
#
|
|
# Revision 13 (APPROVED)
|
|
# Created: 14-APR-2006 08:24:42 TROJAN
|
|
# spr 7117
|
|
#
|
|
# Revision 12 (DELIVERED)
|
|
# Created: 06-FEB-2006 10:09:29 TROJAN
|
|
# several coding errors related to change of alternate site
|
|
# list format
|
|
#
|
|
# Revision 11 (APPROVED)
|
|
# Created: 30-JAN-2006 10:05:40 TROJAN
|
|
# stdr 956
|
|
#
|
|
# Revision 10 (DELIVERED)
|
|
# Created: 09-SEP-2005 12:35:23 TROJAN
|
|
# spr 7011
|
|
#
|
|
# Revision 9 (DELIVERED)
|
|
# Created: 07-MAY-2005 11:38:11 OBERFIEL
|
|
# Added Item Header Block
|
|
#
|
|
# Revision 8 (DELIVERED)
|
|
# Created: 18-APR-2005 17:57:38 TROJAN
|
|
# spr 6800
|
|
#
|
|
# Revision 7 (DELIVERED)
|
|
# Created: 21-MAR-2005 15:14:37 TROJAN
|
|
# spr 6732
|
|
#
|
|
# Revision 6 (DELIVERED)
|
|
# Created: 15-FEB-2005 18:28:18 TROJAN
|
|
# spr 6529
|
|
#
|
|
# Revision 5 (APPROVED)
|
|
# Created: 14-FEB-2005 19:29:05 TROJAN
|
|
# spr 6648
|
|
#
|
|
# Revision 4 (APPROVED)
|
|
# Created: 07-DEC-2004 18:50:40 TROJAN
|
|
# spr 6451
|
|
#
|
|
# Revision 3 (APPROVED)
|
|
# Created: 09-NOV-2004 15:07:04 OBERFIEL
|
|
# Added LLWS functions
|
|
#
|
|
# Revision 2 (APPROVED)
|
|
# Created: 08-NOV-2004 19:01:29 OBERFIEL
|
|
# Changes to support LLWS
|
|
#
|
|
# Revision 1 (APPROVED)
|
|
# Created: 30-SEP-2004 18:21:27 TROJAN
|
|
# rewrite of avnsetup
|
|
#
|
|
# Change Document History:
|
|
# 1:
|
|
# Change Document: GFS1-NHD_SPR_7383
|
|
# Action Date: 06-NOV-2008 15:25:22
|
|
# Relationship Type: In Response to
|
|
# Status: TEST
|
|
# Title: AvnFPS: Lack of customization in QC check
|
|
#
|
|
#
|
|
import logging, os, re
|
|
import ConfigParser
|
|
from Tkinter import *
|
|
import Pmw
|
|
from Balloon import Balloon
|
|
import Avn, AvnDialog, AvnParser, EditDialog
|
|
|
|
_Help = {
|
|
'title': 'Site Setup Help',
|
|
'content': """
|
|
This dialog is used to define TAF site information.
|
|
|
|
To add a new site, enter site id and press "Update". Edit displayed
|
|
entries and press "Save". Create default template files.
|
|
|
|
To change an existing TAF site attribute, enter site id and press
|
|
the "Load" button.
|
|
|
|
To create template files, press "Make" in the "Templates" area.
|
|
|
|
To edit template file, select issue hour, then press "Edit" in
|
|
the "Templates" area.
|
|
|
|
You can use "Update" button to extract information from AWIPS
|
|
configuration files. Only non-empty fields will be overwritten.
|
|
"""
|
|
}
|
|
|
|
_Issue_Hours = ['00Z', '06Z', '12Z', '18Z']
|
|
_A2A = os.path.join(os.environ['FXA_HOME'], 'data', 'afos2awips.txt')
|
|
_Geo = os.path.join(os.environ['FXA_HOME'], 'data', 'metarStationInfo.txt')
|
|
_Logger = logging.getLogger(__name__)
|
|
|
|
def _validateAFOS(text):
|
|
text = text.strip()
|
|
length = len(text)
|
|
if length < 8:
|
|
return Pmw.PARTIAL
|
|
value = text.upper()
|
|
if re.match('^[A-Z]{3,3}TAF[(0-9)|(A-Z)]{2,3}$', value):
|
|
return Pmw.OK
|
|
|
|
if length == 9:
|
|
return Pmw.ERROR
|
|
else:
|
|
return Pmw.PARTIAL
|
|
|
|
def _validateWMO(text):
|
|
text = text.strip()
|
|
length = len(text)
|
|
if length < 11:
|
|
return Pmw.PARTIAL
|
|
value = text.upper()
|
|
if re.match('^[A-Z]{4}[0-9]{2} [KPTI][A-Z]{3}$', value):
|
|
return Pmw.OK
|
|
else:
|
|
return Pmw.ERROR
|
|
|
|
def _validateTafduration(text):
|
|
try:
|
|
times=[24,30]
|
|
duration=int(text)
|
|
if duration in times:
|
|
return Pmw.OK
|
|
else:
|
|
if len(times) > 1:
|
|
return Pmw.PARTIAL
|
|
else:
|
|
return Pmw.FAIL
|
|
except:
|
|
return Pmw.PARTIAL
|
|
|
|
def _validateRunway(text):
|
|
if ',' not in text:
|
|
return Pmw.PARTIAL
|
|
try:
|
|
tmp = [int(x) for x in text.split(',') if x]
|
|
except ValueError:
|
|
return Pmw.ERROR
|
|
for x in tmp:
|
|
if not 0 <= x <= 360:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateHeight(text):
|
|
text = text.strip()
|
|
if not text:
|
|
return Pmw.OK
|
|
try:
|
|
tmp = [int(x) for x in text.split(',') if x]
|
|
except ValueError:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateDist(text):
|
|
text = text.strip()
|
|
if not text:
|
|
return Pmw.OK
|
|
try:
|
|
tmp = [int(x) for x in text.split(',') if x]
|
|
except ValueError:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateMetar(text):
|
|
if not text:
|
|
return Pmw.PARTIAL
|
|
for x in text.split(','):
|
|
n = len(x)
|
|
if n == 0:
|
|
continue
|
|
elif n > 4:
|
|
return Pmw.ERROR
|
|
elif n < 4:
|
|
return Pmw.PARTIAL
|
|
if Pmw.alphanumericvalidator(x) == Pmw.ERROR:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateProfiler(text):
|
|
text = text.strip()
|
|
if not text:
|
|
return Pmw.OK
|
|
for x in text.split(','):
|
|
n = len(x)
|
|
if n == 0:
|
|
continue
|
|
elif n > 5:
|
|
return Pmw.ERROR
|
|
elif n < 5:
|
|
return Pmw.PARTIAL
|
|
if Pmw.alphanumericvalidator(x) == Pmw.ERROR:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateRadar(text):
|
|
text = text.strip()
|
|
if not text:
|
|
return Pmw.OK
|
|
for x in text.split(','):
|
|
n = len(x)
|
|
if n == 0:
|
|
continue
|
|
elif n > 4:
|
|
return Pmw.ERROR
|
|
elif n < 4:
|
|
return Pmw.PARTIAL
|
|
if Pmw.alphabeticvalidator(x) == Pmw.ERROR:
|
|
return Pmw.ERROR
|
|
return Pmw.OK
|
|
|
|
def _validateOther(text):
|
|
text = text.strip()
|
|
n = len(text)
|
|
if n == 0:
|
|
return Pmw.OK
|
|
elif n > 4:
|
|
return Pmw.ERROR
|
|
elif n < 3:
|
|
return Pmw.PARTIAL
|
|
return Pmw.alphanumericvalidator(text)
|
|
|
|
def _validateVsby(text):
|
|
if ',' not in text:
|
|
return Pmw.PARTIAL
|
|
try:
|
|
tmp = [float(x) for x in text.split(',') if x]
|
|
except ValueError:
|
|
return Pmw.ERROR
|
|
for x in tmp:
|
|
if x < 0.0 or x > 10.0:
|
|
return Pmw.ERROR
|
|
tmps = tmp[:]
|
|
tmps.sort()
|
|
if tmps != tmp:
|
|
return Pmw.PARTIAL
|
|
return Pmw.OK
|
|
|
|
def _validateCig(text):
|
|
if ',' not in text:
|
|
return Pmw.PARTIAL
|
|
try:
|
|
tmp = [int(x) for x in text.split(',') if x]
|
|
except ValueError:
|
|
return Pmw.ERROR
|
|
for x in tmp:
|
|
if x < 0 or x > 30000:
|
|
return Pmw.ERROR
|
|
tmps = tmp[:]
|
|
tmps.sort()
|
|
if tmps != tmp:
|
|
return Pmw.PARTIAL
|
|
return Pmw.OK
|
|
|
|
def getHeaders(kind, ident):
|
|
tid = kind+ident[1:]
|
|
for line in file(_A2A):
|
|
if line[3:9] == tid:
|
|
return line.rstrip().split(None, 1)
|
|
else:
|
|
return None
|
|
|
|
def getGeography(ident):
|
|
for line in file(_Geo):
|
|
if line.startswith('#'):
|
|
continue
|
|
syno, i, lat, lon, elev, name, country, junk = line.split('|')
|
|
if i.strip() == ident:
|
|
return lat.strip(), lon.strip(), elev.strip()
|
|
else:
|
|
return None
|
|
|
|
##############################################################################
|
|
class Editor(AvnDialog.Dialog):
|
|
AltSites = ['METAR', 'GFSLAMP', 'GFSMOS', 'ETAMOS', \
|
|
'NGMMOS', 'ETA', 'Radars', 'Profilers', \
|
|
'ACARS']
|
|
def __init__(self, parent, **kw):
|
|
AvnDialog.Dialog.__init__(self, parent, **kw)
|
|
|
|
self.title('TAF Site Info Editor')
|
|
self.wm_iconname(newName='SEditor')
|
|
|
|
# from AvnDialog
|
|
self.createMessageBar(self.interior(), True)
|
|
|
|
interior = self.interior()
|
|
frame = Frame(interior, relief='ridge', bd=2)
|
|
self.site = Pmw.EntryField(frame,
|
|
labelpos='w',
|
|
label_text='Site Id',
|
|
entry_width=4,
|
|
validate={'validator': 'alphanumeric',
|
|
'min': 4, 'max': 4, 'minstrict': 0},
|
|
command=self.__load,
|
|
)
|
|
self.site.pack(side='left', expand='no', padx=5)
|
|
bbox = Pmw.ButtonBox(frame)
|
|
btn = bbox.add('Load', command=self.__load)
|
|
Balloon().bind(btn, 'Retrieves data for selected site')
|
|
btn = bbox.add('Update', command=self.__update)
|
|
Balloon().bind(btn, 'Retrieves site info from fxa data files')
|
|
btn = bbox.add('Save', command=self.__save)
|
|
Balloon().bind(btn, 'Saves site info to a file')
|
|
btn = bbox.add('Close', command=self.close)
|
|
Balloon().bind(btn, 'Closes this dialog')
|
|
btn = bbox.add('Help', command=Avn.curry(self.showHelp, _Help))
|
|
Balloon().bind(btn, 'Shows help')
|
|
bbox.alignbuttons()
|
|
bbox.pack(side='right', expand='no')
|
|
frame.pack(side='top', expand='yes', fill='x')
|
|
|
|
frame = Frame(interior)
|
|
headers = group = Pmw.Group(frame, tag_text='TAF Headers')
|
|
self.wmo = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='WMO',
|
|
entry_width=12,
|
|
validate=_validateWMO
|
|
)
|
|
self.wmo.grid(row=0, column=0, sticky='ew', padx=5)
|
|
self.afos = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='AFOS',
|
|
entry_width=9,
|
|
validate=_validateAFOS
|
|
)
|
|
self.afos.grid(row=0, column=1, sticky='ew', padx=5)
|
|
group.pack(side='left', expand='yes', fill='x', pady=5)
|
|
|
|
group = Pmw.Group(frame, tag_text='TAF Duration')
|
|
self.tafDuration = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Hours',
|
|
entry_width=2,
|
|
validate=_validateTafduration)
|
|
self.tafDuration.grid(row=0,column=1, sticky='ew', padx=5)
|
|
group.pack(side='right', expand='yes', fill='x', pady=5)
|
|
frame.pack(side='top', expand='yes', fill='x')
|
|
|
|
group = Pmw.Group(interior, tag_text='Thresholds')
|
|
self.vsby = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Visibility',
|
|
entry_width=24,
|
|
validate=_validateVsby,
|
|
)
|
|
self.vsby.grid(row=0, column=0, sticky='ew', padx=5)
|
|
self.cig = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Ceiling',
|
|
entry_width=24,
|
|
validate=_validateCig,
|
|
)
|
|
self.cig.grid(row=0, column=1, sticky='ew', padx=5)
|
|
self.radar_hgt = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Radar Cutoff',
|
|
entry_width=24,
|
|
validate=_validateHeight,
|
|
)
|
|
self.radar_hgt.grid(row=1, column=0, sticky='ew', padx=5)
|
|
self.profiler_hgt = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Profiler Cutoff',
|
|
entry_width=24,
|
|
validate=_validateHeight,
|
|
)
|
|
self.profiler_hgt.grid(row=1, column=1, sticky='ew', padx=5)
|
|
Pmw.alignlabels([self.vsby, self.cig, self.radar_hgt, \
|
|
self.profiler_hgt])
|
|
group.pack(side='top', expand='yes', fill='x', pady=5)
|
|
|
|
group = Pmw.Group(interior, tag_text='Geography')
|
|
self.lat = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Latitude',
|
|
entry_width=8,
|
|
validate={'validator': 'real',
|
|
'min': -90.0, 'max': 90.0},
|
|
)
|
|
self.lat.grid(row=0, column=0, sticky='ew', padx=5)
|
|
self.lon = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Longitude',
|
|
entry_width=8,
|
|
validate={'validator': 'real',
|
|
'min': -180.0, 'max': 180.0},
|
|
)
|
|
self.lon.grid(row=0, column=1, sticky='ew', padx=5)
|
|
self.elev = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Elevation',
|
|
entry_width=4,
|
|
validate={'validator': 'integer'},
|
|
)
|
|
self.elev.grid(row=0, column=2, sticky='ew', padx=5)
|
|
self.runway = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text='Runway(s)',
|
|
entry_width=12,
|
|
validate=_validateRunway,
|
|
)
|
|
self.runway.grid(row=0, column=3, sticky='ew', padx=5)
|
|
group.pack(side='top', expand='yes', fill='x', pady=5)
|
|
|
|
group = Pmw.Group(interior, tag_text='Alternate ids')
|
|
self.ident = {}
|
|
for n, tag in enumerate(self.AltSites):
|
|
if tag == 'METAR':
|
|
# to allow for multiple ids
|
|
validator = _validateMetar
|
|
elif tag == 'Radars':
|
|
validator = _validateRadar
|
|
elif tag == 'Profilers':
|
|
validator = _validateProfiler
|
|
else:
|
|
validator = _validateOther
|
|
|
|
row = n // 3; col = n % 3
|
|
self.ident[tag] = Pmw.EntryField(group.interior(),
|
|
labelpos='w',
|
|
label_text=tag,
|
|
entry_width=10,
|
|
validate=validator,
|
|
)
|
|
self.ident[tag].grid(row=row, column=col, sticky='ew',
|
|
padx=5)
|
|
|
|
Pmw.alignlabels(self.ident.values())
|
|
group.pack(side='top', expand='yes', fill='x', pady=5)
|
|
|
|
group = Pmw.Group(interior, tag_text='QC Checks')
|
|
self.impact = self.climate = self.currentwx = 1
|
|
self.qcCheck = Pmw.RadioSelect(group.interior(), buttontype='checkbutton',
|
|
orient='horizontal', command=self.__setQC)
|
|
self.qcCheck.add("Impact")
|
|
self.qcCheck.add("Climate")
|
|
self.qcCheck.add("Current Wx")
|
|
|
|
self.qcCheck.grid(row=0,column=0, sticky='news', padx=5)
|
|
|
|
group.pack(side='top', expand='yes', fill='x', pady=5)
|
|
frame.pack(side='top', expand='yes', fill='x')
|
|
|
|
group = Pmw.Group(interior, tag_text='Templates')
|
|
self._tkHour = StringVar()
|
|
self._tkHour.set(_Issue_Hours[0])
|
|
menu = Pmw.OptionMenu(group.interior(),
|
|
labelpos='w',
|
|
label_text='Issue',
|
|
menubutton_textvariable=self._tkHour,
|
|
items=tuple(_Issue_Hours),
|
|
)
|
|
menu.grid(row=0, column=0, sticky='news', padx=10)
|
|
bbox = Pmw.ButtonBox(group.interior())
|
|
btn = bbox.add('Edit', command=self.__editTemplate)
|
|
Balloon().bind(btn, 'Template editor')
|
|
btn = bbox.add('Make', command=self.__makeTemplates)
|
|
Balloon().bind(btn, 'Makes default templates')
|
|
bbox.alignbuttons()
|
|
bbox.grid(row=0, column=1, sticky='news')
|
|
group.pack(side='left', expand='yes', fill='x', pady=5)
|
|
|
|
self.initialiseoptions(Editor)
|
|
self.setGeometry()
|
|
|
|
def __clear(self):
|
|
for name in ['wmo', 'afos', 'vsby', 'cig', 'radar_hgt', \
|
|
'profiler_hgt', 'lat', 'lon', 'elev', 'runway']:
|
|
getattr(self, name).clear()
|
|
self.runway.clear()
|
|
for tag in self.AltSites:
|
|
self.ident[tag].clear()
|
|
|
|
def __validate(self):
|
|
if not self.site.valid():
|
|
msg = 'Invalid site id'
|
|
self.messagebar().message('usererror', msg)
|
|
return
|
|
for name, label in [('wmo', 'TAF WMO'), ('afos', 'TAF AFOS'), \
|
|
('vsby', 'Visibility'), ('cig', 'Ceiling'), \
|
|
('radar_hgt', 'Radar Cutoff'), \
|
|
('profiler_hgt', 'Profiler Cutoff'), \
|
|
('lat', 'Latitude'), ('lon', 'Longitude'), \
|
|
('elev', 'Elevation'), ('runway', 'Runway(s)')]:
|
|
if not getattr(self, name).valid():
|
|
msg = 'Invalid %s entry' % label
|
|
self.messagebar().message('usererror', msg)
|
|
return False
|
|
|
|
for tag in self.AltSites:
|
|
if not self.ident[tag].valid():
|
|
msg = 'Invalid %s entry' % tag
|
|
self.messagebar().message('usererror', msg)
|
|
return False
|
|
# check for number of radar and profiler heights
|
|
num_radars = len(AvnParser.split(self.ident['Radars'].getvalue()))
|
|
num_heights = len(AvnParser.split(self.radar_hgt.getvalue()))
|
|
if num_radars != num_heights:
|
|
msg = 'Invalid number of Radar Cutoff heights'
|
|
self.messagebar().message('usererror', msg)
|
|
return False
|
|
num_profilers = len(AvnParser.split(self.ident['Profilers'].getvalue()))
|
|
num_heights = len(AvnParser.split(self.profiler_hgt.getvalue()))
|
|
if num_profilers != num_heights:
|
|
msg = 'Invalid number of Profiler Cutoff heights'
|
|
self.messagebar().message('usererror', msg)
|
|
return False
|
|
return True
|
|
|
|
def __setQC(self, tag, state):
|
|
if tag == 'Impact':
|
|
self.impact = state
|
|
elif tag == 'Climate':
|
|
self.climate = state
|
|
elif tag == 'Current Wx':
|
|
self.currentwx = state
|
|
return
|
|
|
|
def __load(self):
|
|
self.messagebar().resetmessages('systemerror')
|
|
if not self.site.valid():
|
|
msg = 'Invalid site id'
|
|
self.messagebar().message('usererror', msg)
|
|
return
|
|
ident = self.site.getvalue().upper()
|
|
cfg = AvnParser.getTafSiteCfg(ident)
|
|
if cfg is None:
|
|
self.__clear()
|
|
msg = 'Failed to retrieve configuration for %s' % ident
|
|
self.messagebar().message('systemerror', msg)
|
|
return
|
|
|
|
self.wmo.setvalue(cfg['headers']['wmo'])
|
|
self.afos.setvalue(cfg['headers']['afos'])
|
|
|
|
self.vsby.setvalue(','.join([str(x) for x in \
|
|
cfg['thresholds']['vsby']]))
|
|
self.cig.setvalue(','.join([str(x) for x in \
|
|
cfg['thresholds']['cig']]))
|
|
self.radar_hgt.setvalue(','.join([str(x) for x in \
|
|
cfg['thresholds']['radar_cutoff']]))
|
|
self.profiler_hgt.setvalue(','.join([str(x) for x in \
|
|
cfg['thresholds']['profiler_cutoff']]))
|
|
self.tafDuration.setvalue(cfg['thresholds']['tafduration'])
|
|
|
|
self.lat.setvalue(cfg['geography']['lat'])
|
|
self.lon.setvalue(cfg['geography']['lon'])
|
|
self.elev.setvalue(cfg['geography']['elev'])
|
|
self.runway.setvalue(','.join([str(x) for x in \
|
|
cfg['geography']['runway']+['']]))
|
|
|
|
for tag in self.AltSites:
|
|
try:
|
|
self.ident[tag].setvalue(','.join(cfg['sites'][tag.lower()]))
|
|
except KeyError:
|
|
if tag not in ['Radars', 'Profilers', 'ACARS']:
|
|
msg = 'Missing entry %s for %s' % (tag, ident)
|
|
self.messagebar().message('systemerror', msg)
|
|
_Logger.error(msg)
|
|
|
|
for btn, label in [('Impact','impact'),('Climate','climate'),('Current Wx','currentwx')]:
|
|
try:
|
|
self.qcCheck.button(btn).select()
|
|
if cfg['qc'][label] == 0:
|
|
self.qcCheck.button(btn).deselect()
|
|
|
|
except KeyError:
|
|
self.qcCheck.button(btn).select()
|
|
continue
|
|
|
|
self.__setQC(label, cfg['qc'][label])
|
|
|
|
def __update(self):
|
|
self.messagebar().resetmessages('systemerror')
|
|
if not self.site.valid():
|
|
msg = 'Invalid site id'
|
|
self.messagebar().message('usererror', msg)
|
|
return
|
|
ident = self.site.getvalue().upper()
|
|
hdr = getHeaders('TAF', ident)
|
|
if hdr:
|
|
self.afos.setvalue(hdr[0])
|
|
self.wmo.setvalue(hdr[1])
|
|
else:
|
|
msg = 'Failed to find headers for %s' % ident
|
|
self.messagebar().message('systemerror', msg)
|
|
_Logger.exception(msg)
|
|
|
|
self.tafDuration.setvalue('24')
|
|
self.vsby.setvalue('0.5,1.0,2.0,3.0,6.0')
|
|
self.cig.setvalue('200,600,1000,2000,3100')
|
|
|
|
geo = getGeography(ident)
|
|
if geo:
|
|
self.lat.setvalue(geo[0])
|
|
self.lon.setvalue(geo[1])
|
|
self.elev.setvalue(geo[2])
|
|
else:
|
|
msg = 'Failed to find geography for %s' % ident
|
|
self.messagebar().message('systemerror', msg)
|
|
_Logger.exception(msg)
|
|
self.runway.setvalue('0,')
|
|
# no radars and profilers here
|
|
for tag in ['ACARS','METAR', 'ETA', 'ETAMOS', 'NGMMOS', 'GFSMOS', 'GFSLAMP']:
|
|
if tag in ['ACARS', 'NGMMOS']:
|
|
self.ident[tag].setvalue(ident[1:])
|
|
else:
|
|
self.ident[tag].setvalue(ident)
|
|
|
|
def __save(self):
|
|
self.messagebar().resetmessages('systemerror')
|
|
if not self.__validate():
|
|
return
|
|
ident = self.site.getvalue().upper()
|
|
path = os.path.join('etc', 'tafs', ident, 'info.cfg')
|
|
try:
|
|
cp = ConfigParser.ConfigParser()
|
|
cp.add_section('headers')
|
|
wmo = self.wmo.getvalue().strip().upper()
|
|
cp.set('headers', 'wmo', wmo)
|
|
afos = self.afos.getvalue().strip().upper()
|
|
cp.set('headers', 'afos', afos)
|
|
|
|
cp.add_section('thresholds')
|
|
vsby = self.vsby.getvalue().strip()
|
|
cp.set('thresholds', 'vsby', vsby)
|
|
cig = self.cig.getvalue().strip()
|
|
cp.set('thresholds', 'cig', cig)
|
|
hgts = self.radar_hgt.getvalue().strip()
|
|
cp.set('thresholds', 'radar_cutoff', hgts)
|
|
hgts = self.profiler_hgt.getvalue().strip()
|
|
cp.set('thresholds', 'profiler_cutoff', hgts)
|
|
hours = self.tafDuration.getvalue().strip()
|
|
cp.set('thresholds', 'tafduration', hours)
|
|
|
|
cp.add_section('geography')
|
|
lat = self.lat.getvalue().strip()
|
|
cp.set('geography', 'lat', lat)
|
|
lon = self.lon.getvalue().strip()
|
|
cp.set('geography', 'lon', lon)
|
|
elev = self.elev.getvalue().strip()
|
|
cp.set('geography', 'elev', elev)
|
|
runway = self.runway.getvalue().strip()
|
|
cp.set('geography', 'runway', runway)
|
|
|
|
cp.add_section('qc')
|
|
cp.set('qc','impact',self.impact)
|
|
cp.set('qc','climate',self.climate)
|
|
cp.set('qc','currentwx',self.currentwx)
|
|
|
|
cp.add_section('sites')
|
|
for tag in self.AltSites:
|
|
if tag != 'ACARS':
|
|
i = self.ident[tag].getvalue().strip().upper()
|
|
else:
|
|
i = self.ident[tag].getvalue().strip()
|
|
cp.set('sites', tag, i)
|
|
|
|
try:
|
|
if not os.path.exists(os.path.dirname(path)):
|
|
os.mkdir(os.path.dirname(path))
|
|
|
|
fp = file(path, 'w')
|
|
fp.write('# %s\n\n' % path)
|
|
cp.write(fp)
|
|
|
|
finally:
|
|
fp.close()
|
|
|
|
msg = 'Updated %s' % path
|
|
self.messagebar().message('systemevent', msg)
|
|
|
|
except Exception, e:
|
|
msg = 'Failed to update %s' % path
|
|
_Logger.exception(msg)
|
|
self.messagebar().message('systemerror', msg)
|
|
|
|
def __makeTemplates(self):
|
|
self.messagebar().resetmessages('systemerror')
|
|
if not self.site.valid():
|
|
msg = 'Invalid site id'
|
|
self.messagebar().message('usererror', msg)
|
|
return
|
|
|
|
id_ = self.site.getvalue().upper()
|
|
duration=24
|
|
if self.tafDuration.valid():
|
|
duration=int(self.tafDuration.getvalue())
|
|
f = []
|
|
for starthour in [int(x[:2]) for x in _Issue_Hours]:
|
|
path = os.path.join('etc', 'tafs', id_, '%02d.template' % starthour)
|
|
if os.path.exists(path):
|
|
continue
|
|
#
|
|
endhour=(starthour+duration)%24
|
|
if endhour == 0:
|
|
endhour = 24
|
|
|
|
if Avn.DTGImplementationSwitch():
|
|
line='%s DD%02d00Z D1%02dD2%02d =\n' % (id_, starthour, starthour,
|
|
endhour)
|
|
else:
|
|
line='%s DD%02d00Z DD%02d%02d =\n' % (id_, starthour, starthour,
|
|
endhour)
|
|
try:
|
|
if not os.path.exists(os.path.dirname(path)):
|
|
os.mkdir(os.path.dirname(path))
|
|
file(path, 'w').write(line)
|
|
f.append(starthour)
|
|
except IOError:
|
|
msg = 'Cannot make template %s' % path
|
|
_Logger.exception(msg)
|
|
self.messagebar().message('systemerror', msg)
|
|
if f:
|
|
msg = 'Template files created'
|
|
self.messagebar().message('userevent', msg)
|
|
|
|
def __editTemplate(self):
|
|
if not hasattr(self, '_textEditor'):
|
|
self._textEditor = EditDialog.Editor(self.interior())
|
|
if not self.site.valid():
|
|
msg = 'Invalid site id'
|
|
self.messagebar().message('usererror', msg)
|
|
return
|
|
ident = self.site.getvalue().upper()
|
|
hour = int(self._tkHour.get()[:2])
|
|
path = os.path.join('etc', 'tafs', ident, '%02d.template' % hour)
|
|
if os.path.exists(path):
|
|
self._textEditor.getFile(path)
|
|
self._textEditor.setworkdir(os.path.dirname(path))
|
|
self._textEditor.display()
|
|
|