1 /*******************************************************************************
2 * Copyright (c) 2013 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
.linuxtools
.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
.linuxtools
.internal
.tmf
.ui
.Activator
;
41 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.ITmfImageConstants
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceValidationHelper
;
44 import org
.eclipse
.swt
.SWT
;
45 import org
.eclipse
.swt
.events
.SelectionEvent
;
46 import org
.eclipse
.swt
.events
.SelectionListener
;
47 import org
.eclipse
.swt
.graphics
.Image
;
48 import org
.eclipse
.swt
.layout
.GridData
;
49 import org
.eclipse
.swt
.layout
.GridLayout
;
50 import org
.eclipse
.swt
.widgets
.Button
;
51 import org
.eclipse
.swt
.widgets
.Composite
;
52 import org
.eclipse
.swt
.widgets
.Control
;
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
63 public class ImportTraceWizardScanPage
extends AbstractImportTraceWizardPage
{
65 private static final int COL_WIDTH
= 200;
66 private static final int MAX_TRACES
= 65536;
67 private CheckboxTreeViewer traceTypeViewer
;
69 final ScanRunnable fRunnable
= new ScanRunnable("Scan job"); //$NON-NLS-1$
70 final private BlockingQueue
<TraceValidationHelper
> fTracesToScan
= new ArrayBlockingQueue
<>(MAX_TRACES
);
71 private volatile boolean fCanRun
= true;
73 // --------------------------------------------------------------------------------
74 // Constructor and destructor
75 // --------------------------------------------------------------------------------
78 * Import page that scans files, can be cancelled.
81 * The name of the page.
83 * The current selection
85 protected ImportTraceWizardScanPage(String name
, IStructuredSelection selection
) {
86 super(name
, selection
);
90 * Import page that scans files, can be cancelled
93 * The workbench reference.
95 * The current selection
97 public ImportTraceWizardScanPage(IWorkbench workbench
, IStructuredSelection selection
) {
98 super(workbench
, selection
);
102 public void dispose() {
104 fRunnable
.done(Status
.OK_STATUS
);
113 public void createControl(Composite parent
) {
114 super.createControl(parent
);
115 final Composite control
= (Composite
) this.getControl();
116 setTitle(Messages
.ImportTraceWizardScanPageTitle
);
117 traceTypeViewer
= new CheckboxTreeViewer(control
, SWT
.CHECK
);
118 traceTypeViewer
.setContentProvider(getBatchWizard().getScannedTraces());
119 traceTypeViewer
.getTree().setHeaderVisible(true);
120 traceTypeViewer
.getControl().setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
121 traceTypeViewer
.setInput(getBatchWizard().getScannedTraces());
122 traceTypeViewer
.addCheckStateListener(new ImportTraceCheckStateListener());
124 TreeViewerFocusCellManager focusCellManager
= new TreeViewerFocusCellManager(traceTypeViewer
, new FocusCellOwnerDrawHighlighter(traceTypeViewer
));
125 ColumnViewerEditorActivationStrategy actSupport
= new ColumnViewerEditorActivationStrategy(traceTypeViewer
) {
127 TreeViewerEditor
.create(traceTypeViewer
, focusCellManager
, actSupport
, ColumnViewerEditor
.TABBING_HORIZONTAL
128 | ColumnViewerEditor
.TABBING_MOVE_TO_ROW_NEIGHBOR
129 | ColumnViewerEditor
.TABBING_VERTICAL
| ColumnViewerEditor
.KEYBOARD_ACTIVATION
);
131 final TextCellEditor textCellEditor
= new TextCellEditor(traceTypeViewer
.getTree());
132 // --------------------
134 // --------------------
135 TreeViewerColumn column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
136 column
.getColumn().setWidth(COL_WIDTH
);
137 column
.getColumn().setText(Messages
.ImportTraceWizardTraceDisplayName
);
138 column
.setLabelProvider(new FirstColumnLabelProvider());
139 column
.setEditingSupport(new ColumnEditorSupport(traceTypeViewer
, textCellEditor
));
141 // --------------------
143 // --------------------
145 column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
146 column
.getColumn().setWidth(500);
147 column
.getColumn().setText(Messages
.ImportTraceWizardImportCaption
);
148 column
.setLabelProvider(new ColumnLabelProvider() {
150 public String
getText(Object element
) {
151 if (element
instanceof FileAndName
) {
152 FileAndName elem
= (FileAndName
) element
;
153 return elem
.getFile().getPath();
158 // --------------------
160 // --------------------
162 column
= new TreeViewerColumn(traceTypeViewer
, SWT
.NONE
);
164 column
.getColumn().setWidth(80);
165 column
.getColumn().setText(Messages
.ImportTraceWizardScanPageSize
);
166 column
.getColumn().setAlignment(SWT
.RIGHT
);
167 column
.setLabelProvider(new ColumnLabelProvider() {
170 public String
getText(Object element
) {
171 if (element
instanceof FileAndName
) {
173 FileAndName elem
= (FileAndName
) element
;
174 long len
= recurseSize(elem
.getFile());
176 double sizeb10
= Math
.log10(len
);
177 DecimalFormat df
= new DecimalFormat();
178 df
.setMaximumFractionDigits(2);
179 df
.setMinimumFractionDigits(0);
181 final double tbSize
= len
/ 1024.0 / 1024 / 1024 / 1024;
182 return df
.format(tbSize
) + Messages
.ImportTraceWizardScanPageTerabyte
;
185 final double gbSize
= len
/ 1024.0 / 1024 / 1024;
186 return df
.format(gbSize
) + Messages
.ImportTraceWizardScanPageGigabyte
;
189 final double mbSize
= len
/ 1024.0 / 1024;
190 return df
.format(mbSize
) + Messages
.ImportTraceWizardScanPageMegabyte
;
193 final double kbSize
= len
/ 1024.0;
194 return df
.format(kbSize
) + Messages
.ImportTraceWizardScanPageKilobyte
;
197 return Long
.toString(len
) + Messages
.ImportTraceWizardScanPagebyte
;
203 private long recurseSize(File file
) {
204 if (file
.isFile() && file
.canRead()) {
205 return file
.length();
208 if (file
.exists() && file
.isDirectory() && file
.canRead()) {
209 final File
[] listFiles
= file
.listFiles();
210 if (listFiles
!= null) {
211 for (File child
: listFiles
) {
212 if (child
.isFile() && child
.canRead()) {
213 size
+= child
.length();
214 } else if (child
.isDirectory()) {
215 size
+= recurseSize(child
);
217 Activator
.getDefault().logError("Unknown \"file\" type for " + child
+ ' ' + child
.toString()); //$NON-NLS-1$
227 getBatchWizard().setTracesToScan(fTracesToScan
);
228 getBatchWizard().setTraceFolder(fTargetFolder
);
230 fRunnable
.schedule();
231 setErrorMessage(Messages
.ImportTraceWizardScanPageSelectAtleastOne
);
234 private void init() {
235 Composite optionPane
= (Composite
) this.getControl();
237 optionPane
.setLayout(new GridLayout());
238 optionPane
.setLayoutData(new GridData(SWT
.LEFT
, SWT
.TOP
, true, true));
240 final Button fLink
= new Button(optionPane
, SWT
.RADIO
);
241 fLink
.setText(Messages
.ImportTraceWizardLinkTraces
);
242 fLink
.setSelection(true);
243 fLink
.setLayoutData(new GridData());
245 final Button fCopy
= new Button(optionPane
, SWT
.RADIO
);
246 fCopy
.setText(Messages
.ImportTraceWizardCopyTraces
);
247 fCopy
.setLayoutData(new GridData());
249 final SelectionListener linkedListener
= new RadioChooser(fLink
);
251 fLink
.addSelectionListener(linkedListener
);
252 fCopy
.addSelectionListener(linkedListener
);
254 Button fOverwrite
= new Button(optionPane
, SWT
.CHECK
);
255 fOverwrite
.setText(Messages
.ImportTraceWizardOverwriteTraces
);
256 fOverwrite
.setLayoutData(new GridData());
257 fOverwrite
.setSelection(true);
258 fOverwrite
.addSelectionListener(new SelectionListener() {
261 public void widgetSelected(SelectionEvent e
) {
262 getBatchWizard().setOverwrite(((Button
) e
.widget
).getSelection());
266 public void widgetDefaultSelected(SelectionEvent e
) {
275 private final class RadioChooser
implements SelectionListener
{
276 final private Button isLinked
;
278 public RadioChooser(Button desiredButton
) {
279 isLinked
= desiredButton
;
283 public void widgetSelected(SelectionEvent e
) {
285 final Button widget
= (Button
) e
.widget
;
286 getBatchWizard().setLinked(widget
.equals(isLinked
));
290 public void widgetDefaultSelected(SelectionEvent e
) {
295 private final class ColumnEditorSupport
extends EditingSupport
{
296 private final TextCellEditor textCellEditor
;
298 private ColumnEditorSupport(ColumnViewer viewer
, TextCellEditor textCellEditor
) {
300 this.textCellEditor
= textCellEditor
;
304 protected boolean canEdit(Object element
) {
305 return element
instanceof FileAndName
;
309 protected CellEditor
getCellEditor(Object element
) {
310 return textCellEditor
;
314 protected Object
getValue(Object element
) {
315 if (element
instanceof FileAndName
) {
316 return ((FileAndName
) element
).getName();
322 protected void setValue(Object element
, Object value
) {
323 FileAndName fan
= (FileAndName
) element
;
324 fan
.setName((String
) value
);
325 getBatchWizard().updateConflicts();
326 traceTypeViewer
.update(element
, null);
327 traceTypeViewer
.refresh();
331 private final class FirstColumnLabelProvider
extends ColumnLabelProvider
{
335 public Image
getImage(Object element
) {
336 if (element
instanceof FileAndName
) {
337 final FileAndName fan
= (FileAndName
) element
;
338 if (fan
.isConflictingName()) {
339 if (fConflict
== null) {
340 fConflict
= Activator
.getDefault().getImageFromImageRegistry(ITmfImageConstants
.IMG_UI_CONFLICT
);
349 public String
getText(Object element
) {
350 if (element
instanceof FileAndName
) {
351 FileAndName elem
= (FileAndName
) element
;
352 return elem
.getName();
354 if (element
instanceof String
) {
355 return (String
) element
;
361 private final class ImportTraceCheckStateListener
implements ICheckStateListener
{
363 public void checkStateChanged(CheckStateChangedEvent event
) {
364 final CheckboxTreeViewer tv
= (CheckboxTreeViewer
)
366 if (event
.getElement() instanceof FileAndName
) {
367 final FileAndName element
= (FileAndName
) event
.getElement();
368 if (event
.getChecked()) {
369 getBatchWizard().addFileToImport(element
);
370 traceTypeViewer
.update(element
, null);
373 getBatchWizard().removeFileToImport(element
);
374 traceTypeViewer
.update(element
, null);
376 maintainCheckIntegrity(tv
, element
);
378 if (event
.getElement() instanceof String
) {
380 tv
.setSubtreeChecked(event
.getElement(), event
.getChecked());
381 final Object
[] children
=
382 getBatchWizard().getScannedTraces().getChildren(event
.getElement());
383 if (event
.getChecked()) {
384 for (int i
= 0; i
< children
.length
; i
++) {
385 final FileAndName element
= (FileAndName
) children
[i
];
386 getBatchWizard().addFileToImport(element
);
387 traceTypeViewer
.update(children
[i
], null);
391 for (int i
= 0; i
< children
.length
; i
++) {
392 getBatchWizard().removeFileToImport((FileAndName
) children
[i
]);
398 getBatchWizard().updateConflicts();
399 if (getBatchWizard().hasConflicts()) {
400 setErrorMessage(Messages
.ImportTraceWizardScanPageRenameError
);
401 } else if (!getBatchWizard().hasTracesToImport()) {
402 setErrorMessage(Messages
.ImportTraceWizardScanPageSelectAtleastOne
);
404 setErrorMessage(null);
406 getWizard().getContainer().updateButtons();
407 traceTypeViewer
.update(event
.getElement(), null);
410 private void maintainCheckIntegrity(final CheckboxTreeViewer viewer
, final FileAndName element
) {
411 final ImportTraceContentProvider scannedTraces
= getBatchWizard().getScannedTraces();
412 String parentElement
= (String
) scannedTraces
.getParent(element
);
413 boolean allChecked
= true;
414 final FileAndName
[] siblings
= scannedTraces
.getSiblings(element
);
415 if (siblings
!= null) {
416 for (FileAndName child
: siblings
) {
417 allChecked
&= viewer
.getChecked(child
);
420 viewer
.setChecked(parentElement
, allChecked
);
424 private final class ScanRunnable
extends Job
{
426 // monitor is stored here, starts as the main monitor but becomes a
428 private IProgressMonitor fMonitor
;
430 public ScanRunnable(String name
) {
432 this.setSystem(true);
435 private synchronized IProgressMonitor
getMonitor() {
440 public IStatus
run(IProgressMonitor monitor
) {
442 * Set up phase, it is synchronous
445 final Control control
= traceTypeViewer
.getControl();
446 // please note the sync exec here is to allow us to set
447 control
.getDisplay().syncExec(new Runnable() {
450 // monitor gets overwritten here so it's necessary to save
452 fMonitor
= SubMonitor
.convert(getMonitor());
453 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
454 ((SubMonitor
) getMonitor()).setWorkRemaining(IProgressMonitor
.UNKNOWN
);
458 * At this point we start calling async execs and updating the view.
459 * This is a good candidate to parallelise.
461 while (fCanRun
== true) {
462 boolean updated
= false;
464 if (fTracesToScan
.isEmpty() && !control
.isDisposed()) {
465 control
.getDisplay().asyncExec(new Runnable() {
469 if (!control
.isDisposed()) {
470 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
471 getMonitor().subTask(Messages
.ImportTraceWizardPageScanDone
);
472 ImportTraceWizardScanPage
.this.setMessage(Messages
.ImportTraceWizardPageScanScanning
+ ' ' + Messages
.ImportTraceWizardPageScanDone
);
478 final TraceValidationHelper traceToScan
= fTracesToScan
.take();
480 if (!getBatchWizard().hasScanned(traceToScan
)) {
481 getBatchWizard().addResult(traceToScan
, TmfTraceType
.getInstance().validate(traceToScan
));
485 * The following is to update the UI
487 validCombo
= getBatchWizard().getResult(traceToScan
);
489 // Synched on it's parent
491 getBatchWizard().getScannedTraces().addCandidate(traceToScan
.getTraceType(), new File(traceToScan
.getTraceToScan()));
494 final int scanned
= getBatchWizard().getNumberOfResults();
495 final int total
= scanned
+ fTracesToScan
.size();
496 final int prevVal
= (int) ((scanned
- 1) * 100.0 / total
);
497 final int curVal
= (int) ((scanned
) * 100.0 / total
);
498 if (curVal
!= prevVal
) {
502 * update the progress
505 if (!control
.isDisposed()) {
506 control
.getDisplay().asyncExec(new Runnable() {
509 if (!control
.isDisposed()) {
510 getMonitor().setTaskName(Messages
.ImportTraceWizardPageScanScanning
+ ' ');
511 getMonitor().subTask(traceToScan
.getTraceToScan());
512 getMonitor().worked(1);
513 ImportTraceWizardScanPage
.this.setMessage(Messages
.ImportTraceWizardPageScanScanning
+ ' '
514 + Integer
.toString(curVal
)
524 * here we update the table
526 final boolean editing
= traceTypeViewer
.isCellEditorActive();
527 if (updated
&& !editing
) {
528 if (!control
.isDisposed()) {
529 control
.getDisplay().asyncExec(new Runnable() {
533 if (!control
.isDisposed()) {
534 if (!traceTypeViewer
.isCellEditorActive()) {
535 traceTypeViewer
.refresh();
542 } catch (InterruptedException e
) {
543 return new Status(IStatus
.CANCEL
, Activator
.PLUGIN_ID
, new String());
546 return Status
.OK_STATUS
;
551 * Refresh the view and the corresponding model.
553 public void refresh() {
554 final Control control
= traceTypeViewer
.getControl();
555 if (!control
.isDisposed()) {
556 control
.getDisplay().asyncExec(new Runnable() {
559 if (!control
.isDisposed()) {
560 traceTypeViewer
.refresh();