blob: 999fe75523e9eb1d33fe0dc2d7651243ec8cedb9 [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.fileEditor.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.UISettingsListener;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.ContentManagerAdapter;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.docking.DockManager;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.EnumSet;
class PreviewPanel extends JPanel {
private CardLayout myLayout;
enum ContentType {Files, Usages, Diagrams, Documentation}
private static final Key<VirtualFile> FILE_KEY = Key.create("v_file");
private static final int HISTORY_LIMIT = 10;
private final Project myProject;
private final FileEditorManagerImpl myManager;
private final DockManager myDockManager;
private EditorWindow myWindow;
private EditorsSplitters myEditorsSplitters;
private ArrayList<VirtualFile> myHistory = new ArrayList<VirtualFile>();
private VirtualFile myModifiedFile = null;
private ToolWindowImpl myToolWindow;
private VirtualFile myAwaitingForOpen = null;
private ContentManager myContentManager;
private Content myStubContent;
private boolean myBlocked = false;
private EnumSet<ContentType> myTypes = EnumSet.noneOf(ContentType.class);
static boolean isAvailable() {
return UISettings.getInstance().NAVIGATE_TO_PREVIEW;
}
PreviewPanel(Project project, FileEditorManagerImpl manager, DockManager dockManager) {
myProject = project;
myManager = manager;
myDockManager = dockManager;
}
/*
* @return null if preview is not avalable
*/
@Nullable
EditorWindow getWindow() {
if (!isAvailable() || isBlocked() || myProject.isDisposed()) return null;
initToolWindowIfNeed();
return myWindow;
}
boolean isBlocked() {
return myBlocked;
}
private void initToolWindowIfNeed() {
if (!isAvailable() || ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW) != null) return;
myToolWindow = (ToolWindowImpl)ToolWindowManager.getInstance(myProject)
.registerToolWindow(ToolWindowId.PREVIEW, this, ToolWindowAnchor.RIGHT, myProject, false);
UISettings.getInstance().addUISettingsListener(new UISettingsListener() {
@Override
public void uiSettingsChanged(UISettings source) {
if (!isAvailable()) {
VirtualFile[] files = myWindow.getFiles();
for (VirtualFile file : files) {
close(file);
}
ToolWindowManager.getInstance(myProject).unregisterToolWindow(ToolWindowId.PREVIEW);
}
}
}, myProject);
myToolWindow.setIcon(AllIcons.Actions.PreviewDetails);
myToolWindow.setContentUiType(ToolWindowContentUiType.COMBO, null);
myContentManager = myToolWindow.getContentManager();
myStubContent = myContentManager.getContent(0);
myContentManager.addContentManagerListener(new ContentManagerAdapter() {
@Override
public void selectionChanged(ContentManagerEvent event) {
final VirtualFile file = event.getContent().getUserData(FILE_KEY);
if (event.getOperation() == ContentManagerEvent.ContentOperation.remove && file != null && file.equals(myModifiedFile)) {
close(file);
return;
}
if (event.getOperation() != ContentManagerEvent.ContentOperation.add) return;
if (file != null) {
event.getContent().setComponent(PreviewPanel.this);//Actually we share the same component between contents
if (!file.equals(myWindow.getSelectedFile())) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
myManager.openFileWithProviders(file, false, myWindow);
}
});
}
}
}
});
myEditorsSplitters = new MyEditorsSplitters();
myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER,
new FileEditorManagerListener.Before() {
@Override
public void beforeFileOpened(@NotNull FileEditorManager source,
@NotNull VirtualFile file) {
myAwaitingForOpen = file;
VirtualFile currentFile = getCurrentFile();
if (currentFile != null &&
currentFile.equals(myModifiedFile) &&
!currentFile.equals(file)) {
close(currentFile);
}
}
@Override
public void beforeFileClosed(@NotNull FileEditorManager source,
@NotNull VirtualFile file) {
checkStubContent();
}
});
myEditorsSplitters.createCurrentWindow();
myWindow = myEditorsSplitters.getCurrentWindow();
myWindow.setTabsPlacement(UISettings.TABS_NONE);
myLayout = new CardLayout();
setLayout(myLayout);
add(ContentType.Files.toString(), myEditorsSplitters);
//add(ContentType.Usages.toString(), myUsagesPreview);??? tree or editor ???
//add(ContentType.Diagrams.toString(), myDiagramPanel);
//add(ContentType.Documentation.toString(), myDocumentationPanel);//todo
myToolWindow.setTitleActions(new MoveToEditorTabsAction());
ArrayList<AnAction> myGearActions = new ArrayList<AnAction>();
for (ContentType contentType : ContentType.values()) {
myGearActions.add(new ContentTypeToggleAction(contentType));
}
myToolWindow.setAdditionalGearActions(new DefaultActionGroup("Preview", myGearActions));
myToolWindow.hide(null);
}
@Nullable
private VirtualFile getCurrentFile() {
VirtualFile[] files = myWindow.getFiles();
return files.length == 1 ? files[0] : null;
}
@NotNull
private Content addContent(VirtualFile file) {
myHistory.add(file);
while (myHistory.size() > HISTORY_LIMIT) {
myHistory.remove(0);
}
String title =
StringUtil.getShortened(EditorTabbedContainer.calcTabTitle(myProject, file), UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT);
Content content = myContentManager.getFactory().createContent(this, title, false);
content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
content.putUserData(FILE_KEY, file);
content.setIcon(file.getFileType().getIcon());
content.setPopupIcon(file.getFileType().getIcon());
myContentManager.addContent(content, 0);
checkStubContent();
return content;
}
private void setSelected(VirtualFile file) {
Content content = getContent(file);
if (content == null) {
content = addContent(file);
}
myContentManager.setSelectedContent(content);
myContentManager.addContent(content, 0);
}
@Nullable
private Content getContent(VirtualFile file) {
Content[] contents = myContentManager.getContents();
for (Content content : contents) {
if (file.equals(content.getUserData(FILE_KEY))) {
return content;
}
}
return null;
}
private void checkStubContent() {
if (myContentManager.getContents().length == 0) {
myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "false");
myStubContent.setComponent(this);
myContentManager.addContent(myStubContent);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (myContentManager.getIndexOfContent(myStubContent) != -1) {
toggleToolWindow(false);
}
}
});
}
else if (myContentManager.getContents().length > 1) {
myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true");
myContentManager.removeContent(myStubContent, false);
}
}
private void close(@NotNull VirtualFile file) {
myHistory.remove(file);
if (ArrayUtil.find(myEditorsSplitters.getOpenFiles(), file) != -1) {
myEditorsSplitters.closeFile(file, false);
}
if (file.equals(myAwaitingForOpen)) {
myAwaitingForOpen = null;
}
if (file.equals(myModifiedFile)) {
myBlocked = true;
try {
myManager.openFileWithProviders(myModifiedFile, false, true);
}
finally {
myBlocked = false;
}
myModifiedFile = null;
}
Content content = getContent(file);
if (content != null) {
myContentManager.removeContent(content, false);
checkStubContent();
}
}
private void toggleToolWindow(boolean activate) {
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW);
if (toolWindow != null) {
if (activate) {
toolWindow.activate(null, false);
}
else {
toolWindow.hide(null);
}
}
}
private class MoveToEditorTabsAction extends AnAction {
public MoveToEditorTabsAction() {
super("Move to main tabs", "Move to main tabs", AllIcons.Duplicates.SendToTheLeftGrayed);
}
@Override
public void actionPerformed(AnActionEvent e) {
VirtualFile virtualFile = getCurrentFile();
if (virtualFile == null) {
return;
}
EditorWindow window = myManager.getCurrentWindow();
if (window == null) { //main tab set is still not created, rare situation
myManager.getMainSplitters().createCurrentWindow();
window = myManager.getCurrentWindow();
}
myManager.openFileWithProviders(virtualFile, true, window);
close(virtualFile);
toggleToolWindow(false);
}
}
private class ContentTypeToggleAction extends ToggleAction {
private final ContentType myContentType;
ContentTypeToggleAction(ContentType contentType) {
super(contentType.toString());
myContentType = contentType;
}
@Override
public boolean isSelected(AnActionEvent e) {
return myTypes.contains(myContentType);
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
if (state) {
myTypes.add(myContentType);
} else {
myTypes.remove(myContentType);
}
}
}
private class MyEditorsSplitters extends EditorsSplitters {
public MyEditorsSplitters() {
super(myManager, myDockManager, false);
}
@Override
protected void afterFileOpen(VirtualFile file) {
if (file.equals(myAwaitingForOpen)) {
setSelected(file);
}
myAwaitingForOpen = null;
}
@Override
protected void afterFileClosed(VirtualFile file) {
close(file);
}
@Override
public void updateFileIcon(@NotNull VirtualFile file) {
EditorWithProviderComposite composite = myWindow.findFileComposite(file);
if (composite != null && composite.isModified()) {
myModifiedFile = file;
}
}
@Override
protected EditorWindow createEditorWindow() {
return new EditorWindow(this) {
@Override
protected void onBeforeSetEditor(VirtualFile file) {
VirtualFile currentFile = getCurrentFile();
if (currentFile != null && currentFile.equals(myModifiedFile)) {
myBlocked = true;
try {
myManager.openFileWithProviders(myModifiedFile, false, true);
}
finally {
myBlocked = false;
}
}
else {
toggleToolWindow(true);
}
}
};
}
@Override
public void setTabsPlacement(int tabPlacement) {
super.setTabsPlacement(UISettings.TABS_NONE);
}
@Override
public boolean isPreview() {
return true;
}
}
}