blob: 2341c71d168377ad4ba96f68afaf905b4aedff45 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.intro.impl.model;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.PerformanceStats;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.internal.intro.impl.IIntroConstants;
import org.eclipse.ui.internal.intro.impl.IntroPlugin;
import org.eclipse.ui.internal.intro.impl.Messages;
import org.eclipse.ui.internal.intro.impl.model.viewer.IntroModelContentProvider;
import org.eclipse.ui.internal.intro.impl.model.viewer.IntroModelLabelProvider;
import org.eclipse.ui.internal.intro.impl.util.ImageUtil;
import org.eclipse.ui.internal.intro.impl.util.Log;
import org.eclipse.ui.internal.intro.impl.util.Util;
import org.eclipse.ui.intro.IIntroPart;
import org.eclipse.ui.intro.config.CustomizableIntroPart;
/**
* UI Implementation class that represents a Presentation Part. This class is
* instantiated from plugin markup and so we need a default constructor,
* including in subclasses. It has some base methods, including maintaining a
* history of navigation locations. Also, dynamic awarness is honored here.
*
*/
public abstract class AbstractIntroPartImplementation {
// CustomizableIntroPart instance.
private CustomizableIntroPart introPart = null;
// IMemento for restoring state.
private IMemento memento;
protected History history = new History();
// flag used to enable logging of perf data for full UI creation only once.
// Since standbyStateChanged is called several times, flag is used in method
// to filter out all subsequent calls.
boolean logUIcreationTime = true;
// Global actions
protected Action backAction = new Action() {
{
setToolTipText(Messages.Browser_backwardButton_tooltip);
setImageDescriptor(ImageUtil
.createImageDescriptor("full/elcl16/backward_nav.png")); //$NON-NLS-1$
setDisabledImageDescriptor(ImageUtil
.createImageDescriptor("full/dlcl16/backward_nav.png")); //$NON-NLS-1$
}
@Override
public void run() {
navigateBackward();
}
};
protected Action forwardAction = new Action() {
{
setToolTipText(Messages.Browser_forwardButton_tooltip);
setImageDescriptor(ImageUtil
.createImageDescriptor("full/elcl16/forward_nav.png")); //$NON-NLS-1$
setDisabledImageDescriptor(ImageUtil
.createImageDescriptor("full/dlcl16/forward_nav.png")); //$NON-NLS-1$
}
@Override
public void run() {
navigateForward();
}
};
protected Action homeAction = new Action() {
{
setToolTipText(Messages.Browser_homeButton_tooltip);
setImageDescriptor(ImageUtil
.createImageDescriptor("full/elcl16/home_nav.png")); //$NON-NLS-1$
setDisabledImageDescriptor(ImageUtil
.createImageDescriptor("full/dlcl16/home_nav.png")); //$NON-NLS-1$
}
@Override
public void run() {
navigateHome();
}
};
protected Action viewIntroModelAction = new Action() {
{
setToolTipText(Messages.IntroPart_showContentButton_tooltip);
setImageDescriptor(ImageUtil
.createImageDescriptor("contents_view.png")); //$NON-NLS-1$
}
@Override
public void run() {
ElementTreeSelectionDialog treeViewer = new ElementTreeSelectionDialog(
getIntroPart().getIntroSite().getShell(),
new IntroModelLabelProvider(), new IntroModelContentProvider());
treeViewer.setInput(getModel());
treeViewer.open();
}
};
/**
* Creates the UI based on this implementation class. .
*
* @param parent
*/
public abstract void createPartControl(Composite parent);
/**
* Called when the init method is called in the IIntroPart. Subclasses may
* extend, for example to get the passed Memento. When extending, make sure
* you include a call to super.
*
* @param introPart
*/
public void init(IIntroPart introPart, IMemento memento) {
// we know the class type to cast to.
this.introPart = (CustomizableIntroPart) introPart;
this.memento = memento;
}
/**
* @return
*/
public IntroModelRoot getModel() {
return IntroPlugin.getDefault().getIntroModelRoot();
}
/**
* @return Returns the introPart.
*/
public CustomizableIntroPart getIntroPart() {
return introPart;
}
/**
* Updates the UI navigation history with either a real URL.
*
* @param location
*/
public void updateHistory(String location) {
history.updateHistory(location);
updateNavigationActionsState();
}
/**
* Updates the UI navigation history with a page ID.
*
* @param pageId
*/
public void updateHistory(AbstractIntroPage page) {
history.updateHistory(page);
updateNavigationActionsState();
}
/**
* Subclasses must implement to set the state of the navigation actions in
* the toolbar.
*
*/
public abstract void setFocus();
/**
* Subclasses must implement to update the intro view actions when history
* is updated.
*
*/
protected abstract void updateNavigationActionsState();
public abstract boolean navigateBackward();
public abstract boolean navigateForward();
public abstract boolean navigateHome();
/**
* Called when the IntroPart is disposed. Subclasses should override to
* dispose of resources. By default, this implementation does nothing.
*/
public void dispose() {
// no-op
}
/*
* Add the Intro Model Viewer as an action to all implementations.
*/
protected void addToolBarActions() {
// Handle menus:
IActionBars actionBars = getIntroPart().getIntroSite().getActionBars();
IToolBarManager toolBarManager = actionBars.getToolBarManager();
toolBarManager.add(viewIntroModelAction);
toolBarManager.update(true);
actionBars.updateActionBars();
}
/**
* Called when the Intro changes state. This method should not be
* subclassed. It adds performance logging calls. Subclasses must implement
* doStandbyStateChanged instead.
*
* @param standby
*/
public void standbyStateChanged(boolean standby, boolean isStandbyPartNeeded) {
PerformanceStats setStandbyStateStats = null;
long start = 0;
if (Log.logPerformance) {
if (logUIcreationTime && PerformanceStats.ENABLED) {
PerformanceStats stats = PerformanceStats.getStats(
IIntroConstants.PERF_UI_ZOOM, IIntroConstants.INTRO);
stats.endRun();
Util
.logPerformanceMessage(
"(perf stats) time spent in UI code before content is displayed (standbyStateChanged event is fired) ", //$NON-NLS-1$
stats.getRunningTime());
stats.reset();
}
// standby time.
setStandbyStateStats = PerformanceStats.getStats(
IIntroConstants.PERF_SET_STANDBY_STATE, IIntroConstants.INTRO);
setStandbyStateStats.startRun();
start = System.currentTimeMillis();
}
doStandbyStateChanged(standby, isStandbyPartNeeded);
// now log performance
if (Log.logPerformance) {
if (PerformanceStats.ENABLED) {
setStandbyStateStats.endRun();
Util
.logPerformanceMessage(
"(perf stats) setting standby state (zooming, displaying content) took:", //$NON-NLS-1$
+setStandbyStateStats.getRunningTime());
setStandbyStateStats.reset();
} else
Util
.logPerformanceTime(
"setting standby state (zooming, generating content, setText() ) took:", //$NON-NLS-1$
+start);
if (logUIcreationTime) {
if (PerformanceStats.ENABLED) {
PerformanceStats stats = PerformanceStats.getStats(
IIntroConstants.PERF_VIEW_CREATION_TIME,
IIntroConstants.INTRO);
stats.endRun();
Util
.logPerformanceMessage(
"END - (perf stats): creating CustomizableIntroPart view took:", //$NON-NLS-1$
+stats.getRunningTime());
stats.reset();
} else
Util.logPerformanceTime(
"END: creating CustomizableIntroPart view took:", //$NON-NLS-1$
+IntroPlugin.getDefault().gettUICreationStartTime());
// prevent further logging of UI creation time.
logUIcreationTime = false;
}
}
}
/*
* Subclasses must implement the actual logic for the method.
*/
protected abstract void doStandbyStateChanged(boolean standby,
boolean isStandbyPartNeeded);
/**
* Save the current state of the intro. Currently, we only store information
* about the most recently visited intro page. In static case, the last HTML
* page is remembered. In dynamic case, the last UI page or HTML page is
* remembered.
*
* Note: This method saves the last visited intro page in a dynamic case.
* Subclasses need to extend to get the desired behavior relavent to the
* specific implementation. Broswer implementation needs to cache an http
* web page, if it happens to be the last page visited.
*
* @param memento
*/
public void saveState(IMemento memento) {
saveCurrentPage(memento);
}
/**
* This method saves the most recently visited dynamic intro page in the
* memento. If a given implementation requires saving alternative
* information (e.g., information about the most recently visited static
* page) it should override this method.
*
* @param memento
*/
protected void saveCurrentPage(IMemento memento) {
IntroModelRoot model = getModel();
if (memento == null || model == null)
return;
String currentPage = model.getCurrentPageId();
if (currentPage != null && currentPage.length() > 0) {
memento.putString(IIntroConstants.MEMENTO_CURRENT_PAGE_ATT,
currentPage);
}
}
/**
* get the last page if it was stored in memento. This page is the last
* visited intro page. It can be a intro page id, in the case of dynamic
* intro. Or it can be an http in the case of static intro. It can also be
* an http in the case of dynamic intro where the last visited page is a
* url.
*/
protected String getCachedCurrentPage() {
// Check to see if the start page has been overridden because
// content
String newContentPage = ExtensionMap.getInstance().getStartPage();
if (newContentPage != null) {
return newContentPage;
}
IMemento memento = getMemento();
if (memento == null) {
String startPageId = getModel().getStartPageId();
if (startPageId.length() > 0) {
return startPageId;
} else {
return null;
}
}
return memento.getString(IIntroConstants.MEMENTO_CURRENT_PAGE_ATT);
}
/**
* @return Returns the memento passed on creation.
*/
public IMemento getMemento() {
return memento;
}
/**
* Support dynamic awarness. Clear cached models first, then update UI by
* delegating to implementation.
*
* @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
*/
public void registryChanged(IRegistryChangeEvent event) {
history.clear();
// give implementation a chance to react to change.
handleRegistryChanged(event);
}
/*
* Handle reacting to plugin registry changes. This method will only be
* called when regitry changes pertaining to Intro extension points is
* detected.
*/
protected abstract void handleRegistryChanged(IRegistryChangeEvent event);
public History getHistory() {
return history;
}
}