blob: 6e1bce3171f474e30391b6db7ce40ce38f1eb8a4 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.idea.welcome.wizard;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.lang.ref.WeakReference;
/**
* Substitutes Idea listener that terminates the app when window closes.
*/
public final class WelcomeScreenWindowListener {
public static WindowListener install(@NotNull JFrame frame, @NotNull FirstRunWizardHost host) {
WindowListener ideaListener = removeCloseListener(frame);
// This code is a hack to replace IntelliJ window listener with ours.
// That listener is an instance of anonymous class and our hack will stop working if
// that class is removed or renamed. "DirectListener" is a fallback in case we don't
// find an original listener.
WindowListener ourListener = ideaListener != null ? new DelegatingListener(host, ideaListener) : new DirectListener(host);
frame.addWindowListener(ourListener);
return ourListener;
}
/**
* Remove the listener that causes application to quit if the user closes the welcome frame.
* <p/>
* I was unable to find proper API in IntelliJ to do this without forking quite a few classes.
*/
@Nullable
private static WindowListener removeCloseListener(@NotNull JFrame frame) {
WindowListener[] listeners = frame.getListeners(WindowListener.class);
for (WindowListener listener : listeners) {
// The listener in question is an anonymous class nested in WelcomeFrame
if (listener.getClass().getName().startsWith(WelcomeFrame.class.getName())) {
frame.removeWindowListener(listener);
return listener;
}
}
return null;
}
@Contract("null->false")
private static boolean handleClose(@Nullable FirstRunWizardHost host) {
if (host != null && host.isActive()) {
host.cancel();
return true;
} else {
return false;
}
}
/**
* This code is needed to avoid breaking IntelliJ native event processing.
*/
private static class DelegatingListener extends DirectListener {
@NotNull private final WindowListener myIdeaListener;
public DelegatingListener(@NotNull FirstRunWizardHost host, @NotNull WindowListener ideaListener) {
super(host);
myIdeaListener = ideaListener;
}
@Override
public void windowOpened(WindowEvent e) {
myIdeaListener.windowOpened(e);
}
@Override
public void windowClosed(WindowEvent e) {
myIdeaListener.windowClosed(e);
}
@Override
public void windowIconified(WindowEvent e) {
myIdeaListener.windowIconified(e);
}
@Override
public void windowClosing(WindowEvent e) {
if (!handleClose(getHost())) {
Window window = e.getWindow();
window.removeWindowListener(this);
window.addWindowListener(myIdeaListener);
myIdeaListener.windowClosing(e);
}
}
@Override
public void windowDeiconified(WindowEvent e) {
myIdeaListener.windowDeiconified(e);
}
@Override
public void windowActivated(WindowEvent e) {
myIdeaListener.windowActivated(e);
}
@Override
public void windowDeactivated(WindowEvent e) {
myIdeaListener.windowDeactivated(e);
}
}
private static class DirectListener extends WindowAdapter {
private final WeakReference<FirstRunWizardHost> myHostReference;
public DirectListener(@NotNull FirstRunWizardHost host) {
// Let the instance leave
myHostReference = new WeakReference<FirstRunWizardHost>(host);
}
@Nullable
protected final FirstRunWizardHost getHost() {
return myHostReference.get();
}
@Override
public void windowClosing(WindowEvent e) {
if (!handleClose(getHost())) {
e.getWindow().removeWindowListener(this);
}
}
}
}