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
.NullProgressMonitor
;
22 import org
.eclipse
.core
.runtime
.Path
;
23 import org
.eclipse
.jface
.dialogs
.Dialog
;
24 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
25 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
26 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
27 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
28 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
29 import org
.eclipse
.jface
.window
.Window
;
30 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.Activator
;
31 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.messages
.Messages
;
32 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.model
.impl
.TraceSessionComponent
;
33 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.remote
.IRemoteSystemProxy
;
34 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
35 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TraceUtils
;
36 import org
.eclipse
.rse
.core
.subsystems
.RemoteChildrenContentsType
;
37 import org
.eclipse
.rse
.services
.clientserver
.messages
.SystemMessageException
;
38 import org
.eclipse
.rse
.subsystems
.files
.core
.servicesubsystem
.IFileServiceSubSystem
;
39 import org
.eclipse
.rse
.subsystems
.files
.core
.subsystems
.IRemoteFile
;
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
.Point
;
45 import org
.eclipse
.swt
.layout
.GridData
;
46 import org
.eclipse
.swt
.layout
.GridLayout
;
47 import org
.eclipse
.swt
.widgets
.Button
;
48 import org
.eclipse
.swt
.widgets
.Composite
;
49 import org
.eclipse
.swt
.widgets
.Control
;
50 import org
.eclipse
.swt
.widgets
.Group
;
51 import org
.eclipse
.swt
.widgets
.Shell
;
52 import org
.eclipse
.swt
.widgets
.Text
;
53 import org
.eclipse
.swt
.widgets
.Tree
;
54 import org
.eclipse
.ui
.model
.WorkbenchContentProvider
;
55 import org
.eclipse
.ui
.model
.WorkbenchLabelProvider
;
59 * Dialog box for collecting trace import information.
62 * @author Bernd Hufmann
64 public class ImportDialog
extends Dialog
implements IImportDialog
{
66 // ------------------------------------------------------------------------
68 // ------------------------------------------------------------------------
69 /** The icon file for this dialog box. */
70 public static final String IMPORT_ICON_FILE
= "icons/elcl16/import_trace.gif"; //$NON-NLS-1$
72 /** Parent directory for UST traces */
73 public static final String UST_PARENT_DIRECTORY
= "ust"; //$NON-NLS-1$
75 /** Name of metadata file of trace */
76 public static final String METADATA_FILE_NAME
= "metadata"; //$NON-NLS-1$
78 /** Default name of kernel traces */
79 public static final String DEFAULT_KERNEL_TRACE_NAME
= "kernel"; //$NON-NLS-1$
81 // ------------------------------------------------------------------------
83 // ------------------------------------------------------------------------
85 * The dialog composite.
87 private Composite fDialogComposite
= null;
89 * The checkbox tree viewer for selecting available traces
91 private CheckboxTreeViewer fFolderViewer
;
93 * The combo box for selecting a project.
95 private CCombo fCombo
;
97 * The overwrite button
99 private Button fOverwriteButton
;
101 * List of available LTTng 2.0 projects
103 private List
<IProject
> fProjects
;
105 * The parent where the new node should be added.
107 private TraceSessionComponent fSession
= null;
110 * The name of the default project name
112 private String fDefaultProjectName
= null;
114 * List of traces to import
116 private final List
<ImportFileInfo
> fTraces
= new ArrayList
<>();
118 * Selection index in project combo box.
120 private int fProjectIndex
;
122 * Flag to indicate that something went wrong when creating the dialog box.
124 private boolean fIsError
= false;
126 * Children of the remote folder (can be null)
128 private Object
[] fFolderChildren
= null;
130 // ------------------------------------------------------------------------
132 // ------------------------------------------------------------------------
135 * @param shell - a shell for the display of the dialog
137 public ImportDialog(Shell shell
) {
139 setShellStyle(SWT
.RESIZE
| getShellStyle());
142 // ------------------------------------------------------------------------
144 // ------------------------------------------------------------------------
147 public List
<ImportFileInfo
> getTracePathes() {
148 List
<ImportFileInfo
> retList
= new ArrayList
<>();
149 retList
.addAll(fTraces
);
154 public IProject
getProject() {
155 return fProjects
.get(fProjectIndex
);
159 public void setSession(TraceSessionComponent session
) {
164 public void setDefaultProject(String defaultProject
) {
165 fDefaultProjectName
= defaultProject
;
168 // ------------------------------------------------------------------------
170 // ------------------------------------------------------------------------
173 protected void configureShell(Shell newShell
) {
174 super.configureShell(newShell
);
175 newShell
.setText(Messages
.TraceControl_ImportDialogTitle
);
176 newShell
.setImage(Activator
.getDefault().loadIcon(IMPORT_ICON_FILE
));
180 protected Control
createDialogArea(Composite parent
) {
183 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
184 GridLayout layout
= new GridLayout(1, true);
185 fDialogComposite
.setLayout(layout
);
186 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
189 createRemoteComposite();
190 } catch (SystemMessageException e
) {
191 createErrorComposite(parent
, e
.fillInStackTrace());
192 return fDialogComposite
;
194 return fDialogComposite
;
198 protected void createButtonsForButtonBar(Composite parent
) {
199 Button selectAllButton
= createButton(parent
, IDialogConstants
.SELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_SelectAll
, true);
200 selectAllButton
.addSelectionListener(new SelectionAdapter() {
202 public void widgetSelected(SelectionEvent e
) {
203 setFolderChildrenChecked(true);
207 Button deselectAllButton
= createButton(parent
, IDialogConstants
.DESELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_DeselectAll
, true);
208 deselectAllButton
.addSelectionListener(new SelectionAdapter() {
210 public void widgetSelected(SelectionEvent e
) {
211 setFolderChildrenChecked(false);
214 createButton(parent
, IDialogConstants
.CANCEL_ID
, IDialogConstants
.CANCEL_LABEL
, true);
215 createButton(parent
, IDialogConstants
.OK_ID
, IDialogConstants
.OK_LABEL
, true);
216 updateOKButtonEnablement();
220 protected void okPressed() {
223 // Validate input data
226 fProjectIndex
= fCombo
.getSelectionIndex();
228 if (fProjectIndex
< 0) {
229 MessageDialog
.openError(getShell(),
230 Messages
.TraceControl_ImportDialogTitle
,
231 Messages
.TraceControl_ImportDialogNoProjectSelectedError
);
235 IProject project
= fProjects
.get(fProjectIndex
);
236 IFolder traceFolder
= project
.getFolder(TmfTraceFolder
.TRACE_FOLDER_NAME
);
238 if (!traceFolder
.exists()) {
239 // Invalid LTTng 2.0 project
240 MessageDialog
.openError(getShell(),
241 Messages
.TraceControl_ImportDialogTitle
,
242 Messages
.TraceControl_ImportDialogInvalidTracingProject
+ " (" + TmfTraceFolder
.TRACE_FOLDER_NAME
+ ")"); //$NON-NLS-1$//$NON-NLS-2$
246 boolean overwriteAll
= fOverwriteButton
.getSelection();
248 Object
[] checked
= fFolderViewer
.getCheckedElements();
249 for (int i
= 0; i
< checked
.length
; i
++) {
250 IRemoteFile file
= (IRemoteFile
) checked
[i
];
251 if (!file
.isDirectory() && file
.getName().equals(METADATA_FILE_NAME
)) {
252 IRemoteFile trace
= file
.getParentRemoteFile();
253 IRemoteFile parent
= trace
.getParentRemoteFile();
254 boolean isKernel
= false;
255 if (trace
.getName().equals(DEFAULT_KERNEL_TRACE_NAME
)) {
258 StringBuffer traceName
= new StringBuffer();
259 traceName
.append(trace
.getName());
260 traceName
.insert(0, '-');
262 String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
263 path
= getUnifiedPath(path
);
264 String parentPath
= getUnifiedPath(parent
.getAbsolutePath());
266 while (!parentPath
.equals(path
)) {
267 traceName
.insert(0, parent
.getName());
268 traceName
.insert(0, '-');
269 parent
= parent
.getParentRemoteFile();
270 parentPath
= getUnifiedPath(parent
.getAbsolutePath());
272 traceName
.insert(0, parent
.getName());
274 ImportFileInfo info
= new ImportFileInfo(trace
, traceName
.toString(), overwriteAll
, isKernel
);
275 IFolder folder
= traceFolder
.getFolder(traceName
.toString());
277 // Verify if trace directory already exists (and not overwrite)
278 if (folder
.exists() && !overwriteAll
) {
280 // Ask user for overwrite or new name
281 IImportConfirmationDialog conf
= TraceControlDialogFactory
.getInstance().getImportConfirmationDialog();
282 conf
.setTraceName(traceName
.toString());
284 // Don't add trace to list if dialog was cancelled.
285 if (conf
.open() == Window
.OK
) {
286 info
.setOverwrite(conf
.isOverwrite());
287 if (!conf
.isOverwrite()) {
288 info
.setLocalTraceName(conf
.getNewTraceName());
298 if (fTraces
.isEmpty()) {
299 MessageDialog
.openError(getShell(),
300 Messages
.TraceControl_ImportDialogTitle
,
301 Messages
.TraceControl_ImportDialogNoTraceSelectedError
);
306 // validation successful -> call super.okPressed()
310 // ------------------------------------------------------------------------
311 // Helper methods and classes
312 // ------------------------------------------------------------------------
315 * Helper class for the contents of a folder in a tracing project
317 * @author Bernd Hufmann
319 public static class FolderContentProvider
extends WorkbenchContentProvider
{
321 public Object
[] getChildren(Object o
) {
322 if (o
instanceof IRemoteFile
) {
323 IRemoteFile element
= (IRemoteFile
) o
;
324 // For our purpose, we need folders + files
325 if (!element
.isDirectory()) {
326 return new Object
[0];
329 return super.getChildren(o
);
334 * Creates a dialog composite with an error message which can be used
335 * when an exception occurred during creation time of the dialog box.
336 * @param parent - a parent composite
337 * @param e - a error causing exception
339 private void createErrorComposite(Composite parent
, Throwable e
) {
341 fDialogComposite
.dispose();
343 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
344 GridLayout layout
= new GridLayout(1, true);
345 fDialogComposite
.setLayout(layout
);
346 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
348 Text errorText
= new Text(fDialogComposite
, SWT
.MULTI
);
349 StringBuffer error
= new StringBuffer();
350 error
.append(Messages
.TraceControl_ImportDialogCreationError
);
351 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
352 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
353 error
.append(e
.toString());
354 errorText
.setText(error
.toString());
355 errorText
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
358 private void createRemoteComposite() throws SystemMessageException
{
359 Group contextGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
360 contextGroup
.setText(Messages
.TraceControl_ImportDialogTracesGroupName
);
361 GridLayout layout
= new GridLayout(1, true);
362 contextGroup
.setLayout(layout
);
363 contextGroup
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
365 IRemoteSystemProxy proxy
= fSession
.getTargetNode().getRemoteSystemProxy();
367 IFileServiceSubSystem fsss
= proxy
.getFileServiceSubSystem();
369 final String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
370 final IRemoteFile remoteFolder
= fsss
.getRemoteFileObject(path
, new NullProgressMonitor());
371 // make sure that remote directory is read and not cached
372 remoteFolder
.markStale(true, true);
374 fFolderViewer
= new CheckboxTreeViewer(contextGroup
, SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.H_SCROLL
);
375 GridData data
= new GridData(GridData
.FILL_BOTH
);
376 Tree tree
= fFolderViewer
.getTree();
377 tree
.setLayoutData(data
);
378 tree
.setFont(fDialogComposite
.getFont());
379 tree
.setToolTipText(Messages
.TraceControl_ImportDialogTracesTooltip
);
381 fFolderViewer
.setContentProvider(new FolderContentProvider());
382 fFolderViewer
.setLabelProvider(new WorkbenchLabelProvider());
384 fFolderViewer
.addCheckStateListener(new ICheckStateListener() {
386 public void checkStateChanged(CheckStateChangedEvent event
) {
387 Object elem
= event
.getElement();
388 if (elem
instanceof IRemoteFile
) {
389 IRemoteFile element
= (IRemoteFile
) elem
;
390 if (!element
.isDirectory()) {
391 // A trick to keep selection of a file in sync with the directory
392 boolean p
= fFolderViewer
.getChecked((element
.getParentRemoteFile()));
393 fFolderViewer
.setChecked(element
, p
);
395 fFolderViewer
.setSubtreeChecked(event
.getElement(), event
.getChecked());
396 if (!event
.getChecked()) {
397 fFolderViewer
.setChecked(element
.getParentRemoteFile(), false);
400 updateOKButtonEnablement();
404 fFolderViewer
.setInput(remoteFolder
);
406 fFolderChildren
= remoteFolder
.getContents(RemoteChildrenContentsType
.getInstance());
407 // children can be null if there the path doesn't exist. This happens when a trace
408 // session hadn't been started and no output was created.
409 setFolderChildrenChecked(true);
411 Group projectGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
412 projectGroup
.setText(Messages
.TraceControl_ImportDialogProjectsGroupName
);
413 layout
= new GridLayout(1, true);
414 projectGroup
.setLayout(layout
);
415 projectGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
417 fProjects
= new ArrayList
<>();
418 List
<String
> projectNames
= new ArrayList
<>();
420 for (IProject project
: TraceUtils
.getOpenedTmfProjects()) {
421 fProjects
.add(project
);
422 projectNames
.add(project
.getName());
425 fCombo
= new CCombo(projectGroup
, SWT
.READ_ONLY
);
426 fCombo
.setToolTipText(Messages
.TraceControl_ImportDialogProjectsTooltip
);
427 fCombo
.setLayoutData(new GridData(GridData
.FILL
, GridData
.CENTER
, true, false, 1, 1));
428 fCombo
.setItems(projectNames
.toArray(new String
[projectNames
.size()]));
430 if (fDefaultProjectName
!= null) {
431 int select
= projectNames
.indexOf(fDefaultProjectName
);
432 fCombo
.select(select
);
435 Group overrideGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
436 layout
= new GridLayout(1, true);
437 overrideGroup
.setLayout(layout
);
438 overrideGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
440 fOverwriteButton
= new Button(overrideGroup
, SWT
.CHECK
);
441 fOverwriteButton
.setText(Messages
.TraceControl_ImportDialogOverwriteButtonText
);
442 getShell().setMinimumSize(new Point(500, 400));
445 private void setFolderChildrenChecked(boolean isChecked
) {
446 if (fFolderChildren
!= null) {
447 for (Object child
: fFolderChildren
) {
448 fFolderViewer
.setSubtreeChecked(child
, isChecked
);
451 updateOKButtonEnablement();
454 private void updateOKButtonEnablement() {
455 Object
[] checked
= fFolderViewer
.getCheckedElements();
456 Button okButton
= getButton(IDialogConstants
.OK_ID
);
457 if (okButton
!= null) {
458 okButton
.setEnabled(checked
.length
> 0);
462 private static String
getUnifiedPath(String path
) {
463 // Use Path class to remove unnecessary slashes
464 return new Path(path
).removeTrailingSeparator().toString();