tmf: Import and Export trace package
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / internal / tmf / ui / project / wizards / tracepkg / AbstractTracePackageWizardPage.java
CommitLineData
6e651d8b
MAL
1/*******************************************************************************
2 * Copyright (c) 2013 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 * Marc-Andre Laperle - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg;
14
15import java.io.ByteArrayOutputStream;
16import java.io.File;
17import java.io.IOException;
18import java.io.PrintStream;
19import java.util.ArrayList;
20import java.util.Arrays;
21import java.util.List;
22
23import org.eclipse.core.runtime.CoreException;
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.jface.dialogs.ErrorDialog;
27import org.eclipse.jface.dialogs.IDialogSettings;
28import org.eclipse.jface.resource.ImageDescriptor;
29import org.eclipse.jface.viewers.CheckStateChangedEvent;
30import org.eclipse.jface.viewers.CheckboxTreeViewer;
31import org.eclipse.jface.viewers.ICheckStateListener;
32import org.eclipse.jface.viewers.IStructuredSelection;
33import org.eclipse.jface.wizard.WizardPage;
34import org.eclipse.linuxtools.internal.tmf.ui.Activator;
35import org.eclipse.swt.SWT;
36import org.eclipse.swt.events.SelectionAdapter;
37import org.eclipse.swt.events.SelectionEvent;
38import org.eclipse.swt.events.SelectionListener;
39import org.eclipse.swt.layout.GridData;
40import org.eclipse.swt.layout.GridLayout;
41import org.eclipse.swt.widgets.Button;
42import org.eclipse.swt.widgets.Combo;
43import org.eclipse.swt.widgets.Composite;
44import org.eclipse.swt.widgets.Event;
45import org.eclipse.swt.widgets.FileDialog;
46import org.eclipse.swt.widgets.Label;
47import org.eclipse.swt.widgets.Listener;
48import org.eclipse.swt.widgets.TreeItem;
49
50/**
51 * An abstract wizard page containing common code useful for both import and
52 * export trace package wizard pages
53 *
54 * @author Marc-Andre Laperle
55 */
56abstract public class AbstractTracePackageWizardPage extends WizardPage {
57
58 private static final int COMBO_HISTORY_LENGTH = 5;
59 private static final String STORE_FILE_PATHS_ID = ".STORE_FILEPATHS_ID"; //$NON-NLS-1$
60
61 private final String fStoreFilePathId;
62 private final IStructuredSelection fSelection;
63
64 private CheckboxTreeViewer fElementViewer;
65 private Button fSelectAllButton;
66 private Button fDeselectAllButton;
67 private Combo fFilePathCombo;
68 private Button fBrowseButton;
69
70 /**
71 * Create the trace package wizard page
72 *
73 * @param pageName
74 * the name of the page
75 * @param title
76 * the title for this wizard page, or null if none
77 * @param titleImage
78 * the image descriptor for the title of this wizard page, or
79 * null if none
80 * @param selection
81 * the current object selection
82 */
83 protected AbstractTracePackageWizardPage(String pageName, String title, ImageDescriptor titleImage, IStructuredSelection selection) {
84 super(pageName, title, titleImage);
85 fStoreFilePathId = getName() + STORE_FILE_PATHS_ID;
86 fSelection = selection;
87 }
88
89 /**
90 * Create the element viewer
91 *
92 * @param parent
93 * the parent composite
94 */
95 protected void createElementViewer(Composite parent) {
96 fElementViewer = new CheckboxTreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.CHECK);
97
98 fElementViewer.addCheckStateListener(new ICheckStateListener() {
99 @Override
100 public void checkStateChanged(CheckStateChangedEvent event) {
101 TracePackageElement element = (TracePackageElement) event.getElement();
102 if (!element.isEnabled()) {
103 fElementViewer.setChecked(element, element.isChecked());
104 } else {
105 setSubtreeChecked(fElementViewer, element, true, event.getChecked());
106 }
107 maintainCheckIntegrity(element);
108 updateApproximateSelectedSize();
109 updatePageCompletion();
110 }
111
112 private void maintainCheckIntegrity(final TracePackageElement element) {
113 TracePackageElement parentElement = element.getParent();
114 boolean allChecked = true;
115 boolean oneChecked = false;
116 if (parentElement != null) {
117 if (parentElement.getChildren() != null) {
118 for (TracePackageElement child : parentElement.getChildren()) {
119 boolean checked = fElementViewer.getChecked(child) && !fElementViewer.getGrayed(child);
120 oneChecked |= checked;
121 allChecked &= checked;
122 }
123 }
124 if (oneChecked && !allChecked) {
125 fElementViewer.setGrayChecked(parentElement, true);
126 } else {
127 fElementViewer.setGrayed(parentElement, false);
128 fElementViewer.setChecked(parentElement, allChecked);
129 }
130 maintainCheckIntegrity(parentElement);
131 }
132 }
133 });
134 GridData layoutData = new GridData(GridData.FILL_BOTH);
135 fElementViewer.getTree().setLayoutData(layoutData);
136 fElementViewer.setContentProvider(new TracePackageContentProvider());
137 fElementViewer.setLabelProvider(new TracePackageLabelProvider());
138 }
139
140 /**
141 * Create the input for the element viewer
142 *
143 * @return the input for the element viewer
144 */
145 protected abstract Object createElementViewerInput();
146
147 /**
148 * Create the file path group that allows the user to type or browse for a
149 * file path
150 *
151 * @param parent
152 * the parent composite
153 * @param label
154 * the label to describe the file path (i.e. import/export)
155 * @param fileDialogStyle
156 * SWT.OPEN or SWT.SAVE
157 */
158 protected void createFilePathGroup(Composite parent, String label, final int fileDialogStyle) {
159
160 Composite filePathSelectionGroup = new Composite(parent, SWT.NONE);
161 GridLayout layout = new GridLayout();
162 layout.numColumns = 3;
163 filePathSelectionGroup.setLayout(layout);
164 filePathSelectionGroup.setLayoutData(new GridData(
165 GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL));
166
167 Label destinationLabel = new Label(filePathSelectionGroup, SWT.NONE);
168 destinationLabel.setText(label);
169
170 fFilePathCombo = new Combo(filePathSelectionGroup, SWT.SINGLE
171 | SWT.BORDER);
172 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
173 | GridData.GRAB_HORIZONTAL);
174 data.grabExcessHorizontalSpace = true;
175 fFilePathCombo.setLayoutData(data);
176
177 fBrowseButton = new Button(filePathSelectionGroup,
178 SWT.PUSH);
179 fBrowseButton.setText(org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_Browse);
180 fBrowseButton.addListener(SWT.Selection, new Listener() {
181 @Override
182 public void handleEvent(Event event) {
183 handleFilePathBrowseButtonPressed(fileDialogStyle);
184 }
185 });
186 setButtonLayoutData(fBrowseButton);
187 }
188
189 /**
190 * Update the page with the file path the current file path selection
191 */
192 abstract protected void updateWithFilePathSelection();
193
194 /**
195 * Creates the buttons for selecting all or none of the elements.
196 *
197 * @param parent
198 * the parent control
199 * @return the button group
200 */
201 protected Composite createButtonsGroup(Composite parent) {
202
203 // top level group
204 Composite buttonComposite = new Composite(parent, SWT.NONE);
205
206 GridLayout layout = new GridLayout();
207 layout.numColumns = 3;
208 buttonComposite.setLayout(layout);
209 buttonComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
210 | GridData.HORIZONTAL_ALIGN_FILL));
211
212 fSelectAllButton = new Button(buttonComposite, SWT.PUSH);
213 fSelectAllButton.setText(org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_SelectAll);
214
215 SelectionListener listener = new SelectionAdapter() {
216 @Override
217 public void widgetSelected(SelectionEvent e) {
218 setAllChecked(fElementViewer, true, true);
219 updateApproximateSelectedSize();
220 updatePageCompletion();
221 }
222 };
223 fSelectAllButton.addSelectionListener(listener);
224
225 fDeselectAllButton = new Button(buttonComposite, SWT.PUSH);
226 fDeselectAllButton.setText(org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_DeselectAll);
227
228 listener = new SelectionAdapter() {
229 @Override
230 public void widgetSelected(SelectionEvent e) {
231 setAllChecked(fElementViewer, true, false);
232 updateApproximateSelectedSize();
233 updatePageCompletion();
234 }
235 };
236 fDeselectAllButton.addSelectionListener(listener);
237
238 return buttonComposite;
239 }
240
241 /**
242 * Restore widget values to the values that they held last time this wizard
243 * was used to completion.
244 */
245 protected void restoreWidgetValues() {
246 IDialogSettings settings = getDialogSettings();
247 if (settings != null) {
248 String[] directoryNames = settings.getArray(fStoreFilePathId);
249 if (directoryNames == null || directoryNames.length == 0) {
250 return;
251 }
252
253 for (int i = 0; i < directoryNames.length; i++) {
254 fFilePathCombo.add(directoryNames[i]);
255 }
256 }
257 }
258
259 /**
260 * Save widget values to Dialog settings
261 */
262 protected void saveWidgetValues() {
263 IDialogSettings settings = getDialogSettings();
264 if (settings != null) {
265 // update directory names history
266 String[] directoryNames = settings.getArray(fStoreFilePathId);
267 if (directoryNames == null) {
268 directoryNames = new String[0];
269 }
270
271 directoryNames = addToHistory(directoryNames, getFilePathValue());
272 settings.put(fStoreFilePathId, directoryNames);
273 }
274 }
275
276 /**
277 * Determine if the page is complete and update the page appropriately.
278 */
279 protected void updatePageCompletion() {
280 boolean pageComplete = determinePageCompletion();
281 setPageComplete(pageComplete);
282 if (pageComplete) {
283 setErrorMessage(null);
284 }
285 }
286
287 /**
288 * Determine if the page is completed or not
289 *
290 * @return true if the page is completed, false otherwise
291 */
292 protected boolean determinePageCompletion() {
293 return fElementViewer.getCheckedElements().length > 0 && !getFilePathValue().isEmpty();
294 }
295
296 /**
297 * Handle error status
298 *
299 * @param status
300 * the error status
301 */
302 protected void handleErrorStatus(IStatus status) {
303
304 Throwable exception = status.getException();
305 String message = status.getMessage().length() > 0 ? status.getMessage() : org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation;
306
307 if (!status.isMultiStatus()) {
308 handleError(message, exception);
309 return;
310 }
311
312 // Build a string with all the children status messages, exception
313 // messages and stack traces
314 StringBuilder sb = new StringBuilder();
315 for (IStatus childStatus : status.getChildren()) {
316 StringBuilder childSb = new StringBuilder();
317 if (!childStatus.getMessage().isEmpty()) {
318 childSb.append(childStatus.getMessage() + '\n');
319 }
320
321 Throwable childException = childStatus.getException();
322 if (childException != null) {
323 String reason = childException.getMessage();
324 // Some system exceptions have no message
325 if (reason == null) {
326 reason = childException.toString();
327 }
328
329 String stackMessage = getExceptionStackMessage(childException);
330 if (stackMessage == null) {
331 stackMessage = reason;
332 }
333
334 childSb.append(stackMessage);
335 }
336
337 if (childSb.length() > 0) {
338 childSb.insert(0, '\n');
339 sb.append(childSb.toString());
340 }
341 }
342
343 // ErrorDialog only prints the call stack for a CoreException
344 exception = new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, sb.toString(), null));
345 final Status statusWithException = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorMultipleProblems, exception);
346
347 Activator.getDefault().logError(message, exception);
348 ErrorDialog.openError(getContainer().getShell(), org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, message, statusWithException);
349 }
350
351 /**
352 * Handle errors occurring in the wizard operations
353 *
354 * @param message
355 * the error message
356 * @param exception
357 * the exception attached to the message
358 */
359 protected void handleError(String message, Throwable exception) {
360 Activator.getDefault().logError(message, exception);
361 displayErrorDialog(message, exception);
362 }
363
364 private static String getExceptionStackMessage(Throwable exception) {
365 String stackMessage = null;
366 ByteArrayOutputStream baos = new ByteArrayOutputStream();
367 PrintStream ps = new PrintStream(baos);
368 exception.printStackTrace(ps);
369 ps.flush();
370 try {
371 baos.flush();
372 stackMessage = baos.toString();
373 } catch (IOException e) {
374 }
375
376 return stackMessage;
377 }
378
379 private void displayErrorDialog(String message, Throwable exception) {
380 if (exception == null) {
381 final Status s = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message);
382 ErrorDialog.openError(getContainer().getShell(), org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, null, s);
383 return;
384 }
385
386 String reason = exception.getMessage();
387 // Some system exceptions have no message
388 if (reason == null) {
389 reason = exception.toString();
390 }
391
392 String stackMessage = getExceptionStackMessage(exception);
393 if (stackMessage == null || stackMessage.isEmpty()) {
394 stackMessage = reason;
395 }
396
397 // ErrorDialog only prints the call stack for a CoreException
398 CoreException coreException = new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, stackMessage, exception));
399 final Status s = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, reason, coreException);
400 ErrorDialog.openError(getContainer().getShell(), org.eclipse.linuxtools.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, message, s);
401 }
402
403 /**
404 * A version of setSubtreeChecked that is aware of isEnabled
405 *
406 * @param viewer
407 * the viewer
408 * @param element
409 * the element
410 * @param enabledOnly
411 * if only enabled elements should be considered
412 * @param checked
413 * true if the item should be checked, and false if it should be
414 * unchecked
415 */
416 protected static void setSubtreeChecked(CheckboxTreeViewer viewer, TracePackageElement element, boolean enabledOnly, boolean checked) {
417 if (!enabledOnly || element.isEnabled()) {
418 viewer.setChecked(element, checked);
419 if (checked) {
420 viewer.setGrayed(element, false);
421 }
422 element.setChecked(checked);
423 if (element.getChildren() != null) {
424 for (TracePackageElement child : element.getChildren()) {
425 setSubtreeChecked(viewer, child, enabledOnly, checked);
426 }
427 }
428 }
429 }
430
431 /**
432 * Sets all items in the element viewer to be checked or unchecked
433 *
434 * @param viewer
435 * the viewer
436 * @param enabledOnly
437 * if only enabled elements should be considered
438 * @param checked
439 * whether or not items should be checked
440 */
441 protected static void setAllChecked(CheckboxTreeViewer viewer, boolean enabledOnly, boolean checked) {
442 TreeItem[] items = viewer.getTree().getItems();
443 for (int i = 0; i < items.length; i++) {
444 Object element = items[i].getData();
445 setSubtreeChecked(viewer, (TracePackageElement) element, enabledOnly, checked);
446 }
447 }
448
449 private static void addToHistory(List<String> history, String newEntry) {
450 history.remove(newEntry);
451 history.add(0, newEntry);
452
453 // since only one new item was added, we can be over the limit
454 // by at most one item
455 if (history.size() > COMBO_HISTORY_LENGTH) {
456 history.remove(COMBO_HISTORY_LENGTH);
457 }
458 }
459
460 private static String[] addToHistory(String[] history, String newEntry) {
461 ArrayList<String> l = new ArrayList<String>(Arrays.asList(history));
462 addToHistory(l, newEntry);
463 String[] r = new String[l.size()];
464 l.toArray(r);
465 return r;
466 }
467
468 /**
469 * Open an appropriate file dialog so that the user can specify a file to
470 * import/export
471 * @param fileDialogStyle
472 */
473 private void handleFilePathBrowseButtonPressed(int fileDialogStyle) {
474 FileDialog dialog = new FileDialog(getContainer().getShell(), fileDialogStyle | SWT.SHEET);
475 dialog.setFilterExtensions(new String[] { "*.zip;*.tar.gz;*.tar;*.tgz", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$
476 dialog.setText(Messages.TracePackage_FileDialogTitle);
477 String currentSourceString = getFilePathValue();
478 int lastSeparatorIndex = currentSourceString.lastIndexOf(File.separator);
479 if (lastSeparatorIndex != -1) {
480 dialog.setFilterPath(currentSourceString.substring(0, lastSeparatorIndex));
481 }
482 String selectedFileName = dialog.open();
483
484 if (selectedFileName != null) {
485 setFilePathValue(selectedFileName);
486 updateWithFilePathSelection();
487 }
488 }
489
490 /**
491 * Get the current file path value
492 *
493 * @return the current file path value
494 */
495 protected String getFilePathValue() {
496 return fFilePathCombo.getText().trim();
497 }
498
499 /**
500 * Set the file path value
501 *
502 * @param value
503 * file path value
504 */
505 protected void setFilePathValue(String value) {
506 fFilePathCombo.setText(value);
507 updatePageCompletion();
508 }
509
510 /**
511 * Update the approximate size of the selected elements
512 */
513 protected void updateApproximateSelectedSize() {
514 }
515
516 /**
517 * Get the element tree viewer
518 *
519 * @return the element tree viewer
520 */
521 protected CheckboxTreeViewer getElementViewer() {
522 return fElementViewer;
523 }
524
525 /**
526 * Get the file path combo box
527 *
528 * @return the file path combo box
529 */
530 protected Combo getFilePathCombo() {
531 return fFilePathCombo;
532 }
533
534 /**
535 * Get the object selection when the wizard was created
536 *
537 * @return the object selection
538 */
539 protected IStructuredSelection getSelection() {
540 return fSelection;
541 }
542}
This page took 0.045337 seconds and 5 git commands to generate.