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.text;
18 import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
19 import com.intellij.ide.structureView.StructureViewBuilder;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.editor.Document;
23 import com.intellij.openapi.editor.Editor;
24 import com.intellij.openapi.editor.LogicalPosition;
25 import com.intellij.openapi.editor.ScrollType;
26 import com.intellij.openapi.editor.ex.EditorEx;
27 import com.intellij.openapi.editor.ex.util.EditorUtil;
28 import com.intellij.openapi.fileEditor.*;
29 import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
30 import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers;
31 import com.intellij.openapi.fileTypes.FileType;
32 import com.intellij.openapi.project.DumbAware;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.openapi.project.ProjectManager;
35 import com.intellij.openapi.util.Disposer;
36 import com.intellij.openapi.util.Key;
37 import com.intellij.openapi.util.UserDataHolderBase;
38 import com.intellij.openapi.vfs.VirtualFile;
39 import com.intellij.pom.Navigatable;
40 import org.jdom.Element;
41 import org.jetbrains.annotations.NonNls;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
46 import java.beans.PropertyChangeListener;
49 * @author Anton Katilin
50 * @author Vladimir Kondratyev
52 public class TextEditorProvider implements FileEditorProvider, DumbAware {
53 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.text.TextEditorProvider");
54 private static final Key<TextEditor> TEXT_EDITOR_KEY = Key.create("textEditor");
56 @NonNls private static final String TYPE_ID = "text-editor";
57 @NonNls private static final String LINE_ATTR = "line";
58 @NonNls private static final String COLUMN_ATTR = "column";
59 @NonNls private static final String SELECTION_START_ATTR = "selection-start";
60 @NonNls private static final String SELECTION_END_ATTR = "selection-end";
61 @NonNls private static final String VERTICAL_SCROLL_PROPORTION_ATTR = "vertical-scroll-proportion";
63 public static TextEditorProvider getInstance() {
64 return ApplicationManager.getApplication().getComponent(TextEditorProvider.class);
67 public boolean accept(@NotNull Project project, @NotNull VirtualFile file) {
68 if (file.isDirectory() || !file.isValid()) {
72 final FileType ft = file.getFileType();
73 return !ft.isBinary() || BinaryFileTypeDecompilers.INSTANCE.forFileType(ft) != null;
77 public FileEditor createEditor(@NotNull Project project, @NotNull final VirtualFile file) {
78 LOG.assertTrue(accept(project, file));
79 return new TextEditorImpl(project, file, this);
82 public void disposeEditor(@NotNull FileEditor editor) {
83 Disposer.dispose(editor);
87 public FileEditorState readState(@NotNull Element element, @NotNull Project project, @NotNull VirtualFile file) {
88 TextEditorState state = new TextEditorState();
91 state.LINE = Integer.parseInt(element.getAttributeValue(LINE_ATTR));
92 state.COLUMN = Integer.parseInt(element.getAttributeValue(COLUMN_ATTR));
93 state.SELECTION_START = Integer.parseInt(element.getAttributeValue(SELECTION_START_ATTR));
94 state.SELECTION_END = Integer.parseInt(element.getAttributeValue(SELECTION_END_ATTR));
95 state.VERTICAL_SCROLL_PROPORTION = Float.parseFloat(element.getAttributeValue(VERTICAL_SCROLL_PROPORTION_ATTR));
97 catch (NumberFormatException ignored) {
103 public void writeState(@NotNull FileEditorState _state, @NotNull Project project, @NotNull Element element) {
104 TextEditorState state = (TextEditorState)_state;
106 element.setAttribute(LINE_ATTR, Integer.toString(state.LINE));
107 element.setAttribute(COLUMN_ATTR, Integer.toString(state.COLUMN));
108 element.setAttribute(SELECTION_START_ATTR, Integer.toString(state.SELECTION_START));
109 element.setAttribute(SELECTION_END_ATTR, Integer.toString(state.SELECTION_END));
110 element.setAttribute(VERTICAL_SCROLL_PROPORTION_ATTR, Float.toString(state.VERTICAL_SCROLL_PROPORTION));
114 public String getEditorTypeId() {
119 public FileEditorPolicy getPolicy() {
120 return FileEditorPolicy.NONE;
123 @NotNull public TextEditor getTextEditor(@NotNull Editor editor) {
124 TextEditor textEditor = editor.getUserData(TEXT_EDITOR_KEY);
125 if (textEditor == null) {
126 textEditor = createWrapperForEditor(editor);
127 putTextEditor(editor, textEditor);
133 protected EditorWrapper createWrapperForEditor(final Editor editor) {
134 return new EditorWrapper(editor);
138 public static Document[] getDocuments(@NotNull FileEditor editor) {
139 if (editor instanceof DocumentsEditor) {
140 DocumentsEditor documentsEditor = (DocumentsEditor)editor;
141 Document[] documents = documentsEditor.getDocuments();
142 return documents.length > 0 ? documents : null;
145 if (editor instanceof TextEditor) {
146 Document document = ((TextEditor)editor).getEditor().getDocument();
147 return new Document[]{document};
150 Project[] projects = ProjectManager.getInstance().getOpenProjects();
151 for (int i = projects.length - 1; i >= 0; i--) {
152 VirtualFile file = FileEditorManagerEx.getInstanceEx(projects[i]).getFile(editor);
154 Document document = FileDocumentManager.getInstance().getDocument(file);
155 if (document != null) {
156 return new Document[]{document};
164 static void putTextEditor(Editor editor, TextEditor textEditor) {
165 editor.putUserData(TEXT_EDITOR_KEY, textEditor);
168 protected TextEditorState getStateImpl(final Project project, final Editor editor, @NotNull FileEditorStateLevel level){
169 TextEditorState state = new TextEditorState();
170 state.LINE = editor.getCaretModel().getLogicalPosition().line;
171 state.COLUMN = editor.getCaretModel().getLogicalPosition().column;
172 state.SELECTION_START = editor.getSelectionModel().getSelectionStart();
173 state.SELECTION_END = editor.getSelectionModel().getSelectionEnd();
175 // Saving scrolling proportion on UNDO may cause undesirable results of undo action fails to perform since
176 // scrolling proportion restored slightly differs from what have been saved.
177 state.VERTICAL_SCROLL_PROPORTION = level == FileEditorStateLevel.UNDO ? -1 : EditorUtil.calcVerticalScrollProportion(editor);
181 protected void setStateImpl(final Project project, final Editor editor, final TextEditorState state){
182 LogicalPosition pos = new LogicalPosition(state.LINE, state.COLUMN);
183 editor.getCaretModel().moveToLogicalPosition(pos);
184 editor.getSelectionModel().removeSelection();
185 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
187 if (state.VERTICAL_SCROLL_PROPORTION != -1) {
188 EditorUtil.setVerticalScrollProportion(editor, state.VERTICAL_SCROLL_PROPORTION);
191 final Document document = editor.getDocument();
193 if (state.SELECTION_START == state.SELECTION_END) {
194 editor.getSelectionModel().removeSelection();
197 int startOffset = Math.min(state.SELECTION_START, document.getTextLength());
198 int endOffset = Math.min(state.SELECTION_END, document.getTextLength());
199 editor.getSelectionModel().setSelection(startOffset, endOffset);
201 ((EditorEx) editor).stopOptimizedScrolling();
202 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
205 protected class EditorWrapper extends UserDataHolderBase implements TextEditor {
206 private final Editor myEditor;
208 public EditorWrapper(Editor editor) {
213 public Editor getEditor() {
218 public JComponent getComponent() {
219 return myEditor.getComponent();
222 public JComponent getPreferredFocusedComponent() {
223 return myEditor.getContentComponent();
227 public String getName() {
231 public StructureViewBuilder getStructureViewBuilder() {
232 VirtualFile file = FileDocumentManager.getInstance().getFile(myEditor.getDocument());
233 if (file == null) return null;
235 final Project project = myEditor.getProject();
236 LOG.assertTrue(project != null);
237 return StructureViewBuilder.PROVIDER.getStructureViewBuilder(file.getFileType(), file, project);
241 public FileEditorState getState(@NotNull FileEditorStateLevel level) {
242 return getStateImpl(null, myEditor, level);
245 public void setState(@NotNull FileEditorState state) {
246 setStateImpl(null, myEditor, (TextEditorState)state);
249 public boolean isModified() {
253 public boolean isValid() {
257 public void dispose() { }
259 public void selectNotify() { }
261 public void deselectNotify() { }
263 public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { }
265 public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { }
267 public BackgroundEditorHighlighter getBackgroundHighlighter() {
271 public FileEditorLocation getCurrentLocation() {
275 public boolean canNavigateTo(@NotNull final Navigatable navigatable) {
279 public void navigateTo(@NotNull final Navigatable navigatable) {