/********************************************************************** * Copyright (c) 2016 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Roy - Initial API and implementation **********************************************************************/ package org.eclipse.tracecompass.internal.lttng2.control.ui.views.dialogs; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.tracecompass.internal.lttng2.control.core.model.ITraceLogLevel; import org.eclipse.tracecompass.internal.lttng2.control.core.model.LogLevelType; import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceDomainType; import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceJulLogLevel; import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceLog4jLogLevel; import org.eclipse.tracecompass.internal.lttng2.control.core.model.TracePythonLogLevel; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.messages.Messages; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.ITraceControlComponent; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.BaseLoggerComponent; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.TargetNodeComponent; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.TraceControlContentProvider; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.TraceControlLabelProvider; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.TraceProviderGroup; import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.UstProviderComponent; import org.eclipse.ui.dialogs.FilteredTree; import org.eclipse.ui.dialogs.PatternFilter; /** * A composite for collecting information about loggers to be enabled. * * @author Bruno Roy */ public class EnableLoggersComposite extends Composite implements IBaseEnableUstEvents { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ private enum GroupEnum { LOGGERS } // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ /** * The referenced trace provider group containing the loggers providers * component which contains a list of available tracepoints. */ private final TraceProviderGroup fProviderGroup; /** * A button to enable/disable the loggers group */ private Button fLoggersActivateButton; /** * A tree viewer for displaying and selection of available loggers. */ private CheckboxTreeViewer fLoggersViewer; /** * A Text field for the specific logger name. */ private Text fSpecificLoggerText; /** * The flag indicating that loggers are selected. */ private boolean fIsLoggers; /** * The list of loggers to be enabled. */ private List<String> fLoggers; /** * A button to enable/disable the log level group */ private Button fLogLevelActivateButton; /** * A Combo box for selecting the log level. */ private CCombo fLogLevelCombo; /** * A button for selecting the log level (range 0 to level). */ private Button fLogLevelButton; /** * A button for selecting the specified log level only. */ private Button fLogLevelOnlyButton; /** * The flag indicating that all log level are selected. */ private boolean fIsLogLevel; /** * The flag indicating that all loggers (across providers) are selected. */ private boolean fIsAllLoggers; /** * The type of the log level (loglevel or loglevel-only) */ private LogLevelType fLogLevelType; /** * The selected log level. */ private ITraceLogLevel fLogLevel; /** * The domain of the loggers. */ private final TraceDomainType fDomain; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Constructor * * @param parent * a parent composite * @param style * a composite style * @param providerGroup * the trace provider group * @param domain * the domain of the loggers */ public EnableLoggersComposite(Composite parent, int style, TraceProviderGroup providerGroup, TraceDomainType domain) { super(parent, style); fProviderGroup = providerGroup; fDomain = domain; } // ------------------------------------------------------------------------ // Accessors // ------------------------------------------------------------------------ @Override public ITraceLogLevel getLogLevel() { return fLogLevel; } @Override public LogLevelType getLogLevelType() { return fLogLevelType; } @Override public boolean isAllTracePoints() { return fIsAllLoggers; } @Override public List<String> getEventNames() { return new ArrayList<>(fLoggers); } @Override public boolean isLogLevel() { return fIsLogLevel; } // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ /** * Create the contents of this event composite */ public void createContent() { // Logger group createLoggersGroup(); // Log Level Group createLogLevelGroup(); // Set default enablements setEnablements(GroupEnum.LOGGERS); } /** * Validates the loggers composite input data. * * @return true if configured data is valid and can be retrieved. */ public boolean isValid() { fIsLoggers = fLoggersActivateButton.getSelection(); fIsLogLevel = fLogLevelActivateButton.getSelection(); // Initialize loggers fields fLoggers = new ArrayList<>(); if (fIsLoggers) { Set<String> set = new HashSet<>(); Object[] checkedElements = fLoggersViewer.getCheckedElements(); int checkedNbLoggers = 0; for (int i = 0; i < checkedElements.length; i++) { ITraceControlComponent component = (ITraceControlComponent) checkedElements[i]; if (component instanceof BaseLoggerComponent) { checkedNbLoggers++; if (!set.contains(component.getName())) { set.add(component.getName()); fLoggers.add(component.getName()); } } } // verify if all events are selected int nbAvailableLoggers = 0; List<ITraceControlComponent> comps = fProviderGroup.getChildren(UstProviderComponent.class); for (ITraceControlComponent comp : comps) { // We want the children of each UST provider ITraceControlComponent[] events = comp.getChildren(); for (ITraceControlComponent event : events) { if (event instanceof BaseLoggerComponent && fDomain.equals(((BaseLoggerComponent)event).getDomain())) { nbAvailableLoggers++; } } } // Either all available loggers are selected or no loggers are available but All checkbox is selected fIsAllLoggers = ((checkedNbLoggers > 0) && (nbAvailableLoggers == checkedNbLoggers)) || ((nbAvailableLoggers == 0) && fLoggersViewer.getCheckedElements().length == 1); String tmpSpecificLogger = fSpecificLoggerText.getText(); if (!fIsAllLoggers && !tmpSpecificLogger.trim().isEmpty()) { // Format the text to a List<String> // Removing all non visible characters tmpSpecificLogger = tmpSpecificLogger.replaceAll("\\s", ""); //$NON-NLS-1$ //$NON-NLS-2$ // Splitting the different events that are separated by commas List<String> specificLoggerList = Arrays.asList(tmpSpecificLogger.split(",")); //$NON-NLS-1$ fLoggers.addAll(specificLoggerList); fLoggers = fLoggers.stream().distinct().collect(Collectors.toList()); } } // initialize log level event name string fLogLevelType = LogLevelType.LOGLEVEL_NONE; if (fIsLogLevel) { if (fLogLevelButton.getSelection()) { fLogLevelType = LogLevelType.LOGLEVEL; } else if (fLogLevelOnlyButton.getSelection()) { fLogLevelType = LogLevelType.LOGLEVEL_ONLY; } ITraceLogLevel[] levels = getLogLevelNames(); int id = fLogLevelCombo.getSelectionIndex(); if (id < 0) { MessageDialog.openError(getShell(), Messages.TraceControl_EnableLoggersDialogTitle, Messages.TraceControl_InvalidLogLevel); return false; } if (fLoggers.isEmpty() && !fIsAllLoggers) { MessageDialog.openError(getShell(), Messages.TraceControl_EnableLoggersDialogTitle, Messages.TraceControl_InvalidLogger); return false; } if (levels != null) { fLogLevel = levels[id]; } } // validation successful -> call super.okPressed() return true; } // ------------------------------------------------------------------------ // Helper methods // ------------------------------------------------------------------------ private ITraceLogLevel[] getLogLevelNames() { switch (fDomain) { case JUL: return TraceJulLogLevel.values(); case LOG4J: return TraceLog4jLogLevel.values(); case PYTHON: return TracePythonLogLevel.values(); //$CASES-OMITTED$ default: return null; } } /** * Creates loggers group. */ private void createLoggersGroup() { // Create the loggers group Group loggersMainGroup = new Group(this, SWT.SHADOW_NONE); loggersMainGroup.setText(Messages.TraceControl_EnableEventsLoggerGroupName); GridLayout layout = new GridLayout(2, false); loggersMainGroup.setLayout(layout); GridData data = new GridData(GridData.FILL_BOTH); loggersMainGroup.setLayoutData(data); // Create the Select button Composite buttonComposite = new Composite(loggersMainGroup, SWT.NONE); layout = new GridLayout(1, true); buttonComposite.setLayout(layout); data = new GridData(SWT.BEGINNING, SWT.CENTER, false, true); buttonComposite.setLayoutData(data); fLoggersActivateButton = new Button(buttonComposite, SWT.RADIO); fLoggersActivateButton.setText(Messages.TraceControl_EnableGroupSelectionName); data = new GridData(GridData.FILL_HORIZONTAL); fLoggersActivateButton.setLayoutData(data); fLoggersActivateButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setEnablements(GroupEnum.LOGGERS); } }); // Create the group for the tree Group loggersGroup = new Group(loggersMainGroup, SWT.SHADOW_NONE); layout = new GridLayout(1, true); loggersGroup.setLayout(layout); data = new GridData(GridData.FILL_BOTH); loggersGroup.setLayoutData(data); new FilteredTree(loggersGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, new PatternFilter(), true) { @Override protected TreeViewer doCreateTreeViewer(Composite aparent, int style) { fLoggersViewer = new CheckboxTreeViewer(aparent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); fLoggersViewer.getTree().setToolTipText(Messages.TraceControl_EnableEventsLoggerTreeTooltip); fLoggersViewer.setContentProvider(new LoggersContentProvider()); fLoggersViewer.setLabelProvider(new LoggersLabelProvider()); fLoggersViewer.addCheckStateListener(new LoggersCheckStateListener()); fLoggersViewer.setInput(fProviderGroup.getParent()); fLoggersViewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); return fLoggersViewer; } }; Group specificLoggerGroup = new Group(loggersGroup, SWT.SHADOW_NONE); specificLoggerGroup.setText(Messages.TraceControl_EnableEventsSpecificLoggerGroupName); layout = new GridLayout(4, true); specificLoggerGroup.setLayout(layout); specificLoggerGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label specificLoggerLabel = new Label(specificLoggerGroup, SWT.LEFT); specificLoggerLabel.setText(Messages.TraceControl_EnableEventsNameLabel); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 1; specificLoggerLabel.setLayoutData(data); fSpecificLoggerText = new Text(specificLoggerGroup, SWT.LEFT); fSpecificLoggerText.setToolTipText(Messages.TraceControl_EnableEventsSpecificLoggerTooltip); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 3; fSpecificLoggerText.setLayoutData(data); } /** * Creates log level group. */ private void createLogLevelGroup() { Group logLevelMainGroup = new Group(this, SWT.SHADOW_NONE); logLevelMainGroup.setText(Messages.TraceControl_EnableEventsLogLevelGroupName); GridLayout layout = new GridLayout(2, false); logLevelMainGroup.setLayout(layout); GridData data = new GridData(GridData.FILL_HORIZONTAL); logLevelMainGroup.setLayoutData(data); Composite buttonComposite = new Composite(logLevelMainGroup, SWT.NONE); layout = new GridLayout(1, false); buttonComposite.setLayout(layout); data = new GridData(SWT.BEGINNING, SWT.CENTER, false, true); buttonComposite.setLayoutData(data); fLogLevelActivateButton = new Button(buttonComposite, SWT.CHECK); fLogLevelActivateButton.setText(Messages.TraceControl_EnableGroupSelectionName); fLogLevelActivateButton.setSelection(false); data = new GridData(GridData.FILL_HORIZONTAL); fLogLevelActivateButton.setLayoutData(data); fLogLevelActivateButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fLogLevelCombo.setEnabled(fLogLevelActivateButton.getSelection()); fLogLevelButton.setEnabled(fLogLevelActivateButton.getSelection()); fLogLevelOnlyButton.setEnabled(fLogLevelActivateButton.getSelection()); } }); Group logLevelGroup = new Group(logLevelMainGroup, SWT.SHADOW_NONE); layout = new GridLayout(2, true); logLevelGroup.setLayout(layout); logLevelGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fLogLevelButton = new Button(logLevelGroup, SWT.RADIO); fLogLevelButton.setText(Messages.TraceControl_EnableEventsLogLevelTypeName); fLogLevelButton.setToolTipText(Messages.TraceControl_EnableEventsLogLevelTypeTooltip); data = new GridData(GridData.FILL_BOTH); fLogLevelButton.setLayoutData(data); fLogLevelButton.setSelection(true); fLogLevelOnlyButton = new Button(logLevelGroup, SWT.RADIO); fLogLevelOnlyButton.setText(Messages.TraceControl_EnableEventsLogLevelOnlyTypeName); fLogLevelOnlyButton.setToolTipText(Messages.TraceControl_EnableEventsLogLevelOnlyTypeTooltip); data = new GridData(GridData.FILL_BOTH); fLogLevelButton.setLayoutData(data); fLogLevelCombo = new CCombo(logLevelGroup, SWT.READ_ONLY); ITraceLogLevel[] levels = getLogLevelNames(); if (levels != null) { String[] levelNames = new String[levels.length - 1]; int k = 0; for (int i = 0; i < levels.length; i++) { if (levels[i] != TraceJulLogLevel.LEVEL_UNKNOWN && levels[i] != TraceLog4jLogLevel.LEVEL_UNKNOWN && levels[i] != TracePythonLogLevel.LEVEL_UNKNOWN) { levelNames[k++] = levels[i].getInName(); } } fLogLevelCombo.setItems(levelNames); } fLogLevelCombo.setToolTipText(Messages.TraceControl_EnableEventsLogLevelTooltip); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 4; fLogLevelCombo.setLayoutData(data); // By default the combo box and the buttons are not enabled fLogLevelCombo.setEnabled(false); fLogLevelButton.setEnabled(false); fLogLevelOnlyButton.setEnabled(false); } /** * Enable/selects widgets depending on the group specified. * * @param group * group to enable. */ private void setEnablements(GroupEnum group) { // Enable/disable trace point items fLoggersActivateButton.setSelection(group == GroupEnum.LOGGERS); fLoggersViewer.getTree().setEnabled(group == GroupEnum.LOGGERS); } /** * Content provider for the loggers tree. */ public final class LoggersContentProvider extends TraceControlContentProvider { @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof TargetNodeComponent) { List<ITraceControlComponent> children = ((ITraceControlComponent) parentElement).getChildren(TraceProviderGroup.class); return children.toArray(new ITraceControlComponent[children.size()]); } if (parentElement instanceof TraceProviderGroup) { List<ITraceControlComponent> ustProviderChildren = ((ITraceControlComponent) parentElement).getChildren(UstProviderComponent.class) .stream().filter(comp -> ((UstProviderComponent) comp).getLoggerComponents(fDomain).size() > 0) .collect(Collectors.toList()); return ustProviderChildren.toArray(new ITraceControlComponent[ustProviderChildren.size()]); } if (parentElement instanceof UstProviderComponent) { List<ITraceControlComponent> loggers = ((UstProviderComponent) parentElement).getLoggerComponents(fDomain); return loggers.toArray(new ITraceControlComponent[loggers.size()]); } return new Object[0]; } } /** * Content label for the loggers tree. */ public static final class LoggersLabelProvider extends TraceControlLabelProvider { @Override public Image getImage(Object element) { return null; } @Override public String getText(Object element) { if ((element != null) && (element instanceof TraceProviderGroup)) { return Messages.TraceControl_EnableEventsTreeAllLabel; } if ((element != null) && (element instanceof UstProviderComponent)) { return Messages.TraceControl_EnableEventsTreeAllLabel + " - " + ((UstProviderComponent)element).getName(); //$NON-NLS-1$ } return super.getText(element); } } /** * Check state listener for the loggers tree. */ public final class LoggersCheckStateListener implements ICheckStateListener { @Override public void checkStateChanged(CheckStateChangedEvent event) { if (event.getChecked()) { if (event.getElement() instanceof TraceProviderGroup) { fLoggersViewer.setSubtreeChecked(event.getElement(), true); } if (event.getElement() instanceof UstProviderComponent) { fLoggersViewer.setSubtreeChecked(event.getElement(), true); } } else { if (event.getElement() instanceof TraceProviderGroup) { fLoggersViewer.setSubtreeChecked(event.getElement(), true); } if (event.getElement() instanceof UstProviderComponent) { ITraceControlComponent component = (ITraceControlComponent) event.getElement(); fLoggersViewer.setSubtreeChecked(event.getElement(), false); fLoggersViewer.setChecked(component.getParent(), false); } else { ITraceControlComponent component = (ITraceControlComponent) event.getElement(); fLoggersViewer.setChecked(component.getParent(), false); fLoggersViewer.setChecked(component.getParent().getParent(), false); } } } } }