/*******************************************************************************
* Copyright (c) 2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.windup.ui.internal.views;
import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME;
import static org.jboss.tools.windup.model.domain.WindupConstants.DEFAULT;
import static org.jboss.tools.windup.model.domain.WorkspaceResourceUtils.findProject;
import java.io.File;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.e4.ui.workbench.modeling.ISelectionListener;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.internal.browser.BrowserViewer;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.jboss.tools.windup.core.IWindupListener;
import org.jboss.tools.windup.core.services.WindupService;
import org.jboss.tools.windup.ui.Preferences;
import org.jboss.tools.windup.ui.WindupUIPlugin;
import org.jboss.tools.windup.ui.internal.Messages;
import org.jboss.tools.windup.ui.internal.Utils;
/**
* <p>
* A view to display Windup Reports.
* </p>
*/
@SuppressWarnings("restriction")
public class WindupReportView implements IShowInTarget
{
@Inject private MPart part;
@Inject private WindupService windupService;
@Inject private ESelectionService selectionService;
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "org.jboss.tools.windup.ui.views.WindupReportView"; //$NON-NLS-1$
private static final String PREVIOUS_REPORT_PREF = "previousReport"; //$NON-NLS-1$
/**
* <p>
* The parent {@link Composite} for this view.
* </p>
*/
private Composite composite;
/**
* <p>
* Widget used to display the HTML Windup report.
* </p>
*/
private BrowserViewer browserViewer;
/**
* <p>
* Used to display messages to the user in the view.
* </p>
*/
private StyledText message;
/**
* <p>
* Listens for selection changes so that the view can be synchronized with the current selection if so specified by the user.
* </p>
*
* @see #syncronizeViewWithCurrentSelection
*/
private ISelectionListener selectionChangedListener;
/**
* <p>
* Listener used to listen to changes in Windup reports, such as a new one being generated.
* </p>
*/
private IWindupListener reportListener;
/**
* <p>
* <code>true</code> if the view should sync with the current workbench selection, <code>false</code> otherwise.
* </p>
*/
private boolean syncronizeViewWithCurrentSelection;
/**
* <p>
* The current resource for which a Windup report is currently being displayed.
* </p>
*/
private IResource currentSelection;
private String currentReportPath;
/**
* <p>
* Required default constructor for this view since it is created via extension point.
* </p>
*/
public WindupReportView()
{
this.browserViewer = null;
this.selectionChangedListener = null;
this.currentSelection = null;
this.syncronizeViewWithCurrentSelection = false;
this.currentReportPath = "";
}
@Inject
public void createPartControl(Composite composite)
{
this.composite = composite;
//this.composite = new Composite(parent, SWT.NONE);
// GridLayout layout = new GridLayout(1, false);
// this.composite.setLayout(layout);
GridLayoutFactory.fillDefaults().margins(0, 0).applyTo(composite);;
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
// create the message label
this.message = new StyledText(this.composite, SWT.WRAP);
this.message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
this.message.setVisible(false);
this.browserViewer = new BrowserViewer(this.composite, BrowserViewer.LOCATION_BAR|BrowserViewer.BUTTON_BAR);
this.browserViewer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
// react to selection changes
this.selectionChangedListener = new ISelectionListener() {
@Override
public void selectionChanged(MPart part, Object selection) {
/*
* if update on selection and the current selection is not the same as the containing workbench part
*/
if (WindupReportView.this.syncronizeViewWithCurrentSelection && part != WindupReportView.this.part)
{
/*
* if editor selection else if some other sort of selection
*/
if (part instanceof IEditorPart)
{
IEditorInput input = ((IEditorPart) part).getEditorInput();
if (input instanceof IFileEditorInput)
{
updateSelection(new StructuredSelection(
((IFileEditorInput) input).getFile()));
}
}
else
{
if (!(selection instanceof ISelection)) {
selection = new StructuredSelection(selection);
}
else {
updateSelection((ISelection)selection);
}
}
}
}
};
selectionService.addPostSelectionListener(selectionChangedListener);
// react to Windup report generations
this.reportListener = new IWindupListener()
{
@Override
public void graphGenerated(IProject project)
{
/*
* if the current selection is in the project that just had a report generated, refresh the view
*/
if (WindupReportView.this.currentSelection != null
&& WindupReportView.this.currentSelection.getProject().equals(project))
{
// refresh has to take place in the display thread
Display.getDefault().syncExec(new Runnable()
{
public void run()
{
WindupReportView.this.refresh();
}
});
}
}
};
windupService.addWindupListener(reportListener);
// store view preferences
IPreferenceStore preferenceStore = getPreferenceStore();
if (preferenceStore.contains(Preferences.REPORTVIEW_SYNC_SELECTION))
{
this.syncronizeViewWithCurrentSelection = preferenceStore.getBoolean(Preferences.REPORTVIEW_SYNC_SELECTION);
}
else
{
preferenceStore.setDefault(Preferences.REPORTVIEW_SYNC_SELECTION, this.syncronizeViewWithCurrentSelection);
}
String previousReport = preferenceStore.getString(PREVIOUS_REPORT_PREF);
boolean showPlaceholder = true;
if (!previousReport.isEmpty()) {
File file = new File(previousReport);
if (file.exists()) {
showPlaceholder = false;
showReport(previousReport, true);
}
}
if (showPlaceholder) {
showMessage("No report available.", true);
}
}
public void setSynchronizeSelection(boolean sync) {
this.syncronizeViewWithCurrentSelection = sync;
}
@Focus
public void setFocus()
{
this.browserViewer.setFocus();
}
@PreDestroy
public void dispose()
{
// remove listeners
//ISelectionService srv = (ISelectionService) site.getService(ISelectionService.class);
selectionService.removePostSelectionListener(this.selectionChangedListener);
windupService.removeWindupListener(this.reportListener);
getPreferenceStore().setValue(PREVIOUS_REPORT_PREF, currentReportPath);
}
public void updateConfiguration(ILaunchConfiguration configuration) {
try {
String projectName = configuration.getAttribute(ATTR_PROJECT_NAME, DEFAULT);
IProject project = findProject(projectName);
displayReport(project, false);
} catch (CoreException e) {
WindupUIPlugin.log(e);
}
}
/**
* <p>
* React to a selection change.
* </p>
*
* @param selection selection change to react to
*
* @return <code>true</code> if the view can react to the given selection, </code>false</code> otherwise
*/
public boolean updateSelection(ISelection selection)
{
boolean canReact = false;
IResource selectedResource = Utils.getSelectedResource(selection);
if (selectedResource != null)
{
canReact = true;
this.displayReport(selectedResource, false);
}
return canReact;
}
/**
* @see org.eclipse.ui.part.IShowInTarget#show(org.eclipse.ui.part.ShowInContext)
*/
@Override
public boolean show(ShowInContext context)
{
return this.updateSelection(context.getSelection());
}
/**
* <p>
* Forces the view to update the report.
* </p>
*/
public void refresh()
{
if (currentSelection != null) {
this.displayReport(this.currentSelection, true);
}
}
/**
* <p>
* Displays the Windup report for the given {@link IResource}.
* </p>
*
* @param resource {@link IResource} to display the Windup report for
* @param force if <code>true</code> then refresh the view even if the the view is already displaying the report for the given resource, if
* <code>false</code> and the view is already displaying the report for the given resource then do nothing
*/
private synchronized void displayReport(IResource resource, boolean force)
{
// don't change displayed report if current selection is same as newly selected resource
if (this.currentSelection != resource || force)
{
this.currentSelection = resource;
if (windupService.reportExists(resource))
{
IPath reportPath = windupService.getReportLocation(resource);
if (reportPath != null)
{
this.showReport(reportPath, true);
}
else
{
this.showMessage(Messages.report_has_no_information_on_resource, true);
}
}
else
{
this.showMessage(Messages.windup_report_has_not_been_generated, true);
}
}
}
/**
* <p>
* Displays the report in the view and optionally hides the current message.
* </p>
*
* @param reportPath {@link IPath} to the report to show
* @param hideMessage <code>true</code> to hide the current message, <code>false</code> to show the message with the report
*/
public void showReport(IPath reportPath, boolean hideMessage) {
showReport(reportPath.toString(), hideMessage);
}
public void showReport(String path, boolean hideMessage) {
this.currentReportPath = path;
this.browserViewer.setURL(path);
this.browserViewer.setVisible(true);
((GridData) this.browserViewer.getLayoutData()).exclude = false;
this.message.setVisible(!hideMessage);
((GridData) this.message.getLayoutData()).exclude = hideMessage;
this.composite.layout(true);
}
/**
* <p>
* Displays the given message in the view and optionally hides the report.
* </p>
*
* @param message text message to display to user in the view
* @param hideReport <code>true</code> to hide the report, <code>false</code> to show the message with the report
*/
public void showMessage(String message, boolean hideReport)
{
this.message.setText(message);
this.message.setVisible(true);
((GridData) this.message.getLayoutData()).exclude = false;
this.browserViewer.setVisible(!hideReport);
if (hideReport) {
currentReportPath = "";
}
((GridData) this.browserViewer.getLayoutData()).exclude = hideReport;
this.composite.layout(true);
}
/**
* @return the plugins {@link IPreferenceStore} instance
*/
private IPreferenceStore getPreferenceStore()
{
return WindupUIPlugin.getDefault().getPreferenceStore();
}
}