analysis: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / internal / tmf / ui / project / wizards / importtrace / ImportTraceWizardScanPage.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 Ericsson
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 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
14
15 import java.io.File;
16 import java.text.DecimalFormat;
17 import java.util.concurrent.ArrayBlockingQueue;
18 import java.util.concurrent.BlockingQueue;
19
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;
54
55 /**
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
58 * be scanned.
59 *
60 * @author Matthew Khouzam
61 */
62 public class ImportTraceWizardScanPage extends AbstractImportTraceWizardPage {
63
64 private static final int COL_WIDTH = 200;
65 private static final int MAX_TRACES = 65536;
66 private CheckboxTreeViewer traceTypeViewer;
67
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;
71
72 // --------------------------------------------------------------------------------
73 // Constructor and destructor
74 // --------------------------------------------------------------------------------
75
76 /**
77 * Import page that scans files, can be cancelled.
78 *
79 * @param name
80 * The name of the page.
81 * @param selection
82 * The current selection
83 */
84 protected ImportTraceWizardScanPage(String name, IStructuredSelection selection) {
85 super(name, selection);
86 }
87
88 /**
89 * Import page that scans files, can be cancelled
90 *
91 * @param workbench
92 * The workbench reference.
93 * @param selection
94 * The current selection
95 */
96 public ImportTraceWizardScanPage(IWorkbench workbench, IStructuredSelection selection) {
97 super(workbench, selection);
98 }
99
100 @Override
101 public void dispose() {
102 fCanRun = false;
103 fRunnable.done(Status.OK_STATUS);
104 super.dispose();
105 }
106
107 /*
108 * Init
109 */
110
111 @Override
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());
122
123 TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(traceTypeViewer, new FocusCellOwnerDrawHighlighter(traceTypeViewer));
124 ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(traceTypeViewer) {
125 };
126 TreeViewerEditor.create(traceTypeViewer, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL
127 | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
128 | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION);
129
130 final TextCellEditor textCellEditor = new TextCellEditor(traceTypeViewer.getTree());
131 // --------------------
132 // Column 1
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));
139
140 // --------------------
141 // Column 2
142 // --------------------
143
144 column = new TreeViewerColumn(traceTypeViewer, SWT.NONE);
145 column.getColumn().setWidth(500);
146 column.getColumn().setText(Messages.ImportTraceWizardImportCaption);
147 column.setLabelProvider(new ColumnLabelProvider() {
148 @Override
149 public String getText(Object element) {
150 if (element instanceof FileAndName) {
151 FileAndName elem = (FileAndName) element;
152 return elem.getFile().getPath();
153 }
154 return null;
155 }
156 });
157 // --------------------
158 // Column 3
159 // --------------------
160
161 column = new TreeViewerColumn(traceTypeViewer, SWT.NONE);
162
163 column.getColumn().setWidth(80);
164 column.getColumn().setText(Messages.ImportTraceWizardScanPageSize);
165 column.getColumn().setAlignment(SWT.RIGHT);
166 column.setLabelProvider(new ColumnLabelProvider() {
167
168 @Override
169 public String getText(Object element) {
170 if (element instanceof FileAndName) {
171
172 FileAndName elem = (FileAndName) element;
173 long len = recurseSize(elem.getFile());
174 if (len > 0) {
175 double sizeb10 = Math.log10(len);
176 DecimalFormat df = new DecimalFormat();
177 df.setMaximumFractionDigits(2);
178 df.setMinimumFractionDigits(0);
179 if (sizeb10 > 12) {
180 final double tbSize = len / 1024.0 / 1024 / 1024 / 1024;
181 return df.format(tbSize) + Messages.ImportTraceWizardScanPageTerabyte;
182 }
183 if (sizeb10 > 9) {
184 final double gbSize = len / 1024.0 / 1024 / 1024;
185 return df.format(gbSize) + Messages.ImportTraceWizardScanPageGigabyte;
186 }
187 if (sizeb10 > 6) {
188 final double mbSize = len / 1024.0 / 1024;
189 return df.format(mbSize) + Messages.ImportTraceWizardScanPageMegabyte;
190 }
191 if (sizeb10 > 3) {
192 final double kbSize = len / 1024.0;
193 return df.format(kbSize) + Messages.ImportTraceWizardScanPageKilobyte;
194 }
195 }
196 return Long.toString(len) + Messages.ImportTraceWizardScanPagebyte;
197
198 }
199 return null;
200 }
201
202 private long recurseSize(File file) {
203 if (file.isFile() && file.canRead()) {
204 return file.length();
205 }
206 long size = 0;
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);
215 } else {
216 Activator.getDefault().logError("Unknown \"file\" type for " + child + ' ' + child.toString()); //$NON-NLS-1$
217 }
218 }
219 }
220 }
221 return size;
222 }
223 });
224
225 init();
226 getBatchWizard().setTracesToScan(fTracesToScan);
227 getBatchWizard().setTraceFolder(fTargetFolder);
228
229 fRunnable.schedule();
230 setErrorMessage(Messages.ImportTraceWizardScanPageSelectAtleastOne);
231 }
232
233 private void init() {
234 Composite optionPane = (Composite) this.getControl();
235
236 optionPane.setLayout(new GridLayout());
237 optionPane.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
238
239 final Button fLink = new Button(optionPane, SWT.RADIO);
240 fLink.setText(Messages.ImportTraceWizardLinkTraces);
241 fLink.setSelection(true);
242 fLink.setLayoutData(new GridData());
243
244 final Button fCopy = new Button(optionPane, SWT.RADIO);
245 fCopy.setText(Messages.ImportTraceWizardCopyTraces);
246 fCopy.setLayoutData(new GridData());
247
248 final SelectionListener linkedListener = new RadioChooser(fLink);
249
250 fLink.addSelectionListener(linkedListener);
251 fCopy.addSelectionListener(linkedListener);
252
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() {
258
259 @Override
260 public void widgetSelected(SelectionEvent e) {
261 getBatchWizard().setOverwrite(((Button) e.widget).getSelection());
262 }
263
264 @Override
265 public void widgetDefaultSelected(SelectionEvent e) {
266 }
267 });
268 }
269
270 /*
271 * Helper classes
272 */
273
274 private final class RadioChooser implements SelectionListener {
275 private final Button isLinked;
276
277 public RadioChooser(Button desiredButton) {
278 isLinked = desiredButton;
279 }
280
281 @Override
282 public void widgetSelected(SelectionEvent e) {
283
284 final Button widget = (Button) e.widget;
285 getBatchWizard().setLinked(widget.equals(isLinked));
286 }
287
288 @Override
289 public void widgetDefaultSelected(SelectionEvent e) {
290
291 }
292 }
293
294 private final class ColumnEditorSupport extends EditingSupport {
295 private final TextCellEditor textCellEditor;
296
297 private ColumnEditorSupport(ColumnViewer viewer, TextCellEditor textCellEditor) {
298 super(viewer);
299 this.textCellEditor = textCellEditor;
300 }
301
302 @Override
303 protected boolean canEdit(Object element) {
304 return element instanceof FileAndName;
305 }
306
307 @Override
308 protected CellEditor getCellEditor(Object element) {
309 return textCellEditor;
310 }
311
312 @Override
313 protected Object getValue(Object element) {
314 if (element instanceof FileAndName) {
315 return ((FileAndName) element).getName();
316 }
317 return null;
318 }
319
320 @Override
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();
327 }
328 }
329
330 private final class FirstColumnLabelProvider extends ColumnLabelProvider {
331 Image fConflict;
332
333 @Override
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);
340 }
341 return fConflict;
342 }
343 }
344 return null;
345 }
346
347 @Override
348 public String getText(Object element) {
349 if (element instanceof FileAndName) {
350 FileAndName elem = (FileAndName) element;
351 return elem.getName();
352 }
353 if (element instanceof String) {
354 return (String) element;
355 }
356 return null;
357 }
358 }
359
360 private final class ImportTraceCheckStateListener implements ICheckStateListener {
361 @Override
362 public void checkStateChanged(CheckStateChangedEvent event) {
363 final CheckboxTreeViewer tv = (CheckboxTreeViewer)
364 event.getSource();
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);
370 }
371 else {
372 getBatchWizard().removeFileToImport(element);
373 traceTypeViewer.update(element, null);
374 }
375 maintainCheckIntegrity(tv, element);
376 }
377 if (event.getElement() instanceof String) {
378
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);
387 }
388 }
389 else {
390 for (int i = 0; i < children.length; i++) {
391 getBatchWizard().removeFileToImport((FileAndName) children[i]);
392
393 }
394 }
395
396 }
397 getBatchWizard().updateConflicts();
398 if (getBatchWizard().hasConflicts()) {
399 setErrorMessage(Messages.ImportTraceWizardScanPageRenameError);
400 } else if (!getBatchWizard().hasTracesToImport()) {
401 setErrorMessage(Messages.ImportTraceWizardScanPageSelectAtleastOne);
402 } else {
403 setErrorMessage(null);
404 }
405 getWizard().getContainer().updateButtons();
406 traceTypeViewer.update(event.getElement(), null);
407 }
408
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);
417 }
418 }
419 viewer.setChecked(parentElement, allChecked);
420 }
421 }
422
423 private final class ScanRunnable extends Job {
424
425 // monitor is stored here, starts as the main monitor but becomes a
426 // submonitor
427 private IProgressMonitor fMonitor;
428
429 public ScanRunnable(String name) {
430 super(name);
431 this.setSystem(true);
432 }
433
434 private synchronized IProgressMonitor getMonitor() {
435 return fMonitor;
436 }
437
438 @Override
439 public IStatus run(IProgressMonitor monitor) {
440 /*
441 * Set up phase, it is synchronous
442 */
443 fMonitor = monitor;
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() {
447 @Override
448 public void run() {
449 // monitor gets overwritten here so it's necessary to save
450 // it in a field.
451 fMonitor = SubMonitor.convert(getMonitor());
452 getMonitor().setTaskName(Messages.ImportTraceWizardPageScanScanning + ' ');
453 ((SubMonitor) getMonitor()).setWorkRemaining(IProgressMonitor.UNKNOWN);
454 }
455 });
456 /*
457 * At this point we start calling async execs and updating the view.
458 * This is a good candidate to parallelise.
459 */
460 while (fCanRun == true) {
461 boolean updated = false;
462 boolean validCombo;
463 if (fTracesToScan.isEmpty() && !control.isDisposed()) {
464 control.getDisplay().asyncExec(new Runnable() {
465
466 @Override
467 public void run() {
468 if (!control.isDisposed()) {
469 getMonitor().setTaskName(Messages.ImportTraceWizardPageScanScanning + ' ');
470 getMonitor().subTask(Messages.ImportTraceWizardPageScanDone);
471 ImportTraceWizardScanPage.this.setMessage(Messages.ImportTraceWizardPageScanScanning + ' ' + Messages.ImportTraceWizardPageScanDone);
472 }
473 }
474 });
475 }
476 try {
477 final TraceValidationHelper traceToScan = fTracesToScan.take();
478
479 if (!getBatchWizard().hasScanned(traceToScan)) {
480 getBatchWizard().addResult(traceToScan, TmfTraceType.validate(traceToScan));
481 }
482
483 /*
484 * The following is to update the UI
485 */
486 validCombo = getBatchWizard().getResult(traceToScan);
487 if (validCombo) {
488 // Synched on it's parent
489
490 getBatchWizard().getScannedTraces().addCandidate(traceToScan.getTraceType(), new File(traceToScan.getTraceToScan()));
491 updated = true;
492 }
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) {
498 updated = true;
499 }
500 /*
501 * update the progress
502 */
503 if (updated) {
504 if (!control.isDisposed()) {
505 control.getDisplay().asyncExec(new Runnable() {
506 @Override
507 public void run() {
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)
514 + '%');
515 }
516 }
517 }
518 );
519 }
520 }
521
522 /*
523 * here we update the table
524 */
525 final boolean editing = traceTypeViewer.isCellEditorActive();
526 if (updated && !editing) {
527 if (!control.isDisposed()) {
528 control.getDisplay().asyncExec(new Runnable() {
529
530 @Override
531 public void run() {
532 if (!control.isDisposed()) {
533 if (!traceTypeViewer.isCellEditorActive()) {
534 traceTypeViewer.refresh();
535 }
536 }
537 }
538 });
539 }
540 }
541 } catch (InterruptedException e) {
542 return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, new String());
543 }
544 }
545 return Status.OK_STATUS;
546 }
547 }
548
549 /**
550 * Refresh the view and the corresponding model.
551 */
552 public void refresh() {
553 final Control control = traceTypeViewer.getControl();
554 if (!control.isDisposed()) {
555 control.getDisplay().asyncExec(new Runnable() {
556 @Override
557 public void run() {
558 if (!control.isDisposed()) {
559 traceTypeViewer.refresh();
560 }
561 }
562 });
563 }
564 }
565 }
This page took 0.052828 seconds and 5 git commands to generate.