/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.ui.desktop.standalone;
import javax.swing.DesktopManager;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import java.beans.PropertyVetoException;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* A DesktopManager managing the internal frames in Desktop using a Most-Recently-Used order when changing
* the active internal frame. A Deque (a stack-like data structure) is used to keep track of frames.
* <ul>
* <li><code>activateFrame(JInternalFrame)</code> puts the frame at top of stack : if frame was already present
* in stack, remove it then add it at top, otherwise, add it at top.</li>
* <li><code>deactivateFrame(JInternalFrame)</code> is a noop on the stack, delegate to superclass.</li>
* <li><code>closeFrame(JInternalFrame)</code> removes frame from the stack and selects the frame at top of stack.</li>
* <li><code>iconifyFrame(JInternalFrame></code> is like <code>closeFrame</code> as far as this manager is concerned,
* but with iconifyFrame on superclass called.</li>
* <li><code>deiconifyFrame</code> delegates to superclass to bring back the frame on desktop, puts it at top of stack
* and makes sure it is selected.</li>
* </ul>
* At anytime, there is one frame selected (unless there are no (open) frames at all) and that frame is the top of
* stack.
*/
public class MostRecentlyUsedOrderDesktopManager implements DesktopManager {
// Keep desktop panel list (JInternalFrame) of existing internal frames in a most-recently-used order (i.e. a stack).
Deque<JInternalFrame> mostRecentlyUsedFrames = new ArrayDeque<JInternalFrame>();
private DesktopManager delegate;
// this is used to prevent AquaInternalFrameManager from activating another pane when we are closing one on Mac
private boolean isClosingFrame;
public MostRecentlyUsedOrderDesktopManager(DesktopManager delegate) {
this.delegate = delegate;
}
@Override
public void activateFrame(JInternalFrame f) {
if (f == null || isClosingFrame) {
return;
}
delegate.activateFrame(f);
if (!mostRecentlyUsedFrames.isEmpty() && f.equals(mostRecentlyUsedFrames.getFirst())) {
selectTopFrame(null);
return;
} else if (!mostRecentlyUsedFrames.isEmpty() && mostRecentlyUsedFrames.contains(f)) {
mostRecentlyUsedFrames.remove(f);
}
JInternalFrame previousTop = mostRecentlyUsedFrames.isEmpty() ? null : mostRecentlyUsedFrames.getFirst();
mostRecentlyUsedFrames.addFirst(f);
selectTopFrame(previousTop);
}
@Override
public void beginDraggingFrame(JComponent f) {
delegate.beginDraggingFrame(f);
}
@Override
public void beginResizingFrame(JComponent f, int direction) {
delegate.beginResizingFrame(f, direction);
}
@Override
public void deactivateFrame(JInternalFrame f) {
delegate.deactivateFrame(f);
}
@Override
public void closeFrame(JInternalFrame f) {
mostRecentlyUsedFrames.remove(f);
try {
isClosingFrame = true;
delegate.closeFrame(f);
} finally {
isClosingFrame = false;
}
selectTopFrame(f);
}
@Override
public void iconifyFrame(JInternalFrame f) {
mostRecentlyUsedFrames.remove(f);
selectTopFrame(f);
delegate.iconifyFrame(f);
}
@Override
public void maximizeFrame(JInternalFrame f) {
delegate.maximizeFrame(f);
}
@Override
public void minimizeFrame(JInternalFrame f) {
delegate.minimizeFrame(f);
}
@Override
public void openFrame(JInternalFrame f) {
delegate.openFrame(f);
}
@Override
public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
}
@Override
public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
}
@Override
public void deiconifyFrame(JInternalFrame f) {
delegate.deiconifyFrame(f);
activateFrame(f);
}
@Override
public void dragFrame(JComponent f, int newX, int newY) {
delegate.dragFrame(f, newX, newY);
}
@Override
public void endDraggingFrame(JComponent f) {
delegate.endDraggingFrame(f);
}
@Override
public void endResizingFrame(JComponent f) {
delegate.endResizingFrame(f);
}
protected void selectTopFrame(JInternalFrame previousTopFrame) {
JInternalFrame topFrame;
try {
if (mostRecentlyUsedFrames.isEmpty()) {
return;
} else {
topFrame = mostRecentlyUsedFrames.getFirst();
}
if (previousTopFrame != null && !previousTopFrame.equals(topFrame)) {
if (previousTopFrame.isSelected()) {
previousTopFrame.setSelected(false);
}
}
if (!topFrame.isSelected()) {
topFrame.setSelected(true);
}
} catch (PropertyVetoException ignore) {
}
}
}