blob: 7e9f88ba1568e7193a701b99645075bc1c3cb644 [file] [log] [blame]
/**
* Copyright (c) 2015 Codetrails GmbH.
* 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
*/
package org.eclipse.epp.internal.logging.aeri.ide.dialogs;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.text.MessageFormat.format;
import static org.apache.commons.lang3.StringUtils.*;
import static org.eclipse.e4.ui.services.IServiceConstants.ACTIVE_SHELL;
import static org.eclipse.emf.databinding.EMFProperties.value;
import static org.eclipse.emf.databinding.FeaturePath.fromList;
import static org.eclipse.epp.internal.logging.aeri.ide.IDEWorkflow.*;
import static org.eclipse.epp.internal.logging.aeri.ide.IIdePackage.Literals.LOG_EVENT__OPTIONS;
import static org.eclipse.epp.internal.logging.aeri.ide.di.ImageRegistryCreationFunction.ICO_INFO;
import static org.eclipse.epp.internal.logging.aeri.ide.dialogs.UI.*;
import static org.eclipse.epp.internal.logging.aeri.ide.utils.IDEConstants.BUNDLE_ID;
import static org.eclipse.epp.logging.aeri.core.IModelPackage.Literals.*;
import static org.eclipse.jface.databinding.swt.WidgetProperties.text;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListDiffVisitor;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.e4.core.contexts.Active;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.epp.internal.logging.aeri.ide.IDEWorkflow;
import org.eclipse.epp.internal.logging.aeri.ide.IIdeFactory;
import org.eclipse.epp.internal.logging.aeri.ide.IIdePackage;
import org.eclipse.epp.internal.logging.aeri.ide.IInternalInput;
import org.eclipse.epp.internal.logging.aeri.ide.ILogEvent;
import org.eclipse.epp.internal.logging.aeri.ide.ILogEventGroup;
import org.eclipse.epp.internal.logging.aeri.ide.ILogEventsQueue;
import org.eclipse.epp.internal.logging.aeri.ide.IProcessorDescriptor;
import org.eclipse.epp.internal.logging.aeri.ide.IServerDescriptor;
import org.eclipse.epp.internal.logging.aeri.ide.l10n.Messages;
import org.eclipse.epp.internal.logging.aeri.ide.processors.AnonymizeMessagesProcessor;
import org.eclipse.epp.internal.logging.aeri.ide.processors.AnonymizeStackTracesProcessor;
import org.eclipse.epp.internal.logging.aeri.ide.processors.Processors;
import org.eclipse.epp.internal.logging.aeri.ide.processors.StepsToReproduceProcessor;
import org.eclipse.epp.internal.logging.aeri.ide.util.IdeSwitch;
import org.eclipse.epp.internal.logging.aeri.ide.utils.IDEConstants;
import org.eclipse.epp.logging.aeri.core.IModelPackage.Literals;
import org.eclipse.epp.logging.aeri.ide.processors.IEditableReportProcessor;
import org.eclipse.epp.logging.aeri.ide.processors.IEditableReportProcessor.EditResult;
import org.eclipse.epp.logging.aeri.core.IReport;
import org.eclipse.epp.logging.aeri.core.IReportProcessor;
import org.eclipse.epp.logging.aeri.core.Severity;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.viewers.IViewerObservableValue;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableFontProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
public class ReviewDialog extends MessageDialog {
public static final String CTX_STATE_REVIEW_IN_PROGRESS = BUNDLE_ID + ".di.review-in-progress"; //$NON-NLS-1$
private static final int DEFAULT_DIALOG_WIDTH = 600;
private static final int DEFAULT_DIALOG_HEIGHT = 320;
private SashForm reportsAndDetailsSash;
private TableViewer reportsViewer;
private SashForm commentAndPreviewSash;
private ComboViewer severity;
private StyledText comments;
private Composite previewArea;
private ReportPreview preview;
private Composite detailsArea;
private ExpandableComposite previewTwistie;
private ToolBar processorsBar;
private ExpandableComposite commentTwistie;
private ShowPreviewListener showPreviewListener;
private IEclipseContext context;
private IEventBroker broker;
private ImageRegistry registry;
@Nullable
private ILogEventGroup active;
private ILogEventsQueue queue;
private DataBindingContext dbContext;
private IViewerObservableValue selectedLogEvent;
private IObservableList<ILogEvent> events;
private IncomingEventsCopier incomingEventsCopier;
private UISynchronize uiSynchronize;
private List<IProcessorDescriptor> reportProcessorDescriptors;
private Map<String, String> directivesToReadable;
@Inject
public ReviewDialog(@Active @Optional ILogEventGroup active, ILogEventsQueue queue, ImageRegistry registry,
@Named(ACTIVE_SHELL) @Optional Shell parentShell, UISynchronize uiSynchronize, IEclipseContext context, IEventBroker broker,
@Named(IDEWorkflow.CTX_REPORT_PROCESSORS) List<IProcessorDescriptor> descriptors) {
super(parentShell, Messages.DIALOG_TITLE_REVIEW, null,
MessageFormat.format(
"Eclipse encountered {0,choice,1#an error|1<{0,number,integer} errors}. Errors may reveal severe issues in the code and thus we kindly ask you to send them to the affected projects.",
queue.getGroups().size()),
MessageDialog.WARNING, new String[] { Messages.BUTTON_TEXT_SEND, Messages.BUTTON_TEXT_DONT_SEND }, 0);
this.active = active;
this.queue = queue;
this.uiSynchronize = uiSynchronize;
this.reportProcessorDescriptors = Lists.newArrayList(descriptors);
sortProcessorDescriptors();
this.directivesToReadable = descriptors.stream()
.collect(Collectors.toMap(IProcessorDescriptor::getDirective, IProcessorDescriptor::getName));
this.registry = checkNotNull(registry);
this.context = context;
this.broker = broker;
setShellStyle(SWT.MODELESS | SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX);
setBlockOnOpen(false);
setupObservableList();
context.modify(CTX_STATE_REVIEW_IN_PROGRESS, true);
}
protected void sortProcessorDescriptors() {
// special handling for the anonymize and steps to reproduce processors, they should always be the last elements
Comparator<IProcessorDescriptor> comparator = Comparator
.comparing(IProcessorDescriptor::getProcessor,
(a, b) -> a.getWrapped() instanceof AnonymizeStackTracesProcessor ? 1
: b.getWrapped() instanceof AnonymizeStackTracesProcessor ? -1 : 0)
.thenComparing(IProcessorDescriptor::getProcessor,
(a, b) -> a.getWrapped() instanceof AnonymizeMessagesProcessor ? 1
: b.getWrapped() instanceof AnonymizeMessagesProcessor ? -1 : 0)
.thenComparing(IProcessorDescriptor::getProcessor,
(a, b) -> a.getWrapped() instanceof StepsToReproduceProcessor ? 1
: b.getWrapped() instanceof StepsToReproduceProcessor ? -1 : 0)
.thenComparing(IProcessorDescriptor::getName, Comparator.naturalOrder());
Collections.sort(reportProcessorDescriptors, comparator);
}
@SuppressWarnings("unchecked")
private void setupObservableList() {
final IInternalInput input = IIdeFactory.eINSTANCE.createInternalInput();
this.events = EMFProperties.list(IIdePackage.Literals.INTERNAL_INPUT__INPUT).observe(input);
for (ILogEventGroup group : queue.getGroups()) {
input.getInput().addAll(group.getEvents());
}
incomingEventsCopier = new IncomingEventsCopier(input);
queue.eAdapters().add(incomingEventsCopier);
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setSize(DEFAULT_DIALOG_WIDTH, DEFAULT_DIALOG_HEIGHT);
}
@Override
public void create() {
super.create();
}
@Override
protected boolean customShouldTakeFocus() {
return false;
}
@Override
protected Control createMessageArea(Composite composite) {
Image image = getImage();
if (image != null) {
imageLabel = new Label(composite, SWT.NULL);
image.setBackground(imageLabel.getBackground());
imageLabel.setImage(image);
GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.BEGINNING).applyTo(imageLabel);
}
Composite messageLink = new Composite(composite, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).applyTo(messageLink);
messageLink.setLayout(new GridLayout());
Control processLink = createMessage(messageLink);
if (processLink != null) {
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false)
.hint(convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH), SWT.DEFAULT).applyTo(processLink);
}
return composite;
}
@Override
public Composite createCustomArea(final Composite parent) {
createReportsAndDetailsSash(parent);
createReportsViewer(reportsAndDetailsSash);
createDetailsArea(reportsAndDetailsSash);
reportsAndDetailsSash.setWeights(new int[] { 1, 3 });
createPreferencesLink(parent);
createDatabindings();
if (active != null) {
EList<ILogEvent> events = active.getEvents();
if (!events.isEmpty()) {
// TODO not sure why/when this could become null - but it was
ILogEvent event = events.get(0);
selectedLogEvent.setValue(event);
}
}
return reportsAndDetailsSash;
}
@Nullable
private Control createMessage(final Composite parent) {
final Multimap<IProcessorDescriptor, ILogEvent> eventsByRequestedProcessors = ArrayListMultimap.create();
Set<IServerDescriptor> interestedServers = Sets.newHashSet();
for (ILogEventGroup group : queue.getGroups()) {
for (ILogEvent event : group.getEvents()) {
reportProcessorDescriptors.stream().filter(descriptor -> Processors.shouldProcess(descriptor, event))
.forEach(descriptor -> {
eventsByRequestedProcessors.put(descriptor, event);
interestedServers.add(event.getServer());
});
}
}
Label additionalInformationRequestedMessage = new Label(parent, SWT.WRAP);
if (!eventsByRequestedProcessors.isEmpty()) {
int countEvents = Sets.newHashSet(eventsByRequestedProcessors.values()).size();
this.message += MessageFormat.format(
" {0,choice,1#One project|1<{0,number,integer} projects} requested additional information for {1,choice,1#this error|1<{1,number,integer} errors}. Please provide the requested information to {1,choice,1#this report|1<the highlighted reports}.",
interestedServers.size(), countEvents);
}
additionalInformationRequestedMessage.setText(this.message);
return additionalInformationRequestedMessage;
}
private void createDetailsArea(Composite parent) {
detailsArea = new Composite(reportsAndDetailsSash, SWT.NONE);
{
commentTwistie = new ExpandableComposite(detailsArea, SWT.NONE);
commentTwistie.setText(Messages.TWISTIE_TEXT_COMMENT);
commentTwistie.setExpanded(true);
commentTwistie.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent e) {
if (e.getState()) {
commentAndPreviewSash.setMaximizedControl(null);
} else {
commentAndPreviewSash.setMaximizedControl(previewArea);
if (!previewTwistie.isExpanded()) {
previewTwistie.setExpanded(true);
showPreviewListener.showPreview();
}
}
}
});
}
{
severity = new ComboViewer(detailsArea);
severity.setContentProvider(ArrayContentProvider.getInstance());
severity.setInput(Severity.VALUES);
severity.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
return element == Severity.UNKNOWN ? Messages.COMBO_TEXT_SEVERITY_UNKNOWN
: capitalize(lowerCase(replaceChars(element.toString(), '_', ' ')));
}
});
}
{
commentAndPreviewSash = new SashForm(detailsArea, SWT.VERTICAL);
commentAndPreviewSash.setSashWidth(10);
createCommentArea(commentAndPreviewSash);
createPreviewArea(commentAndPreviewSash);
final int lineHeight = Math.max(16 + 3, parent.getFont().getFontData()[0].getHeight());
commentAndPreviewSash.addControlListener(new ControlAdapter() {
private int preferredCommentHeight = -1;
private int autoExpandPoint;
@Override
public void controlResized(ControlEvent e) {
int sashHeight = commentAndPreviewSash.getClientArea().height;
if (preferredCommentHeight < 0) {
// Calculate weights and expand point based on initial window
preferredCommentHeight = sashHeight - lineHeight - commentAndPreviewSash.getSashWidth();
autoExpandPoint = (int) (sashHeight * 1.35);
}
if (preview.getStyledText().isVisible()) {
if (sashHeight < autoExpandPoint && commentTwistie.isExpanded()) {
previewTwistie.setExpanded(false);
preview.getStyledText().setVisible(false);
}
} else if (sashHeight >= autoExpandPoint) {
previewTwistie.setExpanded(true);
preview.getStyledText().setVisible(true);
}
int preferredPreviewHeight = sashHeight - preferredCommentHeight;
// never accept negative values
if (preferredPreviewHeight < lineHeight || preferredPreviewHeight < 0 || preferredCommentHeight < 0) {
commentAndPreviewSash.setWeights(new int[] { 3, 1 });
} else {
commentAndPreviewSash.setWeights(new int[] { preferredCommentHeight, preferredPreviewHeight });
}
}
});
}
gl().margins(0, 0).spacing(0, 0).numColumns(2).applyTo(detailsArea);
gdGrabHV().span(2, 1).applyTo(commentAndPreviewSash);
GridDataFactory.fillDefaults().align(SWT.END, SWT.TOP).applyTo(commentTwistie);
GridDataFactory.fillDefaults().align(SWT.END, SWT.TOP).applyTo(severity.getControl());
}
private void createReportsAndDetailsSash(final Composite parent) {
reportsAndDetailsSash = new SashForm(parent, SWT.HORIZONTAL);
reportsAndDetailsSash.setSashWidth(10);
gdGrabHV().indent(0, 10).applyTo(reportsAndDetailsSash);
}
private void createReportsViewer(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
Label label = new Label(container, SWT.NONE);
label.setText(Messages.LABEL_TEXT_EVENTS);
reportsViewer = new TableViewer(container);
reportsViewer.setContentProvider(new ObservableListContentProvider());
reportsViewer.setLabelProvider(new ReportsViewerLabelProvider(reportsViewer));
reportsViewer.getControl().addKeyListener(new ReportsViewerDeleteListener());
gl().applyTo(container);
gdGrabH().align(SWT.BEGINNING, SWT.TOP).applyTo(label);
gdGrabHV().applyTo(container);
gdGrabHV().applyTo(reportsViewer.getControl());
reportsViewer.setInput(events);
}
private void createCommentArea(Composite parent) {
comments = new StyledText(parent, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
comments.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT));
comments.setToolTipText(Messages.TOOLTIP_COMMENTS);
comments.setAlwaysShowScrollBars(false);
gdGrabHV().applyTo(comments);
}
private void createPreviewArea(Composite parent) {
previewArea = new Composite(parent, SWT.NONE);
{
previewTwistie = new ExpandableComposite(previewArea, SWT.NONE);
previewTwistie.setText(Messages.TWISTIE_TEXT_PREVIEW);
showPreviewListener = new ShowPreviewListener();
previewTwistie.addExpansionListener(showPreviewListener);
}
{
processorsBar = new ToolBar(previewArea, SWT.FLAT);
ToolItem showResponseToolItem = new ToolItem(processorsBar, SWT.PUSH);
showResponseToolItem.setImage(registry.get(ICO_INFO));
showResponseToolItem.setToolTipText("Show problem state");
showResponseToolItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ILogEvent event = (ILogEvent) selectedLogEvent.getValue();
if (event == null) {
return;
}
new ProblemStatusDialog(event, reportProcessorDescriptors, getShell()).open();
}
});
new ToolItem(processorsBar, SWT.SEPARATOR);
for (IProcessorDescriptor descriptor : reportProcessorDescriptors) {
ToolItem processorToolItem = new ToolItem(processorsBar, SWT.CHECK);
processorToolItem.setData(descriptor);
processorToolItem.setImage(descriptor.getImage16());
}
}
{
preview = new ReportPreview(previewArea);
preview.setEditListener(isReset -> previewReport());
}
gl().numColumns(2).applyTo(previewArea);
gdGrabH().align(SWT.END, SWT.CENTER).applyTo(processorsBar);
gdGrabHV().span(2, 1).hint(SWT.DEFAULT, DEFAULT_DIALOG_HEIGHT).applyTo(preview.getStyledText());
}
protected void createPreferencesLink(final Composite parent) {
Link link = new Link(parent, SWT.NONE);
link.setText(Messages.LINK_TEXT_SENDING_PREFERENCES);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
uiSynchronize.asyncExec(new Runnable() {
@Override
public void run() {
PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null, IDEConstants.PREFERENCE_PAGE_ID, null,
null);
dialog.open();
}
});
}
});
gdGrabH().indent(0, 10).minSize(SWT.DEFAULT, 20).applyTo(link);
}
@SuppressWarnings("unchecked")
private void createDatabindings() {
dbContext = new DataBindingContext();
{
selectedLogEvent = ViewerProperties.singlePostSelection().observe(reportsViewer);
selectedLogEvent.addChangeListener(x -> {
ILogEvent logEvent = (ILogEvent) selectedLogEvent.getValue();
if (logEvent != null) {
for (ToolItem processorToolItem : processorsBar.getItems()) {
IProcessorDescriptor descriptor = (IProcessorDescriptor) processorToolItem.getData();
if (descriptor != null) {
IReportProcessor processor = descriptor.getProcessor();
boolean canContribute = processor.canContribute(logEvent.getStatus(), logEvent.getContext());
processorToolItem.setEnabled(canContribute);
String tooltipText = format("{0}:\n{1}", descriptor.getName(), descriptor.getDescription());
if (!canContribute) {
tooltipText = format("The processor ''{0}'' cannot contribute to the report.\n\n{1}", descriptor.getName(),
tooltipText);
}
processorToolItem.setToolTipText(tooltipText);
}
}
}
});
}
{
IObservableList<IReportProcessor> enabledProcessors = EMFProperties
.list(fromList(LOG_EVENT__OPTIONS, Literals.SEND_OPTIONS__ENABLED_PROCESSORS)).observeDetail(selectedLogEvent);
enabledProcessors.addListChangeListener(event -> {
event.diff.accept(new ActivatedProcessorsChangeVisitor());
});
for (ToolItem processorToolItem : processorsBar.getItems()) {
IProcessorDescriptor descriptor = (IProcessorDescriptor) processorToolItem.getData();
if (descriptor == null) {
continue;
}
IReportProcessor processor = descriptor.getProcessor();
processorToolItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ILogEvent event = (ILogEvent) selectedLogEvent.getValue();
if (event == null) {
return;
}
EList<IReportProcessor> activeProcessors = event.getOptions().getEnabledProcessors();
if (processorToolItem.getSelection()) {
if (!activeProcessors.contains(processor)) {
activeProcessors.add(processor);
}
} else {
activeProcessors.remove(processor);
}
// update the labels (we may remove the bold notification if all requested processors are activated or vice-versa)
reportsViewer.refresh(true, false);
}
});
}
}
{
IObservableValue<String> emf = value(fromList(LOG_EVENT__OPTIONS, SEND_OPTIONS__COMMENT)).observeDetail(selectedLogEvent);
ISWTObservableValue swt = text(SWT.Modify).observeDelayed(300, comments);
dbContext.bindValue(swt, emf);
}
{
IObservableValue<Severity> emf = value(fromList(LOG_EVENT__OPTIONS, SEND_OPTIONS__SEVERITY)).observeDetail(selectedLogEvent);
IObservableValue<Severity> jface = ViewerProperties.singleSelection().observe(severity);
dbContext.bindValue(jface, emf);
}
addChangeListenerToBindings(dbContext);
selectedLogEvent.addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent e) {
ILogEvent event = (ILogEvent) selectedLogEvent.getValue();
if (event != null) {
for (ToolItem processorToolItem : processorsBar.getItems()) {
IProcessorDescriptor descriptor = (IProcessorDescriptor) processorToolItem.getData();
if (descriptor == null) {
continue;
}
// TODO special handling for the processors bound to preferences, this should be generalized and put somewhere else
// in the next change
if (descriptor.getProcessor().getWrapped() instanceof AnonymizeStackTracesProcessor
&& event.getOptions().isAnonymizeStackTraces()
|| descriptor.getProcessor().getWrapped() instanceof AnonymizeMessagesProcessor
&& event.getOptions().isAnonymizeMessages()) {
event.getOptions().getEnabledProcessors().add(descriptor.getProcessor());
}
boolean shouldProcess = Processors.shouldProcess(descriptor, event);
processorToolItem.setSelection(event.getOptions().getEnabledProcessors().contains(descriptor.getProcessor()));
processorToolItem.setImage(UIUtils.decorate(descriptor, registry, shouldProcess));
}
}
}
});
}
private void editAndPreviewReport(IEditableReportProcessor processor) {
ILogEvent logEvent = (ILogEvent) selectedLogEvent.getValue();
if (logEvent != null) {
IServerDescriptor server = logEvent.getServer();
IReport report = server.getConnection().transform(logEvent.getStatus(), logEvent.getContext());
IProcessorDescriptor descriptor = null;
// TODO is there a better way to obtain the descriptor from the processor?
for (IProcessorDescriptor availableDescriptor : reportProcessorDescriptors) {
if (availableDescriptor.getProcessor() == processor) {
descriptor = availableDescriptor;
break;
}
}
if (descriptor == null) {
return;
}
processor.process(report, logEvent.getStatus(), logEvent.getContext());
EditResult editResult = processor.edit(logEvent.getStatus(), logEvent.getContext(), getShell());
switch (editResult) {
case MODIFIED:
preview.getEditedDescriptors().add(descriptor);
//$FALL-THROUGH$
case UNMODIFIED:
// Ensure report has the updated information
processor.process(report, logEvent.getStatus(), logEvent.getContext());
break;
case CANCELED:
default:
EList<IReportProcessor> activeProcessors = logEvent.getOptions().getEnabledProcessors();
activeProcessors.remove(processor);
report = server.getConnection().transform(logEvent.getStatus(), logEvent.getContext());
for (ToolItem processorToolItem : processorsBar.getItems()) {
IProcessorDescriptor toolItemDescriptor = (IProcessorDescriptor) processorToolItem.getData();
if (toolItemDescriptor == descriptor) {
processorToolItem.setSelection(false);
break;
}
}
break;
}
preview.preview(report, logEvent.getStatus(), server.getName(), reportProcessorDescriptors, logEvent.getContext(), getShell());
reportsViewer.refresh(true, false);
}
}
private void previewReport() {
ILogEvent logEvent = (ILogEvent) selectedLogEvent.getValue();
if (logEvent != null) {
IServerDescriptor server = logEvent.getServer();
IReport report = server.getConnection().transform(logEvent.getStatus(), logEvent.getContext());
preview.preview(report, logEvent.getStatus(), server.getName(), reportProcessorDescriptors, logEvent.getContext(), getShell());
}
}
private void addChangeListenerToBindings(DataBindingContext context) {
for (Object o : context.getBindings()) {
Binding b = (Binding) o;
b.getModel().addChangeListener(new UpdatePreviewChangeListener());
}
}
@Override
protected void buttonPressed(int buttonId) {
// MessageDialogs have a null implementation of this method. Need to re-implement it.
if (IDialogConstants.OK_ID == buttonId) {
okPressed();
} else if (IDialogConstants.CANCEL_ID == buttonId) {
cancelPressed();
}
}
@Override
public boolean close() {
context.modify(CTX_STATE_REVIEW_IN_PROGRESS, false);
dbContext.dispose();
queue.eAdapters().remove(incomingEventsCopier);
return super.close();
}
@Override
protected void okPressed() {
super.okPressed();
broker.post(TOPIC_USER_REQUESTS_SEND_ALL_GROUPS, queue);
}
@Override
protected void cancelPressed() {
super.cancelPressed();
broker.post(TOPIC_USER_REQUESTS_CLEAR_QUEUE, queue);
}
private final class ActivatedProcessorsChangeVisitor extends ListDiffVisitor {
@Override
public void handleAdd(int index, Object processor) {
if (processor instanceof IEditableReportProcessor) {
editAndPreviewReport((IEditableReportProcessor) processor);
} else {
previewReport();
}
}
@Override
public void handleRemove(int index, Object processor) {
previewReport();
}
}
private final class UpdatePreviewChangeListener implements IChangeListener {
@Override
public void handleChange(ChangeEvent event) {
previewReport();
}
}
private final class IncomingEventsCopier extends AdapterImpl {
private final IInternalInput input;
private IncomingEventsCopier(IInternalInput input) {
this.input = input;
}
@Override
public void notifyChanged(Notification msg) {
EList<ILogEvent> input2 = input.getInput();
switch (msg.getEventType()) {
case Notification.ADD: {
ILogEventGroup group = (ILogEventGroup) msg.getNewValue();
for (ILogEvent event : group.getEvents()) {
// TODO me need a better solution than this for final version:
IServerDescriptor server = event.getServer();
if (server.isConfigured()) {
input2.add(event);
}
}
break;
}
case Notification.REMOVE:
ILogEventGroup group = (ILogEventGroup) msg.getOldValue();
input2.removeAll(group.getEvents());
break;
}
}
}
private final class ReportsViewerDeleteListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS) {
deleteSelection();
}
}
private void deleteSelection() {
IStructuredSelection selection = (IStructuredSelection) reportsViewer.getSelection();
@SuppressWarnings("unchecked")
List<ILogEvent> elements = selection.toList();
events.removeAll(elements);
for (ILogEvent event : elements) {
ILogEventGroup group = (ILogEventGroup) event.eContainer();
EcoreUtil.delete(event);
if (group.getEvents().isEmpty()) {
EcoreUtil.remove(group);
}
}
}
}
private final class ShowPreviewListener extends ExpansionAdapter {
private Point collapsedShellSize;
@Override
public void expansionStateChanged(ExpansionEvent e) {
if (e.getState()) {
showPreview();
} else {
hidePreview();
}
}
public void hidePreview() {
Shell shell = getShell();
Point current = shell.getSize();
preview.getStyledText().setVisible(false);
shell.setSize(current.x, DEFAULT_DIALOG_HEIGHT);
}
public void showPreview() {
Shell shell = getShell();
preview.getStyledText().setVisible(true);
collapsedShellSize = shell.getSize();
shell.setSize(collapsedShellSize.x, collapsedShellSize.y + 300);
}
}
private final class ReportsViewerLabelProvider extends ColumnLabelProvider implements ITableFontProvider {
private Font defaultFont;
private Font boldFont;
ReportsViewerLabelProvider(ColumnViewer viewer) {
defaultFont = viewer.getControl().getFont();
FontDescriptor boldDescriptor = FontDescriptor.createFrom(defaultFont).setStyle(SWT.BOLD);
boldFont = boldDescriptor.createFont(viewer.getControl().getDisplay());
}
@Override
public String getText(Object element) {
return new IdeSwitch<String>() {
@Override
public String caseLogEvent(ILogEvent event) {
if (isActivationConfirmRequired(event)) {
return "* " + event.getLabel();
}
return event.getLabel();
}
}.doSwitch((EObject) element);
}
@Override
public int getToolTipDisplayDelayTime(Object object) {
return 100; // msec
}
@Override
public int getToolTipTimeDisplayed(Object object) {
return 5000; // msec
}
@Override
public Image getImage(Object element) {
return new IdeSwitch<Image>() {
@Override
public Image caseLogEvent(ILogEvent event) {
boolean shouldProcess = Processors.shouldProcess(reportProcessorDescriptors, event);
Image image = UIUtils.decorate(event.getServer(), event.getStatus(), registry, shouldProcess);
return image;
}
}.doSwitch((EObject) element);
}
@Override
public Font getFont(Object element, int columnIndex) {
return new IdeSwitch<Font>() {
@Override
public Font caseLogEvent(ILogEvent event) {
return isActivationConfirmRequired(event) ? boldFont : defaultFont;
}
}.doSwitch((EObject) element);
}
private boolean isActivationConfirmRequired(ILogEvent event) {
return reportProcessorDescriptors.stream().filter(descriptor -> Processors.shouldProcess(descriptor, event)
&& !event.getOptions().getEnabledProcessors().contains(descriptor.getProcessor())).findFirst().isPresent();
}
}
}