| /*=============================================================================# |
| # Copyright (c) 2009, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.ecommons.ui.mpbv; |
| |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.IHandler2; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IPropertyListener; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPartSite; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.menus.CommandContributionItemParameter; |
| import org.eclipse.ui.part.IPage; |
| import org.eclipse.ui.part.IPageBookViewPage; |
| import org.eclipse.ui.part.MessagePage; |
| import org.eclipse.ui.part.PageBook; |
| import org.eclipse.ui.part.PageBookView; |
| import org.eclipse.ui.part.PageSite; |
| import org.eclipse.ui.part.PageSwitcher; |
| import org.eclipse.ui.services.IServiceLocator; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.lang.NonNull; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.ui.SharedUIResources; |
| import org.eclipse.statet.ecommons.ui.actions.HandlerCollection; |
| import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem; |
| import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem; |
| import org.eclipse.statet.ecommons.ui.util.StatusLineMessageManager; |
| import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers; |
| |
| |
| @NonNullByDefault |
| public abstract class ManagedPageBookView<S extends PageBookSession> extends PageBookView { |
| |
| |
| protected static final String PAGE_CONTROL_MENU_ID= "page_control"; //$NON-NLS-1$ |
| |
| |
| private class SessionHandler implements IWorkbenchPart { |
| |
| |
| private final S session; |
| |
| |
| public SessionHandler(final S session) { |
| this.session= session; |
| } |
| |
| |
| ManagedPageBookView<S> getView() { |
| return ManagedPageBookView.this; |
| } |
| |
| @Override |
| public IWorkbenchPartSite getSite() { |
| return ManagedPageBookView.this.getSite(); |
| } |
| |
| public S getSession() { |
| return this.session; |
| } |
| |
| |
| @Override |
| public String getTitle() { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public @Nullable Image getTitleImage() { |
| return null; |
| } |
| |
| @Override |
| public String getTitleToolTip() { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void addPropertyListener(final IPropertyListener listener) { |
| } |
| |
| @Override |
| public void removePropertyListener(final IPropertyListener listener) { |
| } |
| |
| @Override |
| public void createPartControl(final Composite parent) { |
| } |
| |
| @Override |
| public void setFocus() { |
| } |
| |
| @Override |
| public void dispose() { |
| } |
| |
| @Override |
| public <T> @Nullable T getAdapter(final Class<T> adapterType) { |
| return null; |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.session.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(final @Nullable Object obj) { |
| return (this == obj |
| || ((obj instanceof ManagedPageBookView<?>.SessionHandler) |
| && (this.session == ((SessionHandler) obj).session) )); |
| } |
| |
| } |
| |
| private class NewPageHandler extends AbstractHandler { |
| |
| public NewPageHandler() { |
| } |
| |
| @Override |
| public void setEnabled(final @Nullable Object evaluationContext) { |
| } |
| |
| @Override |
| public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException { |
| newPage(null, true); |
| return null; |
| } |
| |
| } |
| |
| private class CloseCurrentPageHandler extends AbstractHandler { |
| |
| public CloseCurrentPageHandler() { |
| } |
| |
| @Override |
| public void setEnabled(final @Nullable Object evaluationContext) { |
| setBaseEnabled(!ManagedPageBookView.this.sessionList.isEmpty()); |
| } |
| |
| @Override |
| public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException { |
| final S session= getCurrentSession(); |
| if (session != null) { |
| closePage(session); |
| } |
| return null; |
| } |
| |
| } |
| |
| public class CloseAllPagesHandler extends AbstractHandler { |
| |
| |
| @Override |
| public void setEnabled(final @Nullable Object evaluationContext) { |
| setBaseEnabled(!ManagedPageBookView.this.sessionList.isEmpty()); |
| } |
| |
| @Override |
| public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException { |
| ManagedPageBookView.this.sessionHistory.clear(); |
| final List<S> sessions= getSessions(); |
| for (final S session : sessions) { |
| closePage(session); |
| } |
| return null; |
| } |
| |
| } |
| |
| |
| private final List<@NonNull S> sessionList= new ArrayList<>(); |
| private final Map<S, SessionHandler> sessionMap= new HashMap<>(); |
| private Comparator<S> sessionComparator; |
| |
| private final List<S> sessionHistory= new LinkedList<>(); |
| |
| private @Nullable SessionHandler activeSession; |
| |
| private ContextHandlers handlers; |
| |
| private StatusLineMessageManager statusManager; |
| |
| |
| public ManagedPageBookView() { |
| } |
| |
| |
| protected void setSessionComparator(final Comparator<S> comparator) { |
| this.sessionComparator= comparator; |
| } |
| |
| @Override |
| protected boolean isImportant(final IWorkbenchPart part) { |
| return ( (part instanceof ManagedPageBookView<?>.SessionHandler) |
| && ((ManagedPageBookView<?>.SessionHandler) part).getView() == this ); |
| } |
| |
| @Override |
| protected @Nullable IWorkbenchPart getBootstrapPart() { |
| return null; |
| } |
| |
| @Override |
| protected void initPage(final IPageBookViewPage page) { |
| // E-Bug 473941 |
| try { |
| page.init(new PageSite(getViewSite()) { |
| @Override |
| public void activate() { |
| super.activate(); |
| |
| final IEclipseContext context= getService(IEclipseContext.class); |
| if (context != null) { |
| context.activate(); |
| } |
| } |
| @Override |
| public void deactivate() { |
| super.deactivate(); |
| |
| final IEclipseContext context= getService(IEclipseContext.class); |
| if (context != null) { |
| context.deactivate(); |
| } |
| } |
| }); |
| } |
| catch (final PartInitException e) { |
| WorkbenchPlugin.log(getClass(), "initPage", e); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public void createPartControl(final Composite parent) { |
| super.createPartControl(parent); |
| |
| final IViewSite site= getViewSite(); |
| this.statusManager= new StatusLineMessageManager(site.getActionBars().getStatusLineManager()); |
| initActions(site, |
| this.handlers= new ContextHandlers(site.getService(IHandlerService.class)) ); |
| initPageSwitcher(); |
| contributeToActionBars(site, site.getActionBars(), this.handlers); |
| |
| updateState(); |
| } |
| |
| @Override |
| protected IPage createDefaultPage(final PageBook book) { |
| final MessagePage page= new MessagePage(); |
| page.createControl(getPageBook()); |
| initPage(page); |
| return page; |
| } |
| |
| @Override |
| protected @Nullable PageRec doCreatePage(final IWorkbenchPart part) { |
| final SessionHandler sessionHandler= (SessionHandler) part; |
| final S session= sessionHandler.getSession(); |
| |
| final IPageBookViewPage page= doCreatePage(session); |
| if (page != null) { |
| initPage(page); |
| page.createControl(getPageBook()); |
| |
| final PageRec pageRecord= new PageRec(part, page); |
| return pageRecord; |
| } |
| return null; |
| } |
| |
| protected /* abstract */ @Nullable IPageBookViewPage doCreatePage(final S session) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| protected void showPageRec(final PageRec pageRec) { |
| if ((this.activeSession != null) ? (pageRec.part != this.activeSession) : (pageRec.part != null)) { |
| onPageHiding((IPageBookViewPage) getCurrentPage(), (this.activeSession != null) ? this.activeSession.getSession() : null); |
| this.activeSession= null; |
| |
| super.showPageRec(pageRec); |
| |
| this.activeSession= (SessionHandler) pageRec.part; |
| |
| final S session; |
| if (this.activeSession != null) { |
| session= this.activeSession.getSession(); |
| this.sessionHistory.remove(session); |
| this.sessionHistory.add(0, session); |
| } |
| else { |
| session= null; |
| } |
| onPageShowing((IPageBookViewPage) pageRec.page, session); |
| } |
| updateTitle(); |
| } |
| |
| protected void updateTitle() { |
| final @Nullable S session= getCurrentSession(); |
| if (session == null) { |
| setContentDescription(getNoPageTitle()); |
| } |
| else { |
| setContentDescription(session.getLabel()); |
| } |
| } |
| |
| protected String getNoPageTitle() { |
| return "No page at this time."; |
| } |
| |
| @Override |
| public void partClosed(final IWorkbenchPart part) { |
| if (part instanceof ManagedPageBookView<?>.SessionHandler) { |
| final SessionHandler sessionHandler= (SessionHandler) part; |
| final S session= sessionHandler.getSession(); |
| |
| this.sessionList.remove(session); |
| this.sessionHistory.remove(session); |
| |
| if (this.activeSession == part) { |
| if (!this.sessionHistory.isEmpty()) { |
| showPage(this.sessionHistory.get(0)); |
| } |
| else if (!this.sessionList.isEmpty()) { |
| showPage(this.sessionList.get(this.sessionList.size()-1)); |
| } |
| } |
| super.partClosed(part); |
| } |
| } |
| |
| @Override |
| protected void doDestroyPage(final IWorkbenchPart part, final PageRec pageRecord) { |
| final SessionHandler sessionHandler= (SessionHandler) part; |
| final S session= sessionHandler.getSession(); |
| |
| pageRecord.page.dispose(); |
| pageRecord.dispose(); |
| |
| this.sessionMap.remove(session); |
| if (sessionHandler == this.activeSession) { |
| this.activeSession= null; |
| } |
| } |
| |
| |
| private void initPageSwitcher() { |
| new PageSwitcher(this) { |
| @Override |
| public Object[] getPages() { |
| return ManagedPageBookView.this.sessionList.toArray(); |
| } |
| @Override |
| public String getName(final Object page) { |
| return ((S) page).getLabel(); |
| } |
| @Override |
| public @Nullable ImageDescriptor getImageDescriptor(final Object page) { |
| return ((S) page).getImageDescriptor(); |
| } |
| @Override |
| public int getCurrentPageIndex() { |
| return (ManagedPageBookView.this.activeSession != null) ? |
| ManagedPageBookView.this.sessionList.indexOf( |
| ManagedPageBookView.this.activeSession.getSession() ) : |
| -1; |
| } |
| @Override |
| public void activatePage(final Object page) { |
| showPage((S) page); |
| } |
| }; |
| } |
| |
| |
| protected boolean getPageControlByUser() { |
| return true; |
| } |
| |
| protected void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) { |
| if (getPageControlByUser()) { |
| final IHandler2 newPageHandler= createNewPageHandler(); |
| if (newPageHandler != null) { |
| handlers.addActivate(SharedUIResources.NEW_PAGE_COMMAND_ID, newPageHandler); |
| } |
| final IHandler2 closePageHandler= new CloseCurrentPageHandler(); |
| handlers.addActivate(SharedUIResources.CLOSE_PAGE_COMMAND_ID, closePageHandler); |
| final IHandler2 closeAllPagesHandler= new CloseAllPagesHandler(); |
| handlers.addActivate(SharedUIResources.CLOSE_ALL_PAGES_COMMAND_ID, closeAllPagesHandler); |
| } |
| } |
| |
| protected @Nullable IHandler2 createNewPageHandler() { |
| return new NewPageHandler(); |
| } |
| |
| protected void contributeToActionBars(final IServiceLocator serviceLocator, |
| final IActionBars actionBars, final HandlerCollection handlers) { |
| final IToolBarManager toolBarManager= actionBars.getToolBarManager(); |
| |
| toolBarManager.add(new Separator(ADDITIONS_GROUP_ID)); |
| toolBarManager.add(new Separator(PAGE_CONTROL_MENU_ID)); |
| { final IHandler2 handler= handlers.get(SharedUIResources.NEW_PAGE_COMMAND_ID); |
| if (handler != null) { |
| toolBarManager.appendToGroup(PAGE_CONTROL_MENU_ID, |
| new HandlerContributionItem(new CommandContributionItemParameter( |
| serviceLocator, null, SharedUIResources.NEW_PAGE_COMMAND_ID, HandlerContributionItem.STYLE_PUSH), |
| handler)); |
| } |
| } |
| toolBarManager.appendToGroup(PAGE_CONTROL_MENU_ID, |
| new SimpleContributionItem("page_control.change_page", //$NON-NLS-1$ |
| "Pages", null, |
| SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_CHANGE_PAGE_IMAGE_ID), null, |
| SimpleContributionItem.STYLE_PULLDOWN) { |
| @Override |
| protected void dropDownMenuAboutToShow(final IMenuManager manager) { |
| manager.add(new ShowPageDropdownContribution<>(ManagedPageBookView.this)); |
| } |
| @Override |
| protected void execute() throws ExecutionException { |
| if (ManagedPageBookView.this.sessionHistory.size() >= 2) { |
| showPage(ManagedPageBookView.this.sessionHistory.get(1)); |
| } |
| } |
| }); |
| { final IHandler2 handler= handlers.get(SharedUIResources.CLOSE_PAGE_COMMAND_ID); |
| if (handler != null) { |
| toolBarManager.appendToGroup(PAGE_CONTROL_MENU_ID, |
| new HandlerContributionItem(new CommandContributionItemParameter( |
| serviceLocator, null, SharedUIResources.CLOSE_PAGE_COMMAND_ID, HandlerContributionItem.STYLE_PUSH), |
| handler)); |
| } |
| } |
| { final IHandler2 handler= handlers.get(SharedUIResources.CLOSE_ALL_PAGES_COMMAND_ID); |
| if (handler != null) { |
| toolBarManager.appendToGroup(PAGE_CONTROL_MENU_ID, |
| new HandlerContributionItem(new CommandContributionItemParameter( |
| serviceLocator, null, SharedUIResources.CLOSE_ALL_PAGES_COMMAND_ID, HandlerContributionItem.STYLE_PUSH), |
| handler)); |
| } |
| } |
| } |
| |
| @Override |
| public void dispose() { |
| if (this.handlers != null) { |
| this.handlers.dispose(); |
| this.handlers= null; |
| } |
| |
| super.dispose(); |
| } |
| |
| |
| public @Nullable IPage newPage(@Nullable S session, final boolean show) { |
| session= checkNewSession(session); |
| if (session == null || this.sessionList.contains(session)) { |
| return null; |
| } |
| final SessionHandler sessionHandler= new SessionHandler(session); |
| if (this.sessionComparator != null) { |
| final int idx= Collections.binarySearch(this.sessionList, session, this.sessionComparator); |
| this.sessionList.add((idx >= 0) ? idx : -(idx+1), session); |
| } |
| else { |
| this.sessionList.add(session); |
| } |
| this.sessionMap.put(session, sessionHandler); |
| if (show) { |
| partActivated(sessionHandler); |
| final PageRec pageRec= getPageRec(sessionHandler); |
| if (pageRec != null) { |
| return pageRec.page; |
| } |
| else { |
| this.sessionMap.remove(sessionHandler); |
| this.sessionList.remove(session); |
| return null; |
| } |
| } |
| else { |
| return null; |
| } |
| } |
| |
| protected @Nullable S checkNewSession(final @Nullable S session) { |
| return session; |
| } |
| |
| public @Nullable IPage getPage(final S session) { |
| final SessionHandler sessionHandler= this.sessionMap.get(session); |
| if (sessionHandler != null) { |
| final PageRec pageRec= getPageRec(sessionHandler); |
| if (pageRec != null) { |
| return pageRec.page; |
| } |
| } |
| return null; |
| } |
| |
| public void showPage(final S session) { |
| final SessionHandler sessionHandler= this.sessionMap.get(session); |
| if (sessionHandler != null) { |
| partActivated(sessionHandler); |
| } |
| } |
| |
| public void closePage(final S session) { |
| final SessionHandler sessionHandler= this.sessionMap.get(session); |
| if (sessionHandler != null) { |
| partClosed(sessionHandler); |
| } |
| } |
| |
| public final ImList<S> getSessions() { |
| return ImCollections.toList(this.sessionList); |
| } |
| |
| public final @Nullable S getCurrentSession() { |
| final SessionHandler sessionHandler= this.activeSession; |
| if (sessionHandler != null) { |
| return sessionHandler.getSession(); |
| } |
| return null; |
| } |
| |
| protected void onPageHiding(final IPageBookViewPage page, final S session) { |
| updateState(); |
| } |
| |
| protected void onPageShowing(final IPageBookViewPage page, final S session) { |
| updateState(); |
| } |
| |
| protected StatusLineMessageManager getStatusManager() { |
| return this.statusManager; |
| } |
| |
| protected void updateState() { |
| final Object evaluationContext= null; |
| this.handlers.update(evaluationContext); |
| |
| final IPage currentPage= getCurrentPage(); |
| if (currentPage instanceof ManagedPage<?>) { |
| ((ManagedPage<?>) currentPage).updateState(evaluationContext); |
| } |
| |
| getViewSite().getActionBars().getToolBarManager().update(true); |
| } |
| |
| } |