/*
GanttProject is an opensource project management tool.
Copyright (C) 2004-2011 GanttProject Team
This program 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.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.sourceforge.ganttproject.gui.zoom;
import java.util.ArrayList;
import java.util.List;
import biz.ganttproject.core.time.TimeUnitPair;
import biz.ganttproject.core.time.TimeUnitStack;
/**
* @author bard
*/
public class ZoomManager {
public static class ZoomState {
private final TimeUnitPair myTimeUnitPair;
private final int myBottomUnitWidth;
private final int myStateNumber;
ZoomState(TimeUnitPair timeUnitPair, int bottomUnitWidth, int stateNumber) {
myTimeUnitPair = timeUnitPair;
myBottomUnitWidth = bottomUnitWidth;
myStateNumber = stateNumber;
}
public ZoomState(TimeUnitPair timeUnitPair, int stateNumber) {
this(timeUnitPair, timeUnitPair.getDefaultUnitWidth(), stateNumber);
}
public String getPersistentName() {
return myTimeUnitPair.getTimeUnitStack().getName() + ":" + myStateNumber;
}
public TimeUnitPair getTimeUnitPair() {
return myTimeUnitPair;
}
public int getBottomUnitWidth() {
return myBottomUnitWidth;
}
public int getValue() {
return myStateNumber;
}
}
/** Number representing the selected ZoomState */
private int myZooming = 2;
private List<ZoomListener> myListeners = new ArrayList<ZoomListener>();
/**
* List with available ZoomStates, is expanded when even more ZoomStates are
* required
*/
private ArrayList<ZoomState> myZoomStates;
/** Zoom step for next ZoomState which need to be calculated/extrapolated */
private final float myZoomStep = 0.75f;
/** If this value is false the maximum ZoomState is not reached */
private boolean myMaximumZoomStateReached = false;
public ZoomManager(TimeUnitStack timeUnitStack) {
TimeUnitPair[] unitPairs = timeUnitStack.getTimeUnitPairs();
myZoomStates = new ArrayList<ZoomState>(unitPairs.length);
for (int i = 0; i < unitPairs.length; i++) {
myZoomStates.add(new ZoomManager.ZoomState(unitPairs[i], i));
}
}
public boolean canZoomIn() {
return myZooming > 0;
}
public boolean canZoomOut() {
return myZooming < myZoomStates.size() - 1 || myMaximumZoomStateReached == false;
}
public void zoomIn() {
int oldValue = myZooming--;
fireZoomingChanged(oldValue, myZooming);
}
public void zoomOut() {
int oldValue = myZooming++;
fireZoomingChanged(oldValue, myZooming);
}
public void addZoomListener(ZoomListener listener) {
myListeners.add(listener);
listener.zoomChanged(new ZoomEvent(this, getZoomState()));
}
public void removeZoomListener(ZoomListener listener) {
myListeners.remove(listener);
}
private void fireZoomingChanged(int oldZoomValue, int newZoomValue) {
ZoomEvent e = new ZoomEvent(this, getZoomState());
for (int i = 0; i < myListeners.size(); i++) {
ZoomListener nextListener = myListeners.get(i);
nextListener.zoomChanged(e);
}
}
/**
* Find persistentName in the available ZoomStates or add new States until it
* is found. Or the maximum allowed ZoomState is reached, in this case the
* ZoomState is not changed.
*
* @param persistentName
* is the ZoomState name to find
*/
public void setZoomState(String persistentName) {
for (int i = 0; i < myZoomStates.size() || myMaximumZoomStateReached == false; i++) {
if (getZoomState(i).getPersistentName().equals(persistentName)) {
myZooming = i;
fireZoomingChanged(0, myZooming);
break;
}
}
}
/** @return the selected ZoomState */
public ZoomState getZoomState() {
return getZoomState(myZooming);
}
public ZoomState getZoomState(int zoom) {
while (zoom >= myZoomStates.size()) {
// Zoom out even further by calculating the required ZoomState
// The list of ZoomState is filled step by step until the desired
// ZoomState is added (normally just the next step needs to be calculated)
ZoomState lastZoomState = myZoomStates.get(myZoomStates.size() - 1);
int bottomUnitWidth = (int) (lastZoomState.getBottomUnitWidth() * myZoomStep);
if (bottomUnitWidth < 2) {
// A bottomUnitWidth of 1 is the maximum allowed zoom,
// since a width of 0 is not possible (and breaking stuff).
myMaximumZoomStateReached = true;
}
myZoomStates.add(new ZoomState(lastZoomState.getTimeUnitPair(), bottomUnitWidth, zoom));
}
return myZoomStates.get(zoom);
}
}