Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / February 2005

Tip: Looking for answers? Try searching our database.

Problems combining a JToggleButton and a JPopupMenu

Thread view: 
Stephen Riehm - 13 Feb 2005 21:51 GMT
Hi,

I've got a JToggleButton (always visible) and I'm using its
actionlistener to popup a JPopupMenu. The JButton then listens for the
JPopupMenu's popupMenuWillBecomeInvisible() event so that it can reset
itself when the menu disappears. This works fine, except if the user
clicks on the JToggleButton to close the popup. In this case there's a
race condition: first the popup loses focus and closes itself, which
triggers the willBecomeInvisble event, which resets the toggle button...
AND THEN the togglebutton's action fires, and it always thinks the
button is being activated. The result for the user is that the menu
pop's away and comes straight back again.

Is there a common pattern for connecting a popup to a toggle button so
that the button can be used for opening and closing the popup?
(without sacrificing the normal closing of the popup when the focus is
taken away)

Thanks,

Rom
Andrey Kuznetsov - 13 Feb 2005 23:21 GMT
> I've got a JToggleButton (always visible) and I'm using its actionlistener
> to popup a JPopupMenu. The JButton then listens for the JPopupMenu's
[quoted text clipped - 10 lines]
> (without sacrificing the normal closing of the popup when the focus is
> taken away)

common pattern is to reset state of button a little bit later.
i.e.
SwingUtilities.invokeLater(new Runnable() {
   public void run() {
       //reset state here
   }
});

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

Stephen Riehm - 14 Feb 2005 22:05 GMT
>>Is there a common pattern for connecting a popup to a toggle button so
>>that the button can be used for opening and closing the popup?
[quoted text clipped - 8 lines]
>     }
> });

hmm... thanks for the tip!
I tried it, but then I got a non-deterministic reaction. (before it was
deterministically wrong). Only about one click in five actually has the
desired result, the rest behave as it did in my original post. What I
really want is to get the button's action before the popup closes, or,
to prevent the popup from closing / triggering the button reset if and
only if the mouse is over the button when clicked.

Does anyone else have an idea for connecting a popup and a toggle button
tegether properly?

Thanks in advance,

Steve
Andrey Kuznetsov - 15 Feb 2005 00:35 GMT
> I tried it, but then I got a non-deterministic reaction. (before it was
> deterministically wrong). Only about one click in five actually has the
> desired result, the rest behave as it did in my original post.

