/*
* 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.action.FileActions;
import icy.action.GeneralActions;
import icy.action.SequenceOperationActions;
import icy.file.FileUtil;
import icy.file.Loader;
import icy.gui.component.ExternalizablePanel;
import icy.gui.component.ExternalizablePanel.StateListener;
import icy.gui.frame.IcyExternalFrame;
import icy.gui.inspector.ChatPanel;
import icy.gui.inspector.InspectorPanel;
import icy.gui.menu.ApplicationMenu;
import icy.gui.menu.MainRibbon;
import icy.gui.menu.search.SearchBar;
import icy.gui.util.ComponentUtil;
import icy.gui.util.WindowPositionSaver;
import icy.gui.viewer.Viewer;
import icy.imagej.ImageJWrapper;
import icy.main.Icy;
import icy.math.HungarianAlgorithm;
import icy.preferences.GeneralPreferences;
import icy.resource.ResourceUtil;
import icy.resource.icon.IcyApplicationIcon;
import icy.system.FileDrop;
import icy.system.FileDrop.FileDropExtListener;
import icy.system.FileDrop.FileDropListener;
import icy.system.SystemUtil;
import icy.system.thread.ThreadUtil;
import icy.type.collection.CollectionUtil;
import icy.util.StringUtil;
import ij.IJ;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import org.pushingpixels.flamingo.api.ribbon.JRibbon;
import org.pushingpixels.flamingo.api.ribbon.JRibbonFrame;
/**
* @author fab & Stephane
*/
public class MainFrame extends JRibbonFrame
{
private static Rectangle getDefaultBounds()
{
Rectangle r = SystemUtil.getMaximumWindowBounds();
r.width -= 100;
r.height -= 100;
r.x += 50;
r.y += 50;
return r;
}
/**
* Returns the list of internal viewers.
*
* @param bounds
* If not null only viewers visible in the specified bounds are returned.
* @param wantNotVisible
* Also return not visible viewers
* @param wantIconized
* Also return iconized viewers
*/
public static Viewer[] getExternalViewers(Rectangle bounds, boolean wantNotVisible, boolean wantIconized)
{
final List<Viewer> result = new ArrayList<Viewer>();
for (Viewer viewer : Icy.getMainInterface().getViewers())
{
if (viewer.isExternalized())
{
final IcyExternalFrame externalFrame = viewer.getIcyExternalFrame();
if ((wantNotVisible || externalFrame.isVisible())
&& (wantIconized || !ComponentUtil.isMinimized(externalFrame))
&& ((bounds == null) || bounds.contains(ComponentUtil.getCenter(externalFrame))))
result.add(viewer);
}
}
return result.toArray(new Viewer[result.size()]);
}
/**
* Returns the list of internal viewers.
*
* @param wantNotVisible
* Also return not visible viewers
* @param wantIconized
* Also return iconized viewers
*/
public static Viewer[] getExternalViewers(boolean wantNotVisible, boolean wantIconized)
{
return getExternalViewers(null, wantNotVisible, wantIconized);
}
/**
*
*/
private static final long serialVersionUID = 1113003570969611614L;
public static final String TITLE = "Icy";
public static final String PROPERTY_DETACHEDMODE = "detachedMode";
public static final int TILE_HORIZONTAL = 0;
public static final int TILE_VERTICAL = 1;
public static final int TILE_GRID = 2;
public static final String ID_PREVIOUS_STATE = "previousState";
final MainRibbon mainRibbon;
JSplitPane mainPane;
private final JPanel centerPanel;
private final IcyDesktopPane desktopPane;
InspectorPanel inspector;
boolean detachedMode;
int lastInspectorWidth;
boolean inspectorWidthSet;
// state save for detached mode
private int previousHeight;
private boolean previousMaximized;
private boolean previousInspectorInternalized;
// we need to keep reference on it as the object only use weak reference
final WindowPositionSaver positionSaver;
/**
* @throws HeadlessException
*/
public MainFrame() throws HeadlessException
{
super(TITLE);
// RibbonFrame force these properties to false
// but this might add problems with mac OSX
// JPopupMenu.setDefaultLightWeightPopupEnabled(true);
// ToolTipManager.sharedInstance().setLightWeightPopupEnabled(true);
// FIXME : remove this when Ribbon with have fixed KeyTipLayer component
getRootPane().getLayeredPane().getComponent(0).setVisible(false);
// SubstanceRibbonFrameTitlePane titlePane = (SubstanceRibbonFrameTitlePane)
// LookAndFeelUtil.getTitlePane(this);
// JCheckBox comp = new JCheckBox("test")
// comp.setP
// titlePane.add();
//
// "substancelaf.internal.titlePane.extraComponentKind"
// titlePane.m
final Rectangle defaultBounds = getDefaultBounds();
positionSaver = new WindowPositionSaver(this, "frame/main", defaultBounds.getLocation(),
defaultBounds.getSize());
previousInspectorInternalized = positionSaver.getPreferences().getBoolean(ID_PREVIOUS_STATE, true);
// set "always on top" state
setAlwaysOnTop(GeneralPreferences.getAlwaysOnTop());
// default close operation
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
// build ribbon
mainRibbon = new MainRibbon(getRibbon());
// set application icons
setIconImages(ResourceUtil.getIcyIconImages());
setApplicationIcon(new IcyApplicationIcon());
// set minimized state
getRibbon().setMinimized(GeneralPreferences.getRibbonMinimized());
// main center pane (contains desktop pane)
centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout());
// desktop pane
desktopPane = new IcyDesktopPane();
desktopPane.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 2)
{
final Insets insets = mainPane.getInsets();
final int lastLoc = mainPane.getLastDividerLocation();
final int currentLoc = mainPane.getDividerLocation();
final int maxLoc = mainPane.getWidth() - (mainPane.getDividerSize() + insets.left);
// just hide / unhide inspector
if (currentLoc != maxLoc)
mainPane.setDividerLocation(maxLoc);
else
mainPane.setDividerLocation(lastLoc);
// if (isInpectorInternalized())
// externalizeInspector();
// else
// internalizeInspector();
}
}
});
// set the desktop pane in center pane
centerPanel.add(desktopPane, BorderLayout.CENTER);
// action on file drop
final FileDropListener desktopFileDropListener = new FileDropListener()
{
@Override
public void filesDropped(File[] files)
{
Loader.load(CollectionUtil.asList(FileUtil.toPaths(files)), false, true, true);
}
};
final FileDropExtListener bandFileDropListener = new FileDropExtListener()
{
@Override
public void filesDropped(DropTargetDropEvent evt, File[] files)
{
if (getRibbon().getSelectedTask() == mainRibbon.getImageJTask())
{
final ImageJWrapper imageJ = mainRibbon.getImageJTask().getImageJ();
final JPanel imageJPanel = imageJ.getSwingPanel();
// drop point was inside ImageJ ?
if (imageJPanel.contains(ComponentUtil.convertPoint(getRibbon(), evt.getLocation(), imageJPanel)))
{
if (files.length > 0)
{
final String file = files[0].getAbsolutePath();
ThreadUtil.bgRun(new Runnable()
{
@Override
public void run()
{
IJ.open(file);
}
});
}
return;
}
}
// classic file loading
Loader.load(CollectionUtil.asList(FileUtil.toPaths(files)), false, true, true);
}
};
// handle file drop in desktop pane and in ribbon pane
new FileDrop(desktopPane, BorderFactory.createLineBorder(Color.blue.brighter(), 2), false,
desktopFileDropListener);
new FileDrop(getRibbon(), BorderFactory.createLineBorder(Color.blue.brighter(), 1), false, bandFileDropListener);
// listen ribbon minimization event
getRibbon().addPropertyChangeListener(JRibbon.PROPERTY_MINIMIZED, new PropertyChangeListener()
{
@Override
public void propertyChange(PropertyChangeEvent evt)
{
final boolean value = ((Boolean) evt.getNewValue()).booleanValue();
// pack the frame in detached mode
if (detachedMode)
pack();
// save state in preferene
GeneralPreferences.setRibbonMinimized(value);
}
});
}
/**
* Process init.<br>
* Inspector is an ExternalizablePanel and requires MainFrame to be created.
*/
public void init()
{
// inspector
inspector = new InspectorPanel();
inspectorWidthSet = false;
addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent e)
{
// only need to do it at first display
if (!inspectorWidthSet)
{
// main frame resized --> adjust divider location so inspector keep its size.
// we need to use this method as getWidth() do not return immediate correct
// value on OSX when initial state is maximized.
if (inspector.isInternalized())
mainPane.setDividerLocation(getWidth() - lastInspectorWidth);
inspectorWidthSet = true;
}
if (detachedMode)
{
// fix height
final int prefH = getPreferredSize().height;
if (getHeight() > prefH)
setSize(getWidth(), prefH);
}
}
});
// main pane
mainPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centerPanel, null);
mainPane.setContinuousLayout(true);
mainPane.setOneTouchExpandable(true);
// get saved inspector width
lastInspectorWidth = inspector.getPreferredSize().width;
// add the divider and border size if inspector was visible
if (lastInspectorWidth > 16)
lastInspectorWidth += 6 + 8;
// just force size for collapsed (divider + minimum border)
else
lastInspectorWidth = 6 + 4;
if (inspector.isInternalized())
{
mainPane.setRightComponent(inspector);
mainPane.setDividerSize(6);
}
else
{
mainPane.setDividerSize(0);
inspector.setParent(mainPane);
}
mainPane.setResizeWeight(1);
inspector.addStateListener(new StateListener()
{
@Override
public void stateChanged(ExternalizablePanel source, boolean externalized)
{
if (externalized)
mainPane.setDividerSize(0);
else
{
mainPane.setDividerSize(6);
// restore previous location
mainPane.setDividerLocation(getWidth() - lastInspectorWidth);
}
}
});
previousHeight = getHeight();
previousMaximized = ComponentUtil.isMaximized(this);
detachedMode = GeneralPreferences.getMultiWindowMode();
// detached mode
if (detachedMode)
{
// resize window to ribbon dimension
if (previousMaximized)
ComponentUtil.setMaximized(this, false);
setSize(getWidth(), getMinimumSize().height);
}
else
add(mainPane, BorderLayout.CENTER);
validate();
// initialize now some stuff that need main frame to be initialized
mainRibbon.init();
setVisible(true);
// can be done after setVisible
buildActionMap();
}
void buildActionMap()
{
// global input map
buildActionMap(mainPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW), mainPane.getActionMap());
}
private void buildActionMap(InputMap imap, ActionMap amap)
{
imap.put(GeneralActions.searchAction.getKeyStroke(), GeneralActions.searchAction.getName());
imap.put(FileActions.openSequenceAction.getKeyStroke(), FileActions.openSequenceAction.getName());
imap.put(FileActions.saveAsSequenceAction.getKeyStroke(), FileActions.saveAsSequenceAction.getName());
imap.put(GeneralActions.onlineHelpAction.getKeyStroke(), GeneralActions.onlineHelpAction.getName());
imap.put(SequenceOperationActions.undoAction.getKeyStroke(), SequenceOperationActions.undoAction.getName());
imap.put(SequenceOperationActions.redoAction.getKeyStroke(), SequenceOperationActions.redoAction.getName());
amap.put(GeneralActions.searchAction.getName(), GeneralActions.searchAction);
amap.put(FileActions.openSequenceAction.getName(), FileActions.openSequenceAction);
amap.put(FileActions.saveAsSequenceAction.getName(), FileActions.saveAsSequenceAction);
amap.put(GeneralActions.onlineHelpAction.getName(), GeneralActions.onlineHelpAction);
amap.put(SequenceOperationActions.undoAction.getName(), SequenceOperationActions.undoAction);
amap.put(SequenceOperationActions.redoAction.getName(), SequenceOperationActions.redoAction);
}
public ApplicationMenu getApplicationMenu()
{
return (ApplicationMenu) getRibbon().getApplicationMenu();
}
/**
* Returns the center pane, this pane contains the desktop pane.<br>
* Feel free to add temporary top/left/right or bottom pane to it.
*/
public JPanel getCenterPanel()
{
return centerPanel;
}
/**
* Returns the {@link SearchBar} component.
*/
public SearchBar getSearchBar()
{
if (mainRibbon != null)
return mainRibbon.getSearchBar();
return null;
}
/**
* Returns the desktopPane which contains InternalFrame.
*/
public IcyDesktopPane getDesktopPane()
{
return desktopPane;
}
/**
* Return all internal frames
*/
public ArrayList<JInternalFrame> getInternalFrames()
{
if (desktopPane != null)
return CollectionUtil.asArrayList(desktopPane.getAllFrames());
return new ArrayList<JInternalFrame>();
}
/**
* @return the inspector
*/
public InspectorPanel getInspector()
{
return inspector;
}
/**
* @return the mainRibbon
*/
public MainRibbon getMainRibbon()
{
return mainRibbon;
}
/**
* @return the chat component
*/
public ChatPanel getChat()
{
return inspector.getChatPanel();
}
/**
* Return true if the main frame is in "detached" mode
*/
public boolean isDetachedMode()
{
return detachedMode;
}
/**
* Return content pane dimension (available area in main frame).<br>
* If the main frame is in "detached" mode this actually return the system desktop dimension.
*/
public Dimension getDesktopSize()
{
if (detachedMode)
return SystemUtil.getMaximumWindowBounds().getSize();
return desktopPane.getSize();
}
/**
* Return content pane width
*/
public int getDesktopWidth()
{
return getDesktopSize().width;
}
/**
* Return content pane height
*/
public int getDesktopHeight()
{
return getDesktopSize().height;
}
public int getPreviousHeight()
{
return previousHeight;
}
public boolean getPreviousMaximized()
{
return previousMaximized;
}
/**
* Returns true if the inspector is internalized in main container.<br>
* Always returns false in detached mode.
*/
public boolean isInpectorInternalized()
{
return inspector.isInternalized();
}
/**
* Internalize the inspector in main container.<br>
* The method fails and returns false in detached mode.
*/
public boolean internalizeInspector()
{
if (inspector.isExternalized() && inspector.isInternalizationAutorized())
{
inspector.internalize();
return true;
}
return false;
}
/**
* Externalize the inspector in main container.<br>
* Returns false if the methods failed.
*/
public boolean externalizeInspector()
{
if (inspector.isInternalized() && inspector.isExternalizationAutorized())
{
// save diviser location
lastInspectorWidth = getWidth() - mainPane.getDividerLocation();
inspector.externalize();
return true;
}
return false;
}
/**
* Organize all frames in cascade
*/
public void organizeCascade()
{
// all screen devices
final GraphicsDevice screenDevices[] = SystemUtil.getLocalGraphicsEnvironment().getScreenDevices();
// screen devices to process
final ArrayList<GraphicsDevice> devices = new ArrayList<GraphicsDevice>();
// detached mode ?
if (isDetachedMode())
{
// process all available screen for cascade organization
for (GraphicsDevice dev : screenDevices)
if (dev.getType() == GraphicsDevice.TYPE_RASTER_SCREEN)
devices.add(dev);
}
else
{
// process desktop pane cascade organization
desktopPane.organizeCascade();
// we process screen where the mainFrame is not visible
for (GraphicsDevice dev : screenDevices)
if (dev.getType() == GraphicsDevice.TYPE_RASTER_SCREEN)
if (!dev.getDefaultConfiguration().getBounds().contains(getLocation()))
devices.add(dev);
}
// organize frames on different screen
for (GraphicsDevice dev : devices)
organizeCascade(dev);
}
/**
* Organize frames in cascade on the specified graphics device.
*/
protected void organizeCascade(GraphicsDevice graphicsDevice)
{
final GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
final Rectangle bounds = graphicsConfiguration.getBounds();
final Insets inset = getToolkit().getScreenInsets(graphicsConfiguration);
// adjust bounds of current screen
bounds.x += inset.left;
bounds.y += inset.top;
bounds.width -= inset.left + inset.right;
bounds.height -= inset.top + inset.bottom;
// prepare viewers to process
final Viewer[] viewers = getExternalViewers(bounds, false, false);
// this screen contains the main frame ?
if (bounds.contains(getLocation()))
{
// move main frame at top
setLocation(bounds.x, bounds.y);
final int mainFrameW = getWidth();
final int mainFrameH = getHeight();
// adjust available bounds of current screen
if (mainFrameW > mainFrameH)
{
bounds.y += mainFrameH;
bounds.height -= mainFrameH;
}
else
{
bounds.x += mainFrameW;
bounds.width -= mainFrameW;
}
}
// available space
final int w = bounds.width;
final int h = bounds.height;
final int xMax = bounds.x + w;
final int yMax = bounds.y + h;
final int fw = (int) (w * 0.6f);
final int fh = (int) (h * 0.6f);
int x = bounds.x + 32;
int y = bounds.y + 32;
for (Viewer v : viewers)
{
final IcyExternalFrame externalFrame = v.getIcyExternalFrame();
if (externalFrame.isMaximized())
externalFrame.setMaximized(false);
externalFrame.setBounds(x, y, fw, fh);
externalFrame.toFront();
x += 30;
y += 20;
if ((x + fw) > xMax)
x = bounds.x + 32;
if ((y + fh) > yMax)
y = bounds.y + 32;
}
}
/**
* Organize all frames in tile.<br>
*
* @param type
* tile type.<br>
* TILE_HORIZONTAL, TILE_VERTICAL or TILE_GRID.
*/
public void organizeTile(int type)
{
// all screen devices
final GraphicsDevice screenDevices[] = SystemUtil.getLocalGraphicsEnvironment().getScreenDevices();
// screen devices to process
final ArrayList<GraphicsDevice> devices = new ArrayList<GraphicsDevice>();
// detached mode ?
if (isDetachedMode())
{
// process all available screen for cascade organization
for (GraphicsDevice dev : screenDevices)
if (dev.getType() == GraphicsDevice.TYPE_RASTER_SCREEN)
devices.add(dev);
}
else
{
// process desktop pane tile organization
desktopPane.organizeTile(type);
// we process screen where the mainFrame is not visible
for (GraphicsDevice dev : screenDevices)
if (dev.getType() == GraphicsDevice.TYPE_RASTER_SCREEN)
if (!dev.getDefaultConfiguration().getBounds().contains(getLocation()))
devices.add(dev);
}
// organize frames on different screen
for (GraphicsDevice dev : devices)
organizeTile(dev, type);
}
/**
* Organize frames in tile on the specified graphics device.
*/
protected void organizeTile(GraphicsDevice graphicsDevice, int type)
{
final GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
final Rectangle bounds = graphicsConfiguration.getBounds();
final Insets inset = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
// adjust bounds of current screen
bounds.x += inset.left;
bounds.y += inset.top;
bounds.width -= inset.left + inset.right;
bounds.height -= inset.top + inset.bottom;
// prepare viewers to process
final Viewer[] viewers = getExternalViewers(bounds, false, false);
// this screen contains the main frame ?
if (bounds.contains(getLocation()))
{
// move main frame at top
setLocation(bounds.x, bounds.y);
final int mainFrameW = getWidth();
final int mainFrameH = getHeight();
// adjust available bounds of current screen
if (mainFrameW > mainFrameH)
{
bounds.y += mainFrameH;
bounds.height -= mainFrameH;
}
else
{
bounds.x += mainFrameW;
bounds.width -= mainFrameW;
}
}
final int numFrames = viewers.length;
// nothing to do
if (numFrames == 0)
return;
// available space
final int w = bounds.width;
final int h = bounds.height;
final int x = bounds.x;
final int y = bounds.y;
int numCol;
int numLine;
switch (type)
{
case MainFrame.TILE_HORIZONTAL:
numCol = 1;
numLine = numFrames;
break;
case MainFrame.TILE_VERTICAL:
numCol = numFrames;
numLine = 1;
break;
default:
numCol = (int) Math.sqrt(numFrames);
if (numFrames != (numCol * numCol))
numCol++;
numLine = numFrames / numCol;
if (numFrames > (numCol * numLine))
numLine++;
break;
}
final double[][] framesDistances = new double[numCol * numLine][numFrames];
final int dx = w / numCol;
final int dy = h / numLine;
int k = 0;
for (int i = 0; i < numLine; i++)
{
for (int j = 0; j < numCol; j++, k++)
{
final double[] distances = framesDistances[k];
final double fx = x + (j * dx) + (dx / 2d);
final double fy = y + (i * dy) + (dy / 2d);
for (int f = 0; f < numFrames; f++)
{
final Point2D.Double center = ComponentUtil.getCenter(viewers[f].getExternalFrame());
distances[f] = Point2D.distanceSq(center.x, center.y, fx, fy);
}
}
}
final int[] framePos = new HungarianAlgorithm(framesDistances).resolve();
k = 0;
for (int i = 0; i < numLine; i++)
{
for (int j = 0; j < numCol; j++, k++)
{
final int f = framePos[k];
if (f < numFrames)
{
final IcyExternalFrame externalFrame = viewers[f].getIcyExternalFrame();
if (externalFrame.isMaximized())
externalFrame.setMaximized(false);
externalFrame.setBounds(x + (j * dx), y + (i * dy), dx, dy);
externalFrame.toFront();
}
}
}
}
/**
* Set detached window mode.
*/
public void setDetachedMode(boolean value)
{
if (detachedMode != value)
{
// detached mode
if (value)
{
// save inspector state
previousInspectorInternalized = inspector.isInternalized();
// save it in preferences...
positionSaver.getPreferences().putBoolean(ID_PREVIOUS_STATE, previousInspectorInternalized);
// externalize inspector
externalizeInspector();
// no more internalization possible
inspector.setInternalizationAutorized(false);
// save the current height & state
previousHeight = getHeight();
previousMaximized = ComponentUtil.isMaximized(this);
// hide main pane and remove maximized state
remove(mainPane);
ComponentUtil.setMaximized(this, false);
// and pack the frame
pack();
}
// single window mode
else
{
// show main pane & resize window back to original dimension
add(mainPane, BorderLayout.CENTER);
setSize(getWidth(), previousHeight);
if (previousMaximized)
ComponentUtil.setMaximized(this, true);
// recompute layout
validate();
// internalization possible
inspector.setInternalizationAutorized(true);
// restore inspector internalization
if (previousInspectorInternalized)
internalizeInspector();
}
detachedMode = value;
// notify mode change
firePropertyChange(PROPERTY_DETACHEDMODE, !value, value);
}
}
/**
* Refresh connected username informations
*/
public void refreshUserInfos()
{
final String login = GeneralPreferences.getUserLogin();
final String userName = GeneralPreferences.getUserName();
if (!StringUtil.isEmpty(userName))
setTitle(TITLE + " - " + userName);
else if (!StringUtil.isEmpty(login))
setTitle(TITLE + " - " + login);
else
setTitle(TITLE);
}
@Override
public void reshape(int x, int y, int width, int height)
{
final Rectangle r = new Rectangle(x, y, width, height);
final boolean detached;
// test detached mode by using mainPane parent as resize is called inside setDetachedMode(..) and
// detachedMode variable is not yet updated
if (mainPane == null)
detached = detachedMode;
else
detached = mainPane.getParent() == null;
if (detached)
{
// fix height
final int prefH = getPreferredSize().height;
if (r.height > prefH)
r.height = prefH;
}
ComponentUtil.fixPosition(this, r);
super.reshape(r.x, r.y, r.width, r.height);
}
// @Override
// public synchronized void setMaximizedBounds(Rectangle bounds)
// {
// Rectangle bnds = SystemUtil.getScreenBounds(ComponentUtil.getScreen(this), true);
//
// if (bnds.isEmpty())
// bnds = bounds;
// // at least use the location from original bounds
// else if (bounds != null)
// bnds.setLocation(bounds.getLocation());
// else bnds.setLocation(0, 0);
//
// super.setMaximizedBounds(bnds);
// }
}