/* File: DasTimeRangeSelector.java * Copyright (C) 2002-2003 The University of Iowa * Created by: Jeremy Faden * Jessica Swanner * Edward E. West * * This file is part of the das2 library. * * das2 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.das2.components; import org.das2.datum.DatumRange; import org.das2.datum.Units; import org.das2.datum.Datum; import org.das2.datum.DatumRangeUtil; import org.das2.util.DasExceptionHandler; import org.das2.datum.TimeUtil; import org.das2.event.TimeRangeSelectionEvent; import org.das2.event.TimeRangeSelectionListener; import org.das2.system.DasLogger; import java.awt.CardLayout; import java.awt.Dimension; import java.awt.FlowLayout; import javax.swing.event.EventListenerList; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.text.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.prefs.*; import javax.swing.*; import org.das2.DasApplication; import org.das2.datum.UnitsUtil; /** * code copied from DasTimeRangeSelector for use with Autoplot. * DasTimeRangeSelector wasn't very beany... * @author jbf */ public class TimeRangeEditor implements TimeRangeSelectionListener { private DatumRange range= null; JPanel panel; JTextField idStart= null; JTextField idStop= null; JButton viewButton= null; JPanel startStopModePane=null; CardLayout cardLayout= null; boolean updateRangeString= false; // true indicates use formatted range string in start time cell. /** Utility field used by event firing mechanism. */ private EventListenerList listenerList = null; /** Action that is associated with the previous button. * Access is given to subclasses so that other widgets can be associated * with this action (Popup menu, etc). */ protected final Action previousAction = new AbstractAction("<<") { @Override public void actionPerformed(ActionEvent e) { fireTimeRangeSelectedPrevious(); } }; /** Action that is associated with the next button. * Access is given to subclasses so that other widgets can be associated * with this action (Popup menu, etc). */ protected final Action nextAction = new AbstractAction(">>") { @Override public void actionPerformed(ActionEvent e) { fireTimeRangeSelectedNext(); } }; protected final Action rangeAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { fireTimeRangeSelected(); } }; private boolean favoritesEnabled= false; private List favoritesList= null; private JPopupMenu favoritesMenu= null; private final int FAVORITES_LIST_SIZE= 5; private String favoritesGroup; private JButton favoritesButton; private JPanel timesPane; private JComboBox rangeComboBox; /** * creates an instance of the editor, with an arbitrary range (today) loaded. */ public TimeRangeEditor() { updateRangeString= Preferences.userNodeForPackage(this.getClass()).getBoolean("updateRangeString", false); buildComponents(); Datum tnow= TimeUtil.prevMidnight( TimeUtil.now().convertTo(Units.us2000) ); this.range= new DatumRange( tnow, TimeUtil.next( TimeUtil.DAY, tnow ) ); update(); } private Action getModeAction() { return new AbstractAction("mode") { @Override public void actionPerformed( ActionEvent e ) { updateRangeString= !updateRangeString; Preferences.userNodeForPackage(this.getClass()).putBoolean("updateRangeString", updateRangeString ); revalidateUpdateMode(); update(); } }; } private void revalidateUpdateMode() { if ( updateRangeString ) { //idStop.setColumns(8); idStart.setColumns(28); idStop.setVisible(false); viewButton.setVisible(true); //cardLayout.show( timesPane, "range" ); } else { idStart.setColumns(18); // idStop.setColumns(18); idStop.setVisible(true); //cardLayout.show( timesPane, "startStop" ); } startStopModePane.revalidate(); } private void buildComponents() { panel= new JPanel(); panel.setLayout(new FlowLayout()); JButton b= new JButton(); b.setAction(previousAction); b.setActionCommand("previous"); b.setToolTipText("Scan back in time"); panel.add(b); startStopModePane= new JPanel(new FlowLayout()); cardLayout= new CardLayout(); timesPane= new JPanel( cardLayout ); JPanel startStopPane2= new JPanel(new FlowLayout()); idStart= new JTextField(18); idStart.setAction(rangeAction); idStart.setActionCommand("startTime"); startStopPane2.add(idStart); idStop= new JTextField(18); idStop.addActionListener(rangeAction); idStop.setActionCommand("endTime"); startStopPane2.add(idStop); timesPane.add( startStopPane2, "startStop" ); startStopModePane.add( timesPane ); favoritesButton= new JButton("v"); favoritesButton.setToolTipText("recent entry times"); favoritesButton.setPreferredSize(new Dimension( 20,20 ) ); favoritesButton.setVisible(false); startStopModePane.add(favoritesButton); viewButton= new JButton(getModeAction()); viewButton.setToolTipText("input mode: start/end vs time range string"); viewButton.setPreferredSize(new Dimension( 20,20 ) ); startStopModePane.add(viewButton); panel.add(startStopModePane); b= new JButton(); b.setAction(nextAction); b.setActionCommand("next"); b.setToolTipText("Scan forward in time"); panel.add(b); revalidateUpdateMode(); } /** * create an editor with the initial range. * @param startTime the start time * @param endTime the end time, which must be greater than startTime. */ public TimeRangeEditor(Datum startTime, Datum endTime) { this(new DatumRange( startTime, endTime )); } /** * create an editor with the initial range. * @param range the range */ public TimeRangeEditor( DatumRange range ) { this(); this.range= range; update(); } private void parseRange() { boolean updateRangeString0= updateRangeString; if ( idStop.getText().equals("") ) { DatumRange dr; try { String rangeString= idStart.getText(); if ( rangeString.equals("") ) { rangeString= (String)rangeComboBox.getEditor().getItem(); } dr= DatumRangeUtil.parseTimeRange(rangeString); DatumRange oldRange= range; range= dr; updateRangeString= true; pcs.firePropertyChange( "range", oldRange, range ); } catch ( ParseException e ) { DasApplication.getDefaultApplication().getExceptionHandler().handle(e); } } else { updateRangeString= false; try { Datum s1= TimeUtil.create(idStart.getText()); Datum s2= TimeUtil.create(idStop.getText()); DatumRange oldRange= range; range= new DatumRange(s1,s2); pcs.firePropertyChange( "range", oldRange, range ); } catch ( ParseException e ) { DasApplication.getDefaultApplication().getExceptionHandler().handle(e); } } if ( updateRangeString!=updateRangeString0 ) Preferences.userNodeForPackage(getClass()).putBoolean("updateRangeString", updateRangeString ); } private void refreshFavorites() { favoritesMenu.removeAll(); for ( Iterator i= favoritesList.iterator(); i.hasNext(); ) { final String fav= (String) i.next(); Action favAction= new AbstractAction( fav ) { @Override public void actionPerformed( ActionEvent e ) { TimeRangeEditor.this.setRange( DatumRangeUtil.parseTimeRangeValid(fav) ); fireTimeRangeSelected(new TimeRangeSelectionEvent(this,range)); } }; favoritesMenu.add( favAction ); } } private void buildFavorites( ) { String favorites= Preferences.userNodeForPackage(getClass()).get( "timeRangeSelector.favorites."+favoritesGroup, "" ); String[] ss= favorites.split("\\|\\|"); favoritesList= new ArrayList(); for (String s : ss) { if (!"".equals(s)) { favoritesList.add(s); } } favoritesMenu= new JPopupMenu(); refreshFavorites(); favoritesButton.add( favoritesMenu ); favoritesButton.addActionListener( getFavoritesListener()); } private ActionListener getFavoritesListener() { return new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { favoritesMenu.show(panel, favoritesButton.getX(), favoritesButton.getY() ); } }; } /** * adds a droplist of recently entered times. This should be a spacecraft string, or null. * @param group an arbitrary identifier for the group. */ public void enableFavorites( String group ) { if ( group==null ) group="default"; this.favoritesGroup= group; favoritesEnabled= true; favoritesButton.setVisible(true); buildFavorites( ); } public Datum getStartTime() { parseRange(); return range.min(); } public Datum getEndTime() { parseRange(); return range.max(); } public DatumRange getRange() { return range; } public void setRange( DatumRange value ) { DatumRange oldValue= this.range; this.range= value; update(); if (oldValue != value && oldValue != null && !oldValue.equals(value)) { pcs.firePropertyChange("range", oldValue, value); } } private void update() { if ( range!=null ) { if ( UnitsUtil.isTimeLocation( range.getUnits() ) ) { if ( updateRangeString ) { String rangeString= DatumRangeUtil.formatTimeRange(range); idStart.setText( rangeString ); idStop.setText(""); } else { idStart.setText(range.min().toString()); idStop.setText(range.max().toString()); } } else { if ( updateRangeString ) { String rangeString= range.toString(); idStart.setText( rangeString ); idStop.setText(""); } else { idStart.setText(range.min().toString()); idStop.setText(range.max().toString()); } } } } public void setStartTime(Datum s1) { if ( range==null ) { return; } else { Datum endTime= range.max(); if ( endTime.le(s1) ) { endTime= s1.add(1,Units.seconds); } range= new DatumRange( s1, endTime ); } update(); } public void setEndTime(Datum s2) { if ( range==null ) { return; } else { Datum startTime= range.min(); if ( startTime.ge(s2) ) { startTime= s2.subtract(1, Units.seconds); } range= new DatumRange( startTime, s2 ); } update(); } public boolean isWithin(Datum s1, Datum s2) { Datum startTime= getStartTime(); Datum endTime= getEndTime(); return s1.compareTo(startTime) <= 0 && endTime.compareTo(s2) <= 0; } @Override public void timeRangeSelected(TimeRangeSelectionEvent e) { DatumRange lrange= e.getRange(); if ( !lrange.equals(this.range) ) { setRange( e.getRange() ); fireTimeRangeSelected(e); } } /** Registers TimeRangeSelectionListener to receive events. * @param listener The listener to register. */ public synchronized void addTimeRangeSelectionListener(TimeRangeSelectionListener listener) { if (listenerList == null ) { listenerList = new EventListenerList(); } listenerList.add(TimeRangeSelectionListener.class, listener); } /** Removes TimeRangeSelectionListener from the list of listeners. * @param listener The listener to remove. */ public synchronized void removeTimeRangeSelectionListener(TimeRangeSelectionListener listener) { listenerList.remove(TimeRangeSelectionListener.class, listener); } protected void fireTimeRangeSelectedPrevious() { setRange( range.previous() ); fireTimeRangeSelected(new TimeRangeSelectionEvent( this, range )); } protected void fireTimeRangeSelectedNext() { setRange( range.next() ); fireTimeRangeSelected(new TimeRangeSelectionEvent(this,range)); } protected void fireTimeRangeSelected() { parseRange(); update(); if ( favoritesEnabled ) { String store= range.toString(); if ( favoritesList.contains( store ) ) favoritesList.remove(store); // bring to front favoritesList.add( 0, store ); for ( int i=FAVORITES_LIST_SIZE; i=0; i-=2) { if (listeners[i]==TimeRangeSelectionListener.class) { String logmsg= "fire event: "+this.getClass().getName()+"-->"+listeners[i+1].getClass().getName()+" "+event; DasLogger.getLogger( DasLogger.GUI_LOG ).fine(logmsg); ((org.das2.event.TimeRangeSelectionListener)listeners[i+1]).timeRangeSelected(event); ((TimeRangeSelectionListener)listeners[i+1]).timeRangeSelected(event); } } } public Dimension getMaximumSize() { return panel.getPreferredSize(); } public Dimension getMinimumSize() { return panel.getPreferredSize(); } /** * get the GUI panel. All this was because it was firing off events on * construction, and I was copying DatumEditor. * @return the GUI panel. */ public JPanel getPanel() { return panel; } private void saveFavorites() { if ( favoritesList.isEmpty() ) return; StringBuilder favorites= new StringBuilder( (String)favoritesList.get(0) ); for ( int i=1; i