| /******************************************************************************* |
| * 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(); |
| } |
| } |