package com.mindprod.tz;
import com.mindprod.common18.Build;
import com.mindprod.common18.CMPAboutJBox;
import com.mindprod.common18.Common18;
import com.mindprod.common18.FontFactory;
import com.mindprod.common18.HybridJ;
import com.mindprod.common18.JEButton;
import com.mindprod.common18.VersionCheck;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* TZ display TimeZones supported on your computer with their offsets from GMT.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.9 2008-06-13 flip to JDK 1.6 to allow access to TableRowSorter
* @since 2004
*/
@SuppressWarnings( { "FieldCanBeLocal" } )
public final class TZ extends JApplet
{
/**
* height of Applet box in pixels. Does not include surrounding frame.
*/
private static final int APPLET_HEIGHT = 645;
/**
* Width of Applet box in pixels.
*/
private static final int APPLET_WIDTH = 822;
private static final int FIRST_COPYRIGHT_YEAR = 2004;
/**
* undisplayed copyright notice
*/
@SuppressWarnings( { "UnusedDeclaration" } )
private static final String EMBEDDED_COPYRIGHT =
"Copyright: (c) 2004-2017 Roedy Green, Canadian Mind Products, http://mindprod.com";
private static final String RELEASE_DATE = "2008-06-13";
private static final String TITLE_STRING = "TimeZones";
private static final String VERSION_STRING = "1.9";
/**
* pale violet blue
*/
private static final Color BACKGROUND_FOR_APPLET = new Color( 0xd4d4ff );
private static final Color FOREGROUND_FOR_INSTRUCTIONS = new Color( 0x008000 );
private static final Color FOREGROUND_FOR_LABEL = new Color( 0x0000b0 );
/**
* for titles
*/
private static final Color FOREGROUND_FOR_TITLE = new Color( 0xdc143c );
/**
* pick noon 2007-06-21 0:00 as a typical summer day that likely will be using DST.
*/
private static final Date aSummerDay =
new GregorianCalendar( 2007, Calendar.JUNE, 21 ).getTime();
/**
* pick 2007-06-21 0::00 as a typical winter day that will not be using DST.
*/
private static final Date aWinterDay =
new GregorianCalendar( 2007, Calendar.DECEMBER, 21 ).getTime();
/**
* for for titles and About buttons
*/
private static final Font FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 );
/**
* for for title second line
*/
private static final Font FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 );
/**
* zz=PDT zzzz="pacific Daylight Time" EEEE=dow hh=12 hour
*/
private static final SimpleDateFormat localTimeDisplay =
new SimpleDateFormat( "yyyy-MM-dd hh:mm:ss aa zz : zzzzzz EEEE" );
/**
* zz=PDT zzzz="pacific Daylight Time" EEEE=dow HH=24 hour
*/
private static final SimpleDateFormat utcTimeDisplay =
new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss zz : zzzzzz EEEE" );
private static final int[] PREFERRED_COLUMN_WIDTH = { 45, 45, 215, 330 };
static
{
utcTimeDisplay.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
}
private JButton about;
private JLabel instructions;
private JLabel localTimeLabel;
private JLabel localTZLabel;
private JLabel supportedLabel;
private JLabel title;
/**
* title, second line
*/
private JLabel title2;
private JLabel utcTimeLabel;
/**
* scroll the JTable of TimeZones
*/
private JScrollPane scroller;
/**
* grid of TimeZone data
*/
private JTable timeZoneTable;
private JTextField localTimeField;
private JTextField localTZField;
private JTextField utcTimeField;
/**
* timer to help us keep clock up to date.
*/
private Timer timer;
/**
* allocate all components
*/
private void buildComponents()
{
title = new JLabel( TITLE_STRING + " " + VERSION_STRING );
title.setFont( FONT_FOR_TITLE );
title.setForeground( FOREGROUND_FOR_TITLE );
title2 = new JLabel(
"released:" +
RELEASE_DATE +
" build:" +
Build.BUILD_NUMBER
);
title2.setFont( FONT_FOR_TITLE2 );
title2.setForeground( FOREGROUND_FOR_TITLE );
about = new JEButton( "About" );
about.setToolTipText( "About " + TITLE_STRING + " " + VERSION_STRING );
about.addActionListener( new ActionListener()
{
/**
* Method actionPerformed ...
* @param e of type ActionEvent
*/
public void actionPerformed( ActionEvent e )
{
new CMPAboutJBox( TITLE_STRING,
VERSION_STRING,
"Display all Timezones that Java supports on this machine.",
"",
"freeware",
RELEASE_DATE,
FIRST_COPYRIGHT_YEAR,
"Roedy Green",
"TZ",
"1.8" );
}
} );
utcTimeLabel = new JLabel( "UTC" );
utcTimeLabel.setForeground( FOREGROUND_FOR_LABEL );
utcTimeField = new JTextField( localTimeDisplay.format( new Date() ) );
utcTimeField.setEditable( false );
localTimeLabel = new JLabel( "local time" );
localTimeLabel.setForeground( FOREGROUND_FOR_LABEL );
localTimeField =
new JTextField( localTimeDisplay.format( new Date() ) );
localTimeField.setEditable( false );
localTZLabel = new JLabel( "local TZ" );
localTZLabel.setForeground( FOREGROUND_FOR_LABEL );
localTZField = new JTextField( TimeZone.getDefault().getDisplayName() );
localTZField.setEditable( false );
supportedLabel = new JLabel( "Supported TimeZones", JLabel.CENTER );
supportedLabel.setForeground( FOREGROUND_FOR_LABEL );
final String[] allTimeZoneIDs = TimeZone.getAvailableIDs();
Arrays.sort( allTimeZoneIDs, new ByOffset() );
final TZTableModel model = new TZTableModel( allTimeZoneIDs );
timeZoneTable = new JTable( model );
final TableColumnModel tableColumnModel =
timeZoneTable.getColumnModel();
tableColumnModel.setColumnMargin( 5 );
final TableCellRenderer headerRenderer = new HeaderRenderer();
for ( int i = 0; i < 4; i++ )
{
final TableColumn tableColumn = tableColumnModel.getColumn( i );
tableColumn.setHeaderRenderer( headerRenderer );
tableColumn.setPreferredWidth( PREFERRED_COLUMN_WIDTH[ i ] );
}
scroller =
new JScrollPane( timeZoneTable,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
timeZoneTable.setRowSorter( new TableRowSorter<>( model ) );
instructions = new JLabel( "Click column heading to sort.", JLabel.CENTER );
instructions.setForeground( FOREGROUND_FOR_INSTRUCTIONS );
}
private void layoutComponents( Container contentPane )
{
contentPane.add( title,
new GridBagConstraints( 0,
0,
2,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets( 10, 10, 5, 5 ),
0,
0 )
);
contentPane.add( title2,
new GridBagConstraints( 2,
0,
1,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets( 10, 5, 5, 5 ),
0,
0 )
);
contentPane.add( about,
new GridBagConstraints( 3,
0,
1,
1,
0.0,
0.0,
GridBagConstraints.EAST,
GridBagConstraints.NONE,
new Insets( 10, 5, 5, 10 ),
0,
0 )
);
contentPane.add( utcTimeLabel,
new GridBagConstraints( 0,
1,
1,
1,
0.0,
0.0,
GridBagConstraints.EAST,
GridBagConstraints.NONE,
new Insets( 10, 10, 0, 5 ),
0,
0 )
);
contentPane.add( utcTimeField,
new GridBagConstraints( 1,
1,
3,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets( 10, 5, 0, 10 ),
0,
0 )
);
contentPane.add( localTimeLabel,
new GridBagConstraints( 0,
2,
1,
1,
0.0,
0.0,
GridBagConstraints.EAST,
GridBagConstraints.NONE,
new Insets( 10, 10, 0, 5 ),
0,
0 )
);
contentPane.add( localTimeField,
new GridBagConstraints( 1,
2,
3,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets( 10, 5, 0, 10 ),
0,
0 )
);
contentPane.add( localTZLabel,
new GridBagConstraints( 0,
3,
1,
1,
0.0,
0.0,
GridBagConstraints.EAST,
GridBagConstraints.NONE,
new Insets( 10, 10, 0, 5 ),
0,
0 )
);
contentPane.add( localTZField,
new GridBagConstraints( 1,
3,
3,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets( 10, 5, 0, 10 ),
0,
0 )
);
contentPane.add( supportedLabel,
new GridBagConstraints( 0,
4,
3,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets( 10, 10, 0, 10 ),
0,
0 )
);
contentPane.add( scroller,
new GridBagConstraints( 0,
5,
4,
1,
1.0,
1.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets( 10, 10, 10, 10 ),
0,
0 )
);
contentPane.add( instructions,
new GridBagConstraints( 0,
6,
4,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets( 10, 10, 10, 10 ),
0,
0 )
);
}
/**
* Allow this Applet to run as as application as well.
*
* @param args command line arguments ignored.
*/
public static void main( String args[] )
{
HybridJ.fireup( new TZ(),
TITLE_STRING + " " + VERSION_STRING,
APPLET_WIDTH,
APPLET_HEIGHT );
}
/**
* Called by the browser or Applet viewer to inform
* this Applet that it is being reclaimed and that it should destroy
* any resources that it has allocated.
*/
public void destroy()
{
about = null;
instructions = null;
localTimeField = null;
localTimeLabel = null;
localTZField = null;
localTZLabel = null;
scroller = null;
supportedLabel = null;
timer = null;
timeZoneTable = null;
title2 = null;
title = null;
utcTimeField = null;
utcTimeLabel = null;
}
/**
* Called by the browser or Applet viewer to inform
* this Applet that it has been loaded into the system.
*/
@Override
public void init()
{
if ( !VersionCheck.isJavaVersionOK( 1, 8, 0, this ) )
{
return;
}
Common18.setLaf();
Container contentPane = this.getContentPane();
contentPane.setBackground( BACKGROUND_FOR_APPLET );
contentPane.setLayout( new GridBagLayout() );
buildComponents();
layoutComponents( contentPane );
this.validate();
}
/**
* usual Applet start, we start up Timer to update clock
*/
public void start()
{
timer = new Timer( 500, new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
localTimeField.setText( localTimeDisplay.format( new Date() ) );
utcTimeField.setText( utcTimeDisplay.format( new Date() ) );
}
} );
timer.setRepeats( true );
timer.start();
}
/**
* usual Applet stop, we kill Timer to update clock
*/
public void stop()
{
timer.stop();
timer = null;
}
/**
* Sort by TimeZone offset.
* <p/>
* Defines an alternate sort order for String.
*/
private static class ByOffset implements Comparator<String>
{
/**
* Sort by TimeZone offset.
* Defines an alternate sort order for String.
* Compare two String Objects.
* Compares getRawOffset then String
* Informally, returns (a-b), or +ve if a is more positive than b.
*
* @param a first String to compare
* @param b second String to compare
*
* @return +ve if a>b, 0 if a==b, -ve if a<b
*/
public final int compare( String a, String b )
{
final int diff = TimeZone.getTimeZone( a ).getRawOffset() - TimeZone.getTimeZone( b ).getRawOffset();
if ( diff != 0 )
{
return diff;
}
return a.compareTo( b );
}
}
/**
* nested inner class to render a column heading
*/
static final class HeaderRenderer implements TableCellRenderer
{
/**
* template for HeaderRender, reuses same component for all headers.
*/
private static final JLabel headerTemplate;
static
{
headerTemplate = new JLabel( "", JLabel.CENTER );
headerTemplate.setForeground( FOREGROUND_FOR_LABEL );
headerTemplate.setBackground( BACKGROUND_FOR_APPLET );
headerTemplate.setBorder( BorderFactory.createLineBorder( Color.GRAY ) );
headerTemplate.setOpaque( true );
}
public Component getTableCellRendererComponent( JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column )
{
headerTemplate.setText( value.toString() );
return headerTemplate;
}
}
/**
* nested inner class
*/
static final class TZTableModel extends AbstractTableModel implements TableModel
{
/**
* names of the columns
*/
static final String[] columnNames = {
"Offset", "DST", "ID", "Display Name" };
/**
* timeZoneIDs array of all possible TimeZone IDs
*/
private final String[] timeZoneIDs;
/**
* constructor.
*
* @param timeZoneIDs array of all possible TimeZone IDs, sorted in some reasonable order.
*/
TZTableModel( String[] timeZoneIDs )
{
this.timeZoneIDs = timeZoneIDs;
}
/**
* Returns the most specific superclass for all the cell values in the column. This is used by the
* <code>JTable</code> to set up a default renderer and editor for the column.
*
* @param columnIndex the index of the column
*
* @return the common ancestor class of the object values in the model.
*/
public Class<?> getColumnClass( int columnIndex )
{
switch ( columnIndex )
{
case 0:
case 1:
return Double.class;
case 2:
case 3:
return String.class;
default:
throw new ArrayIndexOutOfBoundsException(
"column index out of range in get ColumnClass" );
}
}
/**
* Returns the number of columns in the model. A <code>JTable</code> uses this method to determine how many
* columns it should create and display by default.
*
* @return the number of columns in the model
* @see #getRowCount
*/
public int getColumnCount()
{
return 4;
}
/**
* Returns the name of the column at <code>columnIndex</code>. This is used to initialize the table's column
* header name. Note: this name does not need to be unique; two columns in a table can have the same name.
*
* @param column the index of the column
*
* @return the name of the column
*/
public String getColumnName( int column )
{
return columnNames[ column ];
}
/**
* Returns the number of rows in the model. A <code>JTable</code> uses this method to determine how many rows it
* should display. This method should be quick, as it is called frequently during rendering.
*
* @return the number of rows in the model
* @see #getColumnCount
*/
public int getRowCount()
{
return timeZoneIDs.length;
}
public Object getValueAt( int rowIndex, int columnIndex )
{
final String timeZoneID = timeZoneIDs[ rowIndex ];
final TimeZone timeZone = TimeZone.getTimeZone( timeZoneID );
switch ( columnIndex )
{
case 0:
return timeZone.getRawOffset() / ( 60 * 60 * 1000.0D );
case 1:
final double raw =
timeZone.getRawOffset() / ( 60
* 60
* 1000.0D );// hrs winter
final double summer =
timeZone.getOffset( aSummerDay.getTime() ) / ( 60
* 60
* 1000.0D );// millis -> hrs summer
final double winter =
timeZone.getOffset( aWinterDay.getTime() ) / ( 60
* 60
* 1000.0D );// millis -> hrs summer
return ( raw == summer ) ? winter : summer;
case 2:
return timeZoneID;
case 3:
return timeZone.getDisplayName();
default:
throw new ArrayIndexOutOfBoundsException(
"col index out of range in get getValueAt" );
}
}
}
}