diff options
10 files changed, 754 insertions, 0 deletions
diff --git a/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF b/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF index 18a9f968e4e..d3133130943 100644 --- a/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF +++ b/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF @@ -15,6 +15,7 @@ Export-Package: org.eclipse.ui.internal.texteditor.quickdiff.compare.equivalence;x-internal:=true, org.eclipse.ui.internal.texteditor.rulers;x-internal:=true, org.eclipse.ui.internal.texteditor.spelling;x-internal:=true, + org.eclipse.ui.internal.views.minimap;x-internal:=true, org.eclipse.ui.texteditor; texteditor="split"; mandatory:="texteditor", org.eclipse.ui.texteditor.link, org.eclipse.ui.texteditor.quickdiff, diff --git a/org.eclipse.ui.workbench.texteditor/icons/full/eview16/minimap.png b/org.eclipse.ui.workbench.texteditor/icons/full/eview16/minimap.png Binary files differnew file mode 100644 index 00000000000..02c4b79e109 --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/icons/full/eview16/minimap.png diff --git a/org.eclipse.ui.workbench.texteditor/plugin.properties b/org.eclipse.ui.workbench.texteditor/plugin.properties index 4f2184330ff..77a35f5b328 100644 --- a/org.eclipse.ui.workbench.texteditor/plugin.properties +++ b/org.eclipse.ui.workbench.texteditor/plugin.properties @@ -193,3 +193,5 @@ SpellingEngine= Spelling Engine blockSelectionModeFont.label= Text Editor Block Selection Font blockSelectionModeFont.description= The block selection mode font is used by text editors in block (column) mode. A monospace font should be used. + +MinimapView.name=Minimap
\ No newline at end of file diff --git a/org.eclipse.ui.workbench.texteditor/plugin.xml b/org.eclipse.ui.workbench.texteditor/plugin.xml index d51f0cc2d15..44ed2d60f88 100644 --- a/org.eclipse.ui.workbench.texteditor/plugin.xml +++ b/org.eclipse.ui.workbench.texteditor/plugin.xml @@ -1338,4 +1338,17 @@ </command> </menuContribution> </extension> + + <extension + point="org.eclipse.ui.views"> + <view + category="org.eclipse.ui" + class="org.eclipse.ui.internal.views.minimap.MinimapView" + icon="icons/full/eview16/minimap.png" + id="org.eclipse.ui.views.minimap.MinimapView" + name="%MinimapView.name" + allowMultiple="false" + restorable="true"> + </view> + </extension> </plugin> diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.java new file mode 100644 index 00000000000..bee8392565c --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2018 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 + *******************************************************************************/ +package org.eclipse.ui.internal.views.minimap; + +import org.eclipse.osgi.util.NLS; + +/** + * MinimapMessages is the message class for the messages used in the minimap. + * + */ +public class MinimapMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.ui.internal.views.minimap.MinimapMessages";//$NON-NLS-1$ + + // ============================================================================== + // Minimap View + // ============================================================================== + /** */ + public static String MinimapViewNoMinimap; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, MinimapMessages.class); + } +}
\ No newline at end of file diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.properties b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.properties new file mode 100644 index 00000000000..ef07d1d3407 --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapMessages.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2018 Angelo ZERR. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 +############################################################################### + +# ============================================================================== +# Minimap View +# ============================================================================== +MinimapViewNoMinimap=A minimap is not available.
\ No newline at end of file diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapPage.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapPage.java new file mode 100644 index 00000000000..68a7a193d8e --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapPage.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2018 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 + *******************************************************************************/ +package org.eclipse.ui.internal.views.minimap; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.source.ISourceViewer; + +import org.eclipse.ui.part.Page; + +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * Minimap page which displays scaled content of the given text editor. + * + */ +public class MinimapPage extends Page { + + private final ISourceViewer fEditorViewer; + private MinimapWidget fMinimapWidget; + + public MinimapPage(ITextEditor textEditor) { + fEditorViewer = (ISourceViewer) textEditor.getAdapter(ITextOperationTarget.class); + } + + @Override + public void createControl(Composite parent) { + // Create minimap styled text + fMinimapWidget = new MinimapWidget(parent, fEditorViewer); + fMinimapWidget.install(); + } + + @Override + public Control getControl() { + return fMinimapWidget.getControl(); + } + + @Override + public void setFocus() { + fMinimapWidget.getControl().setFocus(); + } + + @Override + public void dispose() { + fMinimapWidget.uninstall(); + super.dispose(); + } +} diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapView.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapView.java new file mode 100644 index 00000000000..4b1ebe54a81 --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapView.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2018 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 + *******************************************************************************/ +package org.eclipse.ui.internal.views.minimap; + +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.part.IPage; +import org.eclipse.ui.part.MessagePage; +import org.eclipse.ui.part.MultiPageEditorPart; +import org.eclipse.ui.part.Page; +import org.eclipse.ui.part.PageBook; +import org.eclipse.ui.part.PageBookView; +import org.eclipse.ui.part.PageSite; + +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * Minimap view used to display content of current text editor with scale. + * + */ +public class MinimapView extends PageBookView { + + private String defaultText; + + public MinimapView() { + this.defaultText = MinimapMessages.MinimapViewNoMinimap; + } + + @Override + protected IPage createDefaultPage(PageBook book) { + MessagePage page = new MessagePage(); + this.initPage(page); + page.createControl(book); + page.setMessage(this.defaultText); + return page; + } + + @Override + protected PageRec doCreatePage(IWorkbenchPart part) { + Page page = createMinimapPage(part); + PageSite site = new PageSite(this.getViewSite()); + page.init(site); + page.createControl(this.getPageBook()); + return new PageBookView.PageRec(part, page); + } + + private Page createMinimapPage(IWorkbenchPart part) { + if (part instanceof MultiPageEditorPart) { + return new MultiPageMinimapPage((MultiPageEditorPart) part); + } + return new MinimapPage((ITextEditor) part); + } + + @Override + protected void doDestroyPage(IWorkbenchPart part, PageRec rec) { + IPage page = rec.page; + page.dispose(); + rec.dispose(); + } + + @Override + protected IWorkbenchPart getBootstrapPart() { + IWorkbenchPage page = this.getSite().getPage(); + return page != null ? page.getActiveEditor() : null; + } + + @Override + protected boolean isImportant(IWorkbenchPart part) { + return part instanceof ITextEditor || part instanceof MultiPageEditorPart; + } +} diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapWidget.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapWidget.java new file mode 100644 index 00000000000..2fd40a493a4 --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MinimapWidget.java @@ -0,0 +1,461 @@ +/******************************************************************************* + * Copyright (c) 2018 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 + *******************************************************************************/ +package org.eclipse.ui.internal.views.minimap; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CaretEvent; +import org.eclipse.swt.custom.CaretListener; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.custom.TextChangeListener; +import org.eclipse.swt.custom.TextChangedEvent; +import org.eclipse.swt.custom.TextChangingEvent; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextPresentationListener; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension4; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.IViewportListener; +import org.eclipse.jface.text.JFaceTextUtil; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.TextViewer; + +/** + * Minimap widget which displays scaled content of the given text editor. + * + */ +public class MinimapWidget { + + private static final float SCALE = 0.2f; + + private final ITextViewer fEditorViewer; + + private final StyledText fMinimapTextWidget; + + /** + * Editor tracker used to track text changed and styles changes of the + * editor content. + */ + class EditorTracker implements TextChangeListener, ControlListener, ITextPresentationListener, IViewportListener { + + private Map<Font, Font> fScaledFonts; + + private static final int RESETED = -1; + + private int scaledClientAreaHeight = RESETED; + + @Override + public void textSet(TextChangedEvent event) { + synchText(); + } + + @Override + public void textChanging(TextChangingEvent event) { + fMinimapTracker.replaceTextRange(event); + } + + @Override + public void textChanged(TextChangedEvent event) { + // Do nothing + } + + @Override + public void applyTextPresentation(TextPresentation presentation) { + addPresentation(presentation); + } + + private StyleRange modelStyleRange2WidgetStyleRange(StyleRange range) { + IRegion region = modelRange2WidgetRange(new Region(range.start, range.length)); + if (region != null) { + StyleRange result = (StyleRange) range.clone(); + result.start = region.getOffset(); + result.length = region.getLength(); + return result; + } + return null; + } + + private IRegion modelRange2WidgetRange(IRegion region) { + if (fEditorViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) fEditorViewer; + return extension.modelRange2WidgetRange(region); + } + if (fEditorViewer instanceof TextViewer) { + return ((TextViewer) fEditorViewer).modelRange2WidgetRange(region); + } + IRegion visibleRegion = fEditorViewer.getVisibleRegion(); + int start = region.getOffset() - visibleRegion.getOffset(); + int end = start + region.getLength(); + if (end > visibleRegion.getLength()) + end = visibleRegion.getLength(); + + return new Region(start, end - start); + } + + private void addPresentation(TextPresentation presentation) { + + StyleRange range = presentation.getDefaultStyleRange(); + if (range != null) { + + range = modelStyleRange2WidgetStyleRange(range); + if (range != null) { + updateStyle(range); + fMinimapTextWidget.setStyleRange(range); + } + List<StyleRange> ranges = new ArrayList<>(presentation.getDenumerableRanges()); + Iterator<StyleRange> e = presentation.getNonDefaultStyleRangeIterator(); + while (e.hasNext()) { + range = e.next(); + range = modelStyleRange2WidgetStyleRange(range); + if (range != null) { + updateStyle(range); + ranges.add(range); + } + } + + if (!ranges.isEmpty()) { + fMinimapTextWidget.replaceStyleRanges(0, 0, ranges.toArray(new StyleRange[ranges.size()])); + } + + } else { + IRegion region = modelRange2WidgetRange(presentation.getCoverage()); + if (region == null) + return; + + List<StyleRange> list = new ArrayList<>(presentation.getDenumerableRanges()); + Iterator<StyleRange> e = presentation.getAllStyleRangeIterator(); + while (e.hasNext()) { + range = e.next(); + range = modelStyleRange2WidgetStyleRange(range); + if (range != null) { + updateStyle(range); + list.add(range); + } + } + + if (!list.isEmpty()) { + StyleRange[] ranges = new StyleRange[list.size()]; + list.toArray(ranges); + fMinimapTextWidget.replaceStyleRanges(region.getOffset(), region.getLength(), ranges); + } + } + } + + void updateStyle(StyleRange range) { + // scale the font + range.font = getScaledFont(range.font); + // remove GlyphMetrics (created by code mining) + range.metrics = null; + } + + Font getScaledFont(Font editorFont) { + if (editorFont == null) { + return null; + } + Font scaledFont = fScaledFonts.get(editorFont); + if (scaledFont != null) { + return scaledFont; + } + FontData[] fontData = editorFont.getFontData(); + FontData fontDatum = fontData[0]; + + scaledFont = new Font(editorFont.getDevice(), fontDatum.getName(), + Math.round(fontDatum.getHeight() * getScale()), fontDatum.getStyle()); + fScaledFonts.put(editorFont, scaledFont); + return scaledFont; + } + + @Override + public void controlMoved(ControlEvent e) { + // Do nothing + } + + @Override + public void controlResized(ControlEvent e) { + scaledClientAreaHeight = RESETED; + updateMinimap(); + } + + @Override + public void viewportChanged(int verticalOffset) { + updateMinimap(); + } + + void updateMinimap() { + StyledText editorTextWidget = fEditorViewer.getTextWidget(); + int editorTopIndex = JFaceTextUtil.getPartialTopIndex(editorTextWidget); + int editorBottomIndex = JFaceTextUtil.getPartialBottomIndex(editorTextWidget); + fMinimapTracker.updateMinimap(editorTopIndex, editorBottomIndex); + } + + int getScaledClientAreaHeight() { + if (scaledClientAreaHeight == RESETED) { + scaledClientAreaHeight = Math.round(fEditorViewer.getTextWidget().getClientArea().height * getScale()); + } + return scaledClientAreaHeight; + } + + void install() { + StyledText editorTextWidget = fEditorViewer.getTextWidget(); + fScaledFonts = new HashMap<>(); + // Compute scaled font + Font scaledFont = getScaledFont(editorTextWidget.getFont()); + fMinimapTextWidget.setFont(scaledFont); + // track changed content of styled text of the editor + editorTextWidget.getContent().addTextChangeListener(this); + // track changed styles of styled text of the editor + fMinimapTextWidget.setBackground(editorTextWidget.getBackground()); + fMinimapTextWidget.setForeground(editorTextWidget.getForeground()); + if (fEditorViewer instanceof ITextViewerExtension4) { + ((ITextViewerExtension4) fEditorViewer).addTextPresentationListener(this); + } + // track changed of vertical bar scroll to update highlight + // Viewport. + fEditorViewer.addViewportListener(this); + editorTextWidget.addControlListener(this); + synchTextAndStyles(); + } + + void synchTextAndStyles() { + synchText(); + synchStyles(); + } + + private void synchStyles() { + StyledText editorTextWidget = fEditorViewer.getTextWidget(); + StyleRange[] ranges = editorTextWidget.getStyleRanges(); + if (ranges != null) { + for (StyleRange range : ranges) { + updateStyle(range); + } + } + fMinimapTextWidget.setStyleRanges(ranges); + } + + private void synchText() { + StyledText editorTextWidget = fEditorViewer.getTextWidget(); + fMinimapTextWidget.setText(editorTextWidget.getText()); + } + + void uninstall() { + StyledText editorTextWidget = fEditorViewer.getTextWidget(); + // untrack changed content of styled text of the editor + if (editorTextWidget.getContent() != null) { + editorTextWidget.getContent().removeTextChangeListener(this); + } + // untrack changed styles of styled text of the editor + if (fEditorViewer instanceof ITextViewerExtension4) { + ((ITextViewerExtension4) fEditorViewer).removeTextPresentationListener(this); + } + // track changed of vertical bar scroll to update highlight + // Viewport. + fEditorViewer.removeViewportListener(this); + editorTextWidget.removeControlListener(this); + fScaledFonts.values().forEach(Font::dispose); + } + } + + /** + * Minimap tracker. + * + */ + class MinimapTracker implements CaretListener, SelectionListener, PaintListener, MouseWheelListener { + + private static final int NB_LINES_SCROLL = 10; + + private int fEditorTopIndex; + + private int fTopIndexY; + + private boolean fTextChanging; + + @Override + public void caretMoved(CaretEvent event) { + if (fTextChanging) { + // When editor content changed, it updates the minimap styled + // text content which update caret. + // In this case, ignore it to avoid set the top index of the + // editor viewer. + return; + } + updateEditorTopIndex(); + } + + private void updateEditorTopIndex() { + int caretOffset = fMinimapTextWidget.getCaretOffset(); + int lineAtOffset = fMinimapTextWidget.getLineAtOffset(caretOffset); + int newTopIndex = lineAtOffset; + if (fEditorViewer instanceof ITextViewerExtension5) { + // adjust offset according folded content + newTopIndex = ((ITextViewerExtension5) fEditorViewer).widgetLine2ModelLine(lineAtOffset); + } + fEditorViewer.setTopIndex(newTopIndex); + } + + public void updateMinimap(int editorTopIndex, int editorBottomIndex) { + if (editorTopIndex != fEditorTopIndex) { + fEditorTopIndex = editorTopIndex; + // Update the position of minimap styled text + fMinimapTextWidget.setRedraw(false); + int newMinimapTopIndex = editorTopIndex; + if (editorTopIndex != 0 + && editorBottomIndex != fMinimapTextWidget.getLineAtOffset(fMinimapTextWidget.getCharCount())) { + // center the draw of square of editor client area + int minimapTopIndex = JFaceTextUtil.getPartialTopIndex(fMinimapTextWidget); + int minimapBottomIndex = JFaceTextUtil.getPartialBottomIndex(fMinimapTextWidget); + int minimapVisibleLineCount = minimapBottomIndex - minimapTopIndex; + int editorVisibleLineCount = editorBottomIndex - editorTopIndex; + newMinimapTopIndex = Math.max(0, + editorTopIndex + editorVisibleLineCount - minimapVisibleLineCount / 2); + } + fMinimapTextWidget.setTopIndex(newMinimapTopIndex); + fTopIndexY = fMinimapTextWidget.getLinePixel(fEditorTopIndex); + fMinimapTextWidget.setRedraw(true); + } + } + + public void replaceTextRange(TextChangingEvent event) { + fTextChanging = true; + int start = event.start; + int length = event.replaceCharCount; + String text = event.newText; + if (event.newLineCount > 0 || event.replaceLineCount > 0) { + Rectangle clientArea = fMinimapTextWidget.getClientArea(); + fMinimapTextWidget.setRedraw(false); + fMinimapTextWidget.replaceTextRange(start, length, text); + fMinimapTextWidget.redraw(0, fTopIndexY, clientArea.width, clientArea.height, false); + fMinimapTextWidget.setRedraw(true); + } else { + fMinimapTextWidget.replaceTextRange(start, length, text); + } + fTextChanging = false; + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // Do nothing + } + + @Override + public void widgetSelected(SelectionEvent e) { + // hack to avoid drawing selection of styled text while mouse move + // of highlight viewport + fMinimapTextWidget.setSelection(fMinimapTextWidget.getCaretOffset()); + } + + @Override + public void paintControl(PaintEvent event) { + GC gc = event.gc; + int clientAreaHeight = fEditorTracker.getScaledClientAreaHeight(); + int clientAreaWidth = fMinimapTextWidget.getClientArea().width; + gc.setBackground(fMinimapTextWidget.getSelectionBackground()); + Rectangle rect = new Rectangle(0, fTopIndexY, clientAreaWidth, clientAreaHeight); + gc.drawRectangle(rect.x, rect.y, Math.max(1, rect.width - 1), Math.max(1, rect.height - 1)); + gc.setAdvanced(true); + if (gc.getAdvanced()) { + gc.setAlpha(20); + gc.fillRectangle(rect); + gc.setAdvanced(false); + } + } + + @Override + public void mouseScrolled(MouseEvent e) { + int caretOffset = fMinimapTextWidget.getOffsetAtPoint(new Point(0, fTopIndexY)); + int lineIndex = fMinimapTextWidget.getLineAtOffset(caretOffset); + if (e.count > 0) { + lineIndex = Math.max(0, lineIndex - NB_LINES_SCROLL); + } else { + lineIndex = Math.min(fMinimapTextWidget.getCharCount(), lineIndex + NB_LINES_SCROLL); + } + caretOffset = fMinimapTextWidget.getOffsetAtLine(lineIndex); + fMinimapTextWidget.setCaretOffset(caretOffset); + } + + void install() { + fMinimapTextWidget.addCaretListener(this); + fMinimapTextWidget.addSelectionListener(this); + fMinimapTextWidget.addPaintListener(this); + fMinimapTextWidget.addMouseWheelListener(this); + } + + void uninstall() { + if (!fMinimapTextWidget.isDisposed()) { + fMinimapTextWidget.removeCaretListener(this); + fMinimapTextWidget.removeSelectionListener(this); + fMinimapTextWidget.removePaintListener(this); + fMinimapTextWidget.removeMouseWheelListener(this); + } + } + + } + + private final EditorTracker fEditorTracker; + + private final MinimapTracker fMinimapTracker; + + public MinimapWidget(Composite parent, ITextViewer viewer) { + fEditorViewer = viewer; + + // Create minimap styled text + fMinimapTextWidget = new StyledText(parent, SWT.MULTI | SWT.READ_ONLY); + fMinimapTextWidget.setEditable(false); + fMinimapTextWidget.setCursor(fMinimapTextWidget.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); + + // Initialize trackers + fEditorTracker = new EditorTracker(); + fMinimapTracker = new MinimapTracker(); + } + + /** + * Install minimap widget. + */ + public void install() { + fEditorTracker.install(); + fMinimapTracker.install(); + } + + public void uninstall() { + fEditorTracker.uninstall(); + fMinimapTracker.uninstall(); + } + + public Control getControl() { + return fMinimapTextWidget; + } + + float getScale() { + return SCALE; + } +} diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MultiPageMinimapPage.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MultiPageMinimapPage.java new file mode 100644 index 00000000000..6fc5febc359 --- /dev/null +++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/views/minimap/MultiPageMinimapPage.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2018 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr <angelo.zerr@gmail.com> - [minimap] Initialize minimap view - Bug 535450 + *******************************************************************************/ +package org.eclipse.ui.internal.views.minimap; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; + +import org.eclipse.jface.dialogs.IPageChangedListener; + +import org.eclipse.ui.part.MultiPageEditorPart; +import org.eclipse.ui.part.Page; +import org.eclipse.ui.part.PageBook; + +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * Minimap with multi page editor which shows a minimap for the current page + * which is an {@link ITextEditor}. + * + */ +public class MultiPageMinimapPage extends Page { + + private final MultiPageEditorPart fMultiPageEditor; + private final Map<Object, Control> fTextWidgetMap; + private final IPageChangedListener fPageChangedListener; + private PageBook fPageBook; + private Label fErrorLabel; + + public MultiPageMinimapPage(MultiPageEditorPart multiPageEditor) { + this.fMultiPageEditor = multiPageEditor; + this.fTextWidgetMap = new HashMap<>(); + this.fPageChangedListener = e -> { + Object selectedPage = multiPageEditor.getSelectedPage(); + // Find from cache the minimap for the selected page + Control textWidget = fTextWidgetMap.get(selectedPage); + if (textWidget != null) { + fPageBook.showPage(textWidget); + return; + } + + if (selectedPage instanceof ITextEditor) { + // Create and show a minimap page for the given text editor page + ITextEditor textEditor = (ITextEditor) selectedPage; + MinimapPage minimapPage = new MinimapPage(textEditor); + minimapPage.createControl(fPageBook); + textWidget = minimapPage.getControl(); + fTextWidgetMap.put(selectedPage, textWidget); + fPageBook.showPage(textWidget); + } else { + fTextWidgetMap.put(selectedPage, fErrorLabel); + fPageBook.showPage(fErrorLabel); + } + }; + multiPageEditor.addPageChangedListener(fPageChangedListener); + } + + @Override + public void createControl(Composite parent) { + fPageBook = new PageBook(parent, SWT.NORMAL); + fErrorLabel = new Label(fPageBook, SWT.NORMAL); + fErrorLabel.setText(MinimapMessages.MinimapViewNoMinimap); + fPageChangedListener.pageChanged(null); + } + + @Override + public Control getControl() { + return fPageBook; + } + + @Override + public void setFocus() { + fPageBook.setFocus(); + } + + @Override + public void dispose() { + super.dispose(); + fMultiPageEditor.removePageChangedListener(fPageChangedListener); + } +} |