/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.util.toolbar;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Iterator;
import java.util.Vector;
/** An object that encapsulates position and (optionally) size for
* Absolute positioning of components.
*
* Each toolbar constraints (TC) is component of toolbar row(s) and configuration.
* Every TC has cached the nearest neighbournhood, so there is a list of rows for TC is part,
* list of previous and next toolbars.
* So when there is some motion all of those cached attributes are recomputed.
*
* @author Libor Kramolis
*/
public class ToolbarConstraints {
static final long serialVersionUID =3065774641403311880L;
/** Toolbar anchor status. */
static final int LEFT_ANCHOR = -1;
static final int NO_ANCHOR = 0;
/** Toolbar name */
private String name;
/** Toolbar horizontal position */
private int position;
/** Which anchor toolbar use. */
private int anchor; // LEFT_ANCHOR | NO_ANCHOR
/** Is toolbar visible. */
private boolean visible;
/** Toolbar is part of those rows. */
private Vector ownRows; // Vector of ToolbarRows
/** List of previous toolbars. */
private Vector prevBars; // Vector of ToolbarConstraints
/** List of next toolbars. */
private Vector nextBars; // Vector of ToolbarConstraints
/** The nearest end of previous toolbars. */
private int prevEnd; // nejblizsi konec predchozich toolbaru
/** The nearest begin of next toolbars. */
private int nextBeg; // nejblizsi zacatek nasledujicich toolbaru
/** The nearest begin of previous toolbars. */
private int prevBeg; // nejblizsi zacatek predchozich toolbaru
/** The nearest end of next toolbars. */
private int nextEnd; // nejblizsi konec nasledujicich toolbaru
/** Preferred size. */
private Dimension prefSize;
/** Toolbar bounds. */
private Rectangle bounds;
/** Toolbar constraints is part of ToolbarConfiguration. */
private ToolbarPanel toolbarConfig;
/** Number of rows. */
private int rowCount;
/** Width of last toolbar. */
private int prefLastWidth;
/** Last row index. */
private int lastRowIndex;
/** Create new ToolbarConstraints
* @param conf own ToolbarConfiguration
* @param nam name of toolbar
* @param pos wanted position of toolbar
* @param vis visibility of toolbar
*/
ToolbarConstraints (ToolbarPanel conf, String nam, Integer pos, Boolean vis) {
toolbarConfig = conf;
name = nam;
if (pos == null) {
position = 0;
anchor = LEFT_ANCHOR;
} else {
position = pos.intValue();
anchor = NO_ANCHOR;
}
visible = vis.booleanValue();
prefSize = new Dimension ();
rowCount = 0;
prefLastWidth = 0;
bounds = new Rectangle ();
initValues();
}
/** Init neighbourhood values. */
void initValues () {
ownRows = new Vector();
prevBars = new Vector();
nextBars = new Vector();
resetPrev();
resetNext();
}
/** Checks position and visibility of multirow toolbar.
* @param position maybe new position
* @param visible maybe new visibility
*/
void checkNextPosition (Integer position, Boolean visible) {
if (position == null) {
this.position = 0;
this.anchor = LEFT_ANCHOR;
} else {
if (anchor == NO_ANCHOR)
this.position = (this.position + position.intValue()) / 2;
else
this.position = position.intValue();
this.anchor = NO_ANCHOR;
}
this.visible = this.visible || visible.booleanValue();
}
/** @return name of toolbar. */
String getName () {
return name;
}
/** @return anchor of toolbar. */
int getAnchor () {
return anchor;
}
/** Set anchor of toolbar.
* @param anch new toolbar anchor.
*/
void setAnchor (int anch) {
anchor = anch;
}
/** @return toolbar visibility. */
boolean isVisible () {
return visible;
}
/** Set new toolbar visibility.
* @param v new toolbar visibility
*/
void setVisible (boolean v) {
visible = v;
}
/** @return horizontal toolbar position. */
int getPosition () {
return position;
}
/** Set new toolbar position.
* @param pos new toolbar position
*/
void setPosition (int pos) {
position = pos;
}
/** @return toolbar width. */
int getWidth () {
return prefSize.width;
}
/** @return number toolbar rows. */
int getRowCount () {
return rowCount;
}
/** @return toolbar bounds. */
Rectangle getBounds () {
return new Rectangle (bounds);
}
/** Destroy toolbar and it's neighbourhood (row context).
* @return true if after destroy stay some empty row.
*/
boolean destroy () {
lastRowIndex = rowIndex();
rowCount = ownRows.size();
Iterator it = ownRows.iterator();
ToolbarRow row;
boolean emptyRow = false;
while (it.hasNext()) {
row = (ToolbarRow)it.next();
row.removeToolbar (this);
emptyRow = emptyRow || row.isEmpty();
}
initValues();
return emptyRow;
}
/** Add row to owned rows.
* @param row new owned row.
*/
void addOwnRow (ToolbarRow row) {
ownRows.add (row);
}
/** Add toolbar to list of previous toolbars.
* @param prev new previous toolbar
*/
void addPrevBar (ToolbarConstraints prev) {
if (prev == null)
return;
prevBars.add (prev);
}
/** Add toolbar to list of next toolbars.
* @param next new next toolbar
*/
void addNextBar (ToolbarConstraints next) {
if (next == null)
return;
nextBars.add (next);
}
/** Remove toolbar from previous toolbars.
* @param prev toolbar for remove.
*/
void removePrevBar (ToolbarConstraints prev) {
if (prev == null)
return;
prevBars.remove (prev);
}
/** Remove toolbar from next toolbars.
* @param next toolbar for remove.
*/
void removeNextBar (ToolbarConstraints next) {
if (next == null)
return;
nextBars.remove (next);
}
/** Set preferred size of toolbar. There is important recompute toolbar neighbourhood.
* @param size preferred size
*/
void setPreferredSize (Dimension size) {
prefSize = size;
rowCount = Toolbar.rowCount (prefSize.height);
if (ownRows.isEmpty())
return;
ToolbarRow row;
if (visible) {
boolean emptyRow = false;
while (rowCount < ownRows.size()) {
row = (ToolbarRow)ownRows.lastElement();
row.removeToolbar (this);
ownRows.remove (row);
emptyRow = emptyRow || row.isEmpty();
}
if (emptyRow)
toolbarConfig.checkToolbarRows();
while (rowCount > ownRows.size()) {
row = (ToolbarRow)ownRows.lastElement();
ToolbarRow nR = row.getNextRow();
if (nR == null)
nR = toolbarConfig.createLastRow();
nR.addToolbar (this, position);
}
}
updatePosition();
}
/** @return index of first toolbar row. */
int rowIndex () {
if (!visible)
return toolbarConfig.getRowCount();
if (ownRows.isEmpty())
return lastRowIndex;
return toolbarConfig.rowIndex (((ToolbarRow)ownRows.firstElement()));
}
/** @return true if toolbar is alone at row(s). */
boolean isAlone () {
Iterator it = ownRows.iterator();
ToolbarRow row;
while (it.hasNext()) {
row = (ToolbarRow)it.next();
if (row.toolbarCount() != 1)
return false;
}
return true;
}
/** Update preferred size of toolbar.
* @param size new preferred size
*/
void updatePreferredSize (Dimension size) {
if (!prefSize.equals (size)) {
setPreferredSize (size);
}
}
/** Update toolbar bounds. */
void updateBounds () {
int rI = rowIndex();
int rC = getRowCount();
bounds = new Rectangle (position,
((Toolbar.BASIC_HEIGHT + ToolbarLayout.VGAP) * rI) + ToolbarLayout.VGAP,
nextBeg - position - ToolbarLayout.HGAP,
(Toolbar.BASIC_HEIGHT * rC) + ((rC - 1) * ToolbarLayout.VGAP));
}
/** Update toolbar position and it's neighbourhood. */
void updatePosition () {
updatePrev();
if (anchor == NO_ANCHOR) {
if (position < (prevEnd + ToolbarLayout.HGAP)) {
position = prevEnd + ToolbarLayout.HGAP;
anchor = LEFT_ANCHOR;
}
} else {
position = prevEnd + ToolbarLayout.HGAP;
}
updatePrevBars();
updateNextBars();
updateBounds();
updatePrefWidth();
}
/** Update positions of previous toolbars. */
void updatePrevPosition () {
Iterator it = prevBars.iterator();
ToolbarConstraints tc;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
tc.updatePosition();
}
}
/** Update next position of previous toolbars. */
void updatePrevBars () {
Iterator it = prevBars.iterator();
ToolbarConstraints tc;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
tc.updateNext();
}
}
/** Update previous position of next toolbars. */
void updateNextBars () {
Iterator it = nextBars.iterator();
ToolbarConstraints tc;
if (!it.hasNext()) {
resetNext();
updatePrefWidth();
}
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
tc.updatePosition();
}
}
/** Update width of prevoius toolbars. */
void updatePrefWidth () {
if (nextBars.size() == 0) {
prefLastWidth = getPosition() + getWidth() + ToolbarLayout.HGAP;
toolbarConfig.updatePrefWidth();
}
}
/** @return preferred toolbar width. */
int getPrefWidth () {
return prefLastWidth;
}
/** Update values about next toolbars. */
void updateNext () {
resetNext();
Iterator it = nextBars.iterator();
ToolbarConstraints tc;
int nextPos;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
nextBeg = Math.min (nextBeg, nextPos = tc.getPosition());
nextEnd = Math.min (nextEnd, nextPos + tc.getWidth());
}
updateBounds();
}
/** Update values about previous toolbars. */
void updatePrev () {
resetPrev();
Iterator it = prevBars.iterator();
ToolbarConstraints tc;
int prevPos;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
prevBeg = Math.max (prevBeg, prevPos = tc.getPosition());
prevEnd = Math.max (prevEnd, prevPos + tc.getWidth());
}
}
/** Reset values about previous toolbars. */
void resetPrev () {
prevBeg = 0;
prevEnd = 0;
}
/** Reset values about next toolbars. */
void resetNext () {
nextBeg = Integer.MAX_VALUE;
nextEnd = Integer.MAX_VALUE;
}
/** Move toolbar left if it's possible.
* @param dx horizontal distance
*/
void moveLeft (int dx) {
int wantX = position - dx;
position = wantX;
anchor = NO_ANCHOR;
if (wantX > prevEnd) { // no problem to move left
setAnchorTo (NO_ANCHOR, nextBars);
} else {
if (canSwitchLeft (getPosition(), getWidth(), prevBeg, prevEnd - prevBeg)) { // can switch left ?
switchToolbarLeft ();
}
}
}
/** Move toolbar right if it's possible.
* @param dx horizontal distance
*/
void moveRight (int dx) {
int wantX = position + dx;
int wantXpWidth = wantX + getWidth(); // wantX plus width
if (wantXpWidth < nextBeg) { // no problem to move right
anchor = NO_ANCHOR;
position = wantX;
} else {
if (canSwitchRight (wantX, getWidth(), nextBeg, nextEnd - nextBeg)) { // can switch right ?
position = wantX;
anchor = NO_ANCHOR;
switchToolbarRight ();
} else {
position = nextBeg - getWidth() - ToolbarLayout.HGAP;
anchor = NO_ANCHOR;
}
}
updatePrevPosition();
}
/** Move toolbar left with all followers. */
void moveLeft2End (int dx) {
int wantX = position - dx;
anchor = NO_ANCHOR;
if (wantX < (prevEnd + ToolbarLayout.HGAP)) {
wantX = prevEnd + ToolbarLayout.HGAP;
}
move2End (wantX - position);
}
/** Move toolbar right with all followers. */
void moveRight2End (int dx) {
move2End (dx);
}
/** Move toolbar horizontal with all followers. */
void move2End (int dx) {
position += dx;
Iterator it = nextBars.iterator();
ToolbarConstraints tc;
int nextPos;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
tc.move2End (dx);
}
}
/** Set anchor to list of toolbars.
* @param anch type of anchor
* @param bars list of toolbars
*/
void setAnchorTo (int anch, Vector bars) {
Iterator it = bars.iterator();
ToolbarConstraints tc;
while (it.hasNext()) {
tc = (ToolbarConstraints)it.next();
tc.setAnchor (anch);
}
}
/** Switch toolbar left if it's possible. */
void switchToolbarLeft () {
Iterator it = ownRows.iterator();
ToolbarRow row;
while (it.hasNext()) {
row = (ToolbarRow)it.next();
row.trySwitchLeft (this);
}
}
/** Switch toolbar right if it's possible. */
void switchToolbarRight () {
Iterator it = ownRows.iterator();
ToolbarRow row;
while (it.hasNext()) {
row = (ToolbarRow)it.next();
row.trySwitchRight (this);
}
}
/** Can switch toolbar left?
* @param p1 toolbar1 position
* @param w1 toolbar1 width
* @param p2 toolbar2 position
* @param w2 toolbar2 width
* @return true if possible switch toolbar left.
*/
static boolean canSwitchLeft (int p1, int w1, int p2, int w2) {
return (p1 < (p2));
}
/** Can switch toolbar right?
* @param p1 toolbar1 position
* @param w1 toolbar1 width
* @param p2 toolbar2 position
* @param w2 toolbar2 width
* @return true if possible switch toolbar right.
*/
static boolean canSwitchRight (int p1, int w1, int p2, int w2) {
return (p1 > (p2));
}
} // end of class ToolbarConstraints