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.frame; 020 021import icy.action.IcyAbstractAction; 022import icy.common.MenuCallback; 023import icy.gui.util.LookAndFeelUtil; 024import icy.resource.ResourceUtil; 025import icy.resource.icon.IcyIcon; 026import icy.system.IcyExceptionHandler; 027import icy.system.SystemUtil; 028import icy.system.thread.ThreadUtil; 029 030import java.awt.event.ActionEvent; 031import java.awt.event.KeyEvent; 032import java.beans.PropertyChangeEvent; 033import java.beans.PropertyChangeListener; 034import java.beans.PropertyVetoException; 035 036import javax.swing.JInternalFrame; 037import javax.swing.JMenu; 038import javax.swing.event.InternalFrameAdapter; 039import javax.swing.event.InternalFrameEvent; 040 041import org.pushingpixels.substance.internal.utils.SubstanceInternalFrameTitlePane; 042 043/** 044 * @author Stephane 045 */ 046public class IcyInternalFrame extends JInternalFrame 047{ 048 /** 049 * 050 */ 051 private static final long serialVersionUID = -5445569637723054083L; 052 053 private class CloseAction extends IcyAbstractAction 054 { 055 /** 056 * 057 */ 058 private static final long serialVersionUID = 4933605299188863452L; 059 060 public CloseAction() 061 { 062 super("Close", new IcyIcon(ResourceUtil.ICON_CLOSE, 20), "Close window", KeyEvent.VK_F4, SystemUtil 063 .getMenuCtrlMask()); 064 } 065 066 @Override 067 public boolean doAction(ActionEvent e) 068 { 069 close(false); 070 return true; 071 } 072 } 073 074 /** 075 * internals 076 */ 077 SubstanceInternalFrameTitlePane titlePane = null; 078 // JMenu systemMenu; 079 MenuCallback systemMenuCallback; 080 private boolean titleBarVisible; 081 private boolean closeItemVisible; 082 private boolean initialized = false; 083 084 /** 085 * @param title 086 * @param resizable 087 * @param closable 088 * @param maximizable 089 * @param iconifiable 090 */ 091 public IcyInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) 092 { 093 super(title, resizable, closable, maximizable, iconifiable); 094 095 addPropertyChangeListener("titlePane", new PropertyChangeListener() 096 { 097 @Override 098 public void propertyChange(PropertyChangeEvent evt) 099 { 100 // invoke later so the titlePane variable is up to date 101 ThreadUtil.invokeLater(new Runnable() 102 { 103 @Override 104 public void run() 105 { 106 updateTitlePane(); 107 } 108 }); 109 } 110 }); 111 112 addInternalFrameListener(new InternalFrameAdapter() 113 { 114 @Override 115 public void internalFrameClosed(InternalFrameEvent e) 116 { 117 // release the system menu callback as it can lead to some memory leak 118 // (cycling reference) 119 systemMenuCallback = null; 120 } 121 }); 122 123 setFrameIcon(ResourceUtil.ICON_ICY_16); 124 setVisible(false); 125 126 systemMenuCallback = null; 127 closeItemVisible = closable; 128 updateTitlePane(LookAndFeelUtil.getTitlePane(this)); 129 130 titleBarVisible = true; 131 initialized = true; 132 } 133 134 /** 135 * update internals informations linked to title pane with specified pane 136 */ 137 protected void updateTitlePane(final SubstanceInternalFrameTitlePane pane) 138 { 139 // update pane save 140 if (pane != null) 141 titlePane = pane; 142 // update menu 143 // if (titlePane != null) 144 // systemMenuBar = titlePane.getMenuBar(); 145 // refresh system menu whatever 146 updateSystemMenu(); 147 } 148 149 /** 150 * update internals informations linked to title pane and title pane state 151 */ 152 protected void updateTitlePane() 153 { 154 if (initialized) 155 { 156 // title pane can have changed 157 updateTitlePane(LookAndFeelUtil.getTitlePane(this)); 158 159 if (!titleBarVisible) 160 setTitleBarVisible(false); 161 } 162 } 163 164 /** 165 * Refresh system menu 166 */ 167 public void updateSystemMenu() 168 { 169 if ((titlePane != null) && !isClosed()) 170 { 171 final JMenu menu; 172 173 if (systemMenuCallback != null) 174 menu = systemMenuCallback.getMenu(); 175 else 176 menu = getDefaultSystemMenu(); 177 178 // ensure compatibility with heavyweight component 179 menu.getPopupMenu().setLightWeightPopupEnabled(false); 180 181 // rebuild menu 182 titlePane.setSystemMenu(menu); 183 // systemMenuBar.removeAll(); 184 // systemMenuBar.add(menu); 185 // systemMenuBar.validate(); 186 } 187 } 188 189 /** 190 * Close the frame. 191 * 192 * @param force 193 * if <code>true</code> the frame is close even if {@link #isClosable()} return <code>false</code> 194 */ 195 public void close(boolean force) 196 { 197 if (force || isClosable()) 198 doDefaultCloseAction(); 199 } 200 201 /** 202 * Implement isMinimized method 203 */ 204 public boolean isMinimized() 205 { 206 return isIcon(); 207 } 208 209 /** 210 * Implement isMaximized method 211 */ 212 public boolean isMaximized() 213 { 214 return isMaximum(); 215 } 216 217 /** 218 * Implement setMinimized method 219 */ 220 public void setMinimized(final boolean value) 221 { 222 // only relevant if state changed 223 if (isMinimized() ^ value) 224 { 225 try 226 { 227 setIcon(value); 228 } 229 catch (PropertyVetoException e) 230 { 231 IcyExceptionHandler.showErrorMessage(e, true); 232 } 233 } 234 } 235 236 /** 237 * Implement setMaximized method 238 */ 239 public void setMaximized(final boolean value) 240 { 241 // have to check that else we obtain a null pointer exception 242 if (getParent() == null) 243 return; 244 245 // only relevant if state changed 246 if (isMaximized() ^ value) 247 { 248 try 249 { 250 // have to check for parent non null 251 setMaximum(value); 252 } 253 catch (PropertyVetoException e) 254 { 255 IcyExceptionHandler.showErrorMessage(e, true); 256 } 257 } 258 } 259 260 /** 261 * @return the titleBarVisible 262 */ 263 public boolean isTitleBarVisible() 264 { 265 return titleBarVisible; 266 } 267 268 /** 269 * @return the closeItemVisible 270 */ 271 public boolean isCloseItemVisible() 272 { 273 return closeItemVisible; 274 } 275 276 /** 277 * @param value 278 * the closeItemVisible to set 279 */ 280 public void setCloseItemVisible(boolean value) 281 { 282 if (closeItemVisible != value) 283 { 284 closeItemVisible = value; 285 286 ThreadUtil.invokeLater(new Runnable() 287 { 288 @Override 289 public void run() 290 { 291 updateSystemMenu(); 292 } 293 }); 294 } 295 } 296 297 @Override 298 public void setClosable(boolean b) 299 { 300 super.setClosable(b); 301 302 if (!b) 303 setCloseItemVisible(false); 304 } 305 306 /** 307 * @param value 308 * the titleBarVisible to set 309 */ 310 public void setTitleBarVisible(boolean value) 311 { 312 if (value) 313 LookAndFeelUtil.setTitlePane(this, titlePane); 314 else 315 LookAndFeelUtil.setTitlePane(this, null); 316 317 revalidate(); 318 319 titleBarVisible = value; 320 } 321 322 /** 323 * Return the default system menu 324 */ 325 public JMenu getDefaultSystemMenu() 326 { 327 final JMenu result = new JMenu(); 328 329 if (closeItemVisible) 330 result.add(new CloseAction()); 331 332 return result; 333 } 334 335 /** 336 * @return the systemMenuCallback 337 */ 338 public MenuCallback getSystemMenuCallback() 339 { 340 return systemMenuCallback; 341 } 342 343 /** 344 * @param value 345 * the systemMenuCallback to set 346 */ 347 public void setSystemMenuCallback(MenuCallback value) 348 { 349 if (systemMenuCallback != value) 350 { 351 systemMenuCallback = value; 352 353 ThreadUtil.invokeLater(new Runnable() 354 { 355 @Override 356 public void run() 357 { 358 updateSystemMenu(); 359 } 360 }); 361 } 362 } 363}