/*************************************************************************************
* Copyright (c) 2013 Red Hat, Inc. 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:
* JBoss by Red Hat - Initial implementation.
************************************************************************************/
package org.jboss.tools.runtime.ui.internal.dialogs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
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.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.jboss.tools.runtime.core.internal.RuntimeExtensionManager;
import org.jboss.tools.runtime.core.model.IRuntimeDetectionResolution;
import org.jboss.tools.runtime.core.model.RuntimeDefinition;
import org.jboss.tools.runtime.core.model.RuntimeDetectionProblem;
import org.jboss.tools.runtime.core.model.RuntimePath;
import org.jboss.tools.runtime.ui.RuntimeUIActivator;
import org.jboss.tools.runtime.ui.internal.Messages;
public class RuntimeCheckboxTreeViewer extends CheckboxTreeViewer {
// content assist
private Shell popupShell;
private Table popupTable;
public RuntimeCheckboxTreeViewer(Composite parent, final Set<RuntimePath> runtimePaths2, int heightHint) {
this(parent, runtimePaths2.toArray(new RuntimePath[runtimePaths2.size()]), heightHint);
}
public RuntimeCheckboxTreeViewer(Composite parent, final RuntimePath[] runtimePaths2, int heightHint) {
super(parent, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
GridData gd;
Tree tree = getTree();
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
GC gc = new GC( parent);
FontMetrics fontMetrics = gc.getFontMetrics( );
gc.dispose( );
gd.minimumHeight = Dialog.convertHeightInCharsToPixels(fontMetrics, heightHint);
tree.setLayoutData(gd);
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
String[] columnNames = new String[] { Messages.RuntimeCheckboxTreeViewer_Name,
Messages.RuntimeCheckboxTreeViewer_Type, Messages.RuntimeCheckboxTreeViewer_Version,
Messages.RuntimeCheckboxTreeViewer_Errors, Messages.RuntimeCheckboxTreeViewer_Location};
int[] columnWidths = new int[] {200, 70, 60, 150, 150};
for (int i = 0; i < columnNames.length; i++) {
TreeViewerColumn tc = new TreeViewerColumn(this, SWT.NONE);
tc.getColumn().setText(columnNames[i]);
tc.getColumn().setWidth(columnWidths[i]);
}
setLabelProvider(new RuntimeLabelProvider());
List<RuntimeDefinition> runtimeDefinitions = new ArrayList<RuntimeDefinition>();
for (RuntimePath runtimePath:runtimePaths2) {
runtimeDefinitions.addAll(Arrays.asList(runtimePath.getRuntimeDefinitions()));
}
setContentProvider(new RuntimeContentProvider(runtimeDefinitions));
setInput(runtimeDefinitions);
for (RuntimeDefinition definition:runtimeDefinitions) {
setChecked(definition, definition.isEnabled());
}
addContentAssist();
}
private void addContentAssist() {
// content assist
popupShell = new Shell(getTree().getShell(), SWT.ON_TOP | SWT.RESIZE);
popupShell.setLayout(new FillLayout());
popupTable = new Table(popupShell, SWT.SINGLE);
popupShell.setVisible(false);
getTree().addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent event) {
if( popupShell.getVisible()) {
popupShell.setVisible(false);
} else {
showContentAssist(event);
}
}
});
getTree().addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
switch (event.keyCode) {
case SWT.ARROW_DOWN:
int index = (popupTable.getSelectionIndex() + 1) % popupTable.getItemCount();
popupTable.setSelection(index);
event.doit = false;
break;
case SWT.ARROW_UP:
index = popupTable.getSelectionIndex() - 1;
if (index < 0) index = popupTable.getItemCount() - 1;
popupTable.setSelection(index);
event.doit = false;
break;
case SWT.CR:
if (popupShell.isVisible() && popupTable.getSelectionIndex() != -1) {
event.doit = false;
contentAssistChosen();
}
break;
case SWT.ESC:
popupShell.setVisible(false);
break;
}
}
});
getTree().getShell().addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
if( popupShell.isVisible() ) {
if( event.keyCode == SWT.CR || event.keyCode == SWT.ESC) {
// pre-empt the wizard from closing
event.doit = false;
}
}
}
});
getTree().getShell().addListener(SWT.Traverse, new Listener() {
public void handleEvent(Event event) {
if( popupShell.isVisible() ) {
if (event.detail == SWT.TRAVERSE_ESCAPE) {
// pre-empt the wizard from closing
event.doit = false;
}
}
}
});
Listener hideUnfocusedPopup = new Listener() {
public void handleEvent(final Event event) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Widget w = event.widget;
Control control = Display.getDefault().getFocusControl();
if (control == null || (control != getTree() && control != popupTable)) {
popupShell.setVisible(false);
}
}
});
}
};
popupTable.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
if (event.keyCode == SWT.ESC) {
popupShell.setVisible(false);
}
}
});
//getTree().addListener(SWT.FocusOut, hideUnfocusedPopup);
popupTable.addListener(SWT.FocusOut, hideUnfocusedPopup);
Listener hidePopup = new Listener() {
public void handleEvent(Event event) {
popupShell.setVisible(false);
}
};
getTree().getShell().addListener(SWT.Dispose, hidePopup);
getTree().getShell().addListener(SWT.Move, hidePopup);
popupTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
contentAssistChosen();
}
});
}
private void contentAssistChosen() {
int problemIndex = popupTable.getSelectionIndex();
if( problemIndex != -1 ) {
RuntimeDefinition sel = getSelectedDefinition();
RuntimeDetectionProblem[] s = sel.getProblems();
if( problemIndex < s.length) {
// TODO run the content assist action
// We now have the runtime definition and the chosen problem to be fixed
final RuntimeDetectionProblem problem = s[problemIndex];
IRuntimeDetectionResolution[] resolutions =
RuntimeExtensionManager.getDefault().findResolutions(problem, sel);
if( resolutions.length > 0 ) {
// For now just execute the first one... TODO expand
resolutions[0].run(problem, sel);
// The solution may have fixed several problems, not just one
Object[] all = ((ITreeContentProvider)getContentProvider()).getElements(null);
for( int i = 0; i < all.length; i++ ) {
if( all[i] instanceof RuntimeDefinition ) {
((RuntimeDefinition)all[i]).refreshProblems();
}
}
refresh();
} else {
// Show an error that no resolution could be found
popupShell.setVisible(false);
StatusDialog d = new StatusDialog(getTree().getShell()) {
protected Control createDialogArea(Composite parent) {
Composite composite= (Composite) super.createDialogArea(parent);
Label label= new Label(composite, SWT.WRAP);
GridData layoutData= new GridData(SWT.FILL, SWT.CENTER, true, false);
layoutData.widthHint= convertWidthInCharsToPixels(80);
label.setLayoutData(layoutData);
label.setText("No quickfixes were found for the problem: " + problem.getDescription());
updateStatus(new Status(IStatus.ERROR, RuntimeUIActivator.PLUGIN_ID, "No quickfixes found for the selected problem"));
Dialog.applyDialogFont(composite);
return composite;
}
};
d.setTitle("No quickfix available");
d.open();
}
}
}
popupShell.setVisible(false);
}
private void showContentAssist(MouseEvent event) {
Rectangle itemBounds = findItemBounds(event, 3);
if( itemBounds != null ) {
popupTable.removeAll();
RuntimeDefinition selected = getSelectedDefinition();
if( selected != null ) {
RuntimeDetectionProblem[] s = selected.getProblems();
for( int i = 0; i < s.length; i++ ) {
String text = s[i].getLabel();
if( text != null ) {
int sev = s[i].getSeverity();
TableItem ti = new TableItem(popupTable, SWT.NONE);
ti.setText(text);
Image sevImage = null;
if( sev == IStatus.ERROR ) {
sevImage = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_DEC_FIELD_ERROR);
} else if( sev == IStatus.WARNING) {
sevImage = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_DEC_FIELD_WARNING);
}
if( sevImage != null )
ti.setImage(sevImage);
}
}
}
String[] text = getQuickfixTextForCurrentSelection();
// Don't show it if we have no errors
if( text == null || text.length == 0 ) {
return;
}
for (int i = 0; i < text.length; i++) {
}
Rectangle textBounds = Display.getDefault().map(getTree(), null, itemBounds);
popupShell.setBounds(textBounds.x, textBounds.y + (textBounds.height), textBounds.width > 250 ? textBounds.width : 250, 150);
popupTable.setEnabled(true);
popupShell.setVisible(true);
}
}
private String[] getQuickfixTextForCurrentSelection() {
// TODO Delete this
RuntimeDefinition selected = getSelectedDefinition();
if( selected != null ) {
RuntimeDetectionProblem[] s = selected.getProblems();
ArrayList<String> ret = new ArrayList<String>();
for( int i = 0; i < s.length; i++ ) {
ret.add(s[i].getLabel());
}
return (String[]) ret.toArray(new String[ret.size()]);
}
return new String[]{};
}
private RuntimeDefinition getSelectedDefinition() {
ISelection sel = getSelection();
if( sel instanceof IStructuredSelection ) {
Object f = ((IStructuredSelection)sel).getFirstElement();
if( f instanceof RuntimeDefinition ) {
return ((RuntimeDefinition)f);
}
}
return null;
}
private Rectangle findItemBounds(MouseEvent event, int soughtColumn) {
Point pt = new Point(event.x, event.y);
TreeItem item = getTree().getItem(pt);
if (item != null) {
for (int i = 0, n = getTree().getColumnCount(); i < n; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) {
if (i == soughtColumn) {
return rect;
}
}
}
}
return null;
}
// Refresh your input given the following RuntimePath[]
public void updateInput(RuntimePath[] runtimePaths) {
setInput(null);
List<RuntimeDefinition> runtimeDefinitions = new ArrayList<RuntimeDefinition>();
for (RuntimePath runtimePath : runtimePaths) {
runtimeDefinitions.addAll(Arrays.asList(runtimePath.getRuntimeDefinitions()));
}
setInput(runtimeDefinitions);
for (RuntimeDefinition runtimeDefinition : runtimeDefinitions) {
setChecked(runtimeDefinition,runtimeDefinition.isEnabled());
}
}
}