/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.util.docking;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
/**
* The SideWindowCarrierPanel combines the drag-area (to resize the component) with the actual content of the of the
* SidePanel. The content is stored in a list and each update builds a hierarchy of splitpanes to display the content to
* the user.
*
* @author Thomas Morgner.
*/
public class SideWindowCarrierPanel extends JComponent {
private class DragHandler extends MouseAdapter implements MouseMotionListener {
private int startX;
private int startY;
private DragHandler() {
}
public void mousePressed( final MouseEvent e ) {
startX = e.getX();
startY = e.getY();
}
public void mouseReleased( final MouseEvent e ) {
}
public void mouseDragged( final MouseEvent e ) {
if ( alignment == GlobalPane.Alignment.LEFT ) {
final int x = e.getX();
final int xDiff = startX - x;
final int w = Math.max( 0, getWidth() - xDiff );
final Dimension s = contentPane.getSize();
s.width = w;
contentPane.setPreferredSize( s );
contentPane.revalidate();
} else if ( alignment == GlobalPane.Alignment.RIGHT ) {
final int x = e.getX();
final int xDiff = startX - x;
final int w = Math.max( 0, getWidth() + xDiff );
final Dimension s = contentPane.getSize();
s.width = w;
contentPane.setPreferredSize( s );
contentPane.revalidate();
} else if ( alignment == GlobalPane.Alignment.TOP ) {
final int y = e.getY();
final int yDiff = startY - y;
final int h = Math.max( 0, getHeight() - yDiff );
final Dimension s = contentPane.getSize();
s.height = h;
contentPane.setPreferredSize( s );
contentPane.revalidate();
} else if ( alignment == GlobalPane.Alignment.BOTTOM ) {
final int y = e.getY();
final int yDiff = startY - y;
final int h = Math.max( 0, getHeight() + yDiff );
final Dimension s = contentPane.getSize();
s.height = h;
contentPane.setPreferredSize( s );
contentPane.revalidate();
}
}
/**
* Invoked when the mouse cursor has been moved onto a component but no buttons have been pushed.
*/
public void mouseMoved( final MouseEvent e ) {
}
}
private static class KillAllBordersBasicSplitPaneUI extends BasicSplitPaneUI {
public BasicSplitPaneDivider createDefaultDivider() {
return new BasicSplitPaneDivider( this ) {
public void setBorder( final Border b ) {
// ahh, lovely mac-osx would slap its borders everywhere.
}
};
}
}
private class CategoryVisibleUpdateHandler implements PropertyChangeListener {
/**
* This method gets called when a bound property is changed.
*
* @param evt A PropertyChangeEvent object describing the event source and the property that has changed.
*/
public void propertyChange( final PropertyChangeEvent evt ) {
revalidateComponent();
}
}
private ArrayList<Category> childs;
private JPanel dragPanel;
private GlobalPane.Alignment alignment;
private JComponent contentPane;
private CategoryVisibleUpdateHandler visibleUpdateHandler;
public SideWindowCarrierPanel( final GlobalPane.Alignment alignment ) {
this.setVisible( false );
this.visibleUpdateHandler = new CategoryVisibleUpdateHandler();
this.alignment = alignment;
this.childs = new ArrayList<Category>();
this.contentPane = new JPanel();
this.contentPane.setLayout( new BorderLayout() );
dragPanel = new JPanel();
dragPanel.setPreferredSize( new Dimension( 5, 5 ) );
dragPanel.setSize( 5, 5 );
dragPanel.setOpaque( true );
dragPanel.setBorder( BorderFactory.createEmptyBorder( 0, 0, 1, 0 ) );
final DragHandler dragHandler = new DragHandler();
dragPanel.addMouseListener( dragHandler );
dragPanel.addMouseMotionListener( dragHandler );
setLayout( new BorderLayout() );
add( contentPane, BorderLayout.CENTER );
switch( alignment ) {
case TOP:
add( dragPanel, BorderLayout.SOUTH );
dragPanel.setCursor( Cursor.getPredefinedCursor( Cursor.N_RESIZE_CURSOR ) );
break;
case BOTTOM:
add( dragPanel, BorderLayout.NORTH );
dragPanel.setCursor( Cursor.getPredefinedCursor( Cursor.S_RESIZE_CURSOR ) );
break;
case LEFT:
add( dragPanel, BorderLayout.EAST );
dragPanel.setCursor( Cursor.getPredefinedCursor( Cursor.W_RESIZE_CURSOR ) );
break;
case RIGHT:
add( dragPanel, BorderLayout.WEST );
dragPanel.setCursor( Cursor.getPredefinedCursor( Cursor.E_RESIZE_CURSOR ) );
break;
}
}
public void addWindow( final Category toolWindow ) {
if ( childs.contains( toolWindow ) ) {
return;
}
childs.add( toolWindow );
toolWindow.addPropertyChangeListener( Category.MINIMIZED_PROPERTY, visibleUpdateHandler );
revalidateComponent();
}
public void removeWindow( final Category toolWindow ) {
childs.remove( toolWindow );
toolWindow.removePropertyChangeListener( Category.MINIMIZED_PROPERTY, visibleUpdateHandler );
revalidateComponent();
}
public Category getWindow( final int index ) {
return childs.get( index );
}
public int getWindowCount() {
return childs.size();
}
public void setToolWindowHeight( final int height ) {
for ( int i = 0; i < childs.size(); i++ ) {
final Category category = childs.get( i );
final JComponent toolWindow = category.getMainComponent();
final Dimension size = toolWindow.getSize();
size.height = height - dragPanel.getHeight();
toolWindow.setSize( size );
}
}
public void setToolWindowWidth( final int width ) {
for ( int i = 0; i < childs.size(); i++ ) {
final Category category = childs.get( i );
final JComponent toolWindow = category.getMainComponent();
final Dimension size = toolWindow.getSize();
size.width = width - dragPanel.getWidth();
toolWindow.setSize( size );
}
}
public JComponent getDragPanel() {
return dragPanel;
}
public void revalidateComponent() {
try {
recomputeVisibleFlag();
contentPane.removeAll();
if ( childs.isEmpty() ) {
return;
}
final ArrayList<JComponent> tempList = new ArrayList<JComponent>( childs.size() );
for ( int i = 0; i < childs.size(); i++ ) {
final Category category = childs.get( i );
if ( category.isMinimized() == false ) {
tempList.add( category.getMainComponent() );
}
}
if ( tempList.isEmpty() ) {
// noinspection UnnecessaryReturnStatement
return;// just to be more clear
}
if ( tempList.size() == 1 ) {
final JComponent mainComponent = tempList.get( 0 );
contentPane.add( mainComponent, BorderLayout.CENTER );
return;
}
final JComponent firstComponent = tempList.get( 0 );
JSplitPane splitPane = new JSplitPane( alignment.getDirection(), true );
splitPane.setUI( new KillAllBordersBasicSplitPaneUI() );
splitPane.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
splitPane.setTopComponent( firstComponent );
splitPane.setDividerLocation( 0.5 );
splitPane.setResizeWeight( 0.5 );
splitPane.setContinuousLayout( true );
contentPane.add( splitPane, BorderLayout.CENTER );
for ( int i = 1; i < tempList.size(); i++ ) {
final JComponent toolWindow = tempList.get( i );
if ( i == tempList.size() - 1 ) {
splitPane.setBottomComponent( toolWindow );
splitPane.setDividerLocation( 0.5 );
splitPane.setResizeWeight( 0.5 );
} else {
final JSplitPane childSplitPane = new JSplitPane( alignment.getDirection(), true );
childSplitPane.setUI( new KillAllBordersBasicSplitPaneUI() );
childSplitPane.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
childSplitPane.setTopComponent( toolWindow );
childSplitPane.setDividerLocation( 0.5 );
childSplitPane.setResizeWeight( 0.5 );
splitPane.setBottomComponent( childSplitPane );
splitPane.setDividerLocation( 0.5 );
splitPane.setResizeWeight( 0.5 );
splitPane = childSplitPane;
}
}
} finally {
revalidate();
invalidate();
repaint();
}
}
private void recomputeVisibleFlag() {
for ( int i = 0; i < childs.size(); i++ ) {
final Category category = childs.get( i );
if ( category.isMinimized() == false ) {
setVisible( true );
return;
}
}
setVisible( false );
}
public void setPreferredContentSize( final Integer value ) {
if ( value == null ) {
contentPane.setPreferredSize( null );
contentPane.revalidate();
return;
}
final Dimension dimension = contentPane.getSize();
if ( alignment == GlobalPane.Alignment.LEFT || alignment == GlobalPane.Alignment.RIGHT ) {
dimension.width = value;
} else if ( alignment == GlobalPane.Alignment.TOP || alignment == GlobalPane.Alignment.BOTTOM ) {
dimension.height = value;
}
contentPane.setPreferredSize( dimension );
contentPane.revalidate();
}
public Integer getPreferredContentSize() {
final Dimension dimension = contentPane.getPreferredSize();
if ( dimension == null ) {
return null;
}
if ( alignment == GlobalPane.Alignment.LEFT || alignment == GlobalPane.Alignment.RIGHT ) {
return dimension.width;
} else if ( alignment == GlobalPane.Alignment.TOP || alignment == GlobalPane.Alignment.BOTTOM ) {
return dimension.height;
}
return null;
}
}