please post SSCCE (http://www.physci.org/codes/sscce.jsp)

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

stephen.riehm@gmx.net - 15 Feb 2005 09:52 GMT
> > I tried it, but then I got a non-deterministic reaction. (before it was
> > deterministically wrong). Only about one click in five actually has the
> > desired result, the rest behave as it did in my original post.
>
> please post SSCCE (http://www.physci.org/codes/sscce.jsp)

Gladly. (see below)
The following displays the problem on linux and mac. I don't have a
windows box :-)
What I said about using invokeLater doesn't apply to this example
though. Maybe it's too small, but as you can see, using invokeLater or
not makes effectively no difference.

Thanks,

Steve
----- PopupButton.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/*
* Standalone test of connecting a JToggleButton with a JPopupMenu.
* The goal is to have the toggle appear selected only while the popup
* is visible. When the popup is open, the user should be able to close
* the popup by:
*      1. clicking in the popup (a selection)
*      2. clicking anywhere outside the popup (cancel)
*      3. clicking on the toggle button again (raising the button and
*         canceling the popup)
* Everything works except the case 3.
* In this case the following happen:
*      Initial state: button is selected, popup is open
*      The user clicks the toggle button
*      The popup loses focus
*      The popup fires a cancel event
*      The popup fires an isClosing event
*      The popup becomes invisible
*      The button's action event is fired
*         => the button is not selected and the popup is closed
*      Problem: The action event NEVER sees the popup as being open or
*      the button as being selected
*/
public class PopupButton
extends JFrame
implements ActionListener, PopupMenuListener {

   // start the test. Use any argument on the command line to use
   // invokeLater() to update the toggle button instead of directly
   // updating its status.
   public static void main( String[] args ) {
       final boolean useInvokeLater = ( args.length > 0 );
       javax.swing.SwingUtilities.invokeLater(
           new Runnable() {
               public void run() {
                   new PopupButton( useInvokeLater );
               }
           }
       );
   }

   public PopupButton( boolean useInvokeLater ) {
       this.useInvokeLater = useInvokeLater;

       setDefaultCloseOperation( EXIT_ON_CLOSE );
       getContentPane().setLayout( new FlowLayout() );

       button = new JToggleButton("click me");
       // events caught by actionPerformed() below
       button.addActionListener( this );

       popup = new JPopupMenu();
       // events caught by popupMenuWillBecomeInvisible() below
       popup.addPopupMenuListener( this );

       response = new JButton(
           new AbstractAction("thank you") {
               public void actionPerformed( ActionEvent e ) {
                   popup.setVisible( false );
               }
           }
       );

       getContentPane().add( new JLabel(
                   useInvokeLater
                       ? "using invokeLater"
                       : "using direct updates" ) );
       getContentPane().add( button );
       getContentPane().add( new JLabel(
                   "click here to close the popup " ) );
       popup.add( response );

       pack();
       setVisible( true );
   }

   // respond to the button's click actions by opening or closing the
   // popup
   public void actionPerformed( ActionEvent e ) {
       if( button.isSelected() ) {
           Dimension d = button.getPreferredSize();
           popup.show( button, 0, d.height );
       } else {
           popup.setVisible( false );
       }
   }

   // required by the PopupMenuListener interface
   // disable the toggle button when the popup closes
   public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
       if( useInvokeLater ) {
           javax.swing.SwingUtilities.invokeLater(
               new Runnable() {
                   public void run() {
                       button.setSelected( false );
                   }
               }
           );
       } else {
           button.setSelected( false );
       }
   }

   // required by the PopupMenuListener interface
   public void popupMenuCanceled( PopupMenuEvent e ) {}

   // required by the PopupMenuListener interface
   public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {}

   //------------------------------------------------------------
   // ATTRIBUTES
   //------------------------------------------------------------
   private JToggleButton button;   // button to open popup
   private JPopupMenu    popup;    // popup panel
   private JButton       response; // button in popup panel
   private boolean       useInvokeLater;
}
Andrey Kuznetsov - 15 Feb 2005 15:06 GMT
I changed a bit class design, because extending JFrame is not the best...
Most important thing is to check time since last menu closing, if it is too
short,
then actionEvent should be ignored.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class PopupButton extends JToggleButton implements ActionListener {

   // start the test. Use any argument on the command line to use
   // invokeLater() to update the toggle button instead of directly
   // updating its status.
   public static void main(String[] args) {
       JFrame frame = new JFrame("PopupButton test");

       final PopupButton popup = new PopupButton("PopupButton test");
       JButton response = new JButton(
               new AbstractAction("thank you") {
                   public void actionPerformed(ActionEvent e) {
                       popup.getPopup().setVisible(false);
                       popup.setSelected(false);
                   }
               }
       );
       popup.getPopup().add(response);
       frame.getContentPane().add(popup, BorderLayout.NORTH);
       frame.getContentPane().add(new JLabel("PopupTest"),
BorderLayout.CENTER);
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.pack();
       frame.show();
   }

   public PopupButton(String text) {
       super(text);
       // events caught by actionPerformed() below
       addActionListener(this);
       popup = new JPopupMenu();
       popup.addPopupMenuListener(new PopupMenuListener() {
           public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
           }

           public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
               setSelected(false);
               lastEvent = System.currentTimeMillis();
           }

           public void popupMenuCanceled(PopupMenuEvent e) {
           }
       });
   }

   public JPopupMenu getPopup() {
       return popup;
   }

   // respond to the button's click actions by opening or closing the popup
   public void actionPerformed(ActionEvent e) {
       //check time when popup menu was made invisible
       if ((System.currentTimeMillis() - lastEvent) < 250) {
           setSelected(false);
           return;
       }

       if (isSelected()) {
           Dimension d = getPreferredSize();
           popup.show(PopupButton.this, 0, d.height);
       }
       else {
           popup.setVisible(false);
       }
   }

   long lastEvent;
   private JPopupMenu popup;    // popup panel
}

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

Andrey Kuznetsov - 15 Feb 2005 15:08 GMT
> import javax.swing.*;
> import java.awt.*;
> import java.awt.event.ActionEvent;
> import java.awt.event.ActionListener;
> import java.beans.PropertyChangeEvent;
> import java.beans.PropertyChangeListener;

hmm, here is correct imports:

import javax.swing.*;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.PopupMenuEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

stephen.riehm@gmx.net - 17 Feb 2005 10:34 GMT
> I changed a bit class design, because extending JFrame is not the best...

umm... you wanted a short, self contained, correct example - the
original code has nothing to do with jframes, I just wrapped up the
important bits in a frame to meet the requirements :-)

> Most important thing is to check time since last menu closing,
> if it is too short, then actionEvent should be ignored.

