blob: f7bc7d6373d3df149ac1a91c68a8530c8413e0de [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2022 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 static org.eclipse.statet.ecommons.ui.actions.UIActions.NO_COMMAND_ID;
import java.net.URI;
import java.util.ArrayList;
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.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
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.dialogs.Dialog;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.browser.StatusTextEvent;
import org.eclipse.swt.browser.StatusTextListener;
import org.eclipse.swt.browser.TitleEvent;
import org.eclipse.swt.browser.TitleListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.commands.core.HandlerCollection;
import org.eclipse.statet.ecommons.ui.SharedUIResources;
import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem;
import org.eclipse.statet.ecommons.ui.actions.UIActions;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserHandler.CancelHandler;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserHandler.IBrowserProvider;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserHandler.NavigateBackHandler;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserHandler.NavigateForwardHandler;
import org.eclipse.statet.ecommons.ui.mpbv.BrowserHandler.OpenExternalHandler;
import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers;
@NonNullByDefault
public class PageBookBrowserView extends ManagedPageBookView<BrowserSession> {
private static final String BROWSERCONTROL_MENU_ID= "browser_control"; //$NON-NLS-1$
private static final String BOOKMARKS_MENU_ID= "bookmarks"; //$NON-NLS-1$
/** Action id (local) to open current page in external browser */
protected static final String OPEN_EXTERNAL_ID= ".OpenExternal"; //$NON-NLS-1$
/** Action id (local) to open create a bookmark */
protected static final String CREATE_BOOKMARK_ID= ".CreateBookmark"; //$NON-NLS-1$
/** Action id (command) to navigate one page back. */
protected static final String NAVIGATE_BACK_COMMAND_ID= IWorkbenchCommandConstants.NAVIGATE_BACK;
/** Action id (command) to navigate one page forward. */
protected static final String NAVIGATE_FORWARD_COMMAND_ID= IWorkbenchCommandConstants.NAVIGATE_FORWARD;
/** Action id (command) to go to home page. */
protected static final String GOTO_HOME_COMMAND_ID= "org.eclipse.statet.workbench.commands.GoToHome";
/** Action id (command) to refresh the current page. */
protected static final String REFRESH_PAGE_COMMAND_ID= IWorkbenchCommandConstants.FILE_REFRESH;
/** Action id (command) to print the current page. */
protected static final String PRINT_PAGE_COMMAND_ID= IWorkbenchCommandConstants.FILE_PRINT;
private class GoToHomeHandler extends AbstractHandler {
@Override
public void setEnabled(final @Nullable Object evaluationContext) {
}
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
openUrl(getHomePageUrl(), getCurrentSession());
return null;
}
}
private class RefreshHandler extends AbstractHandler {
@Override
public void setEnabled(final @Nullable Object evaluationContext) {
setBaseEnabled(PageBookBrowserView.this.currentBrowserPage != null);
}
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
final PageBookBrowserPage browserPage= PageBookBrowserView.this.currentBrowserPage;
if (browserPage != null) {
browserPage.refresh();
}
return null;
}
}
private class PrintHandler extends AbstractHandler {
@Override
public void setEnabled(final @Nullable Object evaluationContext) {
setBaseEnabled(PageBookBrowserView.this.currentBrowserPage != null);
}
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
if (PageBookBrowserView.this.currentBrowserPage != null) {
final Browser browser= PageBookBrowserView.this.currentBrowserPage.getBrowser();
browser.execute("window.print();" );
}
return null;
}
}
private class CreateBookmarkHandler extends AbstractHandler {
@Override
public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
BrowserBookmark bookmark= createBookmark();
final EditBookmarkDialog dialog= new EditBookmarkDialog(getSite().getShell(), bookmark);
if (dialog.open() == Dialog.OK) {
bookmark= dialog.getBookmark();
if (bookmark != null) {
PageBookBrowserView.this.bookmarks.getBookmarks().add(bookmark);
return bookmark;
}
}
return null;
}
}
private class BrowserListener implements ProgressListener, TitleListener, StatusTextListener {
@Override
public void changed(final ProgressEvent event) {
if (PageBookBrowserView.this.currentBrowserPage != null && PageBookBrowserView.this.currentBrowserPage.getBrowser() == event.widget) {
if (event.total == 0 || event.total == event.current) {
clearProgress();
}
else if (PageBookBrowserView.this.currentProgress == null) {
initProgress(event.total, event.current);
}
else {
updateProgress(event.current);
}
updateBrowserState();
}
}
@Override
public void completed(final ProgressEvent event) {
if (PageBookBrowserView.this.currentBrowserPage != null && PageBookBrowserView.this.currentBrowserPage.getBrowser() == event.widget) {
clearProgress();
updateBrowserState();
}
}
@Override
public void changed(final TitleEvent event) {
if (PageBookBrowserView.this.currentBrowserPage != null && PageBookBrowserView.this.currentBrowserPage.getBrowser() == event.widget) {
updateTitle();
}
}
@Override
public void changed(final StatusTextEvent event) {
updateTitle();
}
}
private final List<IHandler2> browserHandlers= new ArrayList<>();
private final BrowserListener browserListener= new BrowserListener();
private @Nullable PageBookBrowserPage currentBrowserPage;
private @Nullable IProgressMonitor currentProgress;
private int currentProgressWorked;
private @Nullable BookmarkCollection bookmarks;
private final IBrowserProvider browserInterface= new IBrowserProvider() {
@Override
public @Nullable Browser getBrowser() {
if (PageBookBrowserView.this.currentBrowserPage != null) {
return PageBookBrowserView.this.currentBrowserPage.getBrowser();
}
return null;
}
@Override
public void showMessage(final IStatus status) {
getStatusManager().setMessage(status, 10);
}
};
public PageBookBrowserView() {
}
@Override
public void init(final IViewSite site, final IMemento memento) throws PartInitException {
super.init(site, memento);
this.bookmarks= initBookmarkCollection();
}
@Override
public void saveState(final IMemento memento) {
if (this.bookmarks != null) {
this.bookmarks.save();
}
super.saveState(memento);
}
@Override
protected PageBookBrowserPage doCreatePage(final BrowserSession session) {
return new PageBookBrowserPage(this, session);
}
protected IBrowserProvider getBrowserInterface() {
return this.browserInterface;
}
@Override
protected void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) {
super.initActions(serviceLocator, handlers);
serviceLocator.getService(IContextService.class)
.activateContext("org.eclipse.statet.workbench.contexts.PageViewerContext"); //$NON-NLS-1$
{ final IHandler2 handler= new NavigateBackHandler(getBrowserInterface());
handlers.addActivate(NAVIGATE_BACK_COMMAND_ID, handler);
addBrowserHandler(handler);
handlers.getHandlerService().activateHandler(
IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY, handler );
}
{ final IHandler2 handler= new NavigateForwardHandler(getBrowserInterface());
handlers.addActivate(NAVIGATE_FORWARD_COMMAND_ID, handler);
addBrowserHandler(handler);
handlers.getHandlerService().activateHandler(
IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY, handler );
}
{ final IHandler2 handler= new GoToHomeHandler();
handlers.addActivate(GOTO_HOME_COMMAND_ID, handler);
addBrowserHandler(handler);
}
{ final IHandler2 handler= new RefreshHandler();
handlers.addActivate(REFRESH_PAGE_COMMAND_ID, handler);
addBrowserHandler(handler);
}
final IHandler2 cancelHandler= new CancelHandler(getBrowserInterface());
// handlerService.activateHandler(, cancelHandler);
addBrowserHandler(cancelHandler);
{ final IHandler2 handler= new PrintHandler();
handlers.addActivate(PRINT_PAGE_COMMAND_ID, handler);
}
if (this.bookmarks != null) {
final IHandler2 handler= new CreateBookmarkHandler();
if (handler != null) {
handlers.add(CREATE_BOOKMARK_ID, handler);
addBrowserHandler(handler);
}
}
{ final IHandler2 handler= createOpenExternalHandler();
if (handler != null) {
handlers.add(OPEN_EXTERNAL_ID, handler);
addBrowserHandler(handler);
}
}
}
protected @Nullable IHandler2 createOpenExternalHandler() {
return new OpenExternalHandler(getBrowserInterface());
}
@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 HandlerContributionItem(
new CommandContributionItemParameter(serviceLocator,
null, HandlerContributionItem.NO_COMMAND_ID, null,
null, null, null,
"Open in &external browser", null, null,
HandlerContributionItem.STYLE_PUSH, null, false ),
handlers.get(OPEN_EXTERNAL_ID) ));
menuManager.add(new Separator(UIActions.VIEW_FILTER_GROUP_ID));
menuManager.add(new Separator(UIActions.SETTINGS_GROUP_ID));
menuManager.appendToGroup(UIActions.SETTINGS_GROUP_ID,
new SimpleContributionItem("Preferences...", "P") {
@Override
protected void execute() throws ExecutionException {
final Shell shell= getSite().getShell();
final List<String> pageIds= new ArrayList<>();
PageBookBrowserView.this.collectContextMenuPreferencePages(pageIds);
if (!pageIds.isEmpty() && (shell == null || !shell.isDisposed())) {
org.eclipse.ui.dialogs.PreferencesUtil.createPreferenceDialogOn(shell,
pageIds.get(0), pageIds.toArray(new String[pageIds.size()]), null)
.open();
}
}
});
final IToolBarManager toolBarManager= actionBars.getToolBarManager();
toolBarManager.insertBefore(ADDITIONS_GROUP_ID,
new Separator(BROWSERCONTROL_MENU_ID) );
toolBarManager.appendToGroup(BROWSERCONTROL_MENU_ID, new HandlerContributionItem(
new CommandContributionItemParameter(serviceLocator,
null, NAVIGATE_BACK_COMMAND_ID, HandlerContributionItem.STYLE_PUSH ),
handlers ));
toolBarManager.appendToGroup(BROWSERCONTROL_MENU_ID, new HandlerContributionItem(
new CommandContributionItemParameter(serviceLocator,
null, NAVIGATE_FORWARD_COMMAND_ID, HandlerContributionItem.STYLE_PUSH ),
handlers ));
if (this.bookmarks != null) {
toolBarManager.insertAfter(BROWSERCONTROL_MENU_ID,
new Separator(BOOKMARKS_MENU_ID) );
toolBarManager.appendToGroup(BOOKMARKS_MENU_ID,
new SimpleContributionItem(
"Manage Bookmarks", null,
SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_FAVORITES_IMAGE_ID), null,
SimpleContributionItem.STYLE_PULLDOWN ) {
@Override
protected void execute() throws ExecutionException {
final ManageBookmarksDialog dialog= new ManageBookmarksDialog(PageBookBrowserView.this);
dialog.open();
PageBookBrowserView.this.bookmarks.save();
}
@Override
protected void dropDownMenuAboutToShow(final IMenuManager manager) {
manager.add(new HandlerContributionItem(
new CommandContributionItemParameter(serviceLocator,
null, NO_COMMAND_ID, null,
null, null, null,
"Create Bookmark", "C", null,
HandlerContributionItem.STYLE_PUSH, null, false ),
handlers.get(CREATE_BOOKMARK_ID) ));
manager.add(new Separator());
manager.add(new ShowBookmarksDropdownContribution.OpenBookmarkContributionItem(
PageBookBrowserView.this, new BrowserBookmark("Home Page", getHomePageUrl()),
null, "H" ));
manager.add(new Separator());
manager.add(new ShowBookmarksDropdownContribution(PageBookBrowserView.this));
}
});
}
}
protected void addBrowserHandler(final IHandler2 handler) {
this.browserHandlers.add(handler);
}
@Override
public void dispose() {
this.browserHandlers.clear();
super.dispose();
}
@Override
protected void onPageHiding(final IPageBookViewPage page, final BrowserSession session) {
final PageBookBrowserPage browserPage;
if (session != null) {
browserPage= (PageBookBrowserPage) page;
final Browser browser= browserPage.getBrowser();
browser.removeProgressListener(this.browserListener);
browser.removeTitleListener(this.browserListener);
browser.removeStatusTextListener(this.browserListener);
browserPage.setStatusManager(null);
clearProgress();
}
this.currentBrowserPage= null;
getStatusManager().clearAll();
super.onPageHiding(page, session);
}
@Override
protected void onPageShowing(final IPageBookViewPage page, final BrowserSession session) {
if (session != null) {
final PageBookBrowserPage browserPage= this.currentBrowserPage= (PageBookBrowserPage) page;
final Browser browser= browserPage.getBrowser();
browser.addProgressListener(this.browserListener);
browser.addTitleListener(this.browserListener);
browser.addStatusTextListener(this.browserListener);
initProgress(browserPage.getCurrentProgressTotal(), browserPage.getCurrentProgressWorked());
browserPage.setStatusManager(getStatusManager());
}
super.onPageShowing(page, session);
}
protected void updateBrowserState() {
for (final IHandler2 handler : this.browserHandlers) {
handler.setEnabled(null);
}
}
private void initProgress(final int total, final int current) {
if (current < 0 || current >= total) { // includes total == 0
return;
}
final IStatusLineManager statusLine= getViewSite().getActionBars().getStatusLineManager();
statusLine.setCancelEnabled(true);
final IProgressMonitor monitor= statusLine.getProgressMonitor();
this.currentProgress= monitor;
this.currentProgress.beginTask("", total); //$NON-NLS-1$
this.currentProgressWorked= current;
this.currentProgress.worked(current);
Display.getCurrent().timerExec(200, new Runnable() {
@Override
public void run() {
if (monitor == PageBookBrowserView.this.currentProgress) {
if (monitor.isCanceled()) {
PageBookBrowserView.this.currentBrowserPage.getBrowser().stop();
}
else {
Display.getCurrent().timerExec(100, this);
}
}
}
});
}
private void updateProgress(final int current) {
this.currentProgress.worked(current - PageBookBrowserView.this.currentProgressWorked);
this.currentProgressWorked= current;
}
private void clearProgress() {
if (this.currentProgress != null) {
this.currentProgress.done();
this.currentProgress= null;
this.currentProgressWorked= 0;
}
}
@Override
protected BrowserSession checkNewSession(@Nullable BrowserSession session) {
if (session == null) {
session= new BrowserSession(getHomePageUrl());
}
session.bind();
return session;
}
@Override
public void closePage(final BrowserSession session) {
super.closePage(session);
session.unbind();
}
public boolean canOpen(final BrowserSession session) {
return (!session.isBound() || getSessions().contains(session));
}
public BrowserSession openBookmark(final BrowserBookmark bookmark, final BrowserSession session) {
return openUrl(bookmark.getUrl(), session);
}
public BrowserSession openUrl(final URI url, final @Nullable BrowserSession session) {
return openUrl(url.toString(), session);
}
public BrowserSession openUrl(final String url, @Nullable BrowserSession session) {
if (session != null) {
final PageBookBrowserPage page= (PageBookBrowserPage) getPage(session);
if (page != null) {
page.setUrl(url);
showPage(session);
if (getViewSite().getPage().getActivePart() == this) {
page.setFocusToBrowser();
}
return session;
}
}
if (session == null) {
session= new BrowserSession(url);
}
else {
session.setUrl(url);
}
newPage(session, true);
return session;
}
protected @Nullable PageBookBrowserPage getCurrentBrowserPage() {
return this.currentBrowserPage;
}
public String getHomePageUrl() {
return PageBookBrowserPage.ABOUT_BLANK_URI_STRING;
}
protected @Nullable BookmarkCollection initBookmarkCollection() {
return null;
}
protected List<BrowserBookmark> getBookmarks() {
return this.bookmarks.getBookmarks();
}
protected @Nullable BrowserBookmark createBookmark() {
final PageBookBrowserPage browserPage= this.currentBrowserPage;
if (browserPage == null) {
return null;
}
return new BrowserBookmark(browserPage.getCurrentTitle(), browserPage.getCurrentUrl());
}
protected void collectContextMenuPreferencePages(final List<String> pageIds) {
pageIds.add("org.eclipse.ui.browser.preferencePage"); //$NON-NLS-1$
}
}