blob: ab33e7fde2df08c874fb19f0fb2a27068812d8d3 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2018 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.rj.eclient.graphics;
import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
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.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.StatusLineContributionItem;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.views.IViewDescriptor;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.ts.core.Tool;
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.mpbv.ManagedPageBookView;
import org.eclipse.statet.ecommons.ui.mpbv.PageBookSession;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers;
import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
import org.eclipse.statet.rj.eclient.core.RToolService;
/**
* Multi page view for R graphics.
* <p>
* No view is registered by this plug-in.</p>
*/
@NonNullByDefault
public abstract class PageBookRGraphicView extends ManagedPageBookView<PageBookRGraphicView.RGraphicSession> {
public class RGraphicSession implements PageBookSession {
private final ERGraphic graphic;
public RGraphicSession(final ERGraphic graphic) {
this.graphic= graphic;
}
@Override
public String getLabel() {
return this.graphic.getLabel();
}
@Override
public @Nullable ImageDescriptor getImageDescriptor() {
return ImageDescriptor.createFromImage(getTitleImage());
}
public ERGraphic getGraphic() {
return this.graphic;
}
}
public static class ShowRequiredViewListener implements ERGraphicsManager.ListenerShowExtension {
private final String viewId;
public ShowRequiredViewListener(final String viewId) {
this.viewId= viewId;
}
@Override
public int canShowGraphic(final ERGraphic graphic) {
return 0;
}
private static String getId(final IViewReference ref) {
// E-Bug #405563
final String id= ref.getId();
final int idx= id.indexOf(':');
return (idx >= 0) ? id.substring(0, idx) : id;
}
@Override
public void showGraphic(final ERGraphic graphic) {
try {
final IWorkbenchPage page= getBestPage(graphic);
String secondaryId= ""; //$NON-NLS-1$
final IViewReference[] refs= page.getViewReferences();
for (int i= 0; i < refs.length; i++) { // search views not yet instanced
if (this.viewId.equals(getId(refs[i])) && refs[i].getView(false) == null) {
if (refs[i].getSecondaryId() == null) {
secondaryId= null;
break;
}
if (secondaryId == "") { //$NON-NLS-1$
secondaryId= refs[i].getSecondaryId();
}
}
}
if (secondaryId == "") { //$NON-NLS-1$
secondaryId= "t"+System.currentTimeMillis(); //$NON-NLS-1$
}
newViewGraphic= graphic;
page.showView(this.viewId, secondaryId, IWorkbenchPage.VIEW_VISIBLE );
}
catch (final PartInitException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
"An error occurred when opening a new R Graphics view.", e ));
}
finally {
newViewGraphic= null;
}
}
protected IWorkbenchPage getBestPage(final ERGraphic graphic) {
return UIAccess.getActiveWorkbenchPage(true);
}
@Override
public void graphicAdded(final ERGraphic graphic) {
}
@Override
public void graphicRemoved(final ERGraphic graphic) {
}
}
protected static abstract class NewDevHandler extends AbstractHandler {
public NewDevHandler() {
}
protected abstract Tool getTool() throws CoreException;
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
try {
final Tool tool= getTool();
if (tool != null) {
tool.getQueue().add(new AbstractRToolRunnable(
"r/rj/gd/new", "New R Graphic") { //$NON-NLS-1$
@Override
public void run(final RToolService r,
final IProgressMonitor monitor) throws CoreException {
r.evalVoid("rj.gd::rj.GD()", monitor); //$NON-NLS-1$
}
});
}
}
catch (final CoreException e) {
if (e.getStatus().getSeverity() != IStatus.CANCEL) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
"An error occurrend when creating a new graphic device.", e),
StatusManager.LOG | StatusManager.SHOW);
}
}
return null;
}
}
private static class RGraphicComparator implements Comparator<RGraphicSession> {
public RGraphicComparator() {
}
@Override
public int compare(final RGraphicSession o1, final RGraphicSession o2) {
final Tool handle1= o1.graphic.getRHandle();
final Tool handle2= o2.graphic.getRHandle();
if (handle1 == null) {
if (handle2 == null) {
return 0;
}
return Integer.MIN_VALUE;
}
else if (handle2 == null) {
return Integer.MAX_VALUE;
}
if (handle1 != handle2) {
final int diff= handle1.getLabel(Tool.LONG_LABEL).compareTo(handle2.getLabel(Tool.LONG_LABEL));
if (diff != 0) {
return diff;
}
}
return o1.graphic.getDevId() - o2.graphic.getDevId();
}
}
private static class OpenAdditionalViewHandler extends AbstractHandler {
private final IViewSite viewSite;
public OpenAdditionalViewHandler(final IViewSite viewSite) {
this.viewSite= viewSite;
}
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
try {
final String secondaryId= "t" + System.currentTimeMillis(); //$NON-NLS-1$
this.viewSite.getWorkbenchWindow().getActivePage().showView(this.viewSite.getId(),
secondaryId, IWorkbenchPage.VIEW_ACTIVATE );
}
catch (final PartInitException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
"An error occurred when opening an additional R graphics view.", e));
}
return null;
}
}
private class PinPageAction extends SimpleContributionItem {
public PinPageAction() {
super("Pin Graphic Page", "P",
SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_PIN_PAGE_IMAGE_ID),
SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOLD_PIN_PAGE_IMAGE_ID),
SimpleContributionItem.STYLE_CHECK );
setChecked(PageBookRGraphicView.this.pinPage);
}
@Override
protected void execute() throws ExecutionException {
PageBookRGraphicView.this.pinPage= !PageBookRGraphicView.this.pinPage;
setChecked(PageBookRGraphicView.this.pinPage);
}
}
private static @Nullable ERGraphic newViewGraphic;
private ERGraphicsManager manager;
private final ERGraphicsManager.ListenerShowExtension managerListener= new ERGraphicsManager.ListenerShowExtension() {
private @Nullable ERGraphic toShow;
@Override
public int canShowGraphic(final ERGraphic graphic) {
return PageBookRGraphicView.this.canShowGraphic(graphic);
}
@Override
public void showGraphic(final ERGraphic graphic) {
this.toShow= graphic;
final IViewSite site= getViewSite();
try {
site.getPage().showView(site.getId(), site.getSecondaryId(), IWorkbenchPage.VIEW_VISIBLE);
}
catch (final PartInitException e) {}
}
@Override
public void graphicAdded(final ERGraphic graphic) {
add(graphic, graphic == this.toShow
|| (graphic.isActive() && (!PageBookRGraphicView.this.pinPage || getCurrentSession() == null)) );
this.toShow= null;
}
@Override
public void graphicRemoved(final ERGraphic graphic) {
final RGraphicSession session= getSession(graphic);
if (session != null) {
PageBookRGraphicView.super.closePage(session);
}
}
};
private boolean pinPage;
private final ERGraphic.Listener graphicListener= new ERGraphic.ListenerLocatorExtension() {
@Override
public void activated() {
updateTitle();
}
@Override
public void deactivated() {
updateTitle();
}
@Override
public void drawingStarted() {
}
@Override
public void drawingStopped() {
}
@Override
public void locatorStarted() {
updateTitle();
}
@Override
public void locatorStopped() {
updateTitle();
}
};
private StatusLineContributionItem positionStatusLineItem;
public PageBookRGraphicView() {
}
@Override
public void init(final IViewSite site, final @Nullable IMemento memento) throws PartInitException {
setSessionComparator(new RGraphicComparator());
super.init(site, memento);
this.manager= loadManager();
}
protected abstract ERGraphicsManager loadManager();
@Override
public void createPartControl(final Composite parent) {
super.createPartControl(parent);
if (this.manager != null) {
this.manager.addListener(this.managerListener);
ERGraphic active= newViewGraphic;
if (active != null) {
final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
for (final ERGraphic graphic : graphics) {
add(graphic, false);
}
}
else {
final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
for (final ERGraphic graphic : graphics) {
add(graphic, false);
if (graphic.isActive()) {
active= graphic;
}
}
if (active == null && !graphics.isEmpty()) {
active= graphics.get(graphics.size() - 1);
}
}
if (active != null) {
final RGraphicSession session= getSession(active);
if (session != null) {
showPage(session);
}
}
}
}
public @Nullable RGraphicSession getSession(final ERGraphic graphic) {
final List<RGraphicSession> sessions= getSessions();
for (final RGraphicSession session : sessions) {
if (session.getGraphic() == graphic) {
return session;
}
}
return null;
}
protected int canShowGraphic(final ERGraphic graphic) {
final RGraphicSession session= getCurrentSession();
int canShow;
if (session != null && session.getGraphic() == graphic) {
canShow= (this.pinPage) ? 20 : 10;
}
else if (this.pinPage && session != null) {
return -1;
}
else {
canShow= 1;
}
if (getViewSite().getPage().isPartVisible(this)) {
canShow+=2;
}
return canShow;
}
protected void add(final ERGraphic graphic, final boolean show) {
super.newPage(new RGraphicSession(graphic), show);
}
@Override
protected String getNoPageTitle() {
return "No graphics at this time.";
}
@Override
protected @Nullable IHandler2 createNewPageHandler() {
return null;
}
@Override
protected void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) {
super.initActions(serviceLocator, handlers);
final OpenAdditionalViewHandler openViewHandler= new OpenAdditionalViewHandler(getViewSite());
handlers.add(".OpenView", openViewHandler);
}
@Override
protected void contributeToActionBars(final IServiceLocator serviceLocator, final IActionBars actionBars, final HandlerCollection handlers) {
super.contributeToActionBars(serviceLocator, actionBars, handlers);
final IMenuManager menuManager= actionBars.getMenuManager();
menuManager.add(new Separator("view"));
final IViewDescriptor viewDescriptor= PlatformUI.getWorkbench().getViewRegistry().find(getViewSite().getId());
menuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
null, HandlerContributionItem.NO_COMMAND_ID, null,
viewDescriptor.getImageDescriptor(), null, null,
NLS.bind("Open Additional {0} View", viewDescriptor.getLabel()), "O", null,
HandlerContributionItem.STYLE_PUSH, null, false), handlers.get(".OpenView")));
menuManager.add(new Separator("save"));
menuManager.add(new Separator(ADDITIONS_GROUP_ID));
menuManager.add(new Separator("settings")); //$NON-NLS-1$
menuManager.add(new SimpleContributionItem("Preferences...", "P") {
@Override
protected void execute() throws ExecutionException {
final Shell shell= getViewSite().getShell();
final String[] preferencePages= collectContextMenuPreferencePages();
if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) {
org.eclipse.ui.dialogs.PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null).open();
}
}
});
final IToolBarManager toolBarManager= actionBars.getToolBarManager();
toolBarManager.insertAfter("page_control.change_page", new PinPageAction()); //$NON-NLS-1$
final IStatusLineManager lineManager= actionBars.getStatusLineManager();
this.positionStatusLineItem= new StatusLineContributionItem(RGraphicCompositeActionSet.POSITION_STATUSLINE_ITEM_ID, 20);
lineManager.add(this.positionStatusLineItem);
}
private String[] collectContextMenuPreferencePages() {
final List<String> pageIds= new ArrayList<>();
collectContextMenuPreferencePages(pageIds);
return pageIds.toArray(new String[pageIds.size()]);
}
protected void collectContextMenuPreferencePages(final List<String> pageIds) {
}
@Override
protected RGraphicPage doCreatePage(final RGraphicSession session) {
return new RGraphicPage(session.getGraphic());
}
@Override
protected void initPage(final IPageBookViewPage page) {
super.initPage(page);
if (page instanceof RGraphicPage) {
((RGraphicPage) page).init(this.positionStatusLineItem);
}
}
@Override
public void closePage(final RGraphicSession session) {
final IStatus status= session.getGraphic().close();
if (status != null && status.getSeverity() < IStatus.ERROR) {
return;
}
super.closePage(session);
}
@Override
protected void onPageShowing(final IPageBookViewPage page, final RGraphicSession session) {
if (session != null) {
session.getGraphic().addListener(this.graphicListener);
}
super.onPageShowing(page, session);
}
@Override
protected void onPageHiding(final IPageBookViewPage page, final RGraphicSession session) {
if (session != null) {
session.getGraphic().removeListener(this.graphicListener);
}
if (this.positionStatusLineItem != null) {
this.positionStatusLineItem.setText(""); //$NON-NLS-1$
}
super.onPageHiding(page, session);
}
@Override
public void dispose() {
if (this.manager != null) {
this.manager.removeListener(this.managerListener);
}
final RGraphicSession session= getCurrentSession();
if (session != null) {
session.getGraphic().removeListener(this.graphicListener);
}
super.dispose();
}
}