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.
17 package com.intellij.application.options.colors;
19 import com.intellij.application.options.colors.highlighting.HighlightData;
20 import com.intellij.application.options.colors.highlighting.HighlightsExtractor;
21 import com.intellij.ide.highlighter.HighlighterFactory;
22 import com.intellij.openapi.editor.*;
23 import com.intellij.openapi.editor.colors.CodeInsightColors;
24 import com.intellij.openapi.editor.colors.EditorColorsScheme;
25 import com.intellij.openapi.editor.colors.TextAttributesKey;
26 import com.intellij.openapi.editor.event.CaretAdapter;
27 import com.intellij.openapi.editor.event.CaretEvent;
28 import com.intellij.openapi.editor.event.CaretListener;
29 import com.intellij.openapi.editor.ex.EditorEx;
30 import com.intellij.openapi.editor.highlighter.EditorHighlighter;
31 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
32 import com.intellij.openapi.fileTypes.SyntaxHighlighter;
33 import com.intellij.openapi.options.colors.ColorSettingsPage;
34 import com.intellij.openapi.options.colors.EditorHighlightingProvidingColorSettingsPage;
35 import com.intellij.psi.tree.IElementType;
36 import com.intellij.util.Alarm;
37 import com.intellij.util.EventDispatcher;
38 import com.intellij.util.ui.UIUtil;
39 import org.jetbrains.annotations.NotNull;
43 import java.awt.event.MouseEvent;
44 import java.awt.event.MouseMotionAdapter;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.Comparator;
49 import java.util.List;
51 public class SimpleEditorPreview implements PreviewPanel{
52 private final ColorSettingsPage myPage;
54 private final EditorEx myEditor;
55 private final Alarm myBlinkingAlarm;
56 private final HighlightData[] myHighlightData;
58 private final ColorAndFontOptions myOptions;
60 private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
62 public SimpleEditorPreview(final ColorAndFontOptions options, final ColorSettingsPage page) {
63 this(options, page, true);
66 public SimpleEditorPreview(final ColorAndFontOptions options, final ColorSettingsPage page, final boolean navigatable) {
70 String text = page.getDemoText();
72 HighlightsExtractor extractant2 = new HighlightsExtractor(page.getAdditionalHighlightingTagToDescriptorMap());
73 List<HighlightData> highlights = new ArrayList<HighlightData>();
74 String stripped = extractant2.extractHighlights(text, highlights);
75 myHighlightData = highlights.toArray(new HighlightData[highlights.size()]);
76 int selectedLine = -1;
77 myEditor = (EditorEx)FontEditorPreview.createPreviewEditor(stripped, 10, 3, selectedLine, myOptions, false);
79 FontEditorPreview.installTrafficLights(myEditor);
80 myBlinkingAlarm = new Alarm().setActivationComponent(myEditor.getComponent());
82 addMouseMotionListener(myEditor, page.getHighlighter(), myHighlightData, false);
84 CaretListener listener = new CaretAdapter() {
86 public void caretPositionChanged(CaretEvent e) {
87 navigate(myEditor, true, e.getNewPosition(), page.getHighlighter(), myHighlightData, false);
90 myEditor.getCaretModel().addCaretListener(listener);
94 private void addMouseMotionListener(final Editor view,
95 final SyntaxHighlighter highlighter,
96 final HighlightData[] data, final boolean isBackgroundImportant) {
97 view.getContentComponent().addMouseMotionListener(new MouseMotionAdapter() {
99 public void mouseMoved(MouseEvent e) {
100 LogicalPosition pos = view.xyToLogicalPosition(new Point(e.getX(), e.getY()));
101 navigate(view, false, pos, highlighter, data, isBackgroundImportant);
106 private void navigate(final Editor editor, boolean select,
108 final SyntaxHighlighter highlighter,
109 final HighlightData[] data, final boolean isBackgroundImportant) {
110 int offset = editor.logicalPositionToOffset(pos);
112 if (!isBackgroundImportant && editor.offsetToLogicalPosition(offset).column != pos.column) {
114 ClickNavigator.setCursor(editor, Cursor.TEXT_CURSOR);
120 for (HighlightData highlightData : data) {
121 if (ClickNavigator.highlightDataContainsOffset(highlightData, editor.logicalPositionToOffset(pos))) {
123 ClickNavigator.setCursor(editor, Cursor.HAND_CURSOR);
126 myDispatcher.getMulticaster().selectionInPreviewChanged(highlightData.getHighlightType());
133 if (highlighter != null) {
134 HighlighterIterator itr = ((EditorEx)editor).getHighlighter().createIterator(offset);
135 selectItem(itr, highlighter, select);
137 ClickNavigator.setCursor(editor, Cursor.HAND_CURSOR);
140 ClickNavigator.setCursor(editor, Cursor.TEXT_CURSOR);
145 private void selectItem(HighlighterIterator itr, SyntaxHighlighter highlighter, final boolean select) {
146 IElementType tokenType = itr.getTokenType();
147 if (tokenType == null) return;
148 String type = ClickNavigator.highlightingTypeFromTokenType(tokenType, highlighter);
150 myDispatcher.getMulticaster().selectionInPreviewChanged(type);
155 public JComponent getPanel() {
156 return myEditor.getComponent();
160 public void updateView() {
161 EditorColorsScheme scheme = myOptions.getSelectedScheme();
163 myEditor.setColorsScheme(scheme);
165 EditorHighlighter highlighter = null;
166 if (myPage instanceof EditorHighlightingProvidingColorSettingsPage) {
168 highlighter = ((EditorHighlightingProvidingColorSettingsPage)myPage).createEditorHighlighter(scheme);
170 if (highlighter == null) {
171 final SyntaxHighlighter pageHighlighter = myPage.getHighlighter();
172 highlighter = HighlighterFactory.createHighlighter(pageHighlighter, scheme);
174 myEditor.setHighlighter(highlighter);
175 updateHighlighters();
177 myEditor.reinitSettings();
181 private void updateHighlighters() {
182 UIUtil.invokeLaterIfNeeded(new Runnable() {
185 if (myEditor.isDisposed()) return;
186 myEditor.getMarkupModel().removeAllHighlighters();
187 HighlightData[] datum = myHighlightData;
188 final Map<TextAttributesKey, String> displayText = ColorSettingsUtil.keyToDisplayTextMap(myPage);
189 for (final HighlightData data : datum) {
190 data.addHighlToView(myEditor, myOptions.getSelectedScheme(), displayText);
196 private static final int BLINK_COUNT = 3 * 2;
199 public void blinkSelectedHighlightType(Object description) {
200 if (description instanceof EditorSchemeAttributeDescriptor){
201 String type = ((EditorSchemeAttributeDescriptor)description).getType();
203 List<HighlightData> highlights = startBlinkingHighlights(myEditor,
204 myHighlightData, type,
205 myPage.getHighlighter(), true,
206 myBlinkingAlarm, BLINK_COUNT, myPage);
208 scrollHighlightInView(highlights, myEditor);
212 private static void scrollHighlightInView(final List<HighlightData> highlightDatas, final Editor editor) {
213 boolean needScroll = true;
214 int minOffset = Integer.MAX_VALUE;
215 for(HighlightData data: highlightDatas) {
216 if (isOffsetVisible(editor, data.getStartOffset())) {
220 minOffset = Math.min(minOffset, data.getStartOffset());
222 if (needScroll && minOffset != Integer.MAX_VALUE) {
223 LogicalPosition pos = editor.offsetToLogicalPosition(minOffset);
224 editor.getScrollingModel().scrollTo(pos, ScrollType.MAKE_VISIBLE);
228 private static boolean isOffsetVisible(final Editor editor, final int startOffset) {
229 Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
230 Point point = editor.logicalPositionToXY(editor.offsetToLogicalPosition(startOffset));
231 return point.y >= visibleArea.y && point.y < visibleArea.x + visibleArea.height;
234 private void stopBlinking() {
235 myBlinkingAlarm.cancelAllRequests();
238 private List<HighlightData> startBlinkingHighlights(final EditorEx editor,
239 final HighlightData[] highlightDatum,
240 final String attrKey,
241 final SyntaxHighlighter highlighter,
245 final ColorSettingsPage page) {
246 if (show && count <= 0) return Collections.emptyList();
247 editor.getMarkupModel().removeAllHighlighters();
248 boolean found = false;
249 List<HighlightData> highlights = new ArrayList<HighlightData>();
250 List<HighlightData> matchingHighlights = new ArrayList<HighlightData>();
251 for (int i = 0; highlightDatum != null && i < highlightDatum.length; i++) {
252 HighlightData highlightData = highlightDatum[i];
253 String type = highlightData.getHighlightType();
254 highlights.add(highlightData);
255 if (show && type.equals(attrKey)) {
257 new HighlightData(highlightData.getStartOffset(), highlightData.getEndOffset(),
258 CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES);
259 highlights.add(highlightData);
260 matchingHighlights.add(highlightData);
264 if (!found && highlighter != null) {
265 HighlighterIterator iterator = editor.getHighlighter().createIterator(0);
267 IElementType tokenType = iterator.getTokenType();
268 TextAttributesKey[] tokenHighlights = highlighter.getTokenHighlights(tokenType);
269 for (final TextAttributesKey tokenHighlight : tokenHighlights) {
270 String type = tokenHighlight.getExternalName();
271 if (show && type != null && type.equals(attrKey)) {
272 HighlightData highlightData = new HighlightData(iterator.getStart(), iterator.getEnd(),
273 CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES);
274 highlights.add(highlightData);
275 matchingHighlights.add(highlightData);
280 while (!iterator.atEnd());
283 final Map<TextAttributesKey, String> displayText = ColorSettingsUtil.keyToDisplayTextMap(page);
285 // sort highlights to avoid overlappings
286 Collections.sort(highlights, new Comparator<HighlightData>() {
288 public int compare(HighlightData highlightData1, HighlightData highlightData2) {
289 return highlightData1.getStartOffset() - highlightData2.getStartOffset();
292 for (int i = highlights.size() - 1; i >= 0; i--) {
293 HighlightData highlightData = highlights.get(i);
294 int startOffset = highlightData.getStartOffset();
295 HighlightData prevHighlightData = i == 0 ? null : highlights.get(i - 1);
296 if (prevHighlightData != null
297 && startOffset <= prevHighlightData.getEndOffset()
298 && highlightData.getHighlightType().equals(prevHighlightData.getHighlightType())) {
299 prevHighlightData.setEndOffset(highlightData.getEndOffset());
302 highlightData.addHighlToView(editor, myOptions.getSelectedScheme(), displayText);
305 alarm.cancelAllRequests();
306 alarm.addComponentRequest(new Runnable() {
309 startBlinkingHighlights(editor, highlightDatum, attrKey, highlighter, !show, alarm, count - 1, page);
312 return matchingHighlights;
317 public void addListener(@NotNull final ColorAndFontSettingsListener listener) {
318 myDispatcher.addListener(listener);
322 public void disposeUIResources() {
323 EditorFactory editorFactory = EditorFactory.getInstance();
324 editorFactory.releaseEditor(myEditor);