blob: 1fa2bd95defe546ba79cffff5add988d7fe49115 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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.intellij.openapi.wm.impl;
import com.intellij.ide.UiActivity;
import com.intellij.ide.UiActivityMonitor;
import com.intellij.ide.impl.ContentManagerWatcher;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.BusyObject;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.LayeredIcon;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.impl.ContentImpl;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ui.update.Activatable;
import com.intellij.util.ui.update.UiNotifyConnector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
/**
* @author Anton Katilin
* @author Vladimir Kondratyev
*/
public final class ToolWindowImpl implements ToolWindowEx {
private final PropertyChangeSupport myChangeSupport;
private final ToolWindowManagerImpl myToolWindowManager;
private final String myId;
private final JComponent myComponent;
private boolean myAvailable;
private final ContentManager myContentManager;
private Icon myIcon;
private String myStripeTitle;
private static final Content EMPTY_CONTENT = new ContentImpl(new JLabel(), "", false);
private final ToolWindowContentUi myContentUI;
private InternalDecorator myDecorator;
private boolean myHideOnEmptyContent = false;
private boolean myPlaceholderMode;
private ToolWindowFactory myContentFactory;
@NotNull
private ActionCallback myActivation = new ActionCallback.Done();
private final BusyObject.Impl myShowing = new BusyObject.Impl() {
@Override
public boolean isReady() {
return myComponent != null && myComponent.isShowing();
}
};
private boolean myUseLastFocused = true;
private static final Logger LOG = Logger.getInstance(ToolWindowImpl.class);
ToolWindowImpl(final ToolWindowManagerImpl toolWindowManager, final String id, boolean canCloseContent, @Nullable final JComponent component) {
myToolWindowManager = toolWindowManager;
myChangeSupport = new PropertyChangeSupport(this);
myId = id;
myAvailable = true;
final ContentFactory contentFactory = ServiceManager.getService(ContentFactory.class);
myContentUI = new ToolWindowContentUi(this);
myContentManager =
contentFactory.createContentManager(myContentUI, canCloseContent, toolWindowManager.getProject());
if (component != null) {
final Content content = contentFactory.createContent(component, "", false);
myContentManager.addContent(content);
myContentManager.setSelectedContent(content, false);
}
myComponent = myContentManager.getComponent();
UiNotifyConnector notifyConnector = new UiNotifyConnector(myComponent, new Activatable.Adapter() {
@Override
public void showNotify() {
myShowing.onReady();
}
});
Disposer.register(myContentManager, notifyConnector);
}
public final void addPropertyChangeListener(final PropertyChangeListener l) {
myChangeSupport.addPropertyChangeListener(l);
}
@Override
public final void removePropertyChangeListener(final PropertyChangeListener l) {
myChangeSupport.removePropertyChangeListener(l);
}
@Override
public final void activate(final Runnable runnable) {
activate(runnable, true);
}
@Override
public void activate(@Nullable final Runnable runnable, final boolean autoFocusContents) {
activate(runnable, autoFocusContents, true);
}
@Override
public void activate(@Nullable final Runnable runnable, boolean autoFocusContents, boolean forced) {
ApplicationManager.getApplication().assertIsDispatchThread();
final UiActivity activity = new UiActivity.Focus("toolWindow:" + myId);
UiActivityMonitor.getInstance().addActivity(myToolWindowManager.getProject(), activity, ModalityState.NON_MODAL);
myToolWindowManager.activateToolWindow(myId, forced, autoFocusContents);
getActivation().doWhenDone(new Runnable() {
@Override
public void run() {
myToolWindowManager.invokeLater(new Runnable() {
@Override
public void run() {
if (runnable != null) {
runnable.run();
}
UiActivityMonitor.getInstance().removeActivity(myToolWindowManager.getProject(), activity);
}
});
}
});
}
@Override
public final boolean isActive() {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myToolWindowManager.isEditorComponentActive()) return false;
return myToolWindowManager.isToolWindowActive(myId) || myDecorator != null && myDecorator.isFocused();
}
@NotNull
@Override
public ActionCallback getReady(@NotNull final Object requestor) {
final ActionCallback result = new ActionCallback();
myShowing.getReady(this).doWhenDone(new Runnable() {
@Override
public void run() {
ArrayList<FinalizableCommand> cmd = new ArrayList<FinalizableCommand>();
cmd.add(new FinalizableCommand(null) {
@Override
public void run() {
IdeFocusManager.getInstance(myToolWindowManager.getProject()).doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
if (myContentManager.isDisposed()) return;
myContentManager.getReady(requestor).notify(result);
}
});
}
});
myToolWindowManager.execute(cmd);
}
});
return result;
}
@Override
public final void show(final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.showToolWindow(myId);
if (runnable != null) {
getActivation().doWhenDone(new Runnable() {
@Override
public void run() {
myToolWindowManager.invokeLater(runnable);
}
});
}
}
@Override
public final void hide(@Nullable final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.hideToolWindow(myId, false);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public final boolean isVisible() {
return myToolWindowManager.isToolWindowVisible(myId);
}
@Override
public final ToolWindowAnchor getAnchor() {
return myToolWindowManager.getToolWindowAnchor(myId);
}
@Override
public final void setAnchor(final ToolWindowAnchor anchor, @Nullable final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.setToolWindowAnchor(myId, anchor);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public boolean isSplitMode() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myToolWindowManager.isSplitMode(myId);
}
@Override
public void setContentUiType(ToolWindowContentUiType type, @Nullable Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.setContentUiType(myId, type);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public void setDefaultContentUiType(@NotNull ToolWindowContentUiType type) {
myToolWindowManager.setDefaultContentUiType(this, type);
}
@Override
public ToolWindowContentUiType getContentUiType() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myToolWindowManager.getContentUiType(myId);
}
@Override
public void setSplitMode(final boolean isSideTool, @Nullable final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.setSideTool(myId, isSideTool);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public final void setAutoHide(final boolean state) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.setToolWindowAutoHide(myId, state);
}
@Override
public final boolean isAutoHide() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myToolWindowManager.isToolWindowAutoHide(myId);
}
@Override
public final ToolWindowType getType() {
return myToolWindowManager.getToolWindowType(myId);
}
@Override
public final void setType(final ToolWindowType type, @Nullable final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
myToolWindowManager.setToolWindowType(myId, type);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public final ToolWindowType getInternalType() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myToolWindowManager.getToolWindowInternalType(myId);
}
@Override
public void stretchWidth(int value) {
myToolWindowManager.stretchWidth(this, value);
}
@Override
public void stretchHeight(int value) {
myToolWindowManager.stretchHeight(this, value);
}
@Override
public InternalDecorator getDecorator() {
return myDecorator;
}
@Override
public void setAdditionalGearActions(ActionGroup additionalGearActions) {
getDecorator().setAdditionalGearActions(additionalGearActions);
}
@Override
public void setTitleActions(AnAction... actions) {
getDecorator().setTitleActions(actions);
}
@Override
public final void setAvailable(final boolean available, final Runnable runnable) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Boolean oldAvailable = myAvailable ? Boolean.TRUE : Boolean.FALSE;
myAvailable = available;
myChangeSupport.firePropertyChange(PROP_AVAILABLE, oldAvailable, myAvailable ? Boolean.TRUE : Boolean.FALSE);
if (runnable != null) {
myToolWindowManager.invokeLater(runnable);
}
}
@Override
public void installWatcher(ContentManager contentManager) {
new ContentManagerWatcher(this, contentManager);
}
/**
* @return <code>true</code> if the component passed into constructor is not instance of
* <code>ContentManager</code> class. Otherwise it delegates the functionality to the
* passed content manager.
*/
@Override
public final boolean isAvailable() {
return myAvailable && myComponent != null;
}
@Override
public final JComponent getComponent() {
return myComponent;
}
@Override
public ContentManager getContentManager() {
return myContentManager;
}
public ToolWindowContentUi getContentUI() {
return myContentUI;
}
@Override
public final Icon getIcon() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myIcon;
//return getSelectedContent().getIcon();
}
public final String getId() {
return myId;
}
@Override
public final String getTitle() {
ApplicationManager.getApplication().assertIsDispatchThread();
return getSelectedContent().getDisplayName();
}
@Override
@NotNull
public final String getStripeTitle() {
ApplicationManager.getApplication().assertIsDispatchThread();
return ObjectUtils.notNull(myStripeTitle, myId);
}
@Override
public final void setIcon(final Icon icon) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Icon oldIcon = getIcon();
if (oldIcon != icon && !(icon instanceof LayeredIcon) && (icon.getIconHeight() != 13 || icon.getIconWidth() != 13)) {
LOG.warn("ToolWindow icons should be 13x13. Please fix ToolWindow (ID: " + getId() + ") or icon " + icon);
}
getSelectedContent().setIcon(icon);
myIcon = icon;
myChangeSupport.firePropertyChange(PROP_ICON, oldIcon, icon);
}
@Override
public final void setTitle(String title) {
ApplicationManager.getApplication().assertIsDispatchThread();
String oldTitle = getTitle();
getSelectedContent().setDisplayName(title);
myChangeSupport.firePropertyChange(PROP_TITLE, oldTitle, title);
}
@Override
public final void setStripeTitle(@NotNull String stripeTitle) {
ApplicationManager.getApplication().assertIsDispatchThread();
String oldTitle = myStripeTitle;
myStripeTitle = stripeTitle;
myChangeSupport.firePropertyChange(PROP_STRIPE_TITLE, oldTitle, stripeTitle);
}
private Content getSelectedContent() {
final Content selected = getContentManager().getSelectedContent();
return selected != null ? selected : EMPTY_CONTENT;
}
public void setDecorator(final InternalDecorator decorator) {
myDecorator = decorator;
}
public void fireActivated() {
if (myDecorator != null) {
myDecorator.fireActivated();
}
}
public void fireHidden() {
if (myDecorator != null) {
myDecorator.fireHidden();
}
}
public void fireHiddenSide() {
if (myDecorator != null) {
myDecorator.fireHiddenSide();
}
}
public ToolWindowManagerImpl getToolWindowManager() {
return myToolWindowManager;
}
@Nullable
public ActionGroup getPopupGroup() {
return myDecorator != null ? myDecorator.createPopupGroup() : null;
}
@Override
public void setDefaultState(@Nullable final ToolWindowAnchor anchor, @Nullable final ToolWindowType type, @Nullable final Rectangle floatingBounds) {
myToolWindowManager.setDefaultState(this, anchor, type, floatingBounds);
}
@Override
public void setToHideOnEmptyContent(final boolean hideOnEmpty) {
myHideOnEmptyContent = hideOnEmpty;
}
@Override
public boolean isToHideOnEmptyContent() {
return myHideOnEmptyContent;
}
@Override
public boolean isDisposed() {
return myContentManager.isDisposed();
}
public boolean isPlaceholderMode() {
return myPlaceholderMode;
}
public void setPlaceholderMode(final boolean placeholderMode) {
myPlaceholderMode = placeholderMode;
}
@Override
@NotNull
public ActionCallback getActivation() {
return myActivation;
}
@NotNull
public ActionCallback setActivation(@NotNull ActionCallback activation) {
if (!myActivation.isProcessed() && !myActivation.equals(activation)) {
myActivation.setRejected();
}
myActivation = activation;
return myActivation;
}
public void setContentFactory(ToolWindowFactory contentFactory) {
myContentFactory = contentFactory;
if (contentFactory instanceof ToolWindowFactoryEx) {
((ToolWindowFactoryEx)contentFactory).init(this);
}
}
public void ensureContentInitialized() {
if (myContentFactory != null) {
getContentManager().removeAllContents(false);
myContentFactory.createToolWindowContent(myToolWindowManager.getProject(), this);
myContentFactory = null;
}
}
@Override
public void showContentPopup(InputEvent inputEvent) {
myContentUI.toggleContentPopup();
}
@Override
public void setUseLastFocusedOnActivation(boolean focus) {
myUseLastFocused = focus;
}
@Override
public boolean isUseLastFocusedOnActivation() {
return myUseLastFocused;
}
}