1
by Miguel Landaeta
Import upstream version 1.1-rc4 |
1 |
//////////////////////////////////////////////////////////////////////
|
2 |
// //
|
|
3 |
// JCSP ("CSP for Java") Libraries //
|
|
4 |
// Copyright (C) 1996-2008 Peter Welch and Paul Austin. //
|
|
5 |
// 2001-2004 Quickstone Technologies Limited. //
|
|
6 |
// //
|
|
7 |
// This library is free software; you can redistribute it and/or //
|
|
8 |
// modify it under the terms of the GNU Lesser General Public //
|
|
9 |
// License as published by the Free Software Foundation; either //
|
|
10 |
// version 2.1 of the License, or (at your option) any later //
|
|
11 |
// version. //
|
|
12 |
// //
|
|
13 |
// This library is distributed in the hope that it will be //
|
|
14 |
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
|
15 |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
|
16 |
// PURPOSE. See the GNU Lesser General Public License for more //
|
|
17 |
// details. //
|
|
18 |
// //
|
|
19 |
// You should have received a copy of the GNU Lesser General //
|
|
20 |
// Public License along with this library; if not, write to the //
|
|
21 |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, //
|
|
22 |
// Boston, MA 02111-1307, USA. //
|
|
23 |
// //
|
|
24 |
// Author contact: P.H.Welch@kent.ac.uk //
|
|
25 |
// //
|
|
26 |
// //
|
|
27 |
//////////////////////////////////////////////////////////////////////
|
|
28 |
||
29 |
package org.jcsp.awt; |
|
30 |
||
31 |
import java.awt.*; |
|
32 |
import java.util.Vector; |
|
33 |
import org.jcsp.lang.*; |
|
34 |
||
35 |
/**
|
|
36 |
* {@link java.awt.TextField <TT>java.awt.TextField</TT>}
|
|
37 |
* with a channel interface.
|
|
38 |
* <H2>Process Diagram</H2>
|
|
39 |
* <p><img src="doc-files/ActiveTextField1.gif"></p>
|
|
40 |
* <P>
|
|
41 |
* <H2>Description</H2>
|
|
42 |
* <TT>ActiveTextField</TT> is a process extension of <TT>java.awt.TextField</TT>
|
|
43 |
* with channels for run-time configuration and event notification. The event channels
|
|
44 |
* should be connected to one or more application-specific server processes (instead
|
|
45 |
* of registering a passive object as a <I>Listener</I> to this component).
|
|
46 |
* <P>
|
|
47 |
* All channels are optional. The <TT>configure</TT> and <TT>event</TT> channels are
|
|
48 |
* settable from a constructor.
|
|
49 |
* The <TT>event</TT> channel delivers updated text whenever
|
|
50 |
* the <TT>ActiveTextField</TT> is changed.
|
|
51 |
* Other event channels can be added to notify the occurrence of any other events
|
|
52 |
* the component generates (by calling the appropriate
|
|
53 |
* <TT>add</TT><I>XXX</I><TT>EventChannel</TT> method <I>before</I> the process is run).
|
|
54 |
* Messages can be sent down the <TT>configure</TT> channel at any time to configure
|
|
55 |
* the component. See the <A HREF="#Protocols">table below</A> for details.
|
|
56 |
* <P>
|
|
57 |
* All channels are managed by independent internal handler processes. It is, therefore,
|
|
58 |
* safe for a serial application process both to service an event channel and configure
|
|
59 |
* the component -- no deadlock can occur.
|
|
60 |
* <P>
|
|
61 |
* <I>IMPORTANT: it is essential that event channels from this process are
|
|
62 |
* always serviced -- otherwise the Java Event Thread will be blocked and the GUI
|
|
63 |
* will stop responding. A simple way to guarantee this is to use channels
|
|
64 |
* configured with overwriting buffers.
|
|
65 |
* For example:</I>
|
|
66 |
* <PRE>
|
|
67 |
* final One2OneChannel myTextFieldEvent = Channel.one2one (new OverWriteOldestBuffer (n));
|
|
68 |
*
|
|
69 |
* final ActiveTextField myTextField =
|
|
70 |
* new ActiveTextField (null, myTextFieldEvent.out (), "Edit Me");
|
|
71 |
* </PRE>
|
|
72 |
* <I>This will ensure that the Java Event Thread will never be blocked.
|
|
73 |
* Slow or inattentive readers may miss rapidly generated events, but
|
|
74 |
* the </I><TT>n</TT><I> most recent events will always be available.</I>
|
|
75 |
* </P>
|
|
76 |
* <H2><A NAME="Protocols">Channel Protocols</A></H2>
|
|
77 |
* <CENTER>
|
|
78 |
* <TABLE BORDER="2">
|
|
79 |
* <TR>
|
|
80 |
* <TH COLSPAN="3">Input Channels</TH>
|
|
81 |
* </TR>
|
|
82 |
* <TR>
|
|
83 |
* <TH ROWSPAN="4">configure</TH>
|
|
84 |
* <TD>String</TD>
|
|
85 |
* <TD>Set the text in this <TT>ActiveTextField</TT> to the value of the <TT>String</TT></TD>
|
|
86 |
* </TR>
|
|
87 |
* <TR>
|
|
88 |
* <TD>Boolean</TD>
|
|
89 |
* <TD>
|
|
90 |
* <OL>
|
|
91 |
* <LI>If this is the <TT>Boolean.TRUE</TT> object,
|
|
92 |
* the text field is made active</LI>
|
|
93 |
* <LI>If this is the <TT>Boolean.FALSE</TT> object,
|
|
94 |
* the text field is made inactive</LI>
|
|
95 |
* <LI>Other <TT>Boolean</TT> objects are ignored</LI>
|
|
96 |
* </OL>
|
|
97 |
* </TD>
|
|
98 |
* </TR>
|
|
99 |
* <TR>
|
|
100 |
* <TD>ActiveTextField.Configure</TD>
|
|
101 |
* <TD>Invoke the user-defined <TT>Configure.configure</TT> method on the textField.</TD>
|
|
102 |
* </TR>
|
|
103 |
* <TR>
|
|
104 |
* <TD><I>otherwise</I></TD>
|
|
105 |
* <TD>Append the <TT>toString</TT> form of the object to the text in this <TT>ActiveTextField</TT>.</TD>
|
|
106 |
* </TR>
|
|
107 |
* <TR>
|
|
108 |
* <TH COLSPAN="3">Output Channels</TH>
|
|
109 |
* </TR>
|
|
110 |
* <TR>
|
|
111 |
* <TH>event</TH>
|
|
112 |
* <TD>String</TD>
|
|
113 |
* <TD>The text in the <TT>ActiveTextField</TT> (whenever the text field is altered)</TD>
|
|
114 |
* </TR>
|
|
115 |
* <TR>
|
|
116 |
* <TH>componentEvent</TH>
|
|
117 |
* <TD>ComponentEvent</TD>
|
|
118 |
* <TD>See the {@link #addComponentEventChannel
|
|
119 |
* <TT>addComponentEventChannel</TT>} method.</TD>
|
|
120 |
* </TR>
|
|
121 |
* <TR>
|
|
122 |
* <TH>focusEvent</TH>
|
|
123 |
* <TD>FocusEvent</TD>
|
|
124 |
* <TD>See the {@link #addFocusEventChannel
|
|
125 |
* <TT>addFocusEventChannel</TT>} method.</TD>
|
|
126 |
* </TR>
|
|
127 |
* <TR>
|
|
128 |
* <TH>keyEvent</TH>
|
|
129 |
* <TD>KeyEvent</TD>
|
|
130 |
* <TD>See the {@link #addKeyEventChannel
|
|
131 |
* <TT>addKeyEventChannel</TT>} method.</TD>
|
|
132 |
* </TR>
|
|
133 |
* <TR>
|
|
134 |
* <TH>mouseEvent</TH>
|
|
135 |
* <TD>MouseEvent</TD>
|
|
136 |
* <TD>See the {@link #addMouseEventChannel
|
|
137 |
* <TT>addMouseEventChannel</TT>} method.</TD>
|
|
138 |
* </TR>
|
|
139 |
* <TR>
|
|
140 |
* <TH>mouseMotionEvent</TH>
|
|
141 |
* <TD>MouseEvent</TD>
|
|
142 |
* <TD>See the {@link #addMouseMotionEventChannel
|
|
143 |
* <TT>addMouseMotionEventChannel</TT>} method.</TD>
|
|
144 |
* </TR>
|
|
145 |
* </TABLE>
|
|
146 |
* </CENTER>
|
|
147 |
* <H2>Example</H2>
|
|
148 |
* <PRE>
|
|
149 |
* import org.jcsp.lang.*;
|
|
150 |
* import org.jcsp.util.*;
|
|
151 |
* import org.jcsp.awt.*;
|
|
152 |
* import java.awt.*;
|
|
153 |
*
|
|
154 |
* public class ActiveTextFieldExample {
|
|
155 |
*
|
|
156 |
* public static void main (String argv[]) {
|
|
157 |
*
|
|
158 |
* final ActiveClosingFrame frame =
|
|
159 |
* new ActiveClosingFrame ("ActiveTextFieldExample Example");
|
|
160 |
*
|
|
161 |
* final Any2OneChannel event = Channel.any2one (new OverWriteOldestBuffer (10));
|
|
162 |
*
|
|
163 |
* final String[] string =
|
|
164 |
* {"Entia Non Sunt Multiplicanda Praeter Necessitatem",
|
|
165 |
* "Less is More ... More or Less",
|
|
166 |
* "Everything we do, we do it to you",
|
|
167 |
* "Race Hazards - What Rice Hozzers?",
|
|
168 |
* "Cogito Ergo Occam"};
|
|
169 |
*
|
|
170 |
* final String goodbye = "Goodbye World";
|
|
171 |
*
|
|
172 |
* final ActiveTextField[] activeText =
|
|
173 |
* new ActiveTextField[string.length];
|
|
174 |
*
|
|
175 |
* for (int i = 0; i < string.length; i++) {
|
|
176 |
* activeText[i] = new ActiveTextField (null, event.out (), string[i]);
|
|
177 |
* }
|
|
178 |
*
|
|
179 |
* Panel panel = new Panel (new GridLayout (string.length, 1));
|
|
180 |
* for (int i = 0; i < string.length; i++) {
|
|
181 |
* panel.add (activeText[i]);
|
|
182 |
* }
|
|
183 |
*
|
|
184 |
* final Frame realFrame = frame.getActiveFrame ();
|
|
185 |
* realFrame.setBackground (Color.green);
|
|
186 |
* realFrame.add (panel);
|
|
187 |
* realFrame.pack ();
|
|
188 |
* realFrame.setVisible (true);
|
|
189 |
*
|
|
190 |
* new Parallel (
|
|
191 |
* new CSProcess[] {
|
|
192 |
* frame,
|
|
193 |
* new Parallel (activeText),
|
|
194 |
* new CSProcess () {
|
|
195 |
* public void run () {
|
|
196 |
* boolean running = true;
|
|
197 |
* while (running) {
|
|
198 |
* String s = (String) event.in ().read ();
|
|
199 |
* System.out.println (s);
|
|
200 |
* running = (! s.equals (goodbye));
|
|
201 |
* }
|
|
202 |
* realFrame.setVisible (false);
|
|
203 |
* System.exit (0);
|
|
204 |
* }
|
|
205 |
* }
|
|
206 |
* }
|
|
207 |
* ).run ();
|
|
208 |
* }
|
|
209 |
*
|
|
210 |
* }
|
|
211 |
* </PRE>
|
|
212 |
*
|
|
213 |
* @see org.jcsp.awt.ActiveTextEnterField
|
|
214 |
* @see java.awt.TextField
|
|
215 |
* @see java.awt.event.ComponentEvent
|
|
216 |
* @see java.awt.event.FocusEvent
|
|
217 |
* @see java.awt.event.KeyEvent
|
|
218 |
* @see java.awt.event.MouseEvent
|
|
219 |
* @see org.jcsp.util.OverWriteOldestBuffer
|
|
220 |
*
|
|
221 |
* @author P.D. Austin and P.H. Welch
|
|
222 |
*/
|
|
223 |
||
224 |
public class ActiveTextField extends TextField implements CSProcess |
|
225 |
{
|
|
226 |
/**
|
|
227 |
* The Vector construct containing the handlers.
|
|
228 |
*/
|
|
229 |
private Vector vec = new Vector(); |
|
230 |
||
231 |
/**
|
|
232 |
* The channel from which configuration messages arrive.
|
|
233 |
*/
|
|
234 |
private ChannelInput configure; |
|
235 |
||
236 |
/**
|
|
237 |
* Constructs a new <TT>ActiveTextField</TT> with no initial text,
|
|
238 |
* configuration or event channels.
|
|
239 |
*
|
|
240 |
*/
|
|
241 |
public ActiveTextField() |
|
242 |
{
|
|
243 |
this(null, null, "", 0); |
|
244 |
}
|
|
245 |
||
246 |
/**
|
|
247 |
* Constructs a new <TT>ActiveTextField</TT> with initial text and default width,
|
|
248 |
* but no configuration or event channels.
|
|
249 |
*
|
|
250 |
* @param s the initial text displayed in the field.
|
|
251 |
*/
|
|
252 |
public ActiveTextField(String s) |
|
253 |
{
|
|
254 |
this(null, null, s, s.length()); |
|
255 |
}
|
|
256 |
||
257 |
/**
|
|
258 |
* Constructs a new <TT>ActiveTextField</TT> with initial text and width,
|
|
259 |
* but no configuration or event channels.
|
|
260 |
*
|
|
261 |
* @param s the initial text displayed in the field.
|
|
262 |
* @param columns the width of the field.
|
|
263 |
*/
|
|
264 |
public ActiveTextField(String s, int columns) |
|
265 |
{
|
|
266 |
this(null, null, s, columns); |
|
267 |
}
|
|
268 |
||
269 |
/**
|
|
270 |
* Constructs a new <TT>ActiveTextField</TT> with configuration and event channels,
|
|
271 |
* but no initial text.
|
|
272 |
*
|
|
273 |
* @param configure the channel for configuration events
|
|
274 |
* -- can be null if no configuration is required.
|
|
275 |
* @param event the current text will be output when the text field is changed
|
|
276 |
* -- can be null if no notification is required.
|
|
277 |
*/
|
|
278 |
public ActiveTextField(ChannelInput configure, ChannelOutput event) |
|
279 |
{
|
|
280 |
this(configure, event, "", 0); |
|
281 |
}
|
|
282 |
||
283 |
/**
|
|
284 |
* Constructs a new <TT>ActiveTextField</TT> with configuration and event channels,
|
|
285 |
* initial text and default width.
|
|
286 |
*
|
|
287 |
* @param configure the channel for configuration events
|
|
288 |
* -- can be null if no configuration is required.
|
|
289 |
* @param event the current text will be output when the text field is changed
|
|
290 |
* -- can be null if no notification is required.
|
|
291 |
* @param s the initial text displayed in the field.
|
|
292 |
*/
|
|
293 |
public ActiveTextField(ChannelInput configure, ChannelOutput event, String s) |
|
294 |
{
|
|
295 |
this(configure, event, s, s.length()); |
|
296 |
}
|
|
297 |
||
298 |
/**
|
|
299 |
* Constructs a new <TT>ActiveTextField</TT> with configuration and event channels,
|
|
300 |
* initial text and width.
|
|
301 |
*
|
|
302 |
* @param configure the channel for configuration events
|
|
303 |
* -- can be null if no configuration is required.
|
|
304 |
* @param event the current text will be output when the text field is changed
|
|
305 |
* -- can be null if no notification is required.
|
|
306 |
* @param s the initial text displayed in the field.
|
|
307 |
* @param columns the width of the field.
|
|
308 |
*/
|
|
309 |
public ActiveTextField(ChannelInput configure, ChannelOutput event, String s, int columns) |
|
310 |
{
|
|
311 |
super(s, columns); |
|
312 |
||
313 |
// Only create an event handler if the event Channel is not null.
|
|
314 |
if (event != null) |
|
315 |
{
|
|
316 |
TextEventHandler handler = new TextEventHandler(event); |
|
317 |
addTextListener(handler); |
|
318 |
vec.addElement(handler); |
|
319 |
}
|
|
320 |
this.configure = configure; |
|
321 |
}
|
|
322 |
||
323 |
/**
|
|
324 |
* Sets the configuration channel for this <TT>ActiveTextField</TT>.
|
|
325 |
* This method overwrites any configuration channel set in the constructor.
|
|
326 |
*
|
|
327 |
* @param configure the channel for configuration events.
|
|
328 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
329 |
*/
|
|
330 |
public void setConfigureChannel(ChannelInput configure) |
|
331 |
{
|
|
332 |
this.configure = configure; |
|
333 |
}
|
|
334 |
||
335 |
/**
|
|
336 |
* Add a new channel to this component that will be used to notify that
|
|
337 |
* a <TT>ComponentEvent</TT> has occurred. <I>This should be used
|
|
338 |
* instead of registering a ComponentListener with the component.</I> It is
|
|
339 |
* possible to add more than one channel by calling this method multiple times
|
|
340 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
341 |
* <P>
|
|
342 |
* <I>NOTE: This method must be called before this process is run.</I>
|
|
343 |
*
|
|
344 |
* @param componentEvent the channel down which to send ComponentEvents.
|
|
345 |
*/
|
|
346 |
public void addComponentEventChannel(ChannelOutput componentEvent) |
|
347 |
{
|
|
348 |
if (componentEvent != null) |
|
349 |
{
|
|
350 |
ComponentEventHandler handler = new ComponentEventHandler(componentEvent); |
|
351 |
addComponentListener(handler); |
|
352 |
vec.addElement(handler); |
|
353 |
}
|
|
354 |
}
|
|
355 |
||
356 |
/**
|
|
357 |
* Add a new channel to this component that will be used to notify that
|
|
358 |
* a <TT>FocusEvent</TT> has occurred. <I>This should be used
|
|
359 |
* instead of registering a FocusListener with the component.</I> It is
|
|
360 |
* possible to add more than one channel by calling this method multiple times
|
|
361 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
362 |
* <P>
|
|
363 |
* <I>NOTE: This method must be called before this process is run.</I>
|
|
364 |
*
|
|
365 |
* @param focusEvent the channel down which to send FocusEvents.
|
|
366 |
*/
|
|
367 |
public void addFocusEventChannel(ChannelOutput focusEvent) |
|
368 |
{
|
|
369 |
if (focusEvent != null) |
|
370 |
{
|
|
371 |
FocusEventHandler handler = new FocusEventHandler(focusEvent); |
|
372 |
addFocusListener(handler); |
|
373 |
vec.addElement(handler); |
|
374 |
}
|
|
375 |
}
|
|
376 |
||
377 |
/**
|
|
378 |
* Add a new channel to this component that will be used to notify that
|
|
379 |
* a <TT>KeyEvent</TT> has occurred. <I>This should be used
|
|
380 |
* instead of registering a KeyListener with the component.</I> It is
|
|
381 |
* possible to add more than one channel by calling this method multiple times
|
|
382 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
383 |
* <P>
|
|
384 |
* <I>NOTE: This method must be called before this process is run.</I>
|
|
385 |
*
|
|
386 |
* @param keyEvent the channel down which to send KeyEvents.
|
|
387 |
*/
|
|
388 |
public void addKeyEventChannel(ChannelOutput keyEvent) |
|
389 |
{
|
|
390 |
if (keyEvent != null) |
|
391 |
{
|
|
392 |
KeyEventHandler handler = new KeyEventHandler(keyEvent); |
|
393 |
addKeyListener(handler); |
|
394 |
vec.addElement(handler); |
|
395 |
}
|
|
396 |
}
|
|
397 |
||
398 |
/**
|
|
399 |
* Add a new channel to this component that will be used to notify that
|
|
400 |
* a <TT>MouseEvent</TT> has occurred. <I>This should be used
|
|
401 |
* instead of registering a MouseListener with the component.</I> It is
|
|
402 |
* possible to add more than one channel by calling this method multiple times
|
|
403 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
404 |
* <P>
|
|
405 |
* <I>NOTE: This method must be called before this process is run.</I>
|
|
406 |
*
|
|
407 |
* @param mouseEvent the channel down which to send MouseEvents.
|
|
408 |
*/
|
|
409 |
public void addMouseEventChannel(ChannelOutput mouseEvent) |
|
410 |
{
|
|
411 |
if (mouseEvent != null) |
|
412 |
{
|
|
413 |
MouseEventHandler handler = new MouseEventHandler(mouseEvent); |
|
414 |
addMouseListener(handler); |
|
415 |
vec.addElement(handler); |
|
416 |
}
|
|
417 |
}
|
|
418 |
||
419 |
/**
|
|
420 |
* Add a new channel to this component that will be used to notify that
|
|
421 |
* a <TT>MouseMotionEvent</TT> has occurred. <I>This should be used
|
|
422 |
* instead of registering a MouseMotionListener with the component.</I> It is
|
|
423 |
* possible to add more than one channel by calling this method multiple times
|
|
424 |
* If the channel passed is <TT>null</TT>, no action will be taken.
|
|
425 |
* <P>
|
|
426 |
* <I>NOTE: This method must be called before this process is run.</I>
|
|
427 |
*
|
|
428 |
* @param mouseMotionEvent the channel down which to send MouseMotionEvents.
|
|
429 |
*/
|
|
430 |
public void addMouseMotionEventChannel(ChannelOutput mouseMotionEvent) |
|
431 |
{
|
|
432 |
if (mouseMotionEvent != null) |
|
433 |
{
|
|
434 |
MouseMotionEventHandler handler = new MouseMotionEventHandler(mouseMotionEvent); |
|
435 |
addMouseMotionListener(handler); |
|
436 |
vec.addElement(handler); |
|
437 |
}
|
|
438 |
}
|
|
439 |
/**
|
|
440 |
* This enables general configuration of this component. Any object implementing
|
|
441 |
* this interface and sent down the <TT>configure</TT> channel to this component will have its
|
|
442 |
* <TT>configure</TT> method invoked on this component.
|
|
443 |
* <P>
|
|
444 |
* For an example, see {@link ActiveApplet.Configure}.
|
|
445 |
*/
|
|
446 |
static public interface Configure |
|
447 |
{
|
|
448 |
/**
|
|
449 |
* @param textField the TextField being configured.
|
|
450 |
*/
|
|
451 |
public void configure(final TextField textField); |
|
452 |
}
|
|
453 |
||
454 |
/**
|
|
455 |
* The main body of this process.
|
|
456 |
*/
|
|
457 |
public void run() |
|
458 |
{
|
|
459 |
if (configure != null) |
|
460 |
{
|
|
461 |
while (true) |
|
462 |
{
|
|
463 |
Object message = configure.read(); |
|
464 |
if (message instanceof String) |
|
465 |
setText((String) message); |
|
466 |
else if (message instanceof Boolean) |
|
467 |
{
|
|
468 |
if (message == Boolean.TRUE) |
|
469 |
setEnabled(true); |
|
470 |
else if (message == Boolean.FALSE) |
|
471 |
setEnabled(false); |
|
472 |
}
|
|
473 |
else if (message instanceof Configure) |
|
474 |
((Configure) message).configure(this); |
|
475 |
else
|
|
476 |
setText(message.toString()); |
|
477 |
}
|
|
478 |
}
|
|
479 |
}
|
|
480 |
}
|