Thanks. I thought of doing that, but I really don't like using timing
for things like this. The reason being that this is a sequence of
events. If the user is on a slow, overloaded machine, any time limit
you put in can be too short. Making the time limits longer only makes
the interface slow. In this case it would result in the button
appearing depressed even though the popup menu is closed, in other
situations this sort of thing can lead to really nasty side effects.
But since I haven't found a better solution yet, I guess I'll have to
do something like this.

Thanks for your help!

Steve
Thomas Weidenfeller - 17 Feb 2005 11:16 GMT
> I changed a bit class design, because extending JFrame is not the best...

It often is. If you want to produce a re-usable component (also known as
a JavaBean), then for practical reasons you better subclass. Otherwise
you have to duplicate too many methods to provide the existing (and thus
expected) behavior plus your own new behavior. Also, by subclassing you
can use your component directly everywhere where the superclass can be used.

/Thomas

Signature

The comp.lang.java.gui FAQ:
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq

Andrey Kuznetsov - 19 Feb 2005 22:19 GMT
>> I changed a bit class design, because extending JFrame is not the best...
>
[quoted text clipped - 4 lines]
> can use your component directly everywhere where the superclass can be
> used.

hmm, my english is not the best...
I mean of course:
extending of JFrame is not the best way if you want to customize
JToggleButton...

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

John McGrath - 15 Feb 2005 16:14 GMT
>     // required by the PopupMenuListener interface
>     // disable the toggle button when the popup closes
[quoted text clipped - 12 lines]
>     }
> }

That problem looks *very* familiar.  As I recall, the real problem was in
unselecting the JToggleButton when the menu is closed as the result of a
focus loss or of selecting a menu item.  I could not find a way to detect
this condition in such a way that it was not also triggered when you
pressed the toggle button to close the menu.  If the code deselected the
JToggleButton when the menu closed, that occurred *before* the button
handling, so that ended up selecting the JToggleButton again.

What I did to deal with this was to just use a plain old JButton, so I did
not have to deal with the JToggleButton selection.

Signature

Regards,

John McGrath

John McGrath - 16 Feb 2005 05:47 GMT
I just found a way to deal with this in my PopupButton class.  Instead of
doing a setSelected( false ) when the menu is closing, I used the
following code:

  SwingUtilities.invokeLater( new Runnable() {
     public void run() {
        doClick();
     }
  } );

If the button is already armed and pressed, this has no effect, so it does
not interfere with the user pressing the button.  And if called when the
menu is closed for some other reason, the doClick() deselects the button.

Signature

Regards,

John McGrath

stephen.riehm@gmx.net - 17 Feb 2005 11:02 GMT
hmmm.... we're getting closer! This works about 70% of the time - and
when it doesn't work the popup re-opens.

What I don't understand, is why there isn't a deterministic way of
doing this? Using invokeLater is also  really a hack to click the
button after a short non-deterministic pause.

Thanks just the same. I'll put this and the timestamp logic from Andrey
together and it should be OK.

Cheers,

Steve
John McGrath - 19 Feb 2005 18:03 GMT
> hmmm.... we're getting closer! This works about 70% of the time - and
> when it doesn't work the popup re-opens.

Interesting.  I made that change in a PopupButton class that I wrote a
while back, and it seems pretty solid, although I have not yet tested it
on systems other than Windows.

Can you post the version of your code with the doClick() that works 70% of
the time.  I will take a look at it to see if I can tell why it does not
work consistently and my code does.  I will also work up a similar example
using my code.

> What I don't understand, is why there isn't a deterministic way of
> doing this? Using invokeLater is also  really a hack to click the
> button after a short non-deterministic pause.

I am not sure why, but there have been issues with popups, particularly on
other platforms going back to the beginning of Swing.  I suspect that has
had something to do with it.

Signature

Regards,

John McGrath

stephen.riehm@gmx.net - 22 Feb 2005 16:59 GMT
Hi John,

