6395e052dee125280d6ff78b125b5b4d55861d89
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / project / wizards / SelectTracesWizardPage.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2015 Ericsson, École Polytechnique de Montréal
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made 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 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 * Geneviève Bastien - Moved the add and remove code to the experiment class
12 * Patrick Tasse - Add support for folder elements
13 * Marc-Andre Laperle - Convert to tree structure and add select/deselect all
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.tmf.ui.project.wizards;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.eclipse.core.resources.IFolder;
27 import org.eclipse.core.resources.IWorkspace;
28 import org.eclipse.core.resources.IWorkspaceRunnable;
29 import org.eclipse.core.resources.ResourcesPlugin;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IProgressMonitor;
32 import org.eclipse.core.runtime.IStatus;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.core.runtime.SubMonitor;
35 import org.eclipse.jdt.annotation.NonNull;
36 import org.eclipse.jface.dialogs.MessageDialog;
37 import org.eclipse.jface.operation.IRunnableWithProgress;
38 import org.eclipse.jface.operation.ModalContext;
39 import org.eclipse.jface.viewers.CheckStateChangedEvent;
40 import org.eclipse.jface.viewers.CheckboxTreeViewer;
41 import org.eclipse.jface.viewers.ColumnLabelProvider;
42 import org.eclipse.jface.viewers.ICheckStateListener;
43 import org.eclipse.jface.viewers.TreeViewer;
44 import org.eclipse.jface.viewers.TreeViewerColumn;
45 import org.eclipse.jface.viewers.ViewerComparator;
46 import org.eclipse.jface.wizard.WizardPage;
47 import org.eclipse.swt.SWT;
48 import org.eclipse.swt.events.SelectionAdapter;
49 import org.eclipse.swt.events.SelectionEvent;
50 import org.eclipse.swt.graphics.Image;
51 import org.eclipse.swt.layout.FillLayout;
52 import org.eclipse.swt.layout.GridData;
53 import org.eclipse.swt.layout.GridLayout;
54 import org.eclipse.swt.widgets.Button;
55 import org.eclipse.swt.widgets.Composite;
56 import org.eclipse.swt.widgets.Display;
57 import org.eclipse.swt.widgets.Tree;
58 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
59 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
60 import org.eclipse.tracecompass.tmf.ui.project.model.ITmfProjectModelElement;
61 import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement;
62 import org.eclipse.tracecompass.tmf.ui.project.model.TmfNavigatorContentProvider;
63 import org.eclipse.tracecompass.tmf.ui.project.model.TmfNavigatorLabelProvider;
64 import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
65 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
66 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
67 import org.eclipse.ui.dialogs.FilteredTree;
68 import org.eclipse.ui.dialogs.PatternFilter;
69
70 /**
71 * Implementation of a wizard page for selecting trace for an experiment.
72 * <p>
73 *
74 * @version 1.0
75 * @author Francois Chouinard
76 */
77 public class SelectTracesWizardPage extends WizardPage {
78
79 // ------------------------------------------------------------------------
80 // Attributes
81 // ------------------------------------------------------------------------
82
83 private final TmfProjectElement fProject;
84 private final TmfExperimentElement fExperiment;
85 private Map<String, TmfTraceElement> fPreviousTraces;
86 private CheckboxTreeViewer fCheckboxTreeViewer;
87 private TmfNavigatorContentProvider fContentProvider;
88 private TmfNavigatorLabelProvider fLabelProvider;
89
90 private static final int COLUMN_WIDTH = 200;
91 private static final int BUTTON_SPACING = 4;
92
93 // ------------------------------------------------------------------------
94 // Constructor
95 // ------------------------------------------------------------------------
96 /**
97 * Constructor
98 *
99 * @param project
100 * The project model element.
101 * @param experiment
102 * The experiment model experiment.
103 */
104 protected SelectTracesWizardPage(TmfProjectElement project, TmfExperimentElement experiment) {
105 super(""); //$NON-NLS-1$
106 setTitle(Messages.SelectTracesWizardPage_WindowTitle);
107 setDescription(Messages.SelectTracesWizardPage_Description);
108 fProject = project;
109 fExperiment = experiment;
110 }
111
112 // ------------------------------------------------------------------------
113 // Dialog
114 // ------------------------------------------------------------------------
115
116 @Override
117 public void createControl(Composite parent) {
118 Composite container = new Composite(parent, SWT.NULL);
119 container.setLayout(new GridLayout(2, false));
120 setControl(container);
121
122 new FilteredTree(container, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, new PatternFilter(), true) {
123 @Override
124 protected TreeViewer doCreateTreeViewer(Composite aparent, int style) {
125 return SelectTracesWizardPage.this.doCreateTreeViewer(aparent);
126 }
127 };
128
129 Composite buttonComposite = new Composite(container, SWT.NONE);
130 FillLayout layout = new FillLayout(SWT.VERTICAL);
131 layout.spacing = BUTTON_SPACING;
132 buttonComposite.setLayout(layout);
133 GridData gd = new GridData();
134 gd.verticalAlignment = SWT.CENTER;
135 buttonComposite.setLayoutData(gd);
136
137 Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
138 selectAllButton.setText(org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.Messages.Dialog_SelectAll);
139 selectAllButton.addSelectionListener(new SelectionAdapter() {
140 @Override
141 public void widgetSelected(SelectionEvent e) {
142 setAllChecked(true);
143 }
144 });
145
146 Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
147 deselectAllButton.setText(org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.Messages.Dialog_DeselectAll);
148 deselectAllButton.addSelectionListener(new SelectionAdapter() {
149 @Override
150 public void widgetSelected(SelectionEvent e) {
151 setAllChecked(false);
152 }
153 });
154 }
155
156 private TreeViewer doCreateTreeViewer(Composite parent) {
157 fCheckboxTreeViewer = new CheckboxTreeViewer(parent, SWT.BORDER);
158 fContentProvider = new TmfNavigatorContentProvider() {
159
160 @Override
161 public Object[] getElements(Object inputElement) {
162 return getChildren(inputElement);
163 }
164
165 @Override
166 public synchronized Object[] getChildren(Object parentElement) {
167 // We only care about the content of trace folders
168 if (parentElement instanceof TmfTraceFolder) {
169 Object[] children = super.getChildren(parentElement);
170 List<ITmfProjectModelElement> filteredChildren = new ArrayList<>();
171 for (Object child : children) {
172 if (child instanceof TmfTraceElement) {
173 TmfTraceElement traceElement = (TmfTraceElement) child;
174 String traceType = traceElement.getTraceType();
175 if (traceType != null && TmfTraceType.getTraceType(traceType) != null) {
176 filteredChildren.add(traceElement);
177 }
178 } else if (child instanceof TmfTraceFolder) {
179 filteredChildren.add((TmfTraceFolder) child);
180 }
181 }
182 return filteredChildren.toArray();
183 }
184 return null;
185 }
186
187 @Override
188 public boolean hasChildren(Object element) {
189 Object[] children = getChildren(element);
190 return children != null && children.length > 0;
191 }
192 };
193 fCheckboxTreeViewer.setContentProvider(fContentProvider);
194 fLabelProvider = new TmfNavigatorLabelProvider();
195 fCheckboxTreeViewer.setLabelProvider(fLabelProvider);
196 fCheckboxTreeViewer.setComparator(new ViewerComparator());
197
198 final Tree tree = fCheckboxTreeViewer.getTree();
199 GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
200 tree.setLayoutData(gd);
201 tree.setHeaderVisible(true);
202
203 final TreeViewerColumn column = new TreeViewerColumn(fCheckboxTreeViewer, SWT.NONE);
204 column.getColumn().setWidth(COLUMN_WIDTH);
205 column.getColumn().setText(Messages.SelectTracesWizardPage_TraceColumnHeader);
206 column.setLabelProvider(new ColumnLabelProvider() {
207 @Override
208 public String getText(Object element) {
209 return fLabelProvider.getText(element);
210 }
211
212 @Override
213 public Image getImage(Object element) {
214 return fLabelProvider.getImage(element);
215 }
216 });
217
218 // Get the list of traces already part of the experiment
219 fPreviousTraces = new HashMap<>();
220 for (ITmfProjectModelElement child : fExperiment.getChildren()) {
221 if (child instanceof TmfTraceElement) {
222 TmfTraceElement trace = (TmfTraceElement) child;
223 String name = trace.getElementPath();
224 fPreviousTraces.put(name, trace);
225 }
226 }
227
228 // Populate the list of traces to choose from
229 Set<String> keys = fPreviousTraces.keySet();
230 TmfTraceFolder traceFolder = fProject.getTracesFolder();
231 fCheckboxTreeViewer.setInput(traceFolder);
232
233 // Set the checkbox for the traces already included
234 setCheckedAlreadyIncludedTraces(keys, fContentProvider.getElements(fCheckboxTreeViewer.getInput()));
235
236 fCheckboxTreeViewer.addCheckStateListener(new ICheckStateListener() {
237 @Override
238 public void checkStateChanged(CheckStateChangedEvent event) {
239 Object element = event.getElement();
240 setSubtreeChecked(element, event.getChecked());
241 maintainCheckIntegrity(element);
242 }
243 });
244
245 return fCheckboxTreeViewer;
246 }
247
248 private void maintainCheckIntegrity(final Object element) {
249 Object parentElement = fContentProvider.getParent(element);
250 boolean allChecked = true;
251 boolean oneChecked = false;
252 boolean oneGrayed = false;
253 if (parentElement != null) {
254 if (fContentProvider.getChildren(parentElement) != null) {
255 for (Object child : fContentProvider.getChildren(parentElement)) {
256 boolean checked = fCheckboxTreeViewer.getChecked(child);
257 oneChecked |= checked;
258 allChecked &= checked;
259 oneGrayed |= fCheckboxTreeViewer.getGrayed(child);
260 }
261 }
262 if (oneGrayed || oneChecked && !allChecked) {
263 fCheckboxTreeViewer.setGrayChecked(parentElement, true);
264 } else {
265 fCheckboxTreeViewer.setGrayed(parentElement, false);
266 fCheckboxTreeViewer.setChecked(parentElement, allChecked);
267 }
268 maintainCheckIntegrity(parentElement);
269 }
270 }
271
272 private void setCheckedAlreadyIncludedTraces(Set<String> alreadyIncludedTraces, Object[] elements) {
273 for (Object element : elements) {
274 if (element instanceof TmfTraceElement) {
275 TmfTraceElement trace = (TmfTraceElement) element;
276 String elementPath = trace.getElementPath();
277 if (alreadyIncludedTraces.contains(elementPath)) {
278 fCheckboxTreeViewer.setChecked(element, true);
279 maintainCheckIntegrity(element);
280 }
281 }
282 Object[] children = fContentProvider.getChildren(element);
283 if (children != null) {
284 setCheckedAlreadyIncludedTraces(alreadyIncludedTraces, children);
285 }
286 }
287 }
288
289 /**
290 * Sets all items in the element viewer to be checked or unchecked
291 *
292 * @param checked
293 * whether or not items should be checked
294 */
295 private void setAllChecked(boolean checked) {
296 for (Object element : fContentProvider.getChildren(fCheckboxTreeViewer.getInput())) {
297 setSubtreeChecked(element, checked);
298 }
299 }
300
301 /**
302 * A version of setSubtreeChecked that also handles the grayed state
303 *
304 * @param element
305 * the element
306 * @param checked
307 * true if the item should be checked, and false if it should be
308 * unchecked
309 */
310 private void setSubtreeChecked(Object element, boolean checked) {
311 fCheckboxTreeViewer.setChecked(element, checked);
312 if (checked) {
313 fCheckboxTreeViewer.setGrayed(element, false);
314 }
315 Object[] children = fContentProvider.getChildren(element);
316 if (children != null) {
317 for (Object child : children) {
318 setSubtreeChecked(child, checked);
319 }
320 }
321 }
322
323 /**
324 * Method to finalize the select operation.
325 *
326 * @return <code>true</code> if successful else <code>false</code>
327 */
328 public boolean performFinish() {
329
330 IFolder experiment = fExperiment.getResource();
331
332 final SelectTracesOperation operation = new SelectTracesOperation(experiment, getSelection());
333
334 IStatus status = Status.OK_STATUS;
335 try {
336 getContainer().run(true, true, new IRunnableWithProgress() {
337 @Override
338 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
339 // Wrapper to have only one resource changed event at the
340 // end of the operation.
341 IWorkspaceRunnable workspaceRunnable = new IWorkspaceRunnable() {
342 @Override
343 public void run(IProgressMonitor pm) throws CoreException {
344 operation.run(pm);
345 }
346 };
347
348 IWorkspace workspace = ResourcesPlugin.getWorkspace();
349 try {
350 workspace.run(workspaceRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, monitor);
351 } catch (CoreException e) {
352 throw new InvocationTargetException(e);
353 } finally {
354 monitor.done();
355 }
356 }
357 });
358
359 status = operation.getStatus();
360 } catch (InvocationTargetException e) {
361 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SelectTracesWizardPage_SelectionError, e);
362 } catch (InterruptedException e) {
363 status = Status.CANCEL_STATUS;
364 }
365 if (!status.isOK()) {
366 if (status.getSeverity() == IStatus.CANCEL) {
367 setMessage(Messages.SelectTracesWizardPage_SelectionOperationCancelled);
368 setErrorMessage(null);
369 } else {
370 if (status.getException() != null) {
371 MessageDialog.open(MessageDialog.ERROR, getContainer().getShell(),
372 Messages.SelectTracesWizardPage_InternalErrorTitle, status.getMessage() + ": " + status.getException(), SWT.SHEET); //$NON-NLS-1$
373 }
374 setMessage(null);
375 setErrorMessage(Messages.SelectTracesWizardPage_SelectionError);
376 }
377 return false;
378 }
379 setErrorMessage(null);
380
381 return true;
382 }
383
384 private class SelectTracesOperation {
385
386 IFolder experiment = null;
387 TmfTraceElement[] traces;
388 private IStatus fStatus;
389
390 public SelectTracesOperation(IFolder experiment, @NonNull TmfTraceElement[] traces) {
391 this.experiment = experiment;
392 this.traces = Arrays.copyOf(traces, traces.length);
393 }
394
395 public void run(IProgressMonitor progressMonitor) {
396
397 // Check if operation was cancelled.
398 boolean changed = false;
399
400 // Add the selected traces to the experiment
401 Set<String> keys = fPreviousTraces.keySet();
402 SubMonitor subMonitor = SubMonitor.convert(progressMonitor, traces.length + keys.size());
403 try {
404 for (TmfTraceElement trace : traces) {
405 ModalContext.checkCanceled(progressMonitor);
406 String name = trace.getElementPath();
407 if (keys.contains(name)) {
408 subMonitor.setTaskName(Messages.SelectTracesWizardPage_TraceRemovalTask + " " + trace.getElementPath()); //$NON-NLS-1$
409 fPreviousTraces.remove(name);
410 } else {
411 subMonitor.setTaskName(Messages.SelectTracesWizardPage_TraceSelectionTask + " " + trace.getElementPath()); //$NON-NLS-1$
412 fExperiment.addTrace(trace, false);
413 changed = true;
414 }
415 subMonitor.worked(1);
416 }
417
418 // Remove traces that were unchecked (thus left in
419 // fPreviousTraces)
420 for (Map.Entry<String, TmfTraceElement> entry : fPreviousTraces.entrySet()) {
421 ModalContext.checkCanceled(progressMonitor);
422 TmfTraceElement trace = entry.getValue();
423 subMonitor.setTaskName(Messages.SelectTracesWizardPage_TraceRemovalTask + " " + trace.getElementPath()); //$NON-NLS-1$
424
425 try {
426 fExperiment.removeTrace(trace);
427 } catch (CoreException e) {
428 Activator.getDefault().logError(Messages.SelectTracesWizardPage_SelectionError + " " + experiment.getName(), e); //$NON-NLS-1$
429 }
430 changed = true;
431 subMonitor.worked(1);
432 }
433 if (changed) {
434 Display.getDefault().syncExec(new Runnable() {
435 @Override
436 public void run() {
437 fExperiment.closeEditors();
438 }
439 });
440 fExperiment.deleteSupplementaryResources();
441 }
442 setStatus(Status.OK_STATUS);
443 } catch (InterruptedException e) {
444 setStatus(Status.CANCEL_STATUS);
445 } catch (Exception e) {
446 Activator.getDefault().logError(Messages.SelectTracesWizardPage_SelectionError, e);
447 setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SelectTracesWizardPage_SelectionError, e));
448 }
449 }
450
451 /**
452 * Set the status for this operation
453 *
454 * @param status
455 * the status
456 */
457 protected void setStatus(IStatus status) {
458 fStatus = status;
459 }
460
461 public IStatus getStatus() {
462 return fStatus;
463 }
464
465 }
466
467 /**
468 * Get the list of selected traces
469 */
470 private @NonNull TmfTraceElement[] getSelection() {
471 List<TmfTraceElement> traces = new ArrayList<>();
472 Object[] selection = fCheckboxTreeViewer.getCheckedElements();
473 for (Object sel : selection) {
474 if (sel instanceof TmfTraceElement) {
475 traces.add((TmfTraceElement) sel);
476 }
477 }
478 return traces.toArray(new @NonNull TmfTraceElement[0]);
479 }
480
481 }
This page took 0.04048 seconds and 4 git commands to generate.