2 * Copyright 2000-2009 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
.AppTopics
;
19 import com
.intellij
.ide
.IdeBundle
;
20 import com
.intellij
.ide
.plugins
.PluginManager
;
21 import com
.intellij
.ide
.ui
.UISettings
;
22 import com
.intellij
.ide
.ui
.UISettingsListener
;
23 import com
.intellij
.injected
.editor
.VirtualFileWindow
;
24 import com
.intellij
.openapi
.Disposable
;
25 import com
.intellij
.openapi
.application
.ApplicationManager
;
26 import com
.intellij
.openapi
.application
.ModalityState
;
27 import com
.intellij
.openapi
.application
.ex
.ApplicationManagerEx
;
28 import com
.intellij
.openapi
.application
.impl
.LaterInvocator
;
29 import com
.intellij
.openapi
.command
.CommandProcessor
;
30 import com
.intellij
.openapi
.components
.ProjectComponent
;
31 import com
.intellij
.openapi
.diagnostic
.Logger
;
32 import com
.intellij
.openapi
.editor
.Editor
;
33 import com
.intellij
.openapi
.editor
.ex
.EditorEx
;
34 import com
.intellij
.openapi
.fileEditor
.*;
35 import com
.intellij
.openapi
.fileEditor
.ex
.FileEditorManagerEx
;
36 import com
.intellij
.openapi
.fileEditor
.ex
.FileEditorProviderManager
;
37 import com
.intellij
.openapi
.fileEditor
.ex
.IdeDocumentHistory
;
38 import com
.intellij
.openapi
.fileEditor
.impl
.text
.TextEditorImpl
;
39 import com
.intellij
.openapi
.fileEditor
.impl
.text
.TextEditorProvider
;
40 import com
.intellij
.openapi
.fileTypes
.FileTypeEvent
;
41 import com
.intellij
.openapi
.fileTypes
.FileTypeListener
;
42 import com
.intellij
.openapi
.project
.DumbAware
;
43 import com
.intellij
.openapi
.project
.DumbAwareRunnable
;
44 import com
.intellij
.openapi
.project
.DumbService
;
45 import com
.intellij
.openapi
.project
.Project
;
46 import com
.intellij
.openapi
.project
.impl
.ProjectImpl
;
47 import com
.intellij
.openapi
.startup
.StartupManager
;
48 import com
.intellij
.openapi
.util
.*;
49 import com
.intellij
.openapi
.vcs
.FileStatus
;
50 import com
.intellij
.openapi
.vcs
.FileStatusListener
;
51 import com
.intellij
.openapi
.vcs
.FileStatusManager
;
52 import com
.intellij
.openapi
.vfs
.*;
53 import com
.intellij
.openapi
.wm
.ToolWindowManager
;
54 import com
.intellij
.openapi
.wm
.WindowManager
;
55 import com
.intellij
.openapi
.wm
.ex
.StatusBarEx
;
56 import com
.intellij
.openapi
.wm
.ex
.WindowManagerEx
;
57 import com
.intellij
.openapi
.wm
.impl
.FrameTitleBuilder
;
58 import com
.intellij
.openapi
.wm
.impl
.IdeFrameImpl
;
59 import com
.intellij
.util
.containers
.ContainerUtil
;
60 import com
.intellij
.util
.messages
.MessageBusConnection
;
61 import com
.intellij
.util
.messages
.impl
.MessageListenerList
;
62 import com
.intellij
.util
.ui
.update
.MergingUpdateQueue
;
63 import com
.intellij
.util
.ui
.update
.Update
;
64 import org
.jdom
.Element
;
65 import org
.jetbrains
.annotations
.NotNull
;
66 import org
.jetbrains
.annotations
.Nullable
;
70 import java
.beans
.PropertyChangeEvent
;
71 import java
.beans
.PropertyChangeListener
;
73 import java
.util
.ArrayList
;
74 import java
.util
.Arrays
;
75 import java
.util
.Collection
;
76 import java
.util
.List
;
79 * @author Anton Katilin
80 * @author Eugene Belyaev
81 * @author Vladimir Kondratyev
83 public class FileEditorManagerImpl
extends FileEditorManagerEx
implements ProjectComponent
, JDOMExternalizable
{
84 private static final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl");
85 private static final Key
<LocalFileSystem
.WatchRequest
> WATCH_REQUEST_KEY
= Key
.create("WATCH_REQUEST_KEY");
86 private static final Key
<Boolean
> DUMB_AWARE
= Key
.create("DUMB_AWARE");
88 private static final FileEditor
[] EMPTY_EDITOR_ARRAY
= {};
89 private static final FileEditorProvider
[] EMPTY_PROVIDER_ARRAY
= {};
91 private volatile JPanel myPanels
;
92 private EditorsSplitters mySplitters
;
93 private final Project myProject
;
95 private final MergingUpdateQueue myQueue
= new MergingUpdateQueue("FileEditorManagerUpdateQueue", 50, true, null);
98 * Removes invalid myEditor and updates "modified" status.
100 private final MyEditorPropertyChangeListener myEditorPropertyChangeListener
= new MyEditorPropertyChangeListener();
102 private final List
<EditorDataProvider
> myDataProviders
= new ArrayList
<EditorDataProvider
>();
104 public FileEditorManagerImpl(final Project project
) {
105 /* ApplicationManager.getApplication().assertIsDispatchThread(); */
107 myListenerList
= new MessageListenerList
<FileEditorManagerListener
>(myProject
.getMessageBus(), FileEditorManagerListener
.FILE_EDITOR_MANAGER
);
110 public static boolean isDumbAware(FileEditor editor
) {
111 return Boolean
.TRUE
.equals(editor
.getUserData(DUMB_AWARE
));
114 //-------------------------------------------------------------------------------
116 public JComponent
getComponent() {
121 public EditorsSplitters
getSplitters() {
126 private final Object myInitLock
= new Object();
127 private void initUI() {
128 if (myPanels
== null) {
129 synchronized (myInitLock
) {
130 if (myPanels
== null) {
131 myPanels
= new JPanel(new BorderLayout());
132 mySplitters
= new EditorsSplitters(this);
133 myPanels
.add(mySplitters
, BorderLayout
.CENTER
);
139 public JComponent
getPreferredFocusedComponent() {
141 final EditorWindow window
= getSplitters().getCurrentWindow();
142 if (window
!= null) {
143 final EditorWithProviderComposite editor
= window
.getSelectedEditor();
144 if (editor
!= null) {
145 return editor
.getPreferredFocusedComponent();
151 //-------------------------------------------------------
154 * @return color of the <code>file</code> which corresponds to the
157 public Color
getFileColor(@NotNull final VirtualFile file
) {
158 final FileStatusManager fileStatusManager
= FileStatusManager
.getInstance(myProject
);
159 Color statusColor
= fileStatusManager
!= null ? fileStatusManager
.getStatus(file
).getColor() : Color
.BLACK
;
160 if (statusColor
== null) statusColor
= Color
.BLACK
;
164 public boolean isProblem(@NotNull final VirtualFile file
) {
168 public String
getFileTooltipText(VirtualFile file
) {
169 return file
.getPresentableUrl();
172 public void updateFilePresentation(VirtualFile file
) {
173 if (!isFileOpen(file
)) return;
175 updateFileColor(file
);
176 updateFileIcon(file
);
177 updateFileName(file
);
178 updateFileBackgroundColor(file
);
182 * Updates tab color for the specified <code>file</code>. The <code>file</code>
183 * should be opened in the myEditor, otherwise the method throws an assertion.
185 private void updateFileColor(final VirtualFile file
) {
186 getSplitters().updateFileColor(file
);
189 private void updateFileBackgroundColor(final VirtualFile file
) {
190 getSplitters().updateFileBackgroundColor(file
);
194 * Updates tab icon for the specified <code>file</code>. The <code>file</code>
195 * should be opened in the myEditor, otherwise the method throws an assertion.
197 protected void updateFileIcon(final VirtualFile file
) {
198 getSplitters().updateFileIcon(file
);
202 * Updates tab title and tab tool tip for the specified <code>file</code>
204 void updateFileName(@Nullable final VirtualFile file
) {
205 // Queue here is to prevent title flickering when tab is being closed and two events arriving: with component==null and component==next focused tab
206 // only the last event makes sense to handle
207 myQueue
.queue(new Update("UpdateFileName "+(file
==null?
"":file
.getPath())) {
208 public boolean isExpired() {
209 return myProject
.isDisposed() || !myProject
.isOpen() || (file
== null ?
super.isExpired() : !file
.isValid());
213 final WindowManagerEx windowManagerEx
= WindowManagerEx
.getInstanceEx();
214 final IdeFrameImpl frame
= windowManagerEx
.getFrame(myProject
);
215 LOG
.assertTrue(frame
!= null);
216 getSplitters().updateFileName(file
);
217 File ioFile
= file
== null ?
null : new File(file
.getPresentableUrl());
218 frame
.setFileTitle(file
== null ?
null : FrameTitleBuilder
.getInstance().getFileTitle(myProject
, file
), ioFile
);
223 //-------------------------------------------------------
226 public VirtualFile
getFile(@NotNull final FileEditor editor
) {
227 final EditorComposite editorComposite
= getEditorComposite(editor
);
228 if (editorComposite
!= null) {
229 return editorComposite
.getFile();
234 public void unsplitWindow() {
235 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
236 if (currentWindow
!= null) {
237 currentWindow
.unsplit(true);
241 public void unsplitAllWindow() {
242 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
243 if (currentWindow
!= null) {
244 currentWindow
.unsplitAll();
249 public EditorWindow
[] getWindows() {
250 return getSplitters().getWindows();
253 public EditorWindow
getNextWindow(@NotNull final EditorWindow window
) {
254 final EditorWindow
[] windows
= getSplitters().getOrderedWindows();
255 for (int i
= 0; i
!= windows
.length
; ++i
) {
256 if (windows
[i
].equals(window
)) {
257 return windows
[(i
+ 1) % windows
.length
];
260 LOG
.error("Not window found");
264 public EditorWindow
getPrevWindow(@NotNull final EditorWindow window
) {
265 final EditorWindow
[] windows
= getSplitters().getOrderedWindows();
266 for (int i
= 0; i
!= windows
.length
; ++i
) {
267 if (windows
[i
].equals(window
)) {
268 return windows
[(i
+ windows
.length
- 1) % windows
.length
];
271 LOG
.error("Not window found");
275 public void createSplitter(final int orientation
, @Nullable final EditorWindow window
) {
276 // window was available from action event, for example when invoked from the tab menu of an editor that is not the 'current'
277 if (window
!= null) {
278 window
.split(orientation
);
280 // otherwise we'll split the current window, if any
282 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
283 if (currentWindow
!= null) {
284 currentWindow
.split(orientation
);
289 public void changeSplitterOrientation() {
290 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
291 if (currentWindow
!= null) {
292 currentWindow
.changeOrientation();
297 public void flipTabs() {
299 if (myTabs == null) {
300 myTabs = new EditorTabs (this, UISettings.getInstance().EDITOR_TAB_PLACEMENT);
301 remove (mySplitters);
302 add (myTabs, BorderLayout.CENTER);
306 add (mySplitters, BorderLayout.CENTER);
311 myPanels
.revalidate();
314 public boolean tabsMode() {
318 private void setTabsMode(final boolean mode
) {
319 if (tabsMode() != mode
) {
322 //LOG.assertTrue (tabsMode () == mode);
326 public boolean isInSplitter() {
327 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
328 return currentWindow
!= null && currentWindow
.inSplitter();
331 public boolean hasOpenedFile() {
332 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
333 return currentWindow
!= null && currentWindow
.getSelectedEditor() != null;
336 public VirtualFile
getCurrentFile() {
337 return getSplitters().getCurrentFile();
340 public EditorWindow
getCurrentWindow() {
341 return getSplitters().getCurrentWindow();
344 public void setCurrentWindow(final EditorWindow window
) {
345 getSplitters().setCurrentWindow(window
, true);
348 public void closeFile(@NotNull final VirtualFile file
, @NotNull final EditorWindow window
) {
349 assertDispatchThread();
351 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
353 if (window
.isFileOpen(file
)) {
354 window
.closeFile(file
);
355 final List
<EditorWindow
> windows
= getSplitters().findWindows(file
);
356 if (windows
.isEmpty()) { // no more windows containing this file left
357 final LocalFileSystem
.WatchRequest request
= file
.getUserData(WATCH_REQUEST_KEY
);
358 if (request
!= null) {
359 LocalFileSystem
.getInstance().removeWatchedRoot(request
);
364 }, IdeBundle
.message("command.close.active.editor"), null);
367 //============================= EditorManager methods ================================
369 public void closeFile(@NotNull final VirtualFile file
) {
370 closeFile(file
, true);
373 public void closeFile(@NotNull final VirtualFile file
, final boolean moveFocus
) {
374 assertDispatchThread();
376 final LocalFileSystem
.WatchRequest request
= file
.getUserData(WATCH_REQUEST_KEY
);
377 if (request
!= null) {
378 LocalFileSystem
.getInstance().removeWatchedRoot(request
);
381 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
383 closeFileImpl(file
, moveFocus
);
389 private VirtualFile
findNextFile(final VirtualFile file
) {
390 final EditorWindow
[] windows
= getWindows(); // TODO: use current file as base
391 for (int i
= 0; i
!= windows
.length
; ++ i
) {
392 final VirtualFile
[] files
= windows
[i
].getFiles();
393 for (final VirtualFile fileAt
: files
) {
394 if (fileAt
!= file
) {
402 private void closeFileImpl(@NotNull final VirtualFile file
, final boolean moveFocus
) {
403 assertDispatchThread();
404 getSplitters().runChange(new Runnable() {
406 final List
<EditorWindow
> windows
= getSplitters().findWindows(file
);
407 if (!windows
.isEmpty()) {
408 final VirtualFile nextFile
= findNextFile(file
);
409 for (final EditorWindow window
: windows
) {
410 LOG
.assertTrue(window
.getSelectedEditor() != null);
411 window
.closeFile(file
, false, moveFocus
);
412 if (window
.getTabCount() == 0 && nextFile
!= null) {
413 EditorWithProviderComposite newComposite
= newEditorComposite(nextFile
);
414 window
.setEditor(newComposite
, moveFocus
); // newComposite can be null
417 // cleanup windows with no tabs
418 for (final EditorWindow window
: windows
) {
419 if (window
.isDisposed()) {
420 // call to window.unsplit() which might make its sibling disposed
423 if (window
.getTabCount() == 0) {
424 window
.unsplit(false);
432 //-------------------------------------- Open File ----------------------------------------
434 @NotNull public Pair
<FileEditor
[], FileEditorProvider
[]> openFileWithProviders(@NotNull final VirtualFile file
, final boolean focusEditor
) {
435 if (!file
.isValid()) {
436 throw new IllegalArgumentException("file is not valid: " + file
);
438 assertDispatchThread();
439 return openFileImpl2(getSplitters().getOrCreateCurrentWindow(file
), file
, focusEditor
, null);
442 @NotNull Pair
<FileEditor
[], FileEditorProvider
[]> openFileImpl2(final EditorWindow window
, final VirtualFile file
, final boolean focusEditor
,
443 final HistoryEntry entry
) {
444 final Ref
<Pair
<FileEditor
[], FileEditorProvider
[]>> resHolder
= new Ref
<Pair
<FileEditor
[], FileEditorProvider
[]>>();
445 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
447 resHolder
.set(openFileImpl3(window
, file
, focusEditor
, entry
, true));
450 return resHolder
.get();
454 * @param file to be opened. Unlike openFile method, file can be
455 * invalid. For example, all file were invalidate and they are being
456 * removed one by one. If we have removed one invalid file, then another
457 * invalid file become selected. That's why we do not require that
458 * passed file is valid.
459 * @param entry map between FileEditorProvider and FileEditorState. If this parameter
462 @NotNull Pair
<FileEditor
[], FileEditorProvider
[]> openFileImpl3(final EditorWindow window
,
463 @NotNull final VirtualFile file
,
464 final boolean focusEditor
,
465 final HistoryEntry entry
,
468 FileEditor
[] editors
;
469 FileEditorProvider
[] providers
;
470 final EditorWithProviderComposite newSelectedComposite
;
471 boolean newEditorCreated
= false;
473 final boolean open
= window
.isFileOpen(file
);
475 // File is already opened. In this case we have to just select existing EditorComposite
476 newSelectedComposite
= window
.findFileComposite(file
);
477 LOG
.assertTrue(newSelectedComposite
!= null);
479 editors
= newSelectedComposite
.getEditors();
480 providers
= newSelectedComposite
.getProviders();
483 // File is not opened yet. In this case we have to create editors
484 // and select the created EditorComposite.
485 final FileEditorProviderManager editorProviderManager
= FileEditorProviderManager
.getInstance();
486 providers
= editorProviderManager
.getProviders(myProject
, file
);
487 if (DumbService
.getInstance(myProject
).isDumb()) {
488 final List
<FileEditorProvider
> dumbAware
= ContainerUtil
.findAll(providers
, new Condition
<FileEditorProvider
>() {
489 public boolean value(FileEditorProvider fileEditorProvider
) {
490 return fileEditorProvider
instanceof DumbAware
;
493 providers
= dumbAware
.toArray(new FileEditorProvider
[dumbAware
.size()]);
496 if (providers
.length
== 0) {
497 return Pair
.create(EMPTY_EDITOR_ARRAY
, EMPTY_PROVIDER_ARRAY
);
499 newEditorCreated
= true;
501 getProject().getMessageBus().syncPublisher(FileEditorManagerListener
.Before
.FILE_EDITOR_MANAGER
).beforeFileOpened(this, file
);
503 editors
= new FileEditor
[providers
.length
];
504 for (int i
= 0; i
< providers
.length
; i
++) {
506 final FileEditorProvider provider
= providers
[i
];
507 LOG
.assertTrue(provider
!= null);
508 LOG
.assertTrue(provider
.accept(myProject
, file
));
509 final FileEditor editor
= provider
.createEditor(myProject
, file
);
510 LOG
.assertTrue(editor
!= null);
511 LOG
.assertTrue(editor
.isValid());
513 // Register PropertyChangeListener into editor
514 editor
.addPropertyChangeListener(myEditorPropertyChangeListener
);
515 editor
.putUserData(DUMB_AWARE
, provider
instanceof DumbAware
);
517 if (current
&& editor
instanceof TextEditorImpl
) {
518 ((TextEditorImpl
)editor
).initFolding();
521 catch (Exception e
) {
524 catch (AssertionError e
) {
529 // Now we have to create EditorComposite and insert it into the TabbedEditorComponent.
530 // After that we have to select opened editor.
531 newSelectedComposite
= new EditorWithProviderComposite(file
, editors
, providers
, this);
534 window
.setEditor(newSelectedComposite
, focusEditor
);
536 final EditorHistoryManager editorHistoryManager
= EditorHistoryManager
.getInstance(myProject
);
537 for (int i
= 0; i
< editors
.length
; i
++) {
538 final FileEditor editor
= editors
[i
];
539 if (editor
instanceof TextEditor
) {
541 // This code prevents "jumping" on next repaint.
542 ((EditorEx
)((TextEditor
)editor
).getEditor()).stopOptimizedScrolling();
545 final FileEditorProvider provider
= providers
[i
];//getProvider(editor);
547 // Restore editor state
548 FileEditorState state
= null;
550 state
= entry
.getState(provider
);
552 if (state
== null && !open
) {
553 // We have to try to get state from the history only in case
554 // if editor is not opened. Otherwise history enty might have a state
555 // out of sync with the current editor state.
556 state
= editorHistoryManager
.getState(file
, provider
);
559 editor
.setState(state
);
563 // Restore selected editor
564 final FileEditorProvider selectedProvider
= editorHistoryManager
.getSelectedProvider(file
);
565 if (selectedProvider
!= null) {
566 final FileEditor
[] _editors
= newSelectedComposite
.getEditors();
567 final FileEditorProvider
[] _providers
= newSelectedComposite
.getProviders();
568 for (int i
= _editors
.length
- 1; i
>= 0; i
--) {
569 final FileEditorProvider provider
= _providers
[i
];//getProvider(_editors[i]);
570 if (provider
.equals(selectedProvider
)) {
571 newSelectedComposite
.setSelectedEditor(i
);
577 // Notify editors about selection changes
578 getSplitters().setCurrentWindow(window
, false);
579 newSelectedComposite
.getSelectedEditor().selectNotify();
581 if (newEditorCreated
) {
582 getProject().getMessageBus().syncPublisher(FileEditorManagerListener
.FILE_EDITOR_MANAGER
).fileOpened(this, file
);
584 //Add request to watch this editor's virtual file
585 final VirtualFile parentDir
= file
.getParent();
586 if (parentDir
!= null) {
587 final LocalFileSystem
.WatchRequest request
= LocalFileSystem
.getInstance().addRootToWatch(parentDir
.getPath(), false);
588 file
.putUserData(WATCH_REQUEST_KEY
, request
);
592 //[jeka] this is a hack to support back-forward navigation
593 // previously here was incorrect call to fireSelectionChanged() with a side-effect
594 ((IdeDocumentHistoryImpl
)IdeDocumentHistory
.getInstance(myProject
)).onSelectionChanged();
596 // Transfer focus into editor
597 if (!ApplicationManagerEx
.getApplicationEx().isUnitTestMode()) {
599 //myFirstIsActive = myTabbedContainer1.equals(tabbedContainer);
600 window
.setAsCurrentWindow(false);
601 ToolWindowManager
.getInstance(myProject
).activateEditorComponent();
605 // Update frame and tab title
606 updateFileName(file
);
608 // Make back/forward work
609 IdeDocumentHistory
.getInstance(myProject
).includeCurrentCommandAsNavigation();
611 return Pair
.create(editors
, providers
);
614 private void setSelectedEditor(VirtualFile file
, String fileEditorProviderId
) {
615 EditorWithProviderComposite composite
= getCurrentEditorWithProviderComposite(file
);
616 if (composite
== null) {
617 final List
<EditorWithProviderComposite
> composites
= getEditorComposites(file
);
619 if (composites
.isEmpty()) return;
620 composite
= composites
.get(0);
623 final FileEditorProvider
[] editorProviders
= composite
.getProviders();
624 final FileEditorProvider selectedProvider
= composite
.getSelectedEditorWithProvider().getSecond();
626 for (int i
= 0; i
< editorProviders
.length
; i
++) {
627 if (editorProviders
[i
].getEditorTypeId().equals(fileEditorProviderId
) && !selectedProvider
.equals(editorProviders
[i
])) {
628 composite
.setSelectedEditor(i
);
629 composite
.getSelectedEditor().selectNotify();
635 private EditorWithProviderComposite
newEditorComposite(final VirtualFile file
) {
640 final FileEditorProviderManager editorProviderManager
= FileEditorProviderManager
.getInstance();
641 final FileEditorProvider
[] providers
= editorProviderManager
.getProviders(myProject
, file
);
642 final FileEditor
[] editors
= new FileEditor
[providers
.length
];
643 for (int i
= 0; i
< providers
.length
; i
++) {
644 final FileEditorProvider provider
= providers
[i
];
645 LOG
.assertTrue(provider
!= null);
646 LOG
.assertTrue(provider
.accept(myProject
, file
));
647 final FileEditor editor
= provider
.createEditor(myProject
, file
);
649 LOG
.assertTrue(editor
.isValid());
650 editor
.addPropertyChangeListener(myEditorPropertyChangeListener
);
653 final EditorWithProviderComposite newComposite
= new EditorWithProviderComposite(file
, editors
, providers
, this);
654 final EditorHistoryManager editorHistoryManager
= EditorHistoryManager
.getInstance(myProject
);
655 for (int i
= 0; i
< editors
.length
; i
++) {
656 final FileEditor editor
= editors
[i
];
657 if (editor
instanceof TextEditor
) {
659 // This code prevents "jumping" on next repaint.
660 //((EditorEx)((TextEditor)editor).getEditor()).stopOptimizedScrolling();
663 final FileEditorProvider provider
= providers
[i
];
665 // Restore myEditor state
666 FileEditorState state
= editorHistoryManager
.getState(file
, provider
);
668 editor
.setState(state
);
675 public List
<FileEditor
> openEditor(@NotNull final OpenFileDescriptor descriptor
, final boolean focusEditor
) {
676 assertDispatchThread();
677 if (descriptor
.getFile() instanceof VirtualFileWindow
) {
678 VirtualFileWindow delegate
= (VirtualFileWindow
)descriptor
.getFile();
679 int hostOffset
= delegate
.getDocumentWindow().injectedToHost(descriptor
.getOffset());
680 OpenFileDescriptor realDescriptor
= new OpenFileDescriptor(descriptor
.getProject(), delegate
.getDelegate(), hostOffset
);
681 return openEditor(realDescriptor
, focusEditor
);
684 final List
<FileEditor
> result
= new ArrayList
<FileEditor
>();
685 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
687 VirtualFile file
= descriptor
.getFile();
688 final FileEditor
[] editors
= openFile(file
, focusEditor
);
689 result
.addAll(Arrays
.asList(editors
));
691 boolean navigated
= false;
692 for (final FileEditor editor
: editors
) {
693 if (editor
instanceof NavigatableFileEditor
&& getSelectedEditor(descriptor
.getFile()) == editor
) { // try to navigate opened editor
694 navigated
= navigateAndSelectEditor((NavigatableFileEditor
) editor
, descriptor
);
695 if (navigated
) break;
700 for (final FileEditor editor
: editors
) {
701 if (editor
instanceof NavigatableFileEditor
&& getSelectedEditor(descriptor
.getFile()) != editor
) { // try other editors
702 if (navigateAndSelectEditor((NavigatableFileEditor
) editor
, descriptor
)) {
714 private boolean navigateAndSelectEditor(final NavigatableFileEditor editor
, final OpenFileDescriptor descriptor
) {
715 if (editor
.canNavigateTo(descriptor
)) {
716 setSelectedEditor(editor
);
717 editor
.navigateTo(descriptor
);
724 private void setSelectedEditor(final FileEditor editor
) {
725 final EditorWithProviderComposite composite
= getEditorComposite(editor
);
726 if (composite
== null) return;
728 final FileEditor
[] editors
= composite
.getEditors();
729 for (int i
= 0; i
< editors
.length
; i
++) {
730 final FileEditor each
= editors
[i
];
731 if (editor
== each
) {
732 composite
.setSelectedEditor(i
);
733 composite
.getSelectedEditor().selectNotify();
740 public Project
getProject() {
744 public void registerExtraEditorDataProvider(@NotNull final EditorDataProvider provider
, Disposable parentDisposable
) {
745 myDataProviders
.add(provider
);
746 if (parentDisposable
!= null) {
747 Disposer
.register(parentDisposable
, new Disposable() {
748 public void dispose() {
749 myDataProviders
.remove(provider
);
756 public final Object
getData(String dataId
, Editor editor
, final VirtualFile file
) {
757 for (final EditorDataProvider dataProvider
: myDataProviders
) {
758 final Object o
= dataProvider
.getData(dataId
, editor
, file
);
759 if (o
!= null) return o
;
765 public Editor
openTextEditor(final OpenFileDescriptor descriptor
, final boolean focusEditor
) {
766 final Collection
<FileEditor
> fileEditors
= openEditor(descriptor
, focusEditor
);
767 for (FileEditor fileEditor
: fileEditors
) {
768 if (fileEditor
instanceof TextEditor
) {
769 setSelectedEditor(descriptor
.getFile(), TextEditorProvider
.getInstance().getEditorTypeId());
770 Editor editor
= ((TextEditor
)fileEditor
).getEditor();
771 return getOpenedEditor(editor
, focusEditor
);
778 protected Editor
getOpenedEditor(final Editor editor
, final boolean focusEditor
) {
782 public Editor
getSelectedTextEditor() {
785 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
786 if (currentWindow
!= null) {
787 final EditorWithProviderComposite selectedEditor
= currentWindow
.getSelectedEditor();
788 if (selectedEditor
!= null && selectedEditor
.getSelectedEditor() instanceof TextEditor
) {
789 return ((TextEditor
)selectedEditor
.getSelectedEditor()).getEditor();
797 public boolean isFileOpen(@NotNull final VirtualFile file
) {
798 return getEditors(file
).length
!= 0;
802 public VirtualFile
[] getOpenFiles() {
803 return getSplitters().getOpenFiles();
807 public VirtualFile
[] getSelectedFiles() {
808 return getSplitters().getSelectedFiles();
812 public FileEditor
[] getSelectedEditors() {
813 return getSplitters().getSelectedEditors();
816 public FileEditor
getSelectedEditor(@NotNull final VirtualFile file
) {
817 final Pair
<FileEditor
, FileEditorProvider
> selectedEditorWithProvider
= getSelectedEditorWithProvider(file
);
818 return selectedEditorWithProvider
== null ?
null : selectedEditorWithProvider
.getFirst();
822 public Pair
<FileEditor
, FileEditorProvider
> getSelectedEditorWithProvider(@NotNull VirtualFile file
) {
823 if (file
instanceof VirtualFileWindow
) file
= ((VirtualFileWindow
)file
).getDelegate();
824 final EditorWithProviderComposite composite
= getCurrentEditorWithProviderComposite(file
);
825 if (composite
!= null) {
826 return composite
.getSelectedEditorWithProvider();
829 final List
<EditorWithProviderComposite
> composites
= getEditorComposites(file
);
830 return composites
.isEmpty() ?
null : composites
.get(0).getSelectedEditorWithProvider();
834 public Pair
<FileEditor
[], FileEditorProvider
[]> getEditorsWithProviders(@NotNull final VirtualFile file
) {
837 final EditorWithProviderComposite composite
= getCurrentEditorWithProviderComposite(file
);
838 if (composite
!= null) {
839 return Pair
.create(composite
.getEditors(), composite
.getProviders());
842 final List
<EditorWithProviderComposite
> composites
= getEditorComposites(file
);
843 if (!composites
.isEmpty()) {
844 return Pair
.create(composites
.get(0).getEditors(), composites
.get(0).getProviders());
847 return Pair
.create(EMPTY_EDITOR_ARRAY
, EMPTY_PROVIDER_ARRAY
);
852 public FileEditor
[] getEditors(@NotNull VirtualFile file
) {
854 if (file
instanceof VirtualFileWindow
) file
= ((VirtualFileWindow
)file
).getDelegate();
856 final EditorWithProviderComposite composite
= getCurrentEditorWithProviderComposite(file
);
857 if (composite
!= null) {
858 return composite
.getEditors();
861 final List
<EditorWithProviderComposite
> composites
= getEditorComposites(file
);
862 if (!composites
.isEmpty()) {
863 return composites
.get(0).getEditors();
866 return EMPTY_EDITOR_ARRAY
;
872 public FileEditor
[] getAllEditors(@NotNull VirtualFile file
) {
873 List
<EditorWithProviderComposite
> editorComposites
= getEditorComposites(file
);
874 List
<FileEditor
> editors
= new ArrayList
<FileEditor
>();
875 for (EditorWithProviderComposite composite
: editorComposites
) {
876 editors
.addAll(Arrays
.asList(composite
.getEditors()));
878 return editors
.toArray(new FileEditor
[editors
.size()]);
882 private EditorWithProviderComposite
getCurrentEditorWithProviderComposite(@NotNull final VirtualFile virtualFile
) {
883 final EditorWindow editorWindow
= getSplitters().getCurrentWindow();
884 if (editorWindow
!= null) {
885 return editorWindow
.findFileComposite(virtualFile
);
891 public List
<EditorWithProviderComposite
> getEditorComposites(final VirtualFile file
) {
892 return getSplitters().findEditorComposites(file
);
896 public FileEditor
[] getAllEditors() {
898 final ArrayList
<FileEditor
> result
= new ArrayList
<FileEditor
>();
899 final EditorWithProviderComposite
[] editorsComposites
= getSplitters().getEditorsComposites();
900 for (EditorWithProviderComposite editorsComposite
: editorsComposites
) {
901 final FileEditor
[] editors
= editorsComposite
.getEditors();
902 result
.addAll(Arrays
.asList(editors
));
904 return result
.toArray(new FileEditor
[result
.size()]);
907 public void showEditorAnnotation(@NotNull FileEditor editor
, @NotNull JComponent annotationComponent
) {
908 final EditorComposite composite
= getEditorComposite(editor
);
909 if (composite
!= null) {
910 composite
.getPane(editor
).addInfo(annotationComponent
);
914 public void removeEditorAnnotation(@NotNull FileEditor editor
, @NotNull JComponent annotationComponent
) {
915 final EditorComposite composite
= getEditorComposite(editor
);
916 if (composite
!= null) {
917 composite
.getPane(editor
).removeInfo(annotationComponent
);
921 public void addTopComponent(@NotNull final FileEditor editor
, @NotNull final JComponent component
) {
922 final EditorComposite composite
= getEditorComposite(editor
);
923 if (composite
!= null) {
924 composite
.addTopComponent(editor
, component
);
928 public void removeTopComponent(@NotNull final FileEditor editor
, @NotNull final JComponent component
) {
929 final EditorComposite composite
= getEditorComposite(editor
);
930 if (composite
!= null) {
931 composite
.removeTopComponent(editor
, component
);
935 public void addBottomComponent(@NotNull final FileEditor editor
, @NotNull final JComponent component
) {
936 final EditorComposite composite
= getEditorComposite(editor
);
937 if (composite
!= null) {
938 composite
.addBottomComponent(editor
, component
);
942 public void removeBottomComponent(@NotNull final FileEditor editor
, @NotNull final JComponent component
) {
943 final EditorComposite composite
= getEditorComposite(editor
);
944 if (composite
!= null) {
945 composite
.removeBottomComponent(editor
, component
);
949 private final MessageListenerList
<FileEditorManagerListener
> myListenerList
;
951 public void addFileEditorManagerListener(@NotNull final FileEditorManagerListener listener
) {
952 myListenerList
.add(listener
);
955 public void addFileEditorManagerListener(@NotNull final FileEditorManagerListener listener
, final Disposable parentDisposable
) {
956 myListenerList
.add(listener
, parentDisposable
);
959 public void removeFileEditorManagerListener(@NotNull final FileEditorManagerListener listener
) {
960 myListenerList
.remove(listener
);
963 // ProjectComponent methods
965 public void projectOpened() {
966 //myFocusWatcher.install(myWindows.getComponent ());
967 getSplitters().startListeningFocus();
969 MessageBusConnection connection
= myProject
.getMessageBus().connect(myProject
);
971 final FileStatusManager fileStatusManager
= FileStatusManager
.getInstance(myProject
);
972 if (fileStatusManager
!= null) {
974 * Updates tabs colors
976 final MyFileStatusListener myFileStatusListener
= new MyFileStatusListener();
977 fileStatusManager
.addFileStatusListener(myFileStatusListener
, myProject
);
979 connection
.subscribe(AppTopics
.FILE_TYPES
, new MyFileTypeListener());
983 final MyVirtualFileListener myVirtualFileListener
= new MyVirtualFileListener();
984 VirtualFileManager
.getInstance().addVirtualFileListener(myVirtualFileListener
, myProject
);
986 * Extends/cuts number of opened tabs. Also updates location of tabs.
988 final MyUISettingsListener myUISettingsListener
= new MyUISettingsListener();
989 UISettings
.getInstance().addUISettingsListener(myUISettingsListener
);
990 Disposer
.register(myProject
, new Disposable() {
991 public void dispose() {
992 UISettings
.getInstance().removeUISettingsListener(myUISettingsListener
);
996 StartupManager
.getInstance(myProject
).registerPostStartupActivity(new DumbAwareRunnable() {
998 ToolWindowManager
.getInstance(myProject
).invokeLater(new Runnable() {
1000 CommandProcessor
.getInstance().executeCommand(myProject
, new Runnable() {
1002 setTabsMode(UISettings
.getInstance().EDITOR_TAB_PLACEMENT
!= UISettings
.TABS_NONE
);
1003 getSplitters().openFiles();
1004 LaterInvocator
.invokeLater(new Runnable() {
1006 long currentTime
= System
.nanoTime();
1007 Long startTime
= myProject
.getUserData(ProjectImpl
.CREATION_TIME
);
1008 if (startTime
!= null) {
1009 LOG
.info("Project opening took " + (currentTime
- startTime
.longValue()) / 1000000 + " ms");
1010 PluginManager
.dumpPluginClassStatistics();
1023 public void projectClosed() {
1024 //myFocusWatcher.deinstall(myWindows.getComponent ());
1025 getSplitters().dispose();
1027 // Dispose created editors. We do not use use closeEditor method because
1028 // it fires event and changes history.
1032 // BaseCompomemnt methods
1035 public String
getComponentName() {
1036 return "FileEditorManager";
1039 public void initComponent() { /* really do nothing */ }
1041 public void disposeComponent() { /* really do nothing */ }
1043 //JDOMExternalizable methods
1045 public void writeExternal(final Element element
) {
1046 getSplitters().writeExternal(element
);
1049 public void readExternal(final Element element
) {
1050 getSplitters().readExternal(element
);
1053 private EditorWithProviderComposite
getEditorComposite(@NotNull final FileEditor editor
) {
1054 final EditorWithProviderComposite
[] editorsComposites
= getSplitters().getEditorsComposites();
1055 for (int i
= editorsComposites
.length
- 1; i
>= 0; i
--) {
1056 final EditorWithProviderComposite composite
= editorsComposites
[i
];
1057 final FileEditor
[] editors
= composite
.getEditors();
1058 for (int j
= editors
.length
- 1; j
>= 0; j
--) {
1059 final FileEditor _editor
= editors
[j
];
1060 LOG
.assertTrue(_editor
!= null);
1061 if (editor
.equals(_editor
)) {
1069 //======================= Misc =====================
1071 private static void assertDispatchThread() {
1072 ApplicationManager
.getApplication().assertIsDispatchThread();
1074 private static void assertReadAccess() {
1075 ApplicationManager
.getApplication().assertReadAccessAllowed();
1078 public void fireSelectionChanged(final EditorComposite oldSelectedComposite
, final EditorComposite newSelectedComposite
) {
1079 final VirtualFile oldSelectedFile
= oldSelectedComposite
!= null ? oldSelectedComposite
.getFile() : null;
1080 final VirtualFile newSelectedFile
= newSelectedComposite
!= null ? newSelectedComposite
.getFile() : null;
1082 final FileEditor oldSelectedEditor
= oldSelectedComposite
!= null && !oldSelectedComposite
.isDisposed() ? oldSelectedComposite
.getSelectedEditor() : null;
1083 final FileEditor newSelectedEditor
= newSelectedComposite
!= null && !newSelectedComposite
.isDisposed() ? newSelectedComposite
.getSelectedEditor() : null;
1085 final boolean filesEqual
= oldSelectedFile
== null ? newSelectedFile
== null : oldSelectedFile
.equals(newSelectedFile
);
1086 final boolean editorsEqual
= oldSelectedEditor
== null ? newSelectedEditor
== null : oldSelectedEditor
.equals(newSelectedEditor
);
1087 if (!filesEqual
|| !editorsEqual
) {
1088 final FileEditorManagerEvent event
=
1089 new FileEditorManagerEvent(this, oldSelectedFile
, oldSelectedEditor
, newSelectedFile
, newSelectedEditor
);
1090 final FileEditorManagerListener publisher
= getProject().getMessageBus().syncPublisher(FileEditorManagerListener
.FILE_EDITOR_MANAGER
);
1091 publisher
.selectionChanged(event
);
1095 public boolean isChanged(@NotNull final EditorComposite editor
) {
1096 final FileStatusManager fileStatusManager
= FileStatusManager
.getInstance(myProject
);
1097 if (fileStatusManager
!= null) {
1098 if (!fileStatusManager
.getStatus(editor
.getFile()).equals(FileStatus
.NOT_CHANGED
)) {
1105 public void disposeComposite(EditorWithProviderComposite editor
) {
1106 if (getAllEditors().length
== 0) {
1107 setCurrentWindow(null);
1110 if (editor
.equals(getLastSelected())) {
1111 editor
.getSelectedEditor().deselectNotify();
1112 getSplitters().setCurrentWindow(null, false);
1115 final FileEditor
[] editors
= editor
.getEditors();
1116 final FileEditorProvider
[] providers
= editor
.getProviders();
1118 final FileEditor selectedEditor
= editor
.getSelectedEditor();
1119 for (int i
= editors
.length
- 1; i
>= 0; i
--) {
1120 final FileEditor editor1
= editors
[i
];
1121 final FileEditorProvider provider
= providers
[i
];
1122 if (!editor
.equals(selectedEditor
)) { // we already notified the myEditor (when fire event)
1123 if (selectedEditor
.equals(editor1
)) {
1124 editor1
.deselectNotify();
1127 editor1
.removePropertyChangeListener(myEditorPropertyChangeListener
);
1128 provider
.disposeEditor(editor1
);
1131 Disposer
.dispose(editor
);
1134 EditorComposite
getLastSelected() {
1135 final EditorWindow currentWindow
= getSplitters().getCurrentWindow();
1136 if (currentWindow
!= null) {
1137 return currentWindow
.getSelectedEditor();
1142 public void runChange(Runnable runnable
) {
1143 getSplitters().runChange(runnable
);
1146 //================== Listeners =====================
1149 * Closes deleted files. Closes file which are in the deleted directories.
1151 private final class MyVirtualFileListener
extends VirtualFileAdapter
{
1152 public void beforeFileDeletion(VirtualFileEvent e
) {
1153 assertDispatchThread();
1154 final VirtualFile file
= e
.getFile();
1155 final VirtualFile
[] openFiles
= getOpenFiles();
1156 for (int i
= openFiles
.length
- 1; i
>= 0; i
--) {
1157 if (VfsUtil
.isAncestor(file
, openFiles
[i
], false)) {
1158 closeFile(openFiles
[i
]);
1163 public void propertyChanged(VirtualFilePropertyEvent e
) {
1164 if (VirtualFile
.PROP_NAME
.equals(e
.getPropertyName())) {
1165 assertDispatchThread();
1166 final VirtualFile file
= e
.getFile();
1167 if (isFileOpen(file
)) {
1168 updateFileName(file
);
1169 updateFileIcon(file
); // file type can change after renaming
1170 updateFileBackgroundColor(file
);
1173 else if (VirtualFile
.PROP_WRITABLE
.equals(e
.getPropertyName()) || VirtualFile
.PROP_ENCODING
.equals(e
.getPropertyName())) {
1174 updateIconAndStatusbar(e
);
1178 private void updateIconAndStatusbar(final VirtualFilePropertyEvent e
) {
1179 assertDispatchThread();
1180 final VirtualFile file
= e
.getFile();
1181 if (isFileOpen(file
)) {
1182 updateFileIcon(file
);
1183 if (file
.equals(getSelectedFiles()[0])) { // update "write" status
1184 final StatusBarEx statusBar
= (StatusBarEx
)WindowManager
.getInstance().getStatusBar(myProject
);
1185 assert statusBar
!= null;
1186 statusBar
.update(getSelectedTextEditor());
1191 public void fileMoved(VirtualFileMoveEvent e
) {
1192 final VirtualFile file
= e
.getFile();
1193 final VirtualFile
[] openFiles
= getOpenFiles();
1194 for (final VirtualFile openFile
: openFiles
) {
1195 if (VfsUtil
.isAncestor(file
, openFile
, false)) {
1196 updateFileName(openFile
);
1197 updateFileBackgroundColor(openFile
);
1204 private final class MyVirtualFileListener extends VirtualFileAdapter {
1205 public void beforeFileDeletion(final VirtualFileEvent e) {
1206 assertDispatchThread();
1207 final VirtualFile file = e.getFile();
1208 final VirtualFile[] openFiles = getOpenFiles();
1209 for (int i = openFiles.length - 1; i >= 0; i--) {
1210 if (VfsUtil.isAncestor(file, openFiles[i], false)) {
1211 closeFile(openFiles[i]);
1216 public void propertyChanged(final VirtualFilePropertyEvent e) {
1217 if (VirtualFile.PROP_WRITABLE.equals(e.getPropertyName())) {
1218 assertDispatchThread();
1219 final VirtualFile file = e.getFile();
1220 if (isFileOpen(file)) {
1221 if (file.equals(getSelectedFiles()[0])) { // update "write" status
1222 final StatusBarEx statusBar = (StatusBarEx)WindowManager.getInstance().getStatusBar(myProject);
1223 LOG.assertTrue(statusBar != null);
1224 statusBar.setWriteStatus(!file.isWritable());
1230 //public void fileMoved(final VirtualFileMoveEvent e){ }
1234 public boolean isInsideChange() {
1235 return getSplitters().isInsideChange();
1238 private final class MyEditorPropertyChangeListener
implements PropertyChangeListener
{
1239 public void propertyChange(final PropertyChangeEvent e
) {
1240 assertDispatchThread();
1242 final String propertyName
= e
.getPropertyName();
1243 if (FileEditor
.PROP_MODIFIED
.equals(propertyName
)) {
1244 final FileEditor editor
= (FileEditor
)e
.getSource();
1245 final EditorComposite composite
= getEditorComposite(editor
);
1246 if (composite
!= null) {
1247 updateFileIcon(composite
.getFile());
1250 else if (FileEditor
.PROP_VALID
.equals(propertyName
)) {
1251 final boolean valid
= ((Boolean
)e
.getNewValue()).booleanValue();
1253 final FileEditor editor
= (FileEditor
)e
.getSource();
1254 LOG
.assertTrue(editor
!= null);
1255 final EditorComposite composite
= getEditorComposite(editor
);
1256 if (composite
!= null) {
1257 closeFile(composite
.getFile());
1266 * Gets events from VCS and updates color of myEditor tabs
1268 private final class MyFileStatusListener
implements FileStatusListener
{
1269 public void fileStatusesChanged() { // update color of all open files
1270 assertDispatchThread();
1271 LOG
.debug("FileEditorManagerImpl.MyFileStatusListener.fileStatusesChanged()");
1272 final VirtualFile
[] openFiles
= getOpenFiles();
1273 for (int i
= openFiles
.length
- 1; i
>= 0; i
--) {
1274 final VirtualFile file
= openFiles
[i
];
1275 LOG
.assertTrue(file
!= null);
1276 ApplicationManager
.getApplication().invokeLater(new Runnable() {
1278 if (LOG
.isDebugEnabled()) {
1279 LOG
.debug("updating file status in tab for " + file
.getPath());
1281 updateFileStatus(file
);
1283 }, ModalityState
.NON_MODAL
, myProject
.getDisposed());
1287 public void fileStatusChanged(@NotNull final VirtualFile file
) { // update color of the file (if necessary)
1288 assertDispatchThread();
1289 if (isFileOpen(file
)) {
1290 updateFileStatus(file
);
1294 private void updateFileStatus(final VirtualFile file
) {
1295 updateFileColor(file
);
1296 updateFileIcon(file
);
1301 * Gets events from FileTypeManager and updates icons on tabs
1303 private final class MyFileTypeListener
implements FileTypeListener
{
1304 public void beforeFileTypesChanged(FileTypeEvent event
) {
1307 public void fileTypesChanged(final FileTypeEvent event
) {
1308 assertDispatchThread();
1309 final VirtualFile
[] openFiles
= getOpenFiles();
1310 for (int i
= openFiles
.length
- 1; i
>= 0; i
--) {
1311 final VirtualFile file
= openFiles
[i
];
1312 LOG
.assertTrue(file
!= null);
1313 updateFileIcon(file
);
1319 * Gets notifications from UISetting component to track changes of RECENT_FILES_LIMIT
1320 * and EDITOR_TAB_LIMIT, etc values.
1322 private final class MyUISettingsListener
implements UISettingsListener
{
1323 public void uiSettingsChanged(final UISettings source
) {
1324 assertDispatchThread();
1325 setTabsMode(source
.EDITOR_TAB_PLACEMENT
!= UISettings
.TABS_NONE
);
1326 getSplitters().setTabsPlacement(source
.EDITOR_TAB_PLACEMENT
);
1327 getSplitters().trimToSize(source
.EDITOR_TAB_LIMIT
);
1329 // Tab layout policy
1330 if (source
.SCROLL_TAB_LAYOUT_IN_EDITOR
) {
1331 getSplitters().setTabLayoutPolicy(JTabbedPane
.SCROLL_TAB_LAYOUT
);
1334 getSplitters().setTabLayoutPolicy(JTabbedPane
.WRAP_TAB_LAYOUT
);
1337 // "Mark modified files with asterisk"
1338 final VirtualFile
[] openFiles
= getOpenFiles();
1339 for (int i
= openFiles
.length
- 1; i
>= 0; i
--) {
1340 final VirtualFile file
= openFiles
[i
];
1341 updateFileIcon(file
);
1342 updateFileName(file
);
1343 updateFileBackgroundColor(file
);
1348 public void closeAllFiles() {
1349 final VirtualFile
[] openFiles
= getSplitters().getOpenFiles();
1350 for (VirtualFile openFile
: openFiles
) {
1351 closeFile(openFile
);
1356 public VirtualFile
[] getSiblings(VirtualFile file
) {
1357 return getOpenFiles();
1360 protected void queueUpdateFile(final VirtualFile file
) {
1361 myQueue
.queue(new Update(file
) {
1363 if (isFileOpen(file
)) {
1364 updateFileIcon(file
);
1365 updateFileColor(file
);
1366 updateFileBackgroundColor(file
);