/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.editor.form;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.jboss.tools.common.editor.ErrorSelectionListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.ui.actions.ActionFactory;
import org.jboss.tools.common.model.ui.ModelUIPlugin;
import org.jboss.tools.common.model.ui.forms.ExpandableForm;
import org.jboss.tools.common.model.ui.widgets.IWidgetSettings;
/**
* @author Aleksey
*/
public class SampleErrorForm extends ExpandableForm {
static Color RED = Display.getDefault().getSystemColor(SWT.COLOR_RED);
static Color BLUE = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
static Color BLACK = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
static Color WHITE = Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
private Composite control;
private Composite superControl;
private Composite contentComposite;
private String errorsString;
private boolean visible;
private static final int ERROR_TYPE = 0;
private static final int ERROR_LOCATION = 1;
private static final int ERROR_MESSAGE = 2;
ErrorSelectionListener listener;
StyledText styledText = null;
StyleRange[] regions = new StyleRange[0];
public SampleErrorForm() {
super();
setHeadingText("Errors");
setCollapsable(Boolean.FALSE.booleanValue());
}
public void addErrorSelectionListener(ErrorSelectionListener listener) {
this.listener = listener;
}
/*
* @param is slava-packed error string
*
* format:
*
* ERROR_TYPE@ERROR_LOCATION@ERROR_MESSAGE_1\n
* ERROR_TYPE@ERROR_LOCATION@ERROR_MESSAGE_2\n
* ERROR_TYPE@ERROR_LOCATION@ERROR_MESSAGE_3
* or
* ERROR_MESSAGE_1\n
* ERROR_MESSAGE_2\n
* ERROR_MESSAGE_3
*
* when specify only ERROR_MESSAGE, by default ERROR_TYPE = 'ERROR', ERROR_LOCATION = 0:0
*
*/
public void initialize(Object model) {
String newErrors = (String)model;
if (newErrors==null) newErrors = ""; //$NON-NLS-1$
if (newErrors.equals(errorsString)) return;
this.errorsString = newErrors;
disposeLabels();
createLabels();
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean b) {
if (visible == b) return;
visible = b;
if (getControl()!=null && !getControl().isDisposed()) {
control.setVisible(visible);
control.setRedraw(false);
control.getParent().setRedraw(false);
control.layout(true);
control.getParent().layout(true);
control.setRedraw(true);
control.getParent().setRedraw(true);
}
}
public Control createControl(Composite parent, IWidgetSettings factory) {
if (control==null) {
control = new Composite(parent, SWT.NONE);
Font f = parent.getFont();
if(f != null) {
control.setFont(f);
}
ErrorLayout layout = new ErrorLayout();
control.setLayout(layout);
control.setLayoutData(getLayoutData());
control.setBackground(parent.getBackground());
// super
superControl = (Composite)super.createControl(control, factory);
//superControl.setLayout(getLayout());
superControl.setLayoutData(new GridData(GridData.FILL_BOTH));
if(f != null) {
superControl.setFont(f);
}
}
return control;
}
protected Control createClientArea(Composite parent, IWidgetSettings factory) {
contentComposite = new Composite(parent, SWT.NONE);
contentComposite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
contentComposite.setLayout(layout);
contentComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
if (regions != null && regions.length > 0) {
disposeLabels();
createLabels();
}
return contentComposite;
}
private StyledText getStyledText(int errorCount) {
boolean needsScroll = errorCount > 4;
int style = SWT.NONE | SWT.READ_ONLY;
if(needsScroll) style |= SWT.V_SCROLL;
if(styledText == null || styledText.isDisposed()) {
return createStyledText(style);
}
if(needsScroll != ((styledText.getStyle() & SWT.V_SCROLL) != 0)) {
styledText.dispose();
return createStyledText(style);
}
return styledText;
}
private StyledText createStyledText(int style) {
styledText = new StyledText(contentComposite, style);
styledText.setCaret(null);
GridData d = new GridData(GridData.FILL_BOTH);
styledText.setLayoutData(d);
ML ml = new ML();
styledText.addMouseMoveListener(ml);
styledText.addMouseListener(ml);
return styledText;
}
private void createLabels() {
if (this.contentComposite == null) return;
String[] errors = getErrorMessages(this.errorsString);
getStyledText(errors.length);
ArrayList<StyleRange> regionList = new ArrayList<StyleRange>();
String[] messages;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < errors.length; ++i) {
messages = parseErrorMessage(errors[i]);
int a = sb.length();
sb.append(messages[ERROR_TYPE]);
StyleRange region = new StyleRange(a, sb.length() - a, RED, null);
regionList.add(region);
a = sb.length();
sb.append(messages[ERROR_LOCATION]);
region = new StyleRange2(a, sb.length() - a, BLUE, null, messages[ERROR_LOCATION]);
regionList.add(region);
a = sb.length();
sb.append(messages[ERROR_MESSAGE]);
region = new StyleRange(a, sb.length() - a, BLACK, null);
regionList.add(region);
if(i < errors.length - 1) {
a = sb.length();
sb.append("\n"); //$NON-NLS-1$
region = new StyleRange(a, sb.length() - a, WHITE, null);
regionList.add(region);
}
}
styledText.setText(sb.toString());
regions = (StyleRange[])regionList.toArray(new StyleRange[0]);
styledText.setStyleRanges(regions);
control.update();
control.layout();
control.getParent().update();
control.getParent().layout();
}
class StyleRange2 extends StyleRange {
int line = 0;
int position = 0;
public StyleRange2(int start, int length, Color fg, Color bg, String location) {
super(start, length, fg, bg);
int i = location.indexOf(":"); //$NON-NLS-1$
line = i < 0 ? 0 : getInt(location.substring(0, i), 0);
position = i < 0 ? 0 : getInt(location.substring(i + 1), 0);
}
public void execute() {
if(listener != null) listener.errorSelected(line, position);
}
}
int getInt(String s, int def) {
if(s == null || s.length() == 0) return def;
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
return def;
}
class ML extends MouseAdapter implements MouseMoveListener {
Cursor hand = null;
Cursor arrow = null;
public void mouseMove(MouseEvent e) {
StyleRange range = getRange(e);
if(range != null && range.foreground == BLUE) {
styledText.setCursor(styledText.getShell().getDisplay().getSystemCursor(SWT.CURSOR_HAND));
} else {
styledText.setCursor(styledText.getShell().getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
}
}
public void mouseUp(MouseEvent e) {
StyleRange range = getRange(e);
if(range instanceof StyleRange2) {
((StyleRange2)range).execute();
}
}
}
StyleRange getRange(MouseEvent e) {
int offset = 0;
try {
offset = styledText.getOffsetAtLocation(new Point(e.x, e.y));
} catch (SWTException exc) {
return null;
} catch (IllegalArgumentException e2) {
return null;
}
return getRange(offset);
}
StyleRange getRange(int offset) {
for (int i = 0; i < regions.length; i++) {
if(regions[i].start <= offset && offset < regions[i].start + regions[i].length) {
return regions[i];
}
}
return null;
}
private void disposeLabels() {
if (regions != null && regions.length > 0) {
regions = new StyleRange[0];
if(styledText != null && !styledText.isDisposed()) {
styledText.setStyleRanges(regions);
styledText.setText(""); //$NON-NLS-1$
}
}
}
public void dispose() {
disposeLabels();
// dispose contentComposite
if (contentComposite!=null && !contentComposite.isDisposed()) contentComposite.dispose();
contentComposite = null;
if (control!=null && !control.isDisposed()) control.dispose();
control = null;
listener = null;
super.dispose();
}
// error reader from slava
private String[] getErrorMessages(String s) {
if(s == null) s = ""; //$NON-NLS-1$
StringTokenizer st = new StringTokenizer(s, "\n"); //$NON-NLS-1$
String[] rs = new String[st.countTokens()];
for (int i = 0; i < rs.length; i++) rs[i] = st.nextToken();
return rs;
}
// error message parser from slava
private String[] parseErrorMessage(String s) {
String[] result = new String[3];
// int line = 1;
// int position = 1;
int i = s.indexOf('@');
int j = s.indexOf('@', i + 1);
int k = s.indexOf('@', j + 1);
if(k > j) {
String q = s.substring(j + 1, k);
result[ERROR_TYPE] = s.substring(0, i);
result[ERROR_LOCATION] = q;
result[ERROR_MESSAGE] = s.substring(k + 1);
} else {
result[ERROR_TYPE] = "ERROR";
result[ERROR_LOCATION] = "0:0"; //$NON-NLS-1$
result[ERROR_MESSAGE] = s;
}
if(result[ERROR_LOCATION] == null || "0:0".equals(result[ERROR_LOCATION])) { //$NON-NLS-1$
result[ERROR_LOCATION] = ""; //$NON-NLS-1$
}
return result;
}
class ErrorLayout extends Layout {
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
if (!isVisible()) return new Point(SWT.DEFAULT,SWT.DEFAULT);
Point size = superControl.computeSize(wHint, hHint, flushCache);
if (getLayout() instanceof GridLayout) {
GridLayout layout = (GridLayout)getLayout();
size.x = size.x + layout.marginWidth*2;
size.y = size.y + layout.marginHeight*2;
}
if(size.y > 100) size.y = 100;
return size;
}
protected void layout(Composite composite, boolean flushCache) {
int x = 0;
int y = 0;
int width = composite.getClientArea().width;
int height = composite.getClientArea().height;
if (!isVisible()) return;
if (getLayout() instanceof GridLayout) {
GridLayout layout = (GridLayout)getLayout();
x = layout.marginHeight;
y = layout.marginWidth;
width = width - x*2;
height = height - y*2;
}
superControl.setBounds(x, y, width, height);
superControl.layout();
contentComposite.layout();
}
}
public boolean doGlobalAction(String actionId) {
if(styledText == null || styledText.isDisposed() || !styledText.isFocusControl()) {
return false;
}
if(styledText != null && !styledText.isDisposed()) {
if (ActionFactory.COPY.getId().equals(actionId)) {
styledText.copy();
}
}
return true;
}
}