2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.openapi.fileEditor.impl;
18 import com.intellij.icons.AllIcons;
19 import com.intellij.ide.ui.UISettings;
20 import com.intellij.openapi.actionSystem.AnAction;
21 import com.intellij.openapi.actionSystem.AnActionEvent;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.fileEditor.FileEditorManager;
24 import com.intellij.openapi.fileEditor.FileEditorManagerListener;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.Key;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.openapi.vfs.VirtualFile;
29 import com.intellij.openapi.wm.*;
30 import com.intellij.openapi.wm.impl.ToolWindowImpl;
31 import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
32 import com.intellij.ui.content.Content;
33 import com.intellij.ui.content.ContentManager;
34 import com.intellij.ui.content.ContentManagerAdapter;
35 import com.intellij.ui.content.ContentManagerEvent;
36 import com.intellij.ui.docking.DockManager;
37 import com.intellij.util.ArrayUtil;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
43 import java.util.ArrayList;
45 class PreviewPanel extends JPanel {
46 private static final Key<VirtualFile> FILE_KEY = Key.create("v_file");
47 private static final int HISTORY_LIMIT = 10;
49 private final Project myProject;
50 private final FileEditorManagerImpl myManager;
51 private final DockManager myDockManager;
52 private EditorWindow myWindow;
53 private EditorsSplitters myEditorsSplitters;
54 private ArrayList<VirtualFile> myHistory = new ArrayList<VirtualFile>();
55 private VirtualFile myModifiedFile = null;
56 private ToolWindowImpl myToolWindow;
57 private VirtualFile myAwaitingForOpen = null;
58 private ContentManager myContentManager;
59 private Content myStubContent;
61 static boolean isAvailable() {
62 return UISettings.getInstance().NAVIGATE_TO_PREVIEW;
65 PreviewPanel(Project project, FileEditorManagerImpl manager, DockManager dockManager) {
68 myDockManager = dockManager;
71 // package-private API
73 EditorWindow getWindow() {
74 initToolWindowIfNeed();
78 boolean hasCurrentFile(@NotNull VirtualFile file) {
79 return file.equals(getCurrentFile());
83 VirtualFile getCurrentModifiedFile() {
84 VirtualFile file = getCurrentFile();
85 return file != null && file.equals(myModifiedFile) ? file : null;
88 private void initToolWindowIfNeed() {
89 if (ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW) != null) return;
91 myToolWindow = (ToolWindowImpl)ToolWindowManager.getInstance(myProject)
92 .registerToolWindow(ToolWindowId.PREVIEW, this, ToolWindowAnchor.RIGHT, myProject, false);
93 myToolWindow.setIcon(AllIcons.Actions.PreviewDetails);
94 myToolWindow.setContentUiType(ToolWindowContentUiType.COMBO, null);
95 myContentManager = myToolWindow.getContentManager();
96 myStubContent = myContentManager.getContent(0);
97 myContentManager.addContentManagerListener(new ContentManagerAdapter() {
99 public void selectionChanged(ContentManagerEvent event) {
100 final VirtualFile file = event.getContent().getUserData(FILE_KEY);
101 if (event.getOperation() == ContentManagerEvent.ContentOperation.remove && file != null && file.equals(myModifiedFile)) {
106 if (event.getOperation() != ContentManagerEvent.ContentOperation.add) return;
109 event.getContent().setComponent(PreviewPanel.this);//Actually we share the same component between contents
110 if (!file.equals(myWindow.getSelectedFile())) {
111 ApplicationManager.getApplication().invokeLater(new Runnable() {
114 myManager.openFileWithProviders(file, false, myWindow);
122 myEditorsSplitters = new MyEditorsSplitters();
124 myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER,
125 new FileEditorManagerListener.Before() {
127 public void beforeFileOpened(@NotNull FileEditorManager source,
128 @NotNull VirtualFile file) {
129 myAwaitingForOpen = file;
130 VirtualFile currentFile = getCurrentFile();
131 if (currentFile != null &&
132 currentFile.equals(myModifiedFile) &&
133 !currentFile.equals(file)) {
139 public void beforeFileClosed(@NotNull FileEditorManager source,
140 @NotNull VirtualFile file) {
144 myEditorsSplitters.createCurrentWindow();
145 myWindow = myEditorsSplitters.getCurrentWindow();
146 myWindow.setTabsPlacement(UISettings.TABS_NONE);
147 setLayout(new GridLayout(1, 1));
148 add(myEditorsSplitters);
149 myToolWindow.setTitleActions(new MoveToEditorTabsAction(), new CloseFileAction());
150 myToolWindow.hide(null);
154 private VirtualFile getCurrentFile() {
155 VirtualFile[] files = myWindow.getFiles();
156 return files.length == 1 ? files[0] : null;
160 private Content addContent(VirtualFile file) {
162 while (myHistory.size() > HISTORY_LIMIT) {
166 StringUtil.getShortened(EditorTabbedContainer.calcTabTitle(myProject, file), UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT);
168 Content content = myContentManager.getFactory().createContent(this, title, false);
169 content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
170 content.putUserData(FILE_KEY, file);
171 content.setIcon(file.getFileType().getIcon());
172 content.setPopupIcon(file.getFileType().getIcon());
174 myContentManager.addContent(content);
179 private void setSelected(VirtualFile file) {
180 Content content = getContent(file);
181 if (content == null) {
182 content = addContent(file);
184 myContentManager.setSelectedContent(content);
188 private Content getContent(VirtualFile file) {
189 Content[] contents = myContentManager.getContents();
190 for (Content content : contents) {
191 if (file.equals(content.getUserData(FILE_KEY))) {
198 private void checkStubContent() {
199 if (myContentManager.getContents().length == 0) {
200 myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "false");
201 myStubContent.setComponent(this);
202 myContentManager.addContent(myStubContent);
203 ApplicationManager.getApplication().invokeLater(new Runnable() {
206 if (myContentManager.getIndexOfContent(myStubContent) != -1) {
207 ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW).hide(null);
212 else if (myContentManager.getContents().length > 1) {
213 myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true");
214 myContentManager.removeContent(myStubContent, false);
218 private void close(@NotNull VirtualFile file) {
219 myHistory.remove(file);
220 if (ArrayUtil.find(myEditorsSplitters.getOpenFiles(), file) != -1) {
221 myEditorsSplitters.closeFile(file, false);
223 if (file.equals(myAwaitingForOpen)) {
224 myAwaitingForOpen = null;
226 if (file.equals(myModifiedFile)) {
227 myModifiedFile = null;
229 Content content = getContent(file);
230 if (content != null) {
231 myContentManager.removeContent(content, false);
236 private class MoveToEditorTabsAction extends AnAction {
237 public MoveToEditorTabsAction() {
238 super(null, "Move to main tabs", AllIcons.Duplicates.SendToTheLeftGrayed);
242 public void actionPerformed(AnActionEvent e) {
243 VirtualFile virtualFile = getCurrentFile();
244 if (virtualFile == null) {
248 EditorWindow window = myManager.getCurrentWindow();
249 if (window == null) { //main tab set is still not created, rare situation
250 myManager.getMainSplitters().createCurrentWindow();
251 window = myManager.getCurrentWindow();
253 myManager.openFileWithProviders(virtualFile, true, window);
255 ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW).hide(null);
260 private class CloseFileAction extends AnAction {
261 public CloseFileAction() {
262 super(null, "Close", AllIcons.Actions.Close);
266 public void actionPerformed(AnActionEvent e) {
267 for (VirtualFile file : myHistory.toArray(new VirtualFile[myHistory.size()])) {
273 private class MyEditorsSplitters extends EditorsSplitters {
274 public MyEditorsSplitters() {
275 super(myManager, myDockManager, false);
279 protected void afterFileOpen(VirtualFile file) {
280 if (file.equals(myAwaitingForOpen)) {
283 myAwaitingForOpen = null;
287 protected void afterFileClosed(VirtualFile file) {
292 public void updateFileIcon(@NotNull VirtualFile file) {
293 EditorWithProviderComposite composite = myWindow.findFileComposite(file);
294 if (composite != null && composite.isModified()) {
295 myModifiedFile = file;
300 public void setTabsPlacement(int tabPlacement) {
301 super.setTabsPlacement(UISettings.TABS_NONE);
305 public boolean isPreview() {