1
//////////////////////////////////////////////////////////////////////
3
// JCSP ("CSP for Java") Libraries //
4
// Copyright (C) 1996-2008 Peter Welch and Paul Austin. //
5
// 2001-2004 Quickstone Technologies Limited. //
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 //
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 //
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. //
24
// Author contact: P.H.Welch@kent.ac.uk //
27
//////////////////////////////////////////////////////////////////////
32
import java.util.Vector;
33
import org.jcsp.lang.*;
36
* {@link java.awt.FileDialog <TT>java.awt.FileDialog</TT>}
37
* with a channel interface.
38
* <H2>Process Diagram</H2>
39
* <p><img src="doc-files/ActiveFileDialog1.gif"></p>
40
* <H2>Description</H2>
41
* <TT>ActiveFileDialog</TT> is a process extension of <TT>java.awt.FileDialog</TT>
42
* with channels for run-time configuration and event notification. The event channels
43
* should be connected to one or more application-specific server processes (instead
44
* of registering a passive object as a <I>Listener</I> to this component).
46
* All channels are optional. The <TT>configure</TT> and <TT>event</TT> channels are
47
* settable from a constructor.
48
* The <TT>event</TT> channel delivers directory and file names (see next paragraph).
49
* Other event channels can be added to notify the occurrence of any other events
50
* the component generates (by calling the appropriate
51
* <TT>add</TT><I>XXX</I><TT>EventChannel</TT> method <I>before</I> the process is run).
52
* Messages can be sent down the <TT>configure</TT> channel at any time to configure
53
* the component. See the <A HREF="#Protocols">table below</A> for details.
55
* The <TT>ActiveFileDialog</TT> is made visible by sending a <TT>Boolean.TRUE</TT> down
56
* its <TT>configure</TT> channel. A <I>modal</I> dialogue takes place to select a file
57
* and the selected directory and file names are output down its <TT>event</TT> channel.
59
* All channels are managed by independent internal handler processes. It is, therefore,
60
* safe for a serial application process both to service an event channel and configure
61
* the component – no deadlock can occur.
63
* <I>IMPORTANT: it is essential that event channels from this process are
64
* always serviced – otherwise the Java Event Thread will be blocked and the GUI
65
* will stop responding. A simple way to guarantee this is to use channels
66
* configured with overwriting buffers.
69
* final One2OneChannel myFileDialogConfigure = Channel.one2one ();
70
* final One2OneChannel myFileDialogEvent = Channel.one2one (new OverWriteOldestBuffer (n));
72
* final ActiveFileDialog myFileDialog =
73
* new ActiveFileDialog (myFileDialogConfigure.in (), myFileDialogEvent.out ());
75
* <I>This will ensure that the Java Event Thread will never be blocked.
76
* Slow or inattentive readers may miss rapidly generated events, but
77
* the </I><TT>n</TT><I> most recent events will always be available.</I>
79
* <H2><A NAME="Protocols">Channel Protocols</A></H2>
83
* <TH COLSPAN="3">Input Channels</TH>
86
* <TH ROWSPAN="3">configure</TH>
89
* The start directory for the fileDialog
96
* <LI>If this is the <TT>Boolean.TRUE</TT> object,
97
* the fileDialog is made visible</LI>
98
* <LI>If this is the <TT>Boolean.FALSE</TT> object,
99
* the fileDialog is made invisible</LI>
100
* <LI>Other <TT>Boolean</TT> objects are ignored</LI>
105
* <TD>ActiveFileDialog.Configure</TD>
106
* <TD>Invoke the user-defined <TT>Configure.configure</TT> method on the activeFileDialog.</TD>
109
* <TH COLSPAN="3">Output Channels</TH>
113
* <TD>String, String</TD>
114
* <TD>The directory and file names generated by the fileDialog – these may be null</TD>
117
* <TH>windowEvent</TH>
118
* <TD>WindowEvent</TD>
119
* <TD>See the {@link #addWindowEventChannel
120
* <TT>addWindowEventChannel</TT>} method.</TD>
123
* <TH>containerEvent</TH>
124
* <TD>ContainerEvent</TD>
125
* <TD>See the {@link #addContainerEventChannel
126
* <TT>addContainerEventChannel</TT>} method.</TD>
129
* <TH>componentEvent</TH>
130
* <TD>ComponentEvent</TD>
131
* <TD>See the {@link #addComponentEventChannel
132
* <TT>addComponentEventChannel</TT>} method.</TD>
135
* <TH>focusEvent</TH>
136
* <TD>FocusEvent</TD>
137
* <TD>See the {@link #addFocusEventChannel
138
* <TT>addFocusEventChannel</TT>} method.</TD>
143
* <TD>See the {@link #addKeyEventChannel
144
* <TT>addKeyEventChannel</TT>} method.</TD>
147
* <TH>mouseEvent</TH>
148
* <TD>MouseEvent</TD>
149
* <TD>See the {@link #addMouseEventChannel
150
* <TT>addMouseEventChannel</TT>} method.</TD>
153
* <TH>mouseMotionEvent</TH>
154
* <TD>MouseEvent</TD>
155
* <TD>See the {@link #addMouseMotionEventChannel
156
* <TT>addMouseMotionEventChannel</TT>} method.</TD>
163
* import org.jcsp.lang.*;
164
* import org.jcsp.util.*;
165
* import org.jcsp.awt.*;
167
* public class ActiveFileDialogExample {
169
* public static void main (String argv[]) {
171
* final Frame root = new Frame ();
173
* final One2OneChannel configure = Channel.one2one ();
175
* final One2OneChannel event = Channel.one2one (new OverWriteOldestBuffer (10));
177
* final ActiveFileDialog fileDialog =
178
* new ActiveFileDialog (configure.in (), event.out (), root, "ActiveFileDialog Example");
184
* public void run () {
185
* String dir = "."; // start directory for the file dialogue
187
* while (file != null) {
188
* configure.out ().write (dir);
189
* configure.out ().write (Boolean.TRUE);
190
* dir = (String) event.in ().read ();
191
* file = (String) event.in ().read ();
193
* System.out.println ("Chosen file = `" + dir + file + "'");
205
* @see java.awt.FileDialog
206
* @see java.awt.event.WindowEvent
207
* @see java.awt.event.ContainerEvent
208
* @see java.awt.event.ComponentEvent
209
* @see java.awt.event.FocusEvent
210
* @see java.awt.event.KeyEvent
211
* @see java.awt.event.MouseEvent
212
* @see org.jcsp.util.OverWriteOldestBuffer
214
* @author P.D. Austin and P.H. Welch
217
public class ActiveFileDialog extends FileDialog implements CSProcess
220
* The Vector construct containing the handlers.
222
private Vector vec = new Vector();
225
* The channel from which configuration messages arrive.
227
private ChannelInput configure;
230
* The channel to which the selected directory and file names are sent.
232
private ChannelOutput event;
235
* Constructs a new <TT>ActiveDialog</TT> with a blank title for loading a file
236
* and with no configuration or event channels.
237
* Constructs a new <TT>ActiveFileDialog</TT>.
239
* @param parent the parent frame for the fileDialog.
241
public ActiveFileDialog(Frame parent)
243
this(null, null, parent, "", LOAD);
247
* Constructs a new <TT>ActiveFileDialog</TT> with a blank title
248
* and no configuration or event channels.
250
* @param parent the parent frame for the fileDialog.
251
* @param mode java.awt.FileDialog.LOAD or java.awt.FileDialog.SAVE.
253
public ActiveFileDialog(Frame parent, int mode)
255
this(null, null, parent, "", mode);
259
* Constructs a new <TT>ActiveFileDialog</TT> for loading a file
260
* and no configuration or event channels.
262
* @param parent the parent frame for the fileDialog.
263
* @param title the title of the fileDialog.
265
public ActiveFileDialog(Frame parent, String title)
267
this(null, null, parent, title, LOAD);
271
* Constructs a new <TT>ActiveFileDialog</TT>
272
* with no configuration or event channels.
274
* @param parent the parent frame for the fileDialog.
275
* @param title the title of the fileDialog.
276
* @param mode java.awt.FileDialog.LOAD or java.awt.FileDialog.SAVE.
278
public ActiveFileDialog(Frame parent, String title, int mode)
280
this(null, null, parent, title, mode);
284
* Constructs a new <TT>ActiveFileDialog</TT> with a blank title for loading a file.
286
* @param configure the channel for configuration events
287
* – can be null if no configuration is required.
288
* @param event the directory and file names will be output whenever selected
289
* – can be null if no notification is required.
290
* @param parent the parent frame for the fileDialog.
292
public ActiveFileDialog(ChannelInput configure, ChannelOutput event, Frame parent)
294
this(configure, event, parent, "", LOAD);
298
* Constructs a new <TT>ActiveFileDialog</TT> with a blank title.
300
* @param configure the channel for configuration events
301
* – can be null if no configuration is required.
302
* @param event the directory and file names will be output whenever selected
303
* – can be null if no notification is required.
304
* @param parent the parent frame for the fileDialog.
305
* @param mode java.awt.FileDialog.LOAD or java.awt.FileDialog.SAVE.
307
public ActiveFileDialog(ChannelInput configure, ChannelOutput event, Frame parent, int mode)
309
this(configure, event, parent, "", mode);
313
* Constructs a new <TT>ActiveFileDialog</TT> for loading a file.
315
* @param configure the channel for configuration events
316
* – can be null if no configuration is required.
317
* @param event the directory and file names will be output whenever selected
318
* – can be null if no notification is required.
319
* @param parent the parent frame for the fileDialog.
320
* @param title the title of the fileDialog.
322
public ActiveFileDialog(ChannelInput configure, ChannelOutput event, Frame parent, String title)
324
this(configure, event, parent, title, LOAD);
328
* Constructs a new <TT>ActiveFileDialog</TT>.
330
* @param configure the channel for configuration events
331
* – can be null if no configuration is required.
332
* @param event the directory and file names will be output whenever selected
333
* – can be null if no notification is required.
334
* @param parent the parent frame for the fileDialog.
335
* @param title the title of the fileDialog.
336
* @param mode java.awt.FileDialog.LOAD or java.awt.FileDialog.SAVE.
337
* <!-- @param modal if true, fileDialog blocks input to the parent window when shown. -->
339
public ActiveFileDialog(ChannelInput configure, ChannelOutput event, Frame parent, String title, int mode)
341
super(parent, title, mode);
342
this.configure = configure;
347
* Sets the configuration channel for this <TT>ActiveFileDialog</TT>.
348
* This method overwrites any configuration channel set in the constructor.
350
* @param configure the channel for configuration events
351
* – can be null if no configuration is required.
353
public void setConfigureChannel(ChannelInput configure)
355
this.configure = configure;
359
* Add a new channel to this component that will be used to notify that
360
* a <TT>WindowEvent</TT> has occurred. <I>This should be used
361
* instead of registering a WindowListener with the component.</I> It is
362
* possible to add more than one channel by calling this method multiple times
363
* If the channel passed is <TT>null</TT>, no action will be taken.
365
* <I>NOTE: This method must be called before this process is run.</I>
367
* @param windowEvent the channel down which to send ContainerEvents.
369
public void addWindowEventChannel(ChannelOutput windowEvent)
371
if (windowEvent != null)
373
WindowEventHandler handler = new WindowEventHandler(windowEvent);
374
addWindowListener(handler);
375
vec.addElement(handler);
380
* Add a new channel to this component that will be used to notify that
381
* a <TT>ContainerEvent</TT> has occurred. <I>This should be used
382
* instead of registering a ContainerListener with the component.</I> It is
383
* possible to add more than one Channel by calling this method multiple times
384
* If the channel passed is <TT>null</TT>, no action will be taken.
386
* <I>NOTE: This method must be called before this process is run.</I>
388
* @param containerEvent the channel down which to send ContainerEvents.
390
public void addContainerEventChannel(ChannelOutput containerEvent)
392
if (containerEvent != null)
394
ContainerEventHandler handler = new ContainerEventHandler(containerEvent);
395
addContainerListener(handler);
396
vec.addElement(handler);
401
* Add a new channel to this component that will be used to notify that
402
* a <TT>ComponentEvent</TT> has occurred. <I>This should be used
403
* instead of registering a ComponentListener with the component.</I> It is
404
* possible to add more than one Channel by calling this method multiple times
405
* If the channel passed is <TT>null</TT>, no action will be taken.
407
* <I>NOTE: This method must be called before this process is run.</I>
409
* @param componentEvent the channel down which to send ComponentEvents.
411
public void addComponentEventChannel(ChannelOutput componentEvent)
413
if (componentEvent != null)
415
ComponentEventHandler handler = new ComponentEventHandler(componentEvent);
416
addComponentListener(handler);
417
vec.addElement(handler);
422
* Add a new channel to this component that will be used to notify that
423
* a <TT>FocusEvent</TT> has occurred. <I>This should be used
424
* instead of registering a FocusListener with the component.</I> It is
425
* possible to add more than one Channel by calling this method multiple times
426
* If the channel passed is <TT>null</TT>, no action will be taken.
428
* <I>NOTE: This method must be called before this process is run.</I>
430
* @param focusEvent the channel down which to send FocusEvents.
432
public void addFocusEventChannel(ChannelOutput focusEvent)
434
if (focusEvent != null)
436
FocusEventHandler handler = new FocusEventHandler(focusEvent);
437
addFocusListener(handler);
438
vec.addElement(handler);
443
* Add a new channel to this component that will be used to notify that
444
* a <TT>KeyEvent</TT> has occurred. <I>This should be used
445
* instead of registering a KeyListener with the component.</I> It is
446
* possible to add more than one Channel by calling this method multiple times
447
* If the channel passed is <TT>null</TT>, no action will be taken.
449
* <I>NOTE: This method must be called before this process is run.</I>
451
* @param keyEvent the channel down which to send KeyEvents.
453
public void addKeyEventChannel(ChannelOutput keyEvent)
455
if (keyEvent != null)
457
KeyEventHandler handler = new KeyEventHandler(keyEvent);
458
addKeyListener(handler);
459
vec.addElement(handler);
464
* Add a new channel to this component that will be used to notify that
465
* a <TT>MouseEvent</TT> has occurred. <I>This should be used
466
* instead of registering a MouseListener with the component.</I> It is
467
* possible to add more than one Channel by calling this method multiple times
468
* If the channel passed is <TT>null</TT>, no action will be taken.
470
* <I>NOTE: This method must be called before this process is run.</I>
472
* @param mouseEvent the channel down which to send MouseEvents.
474
public void addMouseEventChannel(ChannelOutput mouseEvent)
476
if (mouseEvent != null)
478
MouseEventHandler handler = new MouseEventHandler(mouseEvent);
479
addMouseListener(handler);
480
vec.addElement(handler);
485
* Add a new channel to this component that will be used to notify that
486
* a <TT>MouseMotionEvent</TT> has occurred. <I>This should be used
487
* instead of registering a MouseMotionListener with the component.</I> It is
488
* possible to add more than one Channel by calling this method multiple times
489
* If the channel passed is <TT>null</TT>, no action will be taken.
491
* <I>NOTE: This method must be called before this process is run.</I>
493
* @param mouseMotionEvent the channel down which to send MouseMotionEvents.
495
public void addMouseMotionEventChannel(ChannelOutput mouseMotionEvent)
497
if (mouseMotionEvent != null)
499
MouseMotionEventHandler handler = new MouseMotionEventHandler(mouseMotionEvent);
500
addMouseMotionListener(handler);
501
vec.addElement(handler);
506
* This enables general configuration of this component. Any object implementing
507
* this interface and sent down the <TT>configure</TT> channel to this component will have its
508
* <TT>configure</TT> method invoked on this component.
510
* For an example, see {@link ActiveApplet.Configure}.
512
static public interface Configure
515
* @param fileDialog the FileDialog being configured.
517
public void configure(final FileDialog fileDialog);
521
* The main body of this process.
525
if (configure != null)
529
Object message = configure.read();
530
if (message instanceof Boolean)
532
if (message == Boolean.TRUE)
537
event.write(getDirectory());
538
event.write(getFile());
541
else if (message == Boolean.FALSE)
544
else if (message instanceof String)
545
setDirectory((String) message);
546
else if (message instanceof Configure)
547
((Configure) message).configure(this);