1 /*******************************************************************************
2 * Copyright (c) 2009, 2015 Ericsson, École Polytechnique de Montréal
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
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 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.ui
.project
.wizards
;
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
;
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
.ViewerSorter
;
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
;
71 * Implementation of a wizard page for selecting trace for an experiment.
75 * @author Francois Chouinard
77 public class SelectTracesWizardPage
extends WizardPage
{
79 // ------------------------------------------------------------------------
81 // ------------------------------------------------------------------------
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
;
90 private static final int COLUMN_WIDTH
= 200;
91 private static final int BUTTON_SPACING
= 4;
93 // ------------------------------------------------------------------------
95 // ------------------------------------------------------------------------
100 * The project model element.
102 * The experiment model experiment.
104 protected SelectTracesWizardPage(TmfProjectElement project
, TmfExperimentElement experiment
) {
105 super(""); //$NON-NLS-1$
106 setTitle(Messages
.SelectTracesWizardPage_WindowTitle
);
107 setDescription(Messages
.SelectTracesWizardPage_Description
);
109 fExperiment
= experiment
;
112 // ------------------------------------------------------------------------
114 // ------------------------------------------------------------------------
117 public void createControl(Composite parent
) {
118 Composite container
= new Composite(parent
, SWT
.NULL
);
119 container
.setLayout(new GridLayout(2, false));
120 setControl(container
);
122 new FilteredTree(container
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.BORDER
, new PatternFilter(), true) {
124 protected TreeViewer
doCreateTreeViewer(Composite aparent
, int style
) {
125 return SelectTracesWizardPage
.this.doCreateTreeViewer(aparent
);
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
);
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() {
141 public void widgetSelected(SelectionEvent e
) {
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() {
150 public void widgetSelected(SelectionEvent e
) {
151 setAllChecked(false);
156 private TreeViewer
doCreateTreeViewer(Composite parent
) {
157 fCheckboxTreeViewer
= new CheckboxTreeViewer(parent
, SWT
.BORDER
);
158 fContentProvider
= new TmfNavigatorContentProvider() {
161 public Object
[] getElements(Object inputElement
) {
162 return getChildren(inputElement
);
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
);
178 } else if (child
instanceof TmfTraceFolder
) {
179 filteredChildren
.add((TmfTraceFolder
) child
);
182 return filteredChildren
.toArray();
188 public boolean hasChildren(Object element
) {
189 Object
[] children
= getChildren(element
);
190 return children
!= null && children
.length
> 0;
193 fCheckboxTreeViewer
.setContentProvider(fContentProvider
);
194 fLabelProvider
= new TmfNavigatorLabelProvider();
195 fCheckboxTreeViewer
.setLabelProvider(fLabelProvider
);
196 fCheckboxTreeViewer
.setSorter(new ViewerSorter());
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);
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() {
208 public String
getText(Object element
) {
209 return fLabelProvider
.getText(element
);
213 public Image
getImage(Object element
) {
214 return fLabelProvider
.getImage(element
);
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
);
228 // Populate the list of traces to choose from
229 Set
<String
> keys
= fPreviousTraces
.keySet();
230 TmfTraceFolder traceFolder
= fProject
.getTracesFolder();
231 fCheckboxTreeViewer
.setInput(traceFolder
);
233 // Set the checkbox for the traces already included
234 setCheckedAlreadyIncludedTraces(keys
, fContentProvider
.getElements(fCheckboxTreeViewer
.getInput()));
236 fCheckboxTreeViewer
.addCheckStateListener(new ICheckStateListener() {
238 public void checkStateChanged(CheckStateChangedEvent event
) {
239 Object element
= event
.getElement();
240 setSubtreeChecked(element
, event
.getChecked());
241 maintainCheckIntegrity(element
);
245 return fCheckboxTreeViewer
;
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
);
262 if (oneGrayed
|| oneChecked
&& !allChecked
) {
263 fCheckboxTreeViewer
.setGrayChecked(parentElement
, true);
265 fCheckboxTreeViewer
.setGrayed(parentElement
, false);
266 fCheckboxTreeViewer
.setChecked(parentElement
, allChecked
);
268 maintainCheckIntegrity(parentElement
);
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
);
282 Object
[] children
= fContentProvider
.getChildren(element
);
283 if (children
!= null) {
284 setCheckedAlreadyIncludedTraces(alreadyIncludedTraces
, children
);
290 * Sets all items in the element viewer to be checked or unchecked
293 * whether or not items should be checked
295 private void setAllChecked(boolean checked
) {
296 for (Object element
: fContentProvider
.getChildren(fCheckboxTreeViewer
.getInput())) {
297 setSubtreeChecked(element
, checked
);
302 * A version of setSubtreeChecked that also handles the grayed state
307 * true if the item should be checked, and false if it should be
310 private void setSubtreeChecked(Object element
, boolean checked
) {
311 fCheckboxTreeViewer
.setChecked(element
, checked
);
313 fCheckboxTreeViewer
.setGrayed(element
, false);
315 Object
[] children
= fContentProvider
.getChildren(element
);
316 if (children
!= null) {
317 for (Object child
: children
) {
318 setSubtreeChecked(child
, checked
);
324 * Method to finalize the select operation.
326 * @return <code>true</code> if successful else <code>false</code>
328 public boolean performFinish() {
330 IFolder experiment
= fExperiment
.getResource();
332 final SelectTracesOperation operation
= new SelectTracesOperation(experiment
, getSelection());
334 IStatus status
= Status
.OK_STATUS
;
336 getContainer().run(true, true, new IRunnableWithProgress() {
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() {
343 public void run(IProgressMonitor pm
) throws CoreException
{
348 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
350 workspace
.run(workspaceRunnable
, workspace
.getRoot(), IWorkspace
.AVOID_UPDATE
, monitor
);
351 } catch (CoreException e
) {
352 throw new InvocationTargetException(e
);
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
;
365 if (!status
.isOK()) {
366 if (status
.getSeverity() == IStatus
.CANCEL
) {
367 setMessage(Messages
.SelectTracesWizardPage_SelectionOperationCancelled
);
368 setErrorMessage(null);
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$
375 setErrorMessage(Messages
.SelectTracesWizardPage_SelectionError
);
379 setErrorMessage(null);
384 private class SelectTracesOperation
{
386 IFolder experiment
= null;
387 TmfTraceElement
[] traces
;
388 private IStatus fStatus
;
390 public SelectTracesOperation(IFolder experiment
, @NonNull TmfTraceElement
[] traces
) {
391 this.experiment
= experiment
;
392 this.traces
= Arrays
.copyOf(traces
, traces
.length
);
395 public void run(IProgressMonitor progressMonitor
) {
397 // Check if operation was cancelled.
398 boolean changed
= false;
400 // Add the selected traces to the experiment
401 Set
<String
> keys
= fPreviousTraces
.keySet();
402 SubMonitor subMonitor
= SubMonitor
.convert(progressMonitor
, traces
.length
+ keys
.size());
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
);
411 subMonitor
.setTaskName(Messages
.SelectTracesWizardPage_TraceSelectionTask
+ " " + trace
.getElementPath()); //$NON-NLS-1$
412 fExperiment
.addTrace(trace
, false);
415 subMonitor
.worked(1);
418 // Remove traces that were unchecked (thus left in
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$
426 fExperiment
.removeTrace(trace
);
427 } catch (CoreException e
) {
428 Activator
.getDefault().logError(Messages
.SelectTracesWizardPage_SelectionError
+ " " + experiment
.getName(), e
); //$NON-NLS-1$
431 subMonitor
.worked(1);
434 Display
.getDefault().syncExec(new Runnable() {
437 fExperiment
.closeEditors();
440 fExperiment
.deleteSupplementaryResources();
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
));
452 * Set the status for this operation
457 protected void setStatus(IStatus status
) {
461 public IStatus
getStatus() {
468 * Get the list of selected traces
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
);
478 return traces
.toArray(new @NonNull TmfTraceElement
[0]);