blob: 7010524fd99e45354966df4d5c491d051fe5d2a3 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 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.internal.r.ui.rhelp;
import java.net.URI;
import java.net.URISyntaxException;
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.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.browser.TitleEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserSession;
import org.eclipse.statet.ecommons.ui.mpbv.PageBookBrowserPage;
import org.eclipse.statet.ecommons.ui.mpbv.PageBookBrowserView;
import org.eclipse.statet.ecommons.ui.viewers.breadcrumb.IBreadcrumb;
import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers;
import org.eclipse.statet.r.core.RCore;
import org.eclipse.statet.r.ui.RUI;
import org.eclipse.statet.rhelp.core.RHelpUtils;
import org.eclipse.statet.rhelp.core.http.RHelpHttpService;
import org.eclipse.statet.rj.renv.core.REnv;
@NonNullByDefault
public class RHelpViewPage extends PageBookBrowserPage implements IAdaptable {
private IBreadcrumb breadcrumb;
private Control breadcrumbControl;
private @Nullable Object helpObject;
private final ILabelProvider labelProvider= new RHelpLabelProvider();
public RHelpViewPage(final PageBookBrowserView view, final BrowserSession session) {
super(view, session);
}
@Override
public void dispose() {
super.dispose();
this.labelProvider.dispose();
}
public Object getHelpObject() {
return this.helpObject;
}
@Override
public void setUrl(final @Nullable String url) {
if (url != null && url.startsWith(RHelpHttpService.PORTABLE_URI_SCHEME + ':')) {
try {
URI uri= new URI(url);
uri= RCore.getRHelpHttpService().toHttpUrl(uri);
super.setUrl(uri);
return;
}
catch (final URISyntaxException e) {
// ?
return;
}
}
super.setUrl(url);
}
@Override
public void setUrl(@Nullable URI url) {
if (url != null && url.getScheme().equals(RHelpHttpService.PORTABLE_URI_SCHEME)) {
try {
url= RCore.getRHelpHttpService().toHttpUrl(url);
}
catch (final URISyntaxException e) {
return;
}
}
super.setUrl(url);
}
@Override
protected Control createAddressBar(final Composite parent) {
this.breadcrumb= new RHelpBreadcrumb(this);
if (this.breadcrumb != null) {
this.breadcrumbControl= this.breadcrumb.createContent(parent);
updateBreadcrumbInput();
}
return this.breadcrumbControl;
}
@Override
protected void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) {
super.initActions(serviceLocator, handlers);
final IHandlerService handlerService= serviceLocator.getService(IHandlerService.class);
final IContextService contextService= serviceLocator.getService(IContextService.class);
final IHandler2 breadcrumbHandler= new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
if (RHelpViewPage.this.breadcrumb != null) {
RHelpViewPage.this.breadcrumb.activate();
}
return null;
}
};
handlers.add(IBreadcrumb.SHOW_BREADCRUMB_COMMAND_ID, breadcrumbHandler);
handlerService.activateHandler(IBreadcrumb.SHOW_BREADCRUMB_COMMAND_ID, breadcrumbHandler);
contextService.activateContext(IBreadcrumb.WITH_BREADCRUMB_CONTEXT_ID);
}
@Override
protected void onPageChanged() {
super.onPageChanged();
try {
final BrowserSession session= getSession();
final Object input= RCore.getRHelpHttpService().getContentOfUrl(session.getUrl());
this.helpObject= input;
final Image image= this.labelProvider.getImage(input);
if (image != null) {
setIcon(session, ImageDescriptor.createFromImage(image));
}
updateBreadcrumbInput();
}
catch (final Exception e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, RUI.BUNDLE_ID, 0,
"An error occurred when updating the R help view address bar/breadcrumbs.", e));
}
}
@Override
public void changed(final TitleEvent event) {
super.changed(event);
if (this.helpObject == null) {
updateBreadcrumbInput();
}
}
/**
* Makes the breadcrumb visible.
*/
private void showBreadcrumb() {
if (this.breadcrumb == null || this.breadcrumbControl.isVisible()) {
return;
}
// ((GridData) fBreadcrumbControl.getLayoutData()).exclude= false;
this.breadcrumbControl.setVisible(true);
this.breadcrumbControl.getParent().layout(true, true);
}
/**
* Hides the breadcrumb
*/
private void hideBreadcrumb() {
if (this.breadcrumb == null || !this.breadcrumbControl.isVisible()) {
return;
}
// ((GridData) fBreadcrumbControl.getLayoutData()).exclude= true;
this.breadcrumbControl.setVisible(false);
this.breadcrumbControl.getParent().layout(true, true);
}
/**
* Sets the breadcrumb input to the given element.
* @param content the element to use as input for the breadcrumb
* @since 3.4
*/
private void updateBreadcrumbInput() {
if (this.breadcrumb == null) {
return;
}
Object input= this.helpObject;
if (input == null) {
if (getCurrentUrl().length() > 0) {
input= getCurrentTitle();
}
}
else if (input instanceof Object[]) {
final Object[] array= (Object[]) input;
if (array.length >= 2) {
array[array.length-1]= getCurrentTitle();
}
else {
input= null;
}
}
this.breadcrumb.setInput(input);
}
@Override
@SuppressWarnings("unchecked")
public <T> @Nullable T getAdapter(final Class<T> adapterType) {
if (adapterType == REnv.class) {
final Object input= this.helpObject;
if (input != null) {
if (input instanceof REnv) {
return (T) input;
}
return (T) RHelpUtils.getREnv(input);
}
return null;
}
return null;
}
}