Drag ( externalize ) DefaultSingleCDockable to second monitor

Hello,

Can you please support me in the following :

When I drag an externalizable DefaultSingleCDockable , move it on a second monitor and release the mouse,
it disappears. It also causes strange side effects / repaint problems on the application frame in the first monitor.

But if I first click the externalize button on its tab , then I can drag it to the second monitor.

I 've found the following work around in the forums :

	  final DefaultScreenDockWindowFactory factory = new DefaultScreenDockWindowFactory();
	  factory.setUndecorated( false );
	  control.putProperty(ScreenDockStation.WINDOW_FACTORY, factory);

This is working just fine but also places the DefaultSingleCDockable within a dialog with a close button
that does nothing.

I then used something I also found in the forums :

	  DefaultScreenDockWindowFactory factory = new DefaultScreenDockWindowFactory()
	  { //Ensure the dialog's close button will dismiss the dialog
		  @Override
		  public ScreenDockWindow createWindow(ScreenDockStation station)
		  {
			  final ScreenDockWindow window = super.createWindow(station);
			  if (window instanceof ScreenDockDialog && !isUndecorated())
			  {
				  ((ScreenDockDialog) window).getDialog().setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				  ((ScreenDockDialog) window).getDialog().addWindowListener(new WindowAdapter()
				  { //Prevents a memory leak by removing the dialog's station dockable so it doesn't get orphaned
					  @Override
					  public void windowClosed(WindowEvent we)
					  {
						  ((ScreenDockDialog) window).getStation().drag(((ScreenDockDialog) window).getDockable());
					  }
				  });
			  }
			  return window;
		  }
	  };
	  factory.setUndecorated(false);
	  control.putProperty(ScreenDockStation.WINDOW_FACTORY, factory);

In which case , the close button does close the dialog but also throws a :

Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
at bibliothek.gui.dock.ScreenDockStation.drag(ScreenDockStation.java:1052)

when the line :

((ScreenDockDialog) window).getStation().drag(((ScreenDockDialog) window).getDockable());

is invoked.

Ideally , the DefaultSingleCDockable should be able to be dragged to a second monitor without
problems.If this is not possible , it is ok to place it inside a dialog with a close button.
But after I close that dialog , I would like to at least catch this event and be informed that
this DefaultSingleCDockable is no longer visible.

Thanks a lot guys,

George

It’s a while since last time someone reported an issue with a second monitor. What settings do you use? What OS, what JDK, what DockingFrames Version? I always had trouble to recreate this issue in order perform some real testing.

The exception should of course not happen. I’m currently at work, but I’ll look into it later. Once there is no exception, a CDockableStateListener should inform you about the event.

I don’t yet have any solution for the question of why the windows disappear in the first place. But at least here is a working workaround:

Seems the “window closed event” is fired twice because “setVisible(false)” is called a second time when a Dockable is dragged from the ScreenDockStation. The code below adds the necessary checks to stop this exception.

Also the “CDockableAdapter.visibilityChanged” method would be called whenever the visibility of a dockable changes. This includes the cases where the user just clicked on the red “x”.


import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JDialog;
import javax.swing.JFrame;

import bibliothek.gui.Dockable;
import bibliothek.gui.dock.ScreenDockStation;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.event.CDockableAdapter;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.station.screen.DefaultScreenDockWindowFactory;
import bibliothek.gui.dock.station.screen.ScreenDockDialog;
import bibliothek.gui.dock.station.screen.ScreenDockWindow;

public class Dock88 {
	public static void main( String[] args ){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setBounds( 20, 20, 400, 300 );
		CControl control = new CControl( frame );

		control.addStateListener( new CDockableAdapter(){
			@Override
			public void visibilityChanged( CDockable dockable ){
				System.out.println( "visibility event: " + dockable.isVisible() );
			}
		});
		
		DefaultScreenDockWindowFactory factory = new DefaultScreenDockWindowFactory(){ //Ensure the dialog's close button will dismiss the dialog
			@Override
			public ScreenDockWindow createWindow( ScreenDockStation station ){
				final ScreenDockWindow window = super.createWindow( station );
				if( window instanceof ScreenDockDialog && !isUndecorated() ) {
					((ScreenDockDialog) window).getDialog().setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE );
					((ScreenDockDialog) window).getDialog().addWindowListener( new WindowAdapter(){ 
						// Prevents a memory leak by removing the dialog's station dockable so it doesn't get orphaned
						@Override
						public void windowClosed( WindowEvent we ){
							ScreenDockDialog dialog = (ScreenDockDialog)window;
							Dockable dockable = dialog.getDockable();
							if( dockable != null ){
								dialog.getStation().drag( dockable );
							}
						}
					});
				}
				return window;
			}
		};
		factory.setUndecorated( false );
		control.putProperty( ScreenDockStation.WINDOW_FACTORY, factory );

		frame.add( control.getContentArea() );

		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "hallo" );
		control.addDockable( dockable );
		dockable.setCloseable( true );
		dockable.setExtendedMode( ExtendedMode.EXTERNALIZED );
		dockable.setVisible( true );

		frame.setVisible( true );
	}
}