Desktop.browse() opens multiple windows - java

We have the following code running in an applet running in JRE 1.6.0_26.
Desktop.getDesktop().browse(new URI("www.google.com")
On some Windows 7 64-bit, IE8 machines this command opens two windows but not on others which should be the same setup.
Does anyone have any idea what would cause this?

I strongly suspect this was just some coding carelessness (which I'm as guilty of as anyone else).
Consider the following code:
JButton myButton1 = new JButton("Click 1");
myButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Desktop.getDesktop().browse(new URI("www.google.com"));
}
});
JButton myButton2 = new JButton("Click 2");
myButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Desktop.getDesktop().browse(new URI("www.google.com"));
}
});
Notice the bug here?
The intention was to assign one action to each button, but because of a careless copy/paste after the definition of myButton2, we mistakenly assign a second action to myButton1.
What will happen now is when the user clicks on myButton1, the first action will be invoked resulting in the display of a browser with www.google.com showing, and then the second action will be invoked resulting in either another tab in that window or a whole other window (depending on your browser setup).

Related

Can I make an automated java application ignore JOptionPanes?

There is a java swing application that I need to automate one of the functions of. It's quite simple - the user clicks a button in the swing application and starts an action.
I made a small java application that includes the java swing application as a .jar and calls the action behind the button (read).
The problem is - in case of an exception, the swing .jar shows JOptionPane, which halts the automated execution. Is it possible to somehow override this behavior without altering the original jar?
Application structure:
Main.java
import com.swingapp.ui
public static void main(String[] args){
Swingapp.read();
}
Then the read() function in the Swingapp library:
public void read(){
try{
//do a bunch of stuff...
} catch (Exception ex){
JOptionPane.showMessageDialog(null, ex.getMessage()); // In case of an exception, the swing application will show a message dialog. This halts the automated execution of my java task, I'd like to just skip this
}
When exception happens in above application, user is expected to click "OK". But running this as automated task, nobody there to click okay
Since a JOptionPane gains focus as soon as it opens (I think the most right button gets the focus, but it does not matter in your case) you can do the following:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent arg0) {
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
while(c != null) {
if (c instanceof JOptionPane) {
try {
new Robot().keyPress(KeyEvent.VK_ENTER);
} catch (AWTException e) {
e.printStackTrace();
break;
}
}
c = c.getParent();
}
}
}, AWTEvent.FOCUS_EVENT_MASK);
It will traverse up to see if anything in the current hierarchy is an instance of JOptionPane. If so -> simulate that the user pressed Enter (Return) which will close the dialog even if the focus is in an input field.
I have following solution for you. You need to registrate a listener to monitor all window events. Use Toolkit.getDefaultToolkit().addAWTEventListener(). If you get a window opened event, try to check whether the window is a JDialog and whether the dialog's contentPane contains an instance of JOptionPane. If yes you need traverse the component tree, find the first button and click it.

java: TrayIcon right click disabled on Mac OsX

I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:
public class SystemTrayDemo
{
private SystemTray tray;
private TrayIcon tray_icon;
public SystemTrayDemo()
{
if (!SystemTray.isSupported())
{
JOptionPane.showMessageDialog(null, "System tray not supported!");
return;
}
else
tray = SystemTray.getSystemTray();
final PopupMenu popup = new PopupMenu();
MenuItem exit = new MenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (tray != null)
{
tray.remove(tray_icon);
System.exit(0);
}
}
});
popup.add(exit);
//add tray icon
tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
tray_icon.setImageAutoSize(true);
try
{
tray.add(tray_icon); // adds icon
}
catch (AWTException ex) {}
}
private Image getIcon(String name)
{
URL _url = getClass().getResource(name);
return new ImageIcon(_url).getImage();
}
public static void main(String args[])
{
new SystemTrayDemo();
}
}
but how I already said, only through left mouse button click.
So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:
public static void fireMouseEvent(Component c)
{
MouseEvent me = new MouseEvent(c, // which
MouseEvent.MOUSE_CLICKED, // what
System.currentTimeMillis(), // when
MouseEvent.BUTTON1_MASK, // no modifiers
0, 0, // where: at (10, 10}
1, // only 1 click
true); // popup trigger
c.dispatchEvent(me);
}
the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:
class MouseAdapt extends java.awt.event.MouseAdapter
{
public void mouseClicked(java.awt.event.MouseEvent me)
{
int button = me.getButton();
if(button == java.awt.event.MouseEvent.BUTTON3)
{
fireMouseEvent(me.getComponent());
}
}
}
try
{
tray.add(tray_icon); // aggiungi l'icona
tray_icon.addMouseListener(new MouseAdapt());
}
catch (AWTException ex) {}
Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.
Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray
to activate the [TrayIcon] relative popup menu with both left and right click
This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.
https://bugs.openjdk.java.net/browse/JDK-8041890
only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code
Even this is broken in some Java versions (7u79), fixed with an upgrade...
https://bugs.openjdk.java.net/browse/JDK-7158615
Cross-Platform TrayIcon Support:
Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.
Related Tray Issues for Other Platforms
Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004
In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this)
https://stackoverflow.com/a/3882028/3196753
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this)
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157
https://bugzilla.redhat.com/show_bug.cgi?id=1014448
In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon
So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.

