1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 Ericsson
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 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.importtrace
;
16 import java
.text
.DecimalFormat
;
17 import java
.util
.concurrent
.ArrayBlockingQueue
;
18 import java
.util
.concurrent
.BlockingQueue
;
20 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
21 import org
.eclipse
.core
.runtime
.IStatus
;
22 import org
.eclipse
.core
.runtime
.Status
;
23 import org
.eclipse
.core
.runtime
.SubMonitor
;
24 import org
.eclipse
.core
.runtime
.jobs
.Job
;
25 import org
.eclipse
.jface
.viewers
.CellEditor
;
26 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
27 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
28 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
29 import org
.eclipse
.jface
.viewers
.ColumnViewer
;
30 import org
.eclipse
.jface
.viewers
.ColumnViewerEditor
;
31 import org
.eclipse
.jface
.viewers
.ColumnViewerEditorActivationStrategy
;
32 import org
.eclipse
.jface
.viewers
.EditingSupport
;
33 import org
.eclipse
.jface
.viewers
.FocusCellOwnerDrawHighlighter
;
34 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
35 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
36 import org
.eclipse
.jface
.viewers
.TextCellEditor
;
37 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
38 import org
.eclipse
.jface
.viewers
.TreeViewerEditor
;
39 import org
.eclipse
.jface
.viewers
.TreeViewerFocusCellManager
;
40 import org
.eclipse
.swt
.SWT
;
41 import org
.eclipse
.swt
.events
.SelectionEvent
;
42 import org
.eclipse
.swt
.events
.SelectionListener
;
43 import org
.eclipse
.swt
.graphics
.Image
;
44 import org
.eclipse
.swt
.layout
.GridData
;
45 import org
.eclipse
.swt
.layout
.GridLayout
;
46 import org
.eclipse
.swt
.widgets
.Button
;
47 import org
.eclipse
.swt
.widgets
.Composite
;
48 import org
.eclipse
.swt
.widgets
.Control
;
49 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
50 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.ITmfImageConstants
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceValidationHelper
;
53 import org
.eclipse
.ui
.IWorkbench
;
56 * <b>Import page that scans files, can be cancelled</b> this page is the third
57 * of three pages shown. This one selects the traces to be imported that are to
60 * @author Matthew Khouzam
62 public class ImportTraceWizardScanPage
extends AbstractImportTraceWizardPage
{
64 private static final int COL_WIDTH
= 200;
65 private static final int MAX_TRACES
= 65536;
66 private CheckboxTreeViewer traceTypeViewer
;
68 final ScanRunnable fRunnable
= new ScanRunnable("Scan job"); //$NON-NLS-1$
69 private final BlockingQueue
<TraceValidationHelper
> fTracesToScan
= new ArrayBlockingQueue
<>(MAX_TRACES
);
70 private volatile boolean fCanRun
= true;
72 // --------------------------------------------------------------------------------
73 // Constructor and destructor
74 // --------------------------------------------------------------------------------
77 * Import page that scans files, can be cancelled.
80 * The name of the page.
82 * The current selection
84 protected ImportTraceWizardScanPage(String name
, IStructuredSelection selection
) {
85 super(name
, selection
);
89 * Import page that scans files, can be cancelled
92 * The workbench reference.
94 * The current selection
96 public ImportTraceWizardScanPage(IWorkbench workbench
, IStructuredSelection selection
) {
97 super(workbench
, selection
);
101 public void dispose() {
103 fRunnable
.done(Status
.OK_STATUS
);
112 public void createControl(Composite parent
) {
113 super.createControl(parent
);
114 final Composite control
= (Composite
) this.getControl();
115 setTitle(Messages
.ImportTraceWizardScanPageTitle
);
116 traceTypeViewer
= new CheckboxTreeViewer(control
, SWT
.CHECK
);
117 traceTypeViewer
.setContentProvider(getBatchWizard().getScannedTraces());
118 traceTypeViewer
.getTree().setHeaderVisible(true);
119 traceTypeViewer
.getControl().setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
120 traceTypeViewer
.setInput(getBatchWizard().getScannedTraces());
121 traceTypeViewer
.addCheckStateListener(new ImportTraceCheckStateListener());
123 TreeViewerFocusCellManager focusCellManager
= new TreeViewerFocusCellManager(traceTypeViewer
, new FocusCellOwnerDrawHighlighter(traceTypeViewer
));
124 ColumnViewerEditorActivationStrategy actSupport
= new ColumnViewerEditorActivationStrategy(traceTypeViewer
) {
126 TreeViewerEditor
.create(traceTypeViewer
, focusCellManager
, actSupport
, ColumnViewerEditor
.TABBING_HORIZONTAL
127 | ColumnViewerEditor
.TABBING_MOVE_TO_ROW_NEIGHBOR
128 | ColumnViewerEditor
.TABBING_VERTICAL
| ColumnViewerEditor
.KEYBOARD_ACTIVATION
);
130 final TextCellEditor textCellEditor
= new TextCellEditor(traceTypeViewer
.getTree());
131 // --------------------
133 // --------------------
134 TreeViewerColumn column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
135 column
.getColumn().setWidth(COL_WIDTH
);
136 column
.getColumn().setText(Messages
.ImportTraceWizardTraceDisplayName
);
137 column
.setLabelProvider(new FirstColumnLabelProvider());
138 column
.setEditingSupport(new ColumnEditorSupport(traceTypeViewer
, textCellEditor
));
140 // --------------------
142 // --------------------
144 column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
145 column
.getColumn().setWidth(500);
146 column
.getColumn().setText(Messages
.ImportTraceWizardImportCaption
);
147 column
.setLabelProvider(new ColumnLabelProvider() {
149 public String
getText(Object element
) {
150 if (element
instanceof FileAndName
) {
151 FileAndName elem
= (FileAndName
) element
;
152 return elem
.getFile().getPath();
157 // --------------------
159 // --------------------
161 column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
163 column
.getColumn().setWidth(80);
164 column
.getColumn().setText(Messages
.ImportTraceWizardScanPageSize
);
165 column
.getColumn().setAlignment(SWT
.RIGHT
);
166 column
.setLabelProvider(new ColumnLabelProvider() {
169 public String
getText(Object element
) {
170 if (element
instanceof FileAndName
) {
172 FileAndName elem
= (FileAndName
) element
;
173 long len
= recurseSize(elem
.getFile());
175 double sizeb10
= Math
.log10(len
);
176 DecimalFormat df
= new DecimalFormat();
177 df
.setMaximumFractionDigits(2);
178 df
.setMinimumFractionDigits(0);
180 final double tbSize
= len
/ 1024.0 / 1024 / 1024 / 1024;
181 return df
.format(tbSize
) + Messages
.ImportTraceWizardScanPageTerabyte
;
184 final double gbSize
= len
/ 1024.0 / 1024 / 1024;
185 return df
.format(gbSize
) + Messages
.ImportTraceWizardScanPageGigabyte
;
188 final double mbSize
= len
/ 1024.0 / 1024;
189 return df
.format(mbSize
) + Messages
.ImportTraceWizardScanPageMegabyte
;
192 final double kbSize
= len
/ 1024.0;
193 return df
.format(kbSize
) + Messages
.ImportTraceWizardScanPageKilobyte
;
196 return Long
.toString(len
) + Messages
.ImportTraceWizardScanPagebyte
;
202 private long recurseSize(File file
) {
203 if (file
.isFile() && file
.canRead()) {
204 return file
.length();
207 if (file
.exists() && file
.isDirectory() && file
.canRead()) {
208 final File
[] listFiles
= file
.listFiles();
209 if (listFiles
!= null) {
210 for (File child
: listFiles
) {
211 if (child
.isFile() && child
.canRead()) {
212 size
+= child
.length();
213 } else if (child
.isDirectory()) {
214 size
+= recurseSize(child
);
216 Activator
.getDefault().logError("Unknown \"file\" type for " + child
+ ' ' + child
.toString()); //$NON-NLS-1$
226 getBatchWizard().setTracesToScan(fTracesToScan
);
227 getBatchWizard().setTraceFolder(fTargetFolder
);
229 fRunnable
.schedule();
230 setErrorMessage(Messages
.ImportTraceWizardScanPageSelectAtleastOne
);
233 private void init() {
234 Composite optionPane
= (Composite
) this.getControl();
236 optionPane
.setLayout(new GridLayout());
237 optionPane
.setLayoutData(new GridData(SWT
.LEFT
, SWT
.TOP
, true, true));
239 final Button fLink
= new Button(optionPane
, SWT
.RADIO
);
240 fLink
.setText(Messages
.ImportTraceWizardLinkTraces
);
241 fLink
.setSelection(true);
242 fLink
.setLayoutData(new GridData());
244 final Button fCopy
= new Button(optionPane
, SWT
.RADIO
);
245 fCopy
.setText(Messages
.ImportTraceWizardCopyTraces
);
246 fCopy
.setLayoutData(new GridData());
248 final SelectionListener linkedListener
= new RadioChooser(fLink
);
250 fLink
.addSelectionListener(linkedListener
);
251 fCopy
.addSelectionListener(linkedListener
);
253 Button fOverwrite
= new Button(optionPane
, SWT
.CHECK
);
254 fOverwrite
.setText(Messages
.ImportTraceWizardOverwriteTraces
);
255 fOverwrite
.setLayoutData(new GridData());
256 fOverwrite
.setSelection(true);
257 fOverwrite
.addSelectionListener(new SelectionListener() {
260 public void widgetSelected(SelectionEvent e
) {
261 getBatchWizard().setOverwrite(((Button
) e
.widget
).getSelection());
265 public void widgetDefaultSelected(SelectionEvent e
) {
274 private final class RadioChooser
implements SelectionListener
{
275 private final Button isLinked
;
277 public RadioChooser(Button desiredButton
) {
278 isLinked
= desiredButton
;
282 public void widgetSelected(SelectionEvent e
) {
284 final Button widget
= (Button
) e
.widget
;
285 getBatchWizard().setLinked(widget
.equals(isLinked
));
289 public void widgetDefaultSelected(SelectionEvent e
) {
294 private final class ColumnEditorSupport
extends EditingSupport
{
295 private final TextCellEditor textCellEditor
;
297 private ColumnEditorSupport(ColumnViewer viewer
, TextCellEditor textCellEditor
) {
299 this.textCellEditor
= textCellEditor
;
303 protected boolean canEdit(Object element
) {
304 return element
instanceof FileAndName
;
308 protected CellEditor
getCellEditor(Object element
) {
309 return textCellEditor
;
313 protected Object
getValue(Object element
) {
314 if (element
instanceof FileAndName
) {
315 return ((FileAndName
) element
).getName();
321 protected void setValue(Object element
, Object value
) {
322 FileAndName fan
= (FileAndName
) element
;
323 fan
.setName((String
) value
);
324 getBatchWizard().updateConflicts();
325 traceTypeViewer
.update(element
, null);
326 traceTypeViewer
.refresh();
330 private final class FirstColumnLabelProvider
extends ColumnLabelProvider
{
334 public Image
getImage(Object element
) {
335 if (element
instanceof FileAndName
) {
336 final FileAndName fan
= (FileAndName
) element
;
337 if (fan
.isConflictingName()) {
338 if (fConflict
== null) {
339 fConflict
= Activator
.getDefault().getImageFromImageRegistry(ITmfImageConstants
.IMG_UI_CONFLICT
);
348 public String
getText(Object element
) {
349 if (element
instanceof FileAndName
) {
350 FileAndName elem
= (FileAndName
) element
;
351 return elem
.getName();
353 if (element
instanceof String
) {
354 return (String
) element
;
360 private final class ImportTraceCheckStateListener
implements ICheckStateListener
{
362 public void checkStateChanged(CheckStateChangedEvent event
) {
363 final CheckboxTreeViewer tv
= (CheckboxTreeViewer
)
365 if (event
.getElement() instanceof FileAndName
) {
366 final FileAndName element
= (FileAndName
) event
.getElement();
367 if (event
.getChecked()) {
368 getBatchWizard().addFileToImport(element
);
369 traceTypeViewer
.update(element
, null);
372 getBatchWizard().removeFileToImport(element
);
373 traceTypeViewer
.update(element
, null);
375 maintainCheckIntegrity(tv
, element
);
377 if (event
.getElement() instanceof String
) {
379 tv
.setSubtreeChecked(event
.getElement(), event
.getChecked());
380 final Object
[] children
=
381 getBatchWizard().getScannedTraces().getChildren(event
.getElement());
382 if (event
.getChecked()) {
383 for (int i
= 0; i
< children
.length
; i
++) {
384 final FileAndName element
= (FileAndName
) children
[i
];
385 getBatchWizard().addFileToImport(element
);
386 traceTypeViewer
.update(children
[i
], null);
390 for (int i
= 0; i
< children
.length
; i
++) {
391 getBatchWizard().removeFileToImport((FileAndName
) children
[i
]);
397 getBatchWizard().updateConflicts();
398 if (getBatchWizard().hasConflicts()) {
399 setErrorMessage(Messages
.ImportTraceWizardScanPageRenameError
);
400 } else if (!getBatchWizard().hasTracesToImport()) {
401 setErrorMessage(Messages
.ImportTraceWizardScanPageSelectAtleastOne
);
403 setErrorMessage(null);
405 getWizard().getContainer().updateButtons();
406 traceTypeViewer
.update(event
.getElement(), null);
409 private void maintainCheckIntegrity(final CheckboxTreeViewer viewer
, final FileAndName element
) {
410 final ImportTraceContentProvider scannedTraces
= getBatchWizard().getScannedTraces();
411 String parentElement
= (String
) scannedTraces
.getParent(element
);
412 boolean allChecked
= true;
413 final FileAndName
[] siblings
= scannedTraces
.getSiblings(element
);
414 if (siblings
!= null) {
415 for (FileAndName child
: siblings
) {
416 allChecked
&= viewer
.getChecked(child
);
419 viewer
.setChecked(parentElement
, allChecked
);
423 private final class ScanRunnable
extends Job
{
425 // monitor is stored here, starts as the main monitor but becomes a
427 private IProgressMonitor fMonitor
;
429 public ScanRunnable(String name
) {
431 this.setSystem(true);
434 private synchronized IProgressMonitor
getMonitor() {
439 public IStatus
run(IProgressMonitor monitor
) {
441 * Set up phase, it is synchronous
444 final Control control
= traceTypeViewer
.getControl();
445 // please note the sync exec here is to allow us to set
446 control
.getDisplay().syncExec(new Runnable() {
449 // monitor gets overwritten here so it's necessary to save
451 fMonitor
= SubMonitor
.convert(getMonitor());
452 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
453 ((SubMonitor
) getMonitor()).setWorkRemaining(IProgressMonitor
.UNKNOWN
);
457 * At this point we start calling async execs and updating the view.
458 * This is a good candidate to parallelise.
460 while (fCanRun
== true) {
461 boolean updated
= false;
463 if (fTracesToScan
.isEmpty() && !control
.isDisposed()) {
464 control
.getDisplay().asyncExec(new Runnable() {
468 if (!control
.isDisposed()) {
469 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
470 getMonitor().subTask(Messages
.ImportTraceWizardPageScanDone
);
471 ImportTraceWizardScanPage
.this.setMessage(Messages
.ImportTraceWizardPageScanScanning
+ ' ' + Messages
.ImportTraceWizardPageScanDone
);
477 final TraceValidationHelper traceToScan
= fTracesToScan
.take();
479 if (!getBatchWizard().hasScanned(traceToScan
)) {
480 getBatchWizard().addResult(traceToScan
, TmfTraceType
.validate(traceToScan
));
484 * The following is to update the UI
486 validCombo
= getBatchWizard().getResult(traceToScan
);
488 // Synched on it's parent
490 getBatchWizard().getScannedTraces().addCandidate(traceToScan
.getTraceType(), new File(traceToScan
.getTraceToScan()));
493 final int scanned
= getBatchWizard().getNumberOfResults();
494 final int total
= scanned
+ fTracesToScan
.size();
495 final int prevVal
= (int) ((scanned
- 1) * 100.0 / total
);
496 final int curVal
= (int) ((scanned
) * 100.0 / total
);
497 if (curVal
!= prevVal
) {
501 * update the progress
504 if (!control
.isDisposed()) {
505 control
.getDisplay().asyncExec(new Runnable() {
508 if (!control
.isDisposed()) {
509 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
510 getMonitor().subTask(traceToScan
.getTraceToScan());
511 getMonitor().worked(1);
512 ImportTraceWizardScanPage
.this.setMessage(Messages
.ImportTraceWizardPageScanScanning
+ ' '
513 + Integer
.toString(curVal
)
523 * here we update the table
525 final boolean editing
= traceTypeViewer
.isCellEditorActive();
526 if (updated
&& !editing
) {
527 if (!control
.isDisposed()) {
528 control
.getDisplay().asyncExec(new Runnable() {
532 if (!control
.isDisposed()) {
533 if (!traceTypeViewer
.isCellEditorActive()) {
534 traceTypeViewer
.refresh();
541 } catch (InterruptedException e
) {
542 return new Status(IStatus
.CANCEL
, Activator
.PLUGIN_ID
, new String());
545 return Status
.OK_STATUS
;
550 * Refresh the view and the corresponding model.
552 public void refresh() {
553 final Control control
= traceTypeViewer
.getControl();
554 if (!control
.isDisposed()) {
555 control
.getDisplay().asyncExec(new Runnable() {
558 if (!control
.isDisposed()) {
559 traceTypeViewer
.refresh();