/*
* Copyright 2008-2013 Andre Pfeiler
*
* This file is part of FindBugs-IDEA.
*
* FindBugs-IDEA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FindBugs-IDEA 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FindBugs-IDEA. If not, see <http://www.gnu.org/licenses/>.
*/
package org.twodividedbyzero.idea.findbugs.gui.common;
/**
* Layout Manager to control positions of docked toolbars
*
* $Date: 2013-12-05 08:09:56 -0600 (Thu, 05 Dec 2013) $
*
* @author Andre Pfeiler<andrep@twodividedbyzero.org>
* @version $Revision: 257 $
* @since 0.9.29-dev
*/
import javax.swing.JSeparator;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import java.awt.AWTError;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
public class NDockLayout extends BorderLayout {
private static final long serialVersionUID = 0L;
private final ArrayList<Component> _north = new ArrayList<Component>(1);
private final ArrayList<Component> _south = new ArrayList<Component>(1);
private final ArrayList<Component> _east = new ArrayList<Component>(1);
private final ArrayList<Component> _west = new ArrayList<Component>(1);
private Component _center;
private int _northHeight;
private int _southHeight;
private int _eastWidth;
private int _westWidth;
private final Object[] _embeddedComponents = new Object[4];
private static final int TOP = SwingConstants.TOP;
private static final int BOTTOM = SwingConstants.BOTTOM;
private static final int LEFT = SwingConstants.LEFT;
private static final int RIGHT = SwingConstants.RIGHT;
public NDockLayout() {
_embeddedComponents[0] = _north;
_embeddedComponents[1] = _south;
_embeddedComponents[2] = _west;
_embeddedComponents[3] = _east;
}
@Override
public void addLayoutComponent(final Component component, final Object con) {
synchronized (component.getTreeLock()) {
if (con != null) {
final String s = con.toString();
component.setVisible(true);
if (s.equals(NORTH)) {
_north.add(component);
} else if (s.equals(SOUTH)) {
_south.add(component);
} else if (s.equals(EAST)) {
_east.add(component);
} else if (s.equals(WEST)) {
_west.add(component);
} else if (s.equals(CENTER)) {
_center = component;
}
//component.getParent().invalidate();
component.getParent().validate();
} else {
throw new IllegalArgumentException("cannot add to layout: constraint must be a string.");
}
}
}
@Override
public void removeLayoutComponent(final Component component) {
_north.remove(component);
_south.remove(component);
_east.remove(component);
_west.remove(component);
if (component.equals(_center)) {
//noinspection AssignmentToNull
_center = null;
}
flipSeparators(component, SwingConstants.VERTICAL);
//component.getParent().invalidate();
component.getParent().validate();
}
@Override
public void layoutContainer(final Container target) {
synchronized (target.getTreeLock()) {
final Insets insets = target.getInsets();
int top = insets.top;
int bottom = target.getHeight() - insets.bottom;
int left = insets.left;
int right = target.getWidth() - insets.right;
_northHeight = getPreferredDimension(_north).height;
_southHeight = getPreferredDimension(_south).height;
_eastWidth = getPreferredDimension(_east).width;
_westWidth = getPreferredDimension(_west).width;
layoutComponents(target, _north, left, top, right - left, _northHeight, TOP);
top += _northHeight + getVgap();
layoutComponents(target, _south, left, bottom - _southHeight, right - left, _southHeight, BOTTOM);
bottom -= _southHeight + getVgap();
layoutComponents(target, _east, right - _eastWidth, top, _eastWidth, bottom - top, RIGHT);
right -= _eastWidth + getHgap();
layoutComponents(target, _west, left, top, _westWidth, bottom - top, LEFT);
left += _westWidth + getHgap();
if (_center != null) {
_center.setBounds(left, top, right - left, bottom - top);
}
}
}
/**
* Returns the ideal width for a vertically oriented toolbar and the ideal height for a horizontally oriented tollbar.
*
* @param components the <code>Component<code>(s) to get the ideal <code>Dimension</code> for
* @return Returns the ideal width for a vertically oriented toolbar and the ideal height for a horizontally oriented tollbar.
*/
private static Dimension getPreferredDimension(final Iterable<Component> components) {
@SuppressWarnings("MultipleVariablesInDeclaration")
int w = 0, h = 0;
for (final Component comp : components) {
final Dimension d = comp.getPreferredSize();
w = Math.max(w, d.width);
h = Math.max(h, d.height);
}
return new Dimension(w, h);
}
@SuppressWarnings({"AssignmentToMethodParameter"})
private void layoutComponents(final Container target, final ArrayList<Component> components, int x, int y, final int w, final int h, final int orientation) {
int offset = 0;
Component component = null;
if (orientation == TOP || orientation == BOTTOM) {
offset = x;
int totalWidth = 0;
int cwidth = 0;
final int num = components.size();
for (int i = 0; i < num; i++) {
component = components.get(i);
flipSeparators(component, SwingConstants.VERTICAL);
final int widthSwap = totalWidth;
final int cwidthSwap = cwidth;
cwidth = component.getPreferredSize().width;
totalWidth += cwidth;
if (w < totalWidth && i != 0) {
final Component c0 = components.get(i - 1);
final Rectangle rec = c0.getBounds();
c0.setBounds(rec.x, rec.y, w - widthSwap + cwidthSwap, rec.height);
offset = x;
if (orientation == TOP) {
y += h;
_northHeight += h;
} else if (orientation == BOTTOM) {
_southHeight += h;
y -= h;
}
totalWidth = cwidth;
}
if (i + 1 == num) {
component.setBounds(x + offset, y, w - totalWidth + cwidth, h);
} else {
component.setBounds(x + offset, y, cwidth, h);
offset += cwidth;
}
}
flipSeparators(component, SwingConstants.VERTICAL);
} else {
int totalHeight = 0;
int cheight = 0;
final int num = components.size();
for (int i = 0; i < num; i++) {
component = components.get(i);
flipSeparators(component, SwingConstants.HORIZONTAL);
final int heightSwap = totalHeight;
final int cheightSwap = cheight;
cheight = component.getPreferredSize().height;
totalHeight += cheight;
if (h < totalHeight && i != 0) {
final Component c0 = components.get(i - 1);
final Rectangle rec = c0.getBounds();
c0.setBounds(rec.x, rec.y, rec.width, h - heightSwap + cheightSwap);
//offset = y;
if (orientation == LEFT) {
x += w;
_westWidth += w;
} else if (orientation == RIGHT) {
_eastWidth += w;
x -= w;
}
totalHeight = cheight;
offset = 0;
}
if (i + 1 == num) {
component.setBounds(x, y + offset, w, h - totalHeight + cheight);
} else {
component.setBounds(x, y + offset, w, cheight);
offset += cheight;
}
}
flipSeparators(component, SwingConstants.HORIZONTAL);
}
}
private static void flipSeparators(final Component c, final int orientation) {
if (c != null && c instanceof JToolBar/* && UIManager.getLookAndFeel().getName().toLowerCase().contains("windows")*/) {
final JToolBar jtb = (JToolBar) c;
final Component[] comps = jtb.getComponents();
if (comps != null && comps.length > 0) {
for (int i = 0; i < comps.length; i++) {
try {
final Component component = comps[i];
if (component != null) {
if (component instanceof JSeparator) {
final boolean isVisible = component.isVisible();
jtb.remove(component);
final JSeparator separ = new JSeparator();
separ.setVisible(isVisible);
if (orientation == SwingConstants.VERTICAL) {
jtb.setOrientation(SwingConstants.VERTICAL);
separ.setOrientation(SwingConstants.VERTICAL);
separ.setMinimumSize(new Dimension(2, 6));
separ.setPreferredSize(new Dimension(2, 6));
separ.setMaximumSize(new Dimension(2, 100));
} else {
jtb.setOrientation(SwingConstants.HORIZONTAL);
separ.setOrientation(SwingConstants.HORIZONTAL);
separ.setMinimumSize(new Dimension(6, 20));
separ.setPreferredSize(new Dimension(6, 20));
separ.setMaximumSize(new Dimension(100, 20));
}
jtb.add(separ, i);
}
}
} catch (final Exception e) {
throw new AWTError(e.getMessage());
}
}
}
}
}
public boolean containsImbeddedComp(final Component component) {
for (final Object curImbeddedTBR : _embeddedComponents) {
//noinspection unchecked
if (((Collection<Component>) curImbeddedTBR).contains(component)) {
return true;
}
}
return false;
}
/**
* Description:
* (SwingConstants top,left,bottom,right):
* top:1, left:2, bottom:3, right:4
*
* @param component
* @param inx
* @return
*/
public boolean containsEmbeddedComp(final Component component, final int inx) {
//noinspection unchecked
return inx > 0 && inx < 5 && ((Collection<Component>) _embeddedComponents[inx + 1]).contains(component);
}
}