/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy 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. * * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.gui.main; import icy.gui.frame.progress.ProgressFrame; import icy.gui.frame.progress.TaskFrame; import icy.main.Icy; import icy.system.thread.ThreadUtil; import java.awt.Dimension; import java.awt.Point; import java.util.ArrayList; import java.util.List; /** * Manage the TaskFrame to display them on right of the window. * * @author Fabrice de Chaumont & Stephane Dallongeville */ public class TaskFrameManager implements Runnable { private static Dimension getDesktopSize() { final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); if (mainFrame != null) // get bottom right border location return mainFrame.getDesktopSize(); return null; } private static class TaskFrameInfo { final TaskFrame frame; Point position; long showDelay; long hideDelay; boolean visible; public TaskFrameInfo(TaskFrame frame, Point position, long showDelay, long hideDelay) { super(); this.frame = frame; this.position = position; this.showDelay = showDelay; this.hideDelay = hideDelay; visible = false; } public boolean canHide() { return hideDelay < 0; } public boolean canShow() { return showDelay < 0; } } final Thread animThread; List<TaskFrameInfo> taskFrameInfos; long lastUpdateTime; /** * */ public TaskFrameManager() { super(); taskFrameInfos = new ArrayList<TaskFrameInfo>(); animThread = new Thread(this, "TaskFrame manager"); lastUpdateTime = System.currentTimeMillis(); } // we have to separate init as thread call the getMainInterface() method public void init() { animThread.start(); } public void addTaskWindow(final TaskFrame tFrame, final long showDelay, final long hideDelay) { final Dimension desktopSize = getDesktopSize(); if ((desktopSize != null) && !tFrame.canRemove()) { // get bottom right border location final Point pos = new Point(desktopSize.width + 10, desktopSize.height); final TaskFrameInfo frameInfo = new TaskFrameInfo(tFrame, pos, showDelay, hideDelay); synchronized (taskFrameInfos) { taskFrameInfos.add(frameInfo); } } } public void addTaskWindow(final TaskFrame tFrame) { // we use a different default value for progress frame if (tFrame instanceof ProgressFrame) addTaskWindow(tFrame, 0L, 1000L); else addTaskWindow(tFrame, 0L, 0L); } @Override public void run() { while (true) { long currentTime = System.currentTimeMillis(); long deltaTime = currentTime - lastUpdateTime; lastUpdateTime = currentTime; animateFrames(deltaTime); // sleep a bit ThreadUtil.sleep(20); } } void animateFrames(long delta) { // get bottom right border location final Dimension desktopSize = getDesktopSize(); // not yet initialized if (desktopSize == null) return; List<TaskFrameInfo> list; // create temporary copy of the frame list synchronized (taskFrameInfos) { list = new ArrayList<TaskFrameInfo>(taskFrameInfos); } // process frames which will be closed for (int i = list.size() - 1; i >= 0; i--) { final TaskFrameInfo info = list.get(i); final TaskFrame frame = info.frame; info.showDelay -= delta; // close order if (frame.canRemove()) info.hideDelay -= delta; // frame need to be removed ? if (info.canHide()) { // frame hidden ? if (!info.visible || ((info.position.x >= desktopSize.width))) { // remove it from list list.remove(i); // and close it definitely frame.internalClose(); } } } // calculate top Y position float currentY = desktopSize.height; int ind; for (ind = list.size() - 1; ind >= 0; ind--) { final TaskFrameInfo info = list.get(ind); if (info.canShow()) { final int h = info.frame.getHeight(); currentY -= h; // outside screen --> interrupt if (currentY < 0) { currentY += h; break; } } } // need to remove frame outside screen if (ind != -1) { for (int i = 0; i <= ind; i++) { final TaskFrameInfo info = list.get(i); // close the frame definitely info.frame.internalClose(); } // remove frames from list list = new ArrayList<TaskFrameInfo>(list.subList(ind + 1, list.size())); } // calculate and update all frames position for (TaskFrameInfo info : list) { final TaskFrame frame = info.frame; if (info.canShow()) { int targetX; // find X target position if (info.canHide()) targetX = desktopSize.width + 20; else targetX = desktopSize.width - frame.getWidth(); final Point targetPos = new Point(targetX, (int) currentY); final Point curPos = info.position; float vectX = (targetPos.x - curPos.x) / 10f; if (vectX != 0f) { // we want at least 1 or -1 if (Math.abs(vectX) < 1f) { if (vectX < 0) vectX = -1f; else vectX = 1f; } } float vectY = (targetPos.y - curPos.y) / 10f; if (vectY != 0f) { // we want at least 1 or -1 if (Math.abs(vectY) < 1f) { if (vectY < 0) vectY = -1f; else vectY = 1f; } } // define new position final Point newPos = new Point((int) (curPos.x + vectX), (int) (curPos.y + vectY)); // set Y when starting the scroll if (curPos.x > desktopSize.width) newPos.y = targetPos.y; // update position info.position = newPos; // avoid repaint on JDesktopPane if position did not changed if (frame.isInternalized()) { if (!frame.getLocationInternal().equals(newPos)) frame.setLocationInternal(newPos); } else { if (!frame.getLocationExternal().equals(newPos)) frame.setLocationExternal(newPos); } // frame need to be displayed now ? if (info.canShow() && !info.visible) { // do set visible before adding to desktop pane so the frame does not take focus frame.setVisible(true); frame.addToDesktopPane(); frame.toFront(); info.visible = true; } currentY += frame.getHeight(); } } // update global list taskFrameInfos = list; } }