| /********************************************************************** |
| * Copyright (c) 2018 Ericsson |
| * |
| * All rights reserved. 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 |
| **********************************************************************/ |
| package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.preferences; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.resources.IFile; |
| 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.core.runtime.URIUtil; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.layout.GridLayoutFactory; |
| import org.eclipse.jface.preference.PreferencePage; |
| import org.eclipse.jface.resource.JFaceResources; |
| 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.SelectionAdapter; |
| 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.DirectoryDialog; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableItem; |
| 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.DirectoryDialogFactory; |
| 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.TmfOpenTraceHelper; |
| 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.IEditorReference; |
| import org.eclipse.ui.IPropertyListener; |
| import org.eclipse.ui.ISaveablePart; |
| import org.eclipse.ui.IURIEditorInput; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPreferencePage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.ide.IDE; |
| import org.eclipse.ui.part.FileEditorInput; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| |
| /** |
| * This class implements a preference page for XML analyses |
| * |
| * @author Jean-Christian Kouame |
| * @author Christophe Bourque Bedard |
| * |
| */ |
| public class XMLAnalysesManagerPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { |
| |
| private static final int BUTTON_CHECK_SELECTED_ID = IDialogConstants.CLIENT_ID; |
| private static final int BUTTON_UNCHECK_SELECTED_ID = IDialogConstants.CLIENT_ID + 1; |
| |
| private static final String XML_FILTER_EXTENSION = "*.xml"; //$NON-NLS-1$ |
| private Table fAnalysesTable; |
| private Button fDeleteButton; |
| private Button fExportButton; |
| private Button fEditButton; |
| private Label fStatusLabel; |
| |
| private static final String LINE_SEP = System.getProperty("line.separator"); //$NON-NLS-1$ |
| private static final String ELEMENT_SEP = "-\t"; //$NON-NLS-1$ |
| |
| private static final IPropertyListener SAVE_EDITOR_LISTENER = (source, propId) -> { |
| if (source instanceof IEditorPart) { |
| IEditorPart editorPart = (IEditorPart) source; |
| if (ISaveablePart.PROP_DIRTY == propId && !editorPart.isDirty()) { |
| // Editor is not dirty anymore, i.e. it was saved |
| if (editorPart.getEditorInput() instanceof IURIEditorInput) { |
| File file = URIUtil.toFile(((IURIEditorInput) editorPart.getEditorInput()).getURI()); |
| boolean success = loadXmlFile(file, false); |
| if (success) { |
| enableAndDisableAnalyses(Collections.singletonList(file.getName()), Collections.emptyList()); |
| } else { |
| enableAndDisableAnalyses(Collections.emptyList(), Collections.singletonList(file.getName())); |
| } |
| } |
| } |
| } |
| }; |
| |
| @Override |
| public void init(IWorkbench workbench) { |
| // Do nothing |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| getShell().setText(Messages.ManageXMLAnalysisDialog_ManageXmlAnalysesFiles); |
| |
| Composite mainComposite = new Composite(parent, SWT.NONE); |
| mainComposite.setLayout(new GridLayout(2, false)); |
| |
| Composite tableContainer = new Composite(mainComposite, SWT.NONE); |
| tableContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| GridLayoutFactory.fillDefaults().applyTo(tableContainer); |
| |
| // Create sub-contents |
| createTable(tableContainer); |
| createLabels(tableContainer); |
| createImportButtons(mainComposite); |
| createSelectionButtons(mainComposite); |
| |
| fillAnalysesTable(); |
| |
| getShell().setMinimumSize(300, 275); |
| |
| return mainComposite; |
| } |
| |
| @Override |
| public boolean performOk() { |
| handleChecks(); |
| return super.performOk(); |
| } |
| |
| @Override |
| protected void performDefaults() { |
| super.performDefaults(); |
| } |
| |
| /** |
| * Create the analyses table. |
| * |
| * @param composite |
| * the parent composite |
| */ |
| private void createTable(Composite composite) { |
| fAnalysesTable = new Table(composite, SWT.CHECK | SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); |
| fAnalysesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| fAnalysesTable.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| // Do nothing |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (fAnalysesTable.getSelectionCount() == 0) { |
| setButtonsEnabled(false); |
| } else { |
| setButtonsEnabled(true); |
| handleSelection(fAnalysesTable.getSelection()); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Create the file labels. |
| * |
| * @param composite |
| * the parent composite |
| */ |
| private void createLabels(Composite composite) { |
| fStatusLabel = new Label(composite, SWT.NONE); |
| fStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| } |
| |
| /** |
| * Add the import-related buttons. |
| * |
| * @param composite |
| * the parent composite |
| */ |
| private void createImportButtons(Composite composite) { |
| Composite buttonContainer = new Composite(composite, SWT.NULL); |
| buttonContainer.setLayout(new GridLayout()); |
| buttonContainer.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false)); |
| |
| Button importButton = new Button(buttonContainer, SWT.PUSH); |
| importButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); |
| importButton.setText(Messages.ManageXMLAnalysisDialog_Import); |
| importButton.addSelectionListener(new SelectionAdapter() { |
| @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.addSelectionListener(new SelectionAdapter() { |
| @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.addSelectionListener(new SelectionAdapter() { |
| @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.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| deleteAnalyses(); |
| } |
| }); |
| |
| setButtonsEnabled(false); |
| } |
| |
| /** |
| * Add the selection and deselection buttons to the dialog. |
| * |
| * @param composite |
| * the parent composite |
| */ |
| protected void createSelectionButtons(Composite composite) { |
| Composite buttonComposite = new Composite(composite, SWT.NONE); |
| GridLayout layout = new GridLayout(2, true); |
| layout.marginWidth = 0; |
| buttonComposite.setLayout(layout); |
| buttonComposite.setFont(composite.getFont()); |
| GridData data = new GridData(SWT.RIGHT, SWT.TOP, false, false); |
| buttonComposite.setLayoutData(data); |
| |
| /* Create the buttons in the good order to place them as we want */ |
| Button checkSelectedButton = createButton(buttonComposite, |
| BUTTON_CHECK_SELECTED_ID, Messages.ManageXMLAnalysisDialog_CHECK_SELECTED); |
| Button checkAllButton = createButton(buttonComposite, |
| IDialogConstants.SELECT_ALL_ID, Messages.ManageXMLAnalysisDialog_CHECK_ALL); |
| Button uncheckSelectedButton = createButton(buttonComposite, |
| BUTTON_UNCHECK_SELECTED_ID, Messages.ManageXMLAnalysisDialog_UNCHECK_SELECTED); |
| Button uncheckAllButton = createButton(buttonComposite, |
| IDialogConstants.DESELECT_ALL_ID, Messages.ManageXMLAnalysisDialog_UNCHECK_ALL); |
| |
| /* Add a listener to each button */ |
| checkSelectedButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| for (TableItem selectedItem : fAnalysesTable.getSelection()) { |
| selectedItem.setChecked(true); |
| } |
| handleSelection(fAnalysesTable.getSelection()); |
| } |
| }); |
| |
| checkAllButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| for (TableItem selectedItem : fAnalysesTable.getItems()) { |
| selectedItem.setChecked(true); |
| } |
| handleSelection(fAnalysesTable.getSelection()); |
| } |
| }); |
| |
| uncheckSelectedButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| for (TableItem selectedItem : fAnalysesTable.getSelection()) { |
| selectedItem.setChecked(false); |
| } |
| } |
| }); |
| |
| uncheckAllButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| for (TableItem selectedItem : fAnalysesTable.getItems()) { |
| selectedItem.setChecked(false); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Helper method for creating a button. |
| * |
| * @param parent |
| * the parent composite |
| * @param id |
| * the id |
| * @param label |
| * the label to display |
| * @return the resulting button |
| */ |
| private static Button createButton(Composite parent, int id, String label) { |
| Button button = new Button(parent, SWT.PUSH); |
| button.setText(label); |
| button.setFont(JFaceResources.getDialogFont()); |
| button.setData(Integer.valueOf(id)); |
| GridData data = new GridData(SWT.FILL, SWT.CENTER, true, true); |
| button.setLayoutData(data); |
| return button; |
| } |
| |
| private void setButtonsEnabled(boolean enable) { |
| fDeleteButton.setEnabled(enable); |
| fExportButton.setEnabled(enable); |
| fEditButton.setEnabled(enable); |
| } |
| |
| /** |
| * Handle the current table selection by validating the associated file. |
| * |
| * @param selection |
| * the selected table item |
| */ |
| private void handleSelection(TableItem[] selection) { |
| for (TableItem selectedItem : selection) { |
| String xmlName = XmlUtils.createXmlFileString(selectedItem.getText()); |
| if (isFileValid(xmlName)) { |
| if (selection.length == 1) { |
| if (XmlUtils.isAnalysisEnabled(xmlName)) { |
| fStatusLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_DARK_GREEN)); |
| fStatusLabel.setText(Messages.ManageXMLAnalysisDialog_FileEnabled); |
| } else { |
| fStatusLabel.setText(""); //$NON-NLS-1$ |
| } |
| } |
| } else { |
| if (selection.length == 1) { |
| fStatusLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_RED)); |
| fStatusLabel.setText(Messages.ManageXMLAnalysisDialog_FileValidationError); |
| } |
| if (XmlUtils.isAnalysisEnabled(xmlName)) { |
| enableAndDisableAnalyses( |
| Collections.emptyList(), |
| ImmutableList.of(Objects.requireNonNull(xmlName))); |
| } |
| selectedItem.setChecked(false); |
| } |
| } |
| if (selection.length != 1) { |
| fStatusLabel.setText(""); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Fill the table with the imported files. |
| */ |
| private void fillAnalysesTable() { |
| fAnalysesTable.removeAll(); |
| Map<String, File> files = XmlUtils.listFiles(); |
| for (String file : files.keySet()) { |
| // Remove the extension from the file path to display. |
| IPath path = new Path(file); |
| |
| // Create item and add to table |
| TableItem item = new TableItem(fAnalysesTable, SWT.NONE); |
| item.setText(path.removeFileExtension().toString()); |
| item.setChecked(XmlUtils.isAnalysisEnabled(path.toString())); |
| } |
| setButtonsEnabled(false); |
| } |
| |
| /** |
| * Apply change to items according to their checkboxes. |
| */ |
| private void handleChecks() { |
| Map<@NonNull String, @NonNull File> listFiles = XmlUtils.listFiles(); |
| Collection<String> filesToEnable = Lists.newArrayList(); |
| Collection<String> filesToDisable = Lists.newArrayList(); |
| |
| for (TableItem item : fAnalysesTable.getItems()) { |
| String xmlName = XmlUtils.createXmlFileString(item.getText()); |
| // Only enable/disable if the checkbox status has changed |
| if (item.getChecked() && !XmlUtils.isAnalysisEnabled(xmlName)) { |
| // Do not enable an invalid file |
| if (isFileValid(xmlName, listFiles)) { |
| filesToEnable.add(xmlName); |
| } else { |
| item.setChecked(false); |
| } |
| } else if (!item.getChecked() && XmlUtils.isAnalysisEnabled(xmlName)) { |
| filesToDisable.add(xmlName); |
| } |
| } |
| |
| // Apply changes |
| if (!(filesToEnable.isEmpty() && filesToDisable.isEmpty())) { |
| enableAndDisableAnalyses(filesToEnable, filesToDisable); |
| } |
| |
| // Force update for selection handling |
| handleSelection(fAnalysesTable.getSelection()); |
| } |
| |
| /** |
| * Enable and disable analyses all at once. |
| * |
| * @param toEnable |
| * the list of xml file names (with extension) to enable |
| * @param toDisable |
| * the list of xml file names (with extension) to disable |
| */ |
| private static void enableAndDisableAnalyses(Collection<String> toEnable, Collection<String> toDisable) { |
| Collection<String> toEnableOrDisable = new ArrayList<>(toEnable.size() + toDisable.size()); |
| toEnableOrDisable.addAll(toEnable); |
| toEnableOrDisable.addAll(toDisable); |
| Collection<TmfCommonProjectElement> elements = deleteSupplementaryFiles(toEnableOrDisable); |
| XmlUtils.enableFiles(toEnable); |
| XmlUtils.disableFiles(toDisable); |
| XmlAnalysisModuleSource.notifyModuleChange(); |
| refreshProject(elements); |
| } |
| |
| /** |
| * Import new analysis. |
| */ |
| private void importAnalysis() { |
| FileDialog dialog = TmfFileDialogFactory.create(Display.getCurrent().getActiveShell(), SWT.OPEN | SWT.MULTI); |
| dialog.setText(Messages.ManageXMLAnalysisDialog_SelectFilesImport); |
| dialog.setFilterNames(new String[] { Messages.ManageXMLAnalysisDialog_ImportXmlFile + " (" + XML_FILTER_EXTENSION + ")" }); //$NON-NLS-1$ //$NON-NLS-2$ |
| dialog.setFilterExtensions(new String[] { XML_FILTER_EXTENSION }); |
| dialog.open(); |
| String directoryPath = dialog.getFilterPath(); |
| if (!directoryPath.isEmpty()) { |
| File directory = new File(directoryPath); |
| String[] files = dialog.getFileNames(); |
| Collection<String> filesToProcess = Lists.newArrayList(); |
| for (String fileName : files) { |
| File file = new File(directory, fileName); |
| if (loadXmlFile(file, true)) { |
| filesToProcess.add(file.getName()); |
| } |
| } |
| if (!filesToProcess.isEmpty()) { |
| fillAnalysesTable(); |
| Collection<TmfCommonProjectElement> elements = deleteSupplementaryFiles(filesToProcess); |
| XmlAnalysisModuleSource.notifyModuleChange(); |
| refreshProject(elements); |
| } |
| } |
| } |
| |
| /** |
| * Load an XML analysis file. |
| * |
| * @param file |
| * the file |
| * @param addFile |
| * true if the file should be added/copied, false otherwise |
| * @return true if loading was successful, false otherwise |
| */ |
| private static boolean loadXmlFile(File file, boolean addFile) { |
| IStatus status = XmlUtils.xmlValidate(file); |
| if (status.isOK()) { |
| if (addFile) { |
| status = XmlUtils.addXmlFile(file); |
| } else { |
| XmlUtils.updateXmlFile(file); |
| } |
| if (status.isOK()) { |
| 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; |
| } |
| |
| /** |
| * Export analysis to new file. |
| */ |
| private void exportAnalysis() { |
| TableItem[] selection = fAnalysesTable.getSelection(); |
| DirectoryDialog dialog = DirectoryDialogFactory.create(Display.getCurrent().getActiveShell(), SWT.SAVE); |
| dialog.setText(NLS.bind(Messages.ManageXMLAnalysisDialog_SelectDirectoryExport, selection.length)); |
| String directoryPath = dialog.open(); |
| if (directoryPath != null) { |
| File directory = new File(directoryPath); |
| for (TableItem item : selection) { |
| String fileName = item.getText(); |
| String fileNameXml = XmlUtils.createXmlFileString(fileName); |
| String path = new File(directory, fileNameXml).getAbsolutePath(); |
| if (!XmlUtils.exportXmlFile(fileNameXml, path).isOK()) { |
| Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToExport, fileNameXml)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Edit analysis file(s) with built-in editor. |
| */ |
| private void editAnalysis() { |
| Map<@NonNull String, @NonNull File> listFiles = XmlUtils.listFiles(); |
| for (TableItem item : fAnalysesTable.getSelection()) { |
| String selection = XmlUtils.createXmlFileString(item.getText()); |
| @Nullable File file = 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())); |
| // Remove listener first in case the editor was already opened |
| editorPart.removePropertyListener(SAVE_EDITOR_LISTENER); |
| editorPart.addPropertyListener(SAVE_EDITOR_LISTENER); |
| } catch (CoreException e) { |
| Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection)); |
| TraceUtils.displayErrorMsg(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection), e.getMessage()); |
| } |
| } |
| } |
| |
| /** |
| * Delete analyses, remove the corresponding files, and close the editors, if |
| * opened. |
| */ |
| private void deleteAnalyses() { |
| // Get list of files |
| TableItem[] selection = fAnalysesTable.getSelection(); |
| List<String> filesToDeleteList = Lists.newArrayList(); |
| for (TableItem item : selection) { |
| filesToDeleteList.add(ELEMENT_SEP + item.getText()); |
| } |
| final String filesToDelete = Joiner.on(LINE_SEP).join(filesToDeleteList); |
| |
| boolean confirm = MessageDialog.openQuestion( |
| getShell(), |
| Messages.ManageXMLAnalysisDialog_DeleteFile, |
| Messages.ManageXMLAnalysisDialog_DeleteConfirmation + StringUtils.repeat(LINE_SEP, 2) + filesToDelete); |
| if (confirm) { |
| Set<IEditorReference> editorReferences = getEditorReferences(); |
| Collection<String> toDeleteSupFiles = Lists.newArrayList(); |
| Collection<String> toDeleteFiles = Lists.newArrayList(); |
| for (TableItem item : selection) { |
| String itemTitle = XmlUtils.createXmlFileString(item.getText()); |
| // If opened, close the editor before deleting the file |
| editorReferences.forEach(editorReference -> { |
| if (editorReference.getTitle().equals(itemTitle)) { |
| PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeEditor(editorReference.getEditor(false), false); |
| } |
| }); |
| // We do not need to re-open the elements of an analysis that was already |
| // disabled |
| if (XmlUtils.isAnalysisEnabled(itemTitle)) { |
| toDeleteSupFiles.add(itemTitle); |
| } |
| toDeleteFiles.add(itemTitle); |
| } |
| Collection<TmfCommonProjectElement> elements = deleteSupplementaryFiles(toDeleteSupFiles); |
| XmlUtils.deleteFiles(toDeleteFiles); |
| fillAnalysesTable(); |
| handleSelection(fAnalysesTable.getSelection()); |
| XmlAnalysisModuleSource.notifyModuleChange(); |
| refreshProject(elements); |
| } |
| } |
| |
| /** |
| * Delete the supplementary files associated with XML analysis files. |
| * |
| * @param xmlFiles |
| * the xml analysis files (with extension) |
| * @return the list of elements that should be re-opened |
| */ |
| private static Collection<TmfCommonProjectElement> deleteSupplementaryFiles(Collection<String> xmlFiles) { |
| // 1. Look for all traces that have these analyses |
| // 2. Close them if they are opened, but remember them |
| // 3. Delete the related supplementary files |
| Collection<TmfCommonProjectElement> toReopen = new ArrayList<>(); |
| List<IResource> resourceToDelete = new ArrayList<>(); |
| Set<String> ids = Sets.newHashSet(); |
| xmlFiles.forEach(xmlFile -> ids.addAll(XmlUtils.getAnalysisIdsFromFile(xmlFile))); |
| IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(0); |
| for (IProject project : projects) { |
| TmfProjectElement pElement = TmfProjectRegistry.getProject(project); |
| if (pElement != null) { |
| 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()); |
| } |
| |
| Set<IEditorReference> editorReferences = getEditorReferences(); |
| |
| for (TmfCommonProjectElement tElement : tElements) { |
| for (IResource resource : tElement.getSupplementaryResources()) { |
| for (String id : ids) { |
| if (resource.getName().startsWith(id)) { |
| resourceToDelete.add(resource); |
| } |
| } |
| } |
| IFile file = tElement.getBookmarksFile(); |
| FileEditorInput input = new FileEditorInput(file); |
| boolean open = Iterables.any(editorReferences, editorReference -> { |
| try { |
| return editorReference.getEditorInput().equals(input); |
| } catch (PartInitException e) { |
| Activator.logError("Failed to test the " + tElement.getName() + " editor", e); //$NON-NLS-1$ //$NON-NLS-2$ |
| return false; |
| } |
| }); |
| if (open) { |
| toReopen.add(tElement); |
| } |
| tElement.closeEditors(); |
| } |
| } |
| } |
| for (IResource resource : resourceToDelete) { |
| try { |
| resource.delete(false, null); |
| } catch (CoreException e) { |
| Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_DeleteFileError, resource.getName())); |
| } |
| } |
| return toReopen; |
| } |
| |
| /** |
| * Refresh the selected project elements. This is useful after XML files |
| * importing/deletion/enabling/disabling. |
| * |
| * @param elements |
| * the elements to re-open |
| */ |
| private static void refreshProject(Collection<TmfCommonProjectElement> elements) { |
| // 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(); |
| } |
| } |
| |
| // Re-open given elements |
| elements.forEach(TmfOpenTraceHelper::openFromElement); |
| } |
| |
| /** |
| * Validate an XML file. |
| * |
| * @param xmlName |
| * the xml file, with extension |
| * @return true if valid, false otherwise |
| */ |
| private static boolean isFileValid(String xmlName) { |
| return isFileValid(xmlName, XmlUtils.listFiles()); |
| } |
| |
| /** |
| * Validate an XML file. This version is intended to be used when validating |
| * multiple files (i.e. when this is called multiple times). |
| * |
| * @param xmlName |
| * the xml file, with extension |
| * @param listFiles |
| * the XML files |
| * @return |
| */ |
| private static boolean isFileValid(String xmlName, Map<@NonNull String, @NonNull File> listFiles) { |
| File file = listFiles.get(xmlName); |
| return (file != null && XmlUtils.xmlValidate(file).isOK()); |
| } |
| |
| /** |
| * Get editor references. |
| * |
| * @return the set of editor references |
| */ |
| private static Set<IEditorReference> getEditorReferences() { |
| Set<IEditorReference> editorReferences = new HashSet<>(); |
| IWorkbench wb = PlatformUI.getWorkbench(); |
| for (IWorkbenchWindow wbWindow : wb.getWorkbenchWindows()) { |
| for (IWorkbenchPage wbPage : wbWindow.getPages()) { |
| editorReferences.addAll(Arrays.asList(wbPage.getEditorReferences())); |
| } |
| } |
| return editorReferences; |
| } |
| } |