/* * Copyright (c) Henrik Niehaus * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the project (Lazy Bones) nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package lazybones.gui.components.timeline; import static lazybones.gui.components.timeline.Timeline.PADDING; import static lazybones.gui.components.timeline.Timeline.ROW_HEIGHT; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.LayoutManager2; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.Map; import lazybones.LazyBones; import lazybones.LazyBonesTimer; public class TimelineLayout implements LayoutManager2 { private final ArrayList<Component> components = new ArrayList<Component>(); @Override public void addLayoutComponent(Component comp, Object constraints) { components.add(comp); } @Override public float getLayoutAlignmentX(Container target) { return 0; } @Override public float getLayoutAlignmentY(Container target) { return 0; } @Override public void invalidateLayout(Container target) { } @Override public Dimension maximumLayoutSize(Container target) { return target.getMaximumSize(); } @Override public void addLayoutComponent(String name, Component comp) { components.add(comp); } @Override public void layoutContainer(Container parent) { if (parent.isValid()) { return; } int startHour = Integer.parseInt(LazyBones.getProperties().getProperty("timelineStartHour")); int width = parent instanceof TimelineRowHeader ? 0 : parent.getParent().getWidth(); int height = parent.getHeight(); double pixelsPerMinute = (double) (width - 1) / (double) (24 * 60); int rowCount = 0; Map<Integer, Integer> channelRowMap = new HashMap<Integer, Integer>(); for (Component comp : components) { if (comp instanceof TimelineElement) { TimelineElement te = (TimelineElement) comp; LazyBonesTimer timer = te.getTimer(); int startPos = calculateStartPosition(pixelsPerMinute, timer); int endPos = calculateEndPosition(pixelsPerMinute, timer); Calendar currentDate = te.getCurrentDate(); Calendar selectedDayAtStartHour = (Calendar) currentDate.clone(); selectedDayAtStartHour.set(Calendar.HOUR_OF_DAY, startHour); Calendar dayAfterAtStartHour = (Calendar) selectedDayAtStartHour.clone(); dayAfterAtStartHour.add(Calendar.DAY_OF_MONTH, 1); if (timer.getStartTime().before(selectedDayAtStartHour)) { startPos = 0; } if (timer.getEndTime().after(dayAfterAtStartHour)) { endPos = width; } int length = endPos - startPos; Integer channelRow = channelRowMap.get(timer.getChannelNumber()); int row = rowCount; if (channelRow == null) { channelRowMap.put(timer.getChannelNumber(), rowCount); rowCount++; } else { row = channelRow.intValue(); } te.setLocation(startPos, (ROW_HEIGHT + PADDING) * row); te.setSize(length, ROW_HEIGHT); } else if (comp instanceof TimelineRowHeaderElement) { comp.setSize(comp.getPreferredSize()); comp.setSize(comp.getWidth() + 16, ROW_HEIGHT); comp.setLocation(8, (ROW_HEIGHT + PADDING) * rowCount); rowCount++; if (comp.getWidth() > width) { width = comp.getWidth(); } } } if (components.size() == 0 && parent instanceof TimelineRowHeader) { width = 0; } parent.setPreferredSize(new Dimension(width, height)); parent.setSize(width, height); } private int calculateEndPosition(double pixelsPerMinute, LazyBonesTimer timer) { int startHour = Integer.parseInt(LazyBones.getProperties().getProperty("timelineStartHour")); int minute = timer.getEndTime().get(Calendar.MINUTE); int hour = timer.getEndTime().get(Calendar.HOUR_OF_DAY); if (hour >= startHour) { hour -= startHour; } else { hour += (24 - startHour); } int minuteOfDay = hour * 60 + minute; int endPos = (int) (minuteOfDay * pixelsPerMinute); return endPos; } private int calculateStartPosition(double pixelsPerMinute, LazyBonesTimer timer) { int startHour = Integer.parseInt(LazyBones.getProperties().getProperty("timelineStartHour")); int minute = timer.getStartTime().get(Calendar.MINUTE); int hour = timer.getStartTime().get(Calendar.HOUR_OF_DAY); if (hour >= startHour) { hour -= startHour; } else { hour += (24 - startHour); } int minuteOfDay = hour * 60 + minute; int startPos = (int) (minuteOfDay * pixelsPerMinute); return startPos; } @Override public Dimension minimumLayoutSize(Container parent) { Dimension d = new Dimension(); d.width = parent.getWidth(); d.height = 0; for (Component comp : components) { if (comp.getWidth() > d.width) { d.width = comp.getWidth(); } d.height += ROW_HEIGHT + PADDING; } return d; } @Override public Dimension preferredLayoutSize(Container parent) { Dimension d = new Dimension(); d.width = parent.getWidth(); d.height = 0; for (Component comp : components) { if (comp.getWidth() > d.width) { d.width = comp.getWidth(); } d.height += ROW_HEIGHT + PADDING; } return d; } @Override public void removeLayoutComponent(Component comp) { components.remove(comp); } }