OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / ddms / libs / ddmuilib / src / com / android / ddmuilib / location / CoordinateControls.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.ddmuilib.location;
18
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;
27
28 /**
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()})
34  */
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;
42     
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;
46     
47     /**
48      * ModifyListener for the 3 {@link Text} controls of the sexagesimal mode.
49      */
50     private ModifyListener mSexagesimalListener = new ModifyListener() {
51         public void modifyText(ModifyEvent event) {
52             if (mManualTextChange > 0) {
53                 return;
54             }
55             try {
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();
63             }
64         }
65     };
66     
67     /**
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.
71      */
72     public void createDecimalText(Composite parent) {
73         mDecimalText = createTextControl(parent, "-199.999999", new ModifyListener() {
74             public void modifyText(ModifyEvent event) {
75                 if (mManualTextChange > 0) {
76                     return;
77                 }
78                 try {
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();
86                 }
87             }
88         });
89     }
90     
91     /**
92      * Creates the {@link Text} control for the "degree" display of the coordinate in sexagesimal
93      * mode.
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.
96      */
97     public void createSexagesimalDegreeText(Composite parent) {
98         mSexagesimalDegreeText = createTextControl(parent, "-199", mSexagesimalListener); //$NON-NLS-1$
99     }
100     
101     /**
102      * Creates the {@link Text} control for the "minute" display of the coordinate in sexagesimal
103      * mode.
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.
106      */
107     public void createSexagesimalMinuteText(Composite parent) {
108         mSexagesimalMinuteText = createTextControl(parent, "99", mSexagesimalListener); //$NON-NLS-1$
109     }
110
111     /**
112      * Creates the {@link Text} control for the "second" display of the coordinate in sexagesimal
113      * mode.
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.
116      */
117     public void createSexagesimalSecondText(Composite parent) {
118         mSexagesimalSecondText = createTextControl(parent, "99.999", mSexagesimalListener); //$NON-NLS-1$
119     }
120     
121     /**
122      * Sets the coordinate into the {@link Text} controls.
123      * @param value the coordinate value to set.
124      */
125     public void setValue(double value) {
126         mValue = value;
127         mValueValidity = true;
128         setValueIntoDecimalControl(value);
129         setValueIntoSexagesimalControl(value);
130     }
131     
132     /**
133      * Returns whether the value in the control(s) is valid.
134      */
135     public boolean isValueValid() {
136         return mValueValidity;
137     }
138
139     /**
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.
143      */
144     public double getValue() {
145         return mValue;
146     }
147     
148     /**
149      * Enables or disables all the {@link Text} controls.
150      * @param enabled the enabled state.
151      */
152     public void setEnabled(boolean enabled) {
153         mDecimalText.setEnabled(enabled);
154         mSexagesimalDegreeText.setEnabled(enabled);
155         mSexagesimalMinuteText.setEnabled(enabled);
156         mSexagesimalSecondText.setEnabled(enabled);
157     }
158     
159     private void resetDecimalControls() {
160         mManualTextChange++;
161         mDecimalText.setText(""); //$NON-NLS-1$
162         mManualTextChange--;
163     }
164
165     private void resetSexagesimalControls() {
166         mManualTextChange++;
167         mSexagesimalDegreeText.setText(""); //$NON-NLS-1$
168         mSexagesimalMinuteText.setText(""); //$NON-NLS-1$
169         mSexagesimalSecondText.setText(""); //$NON-NLS-1$
170         mManualTextChange--;
171     }
172     
173     /**
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
177      * size hint.
178      * @param listener the {@link ModifyListener} to be called when the {@link Text} control is
179      * modified.
180      */
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);
185         
186         // add the standard listener to it.
187         text.addModifyListener(listener);
188         
189         // compute its size/
190         mManualTextChange++;
191         text.setText(defaultString);
192         text.pack();
193         Point size = text.computeSize(SWT.DEFAULT, SWT.DEFAULT);
194         text.setText(""); //$NON-NLS-1$
195         mManualTextChange--;
196         
197         GridData gridData = new GridData();
198         gridData.widthHint = size.x;
199         text.setLayoutData(gridData);
200         
201         return text;
202     }
203     
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());
208         
209         boolean isPositive = (degrees >= 0.);
210         degrees = Math.abs(degrees);
211
212         double value = degrees + minutes / 60. + seconds / 3600.; 
213         return isPositive ? value : - value;
214     }
215
216     private void setValueIntoDecimalControl(double value) {
217         mManualTextChange++;
218         mDecimalText.setText(String.format("%.6f", value));
219         mManualTextChange--;
220     }
221     
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);
226         
227         // get the degree
228         double degrees = Math.floor(value);
229         
230         // get the minutes
231         double minutes = Math.floor((value - degrees) * 60.);
232         
233         // get the seconds.
234         double seconds = (value - degrees) * 3600. - minutes * 60.;
235         
236         mManualTextChange++;
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$
241         mManualTextChange--;
242     }
243 }