3545 lines
128 KiB
Java
3545 lines
128 KiB
Java
/**
|
|
* 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.
|
|
**/
|
|
package com.raytheon.viz.hydro.timeseries;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.BufferedWriter;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
import java.util.TimeZone;
|
|
|
|
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
|
|
import org.eclipse.core.runtime.jobs.IJobChangeListener;
|
|
import org.eclipse.jface.dialogs.MessageDialog;
|
|
import org.eclipse.swt.SWT;
|
|
import org.eclipse.swt.events.SelectionAdapter;
|
|
import org.eclipse.swt.events.SelectionEvent;
|
|
import org.eclipse.swt.graphics.Color;
|
|
import org.eclipse.swt.graphics.Font;
|
|
import org.eclipse.swt.graphics.GC;
|
|
import org.eclipse.swt.graphics.Point;
|
|
import org.eclipse.swt.graphics.RGB;
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
import org.eclipse.swt.layout.GridData;
|
|
import org.eclipse.swt.layout.GridLayout;
|
|
import org.eclipse.swt.printing.PrintDialog;
|
|
import org.eclipse.swt.printing.Printer;
|
|
import org.eclipse.swt.printing.PrinterData;
|
|
import org.eclipse.swt.widgets.Button;
|
|
import org.eclipse.swt.widgets.Combo;
|
|
import org.eclipse.swt.widgets.Composite;
|
|
import org.eclipse.swt.widgets.FileDialog;
|
|
import org.eclipse.swt.widgets.Group;
|
|
import org.eclipse.swt.widgets.Label;
|
|
import org.eclipse.swt.widgets.Layout;
|
|
import org.eclipse.swt.widgets.MessageBox;
|
|
import org.eclipse.swt.widgets.Shell;
|
|
import org.eclipse.swt.widgets.Table;
|
|
import org.eclipse.swt.widgets.TableColumn;
|
|
import org.eclipse.swt.widgets.TableItem;
|
|
import org.eclipse.swt.widgets.Text;
|
|
|
|
import com.raytheon.uf.common.dataplugin.shef.tables.Fcstheight;
|
|
import com.raytheon.uf.common.dataplugin.shef.tables.FcstheightId;
|
|
import com.raytheon.uf.common.dissemination.OUPRequest;
|
|
import com.raytheon.uf.common.dissemination.OUPResponse;
|
|
import com.raytheon.uf.common.dissemination.OfficialUserProduct;
|
|
import com.raytheon.uf.common.ohd.AppsDefaults;
|
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
|
import com.raytheon.uf.common.status.UFStatus;
|
|
import com.raytheon.uf.common.status.UFStatus.Priority;
|
|
import com.raytheon.uf.common.time.SimulatedTime;
|
|
import com.raytheon.uf.common.time.util.TimeUtil;
|
|
import com.raytheon.uf.common.util.Pair;
|
|
import com.raytheon.uf.viz.core.VizApp;
|
|
import com.raytheon.uf.viz.core.auth.UserController;
|
|
import com.raytheon.uf.viz.core.exception.VizException;
|
|
import com.raytheon.uf.viz.core.requests.ThriftClient;
|
|
import com.raytheon.viz.hydro.timeseries.table.DataRecord;
|
|
import com.raytheon.viz.hydro.timeseries.table.ForecastDataAttribute;
|
|
import com.raytheon.viz.hydro.timeseries.table.SiteInfo;
|
|
import com.raytheon.viz.hydro.timeseries.table.TabInfo;
|
|
import com.raytheon.viz.hydro.timeseries.table.TabularData;
|
|
import com.raytheon.viz.hydro.timeseries.util.GroupInfo;
|
|
import com.raytheon.viz.hydro.timeseries.util.StageDischargeUtils;
|
|
import com.raytheon.viz.hydro.timeseries.util.TimeSeriesUtil;
|
|
import com.raytheon.viz.hydrocommon.HydroConstants;
|
|
import com.raytheon.viz.hydrocommon.data.LoadMaxFcst;
|
|
import com.raytheon.viz.hydrocommon.texteditor.TextEditorDlg;
|
|
import com.raytheon.viz.hydrocommon.util.HydroQC;
|
|
import com.raytheon.viz.hydrocommon.util.HydroUtils;
|
|
import com.raytheon.viz.hydrocommon.util.QualityCodeUtil;
|
|
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
|
|
import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
|
|
|
|
/**
|
|
* This class displays the Tabular Time Series dialog for Hydroview.
|
|
*
|
|
* <pre>
|
|
* SOFTWARE HISTORY
|
|
*
|
|
* Date Ticket# Engineer Description
|
|
* ------------- -------- ---------- -------------------------------------------
|
|
* Nov 29, 2007 373 lvenable Initial creation.
|
|
* Oct 20, 2008 1520 mpduff Implement the dialog.
|
|
* Nov 06, 2009 2641/2 mpduff Implement shef encode, review product and
|
|
* clear product buttons.
|
|
* Jul 19, 2010 5964 lbousaidi being able to enter data for empty
|
|
* timeseries
|
|
* Sep 14, 2010 5282 lbousaidi added disposeTabularTS
|
|
* Oct 19, 2010 6785 lbousaidi implement setMissing for forecast data
|
|
* Oct 28, 2010 2640 lbousaidi fixed ProductTime, basistime, and Obstime
|
|
* times updates and other bugs.
|
|
* Jan 31, 2010 5274 bkowal long-running queries are now done
|
|
* asynchronously so that a status indicator
|
|
* can be displayed and so that the interface
|
|
* is not locked up. Extracted the data
|
|
* retrieval logic from the function that
|
|
* updates the interface with the data
|
|
* retrieved.
|
|
* Apr 04, 2011 5966 lbousaidi fixed Save Table to File and to Printer
|
|
* May 27, 2011 9584 jpiatt Modified to not save updated forecast data
|
|
* in rejecteddata table.
|
|
* Sep 09, 2011 9962 lbousaidi reload time series when there is
|
|
* update/insert and highlight the row that
|
|
* was updated.
|
|
* Feb 05,2013 1578 rferrel Changes for non-blocking singleton
|
|
* TimeSeriesDlg. Code clean up for
|
|
* non-blocking dialog.
|
|
* Feb 27,2013 1790 rferrel Bug fix for non-blocking dialogs.
|
|
* Jun 07, 2013 1981 mpduff Set user's id on the OUPRequest as it is
|
|
* now protected.
|
|
* Jul 16, 2013 2088 rferrel Changes for non-blocking TextEditorDlg.
|
|
* Jul 21, 2015 4500 rjpeter Use Number in blind cast.
|
|
* Oct 13, 2015 4933 rferrel Refactored to use selected variables.
|
|
* Oct 27, 2015 4900 mduff Don't transmit SHEF files if in DRT.
|
|
* Nov 06, 2015 17846 lbousaidi change the query so that after QC, the
|
|
* quality_code
|
|
* Feb 17, 2016 14471 amoore Update/insert/modify in Latest obs table is
|
|
* reset from Bad to Good.
|
|
* Jan 29, 2016 5289 tgurney Add missing minimize button in trim
|
|
* Mar 17, 2016 5483 randerso Major GUI cleanup
|
|
* May 02, 2016 5616 randerso Fix parsing of duration value
|
|
* May 11, 2016 5483 bkowal Fix GUI sizing issues.
|
|
* Aug 02, 2016 5785 mduff Fix the output of questionable and missing
|
|
* data.
|
|
* Mar 08, 2017 17643 jdeng Fix errors when deleting/setting data to
|
|
* missing
|
|
* Oct 03, 2017 18261 qzhu Copy time series
|
|
* Apr 12, 2018 6619 randerso Code cleanup.
|
|
* Jun 27, 2018 6748 randerso Removed request type validation as there is
|
|
* only one type now.
|
|
* Jun 28, 2018 6570 dgilling Populate unused QC description text field.
|
|
* Jul 09, 2018 6844 randerso Only set product id to CCCCWRKXXX when
|
|
* inserting record.
|
|
*
|
|
* </pre>
|
|
*
|
|
* @author lvenable
|
|
*
|
|
*/
|
|
public class TabularTimeSeriesDlg extends CaveSWTDialog
|
|
implements ForecastDataAttributeListener, IJobChangeListener {
|
|
private static final IUFStatusHandler statusHandler = UFStatus
|
|
.getHandler(TabularTimeSeriesDlg.class);
|
|
|
|
/** Line terminator to use when reading a line from a shef file. */
|
|
private static final String CARRIAGECONTROL = "\r";
|
|
|
|
/** Maximum number time series to place in a list. */
|
|
private static final int MAX_TS_ON_LIST = 120;
|
|
|
|
/** Quality control value for manual "Good" */
|
|
private static final int QC_MANUAL_PASSED = 121;
|
|
|
|
/** Quality control value for manual "Quest". */
|
|
private static final int QC_MANUAL_QUEST = 122;
|
|
|
|
/** Quality control value for manual "Bad". */
|
|
private static final int QC_MANUAL_FAILED = 123;
|
|
|
|
/** Value used for undefined type source. */
|
|
private static final String UNDEFINED_TYPESOURCE = "??";
|
|
|
|
/** Default value or product ID. */
|
|
private static final String INSERT_PROD_ID = "CCCCWRKXXX";
|
|
|
|
/** The base for all shef file names. */
|
|
private static final String SHEF_FILE_NAME = "shef_product";
|
|
|
|
/** Message title to use when invalid product ID error message. */
|
|
private static final String INVALID_PRODUCT_ID = "Invalid Product ID";
|
|
|
|
/** the Send configuration dialog. */
|
|
private SendConfigDlg sendConfigDlg;
|
|
|
|
/**
|
|
* Simple date formatter.
|
|
*/
|
|
private final SimpleDateFormat sdf;
|
|
|
|
/**
|
|
* Simple date formatter for the forecast basis time.
|
|
*/
|
|
private final SimpleDateFormat prodBasisFmt;
|
|
|
|
/** Date format for shef information. */
|
|
private final SimpleDateFormat shefDateFormat;
|
|
|
|
/** Time format for shef information. */
|
|
private final SimpleDateFormat shefTimeFormat;
|
|
|
|
/**
|
|
* Beginning time.
|
|
*/
|
|
private final Date beginningTime;
|
|
|
|
/**
|
|
* Ending time.
|
|
*/
|
|
private final Date endingTime;
|
|
|
|
/**
|
|
* List all forecasts check box.
|
|
*/
|
|
private Button listAllFcstChk;
|
|
|
|
/**
|
|
* Data table at the top of the dialog.
|
|
*/
|
|
private final List<Pair<String, Integer>> topTableLabels = Arrays.asList(
|
|
new Pair<>("Loc", SWT.LEFT), new Pair<>("PE", SWT.LEFT),
|
|
new Pair<>("Dur", SWT.RIGHT), new Pair<>("TS", SWT.LEFT),
|
|
new Pair<>("E", SWT.LEFT), new Pair<>("BasisTime(Z)", SWT.LEFT));
|
|
|
|
private Table topDataTable;
|
|
|
|
/**
|
|
* Use product time check box.
|
|
*/
|
|
private Button useProductTimeChk;
|
|
|
|
/**
|
|
* Forecast basis time check box.
|
|
*/
|
|
private Button fcstBasisTimeChk;
|
|
|
|
/**
|
|
* Forecast type source check box.
|
|
*/
|
|
private Button fcstTypSrcChk;
|
|
|
|
/**
|
|
* Product time label.
|
|
*/
|
|
private Label productTimeLbl;
|
|
|
|
/**
|
|
* Forecast basis time label.
|
|
*/
|
|
private Label fcstBasisTimeLbl;
|
|
|
|
/**
|
|
* Dummy time to use; based on the simulated time.
|
|
*/
|
|
private Calendar dummyTime;
|
|
|
|
/**
|
|
* Product label ID.
|
|
*/
|
|
private Label productIdLbl;
|
|
|
|
/**
|
|
* Selected location name button.
|
|
*/
|
|
private Label selectedLocNameLbl;
|
|
|
|
/**
|
|
* Selected location information label.
|
|
*/
|
|
private Label selectedLocInfoLbl;
|
|
|
|
/**
|
|
* Selected flood label.
|
|
*/
|
|
private Label selectedFloodLbl;
|
|
|
|
/**
|
|
* Bottom Table control.
|
|
*/
|
|
|
|
private final List<Pair<String, Integer>> bottomTableColumnLabels = Arrays
|
|
.asList(new Pair<>("Value", SWT.RIGHT),
|
|
new Pair<>("Flow", SWT.RIGHT),
|
|
new Pair<>("Stage", SWT.RIGHT),
|
|
new Pair<>("Time(Z)", SWT.LEFT),
|
|
new Pair<>("RV", SWT.RIGHT), new Pair<>("SQ", SWT.RIGHT),
|
|
new Pair<>("QC", SWT.RIGHT),
|
|
new Pair<>("Product", SWT.LEFT),
|
|
new Pair<>("Time", SWT.LEFT),
|
|
new Pair<>("Posted", SWT.LEFT));
|
|
|
|
private Table bottomTable;
|
|
|
|
/**
|
|
* Value text control.
|
|
*/
|
|
private Text valueTF;
|
|
|
|
/**
|
|
* Time text control.
|
|
*/
|
|
private Text timeTF;
|
|
|
|
/**
|
|
* Quality control combo box.
|
|
*/
|
|
private Combo qcCbo;
|
|
|
|
/**
|
|
* Update/Insert button.
|
|
*/
|
|
private Button updateInsertBtn;
|
|
|
|
/**
|
|
* Set Missing button.
|
|
*/
|
|
private Button setMissingBtn;
|
|
|
|
/**
|
|
* Set Quality Control button.
|
|
*/
|
|
private Button setQcBtn;
|
|
|
|
/**
|
|
* Delete button.
|
|
*/
|
|
private Button deleteBtn;
|
|
|
|
/**
|
|
* Product text control.
|
|
*/
|
|
private Text productTF;
|
|
|
|
/** The location id */
|
|
private String lid = null;
|
|
|
|
/** Selected site name */
|
|
private String siteName = null;
|
|
|
|
/** The group info */
|
|
private GroupInfo groupInfo;
|
|
|
|
/** The TabInfo */
|
|
private TabInfo tabInfo = null;
|
|
|
|
/** The current TabInfo */
|
|
private TabInfo currentTabInfo = null;
|
|
|
|
/** The list of data for the bottom data display list */
|
|
private final List<String> modifiedTSList = new ArrayList<>();
|
|
|
|
/** The parent dialog */
|
|
private TimeSeriesDlg parentDialog = null;
|
|
|
|
/** The selected duration. */
|
|
private String dur = null;
|
|
|
|
/** The selected physical element */
|
|
private String pe = null;
|
|
|
|
/** The selected type source */
|
|
private String ts = null;
|
|
|
|
/** The selected extremum. */
|
|
private String extremum = null;
|
|
|
|
/** The selected basis time. */
|
|
private String basisTime = null;
|
|
|
|
/** Date format for the tabular display */
|
|
private static SimpleDateFormat tabularFormat;
|
|
|
|
/** Date format for the database */
|
|
private static SimpleDateFormat dbFormat;
|
|
|
|
/* Setup the format static variables. */
|
|
static {
|
|
tabularFormat = new SimpleDateFormat("MM/dd HH:mm");
|
|
tabularFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
|
|
dbFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
dbFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
}
|
|
|
|
/** List of TabularData objects */
|
|
private List<TabularData> tabularDataList = null;
|
|
|
|
/** The number of records retrieved using the Record Count query **/
|
|
private long ratingRecordCount = 0;
|
|
|
|
/** List of TabInfo objects */
|
|
private List<TabInfo> tabInfoList = new ArrayList<>();
|
|
|
|
/** The original value */
|
|
private double oldValue;
|
|
|
|
/** Printer to use. */
|
|
private Printer printer;
|
|
|
|
/** Printer's line height. */
|
|
private int lineHeight = 0;
|
|
|
|
/** Printer's tab width. */
|
|
private int tabWidth = 0;
|
|
|
|
/** Printer's left margin. */
|
|
private int leftMargin;
|
|
|
|
/** Printer's right margin. */
|
|
private int rightMargin;
|
|
|
|
/** Printer's top margin. */
|
|
private int topMargin;
|
|
|
|
/** Printer's bottom margin. */
|
|
private int bottomMargin;
|
|
|
|
/** Printer's horizontal location for printing. */
|
|
private int x;
|
|
|
|
/** Printer's vertical location for printing. */
|
|
private int y;
|
|
|
|
/** Location in the text that is being printed. */
|
|
private int index;
|
|
|
|
/** Number of characters in the text being printed. */
|
|
private int end;
|
|
|
|
private StringBuilder wordBuffer;
|
|
|
|
private GC gc;
|
|
|
|
private ForecastAttributeDlg fcstAttDlg = null;
|
|
|
|
private ForecastDataAttribute fcstAtt = null;
|
|
|
|
private String whfsProductDir = null;
|
|
|
|
private String shefFileName = null;
|
|
|
|
private TextEditorDlg editor = null;
|
|
|
|
private int pid = HydroConstants.MISSING_VALUE;
|
|
|
|
private boolean updateFlag = false;
|
|
|
|
private int indexSelected = 0;
|
|
|
|
private TimeSeriesDataJobManager tsDataJobManager = null;
|
|
|
|
/** Users can copy time series to one of these types */
|
|
private static String TYPE_SOURCE_FOR_COPY[] = { "FF", "FZ" };
|
|
|
|
private Text qcDescTF;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param parent
|
|
* Parent shell.
|
|
* @param beginningTime
|
|
* Beginning time.
|
|
* @param endingTime
|
|
* Ending time.
|
|
* @param parentDialog
|
|
* Parent dialog
|
|
*/
|
|
public TabularTimeSeriesDlg(Shell parent, Date beginningTime,
|
|
Date endingTime, TimeSeriesDlg parentDialog) {
|
|
super(parent, SWT.DIALOG_TRIM | SWT.MIN,
|
|
CAVE.DO_NOT_BLOCK | CAVE.INDEPENDENT_SHELL);
|
|
setText("Tabular Time Series");
|
|
|
|
this.beginningTime = beginningTime;
|
|
this.endingTime = endingTime;
|
|
this.parentDialog = parentDialog;
|
|
this.tsDataJobManager = new TimeSeriesDataJobManager();
|
|
|
|
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
|
sdf.setTimeZone(TimeUtil.GMT_TIME_ZONE);
|
|
|
|
prodBasisFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
prodBasisFmt.setTimeZone(TimeUtil.GMT_TIME_ZONE);
|
|
|
|
shefDateFormat = new SimpleDateFormat("yyyyMMdd");
|
|
shefDateFormat.setTimeZone(TimeUtil.GMT_TIME_ZONE);
|
|
|
|
shefTimeFormat = new SimpleDateFormat("HHmm");
|
|
shefTimeFormat.setTimeZone(TimeUtil.GMT_TIME_ZONE);
|
|
}
|
|
|
|
@Override
|
|
protected Layout constructShellLayout() {
|
|
// Create the main layout for the shell.
|
|
GridLayout mainLayout = new GridLayout(1, true);
|
|
return mainLayout;
|
|
}
|
|
|
|
@Override
|
|
protected void disposed() {
|
|
// Delete the SHEF encode file if it exists
|
|
if (shefFileName != null) {
|
|
File shefFile = new File(shefFileName);
|
|
if (shefFile.exists()) {
|
|
shefFile.delete();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set up to retrieve selection data.
|
|
*/
|
|
private void scheduleDataRetrieval() {
|
|
shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
|
|
this.topDataTable.setEnabled(false);
|
|
this.extractFormInformation();
|
|
tsDataJobManager.scheduleGetTableData(this, this);
|
|
}
|
|
|
|
@Override
|
|
protected void initializeComponents(Shell shell) {
|
|
setReturnValue(false);
|
|
|
|
// Set to the first on in the list
|
|
tabInfo = tabInfoList.get(0);
|
|
lid = tabInfo.getLid();
|
|
|
|
// load the info about the available time series
|
|
currentTabInfo = new TabInfo();
|
|
currentTabInfo.setBeginTime(tabInfo.getBeginTime());
|
|
currentTabInfo.setEndTime(tabInfo.getEndTime());
|
|
currentTabInfo.setInfoList(tabInfo.getInfoList());
|
|
|
|
// Initialize all of the controls and layouts
|
|
initializeComponents();
|
|
}
|
|
|
|
/**
|
|
* Initialize the dialog components.
|
|
*/
|
|
private void initializeComponents() {
|
|
// Get the dummy time
|
|
dummyTime = TimeUtil.newGmtCalendar();
|
|
Date d = SimulatedTime.getSystemTime().getTime();
|
|
dummyTime.setTime(d);
|
|
|
|
createTopTimeLabels();
|
|
createTopListAndGroup();
|
|
createSelectedInfoLabels();
|
|
createBottomTableControls();
|
|
createEditSelectedGroup();
|
|
createBottomButtonControls();
|
|
addSeparator();
|
|
createCloseButton();
|
|
|
|
tabularLoadTimeseries();
|
|
}
|
|
|
|
/**
|
|
* Create the time labels at the top of the display.
|
|
*/
|
|
private void createTopTimeLabels() {
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Composite timeComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(3, false);
|
|
timeComp.setLayout(gl);
|
|
timeComp.setLayoutData(gd);
|
|
|
|
Label timeZLbl = new Label(timeComp, SWT.NONE);
|
|
timeZLbl.setText("TimeZ:");
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
timeZLbl.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
Label dateTimeLbl = new Label(timeComp, SWT.NONE);
|
|
StringBuilder strBuf = new StringBuilder();
|
|
strBuf.append(sdf.format(beginningTime)).append(" - ")
|
|
.append(sdf.format(endingTime));
|
|
dateTimeLbl.setText(strBuf.toString());
|
|
dateTimeLbl.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
|
|
listAllFcstChk = new Button(timeComp, SWT.CHECK);
|
|
listAllFcstChk.setText("List ALL Forecasts");
|
|
listAllFcstChk.setLayoutData(gd);
|
|
listAllFcstChk.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
tabularLoadTimeseries();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create the list control and the inserted data attributes group container
|
|
* at the top of the display.
|
|
*/
|
|
private void createTopListAndGroup() {
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Composite listGroupComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(2, false);
|
|
listGroupComp.setLayout(gl);
|
|
listGroupComp.setLayoutData(gd);
|
|
|
|
addLabelsAndTopDataList(listGroupComp);
|
|
addInsertedDataGroup(listGroupComp);
|
|
}
|
|
|
|
/**
|
|
* Add the top list control to the display.
|
|
*
|
|
* @param parentComp
|
|
* Parent composite.
|
|
*/
|
|
private void addLabelsAndTopDataList(Composite parentComp) {
|
|
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
Composite topListComp = new Composite(parentComp, SWT.NONE);
|
|
GridLayout gl = new GridLayout(1, false);
|
|
gl.marginWidth = 0;
|
|
topListComp.setLayout(gl);
|
|
topListComp.setLayoutData(gd);
|
|
|
|
topDataTable = new Table(topListComp,
|
|
SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
|
|
topDataTable.setHeaderVisible(true);
|
|
|
|
GC gc = new GC(topDataTable);
|
|
// Estimate width of table text.
|
|
int textWidth = gc
|
|
.textExtent("WWWWW WW WWWW WW W 9999-99-99 99:99:99").x;
|
|
gc.dispose();
|
|
|
|
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
gd.widthHint = textWidth;
|
|
gd.heightHint = topDataTable.getItemHeight() * 8;
|
|
topDataTable.setLayoutData(gd);
|
|
topDataTable.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
topDataSelectionAction();
|
|
}
|
|
});
|
|
|
|
for (Pair<String, Integer> pair : topTableLabels) {
|
|
TableColumn column = new TableColumn(topDataTable,
|
|
pair.getSecond());
|
|
column.setText(pair.getFirst());
|
|
}
|
|
}
|
|
|
|
private void topDataSelectionAction() {
|
|
scheduleDataRetrieval();
|
|
updateSelectedLocInfoLabel();
|
|
updateStationLabel();
|
|
updateFloodStageLabel();
|
|
}
|
|
|
|
/**
|
|
* Add the Inserted Data Group and controls to the display.
|
|
*
|
|
* @param parentComp
|
|
*/
|
|
private void addInsertedDataGroup(Composite parentComp) {
|
|
Group insertedGroup = new Group(parentComp, SWT.NONE);
|
|
GridLayout gl = new GridLayout(2, false);
|
|
insertedGroup.setLayout(gl);
|
|
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
insertedGroup.setLayoutData(gd);
|
|
insertedGroup.setText("Inserted Data Attributes");
|
|
|
|
Composite leftComp = new Composite(insertedGroup, SWT.NONE);
|
|
gl = new GridLayout(1, false);
|
|
gl.marginHeight = 0;
|
|
gl.marginWidth = 0;
|
|
leftComp.setLayout(gl);
|
|
gd = new GridData(SWT.DEFAULT, SWT.FILL, false, true);
|
|
leftComp.setLayoutData(gd);
|
|
|
|
useProductTimeChk = new Button(leftComp, SWT.CHECK);
|
|
useProductTimeChk.setText("Use Product Time/ID:");
|
|
|
|
productTimeLbl = new Label(leftComp, SWT.NONE);
|
|
productTimeLbl.setText(prodBasisFmt.format(dummyTime.getTime()));
|
|
|
|
productIdLbl = new Label(leftComp, SWT.NONE);
|
|
productIdLbl.setText("CCCWRKXXX ");
|
|
|
|
fcstBasisTimeChk = new Button(leftComp, SWT.CHECK);
|
|
fcstBasisTimeChk.setText("Fcst BasisTime:");
|
|
|
|
fcstBasisTimeLbl = new Label(leftComp, SWT.NONE);
|
|
fcstBasisTimeLbl.setText(prodBasisFmt.format(dummyTime.getTime()));
|
|
|
|
Composite rightComp = new Composite(insertedGroup, SWT.NONE);
|
|
gl = new GridLayout(1, false);
|
|
gl.marginHeight = 0;
|
|
gl.marginWidth = 0;
|
|
rightComp.setLayout(gl);
|
|
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
rightComp.setLayoutData(gd);
|
|
|
|
fcstTypSrcChk = new Button(leftComp, SWT.CHECK);
|
|
fcstTypSrcChk.setText("Fcst TypSrc: ??");
|
|
|
|
gd = new GridData(SWT.FILL, SWT.BOTTOM, true, true);
|
|
Button copyFullFcstBtn = new Button(rightComp, SWT.PUSH);
|
|
copyFullFcstBtn.setText("Copy Full\nForecast");
|
|
copyFullFcstBtn.setLayoutData(gd);
|
|
copyFullFcstBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
tabularCopyTS();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.BOTTOM, true, true);
|
|
Button insertDataEditBtn = new Button(leftComp, SWT.PUSH);
|
|
insertDataEditBtn.setText("Edit");
|
|
insertDataEditBtn.setLayoutData(gd);
|
|
insertDataEditBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
if (fcstAttDlg == null) {
|
|
fcstAtt = new ForecastDataAttribute(productIdLbl.getText(),
|
|
productTimeLbl.getText(),
|
|
fcstBasisTimeLbl.getText(),
|
|
new String[] { "FF", "FZ" });
|
|
fcstAttDlg = new ForecastAttributeDlg(shell, fcstAtt,
|
|
TimeUtil.newCalendar(dummyTime),
|
|
TimeUtil.newCalendar(dummyTime));
|
|
fcstAttDlg.addListener(TabularTimeSeriesDlg.this);
|
|
fcstAttDlg.open();
|
|
} else {
|
|
fcstAttDlg.showDialog();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create the information labels located between the 2 list box controls.
|
|
*/
|
|
private void createSelectedInfoLabels() {
|
|
Composite selectedInfoComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(2, false);
|
|
selectedInfoComp.setLayout(gl);
|
|
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
gd.horizontalSpan = 2;
|
|
selectedLocNameLbl = new Label(selectedInfoComp, SWT.NONE);
|
|
selectedLocNameLbl.setLayoutData(gd);
|
|
|
|
gd = new GridData(350, SWT.DEFAULT);
|
|
selectedLocInfoLbl = new Label(selectedInfoComp, SWT.NONE);
|
|
selectedLocInfoLbl.setLayoutData(gd);
|
|
|
|
selectedFloodLbl = new Label(selectedInfoComp, SWT.NONE);
|
|
}
|
|
|
|
/**
|
|
* Create the bottom table and text control below the table.
|
|
*/
|
|
private void createBottomTableControls() {
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Composite bottomListComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(1, false);
|
|
bottomListComp.setLayout(gl);
|
|
bottomListComp.setLayoutData(gd);
|
|
|
|
bottomTable = new Table(bottomListComp,
|
|
SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
|
|
|
|
GC gc = new GC(bottomTable);
|
|
int textWidth = gc.textExtent(
|
|
"00000.00 00000.00 99/99 99:99 WW WW WW WWWWWWWWWW 99/99 99:99 99/99 99:99").x;
|
|
gc.dispose();
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
gd.widthHint = textWidth;
|
|
gd.heightHint = bottomTable.getItemHeight() * 12;
|
|
bottomTable.setLayoutData(gd);
|
|
bottomTable.setHeaderVisible(true);
|
|
for (Pair<String, Integer> pair : bottomTableColumnLabels) {
|
|
TableColumn column = new TableColumn(bottomTable, pair.getSecond());
|
|
column.setText(pair.getFirst());
|
|
}
|
|
bottomTable.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
handleBottomTableSelection();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
qcDescTF = new Text(shell, SWT.BORDER | SWT.READ_ONLY);
|
|
qcDescTF.setLayoutData(gd);
|
|
}
|
|
|
|
/**
|
|
* Create the Edit Selected group container and the associated controls.
|
|
*/
|
|
private void createEditSelectedGroup() {
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Group editSelectedGroup = new Group(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(4, true);
|
|
gl.horizontalSpacing = 10;
|
|
editSelectedGroup.setLayout(gl);
|
|
editSelectedGroup.setLayoutData(gd);
|
|
editSelectedGroup.setText("Edit Selected");
|
|
|
|
// ---------------------------------------
|
|
// Create the top row of controls
|
|
// ---------------------------------------
|
|
Composite comp = new Composite(editSelectedGroup, SWT.NONE);
|
|
gl = new GridLayout(2, false);
|
|
gl.marginWidth = 0;
|
|
comp.setLayout(gl);
|
|
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
|
comp.setLayoutData(gd);
|
|
|
|
Label valueLbl = new Label(comp, SWT.NONE);
|
|
valueLbl.setText("Value:");
|
|
|
|
valueTF = new Text(comp, SWT.BORDER);
|
|
GC gc = new GC(valueTF);
|
|
int textWidth = gc.textExtent("0000000.000000").x;
|
|
gc.dispose();
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
gd.widthHint = textWidth;
|
|
valueTF.setLayoutData(gd);
|
|
|
|
comp = new Composite(editSelectedGroup, SWT.NONE);
|
|
gl = new GridLayout(2, false);
|
|
gl.marginWidth = 0;
|
|
comp.setLayout(gl);
|
|
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
|
gd.horizontalSpan = 2;
|
|
comp.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
Label timeLbl = new Label(comp, SWT.RIGHT);
|
|
timeLbl.setText("Time:");
|
|
timeLbl.setLayoutData(gd);
|
|
|
|
timeTF = new Text(comp, SWT.BORDER);
|
|
gc = new GC(timeTF);
|
|
textWidth = gc.textExtent("0000-00-00 00:00:00").x;
|
|
gc.dispose();
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
gd.widthHint = textWidth;
|
|
timeTF.setLayoutData(gd);
|
|
|
|
comp = new Composite(editSelectedGroup, SWT.NONE);
|
|
gl = new GridLayout(2, false);
|
|
gl.marginWidth = 0;
|
|
comp.setLayout(gl);
|
|
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
|
comp.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
Label qcLbl = new Label(comp, SWT.RIGHT);
|
|
qcLbl.setText("QC:");
|
|
qcLbl.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
qcCbo = new Combo(comp, SWT.DROP_DOWN | SWT.READ_ONLY);
|
|
qcCbo.add("Good");
|
|
qcCbo.add("Quest.");
|
|
qcCbo.add("Bad");
|
|
qcCbo.select(0);
|
|
qcCbo.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
updateInsertBtn = new Button(editSelectedGroup, SWT.NONE);
|
|
updateInsertBtn.setText("Update/Insert Value");
|
|
updateInsertBtn.setLayoutData(gd);
|
|
updateInsertBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
updateFlag = true;
|
|
updateInsertValue();
|
|
updateFlag = false;
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
setMissingBtn = new Button(editSelectedGroup, SWT.NONE);
|
|
setMissingBtn.setText("Set Missing");
|
|
setMissingBtn.setLayoutData(gd);
|
|
setMissingBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
setMissing();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
setQcBtn = new Button(editSelectedGroup, SWT.NONE);
|
|
setQcBtn.setText("Set QC");
|
|
setQcBtn.setLayoutData(gd);
|
|
setQcBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
setQC();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
deleteBtn = new Button(editSelectedGroup, SWT.NONE);
|
|
deleteBtn.setText("Delete");
|
|
deleteBtn.setLayoutData(gd);
|
|
deleteBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
deleteData();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create the bottom control buttons.
|
|
*/
|
|
private void createBottomButtonControls() {
|
|
Composite mainBtnComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(2, false);
|
|
gl.marginWidth = 0;
|
|
mainBtnComp.setLayout(gl);
|
|
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
mainBtnComp.setLayoutData(gd);
|
|
|
|
// --------------------------------------------
|
|
// Buttons on the left side on the composite
|
|
// --------------------------------------------
|
|
Composite leftComp = new Composite(mainBtnComp, SWT.NONE);
|
|
gl = new GridLayout(2, true);
|
|
gl.marginWidth = 0;
|
|
gl.horizontalSpacing = 10;
|
|
leftComp.setLayout(gl);
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
leftComp.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Button shefEncodeBtn = new Button(leftComp, SWT.PUSH);
|
|
shefEncodeBtn.setText("SHEF Encode Selected");
|
|
shefEncodeBtn.setLayoutData(gd);
|
|
shefEncodeBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
tabularShefEncode();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Button clearProductBtn = new Button(leftComp, SWT.PUSH);
|
|
clearProductBtn.setText("Clear Product");
|
|
clearProductBtn.setLayoutData(gd);
|
|
clearProductBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
clearProduct();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Button reviewProductBtn = new Button(leftComp, SWT.PUSH);
|
|
reviewProductBtn.setText("Review Product");
|
|
reviewProductBtn.setLayoutData(gd);
|
|
reviewProductBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
reviewShefEncodedProduct();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Button reviewSendScriptBtn = new Button(leftComp, SWT.PUSH);
|
|
reviewSendScriptBtn.setText("Review Send Script");
|
|
reviewSendScriptBtn.setLayoutData(gd);
|
|
reviewSendScriptBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
if (sendConfigDlg == null || sendConfigDlg.isDisposed()) {
|
|
sendConfigDlg = new SendConfigDlg(shell);
|
|
sendConfigDlg.open();
|
|
} else {
|
|
sendConfigDlg.bringToTop();
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
Button sendProductBtn = new Button(leftComp, SWT.PUSH);
|
|
sendProductBtn.setText("Send Product");
|
|
sendProductBtn.setLayoutData(gd);
|
|
sendProductBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
sendProduct();
|
|
}
|
|
});
|
|
|
|
Composite comp = new Composite(leftComp, SWT.NONE);
|
|
gl = new GridLayout(2, false);
|
|
comp.setLayout(gl);
|
|
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
|
comp.setLayoutData(gd);
|
|
|
|
Label productLbl = new Label(comp, SWT.NONE);
|
|
productLbl.setText("Product:");
|
|
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, false, false);
|
|
productLbl.setLayoutData(gd);
|
|
|
|
productTF = new Text(comp, SWT.BORDER);
|
|
GC gc = new GC(productTF);
|
|
int textWidth = gc.textExtent("WWWWWWWWWW").x;
|
|
gc.dispose();
|
|
|
|
gd = new GridData(SWT.DEFAULT, SWT.DEFAULT);
|
|
gd.widthHint = textWidth;
|
|
productTF.setLayoutData(gd);
|
|
AppsDefaults defaults = AppsDefaults.getInstance();
|
|
String product = defaults.getToken("shefencode_prodid");
|
|
productTF.setText(product);
|
|
|
|
// --------------------------------------------
|
|
// Buttons on the right side on the composite
|
|
// --------------------------------------------
|
|
Composite rightComp = new Composite(mainBtnComp, SWT.NONE);
|
|
gl = new GridLayout(2, false);
|
|
gl.marginWidth = 0;
|
|
gl.horizontalSpacing = 10;
|
|
rightComp.setLayout(gl);
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
|
rightComp.setLayoutData(gd);
|
|
|
|
gd = new GridData(GridData.FILL_VERTICAL);
|
|
gd.verticalSpan = 2;
|
|
Label sepLbl = new Label(rightComp, SWT.SEPARATOR | SWT.VERTICAL);
|
|
sepLbl.setLayoutData(gd);
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, true);
|
|
Button saveTableBtn = new Button(rightComp, SWT.PUSH);
|
|
saveTableBtn.setText("Save Table\nto File");
|
|
saveTableBtn.setLayoutData(gd);
|
|
saveTableBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
saveTable();
|
|
}
|
|
});
|
|
|
|
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, true);
|
|
Button sendTableToPrinterBtn = new Button(rightComp, SWT.PUSH);
|
|
sendTableToPrinterBtn.setText("Send Table\nto Printer");
|
|
sendTableToPrinterBtn.setLayoutData(gd);
|
|
sendTableToPrinterBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
sendTableToPrinter();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add a horizontal separator line to the display.
|
|
*/
|
|
private void addSeparator() {
|
|
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
|
|
Label sepLbl = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
|
|
sepLbl.setLayoutData(gd);
|
|
}
|
|
|
|
/**
|
|
* Create the bottom Close button.
|
|
*/
|
|
private void createCloseButton() {
|
|
Composite centeredComp = new Composite(shell, SWT.NONE);
|
|
GridLayout gl = new GridLayout(1, false);
|
|
centeredComp.setLayout(gl);
|
|
GridData gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
|
gd.horizontalSpan = 2;
|
|
centeredComp.setLayoutData(gd);
|
|
|
|
gd = new GridData(90, SWT.DEFAULT);
|
|
Button closeBtn = new Button(centeredComp, SWT.NONE);
|
|
closeBtn.setText("Close");
|
|
closeBtn.setLayoutData(gd);
|
|
closeBtn.addSelectionListener(new SelectionAdapter() {
|
|
@Override
|
|
public void widgetSelected(SelectionEvent event) {
|
|
close();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Load the data types list
|
|
*/
|
|
private void tabularLoadTimeseries() {
|
|
topDataTable.removeAll();
|
|
modifiedTSList.clear();
|
|
List<SiteInfo> siteInfoList = new ArrayList<>();
|
|
|
|
try {
|
|
/* Get the unique time series defined from the parent info */
|
|
for (TabInfo ti : tabInfoList) {
|
|
List<SiteInfo> peList = ti.getInfoList();
|
|
|
|
updateStationLabel();
|
|
|
|
/*
|
|
* loop on the unique time series defined from the parent info
|
|
*/
|
|
for (int i = 0; i < peList.size(); i++) {
|
|
SiteInfo row = peList.get(i);
|
|
displayTS(row, siteInfoList);
|
|
}
|
|
}
|
|
for (TableColumn column : topDataTable.getColumns()) {
|
|
column.pack();
|
|
}
|
|
|
|
topDataTable.setSelection(0);
|
|
|
|
/* Find the selected types */
|
|
for (int i = 0; i < siteInfoList.size(); i++) {
|
|
SiteInfo siteInfo = siteInfoList.get(i);
|
|
boolean selected = siteInfo.isSelected();
|
|
if (selected) {
|
|
for (int j = 0; j < topDataTable.getItemCount(); j++) {
|
|
TableItem item = topDataTable.getItem(j);
|
|
ts = item.getText(3);
|
|
pe = item.getText(1);
|
|
if (pe.equals(siteInfo.getPe()) && Integer.parseInt(
|
|
item.getText(2).trim()) == siteInfo.getDur()
|
|
&& ts.equals(siteInfo.getTs())
|
|
&& item.getText(4).equals(siteInfo.getExt())) {
|
|
topDataTable.setSelection(j);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (updateFlag) {
|
|
topDataTable.setSelection(indexSelected);
|
|
}
|
|
topDataSelectionAction();
|
|
} catch (Exception ve) {
|
|
statusHandler.handle(Priority.PROBLEM, "Time Series Load", ve);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get table data for the selection.
|
|
*/
|
|
public void getDataForTable() {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
|
|
String tableName = HydroUtils.getTableName(pe, ts);
|
|
boolean forecast = false;
|
|
if (ts.toUpperCase().startsWith("C")
|
|
|| ts.toUpperCase().startsWith("F")) {
|
|
forecast = true;
|
|
}
|
|
|
|
String myBasisTime = basisTime;
|
|
if (myBasisTime != null && "No Data".equalsIgnoreCase(myBasisTime)) {
|
|
myBasisTime = prodBasisFmt.format(dummyTime.getTime());
|
|
}
|
|
|
|
try {
|
|
String where = " where lid = '" + lid + "'";
|
|
|
|
this.ratingRecordCount = dataManager.recordCount("Rating", where);
|
|
|
|
tabularDataList = dataManager.getTabularData(tableName, lid, pe, ts,
|
|
dur, extremum, beginningTime, endingTime, myBasisTime,
|
|
forecast);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "Getting Table Data: ", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use this method to extract the information that we will need to run the
|
|
* data retrieval query. This has to be done outside of the function that
|
|
* actually retrieves the data or we will end up with a "Invalid Thread
|
|
* Access" error.
|
|
*/
|
|
private void extractFormInformation() {
|
|
int selectedIndex = topDataTable.getSelectionIndex();
|
|
TableItem item = topDataTable.getItem(selectedIndex);
|
|
|
|
bottomTable.removeAll();
|
|
|
|
/* Get all selected parts for latter use. */
|
|
|
|
lid = item.getText(0);
|
|
pe = item.getText(1);
|
|
dur = item.getText(2).trim();
|
|
ts = item.getText(3);
|
|
extremum = item.getText(4);
|
|
basisTime = item.getText(5);
|
|
}
|
|
|
|
/**
|
|
* Load the data list.
|
|
*/
|
|
private synchronized void loadDataList() {
|
|
updateStationLabel();
|
|
updateSelectedLocInfoLabel();
|
|
|
|
useProductTimeChk.setEnabled(true);
|
|
useProductTimeChk.setSelection(true);
|
|
|
|
if (tabularDataList == null || tabularDataList.isEmpty()) {
|
|
// if there is no forecast data, don't allow certain actions
|
|
|
|
if (ts.toUpperCase().startsWith("C")
|
|
|| ts.toUpperCase().startsWith("F")) {
|
|
enableDataAttributes(true);
|
|
} else {
|
|
enableDataAttributes(false);
|
|
}
|
|
|
|
enableEditButtons(false);
|
|
TableItem item = new TableItem(bottomTable, SWT.LEFT);
|
|
item.setText(0, "No Data");
|
|
bottomTable.setSelection(0);
|
|
timeTF.setText("");
|
|
valueTF.setText("");
|
|
qcDescTF.setText("");
|
|
qcCbo.select(0);
|
|
|
|
} else {
|
|
bottomTable.removeAll();
|
|
enableEditButtons(true);
|
|
if (ts.toUpperCase().startsWith("C")
|
|
|| ts.toUpperCase().startsWith("F")) {
|
|
fcstTypSrcChk.setEnabled(true);
|
|
fcstBasisTimeChk.setEnabled(true);
|
|
fcstTypSrcChk.setSelection(false);
|
|
fcstBasisTimeChk.setSelection(false);
|
|
} else {
|
|
enableDataAttributes(false);
|
|
}
|
|
|
|
double derivedValue;
|
|
String revision;
|
|
|
|
for (int i = 0; i < tabularDataList.size(); i++) {
|
|
TabularData td = tabularDataList.get(i);
|
|
if (td.getRevision() == 0) {
|
|
revision = "F";
|
|
} else {
|
|
revision = "T";
|
|
}
|
|
|
|
TableItem item = new TableItem(bottomTable, SWT.LEFT);
|
|
|
|
if ("HG".equals(pe)
|
|
|| "HT".equals(pe) && this.ratingRecordCount > 1) {
|
|
if (td.getValue() == HydroConstants.MISSING_VALUE) {
|
|
derivedValue = HydroConstants.MISSING_VALUE;
|
|
} else {
|
|
derivedValue = StageDischargeUtils
|
|
.stage2discharge(td.getLid(), td.getValue());
|
|
}
|
|
item.setText(0, String.format("%6.2f", td.getValue()));
|
|
item.setText(1, String.format("%7.0f", derivedValue));
|
|
item.setText(3, tabularFormat.format(td.getObsTime()));
|
|
item.setText(4, revision);
|
|
item.setText(5, td.getShefQualCode());
|
|
item.setText(6,
|
|
TimeSeriesUtil.buildQcSymbol(td.getQualityCode()));
|
|
item.setText(7, td.getProductId());
|
|
item.setText(8, tabularFormat.format(td.getProductTime()));
|
|
item.setText(9, tabularFormat.format(td.getPostingTime()));
|
|
|
|
} else if ("QR".equals(pe) && this.ratingRecordCount > 1) {
|
|
if (td.getValue() == HydroConstants.MISSING_VALUE) {
|
|
derivedValue = HydroConstants.MISSING_VALUE;
|
|
} else {
|
|
derivedValue = StageDischargeUtils
|
|
.discharge2stage(td.getLid(), td.getValue());
|
|
}
|
|
item.setText(0, String.format("%8.2f", td.getValue()));
|
|
item.setText(2, String.format("%8.0f", derivedValue));
|
|
item.setText(3, tabularFormat.format(td.getObsTime()));
|
|
item.setText(4, revision);
|
|
item.setText(5, td.getShefQualCode());
|
|
item.setText(6,
|
|
TimeSeriesUtil.buildQcSymbol(td.getQualityCode()));
|
|
item.setText(7, td.getProductId());
|
|
item.setText(8, tabularFormat.format(td.getProductTime()));
|
|
item.setText(9, tabularFormat.format(td.getPostingTime()));
|
|
} else {
|
|
item.setText(0, String.format("%8.2f", td.getValue()));
|
|
item.setText(3, tabularFormat.format(td.getObsTime()));
|
|
item.setText(4, revision);
|
|
item.setText(5, td.getShefQualCode());
|
|
item.setText(6,
|
|
TimeSeriesUtil.buildQcSymbol(td.getQualityCode()));
|
|
item.setText(7, td.getProductId());
|
|
item.setText(8, tabularFormat.format(td.getProductTime()));
|
|
item.setText(9, tabularFormat.format(td.getPostingTime()));
|
|
}
|
|
|
|
/*
|
|
* load the list of modified times series and select the first
|
|
* one in the list.
|
|
*/
|
|
TabularData tdSelection = tabularDataList.get(0);
|
|
bottomTable.setSelection(0);
|
|
valueTF.setText(String.valueOf(tdSelection.getValue()));
|
|
timeTF.setText(dbFormat.format(tdSelection.getObsTime()));
|
|
qcDescTF.setText(QualityCodeUtil
|
|
.buildQcDescr(tdSelection.getQualityCode()));
|
|
qcCbo.setData(TimeSeriesUtil
|
|
.buildQcSymbol(tdSelection.getQualityCode()));
|
|
}
|
|
}
|
|
|
|
for (TableColumn column : bottomTable.getColumns()) {
|
|
column.pack();
|
|
}
|
|
|
|
/* determine which columns to hide. */
|
|
if ("HG".equals(pe) || "HT".equals(pe) && this.ratingRecordCount > 1) {
|
|
bottomTable.getColumn(2).setWidth(0);
|
|
} else if ("QR".equals(pe) && this.ratingRecordCount > 1) {
|
|
bottomTable.getColumn(1).setWidth(0);
|
|
} else {
|
|
bottomTable.getColumn(1).setWidth(0);
|
|
bottomTable.getColumn(2).setWidth(0);
|
|
}
|
|
|
|
shell.setCursor(null);
|
|
this.topDataTable.setEnabled(true);
|
|
this.parentDialog.enableTableButton();
|
|
this.parentDialog.enableBothButton();
|
|
}
|
|
|
|
/**
|
|
* Update/Insert the edited value into the database
|
|
*/
|
|
private void updateInsertValue() {
|
|
|
|
TabularData td = null;
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
Date now = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime();
|
|
String selectCheck = bottomTable
|
|
.getItem(bottomTable.getSelectionIndex()).getText(0);
|
|
|
|
if (bottomTable.getSelectionIndex() == -1) {
|
|
td = tabularDataList.get(0);
|
|
} else {
|
|
if (!"No Data".equalsIgnoreCase(selectCheck)) {
|
|
td = tabularDataList.get(bottomTable.getSelectionIndex());
|
|
}
|
|
}
|
|
|
|
if (!tabularDataList.isEmpty()) {
|
|
oldValue = td.getValue();
|
|
}
|
|
|
|
indexSelected = topDataTable.getSelectionIndex();
|
|
String tablename = HydroUtils.getTableName(pe, ts);
|
|
DataRecord dr = new DataRecord();
|
|
|
|
Date newDateTime;
|
|
String newDataTime = timeTF.getText();
|
|
try {
|
|
newDateTime = dbFormat.parse(newDataTime);
|
|
dr.setObsTime(newDateTime);
|
|
} catch (ParseException e) {
|
|
MessageDialog.openError(shell, "Invalid date/time",
|
|
"Invalid date/time entered.\nRequired format: 01-01-2002 12:00:00");
|
|
return;
|
|
}
|
|
|
|
/* code to update an observation */
|
|
if (ts.toUpperCase().startsWith("R")
|
|
|| ts.toUpperCase().startsWith("P")) {
|
|
/* set the update/add structure with data which doesn't change */
|
|
|
|
dr.setLid(lid);
|
|
dr.setPe(pe);
|
|
dr.setDur(Integer.parseInt(dur));
|
|
dr.setTs(ts);
|
|
dr.setExt(extremum);
|
|
/* set posting time to current time */
|
|
dr.setPostingTime(now);
|
|
|
|
/* set the update structure with data from the original entry */
|
|
|
|
if (!tabularDataList.isEmpty()) {
|
|
|
|
dr.setProductId(td.getProductId());
|
|
dr.setProductTime(td.getProductTime());
|
|
dr.setValue(Double.parseDouble(valueTF.getText()));
|
|
|
|
long qualityCode;
|
|
if ("Good".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED,
|
|
td.getQualityCode());
|
|
} else if ("Bad"
|
|
.equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_FAILED,
|
|
td.getQualityCode());
|
|
} else {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_QUEST,
|
|
td.getQualityCode());
|
|
}
|
|
|
|
dr.setQualityCode(qualityCode);
|
|
|
|
} else {
|
|
/* if no data in list, set defaults values. */
|
|
|
|
dr.setProductId(INSERT_PROD_ID);
|
|
dr.setValue(Double.parseDouble(valueTF.getText()));
|
|
dr.setQualityCode(
|
|
TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED, 0));
|
|
dr.setRevision(0);
|
|
newDateTime = now;
|
|
|
|
try {
|
|
Date defaultDate = dbFormat.parse(productTimeLbl.getText());
|
|
dr.setProductTime(defaultDate);
|
|
} catch (ParseException e) {
|
|
statusHandler.error("Parse Error", e);
|
|
}
|
|
|
|
}
|
|
/* always set the shefQualCode with a "M" for Manual edit */
|
|
dr.setShefQualCode("M");
|
|
|
|
/* do the update */
|
|
String where;
|
|
String sql;
|
|
where = createUpdDelWhereObs(dr);
|
|
/* if toggle button ProductTime/ID is checked */
|
|
|
|
if (useProductTimeChk.getSelection()) {
|
|
try {
|
|
Date useProductDate = dbFormat
|
|
.parse(productTimeLbl.getText());
|
|
dr.setProductTime(useProductDate);
|
|
|
|
} catch (ParseException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "Parse Error: " + e);
|
|
}
|
|
}
|
|
|
|
try {
|
|
long recordCount = dataManager.recordCount(tablename, where);
|
|
/* already a record with same key do an update */
|
|
if (recordCount == 1) {
|
|
dr.setRevision(1);
|
|
sql = "update " + tablename + " set value = "
|
|
+ dr.getValue() + ", quality_code = "
|
|
+ dr.getQualityCode() + ", obstime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(newDateTime)
|
|
+ "', postingtime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(
|
|
dr.getPostingTime())
|
|
+ "', product_id = '" + dr.getProductId() + "', "
|
|
+ "producttime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(
|
|
dr.getProductTime())
|
|
+ "', revision = " + dr.getRevision()
|
|
+ ", shef_qual_code = '" + dr.getShefQualCode()
|
|
+ "' ";
|
|
|
|
dataManager.update(sql + where);
|
|
|
|
/*
|
|
* Insert original data into rejected obs table ans set
|
|
* revision to 1
|
|
*/
|
|
dataManager.insertRejectedData(dr);
|
|
dr.setRevision(1);
|
|
|
|
} else {
|
|
/* if no record, insert a new one and set revision to 0 */
|
|
|
|
dr.setProductId(INSERT_PROD_ID);
|
|
dr.setRevision(0);
|
|
dataManager.addDataRecord(tablename, dr);
|
|
|
|
}
|
|
scheduleDataRetrieval();
|
|
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "", e);
|
|
}
|
|
}
|
|
|
|
/* code to insert or update a forecast */
|
|
if (ts.startsWith("F") || ts.startsWith("C")) {
|
|
/*
|
|
* set the update/add structure with data which doesn't change.
|
|
* although the type-source may be changed...
|
|
*/
|
|
|
|
dr.setLid(lid);
|
|
dr.setPe(pe);
|
|
dr.setDur(Integer.parseInt(dur));
|
|
dr.setTs(ts);
|
|
dr.setExt(extremum);
|
|
dr.setPostingTime(now);
|
|
|
|
/*
|
|
* set the update structure with data from the original entry note
|
|
* that the basistime may be changed below...
|
|
*/
|
|
|
|
if (!tabularDataList.isEmpty()) {
|
|
/*
|
|
* read data from the value and time widgets and replace in
|
|
* structure
|
|
*/
|
|
dr.setProductId(td.getProductId());
|
|
dr.setProductTime(td.getProductTime());
|
|
dr.setQualityCode(td.getQualityCode());
|
|
dr.setValue(Double.parseDouble(valueTF.getText()));
|
|
dr.setPostingTime(now);
|
|
|
|
long qualityCode;
|
|
if ("Good".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED,
|
|
td.getQualityCode());
|
|
} else if ("Bad"
|
|
.equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_FAILED,
|
|
td.getQualityCode());
|
|
} else {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_QUEST,
|
|
td.getQualityCode());
|
|
}
|
|
|
|
dr.setQualityCode(qualityCode);
|
|
if (fcstBasisTimeChk.getSelection()) {
|
|
dr.setBasisTime(fcstBasisTimeLbl.getText());
|
|
} else {
|
|
dr.setBasisTime(basisTime);
|
|
}
|
|
|
|
if (fcstTypSrcChk.getSelection() && fcstAtt != null) {
|
|
dr.setTs(fcstAtt.getSelectedTS());
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
* if no data in list, set defaults for product info and for the
|
|
* type source
|
|
*/
|
|
|
|
dr.setProductId(INSERT_PROD_ID);
|
|
dr.setValue(Double.parseDouble(valueTF.getText()));
|
|
dr.setQualityCode(
|
|
TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED, 0));
|
|
|
|
String newDefaultTime = timeTF.getText();
|
|
try {
|
|
newDateTime = dbFormat.parse(newDefaultTime);
|
|
dr.setProductTime(newDateTime);
|
|
dr.setBasisTime(newDefaultTime);
|
|
} catch (ParseException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "Parse error: ", e);
|
|
}
|
|
|
|
newDateTime = now;
|
|
|
|
/* set posting time to current time */
|
|
dr.setPostingTime(now);
|
|
|
|
}
|
|
|
|
/* always set the shefQualCode with a "M" for Manual edit */
|
|
dr.setShefQualCode("M");
|
|
|
|
/* Check if the record exists already */
|
|
String where = createUpdDelWhereFcst(td, dr);
|
|
/* use producTime/ID if checked */
|
|
if (useProductTimeChk.getSelection()) {
|
|
try {
|
|
Date useProductDate = dbFormat
|
|
.parse(productTimeLbl.getText());
|
|
dr.setProductTime(useProductDate);
|
|
|
|
} catch (ParseException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "Parse error: ", e);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* use the info for BasisTime and Type Source if button pressed.
|
|
* these two fields are part of the data key. use a type source if a
|
|
* valid one has been selected.
|
|
*/
|
|
|
|
try {
|
|
if (dataManager.recordCount(tablename, where) == 0) {
|
|
/* add a new record and set revision to 0 */
|
|
dr.setProductId(INSERT_PROD_ID);
|
|
dr.setRevision(0);
|
|
int status = dataManager.addDataRecord(tablename, dr);
|
|
if (status != 1) {
|
|
statusHandler.handle(Priority.PROBLEM, "Data Query:"
|
|
+ " Error inserting forecast record.");
|
|
} else {
|
|
/* successful add of a new forecast record */
|
|
scheduleDataRetrieval();
|
|
}
|
|
|
|
} else {
|
|
/* already a record with same key */
|
|
/* place a copy of this record in the Rejected Data table */
|
|
dr.setValue(oldValue);
|
|
int status = 1;
|
|
if (!ts.startsWith("F")) {
|
|
status = dataManager.insertRejectedData(dr);
|
|
}
|
|
if (status != 1) {
|
|
// error
|
|
statusHandler.handle(Priority.PROBLEM, "Data Query:"
|
|
+ " Error inserting rejected record.");
|
|
}
|
|
|
|
dr.setRevision(1);
|
|
dr.setValue(Double.parseDouble(valueTF.getText()));
|
|
|
|
String sql = null;
|
|
if (useProductTimeChk.getSelection()) {
|
|
sql = "update " + tablename + " set value = "
|
|
+ dr.getValue() + ", quality_code = "
|
|
+ dr.getQualityCode() + ", postingtime = '"
|
|
+ HydroConstants.DATE_FORMAT
|
|
.format(dr.getPostingTime())
|
|
+ "', producttime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(
|
|
dr.getProductTime())
|
|
+ "', revision = " + dr.getRevision() + ", "
|
|
+ "product_id = '" + dr.getProductId() + "', "
|
|
+ " basistime = '" + dr.getBasisTime()
|
|
+ "', shef_qual_code = '" + dr.getShefQualCode()
|
|
+ "' ";
|
|
} else {
|
|
|
|
sql = "update " + tablename + " set value = "
|
|
+ dr.getValue() + ", quality_code = "
|
|
+ dr.getQualityCode() + ", postingtime = '"
|
|
+ HydroConstants.DATE_FORMAT
|
|
.format(dr.getPostingTime())
|
|
+ "', producttime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(newDateTime)
|
|
+ "', revision = " + dr.getRevision() + ", "
|
|
+ "shef_qual_code = '" + dr.getShefQualCode()
|
|
+ "' ";
|
|
|
|
}
|
|
|
|
status = dataManager.update(sql + where);
|
|
|
|
if (status != 1) {
|
|
statusHandler.handle(Priority.PROBLEM, "Data Query:"
|
|
+ " Error inserting forecast record.");
|
|
}
|
|
|
|
}
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:" + " Error inserting forecast data.", e);
|
|
}
|
|
|
|
/* call Load Max Forecast if update or insert of H or Q PE's */
|
|
if (pe.toUpperCase().startsWith("H")
|
|
|| pe.toUpperCase().startsWith("Q")) {
|
|
try {
|
|
LoadMaxFcst.loadMaxFcstItem(lid, pe, ts);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:"
|
|
+ " Error inserting max forecast record.",
|
|
e);
|
|
}
|
|
}
|
|
} else {
|
|
/*
|
|
* code for inserting/updating latestobsvalue table, if not forecast
|
|
*/
|
|
updateInsertLatestObsValue(td, dataManager, now, dr, newDateTime);
|
|
}
|
|
/* reload list of timeseries */
|
|
scheduleDataRetrieval();
|
|
tabularLoadTimeseries();
|
|
}
|
|
|
|
/**
|
|
* Update/Insert the edited value into the latestobsvalue table, if newer
|
|
* than the existing record.
|
|
*
|
|
* @param tabularData
|
|
* tabular data.
|
|
* @param dataManager
|
|
* data manager.
|
|
* @param postingTime
|
|
* posting time to use.
|
|
* @param dataRecord
|
|
* data record to use/update with information.
|
|
* @param obsTime
|
|
* observation time to use.
|
|
*/
|
|
private void updateInsertLatestObsValue(TabularData tabularData,
|
|
TimeSeriesDataManager dataManager, Date postingTime,
|
|
DataRecord dataRecord, Date obsTime) {
|
|
String tablename = "latestobsvalue";
|
|
|
|
/* set the update/add structure with data which doesn't change */
|
|
dataRecord.setLid(lid);
|
|
dataRecord.setPe(pe);
|
|
dataRecord.setDur(Integer.parseInt(dur));
|
|
dataRecord.setTs(ts);
|
|
dataRecord.setExt(extremum);
|
|
/* set posting time to current time */
|
|
dataRecord.setPostingTime(postingTime);
|
|
|
|
/* set the update structure with data from the original entry */
|
|
|
|
if (!tabularDataList.isEmpty()) {
|
|
|
|
dataRecord.setProductId(tabularData.getProductId());
|
|
dataRecord.setProductTime(tabularData.getProductTime());
|
|
dataRecord.setValue(Double.parseDouble(valueTF.getText()));
|
|
|
|
long qualityCode;
|
|
if ("Good".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED,
|
|
tabularData.getQualityCode());
|
|
} else if ("Bad".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_FAILED,
|
|
tabularData.getQualityCode());
|
|
} else {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_QUEST,
|
|
tabularData.getQualityCode());
|
|
}
|
|
|
|
dataRecord.setQualityCode(qualityCode);
|
|
|
|
} else {
|
|
/* if no data in list, set defaults values. */
|
|
|
|
dataRecord.setProductId(INSERT_PROD_ID);
|
|
dataRecord.setValue(Double.parseDouble(valueTF.getText()));
|
|
dataRecord.setQualityCode(
|
|
TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED, 0));
|
|
dataRecord.setRevision(0);
|
|
obsTime = postingTime;
|
|
|
|
try {
|
|
Date defaultDate = dbFormat.parse(productTimeLbl.getText());
|
|
dataRecord.setProductTime(defaultDate);
|
|
} catch (ParseException e) {
|
|
statusHandler.error("Parse Error: Could not parse ["
|
|
+ productTimeLbl.getText() + "]", e);
|
|
}
|
|
|
|
}
|
|
/* always set the shefQualCode with a "M" for Manual edit */
|
|
dataRecord.setShefQualCode("M");
|
|
|
|
/* do the update */
|
|
String whereExists = createWhereExistsLatestObsValue(dataRecord);
|
|
String whereOlderExists = createOlderThanWhereLatestObsValue(
|
|
dataRecord);
|
|
/* if toggle button ProductTime/ID is checked */
|
|
|
|
if (useProductTimeChk.getSelection()) {
|
|
try {
|
|
Date useProductDate = dbFormat.parse(productTimeLbl.getText());
|
|
dataRecord.setProductTime(useProductDate);
|
|
|
|
} catch (ParseException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Parse Error: Could not parse ["
|
|
+ productTimeLbl.getText() + "]",
|
|
e);
|
|
}
|
|
}
|
|
|
|
try {
|
|
long existingRecordCount = dataManager.recordCount(tablename,
|
|
whereExists);
|
|
long olderRecordCount = dataManager.recordCount(tablename,
|
|
whereOlderExists);
|
|
/* already a record with same key that is older */
|
|
if (olderRecordCount == 1) {
|
|
dataRecord.setRevision(1);
|
|
String updateSQL = "update " + tablename + " set value = "
|
|
+ dataRecord.getValue() + ", quality_code = "
|
|
+ dataRecord.getQualityCode() + ", obstime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(obsTime)
|
|
+ "', postingtime = '"
|
|
+ HydroConstants.DATE_FORMAT
|
|
.format(dataRecord.getPostingTime())
|
|
+ "', product_id = '" + dataRecord.getProductId()
|
|
+ "', " + "producttime = '"
|
|
+ HydroConstants.DATE_FORMAT.format(
|
|
dataRecord.getProductTime())
|
|
+ "', revision = " + dataRecord.getRevision()
|
|
+ ", shef_qual_code = '" + dataRecord.getShefQualCode()
|
|
+ "' ";
|
|
|
|
String query = updateSQL + whereExists;
|
|
try {
|
|
dataManager.update(query);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Failed to execute query [" + query + "]", e);
|
|
}
|
|
} else if (existingRecordCount == 0) {
|
|
/*
|
|
* if no record, insert a new one and set revision to 0
|
|
*/
|
|
try {
|
|
dataRecord.setProductId(INSERT_PROD_ID);
|
|
dataRecord.setRevision(0);
|
|
/*
|
|
* addDataRecord used -1 for probability. For DR 18261, the
|
|
* probability needs to be passed into addDataRecord
|
|
*/
|
|
|
|
dataManager.addDataRecord(tablename, dataRecord);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Failed to add data record to table [" + tablename
|
|
+ "]",
|
|
e);
|
|
}
|
|
}
|
|
scheduleDataRetrieval();
|
|
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Failed to get record count for table [" + tablename + "]",
|
|
e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets just the value of the selected row to missing.
|
|
*/
|
|
private void setMissing() {
|
|
Double origVal = 0.0;
|
|
String checkSelect = bottomTable
|
|
.getItem(bottomTable.getSelectionIndex()).getText(0);
|
|
|
|
if (bottomTable.getSelectionCount() == 0
|
|
|| "No Data".equalsIgnoreCase(checkSelect)) {
|
|
|
|
return;
|
|
}
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
Date postTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
|
|
.getTime();
|
|
|
|
String tablename = HydroUtils.getTableName(pe, ts);
|
|
|
|
DataRecord dr = new DataRecord();
|
|
int[] selectionIndices = bottomTable.getSelectionIndices();
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
List<DataRecord> dataRecordList = new ArrayList<>();
|
|
|
|
for (int selectionIndice : selectionIndices) {
|
|
TabularData td = tabularDataList.get(selectionIndice);
|
|
|
|
/* set the update structure with data which doesn't change */
|
|
dr = new DataRecord();
|
|
dr.setLid(lid);
|
|
dr.setPe(pe);
|
|
dr.setDur(Integer.parseInt(dur));
|
|
dr.setTs(ts);
|
|
dr.setExt(extremum);
|
|
dr.setPostingTime(postTime);
|
|
|
|
/* set the update structure with data from the original entry */
|
|
dr.setProductId(td.getProductId());
|
|
dr.setProductTime(td.getProductTime());
|
|
dr.setObsTime(td.getObsTime());
|
|
origVal = td.getValue();
|
|
|
|
/* Set value to MISSING */
|
|
dr.setValue(HydroConstants.MISSING_VALUE);
|
|
|
|
/* set the shefQualCode with a "M" for Manual edit */
|
|
dr.setShefQualCode("M");
|
|
|
|
dr.setQualityCode(TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED,
|
|
td.getQualityCode()));
|
|
|
|
dr.setRevision((short) 1);
|
|
|
|
String sql = "update " + tablename + " set value = "
|
|
+ HydroConstants.MISSING_VALUE
|
|
+ ", revision= 1, shef_qual_code = 'M' , quality_code= '"
|
|
+ dr.getQualityCode() + "' " + ", postingtime= '"
|
|
+ HydroConstants.DATE_FORMAT.format(postTime) + "' ";
|
|
|
|
/* code to update an observation to MISSING */
|
|
if (ts.toUpperCase().startsWith("R")
|
|
|| ts.toUpperCase().startsWith("P")) {
|
|
sb.append(sql);
|
|
String where = createUpdDelWhereObs(dr);
|
|
sb.append(where);
|
|
}
|
|
|
|
/* code to update a forecast to MISSING */
|
|
if (ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) {
|
|
|
|
dr.setBasisTime(basisTime);
|
|
|
|
sb.append(sql);
|
|
String where = createUpdDelWhereFcst(td, dr);
|
|
sb.append(where);
|
|
}
|
|
dataRecordList.add(dr);
|
|
}
|
|
|
|
try {
|
|
int status = dataManager.update(sb.toString());
|
|
if (status > 0) {
|
|
/*
|
|
* Data updated successfully Add data record to rejected data
|
|
*/
|
|
status = dataManager.insertRejectedData(dataRecordList,
|
|
origVal);
|
|
}
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:" + " Error updating records.", e);
|
|
}
|
|
|
|
/* call Load Max Forecast if update of H or Q PE's */
|
|
if (ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) {
|
|
try {
|
|
LoadMaxFcst.loadMaxFcstItem(lid, pe, ts);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:" + " Error loading Max Forecast Table.",
|
|
e);
|
|
}
|
|
|
|
}
|
|
|
|
scheduleDataRetrieval();
|
|
}
|
|
|
|
/* From tabular_show.c */
|
|
/**
|
|
* Delete the selected record(s) from the database
|
|
*/
|
|
private void deleteData() {
|
|
Double origVal = 0.0;
|
|
String checkSelect = bottomTable
|
|
.getItem(bottomTable.getSelectionIndex()).getText(0);
|
|
|
|
if (bottomTable.getSelectionCount() == 0
|
|
|| "No Data".equalsIgnoreCase(checkSelect)) {
|
|
return;
|
|
}
|
|
|
|
boolean choice = MessageDialog.openConfirm(shell, "Delete Confirmation",
|
|
"Do you wish to delete this record?");
|
|
|
|
/* If true then delete the record */
|
|
if (choice) {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager
|
|
.getInstance();
|
|
List<String> queryList = new ArrayList<>();
|
|
List<DataRecord> dataRecordList = new ArrayList<>();
|
|
|
|
String tablename = HydroUtils.getTableName(pe, ts);
|
|
|
|
/* Loop through the data values selected and delete each one */
|
|
int[] selectionIndices = bottomTable.getSelectionIndices();
|
|
|
|
for (int selectionIndice : selectionIndices) {
|
|
TabularData td = tabularDataList.get(selectionIndice);
|
|
DataRecord dr = new DataRecord();
|
|
|
|
dr.setLid(lid);
|
|
dr.setPe(pe.toUpperCase());
|
|
dr.setDur(Integer.parseInt(dur));
|
|
dr.setTs(ts);
|
|
dr.setExt(extremum);
|
|
dr.setPostingTime(td.getPostingTime());
|
|
|
|
/* set the update structure with data from the original entry */
|
|
dr.setProductId(td.getProductId());
|
|
dr.setProductTime(td.getProductTime());
|
|
dr.setObsTime(td.getObsTime());
|
|
dr.setShefQualCode(td.getShefQualCode());
|
|
dr.setQualityCode(td.getQualityCode());
|
|
origVal = td.getValue();
|
|
|
|
/**********
|
|
* This part is for OBSERVED or PROCCESSED data
|
|
**********/
|
|
if (ts.toUpperCase().startsWith("R")
|
|
|| ts.toUpperCase().startsWith("P")) {
|
|
String where = createUpdDelWhereObs(dr);
|
|
queryList.add("delete from " + tablename + " " + where);
|
|
|
|
/* if precip then delete from curprecip table as well */
|
|
if (dr.getPe().startsWith("P") && !dr.getPe().endsWith("A")
|
|
&& !dr.getPe().endsWith("D")
|
|
&& !dr.getPe().endsWith("E")
|
|
&& !dr.getPe().endsWith("L")) {
|
|
if (dr.getPe().endsWith("P")) {
|
|
queryList.add("delete from curpp " + where);
|
|
// dataManager.deleteRecord("curpp", where);
|
|
}
|
|
}
|
|
|
|
dataRecordList.add(dr);
|
|
/* copy the deleted record to RejectedData */
|
|
|
|
}
|
|
|
|
/********** This part is for FORECAST data **********/
|
|
if (ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) {
|
|
|
|
dr.setBasisTime(basisTime);
|
|
/* Delete all rows that have been selected */
|
|
String where = createUpdDelWhereFcst(td, dr);
|
|
queryList.add("delete from " + tablename + " " + where);
|
|
|
|
/* copy the deleted record to RejectedData */
|
|
dataRecordList.add(dr);
|
|
}
|
|
|
|
/********** This part is for latestobsvalue data ****/
|
|
String where = createUpdDelWhereObs(dr);
|
|
queryList.add("delete from latestobsvalue" + " " + where);
|
|
}
|
|
|
|
// execute the queries
|
|
try {
|
|
dataManager.deleteRecords(queryList);
|
|
dataManager.insertRejectedData(dataRecordList, origVal);
|
|
} catch (VizException e1) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:" + " Error Deleting records.", e1);
|
|
}
|
|
|
|
/*
|
|
* if height or discharge then calculate new RiverStatus as well
|
|
*/
|
|
if (pe.toUpperCase().startsWith("H")
|
|
|| pe.toUpperCase().startsWith("Q")) {
|
|
String command = String.format(
|
|
"load_obs_river('%s', '%s', '%s')", lid, pe, ts);
|
|
|
|
try {
|
|
dataManager.execFunction(command);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:"
|
|
+ " An error occurred executing load_obs_river function",
|
|
e);
|
|
}
|
|
}
|
|
if (ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) {
|
|
if (pe.toUpperCase().startsWith("H")
|
|
|| pe.toUpperCase().startsWith("Q")) {
|
|
|
|
try {
|
|
LoadMaxFcst.loadMaxFcstItem(lid, pe, ts);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Data Query:"
|
|
+ " An error occurred executing loadMaxFcst function",
|
|
e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
scheduleDataRetrieval();
|
|
}
|
|
|
|
/**
|
|
* Set the QC value for the selected record
|
|
*/
|
|
private void setQC() {
|
|
String checkSelect = bottomTable
|
|
.getItem(bottomTable.getSelectionIndex()).getText(0);
|
|
|
|
if (bottomTable.getSelectionCount() == 0
|
|
|| "No Data".equalsIgnoreCase(checkSelect)) {
|
|
return;
|
|
}
|
|
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
Date postTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
|
|
.getTime();
|
|
|
|
String tablename = HydroUtils.getTableName(pe, ts);
|
|
|
|
int[] selectionIndices = bottomTable.getSelectionIndices();
|
|
|
|
DataRecord dr = new DataRecord();
|
|
|
|
/* code to update an observation qc info */
|
|
for (int selectionIndice : selectionIndices) {
|
|
TabularData td = tabularDataList.get(selectionIndice);
|
|
|
|
/* set the update structure with data which doesn't change */
|
|
dr.setLid(lid);
|
|
dr.setPe(pe.toUpperCase());
|
|
dr.setDur(Integer.parseInt(dur));
|
|
dr.setTs(ts.toUpperCase());
|
|
dr.setExt(extremum.toUpperCase());
|
|
dr.setPostingTime(postTime);
|
|
|
|
/* set the update structure with data from the original entry */
|
|
dr.setProductId(td.getProductId());
|
|
dr.setProductTime(td.getProductTime());
|
|
dr.setObsTime(td.getObsTime());
|
|
|
|
/* set the shefQualCode with a "M" for Manual edit */
|
|
dr.setShefQualCode("M");
|
|
dr.setRevision((short) 1);
|
|
|
|
long qualityCode;
|
|
if ("Good".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_PASSED,
|
|
td.getQualityCode());
|
|
} else if ("Bad".equals(qcCbo.getItem(qcCbo.getSelectionIndex()))) {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_FAILED,
|
|
td.getQualityCode());
|
|
} else {
|
|
qualityCode = TimeSeriesUtil.setQcCode(QC_MANUAL_QUEST,
|
|
td.getQualityCode());
|
|
}
|
|
dr.setQualityCode(qualityCode);
|
|
|
|
if (ts.toUpperCase().startsWith("R")
|
|
|| ts.toUpperCase().startsWith("P")) {
|
|
|
|
/* do the update */
|
|
String where = createUpdDelWhereObs(dr);
|
|
String sql = "update " + tablename + " set quality_code= "
|
|
+ dr.getQualityCode() + ",revision= " + dr.getRevision()
|
|
+ ", postingtime= '"
|
|
+ HydroConstants.DATE_FORMAT.format(dr.getPostingTime())
|
|
+ "' ";
|
|
int status;
|
|
try {
|
|
status = dataManager.update(sql + where);
|
|
if (status != 1) {
|
|
throw new VizException("Error Updating QC value");
|
|
}
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Updating QC value: ", e);
|
|
}
|
|
}
|
|
|
|
if (ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) {
|
|
|
|
dr.setBasisTime(basisTime);
|
|
|
|
/* do an update */
|
|
|
|
String where = createUpdDelWhereFcst(td, dr);
|
|
|
|
String sql = "update " + tablename + " set quality_code = "
|
|
+ dr.getQualityCode() + ", revision= "
|
|
+ dr.getRevision() + ", postingtime= '"
|
|
+ HydroConstants.DATE_FORMAT.format(dr.getPostingTime())
|
|
+ "' ";
|
|
|
|
int status;
|
|
try {
|
|
status = dataManager.update(sql + where);
|
|
if (status > 0) {
|
|
/*
|
|
* Data updated successfully Add data record to rejected
|
|
* data
|
|
*/
|
|
status = dataManager.insertRejectedData(dr);
|
|
}
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Inserted Rejected Data: ", e);
|
|
}
|
|
|
|
}
|
|
}
|
|
scheduleDataRetrieval();
|
|
}
|
|
|
|
/**
|
|
* Update the edit widgets upon selection of a data record
|
|
*/
|
|
private void handleBottomTableSelection() {
|
|
int index = bottomTable.getSelectionIndex();
|
|
if (!tabularDataList.isEmpty()) {
|
|
TabularData td = tabularDataList.get(index);
|
|
valueTF.setText(String.valueOf(td.getValue()));
|
|
timeTF.setText(dbFormat.format(td.getObsTime()));
|
|
qcDescTF.setText(QualityCodeUtil.buildQcDescr(td.getQualityCode()));
|
|
|
|
if (TimeSeriesUtil.buildQcSymbol(td.getQualityCode()) == "G") {
|
|
qcCbo.select(0);
|
|
} else if (TimeSeriesUtil
|
|
.buildQcSymbol(td.getQualityCode()) == "B") {
|
|
qcCbo.select(2);
|
|
} else {
|
|
qcCbo.select(1);
|
|
}
|
|
/* set default value when there is no Data */
|
|
} else {
|
|
double noDatavalue = HydroConstants.MISSING_VALUE;
|
|
enableEditButtons(true);
|
|
timeTF.setText(prodBasisFmt.format(dummyTime.getTime()));
|
|
valueTF.setText(String.valueOf(noDatavalue));
|
|
qcDescTF.setText("");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Save the table data in a text file
|
|
*/
|
|
private void saveTable() {
|
|
String text = createTableText();
|
|
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
|
|
String filename = dialog.open();
|
|
if (filename == null) {
|
|
return;
|
|
}
|
|
|
|
try (BufferedWriter out = new BufferedWriter(
|
|
new FileWriter(filename))) {
|
|
out.write(text);
|
|
} catch (IOException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "Saving Table: ", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle the print table selection
|
|
*/
|
|
private void sendTableToPrinter() {
|
|
final String text = createTableText();
|
|
if (text != null) {
|
|
PrintDialog dialog = new PrintDialog(shell, SWT.NONE);
|
|
PrinterData data = dialog.open();
|
|
|
|
if (data == null) {
|
|
return;
|
|
}
|
|
|
|
printer = new Printer(data);
|
|
|
|
/*
|
|
* Do the printing in a background thread so that spooling does not
|
|
* freeze the UI.
|
|
*/
|
|
Thread printingThread = new Thread("PrintTable") {
|
|
@Override
|
|
public void run() {
|
|
print(printer, text);
|
|
printer.dispose();
|
|
}
|
|
};
|
|
printingThread.start();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the text to the printer
|
|
*
|
|
* @param printer
|
|
* The printer
|
|
* @param text
|
|
* The text to print
|
|
*/
|
|
private void print(Printer printer, String text) {
|
|
if (printer.startJob("Text")) {
|
|
Rectangle clientArea = printer.getClientArea();
|
|
Rectangle trim = printer.computeTrim(0, 0, 0, 0);
|
|
Point dpi = printer.getDPI();
|
|
// one inch from left side of paper
|
|
leftMargin = dpi.x + trim.x;
|
|
// one inch from right side of paper
|
|
rightMargin = clientArea.width - dpi.x + trim.x + trim.width;
|
|
// one inch from top edge of paper
|
|
topMargin = dpi.y + trim.y;
|
|
// one inch from bottom edge of paper
|
|
bottomMargin = clientArea.height - dpi.y + trim.y + trim.height;
|
|
|
|
// Create a buffer for computing tab width.
|
|
int tabSize = 4;
|
|
StringBuilder tabBuffer = new StringBuilder(tabSize);
|
|
for (int i = 0; i < tabSize; i++) {
|
|
tabBuffer.append(' ');
|
|
}
|
|
String tabs = tabBuffer.toString();
|
|
|
|
/*
|
|
* Create printer GC, and create and set the printer font &
|
|
* foreground color.
|
|
*/
|
|
gc = new GC(printer);
|
|
|
|
Font printerFont = new Font(printer, "Monospace", 8, SWT.NORMAL);
|
|
|
|
Color printerForegroundColor = new Color(printer, new RGB(0, 0, 0));
|
|
Color printerBackgroundColor = new Color(printer,
|
|
new RGB(255, 255, 255));
|
|
|
|
gc.setFont(printerFont);
|
|
gc.setForeground(printerForegroundColor);
|
|
gc.setBackground(printerBackgroundColor);
|
|
tabWidth = gc.stringExtent(tabs).x;
|
|
lineHeight = gc.getFontMetrics().getHeight();
|
|
|
|
/* Print text to current gc using word wrap */
|
|
printText(text);
|
|
|
|
printer.endJob();
|
|
|
|
/* Cleanup graphics resources used in printing */
|
|
printerFont.dispose();
|
|
printerForegroundColor.dispose();
|
|
printerBackgroundColor.dispose();
|
|
gc.dispose();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the text to be saved/printed
|
|
*
|
|
* @return the formated text
|
|
*/
|
|
private String createTableText() {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
boolean ratingCurveExists = false;
|
|
double derivedValue = HydroConstants.MISSING_VALUE;
|
|
String timeValue = null;
|
|
String prodTime = null;
|
|
String postTime = null;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("Beginning Time(Z): " + dbFormat.format(beginningTime)
|
|
+ "\n");
|
|
sb.append("Ending Time(Z): " + dbFormat.format(endingTime) + "\n");
|
|
|
|
String myBasisTime = basisTime;
|
|
if (myBasisTime != null && "No Data".equalsIgnoreCase(myBasisTime)) {
|
|
myBasisTime = "";
|
|
}
|
|
|
|
sb.append("Station Identifier: " + lid + "\n");
|
|
sb.append("Physical Element: " + pe + "\n");
|
|
sb.append("Duration: " + dur + "\n");
|
|
sb.append("SHEF Type Source: " + ts + "\n");
|
|
sb.append("SHEF Extremum: " + extremum + "\n");
|
|
|
|
if (ts.startsWith("F") || ts.startsWith("C")) {
|
|
sb.append("Basis Time(Z): " + myBasisTime + "\n");
|
|
}
|
|
|
|
String where = " where lid = '" + lid.toUpperCase() + "'";
|
|
|
|
try {
|
|
if (("HG".equals(pe) || "HT".equals(pe))
|
|
&& dataManager.recordCount("Rating", where) > 1) {
|
|
sb.append("\n");
|
|
sb.append(" Derived R S Q\n");
|
|
sb.append(
|
|
" Value Flow Time(Z) V Q C Product Time Posted\n");
|
|
sb.append(
|
|
"-------- -------- ----------- - - - ---------- ----------- -----------\n");
|
|
ratingCurveExists = true;
|
|
} else if ("QR".equals(pe)
|
|
&& dataManager.recordCount("Rating", where) > 1) {
|
|
sb.append("\n");
|
|
sb.append(" Derived R S Q\n");
|
|
sb.append(
|
|
" Value Stage Time(Z) V Q C Product Time Posted\n");
|
|
sb.append(
|
|
"-------- -------- ----------- - - - ---------- ----------- -----------\n");
|
|
ratingCurveExists = true;
|
|
} else {
|
|
sb.append("\n");
|
|
sb.append(" R S Q\n");
|
|
sb.append(
|
|
" Value Time(Z) V Q C Product Time Posted\n");
|
|
sb.append(
|
|
"-------- ----------- - - - ---------- ----------- -----------\n");
|
|
ratingCurveExists = false;
|
|
}
|
|
|
|
/*
|
|
* For both observed and Forecast data
|
|
*/
|
|
if (!tabularDataList.isEmpty()) {
|
|
for (TabularData data : tabularDataList) {
|
|
if (ts.startsWith("F") || ts.startsWith("C")) {
|
|
timeValue = tabularFormat.format(data.getObsTime());
|
|
} else {
|
|
timeValue = tabularFormat.format(data.getObsTime());
|
|
}
|
|
prodTime = tabularFormat.format(data.getProductTime());
|
|
postTime = tabularFormat.format(data.getPostingTime());
|
|
String qcSymbol = TimeSeriesUtil
|
|
.buildQcSymbol(data.getQualityCode());
|
|
|
|
String revision;
|
|
if (data.getRevision() == 1) {
|
|
revision = "T";
|
|
} else {
|
|
revision = "F";
|
|
}
|
|
|
|
if (("HG".equals(pe) || "HT".equals(pe))
|
|
&& ratingCurveExists) {
|
|
if (data.getValue() == HydroConstants.MISSING_VALUE) {
|
|
derivedValue = HydroConstants.MISSING_VALUE;
|
|
} else {
|
|
derivedValue = StageDischargeUtils
|
|
.stage2discharge(lid, data.getValue());
|
|
}
|
|
sb.append(String.format(
|
|
"%8.2f %8.0f %11s %s %1s %1s %10s %11s %11s\n",
|
|
data.getValue(), derivedValue, timeValue,
|
|
revision, data.getShefQualCode(), qcSymbol,
|
|
data.getProductId(), prodTime, postTime));
|
|
} else if ("QR".equals(pe) && ratingCurveExists) {
|
|
if (data.getValue() == HydroConstants.MISSING_VALUE) {
|
|
derivedValue = HydroConstants.MISSING_VALUE;
|
|
} else {
|
|
derivedValue = StageDischargeUtils
|
|
.discharge2stage(lid, data.getValue());
|
|
}
|
|
sb.append(String.format(
|
|
"%8.2f %8.2f %11s %s %1s %1s %10s %11s %11s\n",
|
|
data.getValue(), derivedValue, timeValue,
|
|
revision, data.getShefQualCode(), qcSymbol,
|
|
data.getProductId(), prodTime, postTime));
|
|
} else {
|
|
sb.append(String.format(
|
|
"%8.2f %11s %s %1s %1s %10s %11s %11s\n",
|
|
data.getValue(), timeValue, revision,
|
|
data.getShefQualCode(), qcSymbol,
|
|
data.getProductId(), prodTime, postTime));
|
|
}
|
|
}
|
|
} else {
|
|
sb.append("\nNO data for the parameters defined above.\n");
|
|
}
|
|
|
|
return sb.toString();
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM, "", e);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Print the text
|
|
*
|
|
* @param text
|
|
* The text to be printed
|
|
*/
|
|
private void printText(String text) {
|
|
printer.startPage();
|
|
wordBuffer = new StringBuilder();
|
|
x = leftMargin;
|
|
y = topMargin;
|
|
index = 0;
|
|
end = text.length();
|
|
while (index < end) {
|
|
char c = text.charAt(index);
|
|
index++;
|
|
if (c != 0) {
|
|
if (c == 0x0a || c == 0x0d) {
|
|
// if this is cr-lf, skip the lf
|
|
if (c == 0x0d && index < end
|
|
&& text.charAt(index) == 0x0a) {
|
|
index++;
|
|
}
|
|
printWordBuffer();
|
|
newline();
|
|
} else {
|
|
if (c != '\t') {
|
|
wordBuffer.append(c);
|
|
}
|
|
if (Character.isWhitespace(c)) {
|
|
printWordBuffer();
|
|
if (c == '\t') {
|
|
x += tabWidth;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (y + lineHeight <= bottomMargin) {
|
|
printer.endPage();
|
|
}
|
|
wordBuffer = null;
|
|
}
|
|
|
|
/**
|
|
* Word buffer for formating lines on the printed page
|
|
*/
|
|
private void printWordBuffer() {
|
|
if (wordBuffer.length() > 0) {
|
|
String word = wordBuffer.toString();
|
|
int wordWidth = gc.stringExtent(word).x;
|
|
if (x + wordWidth > rightMargin) {
|
|
// word doesn't fit on current line, so wrap
|
|
newline();
|
|
}
|
|
gc.drawString(word, x, y, false);
|
|
x += wordWidth;
|
|
wordBuffer.setLength(0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* New line on the printed page
|
|
*/
|
|
private void newline() {
|
|
x = leftMargin;
|
|
y += lineHeight;
|
|
if (y + lineHeight > bottomMargin) {
|
|
printer.endPage();
|
|
if (index + 1 < end) {
|
|
y = topMargin;
|
|
printer.startPage();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the where clause for latestobsvalue table, seeing if matching keys
|
|
* and the given record's obstime is newer.
|
|
*
|
|
* @param dataRecord
|
|
* The DataRecord to update
|
|
* @return The Where clause used in the update
|
|
*/
|
|
private String createOlderThanWhereLatestObsValue(DataRecord dr) {
|
|
StringBuilder sb = new StringBuilder(" where ");
|
|
sb.append("lid = '");
|
|
sb.append(dr.getLid());
|
|
sb.append("' and ");
|
|
sb.append("pe = '");
|
|
sb.append(dr.getPe().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("dur = ");
|
|
sb.append(dr.getDur());
|
|
sb.append(" and ");
|
|
sb.append("ts = '");
|
|
sb.append(dr.getTs().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("extremum = '");
|
|
sb.append(dr.getExt().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("obstime < '");
|
|
sb.append(dbFormat.format(dr.getObsTime()));
|
|
sb.append("';");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Create the update where clause for latestobsvalue table.
|
|
*
|
|
* @param dataRecord
|
|
* The DataRecord to update or delete
|
|
* @return The Where clause used in the update or delete
|
|
*/
|
|
private String createWhereExistsLatestObsValue(DataRecord dr) {
|
|
StringBuilder sb = new StringBuilder(" where ");
|
|
sb.append("lid = '");
|
|
sb.append(dr.getLid());
|
|
sb.append("' and ");
|
|
sb.append("pe = '");
|
|
sb.append(dr.getPe().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("dur = ");
|
|
sb.append(dr.getDur());
|
|
sb.append(" and ");
|
|
sb.append("ts = '");
|
|
sb.append(dr.getTs().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("extremum = '");
|
|
sb.append(dr.getExt().toUpperCase());
|
|
sb.append("';");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Create the update where clause
|
|
*
|
|
* @param dataRecord
|
|
* The DataRecord to update
|
|
* @return The Where clause used in the update or delete
|
|
*/
|
|
private String createUpdDelWhereObs(DataRecord dr) {
|
|
StringBuilder sb = new StringBuilder(" where ");
|
|
sb.append("lid = '");
|
|
sb.append(dr.getLid());
|
|
sb.append("' and ");
|
|
sb.append("pe = '");
|
|
sb.append(dr.getPe().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("obstime = '");
|
|
sb.append(dbFormat.format(dr.getObsTime()));
|
|
sb.append("' and ");
|
|
sb.append("dur = ");
|
|
sb.append(dr.getDur());
|
|
sb.append(" and ");
|
|
sb.append("ts = '");
|
|
sb.append(dr.getTs().toUpperCase());
|
|
sb.append("' and ");
|
|
sb.append("extremum = '");
|
|
sb.append(dr.getExt().toUpperCase());
|
|
sb.append("';");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Enable/Disable the edit buttons
|
|
*
|
|
* @param enabled
|
|
* Enable if true, disable if false
|
|
*/
|
|
private void enableEditButtons(boolean enabled) {
|
|
updateInsertBtn.setEnabled(enabled);
|
|
setMissingBtn.setEnabled(enabled);
|
|
setQcBtn.setEnabled(enabled);
|
|
deleteBtn.setEnabled(enabled);
|
|
}
|
|
|
|
/**
|
|
* Enable/Disable the Fcst Inserted Data Attributes
|
|
*
|
|
* @param enabled
|
|
* Enable if true, disable if false
|
|
*/
|
|
private void enableDataAttributes(boolean enabled) {
|
|
fcstTypSrcChk.setEnabled(enabled);
|
|
fcstBasisTimeChk.setEnabled(enabled);
|
|
fcstTypSrcChk.setSelection(enabled);
|
|
fcstBasisTimeChk.setSelection(enabled);
|
|
|
|
}
|
|
|
|
/**
|
|
* Update the station label
|
|
*/
|
|
private void updateStationLabel() {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
|
|
String siteLabel = null;
|
|
try {
|
|
/* append the river name info */
|
|
String[] sa = dataManager.getStnRiverName(lid);
|
|
|
|
if (sa != null && sa[0] != null && sa[1] != null) {
|
|
if (sa[0].equalsIgnoreCase(HydroConstants.UNDEFINED)
|
|
&& sa[1].equalsIgnoreCase(HydroConstants.UNDEFINED)) {
|
|
siteLabel = lid;
|
|
} else if (!sa[0].equals(HydroConstants.UNDEFINED)
|
|
&& !sa[1].equals(HydroConstants.UNDEFINED)) {
|
|
siteLabel = lid + " (" + sa[0] + " - " + sa[1] + ")";
|
|
} else if (!sa[0].equals(HydroConstants.UNDEFINED)
|
|
&& sa[1].equals(HydroConstants.UNDEFINED)) {
|
|
siteLabel = lid + " (" + sa[0] + ")";
|
|
} else {
|
|
siteLabel = lid;
|
|
}
|
|
} else {
|
|
siteLabel = lid;
|
|
}
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.INFO, "Uable to get site: ", e);
|
|
siteLabel = lid;
|
|
}
|
|
|
|
selectedLocNameLbl.setText(siteLabel);
|
|
}
|
|
|
|
/**
|
|
* Update the selected location information label with lid, PE, T and
|
|
* basistime
|
|
*/
|
|
private void updateSelectedLocInfoLabel() {
|
|
if (basisTime != null) {
|
|
selectedLocInfoLbl
|
|
.setText(pe + " " + ts + " " + extremum + " " + basisTime);
|
|
} else {
|
|
selectedLocInfoLbl.setText(pe + " " + ts + " " + extremum);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the flood stage label based on selection.
|
|
*/
|
|
private void updateFloodStageLabel() {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
|
|
/* Find the flood stg/flow if a river station */
|
|
java.util.List<Object[]> floodList = null;
|
|
try {
|
|
floodList = dataManager.getFloodStage(lid);
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Unable to get Flood Stage List: ", e);
|
|
}
|
|
|
|
/* Should only be one here, lid is primary key */
|
|
if (floodList != null && !floodList.isEmpty()) {
|
|
Object[] oa = floodList.get(0);
|
|
String floodStage = "0.0";
|
|
String floodFlow = "0";
|
|
if (oa != null) {
|
|
if (oa[1] != null) {
|
|
floodStage = String.format("%.1f", oa[1]);
|
|
}
|
|
|
|
if (oa[2] != null) {
|
|
floodFlow = String.format("%.0f", oa[2]);
|
|
}
|
|
}
|
|
selectedFloodLbl.setText(
|
|
"Flood Stg/Flow: " + floodStage + "/" + floodFlow);
|
|
} else {
|
|
StringBuilder sb = new StringBuilder("Flood Stg/Flow: ");
|
|
sb.append("0.0/");
|
|
sb.append("0");
|
|
selectedFloodLbl.setText(sb.toString());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* copy the current forecast time series in its entirety to a new type
|
|
* source and/or basis time
|
|
*/
|
|
private void tabularCopyTS() {
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
boolean keyChanged = false;
|
|
int cnt = 0;
|
|
Date postingTime;
|
|
int duplicateCnt = 0;
|
|
|
|
if (fcstBasisTimeChk.getSelection() || fcstTypSrcChk.getSelection()) {
|
|
keyChanged = true;
|
|
} else {
|
|
keyChanged = false;
|
|
}
|
|
|
|
/* get the count of the records in the list */
|
|
if (tabularDataList == null) {
|
|
cnt = 0;
|
|
} else {
|
|
cnt = tabularDataList.size();
|
|
}
|
|
|
|
try {
|
|
/*
|
|
* only do something if we have forecast or contingency data and a
|
|
* valid type source has been selected.
|
|
*/
|
|
if ((ts.toUpperCase().startsWith("F")
|
|
|| ts.toUpperCase().startsWith("C")) && cnt > 0
|
|
&& keyChanged
|
|
&& !fcstAtt.getSelectedTS().equals(UNDEFINED_TYPESOURCE)) {
|
|
/* set postingtime to current time */
|
|
postingTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
|
|
.getTime();
|
|
|
|
SiteInfo si = tabInfo
|
|
.getSiteInfo(topDataTable.getSelectionIndex());
|
|
|
|
si.setTs(fcstAtt.getSelectedTS());
|
|
|
|
/* load the structure with the general data */
|
|
Fcstheight fcstRow = new Fcstheight();
|
|
FcstheightId fhid = new FcstheightId();
|
|
fhid.setLid(si.getLid());
|
|
fhid.setPe(si.getPe());
|
|
fhid.setDur((short) si.getDur());
|
|
fhid.setExtremum(si.getExt());
|
|
fcstRow.setPostingtime(postingTime);
|
|
|
|
/*
|
|
* load the type source key field specific to the copy request.
|
|
*/
|
|
if (fcstTypSrcChk.getSelection()) {
|
|
fhid.setTs(fcstAtt.getSelectedTS());
|
|
} else {
|
|
fhid.setTs(si.getTs());
|
|
}
|
|
|
|
/* load the basistime key field specific to the copy request */
|
|
if (fcstBasisTimeChk.getSelection()) {
|
|
si.setBasisTime(fcstAtt.getBasisTime());
|
|
fhid.setBasistime(HydroConstants.DATE_FORMAT
|
|
.parse(fcstAtt.getBasisTime()));
|
|
} else {
|
|
si.setBasisTime(basisTime);
|
|
fhid.setBasistime(HydroConstants.DATE_FORMAT
|
|
.parse(si.getBasisTime()));
|
|
}
|
|
|
|
/* load the product id and time data fields accordingly */
|
|
if (useProductTimeChk.getSelection()) {
|
|
fcstRow.setProducttime(HydroConstants.DATE_FORMAT
|
|
.parse(fcstAtt.getTime()));
|
|
fcstRow.setProductId(fcstAtt.getProductId());
|
|
} else {
|
|
fcstRow.setProductId(tabularDataList.get(0).getProductId());
|
|
fcstRow.setProducttime(
|
|
tabularDataList.get(0).getProductTime());
|
|
}
|
|
|
|
fcstRow.setId(fhid);
|
|
|
|
/* define the table name to insert data into */
|
|
String tableName = HydroUtils.getTableName(
|
|
fcstRow.getId().getPe(), fcstRow.getId().getTs());
|
|
|
|
long qualityCode = HydroConstants.MISSING_VALUE;
|
|
for (TabularData td : tabularDataList) {
|
|
fhid.setProbability(td.getProbability());
|
|
fcstRow.setValue(td.getValue());
|
|
fhid.setValidtime(td.getObsTime());
|
|
fcstRow.setShefQualCode("M");
|
|
fcstRow.setQualityCode((int) HydroQC
|
|
.setQcCode(HydroQC.QC_MANUAL_NEW, qualityCode));
|
|
fcstRow.setRevision((short) 0);
|
|
|
|
/* build the where clause */
|
|
final String format = " where lid = '%s' and pe = '%s' "
|
|
+ "and validtime = '%s' and basistime = '%s' "
|
|
+ "and dur = %d and ts = '%s' and extremum = '%s' ";
|
|
|
|
String where = String.format(format,
|
|
fcstRow.getId().getLid(), fcstRow.getId().getPe(),
|
|
HydroConstants.DATE_FORMAT
|
|
.format(fcstRow.getId().getValidtime()),
|
|
HydroConstants.DATE_FORMAT
|
|
.format(fcstRow.getId().getBasistime()),
|
|
fcstRow.getId().getDur(), si.getTs(),
|
|
fcstRow.getId().getExtremum());
|
|
|
|
if (dataManager.recordCount(tableName, where) > 0) {
|
|
/* already a record with same key */
|
|
duplicateCnt++;
|
|
} else {
|
|
DataRecord dr = new DataRecord(td, si);
|
|
|
|
dataManager.addDataRecord(tableName, dr);
|
|
}
|
|
}
|
|
|
|
// report on any duplicates which are ignored
|
|
if (duplicateCnt > 0) {
|
|
statusHandler.handle(Priority.INFO, duplicateCnt
|
|
+ " records detected in copy operation.");
|
|
}
|
|
|
|
int selection = topDataTable.getSelectionIndex();
|
|
|
|
// reload list of timeseries
|
|
tabularLoadTimeseries();
|
|
topDataTable.select(selection);
|
|
|
|
}
|
|
} catch (ParseException pe) {
|
|
statusHandler.handle(Priority.PROBLEM, "Parse error: ", pe);
|
|
} catch (VizException ve) {
|
|
statusHandler.handle(Priority.PROBLEM, "", ve);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Create an update/delete where clause for forecast data.
|
|
*
|
|
* @param td
|
|
* The TabularData object
|
|
* @param dr
|
|
* The DataRecord
|
|
* @return The where clause
|
|
*/
|
|
private String createUpdDelWhereFcst(TabularData td, DataRecord dr) {
|
|
final String format = " where lid = '%s' and pe = '%s' "
|
|
+ "and validtime = '%s' and basistime = '%s' "
|
|
+ "and dur = %d and ts = '%s' and extremum = '%s' ; ";
|
|
|
|
String where = String.format(format, dr.getLid(), dr.getPe(),
|
|
HydroConstants.DATE_FORMAT.format(dr.getObsTime()),
|
|
dr.getBasisTime(), dr.getDur(), dr.getTs(), dr.getExt());
|
|
|
|
return where;
|
|
}
|
|
|
|
/**
|
|
* Handle the SHEF Encode Selected button selection. Writes the .A or .AR
|
|
* rec to the shef encode file.
|
|
*/
|
|
private void tabularShefEncode() {
|
|
AppsDefaults appsDefaults = AppsDefaults.getInstance();
|
|
String fmtType = ".A ";
|
|
String txtValue = null;
|
|
|
|
if (shefFileName == null) {
|
|
if (whfsProductDir == null) {
|
|
whfsProductDir = appsDefaults.getToken("whfs_product_dir");
|
|
}
|
|
|
|
if (whfsProductDir == null || whfsProductDir.length() == 0) {
|
|
shefFileName = "." + SHEF_FILE_NAME + "." + getPid();
|
|
} else {
|
|
shefFileName = whfsProductDir + "/" + SHEF_FILE_NAME + "."
|
|
+ getPid();
|
|
}
|
|
}
|
|
|
|
try (BufferedWriter out = new BufferedWriter(
|
|
new FileWriter(shefFileName, true))) {
|
|
int[] indices = bottomTable.getSelectionIndices();
|
|
String tablename = HydroUtils.getTableName(pe, ts);
|
|
boolean forecast = ts.toUpperCase().startsWith("C")
|
|
|| ts.toUpperCase().startsWith("F");
|
|
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager
|
|
.getInstance();
|
|
// update the tabular data list with the latest data
|
|
tabularDataList = dataManager.getTabularData(tablename, lid, pe, ts,
|
|
dur, extremum, beginningTime, endingTime, basisTime,
|
|
forecast);
|
|
|
|
for (int indice : indices) {
|
|
|
|
/* if manually edited data then format as .AR message */
|
|
TabularData td = tabularDataList.get(indice);
|
|
if (td.getShefQualCode().startsWith("M")) {
|
|
fmtType = ".AR";
|
|
}
|
|
|
|
/* convert time */
|
|
Date d = td.getObsTime();
|
|
String dateStr = shefDateFormat.format(d);
|
|
String timeStr = shefTimeFormat.format(d);
|
|
String timeBuf = dateStr + " Z DH" + timeStr;
|
|
|
|
/* convert '-9999' to missing symbol 'M' */
|
|
if (td.getValue() == HydroConstants.MISSING_VALUE) {
|
|
txtValue = "M";
|
|
} else if (pe.startsWith("Q") && !"QB".equals(pe)
|
|
&& !"QE".equals(pe) && !"QF".equals(pe)) {
|
|
txtValue = String.format("%.3f", td.getValue() / 1000);
|
|
} else {
|
|
txtValue = String.format("%.2f", td.getValue());
|
|
}
|
|
|
|
/* get the internal QC code and set the SHEF data Qualifier */
|
|
String qcSymbol = TimeSeriesUtil
|
|
.buildQcSymbol(td.getQualityCode());
|
|
String dataQualifier = null;
|
|
|
|
if (qcSymbol.startsWith("B")) {
|
|
dataQualifier = "B";
|
|
} else if (qcSymbol.startsWith("Q")) {
|
|
if (td.getShefQualCode().startsWith("F")) {
|
|
dataQualifier = "F";
|
|
} else {
|
|
dataQualifier = "Q";
|
|
}
|
|
} else {
|
|
dataQualifier = " ";
|
|
}
|
|
|
|
/*
|
|
* If value is missing then there should not be a dataQualifier
|
|
*/
|
|
if ("M".equals(txtValue)) {
|
|
dataQualifier = "";
|
|
}
|
|
|
|
/* get durcode and format the outgoing SHEF message */
|
|
Character durSymbol = TimeSeriesUtil
|
|
.convertDur2Code(Integer.parseInt(dur));
|
|
|
|
String aRec = String.format("%s %s %s/%s%s%s%s %s%s", fmtType,
|
|
lid, timeBuf, pe, durSymbol, ts, extremum, txtValue,
|
|
dataQualifier);
|
|
|
|
out.write(aRec + "\n");
|
|
}
|
|
} catch (IOException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Unable to create shef file: ", e);
|
|
showMessage(shell, SWT.ERROR | SWT.OK, "Unable to Save File",
|
|
"File: " + SHEF_FILE_NAME + "." + getPid()
|
|
+ "\nUser does NOT have write permission.");
|
|
} catch (VizException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Unable to reload location list.", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Review the shef encoded product.
|
|
*/
|
|
private void reviewShefEncodedProduct() {
|
|
if (shefFileName != null && shefFileName.length() > 0) {
|
|
File shefFile = new File(shefFileName);
|
|
if (shefFile.exists()) {
|
|
if (editor == null || editor.isDisposed()) {
|
|
editor = new TextEditorDlg(shell, false, shefFile);
|
|
editor.open();
|
|
} else {
|
|
editor.bringToTop();
|
|
}
|
|
} else {
|
|
showMessage(shell, SWT.OK, "Unable to Open File",
|
|
"Unable to open file:\n" + SHEF_FILE_NAME + "."
|
|
+ getPid());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Broadcast the SHEF product.
|
|
*/
|
|
private void sendProduct() {
|
|
// Check for DTR and don't transmit if in DRT
|
|
if (!SimulatedTimeOperations.isTransmitAllowed()) {
|
|
SimulatedTimeOperations.displayFeatureLevelWarning(this.shell,
|
|
"Transmission of SHEF products");
|
|
return;
|
|
}
|
|
|
|
if (sendConfirmation()) {
|
|
// check shef issue configuration
|
|
ShefIssueMgr sim = ShefIssueMgr.getInstance();
|
|
|
|
ShefIssueXML xml = sim.getShefIssueXml();
|
|
|
|
try {
|
|
if (xml.isDirCopy()) {
|
|
List<String> directories = xml.getInternalDirectory()
|
|
.getDirectories();
|
|
if (directories != null) {
|
|
for (String dir : directories) {
|
|
Files.copy(Paths.get(shefFileName), Paths.get(dir,
|
|
SHEF_FILE_NAME + "." + getPid()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (xml.isDistributeProduct()) {
|
|
String text = getFileText();
|
|
|
|
OUPRequest req = new OUPRequest();
|
|
OfficialUserProduct oup = new OfficialUserProduct();
|
|
String awipsWanPil = productTF.getText();
|
|
oup.setAwipsWanPil(awipsWanPil);
|
|
oup.setSource("Time Series");
|
|
oup.setAddress("DEFAULTNCF");
|
|
oup.setNeedsWmoHeader(true);
|
|
oup.setFilename(SHEF_FILE_NAME + "." + getPid());
|
|
oup.setProductText(text);
|
|
req.setUser(UserController.getUserObject());
|
|
|
|
req.setCheckBBB(true);
|
|
req.setProduct(oup);
|
|
|
|
OUPResponse response = (OUPResponse) ThriftClient
|
|
.sendRequest(req);
|
|
boolean success = response.isSendLocalSuccess();
|
|
if (response.hasFailure()) {
|
|
Priority p = Priority.EVENTA;
|
|
if (!response.isAttempted()) {
|
|
// if was never attempted to send or store even
|
|
// locally
|
|
p = Priority.CRITICAL;
|
|
} else if (!response.isSendLocalSuccess()) {
|
|
// if send/store locally failed
|
|
p = Priority.CRITICAL;
|
|
} else if (!response.isSendWANSuccess()) {
|
|
// if send to WAN failed
|
|
if (response.getNeedAcknowledgment()) {
|
|
// if ack was needed, if it never sent then no
|
|
// ack was recieved
|
|
p = Priority.CRITICAL;
|
|
} else {
|
|
// if no ack was needed
|
|
p = Priority.EVENTA;
|
|
}
|
|
} else if (response.getNeedAcknowledgment()
|
|
&& !response.isAcknowledged()) {
|
|
// if sent but not acknowledged when acknowledgement
|
|
// is needed
|
|
p = Priority.CRITICAL;
|
|
}
|
|
|
|
statusHandler.handle(p, response.getMessage());
|
|
}
|
|
|
|
if (success) {
|
|
showMessage(shell, SWT.OK, "Distribution Successful",
|
|
"Product successfully distributed via HandleOUP");
|
|
}
|
|
}
|
|
} catch (VizException | IOException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Error transmitting text product", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get confirmation from the user and verify the product id is valid.
|
|
*
|
|
* @return True if ok to send, false otherwise
|
|
*/
|
|
private boolean sendConfirmation() {
|
|
boolean retVal = false;
|
|
|
|
/* Verify the product id is not invalid */
|
|
String productId = productTF.getText();
|
|
if (productId == null || productId.length() == 0) {
|
|
showMessage(shell, SWT.ERROR, INVALID_PRODUCT_ID,
|
|
"Product Id cannot be blank.");
|
|
// Apparently CCCCNNNXXX is valid so we'll accept it
|
|
// } else if (productId.equals("CCCCNNNXXX")) {
|
|
// showMessage(shell, SWT.ERROR, INVALID_PRODUCT_ID,
|
|
// INVALID_PRODUCT_ID + ": CCCCNNNXXX");
|
|
} else {
|
|
retVal = true;
|
|
}
|
|
|
|
/* Get send confirmation from the user */
|
|
if (retVal) {
|
|
int choice = showMessage(shell, SWT.OK | SWT.CANCEL,
|
|
"SHEF Send Confirmation",
|
|
"Do you wish to send product " + productId + "?");
|
|
|
|
if (choice == SWT.CANCEL) {
|
|
retVal = false;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* Get the text from the shef file.
|
|
*
|
|
* @return text
|
|
*/
|
|
private String getFileText() {
|
|
if (shefFileName != null) {
|
|
StringBuilder sb = new StringBuilder();
|
|
try (BufferedReader in = new BufferedReader(
|
|
new FileReader(shefFileName))) {
|
|
String str;
|
|
while ((str = in.readLine()) != null) {
|
|
sb.append(CARRIAGECONTROL);
|
|
sb.append(str);
|
|
}
|
|
} catch (IOException e) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Error reading file: " + shefFileName, e);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* Clear the shef encode file.
|
|
*/
|
|
private void clearProduct() {
|
|
int response = showMessage(shell, SWT.OK | SWT.CANCEL,
|
|
"SHEF Clear Confirmation",
|
|
"Do you wish to remove the SHEF encoded product file?");
|
|
|
|
if (response == SWT.OK && shefFileName != null) {
|
|
File shefFile = new File(shefFileName);
|
|
if (shefFile.exists()) {
|
|
boolean success = shefFile.delete();
|
|
if (!success) {
|
|
showMessage(shell, SWT.ERROR | SWT.OK | SWT.CANCEL, "Error",
|
|
"Error removing the SHEF encode file.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show a dialog message.
|
|
*
|
|
* @param shell
|
|
* The parent shell
|
|
* @param style
|
|
* The dialog style
|
|
* @param title
|
|
* The dialog title
|
|
* @param msg
|
|
* The dialog message
|
|
* @return The value representing the button clicked on the dialog
|
|
*/
|
|
private int showMessage(Shell shell, int style, String title, String msg) {
|
|
MessageBox messageBox = new MessageBox(shell, style);
|
|
messageBox.setText(title);
|
|
messageBox.setMessage(msg);
|
|
return messageBox.open();
|
|
}
|
|
|
|
/**
|
|
* Get a "process id" unique to this session.
|
|
*
|
|
* @return The pid
|
|
*/
|
|
private int getPid() {
|
|
if (pid == HydroConstants.MISSING_VALUE) {
|
|
Random r = new Random();
|
|
|
|
// Let's create a hand-made pid for default
|
|
pid = r.nextInt() & 0x7fffffff;
|
|
}
|
|
|
|
return pid;
|
|
}
|
|
|
|
/**
|
|
* @return the lid
|
|
*/
|
|
public String getLid() {
|
|
return lid;
|
|
}
|
|
|
|
/**
|
|
* @param lid
|
|
* the lid to set
|
|
*/
|
|
public void setLid(String lid) {
|
|
this.lid = lid;
|
|
}
|
|
|
|
/**
|
|
* @return the siteName
|
|
*/
|
|
public String getSiteName() {
|
|
return siteName;
|
|
}
|
|
|
|
/**
|
|
* @param siteName
|
|
* the siteName to set
|
|
*/
|
|
public void setSiteName(String siteName) {
|
|
this.siteName = siteName;
|
|
}
|
|
|
|
/**
|
|
* @return the groupInfo
|
|
*/
|
|
public GroupInfo getGroupInfo() {
|
|
return groupInfo;
|
|
}
|
|
|
|
/**
|
|
* @param groupInfo
|
|
* the groupInfo to set
|
|
*/
|
|
public void setGroupInfo(GroupInfo groupInfo) {
|
|
this.groupInfo = groupInfo;
|
|
}
|
|
|
|
/**
|
|
* @return the tabInfo
|
|
*/
|
|
public List<TabInfo> getTabInfoList() {
|
|
return tabInfoList;
|
|
}
|
|
|
|
/**
|
|
* @param tabInfoList
|
|
* @param tabInfo
|
|
* the tabInfo to set
|
|
*/
|
|
public void setTabInfoList(List<TabInfo> tabInfoList) {
|
|
this.tabInfoList = tabInfoList;
|
|
}
|
|
|
|
/**
|
|
* Get a TabInfo object.
|
|
*
|
|
* @param index
|
|
* the index of the TabInfo object
|
|
* @return the TabInfo
|
|
*/
|
|
public TabInfo getTabInfo(int index) {
|
|
return tabInfoList.get(index);
|
|
}
|
|
|
|
/**
|
|
* @return the currentTabInfo
|
|
*/
|
|
public TabInfo getCurrentTabInfo() {
|
|
return currentTabInfo;
|
|
}
|
|
|
|
/**
|
|
* @param currentTabInfo
|
|
* the currentTabInfo to set
|
|
*/
|
|
public void setCurrentTabInfo(TabInfo currentTabInfo) {
|
|
this.currentTabInfo = currentTabInfo;
|
|
}
|
|
|
|
@Override
|
|
public void notifyUpdate(FcstAttUpdateEvent faue) {
|
|
fcstAtt = faue.getFcstAttributes();
|
|
|
|
productTimeLbl.setText(fcstAtt.getTime());
|
|
productIdLbl.setText(fcstAtt.getProductId());
|
|
fcstBasisTimeLbl.setText(fcstAtt.getBasisTime());
|
|
fcstTypSrcChk.setText("Fcst TypSrc: " + fcstAtt.getSelectedTS());
|
|
getParent().redraw();
|
|
}
|
|
|
|
@Override
|
|
public void aboutToRun(IJobChangeEvent event) {
|
|
}
|
|
|
|
@Override
|
|
public void awake(IJobChangeEvent event) {
|
|
}
|
|
|
|
@Override
|
|
public void done(IJobChangeEvent event) {
|
|
if (!isDisposed()) {
|
|
tsDataJobManager.removeJobChangeListener(this);
|
|
VizApp.runSync(new Runnable() {
|
|
|
|
@Override
|
|
public void run() {
|
|
loadDataList();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void running(IJobChangeEvent event) {
|
|
}
|
|
|
|
@Override
|
|
public void scheduled(IJobChangeEvent event) {
|
|
}
|
|
|
|
@Override
|
|
public void sleeping(IJobChangeEvent event) {
|
|
}
|
|
|
|
private Set<String> getForecastTSTableName(SiteInfo row) {
|
|
Set<String> tableNameSet = new HashSet<>();
|
|
|
|
if (row.getTs().toUpperCase().startsWith("F")
|
|
|| row.getTs().toUpperCase().startsWith("C")) {
|
|
addTableName(tableNameSet, row.getPe(), row.getTs());
|
|
}
|
|
|
|
for (String type : TYPE_SOURCE_FOR_COPY) {
|
|
addTableName(tableNameSet, row.getPe(), type);
|
|
}
|
|
|
|
return tableNameSet;
|
|
}
|
|
|
|
private void addTableName(Set<String> nameSet, String pe, String ts) {
|
|
String tableName = HydroUtils.getTableName(pe, ts);
|
|
|
|
if (!"INVALID".equals(tableName)) {
|
|
nameSet.add(tableName);
|
|
}
|
|
}
|
|
|
|
private void displayTS(SiteInfo site, List<SiteInfo> siteInfoList) {
|
|
List<Object[]> results = null;
|
|
int entryNumber = 0;
|
|
int count = 0;
|
|
TimeSeriesDataManager dataManager = TimeSeriesDataManager.getInstance();
|
|
|
|
/* if a forecast timeseries then find all basis times */
|
|
if (site.getTs().toUpperCase().startsWith("F")
|
|
|| site.getTs().toUpperCase().startsWith("C")) {
|
|
Set<String> tableNameSet = getForecastTSTableName(site);
|
|
Set<String> typeSourceSet = getTypeSources(site);
|
|
|
|
// loop through all possible table names
|
|
for (String tableName : tableNameSet) {
|
|
if (!"INVALID".equals(tableName)) {
|
|
// loop through all possible type sources
|
|
for (String typeSource : typeSourceSet) {
|
|
site.setTs(typeSource);
|
|
|
|
try {
|
|
results = dataManager.getUniqueList(tableName,
|
|
site.getLid(), site.getPe().toUpperCase(),
|
|
site.getDur(), typeSource.toUpperCase(),
|
|
site.getExt().toUpperCase(), beginningTime,
|
|
endingTime);
|
|
((ArrayList<Object[]>) results).trimToSize();
|
|
} catch (Exception ve) {
|
|
statusHandler.handle(Priority.PROBLEM,
|
|
"Load time series from " + tableName
|
|
+ " to copy TS. TimeSeriesDataManager.getUniqueList failed. ",
|
|
ve);
|
|
}
|
|
|
|
if (results != null && !results.isEmpty()) {
|
|
if (listAllFcstChk.getSelection()) {
|
|
count = results.size();
|
|
} else {
|
|
count = 1;
|
|
}
|
|
|
|
/* loop through number of unique basis times */
|
|
/*
|
|
* if list ALL basis TB is not pressed then loop
|
|
* only ONCE
|
|
*/
|
|
for (int j = 0; j < count; j++) {
|
|
if (entryNumber < MAX_TS_ON_LIST) {
|
|
site.setBasisTime(HydroConstants.DATE_FORMAT
|
|
.format((Date) results.get(j)[0]));
|
|
addSite(site, HydroConstants.DATE_FORMAT
|
|
.format((Date) results.get(j)[0]));
|
|
siteInfoList.add(site);
|
|
entryNumber++;
|
|
}
|
|
}
|
|
} else {
|
|
/* if NO basis times found */
|
|
if (entryNumber < MAX_TS_ON_LIST) {
|
|
addSite(site, "No Data");
|
|
entryNumber++;
|
|
siteInfoList.add(site);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/*
|
|
* if an observed timeseries then just store in modified list
|
|
*/
|
|
if (entryNumber < MAX_TS_ON_LIST) {
|
|
addSite(site, null);
|
|
entryNumber++;
|
|
siteInfoList.add(site);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addSite(SiteInfo site, String date) {
|
|
String timeSeriesTableRow = String.format("%-5s %2s %4s %2s %s ",
|
|
site.getLid(), site.getPe().toUpperCase(), site.getDur(),
|
|
site.getTs().toUpperCase(), site.getExt().toUpperCase());
|
|
TableItem item = new TableItem(topDataTable, SWT.NONE);
|
|
|
|
item.setText(0, site.getLid());
|
|
item.setText(1, site.getPe().toUpperCase());
|
|
item.setText(2, String.format("%4s", site.getDur()));
|
|
item.setText(3, site.getTs().toUpperCase());
|
|
item.setText(4, site.getExt().toUpperCase());
|
|
|
|
if (date != null) {
|
|
modifiedTSList.add(timeSeriesTableRow + date);
|
|
item.setText(5, date);
|
|
}
|
|
}
|
|
|
|
private Set<String> getTypeSources(SiteInfo site) {
|
|
Set<String> typeSources = new HashSet<>();
|
|
|
|
typeSources.add(site.getTs().toUpperCase());
|
|
|
|
for (String type : TYPE_SOURCE_FOR_COPY) {
|
|
typeSources.add(type);
|
|
}
|
|
|
|
return typeSources;
|
|
}
|
|
}
|