/* * CompassPanel.java 22 sept. 2010 * * Sweet Home 3D, Copyright (c) 2010 Emmanuel PUYBARET / eTeks <info@eteks.com> * * This program 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 com.eteks.sweethome3d.swing; import java.awt.BasicStroke; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.RenderingHints; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.TimeZone; import javax.swing.DefaultListCellRenderer; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JSpinner.DefaultEditor; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.DefaultFormatterFactory; import javax.swing.text.NumberFormatter; import com.eteks.sweethome3d.model.UserPreferences; import com.eteks.sweethome3d.tools.OperatingSystem; import com.eteks.sweethome3d.viewcontroller.CompassController; import com.eteks.sweethome3d.viewcontroller.DialogView; import com.eteks.sweethome3d.viewcontroller.View; /** * Compass editing panel. * @author Emmanuel Puybaret */ public class CompassPanel extends JPanel implements DialogView { private final CompassController controller; private JLabel xLabel; private JSpinner xSpinner; private JLabel yLabel; private JSpinner ySpinner; private JLabel diameterLabel; private JSpinner diameterSpinner; private JCheckBox visibleCheckBox; private JComponent northDirectionComponent; private JLabel longitudeLabel; private JSpinner longitudeSpinner; private JLabel latitudeLabel; private JSpinner latitudeSpinner; private JLabel timeZoneLabel; private JComboBox timeZoneComboBox; private JLabel northDirectionLabel; private JSpinner northDirectionSpinner; private String dialogTitle; /** * Creates a panel that displays compass data. * @param preferences user preferences * @param controller the controller of this panel */ public CompassPanel(UserPreferences preferences, CompassController controller) { super(new GridBagLayout()); this.controller = controller; createComponents(preferences, controller); setMnemonics(preferences); layoutComponents(preferences); } /** * Creates and initializes components. */ private void createComponents(UserPreferences preferences, final CompassController controller) { // Get unit name matching current unit String unitName = preferences.getLengthUnit().getName(); // Create X label and its spinner bound to X controller property this.xLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "xLabel.text", unitName)); float maximumLength = preferences.getLengthUnit().getMaximumLength(); final NullableSpinner.NullableSpinnerLengthModel xSpinnerModel = new NullableSpinner.NullableSpinnerLengthModel(preferences, -maximumLength, maximumLength); this.xSpinner = new JSpinner(xSpinnerModel); xSpinnerModel.setLength(controller.getX()); final PropertyChangeListener xChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { xSpinnerModel.setLength((Float)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.X, xChangeListener); xSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.X, xChangeListener); controller.setX(xSpinnerModel.getLength()); controller.addPropertyChangeListener(CompassController.Property.X, xChangeListener); } }); // Create Y label and its spinner bound to Y controller property this.yLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "yLabel.text", unitName)); final NullableSpinner.NullableSpinnerLengthModel ySpinnerModel = new NullableSpinner.NullableSpinnerLengthModel(preferences, -maximumLength, maximumLength); this.ySpinner = new NullableSpinner(ySpinnerModel); ySpinnerModel.setLength(controller.getY()); final PropertyChangeListener yChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { ySpinnerModel.setLength((Float)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.Y, yChangeListener); ySpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.Y, yChangeListener); controller.setY(ySpinnerModel.getLength()); controller.addPropertyChangeListener(CompassController.Property.Y, yChangeListener); } }); // Create diameter label and its spinner bound to DIAMETER controller property this.diameterLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "diameterLabel.text", unitName)); final NullableSpinner.NullableSpinnerLengthModel diameterSpinnerModel = new NullableSpinner.NullableSpinnerLengthModel(preferences, preferences.getLengthUnit().getMinimumLength(), preferences.getLengthUnit().getMaximumLength() / 10); this.diameterSpinner = new NullableSpinner(diameterSpinnerModel); diameterSpinnerModel.setLength(controller.getDiameter()); final PropertyChangeListener diameterChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { diameterSpinnerModel.setLength((Float)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.DIAMETER, diameterChangeListener); diameterSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.DIAMETER, diameterChangeListener); controller.setDiameter(diameterSpinnerModel.getLength()); controller.addPropertyChangeListener(CompassController.Property.DIAMETER, diameterChangeListener); } }); // Create visible check box bound to VISIBLE controller property this.visibleCheckBox = new JCheckBox(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "visibleCheckBox.text")); this.visibleCheckBox.setSelected(controller.isVisible()); final PropertyChangeListener visibleChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { visibleCheckBox.setSelected((Boolean)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.VISIBLE, visibleChangeListener); this.visibleCheckBox.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.VISIBLE, visibleChangeListener); controller.setVisible(visibleCheckBox.isSelected()); controller.addPropertyChangeListener(CompassController.Property.VISIBLE, visibleChangeListener); } }); this.latitudeLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "latitudeLabel.text")); final SpinnerNumberModel latitudeSpinnerModel = new SpinnerNumberModel(new Float(0), new Float(-90), new Float(90), new Float(5)); this.latitudeSpinner = new JSpinner(latitudeSpinnerModel); // Change positive / negative notation by North / South JFormattedTextField textField = ((DefaultEditor)this.latitudeSpinner.getEditor()).getTextField(); NumberFormatter numberFormatter = (NumberFormatter)((DefaultFormatterFactory)textField.getFormatterFactory()).getDefaultFormatter(); numberFormatter.setFormat(new DecimalFormat("N ##0.000;S ##0.000")); textField.setFormatterFactory(new DefaultFormatterFactory(numberFormatter)); SwingTools.addAutoSelectionOnFocusGain(textField); latitudeSpinnerModel.setValue(controller.getLatitudeInDegrees()); final PropertyChangeListener latitudeChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { latitudeSpinnerModel.setValue((Float)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.LATITUDE_IN_DEGREES, latitudeChangeListener); latitudeSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.LATITUDE_IN_DEGREES, latitudeChangeListener); controller.setLatitudeInDegrees(((Number)latitudeSpinnerModel.getValue()).floatValue()); controller.addPropertyChangeListener(CompassController.Property.LATITUDE_IN_DEGREES, latitudeChangeListener); } }); this.longitudeLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "longitudeLabel.text")); final SpinnerNumberModel longitudeSpinnerModel = new SpinnerNumberModel(new Float(0), new Float(-180), new Float(180), new Float(5)); this.longitudeSpinner = new JSpinner(longitudeSpinnerModel); // Change positive / negative notation by East / West textField = ((DefaultEditor)this.longitudeSpinner.getEditor()).getTextField(); numberFormatter = (NumberFormatter)((DefaultFormatterFactory)textField.getFormatterFactory()).getDefaultFormatter(); numberFormatter.setFormat(new DecimalFormat("E ##0.000;W ##0.000")); textField.setFormatterFactory(new DefaultFormatterFactory(numberFormatter)); SwingTools.addAutoSelectionOnFocusGain(textField); longitudeSpinnerModel.setValue(controller.getLongitudeInDegrees()); final PropertyChangeListener longitudeChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { longitudeSpinnerModel.setValue((Float)ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.LONGITUDE_IN_DEGREES, longitudeChangeListener); longitudeSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.LONGITUDE_IN_DEGREES, longitudeChangeListener); controller.setLongitudeInDegrees(((Number)longitudeSpinnerModel.getValue()).floatValue()); controller.addPropertyChangeListener(CompassController.Property.LONGITUDE_IN_DEGREES, longitudeChangeListener); } }); this.timeZoneLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "timeZoneLabel.text")); List<String> timeZoneIds = new ArrayList<String>(Arrays.asList(TimeZone.getAvailableIDs())); // Remove synonymous time zones timeZoneIds.remove("GMT"); timeZoneIds.remove("GMT0"); timeZoneIds.remove("Etc/GMT0"); timeZoneIds.remove("Etc/GMT-0"); timeZoneIds.remove("Etc/GMT+0"); // Replace Etc/GMT... ids by their English value that are less misleading for (int i = 0; i < timeZoneIds.size(); i++) { String timeZoneId = timeZoneIds.get(i); if (timeZoneId.startsWith("Etc/GMT")) { timeZoneIds.set(i, TimeZone.getTimeZone(timeZoneId).getDisplayName(Locale.ENGLISH)); } } String [] timeZoneIdsArray = timeZoneIds.toArray(new String [timeZoneIds.size()]); Arrays.sort(timeZoneIdsArray); this.timeZoneComboBox = new JComboBox(timeZoneIdsArray); this.timeZoneComboBox.setSelectedItem(controller.getTimeZone()); final PropertyChangeListener timeZoneChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { timeZoneComboBox.setSelectedItem(ev.getNewValue()); } }; controller.addPropertyChangeListener(CompassController.Property.TIME_ZONE, timeZoneChangeListener); this.timeZoneComboBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { String timeZoneId = (String)value; if (timeZoneId.startsWith("GMT")) { if (!OperatingSystem.isMacOSX()) { setToolTipText(timeZoneId); } } else { String timeZoneDisplayName = TimeZone.getTimeZone(timeZoneId).getDisplayName(); if (OperatingSystem.isMacOSX()) { value = timeZoneId + " - " + timeZoneDisplayName; } else { // Use tool tip do display the complete time zone information setToolTipText(timeZoneId + " - " + timeZoneDisplayName); } } return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } }); this.timeZoneComboBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { controller.removePropertyChangeListener(CompassController.Property.TIME_ZONE, timeZoneChangeListener); controller.setTimeZone((String)timeZoneComboBox.getSelectedItem()); controller.addPropertyChangeListener(CompassController.Property.TIME_ZONE, timeZoneChangeListener); } }); this.timeZoneComboBox.setPrototypeDisplayValue("GMT"); this.northDirectionLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences, CompassPanel.class, "northDirectionLabel.text")); // Create a spinner model able to choose an angle modulo 360 final SpinnerNumberModel northDirectionSpinnerModel = new SpinnerNumberModel(0, 0, 360, 5) { @Override public Object getNextValue() { if (((Number)getValue()).intValue() + ((Number)getStepSize()).intValue() < ((Number)getMaximum()).intValue()) { return super.getNextValue(); } else { return ((Number)getValue()).intValue() + ((Number)getStepSize()).intValue() - ((Number)getMaximum()).intValue() + ((Number)getMinimum()).intValue(); } } @Override public Object getPreviousValue() { if (((Number)getValue()).intValue() - ((Number)getStepSize()).intValue() >= ((Number)getMinimum()).intValue()) { return super.getPreviousValue(); } else { return ((Number)getValue()).intValue() - ((Number)getStepSize()).intValue() - ((Number)getMinimum()).intValue() + ((Number)getMaximum()).intValue(); } } }; this.northDirectionSpinner = new AutoCommitSpinner(northDirectionSpinnerModel); northDirectionSpinnerModel.setValue(new Integer(Math.round(controller.getNorthDirectionInDegrees()))); this.northDirectionComponent = new JComponent() { @Override public Dimension getPreferredSize() { return new Dimension(35, 35); } @Override protected void paintComponent(Graphics g) { Graphics2D g2D = (Graphics2D) g; g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2D.translate(getWidth() / 2, getHeight() / 2); g2D.scale(getWidth() / 2, getWidth() / 2); g2D.rotate(Math.toRadians(controller.getNorthDirectionInDegrees())); // Draw a round arc g2D.setStroke(new BasicStroke(0.5f / getWidth())); g2D.draw(new Ellipse2D.Float(-0.7f, -0.7f, 1.4f, 1.4f)); g2D.draw(new Line2D.Float(-0.85f, 0, -0.7f, 0)); g2D.draw(new Line2D.Float(0.85f, 0, 0.7f, 0)); g2D.draw(new Line2D.Float(0, -0.8f, 0, -0.7f)); g2D.draw(new Line2D.Float(0, 0.85f, 0, 0.7f)); // Draw a N GeneralPath path = new GeneralPath(); path.moveTo(-0.1f, -0.8f); path.lineTo(-0.1f, -1f); path.lineTo(0.1f, -0.8f); path.lineTo(0.1f, -1f); g2D.setStroke(new BasicStroke(1.5f / getWidth())); g2D.draw(path); // Draw the needle GeneralPath needlePath = new GeneralPath(); needlePath.moveTo(0, -0.75f); needlePath.lineTo(0.2f, 0.7f); needlePath.lineTo(0, 0.5f); needlePath.lineTo(-0.2f, 0.7f); needlePath.closePath(); needlePath.moveTo(-0.02f, 0); needlePath.lineTo(0.02f, 0); g2D.setStroke(new BasicStroke(4 / getWidth())); g2D.draw(needlePath); } }; this.northDirectionComponent.setOpaque(false); final PropertyChangeListener northDirectionChangeListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { northDirectionSpinnerModel.setValue(((Number)ev.getNewValue()).intValue()); northDirectionComponent.repaint(); } }; controller.addPropertyChangeListener(CompassController.Property.NORTH_DIRECTION_IN_DEGREES, northDirectionChangeListener); northDirectionSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ev) { controller.removePropertyChangeListener(CompassController.Property.NORTH_DIRECTION_IN_DEGREES, northDirectionChangeListener); controller.setNorthDirectionInDegrees(((Number)northDirectionSpinnerModel.getValue()).floatValue()); northDirectionComponent.repaint(); controller.addPropertyChangeListener(CompassController.Property.NORTH_DIRECTION_IN_DEGREES, northDirectionChangeListener); } }); this.dialogTitle = preferences.getLocalizedString(CompassPanel.class, "compass.title"); } /** * Sets components mnemonics and label / component associations. */ private void setMnemonics(UserPreferences preferences) { if (!OperatingSystem.isMacOSX()) { this.xLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "xLabel.mnemonic")).getKeyCode()); this.xLabel.setLabelFor(this.xSpinner); this.yLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "yLabel.mnemonic")).getKeyCode()); this.yLabel.setLabelFor(this.ySpinner); this.diameterLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "diameterLabel.mnemonic")).getKeyCode()); this.diameterLabel.setLabelFor(this.diameterSpinner); this.visibleCheckBox.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "visibleCheckBox.mnemonic")).getKeyCode()); this.latitudeLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "latitudeLabel.mnemonic")).getKeyCode()); this.latitudeLabel.setLabelFor(this.latitudeSpinner); this.longitudeLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "longitudeLabel.mnemonic")).getKeyCode()); this.longitudeLabel.setLabelFor(this.longitudeSpinner); this.timeZoneLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "timeZoneLabel.mnemonic")).getKeyCode()); this.timeZoneLabel.setLabelFor(this.timeZoneComboBox); this.northDirectionLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString( CompassPanel.class, "northDirectionLabel.mnemonic")).getKeyCode()); this.northDirectionLabel.setLabelFor(this.northDirectionSpinner); } } /** * Layouts panel components in panel with their labels. */ private void layoutComponents(UserPreferences preferences) { int labelAlignment = OperatingSystem.isMacOSX() ? GridBagConstraints.LINE_END : GridBagConstraints.LINE_START; // First row JPanel compassRosePanel = SwingTools.createTitledPanel(preferences.getLocalizedString( CompassPanel.class, "compassRosePanel.title")); Insets labelInsets = new Insets(0, 0, 5, 5); Insets componentInsets = new Insets(0, 0, 5, 10); Insets lastComponentInsets = new Insets(0, 0, 5, 0); int rowGap = OperatingSystem.isMacOSXLeopardOrSuperior() ? 0 : 5; compassRosePanel.add(this.xLabel, new GridBagConstraints( 0, 0, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, labelInsets, 0, 0)); compassRosePanel.add(this.xSpinner, new GridBagConstraints( 1, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 20), -10, 0)); compassRosePanel.add(this.visibleCheckBox, new GridBagConstraints( 2, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, lastComponentInsets, 0, 0)); compassRosePanel.add(this.yLabel, new GridBagConstraints( 0, 1, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); compassRosePanel.add(this.ySpinner, new GridBagConstraints( 1, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 20), -10, 0)); compassRosePanel.add(this.diameterLabel, new GridBagConstraints( 2, 1, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); compassRosePanel.add(this.diameterSpinner, new GridBagConstraints( 3, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); add(compassRosePanel, new GridBagConstraints( 0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, rowGap, 0), 0, 0)); // Second row JPanel geographicLocationPanel = SwingTools.createTitledPanel(preferences.getLocalizedString( CompassPanel.class, "geographicLocationPanel.title")); geographicLocationPanel.add(this.latitudeLabel, new GridBagConstraints( 0, 0, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, labelInsets, 0, 0)); geographicLocationPanel.add(this.latitudeSpinner, new GridBagConstraints( 1, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, componentInsets, 20, 0)); geographicLocationPanel.add(this.northDirectionLabel, new GridBagConstraints( 2, 0, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, labelInsets, 0, 0)); geographicLocationPanel.add(this.northDirectionSpinner, new GridBagConstraints( 3, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 5), 0, 0)); geographicLocationPanel.add(this.northDirectionComponent, new GridBagConstraints( 4, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0)); geographicLocationPanel.add(this.longitudeLabel, new GridBagConstraints( 0, 1, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); geographicLocationPanel.add(this.longitudeSpinner, new GridBagConstraints( 1, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 20, 0)); geographicLocationPanel.add(this.timeZoneLabel, new GridBagConstraints( 2, 1, 1, 1, 0, 0, labelAlignment, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); geographicLocationPanel.add(this.timeZoneComboBox, new GridBagConstraints( 3, 1, 2, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); this.timeZoneComboBox.setPreferredSize(new Dimension(this.latitudeSpinner.getPreferredSize().width + 60, this.timeZoneComboBox.getPreferredSize().height)); add(geographicLocationPanel, new GridBagConstraints( 0, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); } /** * Displays this panel in a modal dialog box. */ public void displayView(View parentView) { JFormattedTextField northDirectionTextField = ((JSpinner.DefaultEditor)this.northDirectionSpinner.getEditor()).getTextField(); if (SwingTools.showConfirmDialog((JComponent)parentView, this, this.dialogTitle, northDirectionTextField) == JOptionPane.OK_OPTION && this.controller != null) { this.controller.modifyCompass(); } } }