cleanup
[idea/community.git] / platform / platform-tests / testSrc / com / intellij / openapi / fileEditor / FileEditorManagerTest.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.fileEditor;
3
4 import com.intellij.ide.ui.UISettings;
5 import com.intellij.ide.ui.UISettingsState;
6 import com.intellij.mock.Mock;
7 import com.intellij.openapi.editor.*;
8 import com.intellij.openapi.fileEditor.impl.EditorWindow;
9 import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
10 import com.intellij.openapi.project.DumbAware;
11 import com.intellij.openapi.project.DumbServiceImpl;
12 import com.intellij.openapi.project.Project;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.intellij.pom.Navigatable;
15 import com.intellij.testFramework.EditorTestUtil;
16 import com.intellij.testFramework.FileEditorManagerTestCase;
17 import com.intellij.testFramework.PlatformTestUtil;
18 import com.intellij.util.containers.ContainerUtil;
19 import com.intellij.util.ui.UIUtil;
20 import org.jetbrains.annotations.NotNull;
21
22 import javax.swing.*;
23 import java.util.Arrays;
24 import java.util.List;
25
26 public class FileEditorManagerTest extends FileEditorManagerTestCase {
27   public void testTabOrder() throws Exception {
28
29     openFiles(STRING);
30     assertOpenFiles("1.txt", "foo.xml", "2.txt", "3.txt");
31   }
32
33   @Override
34   protected void tearDown() throws Exception {
35     try {
36       UISettingsState template = new UISettingsState();
37       UISettingsState uiSettings = UISettings.getInstance().getState();
38       uiSettings.setEditorTabLimit(template.getEditorTabLimit());
39       uiSettings.setReuseNotModifiedTabs(template.getReuseNotModifiedTabs());
40       uiSettings.setEditorTabPlacement(template.getEditorTabPlacement());
41     }
42     catch (Throwable e) {
43       addSuppressedException(e);
44     }
45     finally {
46       super.tearDown();
47     }
48   }
49
50   public void testTabLimit() throws Exception {
51     UISettings.getInstance().getState().setEditorTabLimit(2);
52     openFiles(STRING);
53     // note that foo.xml is pinned
54     assertOpenFiles("foo.xml", "3.txt");
55   }
56
57   public void testSingleTabLimit() throws Exception {
58     UISettings.getInstance().getState().setEditorTabLimit(1);
59     openFiles(STRING.replace("pinned=\"true\"", "pinned=\"false\""));
60     assertOpenFiles("3.txt");
61
62     myManager.closeAllFiles();
63
64     openFiles(STRING);
65     // note that foo.xml is pinned
66     assertOpenFiles("foo.xml");
67     myManager.openFile(getFile("/src/3.txt"), true);
68     assertOpenFiles("3.txt", "foo.xml");//limit is still 1 but pinned prevent closing tab and actual tab number may exceed the limit
69
70     myManager.closeAllFiles();
71
72     myManager.openFile(getFile("/src/3.txt"), true);
73     myManager.openFile(getFile("/src/foo.xml"), true);
74     assertOpenFiles("foo.xml");
75     callTrimToSize();
76     assertOpenFiles("foo.xml");
77   }
78
79   public void testReuseNotModifiedTabs() {
80     UISettingsState uiSettings = UISettings.getInstance().getState();
81     uiSettings.setEditorTabLimit(2);
82     uiSettings.setReuseNotModifiedTabs(false);
83
84     myManager.openFile(getFile("/src/3.txt"), true);
85     myManager.openFile(getFile("/src/foo.xml"), true);
86     assertOpenFiles("3.txt", "foo.xml");
87     uiSettings.setEditorTabLimit(1);
88     callTrimToSize();
89     assertOpenFiles("foo.xml");
90     uiSettings.setEditorTabLimit(2);
91
92     myManager.closeAllFiles();
93
94     uiSettings.setReuseNotModifiedTabs(true);
95     myManager.openFile(getFile("/src/3.txt"), true);
96     assertOpenFiles("3.txt");
97     myManager.openFile(getFile("/src/foo.xml"), true);
98     assertOpenFiles("foo.xml");
99   }
100
101   private void callTrimToSize() {
102     for (EditorsSplitters each : myManager.getAllSplitters()) {
103       each.trimToSize();
104     }
105   }
106
107   public void testOpenRecentEditorTab() throws Exception {
108     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint().registerExtension(new MyFileEditorProvider(), myFixture.getTestRootDisposable());
109
110     openFiles("  <component name=\"FileEditorManager\">\n" +
111               "    <leaf>\n" +
112               "      <file pinned=\"false\" current=\"true\" current-in-tab=\"true\">\n" +
113               "        <entry selected=\"true\" file=\"file://$PROJECT_DIR$/src/1.txt\">\n" +
114               "          <provider editor-type-id=\"mock\" selected=\"true\">\n" +
115               "            <state />\n" +
116               "          </provider>\n" +
117               "          <provider editor-type-id=\"text-editor\">\n" +
118               "            <state/>\n" +
119               "          </provider>\n" +
120               "        </entry>\n" +
121               "      </file>\n" +
122               "    </leaf>\n" +
123               "  </component>\n");
124     FileEditor[] selectedEditors = myManager.getSelectedEditors();
125     assertEquals(1, selectedEditors.length);
126     assertEquals("mockEditor", selectedEditors[0].getName());
127   }
128
129   public void testTrackSelectedEditor() {
130     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint().registerExtension(new MyFileEditorProvider(), myFixture.getTestRootDisposable());
131     VirtualFile file = getFile("/src/1.txt");
132     assertNotNull(file);
133     FileEditor[] editors = myManager.openFile(file, true);
134     assertEquals(2, editors.length);
135     assertEquals("Text", myManager.getSelectedEditor(file).getName());
136     myManager.setSelectedEditor(file, "mock");
137     assertEquals("mockEditor", myManager.getSelectedEditor(file).getName());
138
139     VirtualFile file1 = getFile("/src/2.txt");
140     myManager.openFile(file1, true);
141     assertEquals("mockEditor", myManager.getSelectedEditor(file).getName());
142   }
143
144   public void testWindowClosingRetainsOtherWindows() {
145     VirtualFile file = getFile("/src/1.txt");
146     assertNotNull(file);
147     myManager.openFile(file, false);
148     EditorWindow primaryWindow = myManager.getCurrentWindow();
149     assertNotNull(primaryWindow);
150     myManager.createSplitter(SwingConstants.VERTICAL, primaryWindow);
151     EditorWindow secondaryWindow = myManager.getNextWindow(primaryWindow);
152     assertNotNull(secondaryWindow);
153     myManager.createSplitter(SwingConstants.VERTICAL, secondaryWindow);
154     myManager.closeFile(file, primaryWindow);
155     assertEquals(2, myManager.getWindows().length);
156   }
157
158   public void testOpenFileInTablessSplitter() {
159     VirtualFile file1 = getFile("/src/1.txt");
160     assertNotNull(file1);
161     file1.putUserData(EditorWindow.INITIAL_INDEX_KEY, null);
162     myManager.openFile(file1, false);
163     VirtualFile file2 = getFile("/src/2.txt");
164     file2.putUserData(EditorWindow.INITIAL_INDEX_KEY, null);
165     assertNotNull(file2);
166     myManager.openFile(file2, true);
167     EditorWindow primaryWindow = myManager.getCurrentWindow();//1.txt and selected 2.txt
168     assertNotNull(primaryWindow);
169     myManager.createSplitter(SwingConstants.VERTICAL, primaryWindow);
170     EditorWindow secondaryWindow = myManager.getNextWindow(primaryWindow);//2.txt only, selected and focused
171     assertNotNull(secondaryWindow);
172     UISettings.getInstance().setEditorTabPlacement(UISettings.TABS_NONE);
173     myManager.openFileWithProviders(file1, true, true);//Here we have to ignore 'searchForSplitter'
174     assertEquals(2, primaryWindow.getTabCount());
175     assertEquals(2, secondaryWindow.getTabCount());
176     assertOrderedEquals(primaryWindow.getFiles(), file1, file2);
177     assertOrderedEquals(secondaryWindow.getFiles(), file2, file1);
178   }
179
180   public void testStoringCaretStateForFileWithFoldingsWithNoTabs() {
181     UISettings.getInstance().setEditorTabPlacement(UISettings.TABS_NONE);
182     VirtualFile file = getFile("/src/Test.java");
183     assertNotNull(file);
184     FileEditor[] editors = myManager.openFile(file, false);
185     assertEquals(1, editors.length);
186     assertTrue(editors[0] instanceof TextEditor);
187     Editor editor = ((TextEditor)editors[0]).getEditor();
188     EditorTestUtil.waitForLoading(editor);
189     final FoldingModel foldingModel = editor.getFoldingModel();
190     assertEquals(2, foldingModel.getAllFoldRegions().length);
191     foldingModel.runBatchFoldingOperation(() -> {
192       for (FoldRegion region : foldingModel.getAllFoldRegions()) {
193         region.setExpanded(false);
194       }
195     });
196     int textLength = editor.getDocument().getTextLength();
197     editor.getCaretModel().moveToOffset(textLength);
198     editor.getSelectionModel().setSelection(textLength - 1, textLength);
199
200     myManager.openFile(getFile("/src/1.txt"), false);
201     assertEquals(1, myManager.getEditors(file).length);
202     editors = myManager.openFile(file, false);
203
204     assertEquals(1, editors.length);
205     assertTrue(editors[0] instanceof TextEditor);
206     editor = ((TextEditor)editors[0]).getEditor();
207     EditorTestUtil.waitForLoading(editor);
208     assertEquals(textLength, editor.getCaretModel().getOffset());
209     assertEquals(textLength - 1, editor.getSelectionModel().getSelectionStart());
210     assertEquals(textLength, editor.getSelectionModel().getSelectionEnd());
211   }
212
213   public void testOpenInDumbMode() {
214     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint().registerExtension(new MyFileEditorProvider(), myFixture.getTestRootDisposable());
215     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint().registerExtension(new DumbAwareProvider(), myFixture.getTestRootDisposable());
216     try {
217       DumbServiceImpl.getInstance(getProject()).setDumb(true);
218       VirtualFile file = getFile("/src/foo.bar");
219       assertEquals(1, myManager.openFile(file, false).length);
220       DumbServiceImpl.getInstance(getProject()).setDumb(false);
221       UIUtil.dispatchAllInvocationEvents();
222       assertEquals(2, myManager.getAllEditors(file).length);
223       //assertFalse(FileEditorManagerImpl.isDumbAware(editors[0]));
224     }
225     finally {
226       DumbServiceImpl.getInstance(getProject()).setDumb(false);
227     }
228   }
229
230   public void testOpenSpecificTextEditor() {
231     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint()
232       .registerExtension(new MyTextEditorProvider("one", 1), myFixture.getTestRootDisposable());
233     FileEditorProvider.EP_FILE_EDITOR_PROVIDER.getPoint()
234       .registerExtension(new MyTextEditorProvider("two", 2), myFixture.getTestRootDisposable());
235     Project project = getProject();
236     VirtualFile file = getFile("/src/Test.java");
237     myManager.openTextEditor(new OpenFileDescriptor(project, file, 1), true);
238     assertEquals("one", myManager.getSelectedEditor(file).getName());
239     myManager.openTextEditor(new OpenFileDescriptor(project, file, 2), true);
240     assertEquals("two", myManager.getSelectedEditor(file).getName());
241   }
242
243   private static final String STRING = "<component name=\"FileEditorManager\">\n" +
244                                        "    <leaf>\n" +
245                                        "      <file pinned=\"false\" current=\"false\" current-in-tab=\"false\">\n" +
246                                        "        <entry file=\"file://$PROJECT_DIR$/src/1.txt\">\n" +
247                                        "          <provider selected=\"true\" editor-type-id=\"text-editor\">\n" +
248                                        "            <state line=\"0\" column=\"0\" selection-start=\"0\" selection-end=\"0\" vertical-scroll-proportion=\"0.0\">\n" +
249                                        "            </state>\n" +
250                                        "          </provider>\n" +
251                                        "        </entry>\n" +
252                                        "      </file>\n" +
253                                        "      <file pinned=\"true\" current=\"false\" current-in-tab=\"false\">\n" +
254                                        "        <entry file=\"file://$PROJECT_DIR$/src/foo.xml\">\n" +
255                                        "          <provider selected=\"true\" editor-type-id=\"text-editor\">\n" +
256                                        "            <state line=\"0\" column=\"0\" selection-start=\"0\" selection-end=\"0\" vertical-scroll-proportion=\"0.0\">\n" +
257                                        "            </state>\n" +
258                                        "          </provider>\n" +
259                                        "        </entry>\n" +
260                                        "      </file>\n" +
261                                        "      <file pinned=\"false\" current=\"true\" current-in-tab=\"true\">\n" +
262                                        "        <entry file=\"file://$PROJECT_DIR$/src/2.txt\">\n" +
263                                        "          <provider selected=\"true\" editor-type-id=\"text-editor\">\n" +
264                                        "            <state line=\"0\" column=\"0\" selection-start=\"0\" selection-end=\"0\" vertical-scroll-proportion=\"0.0\">\n" +
265                                        "            </state>\n" +
266                                        "          </provider>\n" +
267                                        "        </entry>\n" +
268                                        "      </file>\n" +
269                                        "      <file pinned=\"false\" current=\"false\" current-in-tab=\"false\">\n" +
270                                        "        <entry file=\"file://$PROJECT_DIR$/src/3.txt\">\n" +
271                                        "          <provider selected=\"true\" editor-type-id=\"text-editor\">\n" +
272                                        "            <state line=\"0\" column=\"0\" selection-start=\"0\" selection-end=\"0\" vertical-scroll-proportion=\"0.0\">\n" +
273                                        "            </state>\n" +
274                                        "          </provider>\n" +
275                                        "        </entry>\n" +
276                                        "      </file>\n" +
277                                        "    </leaf>\n" +
278                                        "  </component>\n";
279
280   private void assertOpenFiles(String... fileNames) {
281     List<String> names = ContainerUtil.map(myManager.getSplitters().getEditorComposites(), composite -> composite.getFile().getName());
282     assertEquals(Arrays.asList(fileNames), names);
283   }
284
285   @Override
286   protected String getTestDataPath() {
287     return PlatformTestUtil.getPlatformTestDataPath() + "fileEditorManager";
288   }
289
290   static class MyFileEditorProvider implements FileEditorProvider {
291     @NotNull
292     @Override
293     public String getEditorTypeId() {
294       return "mock";
295     }
296
297     @Override
298     public boolean accept(@NotNull Project project, @NotNull VirtualFile file) {
299       return true;
300     }
301
302     @NotNull
303     @Override
304     public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) {
305       return new Mock.MyFileEditor() {
306         @Override
307         public boolean isValid() {
308           return true;
309         }
310
311         @NotNull
312         @Override
313         public JComponent getComponent() {
314           return new JLabel();
315         }
316
317         @NotNull
318         @Override
319         public String getName() {
320           return "mockEditor";
321         }
322       };
323     }
324
325     @Override
326     public void disposeEditor(@NotNull FileEditor editor) {
327     }
328
329     @NotNull
330     @Override
331     public FileEditorPolicy getPolicy() {
332       return FileEditorPolicy.PLACE_AFTER_DEFAULT_EDITOR;
333     }
334   }
335
336   private static class DumbAwareProvider extends MyFileEditorProvider implements DumbAware {
337     @NotNull
338     @Override
339     public String getEditorTypeId() {
340       return "dumbAware";
341     }
342   }
343
344   private static final class MyTextEditorProvider implements FileEditorProvider, DumbAware {
345     private final String myId;
346     private final int myTargetOffset;
347
348     private MyTextEditorProvider(String id, int targetOffset) {
349       myId = id;
350       myTargetOffset = targetOffset;
351     }
352
353     @Override
354     public boolean accept(@NotNull Project project, @NotNull VirtualFile file) {
355       return true;
356     }
357
358     @NotNull
359     @Override
360     public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) {
361       return new MyTextEditor(FileDocumentManager.getInstance().getDocument(file), myId, myTargetOffset);
362     }
363
364     @NotNull
365     @Override
366     public String getEditorTypeId() {
367       return myId;
368     }
369
370     @NotNull
371     @Override
372     public FileEditorPolicy getPolicy() {
373       return FileEditorPolicy.HIDE_DEFAULT_EDITOR;
374     }
375   }
376
377   private static final class MyTextEditor extends Mock.MyFileEditor implements TextEditor {
378     private final Editor myEditor;
379     private final String myName;
380     private final int myTargetOffset;
381
382     private MyTextEditor(Document document, String name, int targetOffset) {
383       myEditor = EditorFactory.getInstance().createEditor(document);
384       myName = name;
385       myTargetOffset = targetOffset;
386     }
387
388     @Override
389     public void dispose() {
390       try {
391         EditorFactory.getInstance().releaseEditor(myEditor);
392       }
393       finally {
394         super.dispose();
395       }
396     }
397
398     @NotNull
399     @Override
400     public JComponent getComponent() {
401       return new JLabel();
402     }
403
404     @NotNull
405     @Override
406     public String getName() {
407       return myName;
408     }
409
410     @NotNull
411     @Override
412     public Editor getEditor() {
413       return myEditor;
414     }
415
416     @Override
417     public boolean canNavigateTo(@NotNull Navigatable navigatable) {
418       return navigatable instanceof OpenFileDescriptor && ((OpenFileDescriptor)navigatable).getOffset() == myTargetOffset;
419     }
420
421     @Override
422     public void navigateTo(@NotNull Navigatable navigatable) {}
423   }
424 }
425