1 /**********************************************************************
2 * Copyright (c) 2012, 2015 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 * Markus Schorn - Bug 448058: Use org.eclipse.remote in favor of RSE
14 **********************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.dialogs
;
17 import java
.util
.ArrayList
;
18 import java
.util
.List
;
20 import org
.eclipse
.core
.filesystem
.EFS
;
21 import org
.eclipse
.core
.filesystem
.IFileInfo
;
22 import org
.eclipse
.core
.filesystem
.IFileStore
;
23 import org
.eclipse
.core
.resources
.IFolder
;
24 import org
.eclipse
.core
.resources
.IProject
;
25 import org
.eclipse
.core
.runtime
.CoreException
;
26 import org
.eclipse
.core
.runtime
.IPath
;
27 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
28 import org
.eclipse
.core
.runtime
.Path
;
29 import org
.eclipse
.jface
.dialogs
.Dialog
;
30 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
31 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
32 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
33 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
34 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
35 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
36 import org
.eclipse
.jface
.viewers
.LabelProvider
;
37 import org
.eclipse
.jface
.viewers
.Viewer
;
38 import org
.eclipse
.jface
.window
.Window
;
39 import org
.eclipse
.remote
.core
.IRemoteFileService
;
40 import org
.eclipse
.swt
.SWT
;
41 import org
.eclipse
.swt
.custom
.CCombo
;
42 import org
.eclipse
.swt
.events
.SelectionAdapter
;
43 import org
.eclipse
.swt
.events
.SelectionEvent
;
44 import org
.eclipse
.swt
.graphics
.Image
;
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
.tracecompass
.internal
.lttng2
.control
.ui
.Activator
;
56 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.messages
.Messages
;
57 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.model
.impl
.TraceSessionComponent
;
58 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.proxy
.RemoteSystemProxy
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTracesFolder
;
60 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
61 import org
.eclipse
.ui
.ISharedImages
;
62 import org
.eclipse
.ui
.PlatformUI
;
66 * Dialog box for collecting trace import information.
69 * @author Bernd Hufmann
71 public class ImportDialog
extends Dialog
implements IImportDialog
{
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
76 /** The icon file for this dialog box. */
77 public static final String IMPORT_ICON_FILE
= "icons/elcl16/import_trace.gif"; //$NON-NLS-1$
79 /** Parent directory for UST traces */
80 public static final String UST_PARENT_DIRECTORY
= "ust"; //$NON-NLS-1$
82 /** Name of metadata file of trace */
83 public static final String METADATA_FILE_NAME
= "metadata"; //$NON-NLS-1$
85 // ------------------------------------------------------------------------
87 // ------------------------------------------------------------------------
89 * The dialog composite.
91 private Composite fDialogComposite
= null;
93 * The checkbox tree viewer for selecting available traces
95 private CheckboxTreeViewer fFolderViewer
;
97 * The combo box for selecting a project.
99 private CCombo fCombo
;
101 * The overwrite button
103 private Button fOverwriteButton
;
105 * List of available LTTng 2.0 projects
107 private List
<IProject
> fProjects
;
109 * The parent where the new node should be added.
111 private TraceSessionComponent fSession
= null;
113 * The name of the default project name
115 private String fDefaultProjectName
= null;
117 * List of traces to import
119 private final List
<ImportFileInfo
> fTraces
= new ArrayList
<>();
121 * Selection index in project combo box.
123 private int fProjectIndex
;
125 * Flag to indicate that something went wrong when creating the dialog box.
127 private boolean fIsError
= false;
129 * Children of the remote folder (can be null)
131 private Object
[] fFolderChildren
= null;
133 // ------------------------------------------------------------------------
135 // ------------------------------------------------------------------------
140 * - a shell for the display of the dialog
142 public ImportDialog(Shell shell
) {
144 setShellStyle(SWT
.RESIZE
| getShellStyle());
147 // ------------------------------------------------------------------------
149 // ------------------------------------------------------------------------
152 public List
<ImportFileInfo
> getTracePathes() {
153 List
<ImportFileInfo
> retList
= new ArrayList
<>();
154 retList
.addAll(fTraces
);
159 public IProject
getProject() {
160 return fProjects
.get(fProjectIndex
);
164 public void setSession(TraceSessionComponent session
) {
169 public void setDefaultProject(String defaultProject
) {
170 fDefaultProjectName
= defaultProject
;
173 // ------------------------------------------------------------------------
175 // ------------------------------------------------------------------------
178 protected void configureShell(Shell newShell
) {
179 super.configureShell(newShell
);
180 newShell
.setText(Messages
.TraceControl_ImportDialogTitle
);
181 newShell
.setImage(Activator
.getDefault().loadIcon(IMPORT_ICON_FILE
));
185 protected Control
createDialogArea(Composite parent
) {
188 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
189 GridLayout layout
= new GridLayout(1, true);
190 fDialogComposite
.setLayout(layout
);
191 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
194 createRemoteComposite();
195 } catch (CoreException e
) {
196 createErrorComposite(parent
, e
.fillInStackTrace());
197 return fDialogComposite
;
199 return fDialogComposite
;
203 protected void createButtonsForButtonBar(Composite parent
) {
204 Button selectAllButton
= createButton(parent
, IDialogConstants
.SELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_SelectAll
, true);
205 selectAllButton
.addSelectionListener(new SelectionAdapter() {
207 public void widgetSelected(SelectionEvent e
) {
208 setFolderChildrenChecked(true);
212 Button deselectAllButton
= createButton(parent
, IDialogConstants
.DESELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_DeselectAll
, true);
213 deselectAllButton
.addSelectionListener(new SelectionAdapter() {
215 public void widgetSelected(SelectionEvent e
) {
216 setFolderChildrenChecked(false);
219 createButton(parent
, IDialogConstants
.CANCEL_ID
, IDialogConstants
.CANCEL_LABEL
, true);
220 createButton(parent
, IDialogConstants
.OK_ID
, IDialogConstants
.OK_LABEL
, true);
221 updateOKButtonEnablement();
225 protected void okPressed() {
228 // Validate input data
231 fProjectIndex
= fCombo
.getSelectionIndex();
233 if (fProjectIndex
< 0) {
234 MessageDialog
.openError(getShell(),
235 Messages
.TraceControl_ImportDialogTitle
,
236 Messages
.TraceControl_ImportDialogNoProjectSelectedError
);
240 IProject project
= fProjects
.get(fProjectIndex
);
241 IFolder traceFolder
= project
.getFolder(TmfTracesFolder
.TRACES_FOLDER_NAME
);
243 if (!traceFolder
.exists()) {
244 // Invalid LTTng 2.0 project
245 MessageDialog
.openError(getShell(),
246 Messages
.TraceControl_ImportDialogTitle
,
247 Messages
.TraceControl_ImportDialogInvalidTracingProject
+ " (" + TmfTracesFolder
.TRACES_FOLDER_NAME
+ ")"); //$NON-NLS-1$//$NON-NLS-2$
251 boolean overwriteAll
= fOverwriteButton
.getSelection();
253 Object
[] checked
= fFolderViewer
.getCheckedElements();
254 for (int i
= 0; i
< checked
.length
; i
++) {
255 IFileStore file
= (IFileStore
) checked
[i
];
256 if (!file
.fetchInfo().isDirectory() && file
.getName().equals(METADATA_FILE_NAME
)) {
257 IFileStore trace
= file
.getParent();
258 IFileStore parent
= trace
.getParent();
260 String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
261 path
= getUnifiedPath(path
);
262 IPath sessionParentPath
= new Path(path
).removeLastSegments(1);
263 IPath traceParentPath
= new Path(parent
.toURI().getPath());
265 IPath relativeTracePath
= traceParentPath
.makeRelativeTo(sessionParentPath
);
267 IFolder destinationFolder
= traceFolder
.getFolder(new Path(relativeTracePath
.toOSString()));
269 ImportFileInfo info
= new ImportFileInfo(trace
, trace
.getName(), destinationFolder
, overwriteAll
);
270 IFolder folder
= destinationFolder
.getFolder(trace
.getName());
272 // Verify if trace directory already exists (and not
274 if (folder
.exists() && !overwriteAll
) {
276 // Ask user for overwrite or new name
277 IImportConfirmationDialog conf
= TraceControlDialogFactory
.getInstance().getImportConfirmationDialog();
278 conf
.setTraceName(trace
.getName());
280 // Don't add trace to list if dialog was cancelled.
281 if (conf
.open() == Window
.OK
) {
282 info
.setOverwrite(conf
.isOverwrite());
283 if (!conf
.isOverwrite()) {
284 info
.setLocalTraceName(conf
.getNewTraceName());
294 if (fTraces
.isEmpty()) {
295 MessageDialog
.openError(getShell(),
296 Messages
.TraceControl_ImportDialogTitle
,
297 Messages
.TraceControl_ImportDialogNoTraceSelectedError
);
302 // validation successful -> call super.okPressed()
306 // ------------------------------------------------------------------------
307 // Helper methods and classes
308 // ------------------------------------------------------------------------
310 private final class FolderCheckStateListener
implements ICheckStateListener
{
312 public void checkStateChanged(CheckStateChangedEvent event
) {
313 Object elem
= event
.getElement();
314 if (elem
instanceof IFileStore
) {
315 IFileStore element
= (IFileStore
) elem
;
316 IFileInfo info
= element
.fetchInfo();
317 if (!info
.isDirectory()) {
318 // A trick to keep selection of a file in sync with the
320 boolean p
= fFolderViewer
.getChecked((element
.getParent()));
321 fFolderViewer
.setChecked(element
, p
);
323 fFolderViewer
.setSubtreeChecked(event
.getElement(), event
.getChecked());
324 if (!event
.getChecked()) {
325 fFolderViewer
.setChecked(element
.getParent(), false);
328 updateOKButtonEnablement();
334 * Helper class for the contents of a folder in a tracing project
336 * @author Bernd Hufmann
338 public static class FolderContentProvider
implements ITreeContentProvider
{
340 public Object
[] getChildren(Object o
) {
342 IFileStore store
= (IFileStore
) o
;
343 if (store
.fetchInfo().isDirectory()) {
344 return store
.childStores(EFS
.NONE
, new NullProgressMonitor());
346 } catch (CoreException e
) {
347 Activator
.getDefault().logError(e
.getMessage(), e
);
349 return new Object
[0];
353 public Object
getParent(Object element
) {
354 return ((IFileStore
) element
).getParent();
358 public void dispose() {
362 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
366 public Object
[] getElements(Object inputElement
) {
367 return getChildren(inputElement
);
371 public boolean hasChildren(Object element
) {
372 return ((IFileStore
) element
).fetchInfo().isDirectory();
377 * Creates a dialog composite with an error message which can be used when
378 * an exception occurred during creation time of the dialog box.
381 * - a parent composite
383 * - a error causing exception
385 private void createErrorComposite(Composite parent
, Throwable e
) {
387 fDialogComposite
.dispose();
389 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
390 GridLayout layout
= new GridLayout(1, true);
391 fDialogComposite
.setLayout(layout
);
392 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
394 Text errorText
= new Text(fDialogComposite
, SWT
.MULTI
);
395 StringBuffer error
= new StringBuffer();
396 error
.append(Messages
.TraceControl_ImportDialogCreationError
);
397 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
398 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
399 error
.append(e
.toString());
400 errorText
.setText(error
.toString());
401 errorText
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
404 private void createRemoteComposite() throws CoreException
{
405 Group contextGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
406 contextGroup
.setText(Messages
.TraceControl_ImportDialogTracesGroupName
);
407 GridLayout layout
= new GridLayout(1, true);
408 contextGroup
.setLayout(layout
);
409 contextGroup
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
411 RemoteSystemProxy proxy
= fSession
.getTargetNode().getRemoteSystemProxy();
413 IRemoteFileService fsss
= proxy
.getRemoteConnection().getService(IRemoteFileService
.class);
419 final String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
420 final IFileStore remoteFolder
= fsss
.getResource(path
);
422 fFolderViewer
= new CheckboxTreeViewer(contextGroup
, SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.H_SCROLL
);
423 GridData data
= new GridData(GridData
.FILL_BOTH
);
424 Tree tree
= fFolderViewer
.getTree();
425 tree
.setLayoutData(data
);
426 tree
.setFont(fDialogComposite
.getFont());
427 tree
.setToolTipText(Messages
.TraceControl_ImportDialogTracesTooltip
);
429 fFolderViewer
.setContentProvider(new FolderContentProvider());
430 fFolderViewer
.setLabelProvider(new LabelProvider() {
432 public String
getText(Object element
) {
433 return ((IFileStore
) element
).getName();
437 public Image
getImage(Object element
) {
438 if (((IFileStore
) element
).fetchInfo().isDirectory()) {
439 return PlatformUI
.getWorkbench().getSharedImages().getImage(ISharedImages
.IMG_OBJ_FOLDER
);
441 return PlatformUI
.getWorkbench().getSharedImages().getImage(ISharedImages
.IMG_OBJ_FILE
);
445 fFolderViewer
.addCheckStateListener(new FolderCheckStateListener());
446 fFolderViewer
.setInput(remoteFolder
);
448 fFolderChildren
= remoteFolder
.childStores(EFS
.NONE
, new NullProgressMonitor());
449 // children can be null if there the path doesn't exist. This happens
451 // session hadn't been started and no output was created.
452 setFolderChildrenChecked(true);
454 Group projectGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
455 projectGroup
.setText(Messages
.TraceControl_ImportDialogProjectsGroupName
);
456 layout
= new GridLayout(1, true);
457 projectGroup
.setLayout(layout
);
458 projectGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
460 fProjects
= new ArrayList
<>();
461 List
<String
> projectNames
= new ArrayList
<>();
463 for (IProject project
: TraceUtils
.getOpenedTmfProjects()) {
464 fProjects
.add(project
);
465 projectNames
.add(project
.getName());
468 fCombo
= new CCombo(projectGroup
, SWT
.READ_ONLY
);
469 fCombo
.setToolTipText(Messages
.TraceControl_ImportDialogProjectsTooltip
);
470 fCombo
.setLayoutData(new GridData(GridData
.FILL
, GridData
.CENTER
, true, false, 1, 1));
471 fCombo
.setItems(projectNames
.toArray(new String
[projectNames
.size()]));
473 if (fDefaultProjectName
!= null) {
474 int select
= projectNames
.indexOf(fDefaultProjectName
);
475 fCombo
.select(select
);
478 Group overrideGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
479 layout
= new GridLayout(1, true);
480 overrideGroup
.setLayout(layout
);
481 overrideGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
483 fOverwriteButton
= new Button(overrideGroup
, SWT
.CHECK
);
484 fOverwriteButton
.setText(Messages
.TraceControl_ImportDialogOverwriteButtonText
);
485 getShell().setMinimumSize(new Point(500, 400));
488 private void setFolderChildrenChecked(boolean isChecked
) {
489 if (fFolderChildren
!= null) {
490 for (Object child
: fFolderChildren
) {
491 fFolderViewer
.setSubtreeChecked(child
, isChecked
);
494 updateOKButtonEnablement();
497 private void updateOKButtonEnablement() {
498 Object
[] checked
= fFolderViewer
.getCheckedElements();
499 Button okButton
= getButton(IDialogConstants
.OK_ID
);
500 if (okButton
!= null) {
501 okButton
.setEnabled(checked
.length
> 0);
505 private static String
getUnifiedPath(String path
) {
506 // Use Path class to remove unnecessary slashes
507 return new Path(path
).removeTrailingSeparator().toString();