blob: a6e16da1d04659108e46c9aee81753b7cf644ef0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson
*
* All rights reserved. This program and the accompanying materials are 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
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.handler;
import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlAnalysisModuleSource;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.Activator;
import org.eclipse.tracecompass.tmf.ui.dialog.TmfFileDialogFactory;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectModelElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
/**
* Dialog for XML analysis files
*
* @author Jean-Christian Kouame
*/
public class ManageXMLAnalysisDialog extends Dialog {
private final String XML_FILTER_EXTENSION = "*.xml"; //$NON-NLS-1$
private List fAnalysesList;
private Button fDeleteButton;
private Button fImportButton;
private Button fExportButton;
private Button fEditButton;
private Label fInvalidFileLabel;
/**
* Constructor
*
* @param parent
* Parent shell of this dialog
*/
public ManageXMLAnalysisDialog(Shell parent) {
super(parent);
setShellStyle(SWT.RESIZE | SWT.MAX | getShellStyle());
}
@Override
protected Control createDialogArea(Composite parent) {
getShell().setText(Messages.ManageXMLAnalysisDialog_ManageXmlAnalysesFiles);
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayout(new GridLayout(2, false));
Composite listContainer = new Composite(composite, SWT.NONE);
listContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout lcgl = new GridLayout();
lcgl.marginHeight = 0;
lcgl.marginWidth = 0;
listContainer.setLayout(lcgl);
fAnalysesList = new List(listContainer, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
fAnalysesList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fAnalysesList.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
if (fAnalysesList.getSelectionCount() == 0) {
setButtonsEnabled(false);
} else {
setButtonsEnabled(true);
handleSelection(fAnalysesList.getSelection());
}
}
});
fInvalidFileLabel = new Label(listContainer, SWT.ICON_ERROR);
fInvalidFileLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
fInvalidFileLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_RED));
fInvalidFileLabel.setText(Messages.ManageXMLAnalysisDialog_FileValidationError);
fInvalidFileLabel.setVisible(false);
Composite buttonContainer = new Composite(composite, SWT.NULL);
buttonContainer.setLayout(new GridLayout());
buttonContainer.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false));
fImportButton = new Button(buttonContainer, SWT.PUSH);
fImportButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
fImportButton.setText(Messages.ManageXMLAnalysisDialog_Import);
fImportButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
importAnalysis();
}
});
fExportButton = new Button(buttonContainer, SWT.PUSH);
fExportButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
fExportButton.setText(Messages.ManageXMLAnalysisDialog_Export);
fExportButton.setEnabled(false);
fExportButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
exportAnalysis();
}
});
fEditButton = new Button(buttonContainer, SWT.PUSH);
fEditButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
fEditButton.setText(Messages.ManageXMLAnalysisDialog_Edit);
fEditButton.setEnabled(false);
fEditButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
editAnalysis();
}
});
fDeleteButton = new Button(buttonContainer, SWT.PUSH);
fDeleteButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
fDeleteButton.setText(Messages.ManageXMLAnalysisDialog_Delete);
fDeleteButton.setEnabled(false);
fDeleteButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
deleteAnalysis();
}
});
fillAnalysesList();
getShell().setMinimumSize(300, 275);
return composite;
}
private void setButtonsEnabled(boolean enable) {
fDeleteButton.setEnabled(enable);
fExportButton.setEnabled(enable);
fEditButton.setEnabled(enable);
}
private void handleSelection(String[] selection) {
Map<String, File> files = XmlUtils.listFiles();
File file = files.get(createXmlFileString(selection[0]));
if (file != null && XmlUtils.xmlValidate(file).isOK()) {
fInvalidFileLabel.setVisible(false);
} else {
fInvalidFileLabel.setVisible(true);
}
}
private static void deleteSupplementaryFile(String xmlFile) {
// 1. Look for all traces that have this analysis
// 2. Close them if they are opened.
// 3. Delete the related supplementary files
java.util.List<IResource> resourceToDelete = new ArrayList<>();
java.util.List<String> ids = XmlUtils.getAnalysisIdsFromFile(xmlFile);
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(0);
for (IProject project : projects) {
TmfProjectElement pElement = TmfProjectRegistry.getProject(project);
if (pElement != null) {
java.util.List<TmfCommonProjectElement> tElements = new ArrayList<>();
TmfTraceFolder tracesFolder = pElement.getTracesFolder();
if (tracesFolder != null) {
tElements.addAll(tracesFolder.getTraces());
}
TmfExperimentFolder experimentsFolder = pElement.getExperimentsFolder();
if (experimentsFolder != null) {
tElements.addAll(experimentsFolder.getExperiments());
}
for (TmfCommonProjectElement tElement : tElements) {
boolean closeEditor = false;
for (IResource resource : tElement.getSupplementaryResources()) {
for (String id : ids) {
if (resource.getName().startsWith(id)) {
resourceToDelete.add(resource);
closeEditor = true;
}
}
}
if (closeEditor) {
tElement.closeEditors();
}
}
}
}
for (IResource resource : resourceToDelete) {
try {
resource.delete(false, null);
} catch (CoreException e) {
Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_DeleteFileError, resource.getName()));
}
}
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, false);
}
private void fillAnalysesList() {
fAnalysesList.removeAll();
Map<String, File> files = XmlUtils.listFiles();
for (String file : files.keySet()) {
// Remove the extension from the file path. The extension is at the
// end of the file path
IPath path = new Path(file);
fAnalysesList.add(path.removeFileExtension().toString());
}
setButtonsEnabled(false);
}
private void importAnalysis() {
FileDialog dialog = TmfFileDialogFactory.create(Display.getCurrent().getActiveShell(), SWT.OPEN);
dialog.setText(Messages.ManageXMLAnalysisDialog_SelectFileImport);
dialog.setFilterNames(new String[] { Messages.ManageXMLAnalysisDialog_ImportXmlFile + " (*.xml)" }); //$NON-NLS-1$
dialog.setFilterExtensions(new String[] { XML_FILTER_EXTENSION });
String path = dialog.open();
if (path != null) {
File file = new File(path);
if (loadXmlFile(file, true)) {
fillAnalysesList();
}
}
}
private static boolean loadXmlFile(File file, boolean addFile) {
IStatus status = XmlUtils.xmlValidate(file);
if (status.isOK()) {
deleteSupplementaryFile(file.getName());
if (addFile) {
status = XmlUtils.addXmlFile(file);
} else {
XmlUtils.updateXmlFile(file);
}
if (status.isOK()) {
XmlAnalysisModuleSource.notifyModuleChange();
/*
* FIXME: It refreshes the list of analysis under a trace,
* but since modules are instantiated when the trace opens,
* the changes won't apply to an opened trace, it needs to
* be closed then reopened
*/
refreshProject();
return true;
}
Activator.logError(Messages.ManageXMLAnalysisDialog_ImportFileFailed);
TraceUtils.displayErrorMsg(Messages.ManageXMLAnalysisDialog_ImportFileFailed, status.getMessage());
} else {
Activator.logError(Messages.ManageXMLAnalysisDialog_ImportFileFailed);
TraceUtils.displayErrorMsg(Messages.ManageXMLAnalysisDialog_ImportFileFailed, status.getMessage());
}
return false;
}
private void exportAnalysis() {
FileDialog dialog = TmfFileDialogFactory.create(Display.getCurrent().getActiveShell(), SWT.SAVE);
dialog.setText(NLS.bind(Messages.ManageXMLAnalysisDialog_SelectFileExport, fAnalysesList.getSelection()[0]));
dialog.setFilterExtensions(new String[] { XML_FILTER_EXTENSION, "*" }); //$NON-NLS-1$
String selection = createXmlFileString(fAnalysesList.getSelection()[0]);
dialog.setFileName(selection);
String path = dialog.open();
if (path != null) {
if (!XmlUtils.exportXmlFile(selection, path).isOK()) {
Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToExport, selection));
}
}
}
private void editAnalysis() {
String selection = createXmlFileString(fAnalysesList.getSelection()[0]);
@Nullable
File file = XmlUtils.listFiles().get(selection);
if (file == null) {
Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection));
TraceUtils.displayErrorMsg(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection), NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection));
return;
}
try {
IEditorPart editorPart = IDE.openEditorOnFileStore(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), EFS.getStore(file.toURI()));
editorPart.addPropertyListener(new IPropertyListener() {
@Override
public void propertyChanged(Object source, int propId) {
if (ISaveablePart.PROP_DIRTY == propId) {
if (!editorPart.isDirty()) {
// Editor is not dirty anymore, i.e. it was saved
loadXmlFile(file, false);
}
}
}
});
close();
} catch (CoreException e) {
Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection));
TraceUtils.displayErrorMsg(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection), e.getMessage());
}
}
private void deleteAnalysis() {
boolean confirm = MessageDialog.openQuestion(
getShell(),
Messages.ManageXMLAnalysisDialog_DeleteFile,
NLS.bind(Messages.ManageXMLAnalysisDialog_DeleteConfirmation, fAnalysesList.getSelection()[0]));
if (confirm) {
String selection = createXmlFileString(fAnalysesList.getSelection()[0]);
deleteSupplementaryFile(selection);
XmlUtils.deleteFile(selection);
fillAnalysesList();
fInvalidFileLabel.setVisible(false);
XmlAnalysisModuleSource.notifyModuleChange();
/*
* FIXME: It refreshes the list of analysis under a trace, but since
* modules are instantiated when the trace opens, the changes won't
* apply to an opened trace, it needs to be closed then reopened
*/
refreshProject();
}
}
/**
* Refresh the selected project with the new XML file import
*/
private static void refreshProject() {
// Check if we are closing down
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window == null) {
return;
}
// Get the selection
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IWorkbenchPart part = page.getActivePart();
if (part == null) {
return;
}
ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
if (selectionProvider == null) {
return;
}
ISelection selection = selectionProvider.getSelection();
if (selection instanceof TreeSelection) {
TreeSelection sel = (TreeSelection) selection;
// There should be only one item selected as per the plugin.xml
Object element = sel.getFirstElement();
if (element instanceof TmfProjectModelElement) {
((TmfProjectModelElement) element).getProject().refresh();
}
}
}
private static String createXmlFileString(String baseName) {
IPath path = new Path(baseName).addFileExtension(XmlUtils.XML_EXTENSION);
return path.toString();
}
}