Commit | Line | Data |
---|---|---|
f98e9dbe JCK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2016 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are made | |
5 | * available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | *******************************************************************************/ | |
9 | package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.handler; | |
10 | ||
11 | import java.io.File; | |
12 | import java.util.ArrayList; | |
13 | import java.util.Map; | |
14 | ||
c02cb8e4 | 15 | import org.eclipse.core.filesystem.EFS; |
f98e9dbe JCK |
16 | import org.eclipse.core.resources.IProject; |
17 | import org.eclipse.core.resources.IResource; | |
18 | import org.eclipse.core.resources.ResourcesPlugin; | |
19 | import org.eclipse.core.runtime.CoreException; | |
537572cd | 20 | import org.eclipse.core.runtime.IPath; |
f98e9dbe | 21 | import org.eclipse.core.runtime.IStatus; |
537572cd | 22 | import org.eclipse.core.runtime.Path; |
c02cb8e4 | 23 | import org.eclipse.jdt.annotation.Nullable; |
f98e9dbe JCK |
24 | import org.eclipse.jface.dialogs.Dialog; |
25 | import org.eclipse.jface.dialogs.IDialogConstants; | |
26 | import org.eclipse.jface.dialogs.MessageDialog; | |
27 | import org.eclipse.jface.viewers.ISelection; | |
28 | import org.eclipse.jface.viewers.ISelectionProvider; | |
29 | import org.eclipse.jface.viewers.TreeSelection; | |
30 | import org.eclipse.osgi.util.NLS; | |
31 | import org.eclipse.swt.SWT; | |
32 | import org.eclipse.swt.events.SelectionEvent; | |
33 | import org.eclipse.swt.events.SelectionListener; | |
34 | import org.eclipse.swt.layout.GridData; | |
35 | import org.eclipse.swt.layout.GridLayout; | |
36 | import org.eclipse.swt.widgets.Button; | |
37 | import org.eclipse.swt.widgets.Composite; | |
38 | import org.eclipse.swt.widgets.Control; | |
39 | import org.eclipse.swt.widgets.Display; | |
40 | import org.eclipse.swt.widgets.FileDialog; | |
41 | import org.eclipse.swt.widgets.Label; | |
42 | import org.eclipse.swt.widgets.List; | |
43 | import org.eclipse.swt.widgets.Shell; | |
6eca054d GB |
44 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlAnalysisModuleSource; |
45 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils; | |
f98e9dbe | 46 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.Activator; |
f98e9dbe JCK |
47 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement; |
48 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; | |
49 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectModelElement; | |
50 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; | |
51 | import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; | |
c02cb8e4 MAL |
52 | import org.eclipse.ui.IEditorPart; |
53 | import org.eclipse.ui.IPropertyListener; | |
54 | import org.eclipse.ui.ISaveablePart; | |
f98e9dbe JCK |
55 | import org.eclipse.ui.IWorkbenchPage; |
56 | import org.eclipse.ui.IWorkbenchPart; | |
57 | import org.eclipse.ui.IWorkbenchWindow; | |
58 | import org.eclipse.ui.PlatformUI; | |
c02cb8e4 | 59 | import org.eclipse.ui.ide.IDE; |
f98e9dbe JCK |
60 | |
61 | /** | |
62 | * Dialog for XML analysis files | |
63 | * | |
64 | * @author Jean-Christian Kouame | |
65 | */ | |
66 | public class ManageXMLAnalysisDialog extends Dialog { | |
67 | ||
68 | private final String XML_FILTER_EXTENSION = "*.xml"; //$NON-NLS-1$ | |
69 | private List fAnalysesList; | |
70 | private Button fDeleteButton; | |
71 | private Button fImportButton; | |
72 | private Button fExportButton; | |
c02cb8e4 | 73 | private Button fEditButton; |
f98e9dbe JCK |
74 | private Label fInvalidFileLabel; |
75 | ||
76 | /** | |
77 | * Constructor | |
78 | * | |
79 | * @param parent | |
80 | * Parent shell of this dialog | |
81 | */ | |
82 | public ManageXMLAnalysisDialog(Shell parent) { | |
83 | super(parent); | |
84 | setShellStyle(SWT.RESIZE | SWT.MAX | getShellStyle()); | |
85 | } | |
86 | ||
87 | @Override | |
88 | protected Control createDialogArea(Composite parent) { | |
89 | getShell().setText(Messages.ManageXMLAnalysisDialog_ManageXmlAnalysesFiles); | |
90 | ||
91 | Composite composite = (Composite) super.createDialogArea(parent); | |
92 | composite.setLayout(new GridLayout(2, false)); | |
93 | ||
94 | Composite listContainer = new Composite(composite, SWT.NONE); | |
95 | listContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | |
96 | GridLayout lcgl = new GridLayout(); | |
97 | lcgl.marginHeight = 0; | |
98 | lcgl.marginWidth = 0; | |
99 | listContainer.setLayout(lcgl); | |
100 | ||
101 | fAnalysesList = new List(listContainer, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); | |
102 | fAnalysesList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | |
103 | fAnalysesList.addSelectionListener(new SelectionListener() { | |
104 | @Override | |
105 | public void widgetDefaultSelected(SelectionEvent e) { | |
106 | } | |
107 | ||
108 | @Override | |
109 | public void widgetSelected(SelectionEvent e) { | |
110 | if (fAnalysesList.getSelectionCount() == 0) { | |
111 | fDeleteButton.setEnabled(false); | |
112 | fExportButton.setEnabled(false); | |
c02cb8e4 | 113 | fEditButton.setEnabled(false); |
f98e9dbe JCK |
114 | } else { |
115 | fDeleteButton.setEnabled(true); | |
116 | fExportButton.setEnabled(true); | |
c02cb8e4 | 117 | fEditButton.setEnabled(true); |
f98e9dbe JCK |
118 | handleSelection(fAnalysesList.getSelection()); |
119 | } | |
120 | } | |
121 | }); | |
122 | ||
123 | fInvalidFileLabel = new Label(listContainer, SWT.ICON_ERROR); | |
124 | fInvalidFileLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); | |
125 | fInvalidFileLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_RED)); | |
126 | fInvalidFileLabel.setText(Messages.ManageXMLAnalysisDialog_FileValidationError); | |
127 | fInvalidFileLabel.setVisible(false); | |
128 | ||
129 | Composite buttonContainer = new Composite(composite, SWT.NULL); | |
130 | buttonContainer.setLayout(new GridLayout()); | |
131 | buttonContainer.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false)); | |
132 | ||
133 | fImportButton = new Button(buttonContainer, SWT.PUSH); | |
134 | fImportButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); | |
135 | fImportButton.setText(Messages.ManageXMLAnalysisDialog_Import); | |
136 | fImportButton.addSelectionListener(new SelectionListener() { | |
137 | @Override | |
138 | public void widgetDefaultSelected(SelectionEvent e) { | |
139 | } | |
140 | ||
141 | @Override | |
142 | public void widgetSelected(SelectionEvent e) { | |
143 | importAnalysis(); | |
144 | } | |
145 | }); | |
146 | ||
147 | fExportButton = new Button(buttonContainer, SWT.PUSH); | |
148 | fExportButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); | |
149 | fExportButton.setText(Messages.ManageXMLAnalysisDialog_Export); | |
150 | fExportButton.setEnabled(false); | |
151 | fExportButton.addSelectionListener(new SelectionListener() { | |
152 | @Override | |
153 | public void widgetDefaultSelected(SelectionEvent e) { | |
154 | } | |
155 | ||
156 | @Override | |
157 | public void widgetSelected(SelectionEvent e) { | |
158 | exportAnalysis(); | |
159 | } | |
160 | }); | |
161 | ||
c02cb8e4 MAL |
162 | fEditButton = new Button(buttonContainer, SWT.PUSH); |
163 | fEditButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); | |
164 | fEditButton.setText(Messages.ManageXMLAnalysisDialog_Edit); | |
165 | fEditButton.setEnabled(false); | |
166 | fEditButton.addSelectionListener(new SelectionListener() { | |
167 | @Override | |
168 | public void widgetDefaultSelected(SelectionEvent e) { | |
169 | } | |
170 | ||
171 | @Override | |
172 | public void widgetSelected(SelectionEvent e) { | |
173 | editAnalysis(); | |
174 | } | |
175 | ||
176 | }); | |
177 | ||
f98e9dbe JCK |
178 | fDeleteButton = new Button(buttonContainer, SWT.PUSH); |
179 | fDeleteButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); | |
180 | fDeleteButton.setText(Messages.ManageXMLAnalysisDialog_Delete); | |
181 | fDeleteButton.setEnabled(false); | |
182 | fDeleteButton.addSelectionListener(new SelectionListener() { | |
183 | @Override | |
184 | public void widgetDefaultSelected(SelectionEvent e) { | |
185 | } | |
186 | ||
187 | @Override | |
188 | public void widgetSelected(SelectionEvent e) { | |
189 | deleteAnalysis(); | |
190 | } | |
191 | ||
192 | }); | |
193 | ||
194 | fillAnalysesList(); | |
195 | ||
196 | getShell().setMinimumSize(300, 275); | |
197 | return composite; | |
198 | } | |
199 | ||
200 | private void handleSelection(String[] selection) { | |
537572cd BH |
201 | Map<String, File> files = XmlUtils.listFiles(); |
202 | File file = files.get(createXmlFileString(selection[0])); | |
f98e9dbe JCK |
203 | if (file != null && XmlUtils.xmlValidate(file).isOK()) { |
204 | fInvalidFileLabel.setVisible(false); | |
205 | } else { | |
206 | fInvalidFileLabel.setVisible(true); | |
207 | } | |
208 | } | |
209 | ||
537572cd | 210 | private static void deleteSupplementaryFile(String xmlFile) { |
f98e9dbe JCK |
211 | // 1. Look for all traces that have this analysis |
212 | // 2. Close them if they are opened. | |
213 | // 3. Delete the related supplementary files | |
214 | java.util.List<IResource> resourceToDelete = new ArrayList<>(); | |
537572cd | 215 | java.util.List<String> ids = XmlUtils.getAnalysisIdsFromFile(xmlFile); |
f98e9dbe JCK |
216 | IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(0); |
217 | for (IProject project : projects) { | |
218 | TmfProjectElement pElement = TmfProjectRegistry.getProject(project); | |
219 | if (pElement != null) { | |
220 | java.util.List<TmfCommonProjectElement> tElements = new ArrayList<>(); | |
221 | tElements.addAll(pElement.getTracesFolder().getTraces()); | |
222 | tElements.addAll(pElement.getExperimentsFolder().getExperiments()); | |
223 | for (TmfCommonProjectElement tElement : tElements) { | |
224 | boolean closeEditor = false; | |
225 | for (IResource resource : tElement.getSupplementaryResources()) { | |
226 | for (String id : ids) { | |
227 | if (resource.getName().startsWith(id)) { | |
228 | resourceToDelete.add(resource); | |
229 | closeEditor = true; | |
230 | } | |
231 | } | |
232 | } | |
233 | if (closeEditor) { | |
234 | tElement.closeEditors(); | |
235 | } | |
236 | } | |
237 | } | |
238 | } | |
239 | for (IResource resource : resourceToDelete) { | |
240 | try { | |
241 | resource.delete(false, null); | |
242 | } catch (CoreException e) { | |
243 | Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_DeleteFileError, resource.getName())); | |
244 | } | |
245 | } | |
246 | } | |
247 | ||
248 | @Override | |
249 | protected void createButtonsForButtonBar(Composite parent) { | |
250 | createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, false); | |
251 | } | |
252 | ||
253 | private void fillAnalysesList() { | |
254 | fAnalysesList.removeAll(); | |
537572cd | 255 | Map<String, File> files = XmlUtils.listFiles(); |
f98e9dbe JCK |
256 | for (String file : files.keySet()) { |
257 | // Remove the extension from the file path. The extension is at the | |
258 | // end of the file path | |
537572cd BH |
259 | IPath path = new Path(file); |
260 | fAnalysesList.add(path.removeFileExtension().toString()); | |
f98e9dbe JCK |
261 | } |
262 | fDeleteButton.setEnabled(false); | |
263 | fExportButton.setEnabled(false); | |
264 | } | |
265 | ||
266 | private void importAnalysis() { | |
267 | FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(), SWT.OPEN); | |
268 | dialog.setText(Messages.ManageXMLAnalysisDialog_SelectFileImport); | |
269 | dialog.setFilterNames(new String[] { Messages.ManageXMLAnalysisDialog_ImportXmlFile + " (*.xml)" }); //$NON-NLS-1$ | |
270 | dialog.setFilterExtensions(new String[] { XML_FILTER_EXTENSION }); | |
271 | String path = dialog.open(); | |
272 | if (path != null) { | |
273 | File file = new File(path); | |
c02cb8e4 MAL |
274 | if (loadXmlFile(file, true)) { |
275 | fillAnalysesList(); | |
276 | } | |
277 | } | |
278 | } | |
279 | ||
280 | private static boolean loadXmlFile(File file, boolean addFile) { | |
281 | IStatus status = XmlUtils.xmlValidate(file); | |
282 | if (status.isOK()) { | |
283 | deleteSupplementaryFile(file.getName()); | |
284 | if (addFile) { | |
f98e9dbe | 285 | status = XmlUtils.addXmlFile(file); |
f98e9dbe | 286 | } |
c02cb8e4 MAL |
287 | if (status.isOK()) { |
288 | XmlAnalysisModuleSource.notifyModuleChange(); | |
289 | /* | |
290 | * FIXME: It refreshes the list of analysis under a trace, | |
291 | * but since modules are instantiated when the trace opens, | |
292 | * the changes won't apply to an opened trace, it needs to | |
293 | * be closed then reopened | |
294 | */ | |
295 | refreshProject(); | |
296 | return true; | |
297 | } | |
298 | ||
299 | Activator.logError(Messages.ManageXMLAnalysisDialog_ImportFileFailed); | |
300 | TraceUtils.displayErrorMsg(Messages.ManageXMLAnalysisDialog_ImportFileFailed, status.getMessage()); | |
301 | } else { | |
302 | Activator.logError(Messages.ManageXMLAnalysisDialog_ImportFileFailed); | |
303 | TraceUtils.displayErrorMsg(Messages.ManageXMLAnalysisDialog_ImportFileFailed, status.getMessage()); | |
f98e9dbe | 304 | } |
c02cb8e4 | 305 | return false; |
f98e9dbe JCK |
306 | } |
307 | ||
308 | private void exportAnalysis() { | |
309 | FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(), SWT.SAVE); | |
310 | dialog.setText(NLS.bind(Messages.ManageXMLAnalysisDialog_SelectFileExport, fAnalysesList.getSelection()[0])); | |
311 | dialog.setFilterExtensions(new String[] { XML_FILTER_EXTENSION, "*" }); //$NON-NLS-1$ | |
537572cd BH |
312 | String selection = createXmlFileString(fAnalysesList.getSelection()[0]); |
313 | dialog.setFileName(selection); | |
f98e9dbe JCK |
314 | String path = dialog.open(); |
315 | if (path != null) { | |
537572cd BH |
316 | if (!XmlUtils.exportXmlFile(selection, path).isOK()) { |
317 | Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToExport, selection)); | |
f98e9dbe JCK |
318 | } |
319 | } | |
320 | } | |
321 | ||
c02cb8e4 MAL |
322 | private void editAnalysis() { |
323 | String selection = createXmlFileString(fAnalysesList.getSelection()[0]); | |
324 | @Nullable | |
325 | File file = XmlUtils.listFiles().get(selection); | |
326 | if (file == null) { | |
327 | Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection)); | |
328 | TraceUtils.displayErrorMsg(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection), NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection)); | |
329 | return; | |
330 | } | |
331 | try { | |
332 | IEditorPart editorPart = IDE.openEditorOnFileStore(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), EFS.getStore(file.toURI())); | |
333 | editorPart.addPropertyListener(new IPropertyListener() { | |
334 | @Override | |
335 | public void propertyChanged(Object source, int propId) { | |
336 | if (ISaveablePart.PROP_DIRTY == propId) { | |
337 | if (!editorPart.isDirty()) { | |
338 | // Editor is not dirty anymore, i.e. it was saved | |
339 | loadXmlFile(file, false); | |
340 | } | |
341 | } | |
342 | } | |
343 | }); | |
344 | close(); | |
345 | } catch (CoreException e) { | |
346 | Activator.logError(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection)); | |
347 | TraceUtils.displayErrorMsg(NLS.bind(Messages.ManageXMLAnalysisDialog_FailedToEdit, selection), e.getMessage()); | |
348 | } | |
349 | } | |
350 | ||
f98e9dbe JCK |
351 | private void deleteAnalysis() { |
352 | boolean confirm = MessageDialog.openQuestion( | |
353 | getShell(), | |
354 | Messages.ManageXMLAnalysisDialog_DeleteFile, | |
355 | NLS.bind(Messages.ManageXMLAnalysisDialog_DeleteConfirmation, fAnalysesList.getSelection()[0])); | |
356 | if (confirm) { | |
537572cd | 357 | String selection = createXmlFileString(fAnalysesList.getSelection()[0]); |
f98e9dbe | 358 | deleteSupplementaryFile(selection); |
537572cd | 359 | XmlUtils.deleteFile(selection); |
f98e9dbe JCK |
360 | fillAnalysesList(); |
361 | fInvalidFileLabel.setVisible(false); | |
362 | XmlAnalysisModuleSource.notifyModuleChange(); | |
363 | /* | |
364 | * FIXME: It refreshes the list of analysis under a trace, but since | |
365 | * modules are instantiated when the trace opens, the changes won't | |
366 | * apply to an opened trace, it needs to be closed then reopened | |
367 | */ | |
368 | refreshProject(); | |
369 | } | |
370 | } | |
371 | ||
372 | /** | |
373 | * Refresh the selected project with the new XML file import | |
374 | */ | |
375 | private static void refreshProject() { | |
376 | // Check if we are closing down | |
377 | IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); | |
378 | if (window == null) { | |
379 | return; | |
380 | } | |
381 | ||
382 | // Get the selection | |
383 | IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); | |
384 | IWorkbenchPart part = page.getActivePart(); | |
385 | if (part == null) { | |
386 | return; | |
387 | } | |
388 | ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); | |
389 | if (selectionProvider == null) { | |
390 | return; | |
391 | } | |
392 | ISelection selection = selectionProvider.getSelection(); | |
393 | ||
394 | if (selection instanceof TreeSelection) { | |
395 | TreeSelection sel = (TreeSelection) selection; | |
396 | // There should be only one item selected as per the plugin.xml | |
397 | Object element = sel.getFirstElement(); | |
398 | if (element instanceof TmfProjectModelElement) { | |
399 | ((TmfProjectModelElement) element).getProject().refresh(); | |
400 | } | |
401 | } | |
402 | } | |
537572cd BH |
403 | |
404 | private static String createXmlFileString(String baseName) { | |
405 | IPath path = new Path(baseName).addFileExtension(XmlUtils.XML_EXTENSION); | |
406 | return path.toString(); | |
407 | } | |
f98e9dbe | 408 | } |