Focus issues with java7 modal dialogs on mac osx

I've been validating a swing application that runs on an applet for mac osx.
During this validation I found the following issues with the modal dialogs:
When a dialog is open and is setModal(true) it blocks the content of the root window, but if you click somewhere on the root window, the dialog goes under it, but it should remain on the top of the root window.
If the dialog has a JTextInputField it does not receive focus even when you click on it.
So I created a small program to show the problem. Can you please help me to understand what is wrong here?
package com.macosx.tests;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class DialogExample extends JApplet{
private static final long serialVersionUID = 1L;
private JPanel panel;
private JButton openDialogBtn;
private void doStart() {
panel = new JPanel();
panel.setPreferredSize(new Dimension(500,500));
openDialogBtn = new JButton("open dialog");
openDialogBtn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
ModalDialog dialog = new ModalDialog(panel, true);
dialog.setVisible(true);
}
});
panel.add(openDialogBtn);
setContentPane(panel);
}
class ModalDialog extends JDialog {
private static final long serialVersionUID = 1L;
public ModalDialog(Component parent, boolean modal) {
Dimension dimensionParentFrame = parent.getSize();
setSize(new Dimension((parent == null) ? 300 : dimensionParentFrame.width / 2, 75));
setModal(modal);
setModalityType(ModalityType.APPLICATION_MODAL);
JTextField txtField = new JTextField();
add(txtField, BorderLayout.CENTER);
}
}
#Override
public void start() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
doStart();
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Use the above to create a .jar file (test.jar). Once that is done, create a html file with the following content:
<html>
<head>
<title>Dialog test Applet</title>
</head>
<body>
<applet id="DialogTestApplet" height="800" width="600"
code="com.macosx.tests.DialogExample"
archive="test.jar">
</applet>
</div>
</body>
</html>
When this is done, run the html file. You'll see an applet with a gray background and with a button. Then try to:
click on the button to open the dialog. After that, click somewhere on the gray area: the dialog goes under the browser window but it should remain on the top, right?
click on the button to open the dialog. After that click on the textfield of the dialog and try to write something: the textdialog does not receive focus.
So, what am I doing wrong here? Can someone with a mac computer test this please?
Thanks
Specs:
java.vendor Oracle Corporation
java.version 1.7.0_07
os.name Mac OS X
os.version 10.7.4
browser firefox 15
NOTE: please note that this is only happening when the applet runs on the browser and only on mac osx.
I found another workaround. When the window is opened, show an optionpane for a few milliseconds and close it. It give the focus to the optionpane and then back to the dialog, allowing to ignore the bug.
Add this snipet of code to your dialog constructor and it should work:
addWindowListener(new WindowAdapter(){
public void windowOpened(WindowEvent e){
JOptionPane pane = new JOptionPane();
final JDialog dialog = pane.createDialog("Please Wait");
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
timer.setRepeats(false);
timer.start();
dialog.setVisible(true);
}
You should put an "owner" window on your ModalDialog. To do that, you must call super(owner) in your ModalDialog constructor and you can retrieve the parent window of your component parent with SwingUtilities.getWindowAncestor(parent).
not Mac/OSX user but this is common issue about Focus and JDialog,
there are another issues in the case that JDialog is created on Runtime,
Focus is asynchronous based on properties came from Native OS
create this JDialog only once time and re_use this container for another action
JDialog#setVisible should be wrapped into invokeLater() too
is possible to force the Focus by JTextField#setText(JTextField#getText()) wrapped into invokeLater()
there is Dialog Focus, one of great workaround by #camickr
I confirm, I have the same bug with an old applet running in JDK7 on OS X. As the poster mentioned, the bug is seen only with the applet running in the browser (ff) and not with the appletviewer.
I can verify that this is a problem for Java 1.7 Update 7+ on the Safari 6 and Firefox running on Mountain Lion. Curiously it is not a problem on earlier versions of Safari that run on Lion but it is a problem in Firefox on the older OS. I am pretty desperate to find a fix for this as a number of my applet users are on Macs. One workaround that I have found (that is not sufficient by any means) is to minify the window and then reopen it. The textfields/textareas then become editable. Hopefully, we can find a better solution that gets around this annoying requirement.
I experienced the same problem on Mac with Java 7 update 9 with Safari and Firefox. When I opened a JDialog which contained a JTextField the JTextField was inaccessible.
I did find a solution. I inserted a delay from when the user pressed the “show dialog button” to executing the code that shows the button.
For example:
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae){
TitleDialog dialog = new TitleDialog(main.findParentFrame()); // My JDialog which contains a JTextField.
dialog.setVisible(true);
}
};
javax.swing.Timer timer = new javax.swing.Timer(1000, al);
timer.setRepeats(false);
timer.start();
I experienced that if the delay was to short the solution would not work.
If one uses SwingUtilities.invokeLater instead of javax.swing.Timer it will not work. Maybe the delay of SwingUtilities.invokeLater is too short.
I found one more workaround. When JDialog is invoked from JavaScript it has a focus.
Create an applet's method which will show a dialog
Call this method from JavaScript.
Hope, it helps. By the way, web start samples from Java tutorial have the same issue http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html
I want to use the workaround above (to open dialog from the dialog), but without showing any dialog.
Here is a code for not visible dialog.
final JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.setSize(0, 0);
dialog.setModal(true);
dialog.pack();
I have found a solution.
GetDirectory varGetDirectory = new GetDirectory(new JFrame(),true);
varGetDirectory.setVisible(true);
GetDirectory is JDialog containing a JFileChooser.
The weird thing is that all JDialog object should be called using new JFrame() as parent, otherwise clicking from one parent window, will bring the top modal JDialog backwards in the zOrder and somehow it cannot be set on top anymore.
My problem was the same as above. When I have created the JDialog from another JDialog, the new dialog appeared behind the other.
To bring it to top I have set the parent of all JDialogs as described above and it worked according to what expected.

