2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.ddmuilib.location;
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.ModifyEvent;
21 import org.eclipse.swt.events.ModifyListener;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.layout.GridData;
24 import org.eclipse.swt.layout.GridLayout;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Text;
29 * Encapsulation of controls handling a location coordinate in decimal and sexagesimal.
30 * <p/>This handle the conversion between both modes automatically by using a {@link ModifyListener}
31 * on all the {@link Text} widgets.
32 * <p/>To get/set the coordinate, use {@link #setValue(double)} and {@link #getValue()} (preceded by
33 * a call to {@link #isValueValid()})
35 public final class CoordinateControls {
36 private double mValue;
37 private boolean mValueValidity = false;
38 private Text mDecimalText;
39 private Text mSexagesimalDegreeText;
40 private Text mSexagesimalMinuteText;
41 private Text mSexagesimalSecondText;
43 /** Internal flag to prevent {@link ModifyEvent} to be sent when {@link Text#setText(String)}
44 * is called. This is an int instead of a boolean to act as a counter. */
45 private int mManualTextChange = 0;
48 * ModifyListener for the 3 {@link Text} controls of the sexagesimal mode.
50 private ModifyListener mSexagesimalListener = new ModifyListener() {
51 public void modifyText(ModifyEvent event) {
52 if (mManualTextChange > 0) {
56 mValue = getValueFromSexagesimalControls();
57 setValueIntoDecimalControl(mValue);
58 mValueValidity = true;
59 } catch (NumberFormatException e) {
60 // wrong format empty the decimal controls.
61 mValueValidity = false;
62 resetDecimalControls();
68 * Creates the {@link Text} control for the decimal display of the coordinate.
69 * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}.
70 * @param parent The {@link Composite} parent of the control.
72 public void createDecimalText(Composite parent) {
73 mDecimalText = createTextControl(parent, "-199.999999", new ModifyListener() {
74 public void modifyText(ModifyEvent event) {
75 if (mManualTextChange > 0) {
79 mValue = Double.parseDouble(mDecimalText.getText());
80 setValueIntoSexagesimalControl(mValue);
81 mValueValidity = true;
82 } catch (NumberFormatException e) {
83 // wrong format empty the sexagesimal controls.
84 mValueValidity = false;
85 resetSexagesimalControls();
92 * Creates the {@link Text} control for the "degree" display of the coordinate in sexagesimal
94 * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}.
95 * @param parent The {@link Composite} parent of the control.
97 public void createSexagesimalDegreeText(Composite parent) {
98 mSexagesimalDegreeText = createTextControl(parent, "-199", mSexagesimalListener); //$NON-NLS-1$
102 * Creates the {@link Text} control for the "minute" display of the coordinate in sexagesimal
104 * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}.
105 * @param parent The {@link Composite} parent of the control.
107 public void createSexagesimalMinuteText(Composite parent) {
108 mSexagesimalMinuteText = createTextControl(parent, "99", mSexagesimalListener); //$NON-NLS-1$
112 * Creates the {@link Text} control for the "second" display of the coordinate in sexagesimal
114 * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}.
115 * @param parent The {@link Composite} parent of the control.
117 public void createSexagesimalSecondText(Composite parent) {
118 mSexagesimalSecondText = createTextControl(parent, "99.999", mSexagesimalListener); //$NON-NLS-1$
122 * Sets the coordinate into the {@link Text} controls.
123 * @param value the coordinate value to set.
125 public void setValue(double value) {
127 mValueValidity = true;
128 setValueIntoDecimalControl(value);
129 setValueIntoSexagesimalControl(value);
133 * Returns whether the value in the control(s) is valid.
135 public boolean isValueValid() {
136 return mValueValidity;
140 * Returns the current value set in the control(s).
141 * <p/>This value can be erroneous, and a check with {@link #isValueValid()} should be performed
142 * before any call to this method.
144 public double getValue() {
149 * Enables or disables all the {@link Text} controls.
150 * @param enabled the enabled state.
152 public void setEnabled(boolean enabled) {
153 mDecimalText.setEnabled(enabled);
154 mSexagesimalDegreeText.setEnabled(enabled);
155 mSexagesimalMinuteText.setEnabled(enabled);
156 mSexagesimalSecondText.setEnabled(enabled);
159 private void resetDecimalControls() {
161 mDecimalText.setText(""); //$NON-NLS-1$
165 private void resetSexagesimalControls() {
167 mSexagesimalDegreeText.setText(""); //$NON-NLS-1$
168 mSexagesimalMinuteText.setText(""); //$NON-NLS-1$
169 mSexagesimalSecondText.setText(""); //$NON-NLS-1$
174 * Creates a {@link Text} with a given parent, default string and a {@link ModifyListener}
175 * @param parent the parent {@link Composite}.
176 * @param defaultString the default string to be used to compute the {@link Text} control
178 * @param listener the {@link ModifyListener} to be called when the {@link Text} control is
181 private Text createTextControl(Composite parent, String defaultString,
182 ModifyListener listener) {
183 // create the control
184 Text text = new Text(parent, SWT.BORDER | SWT.LEFT | SWT.SINGLE);
186 // add the standard listener to it.
187 text.addModifyListener(listener);
191 text.setText(defaultString);
193 Point size = text.computeSize(SWT.DEFAULT, SWT.DEFAULT);
194 text.setText(""); //$NON-NLS-1$
197 GridData gridData = new GridData();
198 gridData.widthHint = size.x;
199 text.setLayoutData(gridData);
204 private double getValueFromSexagesimalControls() throws NumberFormatException {
205 double degrees = Double.parseDouble(mSexagesimalDegreeText.getText());
206 double minutes = Double.parseDouble(mSexagesimalMinuteText.getText());
207 double seconds = Double.parseDouble(mSexagesimalSecondText.getText());
209 boolean isPositive = (degrees >= 0.);
210 degrees = Math.abs(degrees);
212 double value = degrees + minutes / 60. + seconds / 3600.;
213 return isPositive ? value : - value;
216 private void setValueIntoDecimalControl(double value) {
218 mDecimalText.setText(String.format("%.6f", value));
222 private void setValueIntoSexagesimalControl(double value) {
223 // get the sign and make the number positive no matter what.
224 boolean isPositive = (value >= 0.);
225 value = Math.abs(value);
228 double degrees = Math.floor(value);
231 double minutes = Math.floor((value - degrees) * 60.);
234 double seconds = (value - degrees) * 3600. - minutes * 60.;
237 mSexagesimalDegreeText.setText(
238 Integer.toString(isPositive ? (int)degrees : (int)- degrees));
239 mSexagesimalMinuteText.setText(Integer.toString((int)minutes));
240 mSexagesimalSecondText.setText(String.format("%.3f", seconds)); //$NON-NLS-1$