/* * [CanadianTax.java] * * Summary: Computes Canadian Sales taxes, GST, PST, HST, TVQ. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 1999-08-27 * 1.1 1999-08-29 improved documentation on the taxes * commas in display * 1.2 1999-08-31 add total Tax and total Payable * 1.3 1999-09-01 use of getProvChoices * 1.4 2001-01-01 Québec and PEI PST isCompounded; * 1.5 2002-01-01 mention Labrador * 1.6 2002-04-23 moved to package com.mindprod.canadiantax * 1.7 2002-04-30 BC Sales tax bumped to 7.5% * 1.8 2004-06-06 add about box and version check, and Nunavut support. * 1.9 2006-02-05 make it easier to configure the initial province choices. * pad files. * change default to Ontario. * coloured backgrounds * convert to Swing * 2.0 2006-02-06 * 2.1 2006-03-04 reformat with IntelliJ * 2.2 2006-06-04 new address * 2.3 2007-01-01 add PAD icon. * 2.4 2007-05-26 add spinner, drop in BC and Saskatchewan sales tax. * BC sales dropped to 7% from 7.5%, * Saskatchewan from 6% to 5% * 2.5 2007-06-07 tidy code * 2.6 2007-06-12 tidy code, dynamically switch between TVP and PST * 2.7 2007-09-08 add dual calc buttons, redo with double instead of long. * 2.8 2007-10-30 introduce named constants to make it easier to modify the tax tables. * 2.9 2007-12-31 GST drop 6 to 5% * 3.0 2008-03-03 correct spelling mistakes, display build and release date. * 3.1 2008-05-03 bigger window, hopefully making it work on Mac * 3.2 2008-05-07 make default province configurable. * 3.3 2008-05-15 change layout to make it work properly on the MacIntosh. * 3.4 2010-05-29 auto flip to new * 3.5 2010-07-07 display GST/PST breakout for HST. * 3.6 2010-07-28 display GST/PST/HST percentages * 3.7 2011-01-21 PST now payable out of province, seller's province irrelevant in determining tax. * 3.8 2011-03-24 Allow you to select asof date you want to see the taxes. * 3.9 2011-03-25 major rewrite. Move instructions to surrounding HTML. * 4.0 2011-03-25 release ability to calculate taxes for dates in the past. * 4.1 2011-06-14 add two promises of BC Liberal government to reduce HST on 2012-07-01 and 2014-07-01 * 4.2 2012-01-13 add menubar, configurable L&F, update BC future PST history. * 4.3 2013-01-02 fix Quebec 2013-01-01 change. * 4.4 2013-02-03 add nickel-rounded total */ package com.mindprod.canadiantax; import com.mindprod.common18.BigDate; import com.mindprod.common18.Build; import com.mindprod.common18.CMPAboutJBox; import com.mindprod.common18.FontFactory; import com.mindprod.common18.HybridJ; import com.mindprod.common18.JEButton; import com.mindprod.common18.Laf; import com.mindprod.common18.VersionCheck; import com.mindprod.spinner.DateSpinner; import com.mindprod.spinner.DollarNumberEditor; import com.mindprod.spinner.DollarNumberFormatter; import javax.swing.DefaultComboBoxModel; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JSpinner; import javax.swing.JSpinner.NumberEditor; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.Color; 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.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.text.DecimalFormat; import java.text.ParseException; import static java.lang.System.*; /** * Computes Canadian Sales taxes, GST, PST, HST, TVQ. * * @author Roedy Green, Canadian Mind Products * @version 4.4 2013-02-03 add nickel-rounded total * @since 1999-08-27 */ public final class CanadianTax extends JApplet { /** * true if want debugging output */ private static final boolean DEBUGGING = false; /** * height of Applet box in pixels. Does not include surrounding frame. */ private static final int APPLET_HEIGHT = 460; /** * Width of Applet box in pixels. */ private static final int APPLET_WIDTH = 550; private static final int FIRST_COPYRIGHT_YEAR = 1999; /** * undisplayed copyright notice. * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; private static final String RELEASE_DATE = "2013-02-03"; private static final String TITLE_STRING = "Canadian Sales Tax Calculator"; private static final String VERSION_STRING = "4.4"; /** * latest date we can compute taxes. If change this change canadiantax.html */ private static final BigDate MAX_DATE = new BigDate( "2015-12-31" ); /** * earliest date we can compute taxes */ private static final BigDate MIN_DATE = new BigDate( "1991-01-01" ); /** * background where for data entry where user enters a value. */ private static final Color BACKGROUND_FOR_EDITABLE = Color.WHITE; /** * medium green resultColor background, don't enter data here. */ private static final Color BACKGROUND_FOR_RESULT_MEDIUM = new Color( 0xafffe4 ); /** * pale green resultColor background, don't enter data here. */ private static final Color BACKGROUND_FOR_RESULT_PALE = new Color( 0xf6fff6 ); /** * darker green resultColor background, don't enter data here. */ private static final Color DARK_BACKGROUND_FOR_RESULT = new Color( 0x9fffd4 ); /** * data entry text field colour */ private static final Color FOREGROUND_FOR_ENTER = Color.BLACK; /** * indicates this value will be excluded from total */ private static final Color FOREGROUND_FOR_EXCLUDED_FROM_PERCENT = new Color( 0xbbbbbbb ); // higher number, // more washed out /** * indicates this value will be excluded from total */ private static final Color FOREGROUND_FOR_EXCLUDED_FROM_TOTAL = new Color( 0xbbbbbbb ); // higher number, // more washed out /** * indicates this value will be included in total */ private static final Color FOREGROUND_FOR_INCLUDED_IN_TOTAL = Color.BLACK; private static final Color FOREGROUND_FOR_INCLUDED_PERCENT = 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 ); private static final Color FOREGROUND_FOR_TOTAL = Color.BLACK; /** * format for display and input of sale amount */ private static final DecimalFormat DOLLARFORMAT = new DecimalFormat( "'$'###,###,###,###,##0.00" ); /** * format for display of a percentage three decimal places and a % */ private static final DecimalFormat PERCENTFORMAT3 = new DecimalFormat( "##0.###'%'" ); private static final Font FONT_FOR_LABELS; /** * for for titles and About buttons */ private static final Font FONT_FOR_TITLE; /** * for for title second line */ private static final Font FONT_FOR_TITLE2; private static final Font FONT_FOR_VALUES; /** * see CanadianTaxTable.getProvChoices */ private static Province defaultBuyerProv; static { if ( DEBUGGING ) { out.println( "selecting fonts..." ); } FONT_FOR_LABELS = FontFactory.build( "Dialog", Font.BOLD, 14 ); FONT_FOR_VALUES = FontFactory.build( "Dialog", Font.BOLD, 15 ); FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 ); FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 ); } /** * canadian tax calculator object, holds result fields. */ private final CalculateCanadianTaxes calc = new CalculateCanadianTaxes(); /** * date we calculate taxes effective */ private DateSpinner asOfDate; /** * trigger calculation. */ private JButton calcSaleAmountButton; /** * trigger calculation. */ private JButton calcTotalPayableButton; /** * province where buyer lives. */ private JComboBox buyerProv; /** * label for asOfDate */ private JLabel asOfDateLabel; /** * label for buyer province. */ private JLabel buyerProvLabel; /** * label for GST. */ private JLabel gstLabel; /** * label for HST. */ private JLabel hstLabel; /** * label for PST. */ private JLabel pstLabel; /** * label for rounded amount payable. */ private JLabel roundedLabel; /** * label for amount of sale. */ private JLabel saleAmountLabel; /** * title */ private JLabel title; /** * title, second line */ private JLabel title2; /** * label for total amount payable. */ private JLabel totalPayableLabel; /** * label for total tax payable. */ private JLabel totalTaxLabel; /** * dollar amount of sale with a spinner to increment/decrement by pennies. * setValue ( double ); (Double) getValue. */ private JSpinner saleAmountSpinner; /** * GST payable. */ private JTextField gstAmountText; /** * GST %. */ private JTextField gstRateText; /** * HST payable. */ private JTextField hstAmountText; /** * HST %. */ private JTextField hstRateText; /** * PST payable. */ private JTextField pstAmountText; /** * PST payable. */ private JTextField pstRateText; /** * total amount rounded. */ private JTextField roundedText; /** * total amount payable. */ private JTextField totalPayableAmountText; /** * total tax payable. */ private JTextField totalTaxAmountText; /** * total tax %. */ private JTextField totalTaxRateText; /** * tracks value of the sale amount spinner. */ private SpinnerNumberModel saleAmountSpinnerModel; /** * constructor for use on as applet */ public CanadianTax() { } /** * constructor for use on command line as an application * * @param defaultProv 2-letter province default. */ private CanadianTax( String defaultProv ) { validateDefaultProv( defaultProv ); } /** * convert dollar value with decorative $ and decimal point. e.g. 1.00 -> $1.00 5 -> $0.05 -90000.00 -> * -$90,000.00 * * @param amount value to be converted. * @param bz true for blank if zero * * @return String showing pennies as a dollar value */ private static String toDollarString( double amount, boolean bz ) { if ( bz && amount == 0 ) { return ""; } else { return DOLLARFORMAT.format( amount ); } } /** * convert * * @param percent percent to be converted. 7.00 = 7% * * @return String showing percentage with % sign */ private static String toPercentString( double percent ) { if ( percent == 0 ) { return ""; } else { return PERCENTFORMAT3.format( percent ); } } /** * validate default prov, compute default if missing. * * @param defaultProv 2-letter upper case prov abbr or null if none. */ private static void validateDefaultProv( String defaultProv ) { if ( defaultProv != null && defaultProv.length() == 2 ) { String provAbbr2 = defaultProv.toUpperCase(); if ( provAbbr2.equals( "PQ" ) ) { provAbbr2 = "QC"; } else if ( provAbbr2.equals( "YK" ) ) { provAbbr2 = "YT"; } else if ( provAbbr2.equals( "NF" ) ) { provAbbr2 = "NL"; } try { defaultBuyerProv = Province.valueOf( provAbbr2 ); return; } catch ( IllegalArgumentException e ) { } } err.println( "Missing or invalid default province parameter. Assuming ON for Ontario." ); defaultBuyerProv = Province.ON; } /** * build a menu with Look & Feel and About across the top */ private void buildMenu() { // turn on anti-alias System.setProperty( "swing.aatext", "true" ); final JMenuBar menubar = new JMenuBar(); setJMenuBar( menubar ); final JMenu lafMenu = Laf.buildLookAndFeelMenu(); if ( lafMenu != null ) { menubar.add( lafMenu ); } final JMenu menuHelp = new JMenu( "Help" ); menubar.add( menuHelp ); final JMenuItem aboutItem = new JMenuItem( "About" ); menuHelp.add( aboutItem ); aboutItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { // open aboutbox frame new CMPAboutJBox( TITLE_STRING, VERSION_STRING, "Calculates Canadian GST/HST/PST sales taxes", "given the buyer's province.", "freeware", RELEASE_DATE, FIRST_COPYRIGHT_YEAR, "Roedy Green", "CANADIANTAX", "1.8" ); } } ); } /** * starting from totalPayable, work backwards to sale amount. */ private void calcAndDisplaySaleAmount() { // buyer province final Province bp = ( Province ) buyerProv.getSelectedItem(); // in Québec PST is called TVP pstLabel.setText( bp == Province.QC ? "TVQ" : "PST" ); String totalPayableString = totalPayableAmountText.getText(); // fancy parse that ignores $ double totalPayable; try { totalPayable = ( Double ) new DollarNumberFormatter().stringToValue( totalPayableString ); } catch ( ParseException event ) { totalPayable = 0; } // will already be rounded. final BigDate date = asOfDate.getValue(); final double saleAmount = calc.calculateSaleAmount( bp, date, totalPayable ); saleAmountSpinner.setValue( saleAmount ); } /** * Calculate and display gst, hst, pst based on current screen values. */ private void calcAndDisplayTaxes() { // buyer province final Province bp = ( Province ) buyerProv.getSelectedItem(); final BigDate date = asOfDate.getValue(); // in Québec PST is called TVP pstLabel.setText( bp == Province.QC ? "TVQ" : "PST" ); final double saleAmount = saleAmountSpinnerModel.getNumber().doubleValue(); calc.calculateCanadianTaxes( bp, date, saleAmount ); // calculate percent rates final double gstRate = calc.getGstRate(); final double hstRate = calc.getHstRate(); final double pstRate = calc.getPstRate(); final double getTotalTaxRate = calc.getTotalTaxRate(); gstRateText.setText( toPercentString( gstRate ) ); hstRateText.setText( toPercentString( hstRate ) ); pstRateText.setText( toPercentString( pstRate ) ); totalTaxRateText.setText( toPercentString( getTotalTaxRate ) ); // calculate tax amounts final double gstAmount = calc.getGstAmount(); final double hstAmount = calc.getHstAmount(); final double pstAmount = calc.getPstAmount(); final double totalTaxAmount = calc.getTotalTaxAmount(); final double totalPayableAmount = calc.getTotalPayableAmount(); final double nickelRoundedtotalPayableAmount = calc.getNickelRoundedtotalPayableAmount(); // display results boolean gives BZ if ( hstAmount > 0 ) { gstAmountText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_TOTAL ); hstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); pstAmountText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_TOTAL ); gstRateText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_PERCENT ); hstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); pstRateText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_PERCENT ); } else { gstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); hstAmountText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_TOTAL ); pstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); gstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); hstRateText.setForeground( FOREGROUND_FOR_EXCLUDED_FROM_PERCENT ); pstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); } gstAmountText.setText( toDollarString( gstAmount, true ) ); hstAmountText.setText( toDollarString( hstAmount, true ) ); pstAmountText.setText( toDollarString( pstAmount, true ) ); totalTaxAmountText.setText( toDollarString( totalTaxAmount, false ) ); totalPayableAmountText.setText( toDollarString( totalPayableAmount, false ) ); roundedText.setText( toDollarString( nickelRoundedtotalPayableAmount, false ) ); } // end calcAndDisplayTaxes /** * create Swing Components */ private void createComponents() { 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 ); // asOfDateLabel = new JLabel( "As-of Date", JLabel.RIGHT ); asOfDateLabel.setFont( FONT_FOR_LABELS ); asOfDateLabel.setForeground( FOREGROUND_FOR_LABEL ); // asOfDate = new DateSpinner(); asOfDate.setMinimum( MIN_DATE ); asOfDate.setMaximum( MAX_DATE ); // default value is today. // buyerProv = new JComboBox<>(); // turn off the write-in feature. buyerProv.setEditable( false ); // add legal choices to boxes buyerProv.setModel( new DefaultComboBoxModel<>( Province.values() ) ); buyerProv.setSelectedItem( defaultBuyerProv ); // buyerProvLabel = new JLabel( "Buyer's Province", JLabel.RIGHT ); buyerProvLabel.setFont( FONT_FOR_LABELS ); buyerProvLabel.setForeground( FOREGROUND_FOR_LABEL ); // saleAmountSpinner = new JSpinner(); saleAmountSpinner.setFont( FONT_FOR_LABELS ); saleAmountSpinner.setBackground( BACKGROUND_FOR_EDITABLE ); saleAmountSpinner.setForeground( FOREGROUND_FOR_ENTER ); saleAmountSpinner.setValue( 100.00d ); saleAmountSpinnerModel = new SpinnerNumberModel( /* initial value */ 100.00d, /* min */ 0.00d, /* max */ 999999.99d, /* step */ 0.01d ); // use custom editor, makes lead $ optional. final NumberEditor saleAmountNumberEditor = new DollarNumberEditor( saleAmountSpinner ); saleAmountSpinner.setModel( saleAmountSpinnerModel ); saleAmountSpinner.setEditor( saleAmountNumberEditor ); JFormattedTextField inner = saleAmountNumberEditor.getTextField(); inner.setMargin( new Insets( 0, 2, 0, 2 ) ); // ?? does not work, why? // saleAmountLabel = new JLabel( "Amount of Sale", JLabel.CENTER ); saleAmountLabel.setFont( FONT_FOR_LABELS ); saleAmountLabel.setForeground( FOREGROUND_FOR_LABEL ); // final boolean usingMac = System.getProperty( "os.name" ).equals( "Mac OS X" ); // prefer double to single arrow, must use single arrow on some Macs final char downArrow = usingMac ? '\u2193' : '\u21d3'; final char upArrow = usingMac ? '\u2191' : '\u21d1'; calcTotalPayableButton = new JEButton( "Calc " + downArrow ); calcTotalPayableButton.setToolTipText( "Calculate sales tax" ); // calcSaleAmountButton = new JEButton( "Calc " + upArrow ); calcSaleAmountButton.setToolTipText( "Reverse calculate sale amount" ); // gstAmountText = new JTextField( 16 ); gstAmountText.setEditable( false ); gstAmountText.setFont( FONT_FOR_VALUES ); gstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); gstAmountText.setBackground( BACKGROUND_FOR_RESULT_PALE ); gstAmountText.setHorizontalAlignment( JTextField.RIGHT ); gstAmountText.setMargin( new Insets( 2, 2, 2, 2 ) ); // gstRateText = new JTextField( 6 ); gstRateText.setEditable( false ); gstRateText.setFont( FONT_FOR_VALUES ); gstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); gstRateText.setHorizontalAlignment( JTextField.RIGHT ); gstRateText.setMargin( new Insets( 2, 2, 2, 2 ) ); // gstLabel = new JLabel( "GST/TPS", JLabel.RIGHT ); gstLabel.setFont( FONT_FOR_LABELS ); gstLabel.setForeground( FOREGROUND_FOR_LABEL ); // hstAmountText = new JTextField( 16 ); hstAmountText.setEditable( false ); hstAmountText.setFont( FONT_FOR_VALUES ); hstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); hstAmountText.setBackground( BACKGROUND_FOR_RESULT_PALE ); hstAmountText.setHorizontalAlignment( JTextField.RIGHT ); hstAmountText.setMargin( new Insets( 2, 2, 2, 2 ) ); // hstRateText = new JTextField( 6 ); hstRateText.setEditable( false ); hstRateText.setFont( FONT_FOR_VALUES ); hstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); hstRateText.setHorizontalAlignment( JTextField.RIGHT ); hstRateText.setMargin( new Insets( 2, 2, 2, 2 ) ); // hstLabel = new JLabel( "HST", JLabel.RIGHT ); hstLabel.setFont( FONT_FOR_LABELS ); hstLabel.setForeground( FOREGROUND_FOR_LABEL ); // pstAmountText = new JTextField( 16 ); pstAmountText.setEditable( false ); pstAmountText.setFont( FONT_FOR_VALUES ); pstAmountText.setForeground( FOREGROUND_FOR_INCLUDED_IN_TOTAL ); pstAmountText.setBackground( BACKGROUND_FOR_RESULT_PALE ); pstAmountText.setHorizontalAlignment( JTextField.RIGHT ); pstAmountText.setMargin( new Insets( 2, 2, 2, 2 ) ); // pstRateText = new JTextField( 6 ); pstRateText.setEditable( false ); pstRateText.setFont( FONT_FOR_VALUES ); pstRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); pstRateText.setHorizontalAlignment( JTextField.RIGHT ); pstRateText.setMargin( new Insets( 2, 2, 2, 2 ) ); // /* will dynamically change to TVQ */ pstLabel = new JLabel( "PST", JLabel.RIGHT ); pstLabel.setFont( FONT_FOR_LABELS ); pstLabel.setForeground( FOREGROUND_FOR_LABEL ); // totalTaxAmountText = new JTextField( 16 ); totalTaxAmountText.setEditable( false ); totalTaxAmountText.setFont( FONT_FOR_VALUES ); totalTaxAmountText.setBackground( BACKGROUND_FOR_RESULT_MEDIUM ); totalTaxAmountText.setForeground( FOREGROUND_FOR_TOTAL ); totalTaxAmountText.setHorizontalAlignment( JTextField.RIGHT ); totalTaxAmountText.setMargin( new Insets( 2, 2, 2, 2 ) ); // totalTaxRateText = new JTextField( 6 ); totalTaxRateText.setEditable( false ); totalTaxRateText.setFont( FONT_FOR_VALUES ); totalTaxRateText.setForeground( FOREGROUND_FOR_INCLUDED_PERCENT ); totalTaxRateText.setHorizontalAlignment( JTextField.RIGHT ); totalTaxRateText.setMargin( new Insets( 2, 2, 2, 2 ) ); // totalTaxLabel = new JLabel( "Total Tax", JLabel.RIGHT ); totalTaxLabel.setFont( FONT_FOR_LABELS ); totalTaxLabel.setForeground( FOREGROUND_FOR_LABEL ); // totalPayableAmountText = new JTextField( 16 ); totalPayableAmountText.setEditable( true ); totalPayableAmountText.setFont( FONT_FOR_VALUES ); totalPayableAmountText.setBackground( DARK_BACKGROUND_FOR_RESULT ); totalPayableAmountText.setForeground( FOREGROUND_FOR_TOTAL ); totalPayableAmountText.setHorizontalAlignment( JTextField.RIGHT ); totalPayableAmountText.setMargin( new Insets( 2, 2, 2, 2 ) ); // totalPayableLabel = new JLabel( "Total Payable", JLabel.RIGHT ); totalPayableLabel.setFont( FONT_FOR_LABELS ); totalPayableLabel.setForeground( FOREGROUND_FOR_LABEL ); // roundedText = new JTextField( 16 ); roundedText.setEditable( false ); roundedText.setFont( FONT_FOR_VALUES ); roundedText.setBackground( DARK_BACKGROUND_FOR_RESULT ); roundedText.setForeground( FOREGROUND_FOR_TOTAL ); roundedText.setHorizontalAlignment( JTextField.RIGHT ); roundedText.setMargin( new Insets( 2, 2, 2, 2 ) ); // roundedLabel = new JLabel( "Nickel Rounded", JLabel.RIGHT ); roundedLabel.setFont( FONT_FOR_LABELS ); roundedLabel.setForeground( FOREGROUND_FOR_LABEL ); } /** * hook up the listeners */ private void hookListeners() { // engage the listeners asOfDate.addChangeListener( new ChangeListener() { public void stateChanged( final ChangeEvent e ) { calcAndDisplayTaxes(); } } ); calcTotalPayableButton.addActionListener( new ActionListener() { /** * user clicked calc V * @param e button push event */ public void actionPerformed( ActionEvent e ) { calcAndDisplayTaxes(); } // end actionPerformed } ); calcSaleAmountButton.addActionListener( new ActionListener() { /** * user clicked calc ^ * @param e button push event */ public void actionPerformed( ActionEvent e ) { // work backwards then forward again calcAndDisplaySaleAmount(); calcAndDisplayTaxes(); } // end actionPerformed } ); buyerProv.addItemListener( new ItemListener() { /** * Notice any change to one of the list box selectors * @param e details of just what the user clicked. */ public void itemStateChanged( ItemEvent e ) { calcAndDisplayTaxes(); } // end itemStateChanged } ); saleAmountSpinnerModel.addChangeListener( new ChangeListener() { /** * } * spinner changed value * @param e event from spinner */ public void stateChanged( ChangeEvent e ) { calcAndDisplayTaxes(); } // end actionPerformed } ); // don't also need saleAmountSpinner.addChangeListener } /** * layout the components * * @param contentPane where to layout the components */ private void layoutGridBag( Container contentPane ) { // basic layout: // ------0-----------1 --2--------------3 // 0 -------title----- ------title2------ // 1 // 2 asOfDateLabel asofDate // 3 buyerprovlabel buyerProv --------- // 4 ----saleAmountLabel saleAmount CALC // 5 ----------gstLabel %-----GST // 6 ---------hstLabel %-----HST // 7 ---------pstLabel %-----PST // 8 ----totalTaxLabel % totalTax // 9 totalPayableLabel totalPayable REV CALC // 0 ----------0---------1 -----2-----3--- // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title, new GridBagConstraints( 0, 0, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 10, 10, 0, 5 ), 0, 0 ) ); contentPane.add( title2, new GridBagConstraints( 2, 0, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 10, 5, 0, 10 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( asOfDateLabel, new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 10, 10, 5, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( asOfDate, new GridBagConstraints( 1, 2, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 10, 5, 5, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( buyerProvLabel, new GridBagConstraints( 0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( buyerProv, new GridBagConstraints( 1, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( saleAmountLabel, new GridBagConstraints( 0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( saleAmountSpinner /* saleAmountText */, new GridBagConstraints( 1, 4, 2, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( calcTotalPayableButton, new GridBagConstraints( 3, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 5, 0, 10 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( gstLabel, new GridBagConstraints( 0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( gstRateText, new GridBagConstraints( 1, 5, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( gstAmountText, new GridBagConstraints( 2, 5, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 + 20 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( hstLabel, new GridBagConstraints( 0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( hstRateText, new GridBagConstraints( 1, 6, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( hstAmountText, new GridBagConstraints( 2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 + 20 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( pstLabel, new GridBagConstraints( 0, 7, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( pstRateText, new GridBagConstraints( 1, 7, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( pstAmountText, new GridBagConstraints( 2, 7, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 + 20 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( totalTaxLabel, new GridBagConstraints( 0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 0, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( totalTaxRateText, new GridBagConstraints( 1, 8, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 ), 65, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( totalTaxAmountText, new GridBagConstraints( 2, 8, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 5 + 20 ), 120, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( totalPayableLabel, new GridBagConstraints( 0, 9, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 5, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( totalPayableAmountText, new GridBagConstraints( 1, 9, 2, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 5, 5 + 20 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( calcSaleAmountButton, new GridBagConstraints( 3, 9, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 5, 5, 10 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( roundedLabel, new GridBagConstraints( 0, 10, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 10, 10, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( roundedText, new GridBagConstraints( 1, 10, 2, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 10, 5 + 20 ), 0, 0 ) ); } /** * Allow this CanadianTax Applet to run as as a hybrid application as well. * * @param args command line arguments ignored. */ public static void main( String args[] ) { HybridJ.fireup( new CanadianTax( args.length == 1 ? args[ 0 ] : null ), 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() { asOfDate = null; asOfDateLabel = null; buyerProv = null; buyerProvLabel = null; calcSaleAmountButton = null; calcTotalPayableButton = null; gstAmountText = null; gstLabel = null; gstRateText = null; hstAmountText = null; hstLabel = null; hstRateText = null; pstAmountText = null; pstLabel = null; pstRateText = null; saleAmountLabel = null; saleAmountSpinner = null; saleAmountSpinnerModel = null; title = null; title2 = null; totalPayableAmountText = null; totalPayableLabel = null; totalTaxAmountText = null; totalTaxLabel = null; totalTaxRateText = 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; } buildMenu(); // also initial L&F Province.importTaxResource(); if ( defaultBuyerProv == null ) { // we were invoked as an Applet validateDefaultProv( this.getParameter( "prov" ) ); } Container contentPane = this.getContentPane(); contentPane.setBackground( BACKGROUND_FOR_RESULT_PALE ); contentPane.setLayout( new GridBagLayout() ); if ( DEBUGGING ) { out.println( "creating components..." ); } createComponents(); if ( DEBUGGING ) { out.println( "calculating default values..." ); } calcAndDisplayTaxes(); layoutGridBag( contentPane ); hookListeners(); this.validate(); this.setVisible( true ); } // end init }