1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 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
.linuxtools
.tmf
.ui
.project
.wizards
;
18 import java
.lang
.reflect
.InvocationTargetException
;
19 import java
.util
.ArrayList
;
20 import java
.util
.HashMap
;
21 import java
.util
.List
;
24 import java
.util
.Vector
;
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
.jface
.dialogs
.MessageDialog
;
36 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
37 import org
.eclipse
.jface
.operation
.ModalContext
;
38 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
39 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
40 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
41 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
42 import org
.eclipse
.jface
.viewers
.TreeViewer
;
43 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
44 import org
.eclipse
.jface
.viewers
.ViewerSorter
;
45 import org
.eclipse
.jface
.wizard
.WizardPage
;
46 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
48 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.ITmfProjectModelElement
;
49 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfExperimentElement
;
50 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfNavigatorContentProvider
;
51 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfNavigatorLabelProvider
;
52 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectElement
;
53 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceElement
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
55 import org
.eclipse
.swt
.SWT
;
56 import org
.eclipse
.swt
.events
.SelectionAdapter
;
57 import org
.eclipse
.swt
.events
.SelectionEvent
;
58 import org
.eclipse
.swt
.graphics
.Image
;
59 import org
.eclipse
.swt
.layout
.FillLayout
;
60 import org
.eclipse
.swt
.layout
.GridData
;
61 import org
.eclipse
.swt
.layout
.GridLayout
;
62 import org
.eclipse
.swt
.widgets
.Button
;
63 import org
.eclipse
.swt
.widgets
.Composite
;
64 import org
.eclipse
.swt
.widgets
.Tree
;
65 import org
.eclipse
.ui
.dialogs
.FilteredTree
;
66 import org
.eclipse
.ui
.dialogs
.PatternFilter
;
69 * Implementation of a wizard page for selecting trace for an experiment.
73 * @author Francois Chouinard
75 public class SelectTracesWizardPage
extends WizardPage
{
77 // ------------------------------------------------------------------------
79 // ------------------------------------------------------------------------
81 private final TmfProjectElement fProject
;
82 private final TmfExperimentElement fExperiment
;
83 private Map
<String
, TmfTraceElement
> fPreviousTraces
;
84 private CheckboxTreeViewer fCheckboxTreeViewer
;
85 private TmfNavigatorContentProvider fContentProvider
;
86 private TmfNavigatorLabelProvider fLabelProvider
;
88 private static final int COLUMN_WIDTH
= 200;
89 private static final int BUTTON_SPACING
= 4;
91 // ------------------------------------------------------------------------
93 // ------------------------------------------------------------------------
98 * The project model element.
100 * The experiment model experiment.
102 protected SelectTracesWizardPage(TmfProjectElement project
, TmfExperimentElement experiment
) {
103 super(""); //$NON-NLS-1$
104 setTitle(Messages
.SelectTracesWizardPage_WindowTitle
);
105 setDescription(Messages
.SelectTracesWizardPage_Description
);
107 fExperiment
= experiment
;
110 // ------------------------------------------------------------------------
112 // ------------------------------------------------------------------------
115 public void createControl(Composite parent
) {
116 Composite container
= new Composite(parent
, SWT
.NULL
);
117 container
.setLayout(new GridLayout(2, false));
118 setControl(container
);
120 new FilteredTree(container
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.BORDER
, new PatternFilter(), true) {
122 protected TreeViewer
doCreateTreeViewer(Composite aparent
, int style
) {
123 return SelectTracesWizardPage
.this.doCreateTreeViewer(aparent
);
127 Composite buttonComposite
= new Composite(container
, SWT
.NONE
);
128 FillLayout layout
= new FillLayout(SWT
.VERTICAL
);
129 layout
.spacing
= BUTTON_SPACING
;
130 buttonComposite
.setLayout(layout
);
131 GridData gd
= new GridData();
132 gd
.verticalAlignment
= SWT
.CENTER
;
133 buttonComposite
.setLayoutData(gd
);
135 Button selectAllButton
= new Button(buttonComposite
, SWT
.PUSH
);
136 selectAllButton
.setText(org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.dialogs
.Messages
.Dialog_SelectAll
);
137 selectAllButton
.addSelectionListener(new SelectionAdapter() {
139 public void widgetSelected(SelectionEvent e
) {
144 Button deselectAllButton
= new Button(buttonComposite
, SWT
.PUSH
);
145 deselectAllButton
.setText(org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.dialogs
.Messages
.Dialog_DeselectAll
);
146 deselectAllButton
.addSelectionListener(new SelectionAdapter() {
148 public void widgetSelected(SelectionEvent e
) {
149 setAllChecked(false);
154 private TreeViewer
doCreateTreeViewer(Composite parent
) {
155 fCheckboxTreeViewer
= new CheckboxTreeViewer(parent
, SWT
.BORDER
);
156 fContentProvider
= new TmfNavigatorContentProvider() {
159 public Object
[] getElements(Object inputElement
) {
160 return getChildren(inputElement
);
164 public synchronized Object
[] getChildren(Object parentElement
) {
165 // We only care about the content of trace folders
166 if (parentElement
instanceof TmfTraceFolder
) {
167 Object
[] children
= super.getChildren(parentElement
);
168 List
<ITmfProjectModelElement
> filteredChildren
= new ArrayList
<>();
169 for (Object child
: children
) {
170 if (child
instanceof TmfTraceElement
) {
171 TmfTraceElement traceElement
= (TmfTraceElement
) child
;
172 String traceType
= traceElement
.getTraceType();
173 if (traceType
!= null && TmfTraceType
.getTraceType(traceType
) != null) {
174 filteredChildren
.add(traceElement
);
176 } else if (child
instanceof TmfTraceFolder
) {
177 filteredChildren
.add((TmfTraceFolder
) child
);
180 return filteredChildren
.toArray();
186 public boolean hasChildren(Object element
) {
187 Object
[] children
= getChildren(element
);
188 return children
!= null && children
.length
> 0;
191 fCheckboxTreeViewer
.setContentProvider(fContentProvider
);
192 fLabelProvider
= new TmfNavigatorLabelProvider();
193 fCheckboxTreeViewer
.setLabelProvider(fLabelProvider
);
194 fCheckboxTreeViewer
.setSorter(new ViewerSorter());
196 final Tree tree
= fCheckboxTreeViewer
.getTree();
197 GridData gd
= new GridData(SWT
.FILL
, SWT
.FILL
, true, true);
198 tree
.setLayoutData(gd
);
199 tree
.setHeaderVisible(true);
201 final TreeViewerColumn column
= new TreeViewerColumn(fCheckboxTreeViewer
, SWT
.NONE
);
202 column
.getColumn().setWidth(COLUMN_WIDTH
);
203 column
.getColumn().setText(Messages
.SelectTracesWizardPage_TraceColumnHeader
);
204 column
.setLabelProvider(new ColumnLabelProvider() {
206 public String
getText(Object element
) {
207 return fLabelProvider
.getText(element
);
211 public Image
getImage(Object element
) {
212 return fLabelProvider
.getImage(element
);
216 // Get the list of traces already part of the experiment
217 fPreviousTraces
= new HashMap
<>();
218 for (ITmfProjectModelElement child
: fExperiment
.getChildren()) {
219 if (child
instanceof TmfTraceElement
) {
220 TmfTraceElement trace
= (TmfTraceElement
) child
;
221 String name
= trace
.getElementPath();
222 fPreviousTraces
.put(name
, trace
);
226 // Populate the list of traces to choose from
227 Set
<String
> keys
= fPreviousTraces
.keySet();
228 TmfTraceFolder traceFolder
= fProject
.getTracesFolder();
229 fCheckboxTreeViewer
.setInput(traceFolder
);
231 // Set the checkbox for the traces already included
232 setCheckedAlreadyIncludedTraces(keys
, fContentProvider
.getElements(fCheckboxTreeViewer
.getInput()));
234 fCheckboxTreeViewer
.addCheckStateListener(new ICheckStateListener() {
236 public void checkStateChanged(CheckStateChangedEvent event
) {
237 Object element
= event
.getElement();
238 setSubtreeChecked(element
, event
.getChecked());
239 maintainCheckIntegrity(element
);
243 return fCheckboxTreeViewer
;
246 private void maintainCheckIntegrity(final Object element
) {
247 Object parentElement
= fContentProvider
.getParent(element
);
248 boolean allChecked
= true;
249 boolean oneChecked
= false;
250 boolean oneGrayed
= false;
251 if (parentElement
!= null) {
252 if (fContentProvider
.getChildren(parentElement
) != null) {
253 for (Object child
: fContentProvider
.getChildren(parentElement
)) {
254 boolean checked
= fCheckboxTreeViewer
.getChecked(child
);
255 oneChecked
|= checked
;
256 allChecked
&= checked
;
257 oneGrayed
|= fCheckboxTreeViewer
.getGrayed(child
);
260 if (oneGrayed
|| oneChecked
&& !allChecked
) {
261 fCheckboxTreeViewer
.setGrayChecked(parentElement
, true);
263 fCheckboxTreeViewer
.setGrayed(parentElement
, false);
264 fCheckboxTreeViewer
.setChecked(parentElement
, allChecked
);
266 maintainCheckIntegrity(parentElement
);
270 private void setCheckedAlreadyIncludedTraces(Set
<String
> alreadyIncludedTraces
, Object
[] elements
) {
271 for (Object element
: elements
) {
272 if (element
instanceof TmfTraceElement
) {
273 TmfTraceElement trace
= (TmfTraceElement
) element
;
274 String elementPath
= trace
.getElementPath();
275 if (alreadyIncludedTraces
.contains(elementPath
)) {
276 fCheckboxTreeViewer
.setChecked(element
, true);
277 maintainCheckIntegrity(element
);
280 Object
[] children
= fContentProvider
.getChildren(element
);
281 if (children
!= null) {
282 setCheckedAlreadyIncludedTraces(alreadyIncludedTraces
, children
);
288 * Sets all items in the element viewer to be checked or unchecked
291 * whether or not items should be checked
293 private void setAllChecked(boolean checked
) {
294 for (Object element
: fContentProvider
.getChildren(fCheckboxTreeViewer
.getInput())) {
295 setSubtreeChecked(element
, checked
);
300 * A version of setSubtreeChecked that also handles the grayed state
305 * true if the item should be checked, and false if it should be
308 private void setSubtreeChecked(Object element
, boolean checked
) {
309 fCheckboxTreeViewer
.setChecked(element
, checked
);
311 fCheckboxTreeViewer
.setGrayed(element
, false);
313 Object
[] children
= fContentProvider
.getChildren(element
);
314 if (children
!= null) {
315 for (Object child
: children
) {
316 setSubtreeChecked(child
, checked
);
322 * Method to finalize the select operation.
324 * @return <code>true</code> if successful else <code>false</code>
326 public boolean performFinish() {
328 IFolder experiment
= fExperiment
.getResource();
330 final SelectTracesOperation operation
= new SelectTracesOperation(experiment
, getSelection());
332 IStatus status
= Status
.OK_STATUS
;
334 getContainer().run(true, true, new IRunnableWithProgress() {
336 public void run(IProgressMonitor monitor
) throws InvocationTargetException
, InterruptedException
{
337 // Wrapper to have only one resource changed event at the
338 // end of the operation.
339 IWorkspaceRunnable workspaceRunnable
= new IWorkspaceRunnable() {
341 public void run(IProgressMonitor pm
) throws CoreException
{
346 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
348 workspace
.run(workspaceRunnable
, workspace
.getRoot(), IWorkspace
.AVOID_UPDATE
, monitor
);
349 } catch (CoreException e
) {
350 throw new InvocationTargetException(e
);
357 status
= operation
.getStatus();
358 } catch (InvocationTargetException e
) {
359 status
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.SelectTracesWizardPage_SelectionError
, e
);
360 } catch (InterruptedException e
) {
361 status
= Status
.CANCEL_STATUS
;
363 if (!status
.isOK()) {
364 if (status
.getSeverity() == IStatus
.CANCEL
) {
365 setMessage(Messages
.SelectTracesWizardPage_SelectionOperationCancelled
);
366 setErrorMessage(null);
368 if (status
.getException() != null) {
369 MessageDialog
.open(MessageDialog
.ERROR
, getContainer().getShell(),
370 Messages
.SelectTracesWizardPage_InternalErrorTitle
, status
.getMessage() + ": " + status
.getException(), SWT
.SHEET
); //$NON-NLS-1$
373 setErrorMessage(Messages
.SelectTracesWizardPage_SelectionError
);
377 setErrorMessage(null);
382 private class SelectTracesOperation
{
384 IFolder experiment
= null;
385 TmfTraceElement
[] traces
;
386 private IStatus fStatus
;
388 public SelectTracesOperation(IFolder experiment
, TmfTraceElement
[] traces
) {
389 this.experiment
= experiment
;
390 this.traces
= traces
;
393 public void run(IProgressMonitor progressMonitor
) {
395 // Check if operation was cancelled.
396 boolean changed
= false;
398 // Add the selected traces to the experiment
399 Set
<String
> keys
= fPreviousTraces
.keySet();
400 SubMonitor subMonitor
= SubMonitor
.convert(progressMonitor
, traces
.length
+ keys
.size());
402 for (TmfTraceElement trace
: traces
) {
403 ModalContext
.checkCanceled(progressMonitor
);
404 String name
= trace
.getElementPath();
405 if (keys
.contains(name
)) {
406 subMonitor
.setTaskName(Messages
.SelectTracesWizardPage_TraceRemovalTask
+ " " + trace
.getElementPath()); //$NON-NLS-1$
407 fPreviousTraces
.remove(name
);
409 subMonitor
.setTaskName(Messages
.SelectTracesWizardPage_TraceSelectionTask
+ " " + trace
.getElementPath()); //$NON-NLS-1$
410 fExperiment
.addTrace(trace
, false);
413 subMonitor
.worked(1);
416 // Remove traces that were unchecked (thus left in
418 keys
= fPreviousTraces
.keySet();
419 for (String key
: keys
) {
420 ModalContext
.checkCanceled(progressMonitor
);
421 TmfTraceElement trace
= fPreviousTraces
.get(key
);
422 subMonitor
.setTaskName(Messages
.SelectTracesWizardPage_TraceRemovalTask
+ " " + trace
.getElementPath()); //$NON-NLS-1$
425 fExperiment
.removeTrace(trace
);
426 } catch (CoreException e
) {
427 Activator
.getDefault().logError(Messages
.SelectTracesWizardPage_SelectionError
+ " " + experiment
.getName(), e
); //$NON-NLS-1$
430 subMonitor
.worked(1);
433 fExperiment
.closeEditors();
434 fExperiment
.deleteSupplementaryResources();
436 setStatus(Status
.OK_STATUS
);
437 } catch (InterruptedException e
) {
438 setStatus(Status
.CANCEL_STATUS
);
439 } catch (Exception e
) {
440 Activator
.getDefault().logError(Messages
.SelectTracesWizardPage_SelectionError
, e
);
441 setStatus(new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.SelectTracesWizardPage_SelectionError
, e
));
446 * Set the status for this operation
451 protected void setStatus(IStatus status
) {
455 public IStatus
getStatus() {
462 * Get the list of selected traces
464 private TmfTraceElement
[] getSelection() {
465 Vector
<TmfTraceElement
> traces
= new Vector
<>();
466 Object
[] selection
= fCheckboxTreeViewer
.getCheckedElements();
467 for (Object sel
: selection
) {
468 if (sel
instanceof TmfTraceElement
) {
469 traces
.add((TmfTraceElement
) sel
);
472 TmfTraceElement
[] result
= new TmfTraceElement
[traces
.size()];
473 traces
.toArray(result
);