package rocks.inspectit.ui.rcp.ci.form.part; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import rocks.inspectit.shared.cs.ci.Environment; import rocks.inspectit.shared.cs.ci.Profile; import rocks.inspectit.ui.rcp.InspectIT; import rocks.inspectit.ui.rcp.InspectITImages; import rocks.inspectit.ui.rcp.ci.form.input.EnvironmentEditorInput; import rocks.inspectit.ui.rcp.ci.job.OpenProfileJob; import rocks.inspectit.ui.rcp.ci.listener.IProfileChangeListener; import rocks.inspectit.ui.rcp.editor.viewers.StyledCellIndexLabelProvider; import rocks.inspectit.ui.rcp.filter.FilterComposite; import rocks.inspectit.ui.rcp.formatter.ImageFormatter; import rocks.inspectit.ui.rcp.formatter.TextFormatter; import rocks.inspectit.ui.rcp.preferences.PreferencesConstants; import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition; import rocks.inspectit.ui.rcp.util.SafeExecutor; import rocks.inspectit.ui.rcp.util.WarningUtils; /** * Profile selection for the environment. * * @author Ivan Senic * */ public class ProfileSelectionPart extends SectionPart implements IProfileChangeListener, IPropertyListener { /** * Id of the exclude profiles ID. */ private static final String EXCLUDE_CLASSES_PROFILE_ID = "exclude-classes"; /** * Repository needed for loading all {@link Profile}s. */ private final CmrRepositoryDefinition cmrRepositoryDefinition; /** * Environment being edited. */ private Environment environment; /** * Profiles environment can be linked to. */ private final List<Profile> profiles; /** * {@link FormPage} section belongs to. */ private final FormPage formPage; /** * Table displaying the profiles. */ private TableViewer tableViewer; /** * Default constructor. * * @param formPage * {@link FormPage} section belongs to. * @param parent * Parent composite. * @param toolkit * {@link FormToolkit} * @param style * Style used for creating the section. */ public ProfileSelectionPart(FormPage formPage, Composite parent, FormToolkit toolkit, int style) { super(parent, toolkit, style); EnvironmentEditorInput input = (EnvironmentEditorInput) formPage.getEditor().getEditorInput(); this.cmrRepositoryDefinition = input.getCmrRepositoryDefinition(); this.environment = input.getEnvironment(); this.profiles = new ArrayList<>(input.getProfiles()); this.formPage = formPage; this.formPage.getEditor().addPropertyListener(this); // client createClient(getSection(), toolkit); // text and description on our own getSection().setText("Profiles"); Label label = toolkit.createLabel(getSection(), "Select profiles to use within environment"); label.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); getSection().setDescriptionControl(label); // profile change listener InspectIT.getDefault().getInspectITConfigurationInterfaceManager().addProfileChangeListener(this); } /** * Creates complete client. * * @param section * {@link Section} * @param toolkit * {@link FormToolkit} */ private void createClient(Section section, FormToolkit toolkit) { Composite mainComposite = toolkit.createComposite(section); mainComposite.setLayout(new GridLayout(1, true)); section.setClient(mainComposite); // filter first FilterProfileComposite filterProfileComposite = new FilterProfileComposite(mainComposite, SWT.NONE); filterProfileComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); toolkit.adapt(filterProfileComposite); // table Table table = toolkit.createTable(mainComposite, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.CHECK); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); table.setHeaderVisible(true); table.setLinesVisible(true); tableViewer = new TableViewer(table); createColumns(); tableViewer.setContentProvider(new ArrayContentProvider()); tableViewer.setLabelProvider(new ProfileLabelProvider()); tableViewer.setComparator(new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { if ((e1 instanceof Profile) && (e2 instanceof Profile)) { int res = Boolean.compare(((Profile) e1).isCommonProfile(), ((Profile) e2).isCommonProfile()); if (0 != res) { return res; } return ((Profile) e1).getName().compareToIgnoreCase(((Profile) e2).getName()); } return 0; } }); tableViewer.setInput(profiles); tableViewer.refresh(); updateCheckedItems(); // filter tableViewer.addFilter(filterProfileComposite.getFilter()); // dirty listener tableViewer.getTable().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if ((e.detail == SWT.CHECK) && !isDirty()) { markDirty(); } // warning for the exclude-classes un-checking TableItem item = (TableItem) e.item; Profile profile = (Profile) item.getData(); if ((e.detail == SWT.CHECK) && !item.getChecked() && EXCLUDE_CLASSES_PROFILE_ID.equals(profile.getId())) { WarningUtils.inform("Exlude Classes Profile Removal", "Please note that removing default exclude classes profile from the environment can result in non-operative agent.", PreferencesConstants.EXCLUDE_CLASSES_PROFILE_WARNING); } } }); // open profile on double-click tableViewer.getTable().addListener(SWT.MouseDoubleClick, new Listener() { @Override public void handleEvent(Event event) { StructuredSelection selection = (StructuredSelection) tableViewer.getSelection(); if (!selection.isEmpty()) { Profile profile = (Profile) selection.getFirstElement(); new OpenProfileJob(cmrRepositoryDefinition, profile.getId(), formPage.getSite().getPage()).schedule(); } } }); // add menu as option also MenuManager menuManager = new MenuManager(); menuManager.add(new EditProfileAction()); Menu menu = menuManager.createContextMenu(table); table.setMenu(menu); } /** * Creates columns for table. */ private void createColumns() { TableViewerColumn profileNameColumn = new TableViewerColumn(tableViewer, SWT.NONE); profileNameColumn.getColumn().setResizable(true); profileNameColumn.getColumn().setWidth(250); profileNameColumn.getColumn().setText("Profile"); profileNameColumn.getColumn().setToolTipText("Profile name."); TableViewerColumn activeColumn = new TableViewerColumn(tableViewer, SWT.NONE); activeColumn.getColumn().setMoveable(true); activeColumn.getColumn().setResizable(true); activeColumn.getColumn().setText("Active"); activeColumn.getColumn().setWidth(40); activeColumn.getColumn().setToolTipText("If profile is active or not, note that deactivated profile will not be considered during the instrumentation even if it's a part of an environment."); TableViewerColumn defaultColumn = new TableViewerColumn(tableViewer, SWT.NONE); defaultColumn.getColumn().setMoveable(true); defaultColumn.getColumn().setResizable(true); defaultColumn.getColumn().setText("Default"); defaultColumn.getColumn().setWidth(40); defaultColumn.getColumn().setToolTipText("If profile is default or not, note that default profile will be added to any new created environment."); TableViewerColumn typeColumn = new TableViewerColumn(tableViewer, SWT.NONE); typeColumn.getColumn().setMoveable(true); typeColumn.getColumn().setResizable(true); typeColumn.getColumn().setText("Type"); typeColumn.getColumn().setWidth(40); typeColumn.getColumn().setToolTipText("Type of data profile is holding."); TableViewerColumn descriptionColumn = new TableViewerColumn(tableViewer, SWT.NONE); descriptionColumn.getColumn().setMoveable(true); descriptionColumn.getColumn().setResizable(true); descriptionColumn.getColumn().setText("Description"); descriptionColumn.getColumn().setWidth(250); descriptionColumn.getColumn().setToolTipText("Profile description."); } /** * Updates states of the check boxes next to the elements. */ private void updateCheckedItems() { for (TableItem item : tableViewer.getTable().getItems()) { Profile data = (Profile) item.getData(); item.setChecked(environment.getProfileIds().contains(data.getId())); } } /** * {@inheritDoc} */ @Override public void commit(boolean onSave) { if (onSave) { super.commit(onSave); Set<String> profileIds = new HashSet<>(1); for (TableItem item : tableViewer.getTable().getItems()) { if (item.getChecked()) { profileIds.add(((Profile) item.getData()).getId()); } } environment.setProfileIds(profileIds); } } /** * Profile label provider. * * @author Ivan Senic * */ private static class ProfileLabelProvider extends StyledCellIndexLabelProvider { /** * Empty. */ private static final StyledString EMPTY = new StyledString(); /** * {@inheritDoc} */ @Override protected StyledString getStyledText(Object element, int index) { if (element instanceof Profile) { Profile profile = ((Profile) element); switch (index) { case 0: return new StyledString(profile.getName()); case 4: return TextFormatter.emptyStyledStringIfNull(TextFormatter.clearLineBreaks(profile.getDescription())); default: return EMPTY; } } return EMPTY; } /** * {@inheritDoc} */ @Override protected Image getColumnImage(Object element, int index) { if (element instanceof Profile) { Profile profile = ((Profile) element); switch (index) { case 0: return ImageFormatter.getProfileImage(profile); case 1: return profile.isActive() ? InspectIT.getDefault().getImage(InspectITImages.IMG_CHECKMARK) : null; // NOPMD case 2: return profile.isDefaultProfile() ? InspectIT.getDefault().getImage(InspectITImages.IMG_CHECKMARK) : null; // NOPMD case 3: return ImageFormatter.getProfileDataImage(profile.getProfileData()); default: return super.getColumnImage(element, index); } } return super.getColumnImage(element, index); } /** * {@inheritDoc} */ @Override protected Color getForeground(Object element, int index) { if (element instanceof Profile) { Profile profile = ((Profile) element); if (profile.isCommonProfile()) { return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_CYAN); } } return super.getForeground(element, index); } /** * {@inheritDoc} */ @Override public String getToolTipText(Object element, int index) { switch (index) { case 0: return "Selecting the profile will include it in the environment."; default: return super.getToolTipText(element, index); } } } /** * Action for editing the profile. * * @author Ivan Senic * */ private class EditProfileAction extends Action { /** * Default constructor. */ public EditProfileAction() { setText("Edit"); setToolTipText("Edit Profile"); } /** * {@inheritDoc} */ @Override public void run() { StructuredSelection selection = (StructuredSelection) tableViewer.getSelection(); if (!selection.isEmpty()) { Profile profile = (Profile) selection.getFirstElement(); new OpenProfileJob(cmrRepositoryDefinition, profile.getId(), formPage.getSite().getPage()).schedule(); } }; } /** * Implementation of the filter for the profiles. * * @author Ivan Senic * */ private class FilterProfileComposite extends FilterComposite { /** * String to be filtered. */ private String filterString = ""; /** * Filter. */ private final ViewerFilter filter = new ViewerFilter() { /** * {@inheritDoc} */ @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (Objects.equals("", filterString)) { return true; } else { if (element instanceof Profile) { return select(((Profile) element)); } return true; } } /** * Does a filter select on {@link Profile}. * * @param profile * {@link Profile} * @return True if data in {@link Profile} fits the filter string. */ private boolean select(Profile profile) { return StringUtils.containsIgnoreCase(profile.getName(), filterString); } }; /** * @param parent * Parent * @param style * Style */ public FilterProfileComposite(Composite parent, int style) { super(parent, style, "Filter profiles"); ((GridLayout) getLayout()).marginWidth = 0; } /** * {@inheritDoc} */ @Override protected void executeCancel() { this.filterString = ""; tableViewer.refresh(); updateCheckedItems(); } /** * {@inheritDoc} */ @Override protected void executeFilter(String filterString) { this.filterString = filterString; tableViewer.refresh(); updateCheckedItems(); } /** * Gets {@link #filter}. * * @return {@link #filter} */ public ViewerFilter getFilter() { return filter; } } /** * {@inheritDoc} */ @Override public void profileCreated(Profile profile, CmrRepositoryDefinition repositoryDefinition) { CmrRepositoryDefinition displayedCmrRepositoryDefinition = ((EnvironmentEditorInput) formPage.getEditor().getEditorInput()).getCmrRepositoryDefinition(); if (!Objects.equals(repositoryDefinition, displayedCmrRepositoryDefinition)) { return; } profiles.add(profile); SafeExecutor.asyncExec(new Runnable() { @Override public void run() { tableViewer.refresh(); updateCheckedItems(); } }, tableViewer.getTable()); } @Override public void profileUpdated(Profile profile, CmrRepositoryDefinition repositoryDefinition, boolean onlyProperties) { CmrRepositoryDefinition displayedCmrRepositoryDefinition = ((EnvironmentEditorInput) formPage.getEditor().getEditorInput()).getCmrRepositoryDefinition(); if (!Objects.equals(repositoryDefinition, displayedCmrRepositoryDefinition)) { return; } for (Iterator<Profile> it = profiles.iterator(); it.hasNext();) { Profile displayed = it.next(); if (Objects.equals(displayed.getId(), profile.getId())) { it.remove(); profiles.add(profile); SafeExecutor.asyncExec(new Runnable() { @Override public void run() { tableViewer.refresh(); updateCheckedItems(); } }, tableViewer.getTable()); break; } } } /** * {@inheritDoc} */ @Override public void profileDeleted(Profile profile, CmrRepositoryDefinition repositoryDefinition) { CmrRepositoryDefinition displayedCmrRepositoryDefinition = ((EnvironmentEditorInput) formPage.getEditor().getEditorInput()).getCmrRepositoryDefinition(); if (!Objects.equals(repositoryDefinition, displayedCmrRepositoryDefinition)) { return; } for (Iterator<Profile> it = profiles.iterator(); it.hasNext();) { final Profile displayed = it.next(); if (Objects.equals(displayed.getId(), profile.getId())) { it.remove(); SafeExecutor.asyncExec(new Runnable() { @Override public void run() { tableViewer.remove(displayed); } }, tableViewer.getTable()); break; } } } /** * {@inheritDoc} */ @Override public void propertyChanged(Object source, int propId) { if (propId == IEditorPart.PROP_INPUT) { EnvironmentEditorInput input = (EnvironmentEditorInput) formPage.getEditor().getEditorInput(); environment = input.getEnvironment(); } } /** * {@inheritDoc} */ @Override public void dispose() { formPage.getEditor().removePropertyListener(this); InspectIT.getDefault().getInspectITConfigurationInterfaceManager().removeProfileChangeListener(this); super.dispose(); } }