OK, here's the whole thing again, with all 4 different cases built in.
Running it with no argument or 0 gives you my original code, 1 uses
Andrey's time-check, 2 uses the invokeLater() method to trigger the
button when the popup closes and 3 uses doClick().
My results are that it behaves the same for case 0 and 2 (broken) and
properly with the time check.
Although the doClick() option almost worked in the real code, in this
example it throws a null pointer exception - haven't been able to
figure out why yet :-( (btw. I get the exact same behaviour on OS-X and
RedHat linux)

Thanks again,

Steve
---- cut here ----
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/*
* Standalone test of connecting a JToggleButton with a JPopupMenu.
* The goal is to have the toggle appear selected only while the popup
* is visible. When the popup is open, the user should be able to close
* the popup by:
*      1. clicking in the popup (a selection)
*      2. clicking anywhere outside the popup (cancel)
*      3. clicking on the toggle button again (raising the button and
*         canceling the popup)
* Everything works except the case 3.
* In this case the following happen:
*      Initial state: button is selected, popup is open
*      The user clicks the toggle button
*      The popup loses focus
*      The popup fires a cancel event
*      The popup fires an isClosing event
*      The popup becomes invisible
*      The button's action event is fired
*         => the button is not selected and the popup is closed
*      Problem: The action event NEVER sees the popup as being open or
*      the button as being selected
*
* Usage:
*    java PopupButton [0-3]
*
* Arguments:
*    0: display the original state - toggle button doesn't toggle
popup
*    1: use a delay to prevent triggering the toggle button twice
*       with one click
*    2: use invokeLater to delay triggering the toggle button
*    3: use doClick() to reset the button instead of setSelected()
*/
public class PopupButton
extends JFrame
implements ActionListener, PopupMenuListener {

   // start the test. Use any argument on the command line to use
   // invokeLater() to update the toggle button instead of directly
   // updating its status.
   public static void main( String[] args ) {
       int testNum = 0;
       if( args.length > 0 )
           {
           testNum = Integer.parseInt( args[0] );
           }
       final int testCase = testNum;
       javax.swing.SwingUtilities.invokeLater(
           new Runnable() {
               public void run() {
                   new PopupButton( testCase );
               }
           }
       );
   }

   public PopupButton( int testCase ) {
       this.testCase = testCase;

       setDefaultCloseOperation( EXIT_ON_CLOSE );
       getContentPane().setLayout( new FlowLayout() );

       button = new JToggleButton("click me");
       // events caught by actionPerformed() below
       button.addActionListener( this );

       popup = new JPopupMenu();
       // events caught by popupMenuWillBecomeInvisible() below
       popup.addPopupMenuListener( this );

       response = new JButton(
           new AbstractAction("thank you") {
               public void actionPerformed( ActionEvent e ) {
                   popup.setVisible( false );
               }
           }
       );

       String testCaseNames[] = {
           "broken triggers",
           "timed triggers",
           "triggering via invokeLater()",
           "triggering via doClick()" };
       getContentPane().add( new JLabel( "Testing " +
testCaseNames[testCase] ) );
       getContentPane().add( button );
       getContentPane().add( new JLabel(
                   "click here to close the popup " ) );
       popup.add( response );

       pack();
       setVisible( true );
   }

   // respond to the button's click actions by opening or closing the
   // popup
   public void actionPerformed( ActionEvent e ) {
       switch( testCase ) {
           case 1: // ensure a minimum delay before allowing another
event
               if ((System.currentTimeMillis() - lastEvent) < 250) {
                   // lastEvent = System.currentTimeMillis();
                   button.setSelected( false );
                   System.out.println( "button action: double-event,
deselecting button" );
                   return;
               } else {
                   System.out.println( "button action: double-event
time expired" );
                   lastEvent = System.currentTimeMillis();
               }
               break;
           default:
       }

       if( button.isSelected() ) {
           System.out.println( "button action: new popup" );
           Dimension d = button.getPreferredSize();
           popup.show( button, 0, d.height );
       } else {
           System.out.println( "button action: closing old popup" );
           popup.setVisible( false );
       }
   }

   // required by the PopupMenuListener interface
   // disable the toggle button when the popup closes
   public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
       switch( testCase ) {
           case 1:
               System.out.println( "popup closing: deselecting button,
catching event time" );
               lastEvent = System.currentTimeMillis();
               button.setSelected( false );
               break;
           case 2: // use invokeLater()
               System.out.println( "popup closing: deselecting button
later" );
               javax.swing.SwingUtilities.invokeLater(
                   new Runnable() {
                       public void run() {
                           button.setSelected( false );
                       }
                   }
               );
               break;
           case 3: // use doClick()
               System.out.println( "popup closing: clicking button" );
               button.doClick();
               break;
           default: // broken
               System.out.println( "popup closing: deselecting button"
);
               button.setSelected( false );
               break;
       }
   }

   // required by the PopupMenuListener interface
   public void popupMenuCanceled( PopupMenuEvent e ) {}

   // required by the PopupMenuListener interface
   public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {}

   //------------------------------------------------------------
   // ATTRIBUTES
   //------------------------------------------------------------
   private JToggleButton button;    // button to open popup
   private JPopupMenu    popup;     // popup panel
   private JButton       response;  // button in popup panel
   private int           testCase;  // which test case to run
   private long          lastEvent; // prevent the button being
pressed too quickly
}
John McGrath - 23 Feb 2005 07:24 GMT
> Although the doClick() option almost worked in the real code, in this
> example it throws a null pointer exception - haven't been able to
> figure out why yet :-(

You left out the EventQueue.invokeLater().

   case 3: // use doClick()
       System.out.println( "popup closing: clicking button" );
       EventQueue.invokeLater( new Runnable() {
           public void run() {
               button.doClick();
           }
       } );
       break;

When I add that, it works very consistently for me.  How does it work for
you with the above changes?

> btw. I get the exact same behaviour on OS-X and RedHat linux

What machines (speed/ram) are you using to test this?
I tried my code on three different systems using JDK 1.5:

   Window XP  (Dell Precision Workstation 260, 2.8 GHz, 1 GB RAM)
   Fedora 3   (Dell PowerEdge 700 server, 2.8 GHz, 1 GB RAM)
   Red Hat 9  (Dell Dimension XPST, 450 MHz, 500 MB RAM)

I will pare my code down to a simpler program and post it shortly.

Signature

Regards,

John McGrath

John McGrath - 23 Feb 2005 09:18 GMT
> I will pare my code down to a simpler program and post it shortly.

OK, here it is.  I just noticed that you were using a JButton rather than
a JMenuItem, so I added both.

I ran this on all three systems, using both JDK 1.4 and JDK 1.5.  I think
I may have seen it "skip" once, but it generally ran correctly.  I did
notice a minor difference in behavior between JDK 1.4 and JDK 1.5, though.
If you click on one popup button when the popup for another popup  button
is showing, the old popup goes away in both cases, but the new popup is
only shown under JDK 1.5.

After thinking about this a little more, I suspect that there is a timing
problem.  Looking at the AbstractButton code again, I think I was wrong
when I figured that the doClick() would always work.  Part of what
doClick() does is introduce a 68 ms delay, and I think that is what was
making it work.  This has the same effect as the 250 ms delay that Andrey
suggested, except it looks like 68 ms is a little short for some systems.

In any case, here is the code.  Would you run it on your systems and let
me know how it works?

=======================================================================
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class PopupButton
   extends JToggleButton
{
   private JPopupMenu popup;

   public PopupButton( String text, JPopupMenu popup ) {
       super( text );
       addActionListener( buttonAction );
       setPopup( popup );
   }

   public void setPopup( JPopupMenu newPopup ) {
       if ( popup != null ) {
           popup.removePopupMenuListener( popupListener );
       }
       popup = newPopup;
       if ( popup != null ) {
           popup.addPopupMenuListener( popupListener );
       }
   }

   protected void showPopup() {
       if ( popup != null ) {
           Point pos = new Point( 0, getSize().height );
           popup.show( PopupButton.this, pos.x, pos.y );
       }
   }

   protected void hidePopup() {
       if ( popup != null ) {
           popup.setVisible( false );
       }
   }

   private ActionListener buttonAction = new ActionListener() {
       public void actionPerformed( ActionEvent event ) {
           if ( isSelected() ) {
               showPopup();
           } else {
               hidePopup();
           }
       }
   };

   private PopupMenuListener popupListener = new PopupMenuListener() {
       public void popupMenuWillBecomeInvisible( PopupMenuEvent event ) {
           SwingUtilities.invokeLater( new Runnable() {
               public void run() {
                   doClick();
               }
           } );
       }

       public void popupMenuWillBecomeVisible( PopupMenuEvent event ) {}
       public void popupMenuCanceled( PopupMenuEvent event ) {}
   };

   public static void main( String[] args ) {
       EventQueue.invokeLater( new Runnable() {
           public void run() {
               JFrame frame = new JFrame();
               frame.setDefaultCloseOperation( javax.swing.JFrame.
                   EXIT_ON_CLOSE );

               // Popup menu
               JPopupMenu popup1 = new JPopupMenu();
               popup1.add( "thank you" );

               // Popup with button
               JPopupMenu popup2 = new JPopupMenu();
               final PopupButton popupButton2 =
                   new PopupButton( "click me", popup2 );
               popup2.add( new JButton( new AbstractAction("thank you") {
                   public void actionPerformed( ActionEvent event ) {
                       popupButton2.hidePopup();
                   }
               } ) );

               Container content = frame.getContentPane();
               content.setLayout( new FlowLayout() );
               content.add( new JLabel( "Testing PopupButton" ) );
               content.add( new PopupButton( "click me", popup1 ) );
               content.add( popupButton2 );
               content.add( new JLabel("click here to close the popup") );

               frame.pack();
               frame.setVisible( true );
           }
       } );
   }
}
=======================================================================

Signature

Regards,

John McGrath



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.