Java JMenu setAccelerator() problem

When I set setAccelerator() to Control + A or Control + P and I run the program it doesn't detect the keystroke.
Here's the code:
menuItem = new JMenuItem("About");
menuItem.setActionCommand("About");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK));
menuItem.setMnemonic(KeyEvent.VK_A);
menuItem.addActionListener(this);
menu.add(menuItem);
Then when it's pressed it should invoke the Action Listener:
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("About")) {
System.out.println("About");
}
}
I'm running it in Eclipse on a Mac if that matters.
Control-A and Control-P are both keystrokes that may already be intercepted, depending on your platform and depending on what has keyboard focus. Control-A may already be intercepted and interpreted as "select all", and Control-P may already be intercepted and interpreted as "paste".
What if you select a less commonly-used keystroke instead of "Control-A", such as "Control-Shift-A" or "Control-B"? Here's a modified version of your code that uses Control-Shift-A instead of Control-A:
menuItem = new JMenuItem("About");
menuItem.setActionCommand("About");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK | Event.SHIFT_MASK));
menuItem.setMnemonic(KeyEvent.VK_A);
menuItem.addActionListener(this);
menu.add(menuItem);
I tested this change on my own system using the JMenu demo from the Swing tutorial, and I found (exactly as you did) that registering Control-A as the accelerator had no effect. However, registering Control-Shift-A as the accelerator worked perfectly.
not sure if it will help, but you're using Event.CTRL_MASK instead of KeyEvent.CTRL_MASK

Performing an action when an JMenuItem is clicked?

So i have made a simple program with a basic menu at the top of the frame, Now i just need to put actions behind each JMenuItem. Im struggling to work the code out though, Here is what i thought would work:
JMenu file_Menu = new JMenu("File");
JMenuItem fileExit = new JMenuItem("Exit Program");
file_Menu.add(fileExit);
fileExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JFrame hello = new JFrame("POPUP");
hello.setSize(100,75);
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
hello.setVisible(true);
}
});
main_Menu.add(file_Menu);
This doesn't seem to work though, I thought that this code would create a small popup window when the menu item is clicked.
Can any spot the bug because i cant seem to.
Suggestion: Instead of adding a separate ActionListener, just use AbstractAction:
JMenuItem fileExit = new JMenuItem(new AbstractAction("Exit Program") {
public void actionPerformed(ActionEvent ae) {
JFrame hello = new JFrame("POPUP");
hello.setSize(100,75);
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
hello.setVisible(true);
}
});
I'd also suggest, instead of setting EXIT_ON_CLOSE on the popup menu, you set it on the main frame of your application, and have the action simply call theMainFrame.dispose().
You got it working, but you have another problem.
Don't do this:
hello.setDefaultCloseOperation(hello.EXIT_ON_CLOSE);
When you close the pop-up frame, your entire JVM terminates. Consult JFrame.setDefaultCloseOperation javadocs for a more appropriate value.
Give an instance of Action (extend from AbstractAction) to JMenuItem
Based on the code you posted it looks like it should work, but we can't see the entire context of how the menu item is being used.
Did you debug your code (with a System.out.println) to see if the ActionListener is being invoked?
If you need more help post your SSCCE that demonstrates the problem.
Fixed it.
Forgot to add the actionPerformed method.

Categories

Resources