1
/**********************************************************************
2
* Copyright (c) 2012, 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
* Bernd Hufmann - Initial API and implementation
11
* Bernd Hufmann - Added handling of streamed traces
12
* Marc-Andre Laperle - Use common method to get opened tmf projects
13
**********************************************************************/
14
package org.eclipse.linuxtools.internal.lttng2.control.ui.views.dialogs;
16
import java.util.ArrayList;
17
import java.util.List;
19
import org.eclipse.core.resources.IFolder;
20
import org.eclipse.core.resources.IProject;
21
import org.eclipse.core.runtime.IPath;
22
import org.eclipse.core.runtime.NullProgressMonitor;
23
import org.eclipse.core.runtime.Path;
24
import org.eclipse.jface.dialogs.Dialog;
25
import org.eclipse.jface.dialogs.IDialogConstants;
26
import org.eclipse.jface.dialogs.MessageDialog;
27
import org.eclipse.jface.viewers.CheckStateChangedEvent;
28
import org.eclipse.jface.viewers.CheckboxTreeViewer;
29
import org.eclipse.jface.viewers.ICheckStateListener;
30
import org.eclipse.jface.window.Window;
31
import org.eclipse.linuxtools.internal.lttng2.control.ui.Activator;
32
import org.eclipse.linuxtools.internal.lttng2.control.ui.views.messages.Messages;
33
import org.eclipse.linuxtools.internal.lttng2.control.ui.views.model.impl.TraceSessionComponent;
34
import org.eclipse.linuxtools.internal.lttng2.control.ui.views.remote.IRemoteSystemProxy;
35
import org.eclipse.linuxtools.tmf.ui.project.model.TmfTracesFolder;
36
import org.eclipse.linuxtools.tmf.ui.project.model.TraceUtils;
37
import org.eclipse.rse.core.subsystems.RemoteChildrenContentsType;
38
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
39
import org.eclipse.rse.subsystems.files.core.servicesubsystem.IFileServiceSubSystem;
40
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile;
41
import org.eclipse.swt.SWT;
42
import org.eclipse.swt.custom.CCombo;
43
import org.eclipse.swt.events.SelectionAdapter;
44
import org.eclipse.swt.events.SelectionEvent;
45
import org.eclipse.swt.graphics.Point;
46
import org.eclipse.swt.layout.GridData;
47
import org.eclipse.swt.layout.GridLayout;
48
import org.eclipse.swt.widgets.Button;
49
import org.eclipse.swt.widgets.Composite;
50
import org.eclipse.swt.widgets.Control;
51
import org.eclipse.swt.widgets.Group;
52
import org.eclipse.swt.widgets.Shell;
53
import org.eclipse.swt.widgets.Text;
54
import org.eclipse.swt.widgets.Tree;
55
import org.eclipse.ui.model.WorkbenchContentProvider;
56
import org.eclipse.ui.model.WorkbenchLabelProvider;
60
* Dialog box for collecting trace import information.
63
* @author Bernd Hufmann
65
public class ImportDialog extends Dialog implements IImportDialog {
67
// ------------------------------------------------------------------------
69
// ------------------------------------------------------------------------
70
/** The icon file for this dialog box. */
71
public static final String IMPORT_ICON_FILE = "icons/elcl16/import_trace.gif"; //$NON-NLS-1$
73
/** Parent directory for UST traces */
74
public static final String UST_PARENT_DIRECTORY = "ust"; //$NON-NLS-1$
76
/** Name of metadata file of trace */
77
public static final String METADATA_FILE_NAME = "metadata"; //$NON-NLS-1$
79
// ------------------------------------------------------------------------
81
// ------------------------------------------------------------------------
83
* The dialog composite.
85
private Composite fDialogComposite = null;
87
* The checkbox tree viewer for selecting available traces
89
private CheckboxTreeViewer fFolderViewer;
91
* The combo box for selecting a project.
93
private CCombo fCombo;
95
* The overwrite button
97
private Button fOverwriteButton;
99
* List of available LTTng 2.0 projects
101
private List<IProject> fProjects;
103
* The parent where the new node should be added.
105
private TraceSessionComponent fSession = null;
107
* The name of the default project name
109
private String fDefaultProjectName = null;
111
* List of traces to import
113
private final List<ImportFileInfo> fTraces = new ArrayList<>();
115
* Selection index in project combo box.
117
private int fProjectIndex;
119
* Flag to indicate that something went wrong when creating the dialog box.
121
private boolean fIsError = false;
123
* Children of the remote folder (can be null)
125
private Object[] fFolderChildren = null;
127
// ------------------------------------------------------------------------
129
// ------------------------------------------------------------------------
132
* @param shell - a shell for the display of the dialog
134
public ImportDialog(Shell shell) {
136
setShellStyle(SWT.RESIZE | getShellStyle());
139
// ------------------------------------------------------------------------
141
// ------------------------------------------------------------------------
144
public List<ImportFileInfo> getTracePathes() {
145
List<ImportFileInfo> retList = new ArrayList<>();
146
retList.addAll(fTraces);
151
public IProject getProject() {
152
return fProjects.get(fProjectIndex);
156
public void setSession(TraceSessionComponent session) {
161
public void setDefaultProject(String defaultProject) {
162
fDefaultProjectName = defaultProject;
165
// ------------------------------------------------------------------------
167
// ------------------------------------------------------------------------
170
protected void configureShell(Shell newShell) {
171
super.configureShell(newShell);
172
newShell.setText(Messages.TraceControl_ImportDialogTitle);
173
newShell.setImage(Activator.getDefault().loadIcon(IMPORT_ICON_FILE));
177
protected Control createDialogArea(Composite parent) {
180
fDialogComposite = new Composite(parent, SWT.NONE);
181
GridLayout layout = new GridLayout(1, true);
182
fDialogComposite.setLayout(layout);
183
fDialogComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
186
createRemoteComposite();
187
} catch (SystemMessageException e) {
188
createErrorComposite(parent, e.fillInStackTrace());
189
return fDialogComposite;
191
return fDialogComposite;
195
protected void createButtonsForButtonBar(Composite parent) {
196
Button selectAllButton = createButton(parent, IDialogConstants.SELECT_ALL_ID, Messages.TraceControl_ImportDialog_SelectAll, true);
197
selectAllButton.addSelectionListener(new SelectionAdapter() {
199
public void widgetSelected(SelectionEvent e) {
200
setFolderChildrenChecked(true);
204
Button deselectAllButton = createButton(parent, IDialogConstants.DESELECT_ALL_ID, Messages.TraceControl_ImportDialog_DeselectAll, true);
205
deselectAllButton.addSelectionListener(new SelectionAdapter() {
207
public void widgetSelected(SelectionEvent e) {
208
setFolderChildrenChecked(false);
211
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true);
212
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
213
updateOKButtonEnablement();
217
protected void okPressed() {
220
// Validate input data
223
fProjectIndex = fCombo.getSelectionIndex();
225
if (fProjectIndex < 0) {
226
MessageDialog.openError(getShell(),
227
Messages.TraceControl_ImportDialogTitle,
228
Messages.TraceControl_ImportDialogNoProjectSelectedError);
232
IProject project = fProjects.get(fProjectIndex);
233
IFolder traceFolder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME);
235
if (!traceFolder.exists()) {
236
// Invalid LTTng 2.0 project
237
MessageDialog.openError(getShell(),
238
Messages.TraceControl_ImportDialogTitle,
239
Messages.TraceControl_ImportDialogInvalidTracingProject + " (" + TmfTracesFolder.TRACES_FOLDER_NAME + ")"); //$NON-NLS-1$//$NON-NLS-2$
243
boolean overwriteAll = fOverwriteButton.getSelection();
245
Object[] checked = fFolderViewer.getCheckedElements();
246
for (int i = 0; i < checked.length; i++) {
247
IRemoteFile file = (IRemoteFile) checked[i];
248
if (!file.isDirectory() && file.getName().equals(METADATA_FILE_NAME)) {
249
IRemoteFile trace = file.getParentRemoteFile();
250
IRemoteFile parent = trace.getParentRemoteFile();
252
String path = fSession.isSnapshotSession() ? fSession.getSnapshotInfo().getSnapshotPath() : fSession.getSessionPath();
253
path = getUnifiedPath(path);
254
IPath sessionParentPath = new Path(path).removeLastSegments(1);
255
IPath traceParentPath = new Path(parent.getAbsolutePath());
257
IPath relativeTracePath = traceParentPath.makeRelativeTo(sessionParentPath);
259
IFolder destinationFolder = traceFolder.getFolder(new Path(relativeTracePath.toOSString()));
261
ImportFileInfo info = new ImportFileInfo(trace, trace.getName(), destinationFolder, overwriteAll);
262
IFolder folder = destinationFolder.getFolder(trace.getName());
264
// Verify if trace directory already exists (and not overwrite)
265
if (folder.exists() && !overwriteAll) {
267
// Ask user for overwrite or new name
268
IImportConfirmationDialog conf = TraceControlDialogFactory.getInstance().getImportConfirmationDialog();
269
conf.setTraceName(trace.getName());
271
// Don't add trace to list if dialog was cancelled.
272
if (conf.open() == Window.OK) {
273
info.setOverwrite(conf.isOverwrite());
274
if (!conf.isOverwrite()) {
275
info.setLocalTraceName(conf.getNewTraceName());
285
if (fTraces.isEmpty()) {
286
MessageDialog.openError(getShell(),
287
Messages.TraceControl_ImportDialogTitle,
288
Messages.TraceControl_ImportDialogNoTraceSelectedError);
293
// validation successful -> call super.okPressed()
297
// ------------------------------------------------------------------------
298
// Helper methods and classes
299
// ------------------------------------------------------------------------
302
* Helper class for the contents of a folder in a tracing project
304
* @author Bernd Hufmann
306
public static class FolderContentProvider extends WorkbenchContentProvider {
308
public Object[] getChildren(Object o) {
309
if (o instanceof IRemoteFile) {
310
IRemoteFile element = (IRemoteFile) o;
311
// For our purpose, we need folders + files
312
if (!element.isDirectory()) {
313
return new Object[0];
316
return super.getChildren(o);
321
* Creates a dialog composite with an error message which can be used
322
* when an exception occurred during creation time of the dialog box.
323
* @param parent - a parent composite
324
* @param e - a error causing exception
326
private void createErrorComposite(Composite parent, Throwable e) {
328
fDialogComposite.dispose();
330
fDialogComposite = new Composite(parent, SWT.NONE);
331
GridLayout layout = new GridLayout(1, true);
332
fDialogComposite.setLayout(layout);
333
fDialogComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
335
Text errorText = new Text(fDialogComposite, SWT.MULTI);
336
StringBuffer error = new StringBuffer();
337
error.append(Messages.TraceControl_ImportDialogCreationError);
338
error.append(System.getProperty("line.separator")); //$NON-NLS-1$
339
error.append(System.getProperty("line.separator")); //$NON-NLS-1$
340
error.append(e.toString());
341
errorText.setText(error.toString());
342
errorText.setLayoutData(new GridData(GridData.FILL_BOTH));
345
private void createRemoteComposite() throws SystemMessageException{
346
Group contextGroup = new Group(fDialogComposite, SWT.SHADOW_NONE);
347
contextGroup.setText(Messages.TraceControl_ImportDialogTracesGroupName);
348
GridLayout layout = new GridLayout(1, true);
349
contextGroup.setLayout(layout);
350
contextGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
352
IRemoteSystemProxy proxy = fSession.getTargetNode().getRemoteSystemProxy();
354
IFileServiceSubSystem fsss = proxy.getFileServiceSubSystem();
356
final String path = fSession.isSnapshotSession() ? fSession.getSnapshotInfo().getSnapshotPath() : fSession.getSessionPath();
357
final IRemoteFile remoteFolder = fsss.getRemoteFileObject(path, new NullProgressMonitor());
358
// make sure that remote directory is read and not cached
359
remoteFolder.markStale(true, true);
361
fFolderViewer = new CheckboxTreeViewer(contextGroup, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
362
GridData data = new GridData(GridData.FILL_BOTH);
363
Tree tree = fFolderViewer.getTree();
364
tree.setLayoutData(data);
365
tree.setFont(fDialogComposite.getFont());
366
tree.setToolTipText(Messages.TraceControl_ImportDialogTracesTooltip);
368
fFolderViewer.setContentProvider(new FolderContentProvider());
369
fFolderViewer.setLabelProvider(new WorkbenchLabelProvider());
371
fFolderViewer.addCheckStateListener(new ICheckStateListener() {
373
public void checkStateChanged(CheckStateChangedEvent event) {
374
Object elem = event.getElement();
375
if (elem instanceof IRemoteFile) {
376
IRemoteFile element = (IRemoteFile) elem;
377
if (!element.isDirectory()) {
378
// A trick to keep selection of a file in sync with the directory
379
boolean p = fFolderViewer.getChecked((element.getParentRemoteFile()));
380
fFolderViewer.setChecked(element, p);
382
fFolderViewer.setSubtreeChecked(event.getElement(), event.getChecked());
383
if (!event.getChecked()) {
384
fFolderViewer.setChecked(element.getParentRemoteFile(), false);
387
updateOKButtonEnablement();
391
fFolderViewer.setInput(remoteFolder);
393
fFolderChildren = remoteFolder.getContents(RemoteChildrenContentsType.getInstance());
394
// children can be null if there the path doesn't exist. This happens when a trace
395
// session hadn't been started and no output was created.
396
setFolderChildrenChecked(true);
398
Group projectGroup = new Group(fDialogComposite, SWT.SHADOW_NONE);
399
projectGroup.setText(Messages.TraceControl_ImportDialogProjectsGroupName);
400
layout = new GridLayout(1, true);
401
projectGroup.setLayout(layout);
402
projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
404
fProjects = new ArrayList<>();
405
List<String> projectNames = new ArrayList<>();
407
for (IProject project : TraceUtils.getOpenedTmfProjects()) {
408
fProjects.add(project);
409
projectNames.add(project.getName());
412
fCombo = new CCombo(projectGroup, SWT.READ_ONLY);
413
fCombo.setToolTipText(Messages.TraceControl_ImportDialogProjectsTooltip);
414
fCombo.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 1));
415
fCombo.setItems(projectNames.toArray(new String[projectNames.size()]));
417
if (fDefaultProjectName != null) {
418
int select = projectNames.indexOf(fDefaultProjectName);
419
fCombo.select(select);
422
Group overrideGroup = new Group(fDialogComposite, SWT.SHADOW_NONE);
423
layout = new GridLayout(1, true);
424
overrideGroup.setLayout(layout);
425
overrideGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
427
fOverwriteButton = new Button(overrideGroup, SWT.CHECK);
428
fOverwriteButton.setText(Messages.TraceControl_ImportDialogOverwriteButtonText);
429
getShell().setMinimumSize(new Point(500, 400));
432
private void setFolderChildrenChecked(boolean isChecked) {
433
if (fFolderChildren != null) {
434
for (Object child : fFolderChildren) {
435
fFolderViewer.setSubtreeChecked(child, isChecked);
438
updateOKButtonEnablement();
441
private void updateOKButtonEnablement() {
442
Object[] checked = fFolderViewer.getCheckedElements();
443
Button okButton = getButton(IDialogConstants.OK_ID);
444
if (okButton != null) {
445
okButton.setEnabled(checked.length > 0);
449
private static String getUnifiedPath(String path) {
450
// Use Path class to remove unnecessary slashes
451
return new Path(path).removeTrailingSeparator().toString();