/*****************************************************************
* Copyright (c) 2010, 2012 Texas Instruments and others
* 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:
* Patrick Chuong (Texas Instruments) - Pin and Clone Supports (331781)
* Patrick Chuong (Texas Instruments) - Add support for icon overlay in the debug view (Bug 334566)
*****************************************************************/
package org.eclipse.cdt.debug.internal.ui.actions;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.cdt.debug.internal.ui.pinclone.DebugContextPinProvider;
import org.eclipse.cdt.debug.internal.ui.pinclone.DebugEventFilterService;
import org.eclipse.cdt.debug.internal.ui.pinclone.PinCloneUtils;
import org.eclipse.cdt.debug.ui.IPinProvider;
import org.eclipse.cdt.debug.ui.IPinProvider.IPinElementColorDescriptor;
import org.eclipse.cdt.debug.ui.IPinProvider.IPinElementHandle;
import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.contexts.IDebugContextService;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionDelegate2;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.WorkbenchPart;
/**
* Pin the selected debug context for the view.
*/
public class PinDebugContextActionDelegate implements IViewActionDelegate, IActionDelegate2, IDebugContextListener {
private IViewPart fPart;
private String fPinnedContextLabel = ""; //$NON-NLS-1$
private String fLastKnownDescription = ""; //$NON-NLS-1$
private IAction fAction;
private IPartListener2 fPartListener;
private DebugContextPinProvider fProvider;
public PinDebugContextActionDelegate() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate2#runWithEvent(org.eclipse.jface.action.IAction, org.eclipse.swt.widgets.Event)
*/
@Override
public void runWithEvent(IAction action, Event event) {
run(action);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
@Override
public void run(IAction action) {
if (action.isChecked()) {
fProvider = DebugEventFilterService.getInstance().addDebugEventFilter(fPart, getActiveDebugContext());
if (fProvider != null) {
fLastKnownDescription = ((WorkbenchPart) fPart).getContentDescription();
fPinnedContextLabel = getPinContextLabel(fProvider);
PinCloneUtils.setPartContentDescription(fPart, fPinnedContextLabel);
updatePinContextColor(fProvider);
}
} else {
fProvider = null;
DebugEventFilterService.getInstance().removeDebugEventFilter(fPart);
updatePinContextColor(fProvider);
PinCloneUtils.setPartContentDescription(fPart, fLastKnownDescription);
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/
@Override
public void selectionChanged(IAction action, ISelection selection) {
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate2#init(org.eclipse.jface.action.IAction)
*/
@Override
public void init(IAction action) {
fAction = action;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
*/
@Override
public void init(IViewPart view) {
fPart = view;
if (fAction != null && !fAction.isChecked()) {
IDebugContextService service = DebugUITools.getDebugContextManager().getContextService(fPart.getViewSite().getWorkbenchWindow());
boolean pinnable = PinCloneUtils.isPinnable(fPart, service.getActiveContext());
fAction.setEnabled(pinnable);
}
fPart.addPropertyListener(new IPropertyListener() {
@Override
public void propertyChanged(Object source, int propId) {
if (IWorkbenchPartConstants.PROP_CONTENT_DESCRIPTION == propId) {
// if the content description is not the pinned context label,
// then cache it so that we can set it back when the action is unchecked.
String desc = ((WorkbenchPart) fPart).getContentDescription();
if (!fPinnedContextLabel.equals(desc)) {
fLastKnownDescription = desc;
}
// if action is checked, than set it back to the pinned context label.
if (fAction != null && fAction.isChecked()) {
PinCloneUtils.setPartContentDescription(fPart, fPinnedContextLabel);
}
} else if (IWorkbenchPartConstants.PROP_PART_NAME == propId) {
PinCloneUtils.setPartTitle(fPart);
}
}
});
DebugUITools.addPartDebugContextListener(fPart.getSite(), this);
// Platform AbstractDebugView saves action check state,
// in our case, we don't want this behavior.
// Listens to part close and set the check state off.
fPartListener = new IPartListener2() {
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {}
@Override
public void partClosed(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);
if (part.equals(fPart)) {
if (fAction.isChecked()) {
DebugEventFilterService.getInstance().removeDebugEventFilter(fPart);
fAction.setChecked(false);
}
}
}
@Override
public void partDeactivated(IWorkbenchPartReference partRef) {}
@Override
public void partOpened(IWorkbenchPartReference partRef) {}
@Override
public void partHidden(IWorkbenchPartReference partRef) {}
@Override
public void partVisible(IWorkbenchPartReference partRef) {}
@Override
public void partInputChanged(IWorkbenchPartReference partRef) {}
@Override
public void partActivated(IWorkbenchPartReference partRef) {}
};
fPart.getSite().getWorkbenchWindow().getPartService().addPartListener(fPartListener);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate2#dispose()
*/
@Override
public void dispose() {
DebugUITools.removePartDebugContextListener(fPart.getSite(), this);
fPart.getSite().getWorkbenchWindow().getPartService().removePartListener(fPartListener);
}
protected ISelection getActiveDebugContext() {
IDebugContextService contextService =
DebugUITools.getDebugContextManager().getContextService(fPart.getSite().getWorkbenchWindow());
return contextService.getActiveContext();
}
private String getPinContextLabel(DebugContextPinProvider provider) {
String description = ""; //$NON-NLS-1$
if (provider != null) {
Set<String> labels = new HashSet<String>();
for (IPinElementHandle handle : provider.getPinHandles()) {
String tmp = getLabel(handle);
if (tmp != null && tmp.trim().length() != 0)
labels.add(tmp);
}
for (String label : labels) {
if (label != null) {
if (description.length() > 0) {
description += ", " + label; //$NON-NLS-1$
} else {
description = label;
}
}
}
}
return description;
}
private String getLabel(IPinElementHandle handle) {
String label = ""; //$NON-NLS-1$
if (handle != null)
label = handle.getLabel();
return label;
}
private boolean useMultiPinImage(Set<IPinElementHandle> handles) {
if (handles.size() <= 1) return false;
int overlayColor = IPinElementColorDescriptor.UNDEFINED;
ImageDescriptor imageDesc = null;
for (IPinElementHandle handle : handles) {
IPinElementColorDescriptor colorDesc = handle.getPinElementColorDescriptor();
if (colorDesc != null) {
ImageDescriptor descImageDesc = colorDesc.getToolbarIconDescriptor();
if (imageDesc != null && !imageDesc.equals(descImageDesc))
return true;
imageDesc = descImageDesc;
int descOverlayColor = colorDesc.getOverlayColor();
if (overlayColor != IPinElementColorDescriptor.UNDEFINED && descOverlayColor != overlayColor)
return true;
overlayColor = descOverlayColor;
}
}
return false;
}
private void updatePinContextColor(DebugContextPinProvider provider) {
ImageDescriptor imageDesc = null;
if (provider != null) {
Set<IPinElementHandle> handles = provider.getPinHandles();
// if handles have different toolbar icon descriptor or different pin color, than use a
// multi-pin toolbar icon
if (useMultiPinImage(handles))
imageDesc = CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_VIEW_PIN_ACTION_MULTI);
if (imageDesc == null) {
Iterator<IPinElementHandle> itr = handles.iterator();
if (itr.hasNext()) {
IPinElementHandle handle = itr.next();
IPinElementColorDescriptor desc = handle.getPinElementColorDescriptor();
if (desc != null)
imageDesc = desc.getToolbarIconDescriptor();
if (imageDesc == null && desc != null) {
int overlayColor = desc.getOverlayColor() % IPinElementColorDescriptor.DEFAULT_COLOR_COUNT;
switch (overlayColor) {
case IPinProvider.IPinElementColorDescriptor.GREEN:
imageDesc = CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_VIEW_PIN_ACTION_G);
break;
case IPinProvider.IPinElementColorDescriptor.RED:
imageDesc = CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_VIEW_PIN_ACTION_R);
break;
case IPinProvider.IPinElementColorDescriptor.BLUE:
imageDesc = CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_VIEW_PIN_ACTION_B);
break;
}
}
}
}
}
if (imageDesc == null)
imageDesc = CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_VIEW_PIN_ACTION);
fAction.setImageDescriptor(imageDesc);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.contexts.IDebugContextListener#debugContextChanged(org.eclipse.debug.ui.contexts.DebugContextEvent)
*/
@Override
public void debugContextChanged(DebugContextEvent event) {
if (fAction != null && !fAction.isChecked()) {
final boolean pinnable = PinCloneUtils.isPinnable(fPart, event.getContext());
if (pinnable != fAction.isEnabled()) {
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
@Override
public void run() {
fAction.setEnabled(pinnable);
}
});
}
}
}
}