/*
GanttProject is an opensource project management tool.
Copyright (C) 2004-2011 Dmitry Barashev, 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 biz.ganttproject.core.chart.grid;
/**
* Holds offset lists and provides a unified way to reset them all at once and
* to rebuild them again.
*
* @author dbarashev (Dmitry Barashev)
*/
public class OffsetManager {
public static interface OffsetBuilderFactory {
OffsetBuilder createTopAndBottomUnitBuilder();
OffsetBuilder createAtomUnitBuilder();
}
private final OffsetList myTopUnitOffsets = new OffsetList();
private final OffsetList myBottomUnitOffsets = new OffsetList();
private final OffsetList myDefaultUnitOffsets = new OffsetList();
private final OffsetBuilderFactory myFactory;
private boolean isReset = true;
public OffsetManager(OffsetBuilderFactory factory) {
myFactory = factory;
}
public void reset() {
isReset = true;
}
public void constructOffsets() {
myTopUnitOffsets.clear();
myBottomUnitOffsets.clear();
myDefaultUnitOffsets.clear();
myFactory.createTopAndBottomUnitBuilder().constructOffsets(myTopUnitOffsets, myBottomUnitOffsets);
// this is a hack which prevents an eternal loop of calling
// constructOffsets.
// The matter is that atom unit builder calls getEndDate() which in turn
// calls
// constructOffsets()
isReset = false;
myFactory.createAtomUnitBuilder().constructOffsets(null, myDefaultUnitOffsets);
alignOffsets(myBottomUnitOffsets);
alignOffsets(myTopUnitOffsets);
}
/**
* It is possible that different lists get misaligned with respect to the atom unit offsets.
* For instance, it may happen when chart start date is not on the unit boundary (e.g. bottom unit is MONTH and chart starts
* somewhere in the middle of a month). We do additional alignment to make sure that offsets which end on the same
* date have the same pixel offset.
*/
private void alignOffsets(OffsetList offsets) {
Offset firstVisibleOffset = null;
for (Offset o : offsets) {
if (o.getOffsetPixels() > 0) {
firstVisibleOffset = o;
break;
}
}
if (firstVisibleOffset == null) {
return;
}
OffsetLookup lookup = new OffsetLookup();
int alignedDefaultOffsetIdx = lookup.lookupOffsetByEndDate(firstVisibleOffset.getOffsetEnd(), myDefaultUnitOffsets);
if (alignedDefaultOffsetIdx >= 0) {
Offset alignedAtomicOffset = myDefaultUnitOffsets.get(alignedDefaultOffsetIdx);
int diff = (alignedAtomicOffset.getOffsetPixels() - firstVisibleOffset.getOffsetPixels());
if (diff == 0) {
return;
}
offsets.shift(diff);
}
}
public OffsetList getTopUnitOffsets() {
if (isReset) {
constructOffsets();
}
return myTopUnitOffsets;
}
public OffsetList getBottomUnitOffsets() {
if (isReset) {
constructOffsets();
}
return myBottomUnitOffsets;
}
public OffsetList getAtomUnitOffsets() {
if (isReset) {
constructOffsets();
}
return myDefaultUnitOffsets;
}
}