Have icon for "reset" entry in reflog
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / commit / MultiPageEditorContentOutlinePage.java
blobf78875e713f73adb391faa7513cbafc7cc68cac0
1 /*******************************************************************************
2 * Copyright (C) 2016, Thomas Wolf <thomas.wolf@paranor.ch>
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.commit;
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.concurrent.CopyOnWriteArrayList;
17 import org.eclipse.egit.core.AdapterUtils;
18 import org.eclipse.egit.ui.internal.UIText;
19 import org.eclipse.jface.dialogs.IPageChangedListener;
20 import org.eclipse.jface.util.SafeRunnable;
21 import org.eclipse.jface.viewers.ISelection;
22 import org.eclipse.jface.viewers.ISelectionChangedListener;
23 import org.eclipse.jface.viewers.ISelectionProvider;
24 import org.eclipse.jface.viewers.SelectionChangedEvent;
25 import org.eclipse.jface.viewers.StructuredSelection;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.ui.IEditorPart;
30 import org.eclipse.ui.SubActionBars;
31 import org.eclipse.ui.part.IPage;
32 import org.eclipse.ui.part.MessagePage;
33 import org.eclipse.ui.part.MultiPageEditorPart;
34 import org.eclipse.ui.part.Page;
35 import org.eclipse.ui.part.PageBook;
36 import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
37 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
39 /**
40 * A {@link ContentOutlinePage} for {@link MultiPageEditorPart}s. The
41 * {@link org.eclipse.ui.views.contentoutline.ContentOutline ContentOutline}
42 * view only automatically handles outline pages of top-level editors, but not
43 * of nested editors. (It reacts only to part events, not to page change events,
44 * and moreover the MultiPageEditorPart framework does not send events when
45 * pages are added or removed.)
46 * <p>
47 * This class manages content outline pages for nested editors in its own
48 * {@link PageBook}. Nested editors can provide their outline pages as usual by
49 * adapting to {@link IContentOutlinePage}.
50 * </p>
52 public class MultiPageEditorContentOutlinePage extends ContentOutlinePage {
54 private final MultiPageEditorPart editorPart;
56 private final ISelectionChangedListener globalSelectionListener = //
57 event -> fireSelectionChangedEvent(event);
59 private final CopyOnWriteArrayList<ISelectionChangedListener> selectionListeners = new CopyOnWriteArrayList<>();
61 private PageBook book;
63 private MessagePage emptyPage;
65 private IPage currentPage;
67 private IPageChangedListener pageListener;
69 private final Map<IEditorPart, IPage> pages = new HashMap<>();
71 private final Map<IPage, SubActionBars> bars = new HashMap<>();
73 /**
74 * Creates a new {@link MultiPageEditorContentOutlinePage} for the given
75 * top-level editor part. It will track page changes and create and manage
76 * outline pages for any nested {@link IEditorPart}s of that top-level
77 * editor part.
79 * @param editorPart
80 * the outline page belongs to
82 public MultiPageEditorContentOutlinePage(MultiPageEditorPart editorPart) {
83 super();
84 this.editorPart = editorPart;
87 @Override
88 public void createControl(Composite parent) {
89 book = new PageBook(parent, SWT.NONE);
90 emptyPage = new MessagePage();
91 emptyPage.createControl(book);
92 emptyPage
93 .setMessage(UIText.MultiPageEditorContentOutlinePage_NoOutline);
94 Object activePage = editorPart.getSelectedPage();
95 if (activePage instanceof IEditorPart) {
96 showPage(createOutlinePage((IEditorPart) activePage));
97 } else {
98 currentPage = emptyPage;
99 book.showPage(emptyPage.getControl());
101 pageListener = (event) -> {
102 Object newPage = event.getSelectedPage();
103 if (!(newPage instanceof IEditorPart)) {
104 showPage(emptyPage);
105 return;
107 IPage newOutlinePage = pages.get(newPage);
108 if (newOutlinePage == null) {
109 newOutlinePage = createOutlinePage((IEditorPart) newPage);
111 showPage(newOutlinePage);
113 editorPart.addPageChangedListener(pageListener);
116 @Override
117 public void dispose() {
118 if (pageListener != null) {
119 editorPart.removePageChangedListener(pageListener);
120 pageListener = null;
122 pages.clear();
123 selectionListeners.clear();
124 for (SubActionBars bar : bars.values()) {
125 bar.dispose();
127 bars.clear();
128 if (currentPage instanceof ISelectionProvider) {
129 ((ISelectionProvider) currentPage)
130 .removeSelectionChangedListener(globalSelectionListener);
132 currentPage = null;
133 if (book != null) {
134 book.dispose();
135 book = null;
137 if (emptyPage != null) {
138 emptyPage.dispose();
139 emptyPage = null;
143 @Override
144 public Control getControl() {
145 return book;
148 @Override
149 public void setFocus() {
150 // See org.eclipse.ui.part.PageBookView
151 book.setFocus();
152 currentPage.setFocus();
155 @Override
156 public void addSelectionChangedListener(
157 ISelectionChangedListener listener) {
158 selectionListeners.addIfAbsent(listener);
161 @Override
162 public ISelection getSelection() {
163 if (currentPage instanceof ISelectionProvider) {
164 return ((ISelectionProvider) currentPage).getSelection();
166 return StructuredSelection.EMPTY;
169 @Override
170 public void removeSelectionChangedListener(
171 ISelectionChangedListener listener) {
172 selectionListeners.remove(listener);
175 @Override
176 public void setSelection(ISelection selection) {
177 if (currentPage instanceof ISelectionProvider) {
178 ((ISelectionProvider) currentPage).setSelection(selection);
182 private void showPage(IPage page) {
183 if (page == null) {
184 page = emptyPage;
186 if (currentPage == page) {
187 return;
189 if (currentPage instanceof ISelectionProvider) {
190 ((ISelectionProvider) currentPage)
191 .removeSelectionChangedListener(globalSelectionListener);
193 SubActionBars localBars = bars.get(currentPage);
194 if (localBars != null) {
195 localBars.deactivate();
197 currentPage = page;
198 if (currentPage instanceof ISelectionProvider) {
199 ((ISelectionProvider) currentPage)
200 .addSelectionChangedListener(globalSelectionListener);
202 localBars = bars.get(currentPage);
203 Control control = page.getControl();
204 if (control == null || control.isDisposed()) {
205 page.createControl(book);
206 page.setActionBars(localBars);
207 control = page.getControl();
209 if (localBars != null) {
210 localBars.activate();
212 getSite().getActionBars().updateActionBars();
213 book.showPage(control);
214 if (currentPage instanceof ISelectionProvider) {
215 ISelection selection = ((ISelectionProvider) currentPage)
216 .getSelection();
217 fireSelectionChangedEvent(new SelectionChangedEvent(
218 (ISelectionProvider) currentPage, selection));
219 } else {
220 fireSelectionChangedEvent(
221 new SelectionChangedEvent(this, StructuredSelection.EMPTY));
225 private IPage createOutlinePage(IEditorPart editor) {
226 IContentOutlinePage outlinePage = AdapterUtils.adapt(editor,
227 IContentOutlinePage.class);
228 if (outlinePage == null) {
229 pages.put(editor, emptyPage);
230 return emptyPage;
232 pages.put(editor, outlinePage);
233 if (outlinePage instanceof NestedContentOutlinePage) {
234 ((Page) outlinePage).init(getSite());
236 SubActionBars pageBars = new SubActionBars(getSite().getActionBars());
237 bars.put(outlinePage, pageBars);
238 return outlinePage;
241 private void fireSelectionChangedEvent(SelectionChangedEvent event) {
242 for (ISelectionChangedListener listener : selectionListeners) {
243 SafeRunnable.run(new SafeRunnable() {
245 @Override
246 public void run() {
247 listener.selectionChanged(event);