blob: 4da325b7f750571b61043377846e07f9ae266b7d [file] [log] [blame]
/*
* Copyright 2000-2013 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.fileEditor.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockableContent;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.CopyOnWriteArraySet;
public class DockableEditorTabbedContainer implements DockContainer.Persistent {
private final EditorsSplitters mySplitters;
private final Project myProject;
private final CopyOnWriteArraySet<Listener> myListeners = new CopyOnWriteArraySet<Listener>();
private JBTabs myCurrentOver;
private Image myCurrentOverImg;
private TabInfo myCurrentOverInfo;
private boolean myDisposeWhenEmpty;
private boolean myWasEverShown;
DockableEditorTabbedContainer(Project project) {
this(project, null, true);
}
DockableEditorTabbedContainer(Project project, @Nullable EditorsSplitters splitters, boolean disposeWhenEmpty) {
myProject = project;
mySplitters = splitters;
myDisposeWhenEmpty = disposeWhenEmpty;
}
@Override
public String getDockContainerType() {
return DockableEditorContainerFactory.TYPE;
}
@Override
public Element getState() {
Element editors = new Element("state");
mySplitters.writeExternal(editors);
return editors;
}
void fireContentClosed(VirtualFile file) {
for (Listener each : myListeners) {
each.contentRemoved(file);
}
}
void fireContentOpen(VirtualFile file) {
for (Listener each : myListeners) {
each.contentAdded(file);
}
}
@Override
public RelativeRectangle getAcceptArea() {
return new RelativeRectangle(mySplitters);
}
public RelativeRectangle getAcceptAreaFallback() {
JRootPane root = mySplitters.getRootPane();
return root != null ? new RelativeRectangle(root) : new RelativeRectangle(mySplitters);
}
@NotNull
@Override
public ContentResponse getContentResponse(@NotNull DockableContent content, RelativePoint point) {
return getTabsAt(content, point) != null ? ContentResponse.ACCEPT_MOVE : ContentResponse.DENY;
}
@Nullable
private JBTabs getTabsAt(DockableContent content, RelativePoint point) {
if (content instanceof EditorTabbedContainer.DockableEditor) {
JBTabs targetTabs = mySplitters.getTabsAt(point);
if (targetTabs != null) {
return targetTabs;
} else {
EditorWindow wnd = mySplitters.getCurrentWindow();
if (wnd != null) {
EditorTabbedContainer tabs = wnd.getTabbedPane();
if (tabs != null) {
return tabs.getTabs();
}
} else {
EditorWindow[] windows = mySplitters.getWindows();
for (EditorWindow each : windows) {
if (each.getTabbedPane() != null && each.getTabbedPane().getTabs() != null) {
return each.getTabbedPane().getTabs();
}
}
}
}
}
return null;
}
@Override
public void add(@NotNull DockableContent content, RelativePoint dropTarget) {
EditorWindow window = null;
if (myCurrentOver != null) {
final DataProvider provider = myCurrentOver.getDataProvider();
if (provider != null) {
window = EditorWindow.DATA_KEY.getData(provider);
}
}
final EditorTabbedContainer.DockableEditor dockableEditor = (EditorTabbedContainer.DockableEditor)content;
VirtualFile file = dockableEditor.getFile();
if (window == null || window.isDisposed()) {
window = mySplitters.getOrCreateCurrentWindow(file);
}
if (myCurrentOver != null) {
int index = ((JBTabsImpl)myCurrentOver).getDropInfoIndex();
file.putUserData(EditorWindow.INITIAL_INDEX_KEY, index);
}
((FileEditorManagerImpl)FileEditorManagerEx.getInstanceEx(myProject)).openFileImpl2(window, file, true);
window.setFilePinned(file, dockableEditor.isPinned());
}
@Override
public Image startDropOver(@NotNull DockableContent content, RelativePoint point) {
return null;
}
@Override
public Image processDropOver(@NotNull DockableContent content, RelativePoint point) {
JBTabs current = getTabsAt(content, point);
if (myCurrentOver != null && myCurrentOver != current) {
resetDropOver(content);
}
if (myCurrentOver == null && current != null) {
myCurrentOver = current;
Presentation presentation = content.getPresentation();
myCurrentOverInfo = new TabInfo(new JLabel("")).setText(presentation.getText()).setIcon(presentation.getIcon());
myCurrentOverImg = myCurrentOver.startDropOver(myCurrentOverInfo, point);
}
if (myCurrentOver != null) {
myCurrentOver.processDropOver(myCurrentOverInfo, point);
}
return myCurrentOverImg;
}
@Override
public void resetDropOver(@NotNull DockableContent content) {
if (myCurrentOver != null) {
myCurrentOver.resetDropOver(myCurrentOverInfo);
myCurrentOver = null;
myCurrentOverInfo = null;
myCurrentOverImg = null;
}
}
@Override
public JComponent getContainerComponent() {
return mySplitters;
}
public EditorsSplitters getSplitters() {
return mySplitters;
}
public void close(VirtualFile file) {
mySplitters.closeFile(file, false);
}
@Override
public void closeAll() {
VirtualFile[] files = mySplitters.getOpenFiles();
for (VirtualFile each : files) {
close(each);
}
}
@Override
public void addListener(final Listener listener, Disposable parent) {
myListeners.add(listener);
Disposer.register(parent, new Disposable() {
@Override
public void dispose() {
myListeners.remove(listener);
}
});
}
@Override
public boolean isEmpty() {
return mySplitters.isEmptyVisible();
}
@Override
public void dispose() {
closeAll();
}
@Override
public boolean isDisposeWhenEmpty() {
return myDisposeWhenEmpty;
}
@Override
public void showNotify() {
if (!myWasEverShown) {
myWasEverShown = true;
getSplitters().openFiles();
}
}
@Override
public void hideNotify() {
}
}