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.component; 020 021import icy.common.listener.weak.WeakListener; 022import icy.gui.frame.IcyFrame; 023import icy.gui.frame.IcyFrameAdapter; 024import icy.gui.frame.IcyFrameEvent; 025import icy.gui.util.WindowPositionSaver; 026import icy.main.Icy; 027import icy.util.StringUtil; 028 029import java.awt.BorderLayout; 030import java.awt.Container; 031import java.awt.Dimension; 032import java.awt.HeadlessException; 033import java.awt.Point; 034import java.util.EventListener; 035 036import javax.swing.JPanel; 037import javax.swing.WindowConstants; 038 039/** 040 * Externalizable panel component.<br> 041 * Basically this is a JPanel you can externalize and display in an IcyFrame.<br> 042 * 043 * @author Stephane 044 */ 045public class ExternalizablePanel extends JPanel 046{ 047 public static class WeakStateListener extends WeakListener<StateListener> implements StateListener 048 { 049 public WeakStateListener(StateListener listener) 050 { 051 super(listener); 052 } 053 054 @Override 055 public void removeListener(Object source) 056 { 057 if (source != null) 058 ((ExternalizablePanel) source).removeStateListener(this); 059 } 060 061 @Override 062 public void stateChanged(ExternalizablePanel source, boolean externalized) 063 { 064 final StateListener listener = getListener(source); 065 066 if (listener != null) 067 listener.stateChanged(source, externalized); 068 } 069 } 070 071 public static interface StateListener extends EventListener 072 { 073 public void stateChanged(ExternalizablePanel source, boolean externalized); 074 } 075 076 public class Frame extends IcyFrame 077 { 078 public Frame(String title) throws HeadlessException 079 { 080 super(title, true, true, true, true); 081 082 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 083 084 addFrameListener(new IcyFrameAdapter() 085 { 086 @Override 087 public void icyFrameClosing(IcyFrameEvent e) 088 { 089 super.icyFrameClosing(e); 090 091 // ignore the event when frame is manually closed or application is exiting 092 if (!(closed || Icy.isExiting())) 093 { 094 if (ExternalizablePanel.this.isExternalized()) 095 ExternalizablePanel.this.internalizeInternal(); 096 } 097 } 098 }); 099 100 setLayout(new BorderLayout()); 101 setSize(400, 400); 102 } 103 } 104 105 /** 106 * 107 */ 108 private static final long serialVersionUID = -7690543443681714719L; 109 110 /** 111 * extern frame 112 */ 113 protected final Frame frame; 114 /** 115 * parent component 116 */ 117 private Container parent; 118 119 /** 120 * internals 121 */ 122 private boolean internalizationAutorized; 123 private boolean externalizationAutorized; 124 boolean closed; 125 126 // we need to keep reference on it as the object only use weak reference 127 final WindowPositionSaver positionSaver; 128 129 /** 130 * Create a new externalizable panel. 131 * 132 * @param title 133 * title for the associated frame. 134 * @param key 135 * save key, used for WindowPositionSaver.<br> 136 * Set to null or empty string disable parameter saving. 137 * @param defLoc 138 * the default location for the frame (externalized state) 139 * @param defDim 140 * the default dimension for the frame (externalized state) 141 */ 142 public ExternalizablePanel(String title, String key, Point defLoc, Dimension defDim) 143 { 144 super(); 145 146 frame = new Frame(title); 147 parent = null; 148 internalizationAutorized = true; 149 externalizationAutorized = true; 150 closed = false; 151 152 // use window position saver with default parameters 153 if (!StringUtil.isEmpty(key)) 154 positionSaver = new WindowPositionSaver(this, "frame/" + key, defLoc, defDim); 155 else 156 positionSaver = null; 157 } 158 159 /** 160 * Create a new externalizable panel. 161 * 162 * @param title 163 * title for the associated frame. 164 * @param key 165 * save key, used for WindowPositionSaver.<br> 166 * Set to null or empty string disable parameter saving. 167 */ 168 public ExternalizablePanel(String title, String key) 169 { 170 // default location and dimension for extern frame 171 this(title, key, new Point(200, 200), new Dimension(400, 300)); 172 } 173 174 public ExternalizablePanel(String title) 175 { 176 this(title, null); 177 } 178 179 public ExternalizablePanel() 180 { 181 this("", null); 182 } 183 184 @Override 185 public void addNotify() 186 { 187 super.addNotify(); 188 189 // set parent on first attachment 190 if (parent == null) 191 { 192 final Container p = getParent(); 193 194 if ((p != frame.getInternalFrame().getContentPane()) && (p != frame.getExternalFrame().getContentPane())) 195 parent = p; 196 } 197 } 198 199 /** 200 * Close the panel (close and release associated frames and resources). 201 */ 202 public void close() 203 { 204 closed = true; 205 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 206 frame.close(); 207 } 208 209 /** 210 * Manual parent set 211 */ 212 public void setParent(Container value) 213 { 214 parent = value; 215 } 216 217 /** 218 * @return the internalizationAutorized 219 */ 220 public boolean isInternalizationAutorized() 221 { 222 return internalizationAutorized; 223 } 224 225 /** 226 * @param internalizationAutorized 227 * the internalizationAutorized to set 228 */ 229 public void setInternalizationAutorized(boolean internalizationAutorized) 230 { 231 this.internalizationAutorized = internalizationAutorized; 232 } 233 234 /** 235 * @return the externalizationAutorized 236 */ 237 public boolean isExternalizationAutorized() 238 { 239 return externalizationAutorized; 240 } 241 242 /** 243 * @param externalizationAutorized 244 * the externalizationAutorized to set 245 */ 246 public void setExternalizationAutorized(boolean externalizationAutorized) 247 { 248 this.externalizationAutorized = externalizationAutorized; 249 } 250 251 /** 252 * Externalize panel in an independent frame 253 */ 254 public void externalize() 255 { 256 if (isInternalized()) 257 externalizeInternal(); 258 } 259 260 /** 261 * Internalize panel (remove from independent frame) 262 */ 263 public void internalize() 264 { 265 if (isExternalized()) 266 internalizeInternal(); 267 } 268 269 /** 270 * Externalize panel (internal method) 271 */ 272 void externalizeInternal() 273 { 274 if (!externalizationAutorized) 275 return; 276 277 // externalize 278 if (parent != null) 279 { 280 parent.remove(this); 281 parent.validate(); 282 } 283 284 frame.add(this, BorderLayout.CENTER); 285 frame.validate(); 286 frame.addToDesktopPane(); 287 frame.setVisible(true); 288 289 // notify 290 fireStateChange(true); 291 } 292 293 /** 294 * Internalize panel (internal method) 295 */ 296 void internalizeInternal() 297 { 298 if (!internalizationAutorized) 299 return; 300 301 // internalize 302 frame.setVisible(false); 303 frame.remove(this); 304 frame.validate(); 305 frame.removeFromMainDesktopPane(); 306 307 if (parent != null) 308 { 309 parent.add(this); 310 parent.validate(); 311 } 312 313 // notify 314 fireStateChange(false); 315 } 316 317 /** 318 * Switch from internalized <--> externalized state and vice versa 319 */ 320 public void switchState() 321 { 322 if (isExternalized()) 323 internalizeInternal(); 324 else 325 externalizeInternal(); 326 } 327 328 public boolean isInternalized() 329 { 330 return !frame.isVisible(); 331 } 332 333 public boolean isExternalized() 334 { 335 return frame.isVisible(); 336 } 337 338 /** 339 * @return the frame 340 */ 341 public IcyFrame getFrame() 342 { 343 return frame; 344 } 345 346 // /** 347 // * Implement getMinimumSize method for external frame only 348 // */ 349 // public Dimension getMinimumSizeExternal() 350 // { 351 // return frame.getMinimumSize(); 352 // } 353 // 354 // /** 355 // * Implement getMaximumSize method for external frame only 356 // */ 357 // public Dimension getMaximumSizeExternal() 358 // { 359 // return frame.getMaximumSize(); 360 // } 361 // 362 // /** 363 // * Implement getPreferredSize method for external frame only 364 // */ 365 // public Dimension getPreferredSizeExternal() 366 // { 367 // return frame.getPreferredSize(); 368 // } 369 // 370 // /** 371 // * Implement getSize method for external frame only 372 // */ 373 // public Dimension getSizeExternal() 374 // { 375 // return frame.getSize(); 376 // } 377 // 378 // /** 379 // * Implement getHeight method for external frame only 380 // */ 381 // public int getHeightExternal() 382 // { 383 // return frame.getHeight(); 384 // } 385 // 386 // /** 387 // * Implement getWidth method for external frame only 388 // */ 389 // public int getWidthExternal() 390 // { 391 // return frame.getWidth(); 392 // } 393 // 394 // /** 395 // * Implement getLocation method for external frame only 396 // */ 397 // public Point getLocationExternal() 398 // { 399 // return frame.getLocation(); 400 // } 401 // 402 // /** 403 // * Implement getBounds method for external frame only 404 // */ 405 // public Rectangle getBoundsExternal() 406 // { 407 // return frame.getBounds(); 408 // } 409 // 410 // /** 411 // * Implement setLocation method for external frame only 412 // */ 413 // public void setLocationExternal(final Point p) 414 // { 415 // frame.setLocation(p); 416 // } 417 // 418 // /** 419 // * Implement setLocation method for external frame only 420 // */ 421 // public void setLocationExternal(final int x, final int y) 422 // { 423 // frame.setLocation(x, y); 424 // } 425 // 426 // /** 427 // * Implement setSize method for external frame only 428 // */ 429 // public void setSizeExternal(final Dimension d) 430 // { 431 // frame.setSize(d); 432 // } 433 // 434 // /** 435 // * Implement setSize method for external frame only 436 // */ 437 // public void setSizeExternal(final int width, final int height) 438 // { 439 // frame.setSize(width, height); 440 // } 441 // 442 // /** 443 // * Implement setPreferredSize method for external frame only 444 // */ 445 // public void setPreferredSizeExternal(final Dimension d) 446 // { 447 // frame.setPreferredSize(d); 448 // } 449 // 450 // /** 451 // * Implement setMinimumSize method for external frame only 452 // */ 453 // public void setMinimumSizeExternal(final Dimension d) 454 // { 455 // frame.setMinimumSize(d); 456 // } 457 // 458 // /** 459 // * Implement setMaximumSize method for external frame only 460 // */ 461 // public void setMaximumSizeExternal(final Dimension d) 462 // { 463 // frame.setMaximumSize(d); 464 // } 465 466 /** 467 * Fire state change event 468 */ 469 private void fireStateChange(boolean externalized) 470 { 471 for (StateListener l : listenerList.getListeners(StateListener.class)) 472 l.stateChanged(this, externalized); 473 } 474 475 /** 476 * Implement addFrameListener method 477 */ 478 public void addStateListener(StateListener l) 479 { 480 listenerList.add(StateListener.class, l); 481 } 482 483 /** 484 * Implement removeFrameListener method 485 */ 486 public void removeStateListener(StateListener l) 487 { 488 listenerList.remove(StateListener.class, l); 489 } 490}