1 /**********************************************************************
2 * Copyright (c) 2012, 2013 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
.ui
.views
.control
.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
.jface
.dialogs
.Dialog
;
23 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
24 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
25 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
26 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
27 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
28 import org
.eclipse
.jface
.window
.Window
;
29 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.Activator
;
30 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.messages
.Messages
;
31 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.model
.impl
.TraceSessionComponent
;
32 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.remote
.IRemoteSystemProxy
;
33 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
34 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TraceUtils
;
35 import org
.eclipse
.rse
.core
.subsystems
.RemoteChildrenContentsType
;
36 import org
.eclipse
.rse
.services
.clientserver
.messages
.SystemMessageException
;
37 import org
.eclipse
.rse
.subsystems
.files
.core
.servicesubsystem
.IFileServiceSubSystem
;
38 import org
.eclipse
.rse
.subsystems
.files
.core
.subsystems
.IRemoteFile
;
39 import org
.eclipse
.swt
.SWT
;
40 import org
.eclipse
.swt
.custom
.CCombo
;
41 import org
.eclipse
.swt
.events
.SelectionAdapter
;
42 import org
.eclipse
.swt
.events
.SelectionEvent
;
43 import org
.eclipse
.swt
.graphics
.Point
;
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
.swt
.widgets
.Group
;
50 import org
.eclipse
.swt
.widgets
.Shell
;
51 import org
.eclipse
.swt
.widgets
.Text
;
52 import org
.eclipse
.swt
.widgets
.Tree
;
53 import org
.eclipse
.ui
.model
.WorkbenchContentProvider
;
54 import org
.eclipse
.ui
.model
.WorkbenchLabelProvider
;
58 * Dialog box for collecting trace import information.
61 * @author Bernd Hufmann
63 public class ImportDialog
extends Dialog
implements IImportDialog
{
65 // ------------------------------------------------------------------------
67 // ------------------------------------------------------------------------
68 /** The icon file for this dialog box. */
69 public static final String IMPORT_ICON_FILE
= "icons/elcl16/import_trace.gif"; //$NON-NLS-1$
71 /** Parent directory for UST traces */
72 public static final String UST_PARENT_DIRECTORY
= "ust"; //$NON-NLS-1$
74 /** Name of metadata file of trace */
75 public static final String METADATA_FILE_NAME
= "metadata"; //$NON-NLS-1$
77 /** Default name of kernel traces */
78 public static final String DEFAULT_KERNEL_TRACE_NAME
= "kernel"; //$NON-NLS-1$
80 // ------------------------------------------------------------------------
82 // ------------------------------------------------------------------------
84 * The dialog composite.
86 private Composite fDialogComposite
= null;
88 * The checkbox tree viewer for selecting available traces
90 private CheckboxTreeViewer fFolderViewer
;
92 * The combo box for selecting a project.
94 private CCombo fCombo
;
96 * The overwrite button
98 private Button fOverwriteButton
;
100 * List of available LTTng 2.0 projects
102 private List
<IProject
> fProjects
;
104 * The parent where the new node should be added.
106 private TraceSessionComponent fSession
= null;
109 * The name of the default project name
111 private String fDefaultProjectName
= null;
113 * List of traces to import
115 private final List
<ImportFileInfo
> fTraces
= new ArrayList
<ImportFileInfo
>();
117 * Selection index in project combo box.
119 private int fProjectIndex
;
121 * Flag to indicate that something went wrong when creating the dialog box.
123 private boolean fIsError
= false;
125 * Children of the remote folder (can be null)
127 private Object
[] fFolderChildren
= null;
129 // ------------------------------------------------------------------------
131 // ------------------------------------------------------------------------
134 * @param shell - a shell for the display of the dialog
136 public ImportDialog(Shell shell
) {
138 setShellStyle(SWT
.RESIZE
| getShellStyle());
141 // ------------------------------------------------------------------------
143 // ------------------------------------------------------------------------
146 public List
<ImportFileInfo
> getTracePathes() {
147 List
<ImportFileInfo
> retList
= new ArrayList
<ImportFileInfo
>();
148 retList
.addAll(fTraces
);
153 public IProject
getProject() {
154 return fProjects
.get(fProjectIndex
);
158 public void setSession(TraceSessionComponent session
) {
163 public void setDefaultProject(String defaultProject
) {
164 fDefaultProjectName
= defaultProject
;
167 // ------------------------------------------------------------------------
169 // ------------------------------------------------------------------------
172 protected void configureShell(Shell newShell
) {
173 super.configureShell(newShell
);
174 newShell
.setText(Messages
.TraceControl_ImportDialogTitle
);
175 newShell
.setImage(Activator
.getDefault().loadIcon(IMPORT_ICON_FILE
));
179 protected Control
createDialogArea(Composite parent
) {
182 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
183 GridLayout layout
= new GridLayout(1, true);
184 fDialogComposite
.setLayout(layout
);
185 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
188 createRemoteComposite();
189 } catch (SystemMessageException e
) {
190 createErrorComposite(parent
, e
.fillInStackTrace());
191 return fDialogComposite
;
193 return fDialogComposite
;
197 protected void createButtonsForButtonBar(Composite parent
) {
198 Button selectAllButton
= createButton(parent
, IDialogConstants
.SELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_SelectAll
, true);
199 selectAllButton
.addSelectionListener(new SelectionAdapter() {
201 public void widgetSelected(SelectionEvent e
) {
202 setFolderChildrenChecked(true);
206 Button deselectAllButton
= createButton(parent
, IDialogConstants
.DESELECT_ALL_ID
, Messages
.TraceControl_ImportDialog_DeselectAll
, true);
207 deselectAllButton
.addSelectionListener(new SelectionAdapter() {
209 public void widgetSelected(SelectionEvent e
) {
210 setFolderChildrenChecked(false);
213 createButton(parent
, IDialogConstants
.CANCEL_ID
, IDialogConstants
.CANCEL_LABEL
, true);
214 createButton(parent
, IDialogConstants
.OK_ID
, IDialogConstants
.OK_LABEL
, true);
215 updateOKButtonEnablement();
219 protected void okPressed() {
222 // Validate input data
225 fProjectIndex
= fCombo
.getSelectionIndex();
227 if (fProjectIndex
< 0) {
228 MessageDialog
.openError(getShell(),
229 Messages
.TraceControl_ImportDialogTitle
,
230 Messages
.TraceControl_ImportDialogNoProjectSelectedError
);
234 IProject project
= fProjects
.get(fProjectIndex
);
235 IFolder traceFolder
= project
.getFolder(TmfTraceFolder
.TRACE_FOLDER_NAME
);
237 if (!traceFolder
.exists()) {
238 // Invalid LTTng 2.0 project
239 MessageDialog
.openError(getShell(),
240 Messages
.TraceControl_ImportDialogTitle
,
241 Messages
.TraceControl_ImportDialogInvalidTracingProject
+ " (" + TmfTraceFolder
.TRACE_FOLDER_NAME
+ ")"); //$NON-NLS-1$//$NON-NLS-2$
245 boolean overwriteAll
= fOverwriteButton
.getSelection();
247 Object
[] checked
= fFolderViewer
.getCheckedElements();
248 for (int i
= 0; i
< checked
.length
; i
++) {
249 IRemoteFile file
= (IRemoteFile
) checked
[i
];
250 if (!file
.isDirectory() && file
.getName().equals(METADATA_FILE_NAME
)) {
251 IRemoteFile trace
= file
.getParentRemoteFile();
252 IRemoteFile parent
= trace
.getParentRemoteFile();
253 boolean isKernel
= false;
254 if (trace
.getName().equals(DEFAULT_KERNEL_TRACE_NAME
)) {
257 StringBuffer traceName
= new StringBuffer();
258 traceName
.append(trace
.getName());
259 traceName
.insert(0, '-');
261 String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
263 while (!parent
.getAbsolutePath().equals(path
)) {
264 traceName
.insert(0, parent
.getName());
265 traceName
.insert(0, '-');
266 parent
= parent
.getParentRemoteFile();
268 traceName
.insert(0, parent
.getName());
270 ImportFileInfo info
= new ImportFileInfo(trace
, traceName
.toString(), overwriteAll
, isKernel
);
271 IFolder folder
= traceFolder
.getFolder(traceName
.toString());
273 // Verify if trace directory already exists (and not overwrite)
274 if (folder
.exists() && !overwriteAll
) {
276 // Ask user for overwrite or new name
277 IImportConfirmationDialog conf
= TraceControlDialogFactory
.getInstance().getImportConfirmationDialog();
278 conf
.setTraceName(traceName
.toString());
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 // ------------------------------------------------------------------------
311 * Helper class for the contents of a folder in a tracing project
313 * @author Bernd Hufmann
315 public static class FolderContentProvider
extends WorkbenchContentProvider
{
317 public Object
[] getChildren(Object o
) {
318 if (o
instanceof IRemoteFile
) {
319 IRemoteFile element
= (IRemoteFile
) o
;
320 // For our purpose, we need folders + files
321 if (!element
.isDirectory()) {
322 return new Object
[0];
325 return super.getChildren(o
);
330 * Creates a dialog composite with an error message which can be used
331 * when an exception occurred during creation time of the dialog box.
332 * @param parent - a parent composite
333 * @param e - a error causing exception
335 private void createErrorComposite(Composite parent
, Throwable e
) {
337 fDialogComposite
.dispose();
339 fDialogComposite
= new Composite(parent
, SWT
.NONE
);
340 GridLayout layout
= new GridLayout(1, true);
341 fDialogComposite
.setLayout(layout
);
342 fDialogComposite
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
344 Text errorText
= new Text(fDialogComposite
, SWT
.MULTI
);
345 StringBuffer error
= new StringBuffer();
346 error
.append(Messages
.TraceControl_ImportDialogCreationError
);
347 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
348 error
.append(System
.getProperty("line.separator")); //$NON-NLS-1$
349 error
.append(e
.toString());
350 errorText
.setText(error
.toString());
351 errorText
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
354 private void createRemoteComposite() throws SystemMessageException
{
355 Group contextGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
356 contextGroup
.setText(Messages
.TraceControl_ImportDialogTracesGroupName
);
357 GridLayout layout
= new GridLayout(1, true);
358 contextGroup
.setLayout(layout
);
359 contextGroup
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
361 IRemoteSystemProxy proxy
= fSession
.getTargetNode().getRemoteSystemProxy();
363 IFileServiceSubSystem fsss
= proxy
.getFileServiceSubSystem();
365 final String path
= fSession
.isSnapshotSession() ? fSession
.getSnapshotInfo().getSnapshotPath() : fSession
.getSessionPath();
366 final IRemoteFile remoteFolder
= fsss
.getRemoteFileObject(path
, new NullProgressMonitor());
367 // make sure that remote directory is read and not cached
368 remoteFolder
.markStale(true, true);
370 fFolderViewer
= new CheckboxTreeViewer(contextGroup
, SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.H_SCROLL
);
371 GridData data
= new GridData(GridData
.FILL_BOTH
);
372 Tree tree
= fFolderViewer
.getTree();
373 tree
.setLayoutData(data
);
374 tree
.setFont(fDialogComposite
.getFont());
375 tree
.setToolTipText(Messages
.TraceControl_ImportDialogTracesTooltip
);
377 fFolderViewer
.setContentProvider(new FolderContentProvider());
378 fFolderViewer
.setLabelProvider(new WorkbenchLabelProvider());
380 fFolderViewer
.addCheckStateListener(new ICheckStateListener() {
382 public void checkStateChanged(CheckStateChangedEvent event
) {
383 Object elem
= event
.getElement();
384 if (elem
instanceof IRemoteFile
) {
385 IRemoteFile element
= (IRemoteFile
) elem
;
386 if (!element
.isDirectory()) {
387 // A trick to keep selection of a file in sync with the directory
388 boolean p
= fFolderViewer
.getChecked((element
.getParentRemoteFile()));
389 fFolderViewer
.setChecked(element
, p
);
391 fFolderViewer
.setSubtreeChecked(event
.getElement(), event
.getChecked());
392 if (!event
.getChecked()) {
393 fFolderViewer
.setChecked(element
.getParentRemoteFile(), false);
396 updateOKButtonEnablement();
400 fFolderViewer
.setInput(remoteFolder
);
402 fFolderChildren
= remoteFolder
.getContents(RemoteChildrenContentsType
.getInstance());
403 // children can be null if there the path doesn't exist. This happens when a trace
404 // session hadn't been started and no output was created.
405 setFolderChildrenChecked(true);
407 Group projectGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
408 projectGroup
.setText(Messages
.TraceControl_ImportDialogProjectsGroupName
);
409 layout
= new GridLayout(1, true);
410 projectGroup
.setLayout(layout
);
411 projectGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
413 fProjects
= new ArrayList
<IProject
>();
414 List
<String
> projectNames
= new ArrayList
<String
>();
416 for (IProject project
: TraceUtils
.getOpenedTmfProjects()) {
417 fProjects
.add(project
);
418 projectNames
.add(project
.getName());
421 fCombo
= new CCombo(projectGroup
, SWT
.READ_ONLY
);
422 fCombo
.setToolTipText(Messages
.TraceControl_ImportDialogProjectsTooltip
);
423 fCombo
.setLayoutData(new GridData(GridData
.FILL
, GridData
.CENTER
, true, false, 1, 1));
424 fCombo
.setItems(projectNames
.toArray(new String
[projectNames
.size()]));
426 if (fDefaultProjectName
!= null) {
427 int select
= projectNames
.indexOf(fDefaultProjectName
);
428 fCombo
.select(select
);
431 Group overrideGroup
= new Group(fDialogComposite
, SWT
.SHADOW_NONE
);
432 layout
= new GridLayout(1, true);
433 overrideGroup
.setLayout(layout
);
434 overrideGroup
.setLayoutData(new GridData(GridData
.FILL_HORIZONTAL
));
436 fOverwriteButton
= new Button(overrideGroup
, SWT
.CHECK
);
437 fOverwriteButton
.setText(Messages
.TraceControl_ImportDialogOverwriteButtonText
);
438 getShell().setMinimumSize(new Point(500, 400));
441 private void setFolderChildrenChecked(boolean isChecked
) {
442 if (fFolderChildren
!= null) {
443 for (Object child
: fFolderChildren
) {
444 fFolderViewer
.setSubtreeChecked(child
, isChecked
);
447 updateOKButtonEnablement();
450 private void updateOKButtonEnablement() {
451 Object
[] checked
= fFolderViewer
.getCheckedElements();
452 Button okButton
= getButton(IDialogConstants
.OK_ID
);
453 if (okButton
!= null) {
454 okButton
.setEnabled(checked
.length
> 0);