001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.main; 020 021import icy.gui.frame.progress.ProgressFrame; 022import icy.gui.frame.progress.TaskFrame; 023import icy.main.Icy; 024import icy.system.thread.ThreadUtil; 025 026import java.awt.Dimension; 027import java.awt.Point; 028import java.util.ArrayList; 029import java.util.List; 030 031/** 032 * Manage the TaskFrame to display them on right of the window. 033 * 034 * @author Fabrice de Chaumont & Stephane Dallongeville 035 */ 036public class TaskFrameManager implements Runnable 037{ 038 private static Dimension getDesktopSize() 039 { 040 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 041 042 if (mainFrame != null) 043 // get bottom right border location 044 return mainFrame.getDesktopSize(); 045 046 return null; 047 } 048 049 private static class TaskFrameInfo 050 { 051 final TaskFrame frame; 052 Point position; 053 long showDelay; 054 long hideDelay; 055 boolean visible; 056 057 public TaskFrameInfo(TaskFrame frame, Point position, long showDelay, long hideDelay) 058 { 059 super(); 060 061 this.frame = frame; 062 this.position = position; 063 this.showDelay = showDelay; 064 this.hideDelay = hideDelay; 065 visible = false; 066 } 067 068 public boolean canHide() 069 { 070 return hideDelay < 0; 071 } 072 073 public boolean canShow() 074 { 075 return showDelay < 0; 076 } 077 } 078 079 final Thread animThread; 080 List<TaskFrameInfo> taskFrameInfos; 081 long lastUpdateTime; 082 083 /** 084 * 085 */ 086 public TaskFrameManager() 087 { 088 super(); 089 090 taskFrameInfos = new ArrayList<TaskFrameInfo>(); 091 animThread = new Thread(this, "TaskFrame manager"); 092 lastUpdateTime = System.currentTimeMillis(); 093 } 094 095 // we have to separate init as thread call the getMainInterface() method 096 public void init() 097 { 098 animThread.start(); 099 } 100 101 public void addTaskWindow(final TaskFrame tFrame, final long showDelay, final long hideDelay) 102 { 103 final Dimension desktopSize = getDesktopSize(); 104 105 if ((desktopSize != null) && !tFrame.canRemove()) 106 { 107 // get bottom right border location 108 final Point pos = new Point(desktopSize.width + 10, desktopSize.height); 109 final TaskFrameInfo frameInfo = new TaskFrameInfo(tFrame, pos, showDelay, hideDelay); 110 111 synchronized (taskFrameInfos) 112 { 113 taskFrameInfos.add(frameInfo); 114 } 115 } 116 } 117 118 public void addTaskWindow(final TaskFrame tFrame) 119 { 120 // we use a different default value for progress frame 121 if (tFrame instanceof ProgressFrame) 122 addTaskWindow(tFrame, 0L, 1000L); 123 else 124 addTaskWindow(tFrame, 0L, 0L); 125 } 126 127 @Override 128 public void run() 129 { 130 while (true) 131 { 132 long currentTime = System.currentTimeMillis(); 133 long deltaTime = currentTime - lastUpdateTime; 134 lastUpdateTime = currentTime; 135 136 animateFrames(deltaTime); 137 138 // sleep a bit 139 ThreadUtil.sleep(20); 140 } 141 } 142 143 void animateFrames(long delta) 144 { 145 // get bottom right border location 146 final Dimension desktopSize = getDesktopSize(); 147 // not yet initialized 148 if (desktopSize == null) 149 return; 150 151 List<TaskFrameInfo> list; 152 153 // create temporary copy of the frame list 154 synchronized (taskFrameInfos) 155 { 156 list = new ArrayList<TaskFrameInfo>(taskFrameInfos); 157 } 158 159 // process frames which will be closed 160 for (int i = list.size() - 1; i >= 0; i--) 161 { 162 final TaskFrameInfo info = list.get(i); 163 final TaskFrame frame = info.frame; 164 165 info.showDelay -= delta; 166 // close order 167 if (frame.canRemove()) 168 info.hideDelay -= delta; 169 170 // frame need to be removed ? 171 if (info.canHide()) 172 { 173 // frame hidden ? 174 if (!info.visible || ((info.position.x >= desktopSize.width))) 175 { 176 // remove it from list 177 list.remove(i); 178 // and close it definitely 179 frame.internalClose(); 180 } 181 } 182 } 183 184 // calculate top Y position 185 float currentY = desktopSize.height; 186 int ind; 187 for (ind = list.size() - 1; ind >= 0; ind--) 188 { 189 final TaskFrameInfo info = list.get(ind); 190 191 if (info.canShow()) 192 { 193 final int h = info.frame.getHeight(); 194 195 currentY -= h; 196 // outside screen --> interrupt 197 if (currentY < 0) 198 { 199 currentY += h; 200 break; 201 } 202 } 203 } 204 205 // need to remove frame outside screen 206 if (ind != -1) 207 { 208 for (int i = 0; i <= ind; i++) 209 { 210 final TaskFrameInfo info = list.get(i); 211 // close the frame definitely 212 info.frame.internalClose(); 213 } 214 215 // remove frames from list 216 list = new ArrayList<TaskFrameInfo>(list.subList(ind + 1, list.size())); 217 } 218 219 // calculate and update all frames position 220 for (TaskFrameInfo info : list) 221 { 222 final TaskFrame frame = info.frame; 223 224 if (info.canShow()) 225 { 226 int targetX; 227 228 // find X target position 229 if (info.canHide()) 230 targetX = desktopSize.width + 20; 231 else 232 targetX = desktopSize.width - frame.getWidth(); 233 234 final Point targetPos = new Point(targetX, (int) currentY); 235 final Point curPos = info.position; 236 237 float vectX = (targetPos.x - curPos.x) / 10f; 238 if (vectX != 0f) 239 { 240 // we want at least 1 or -1 241 if (Math.abs(vectX) < 1f) 242 { 243 if (vectX < 0) 244 vectX = -1f; 245 else 246 vectX = 1f; 247 } 248 } 249 float vectY = (targetPos.y - curPos.y) / 10f; 250 if (vectY != 0f) 251 { 252 // we want at least 1 or -1 253 if (Math.abs(vectY) < 1f) 254 { 255 if (vectY < 0) 256 vectY = -1f; 257 else 258 vectY = 1f; 259 } 260 } 261 262 // define new position 263 final Point newPos = new Point((int) (curPos.x + vectX), (int) (curPos.y + vectY)); 264 265 // set Y when starting the scroll 266 if (curPos.x > desktopSize.width) 267 newPos.y = targetPos.y; 268 269 // update position 270 info.position = newPos; 271 272 // avoid repaint on JDesktopPane if position did not changed 273 if (frame.isInternalized()) 274 { 275 if (!frame.getLocationInternal().equals(newPos)) 276 frame.setLocationInternal(newPos); 277 } 278 else 279 { 280 if (!frame.getLocationExternal().equals(newPos)) 281 frame.setLocationExternal(newPos); 282 } 283 284 // frame need to be displayed now ? 285 if (info.canShow() && !info.visible) 286 { 287 // do set visible before adding to desktop pane so the frame does not take focus 288 frame.setVisible(true); 289 frame.addToDesktopPane(); 290 frame.toFront(); 291 info.visible = true; 292 } 293 294 currentY += frame.getHeight(); 295 } 296 } 297 298 // update global list 299 taskFrameInfos = list; 300 } 301}