blob: ae478f1da292ecd2c49bc3d767339270daf3914e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly marked,
* so as not to confuse it with the version available from LANL.
*
* Additionally, 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
*
* LA-CC 04-115
*******************************************************************************/
package org.eclipse.ptp.ui.views;
import java.io.File;
import java.net.URL;
import java.util.BitSet;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.ptp.internal.ui.hover.IconHover;
import org.eclipse.ptp.ui.hover.IIconInformationControl;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.Accessible;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
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.widgets.Canvas;
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.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
/**
* @author Clement chu
*
*/
public class IconCanvas extends Canvas {
public final static int SE = 1;
public final static int SW = 2;
public final static int NW = 3;
public final static int NE = 4;
protected ListenerList actionListeners = new ListenerList();
protected IToolTipProvider toolTipProvider = null;
protected IImageProvider imageProvider = null;
protected IContentProvider contentProvider = null;
// default element info
protected int e_offset_x = 5;
protected int e_offset_y = 5;
protected int e_spacing_x = 4;
protected int e_spacing_y = 4;
protected int e_width = 16;
protected int e_height = 16;
protected int max_e_row = -1;
protected int max_e_col = -1;
// key and listener
protected Hashtable<Integer, Integer> keyActionMap = new Hashtable<Integer, Integer>();
protected Listener listener = null;
protected boolean mouseDown = false;
protected boolean mouseDoubleClick = false;
// scrolling and selection
protected int firstSelectedIndex = -1;
protected int secondSelectedIndex = -1; //for mac
protected BitSet selectedElements = new BitSet();
protected BitSet tempSelectedElements = new BitSet();
protected int sel_size = 1;
protected final int sel_length = 2;
protected final int sel_gap = 2;
protected Color sel_color = null;
protected Point selection = null;
protected Point movingSelectionStart = null;
protected Point movingSelectionEnd = null;
protected int current_top_row = -1;
protected int actualScrollStart_y = 0;
protected int autoScrollDirection = SWT.NULL;
protected int verticalScrollOffset = 0;
// mouse and color
protected Cursor defaultCursor = null;
protected Color background = null;
protected Color foreground = null;
//font
protected final int DEFAULT_FONT_SIZE = 9;
protected int font_size = DEFAULT_FONT_SIZE;
//margin
protected final int margin_text = 2;
protected Color margin_color = null;
protected boolean displayRuler = true;
private final int DEFAULT_OFFSET = 5;
// tooltip
private IconHover iconHover = new IconHover();
protected IIconInformationControl fInformationControl = null;
protected long tooltip_timeout = 10000;
protected boolean show_tooltip_allthetime = false;
private Timer hoverTimer = null;
protected boolean tooltip_wrap = true;
protected boolean show_tooltip = true;
// input
protected int total_elements = 0;
final static boolean IS_CARBON, IS_GTK, IS_MOTIF;
final static boolean DOUBLE_BUFFER;
static {
String platform = SWT.getPlatform();
IS_CARBON = "carbon".equals(platform);
IS_GTK = "gtk".equals(platform);
IS_MOTIF = "motif".equals(platform);
DOUBLE_BUFFER = !IS_CARBON;
}
/** Constructor
* @param parent
* @param style composite style
*/
public IconCanvas(Composite parent, int style) {
super(parent, SWT.V_SCROLL | SWT.WRAP | SWT.MULTI | style);
Display display = getDisplay();
calculateVerticalScrollBar();
createKeyBindings();
defaultCursor = new Cursor(display, SWT.CURSOR_ARROW);
setCursor(defaultCursor);
installListeners();
initializeAccessible();
sel_color = display.getSystemColor(SWT.COLOR_RED);
margin_color = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
changeFontSize(display);
super.setBackground(getBackground());
super.setForeground(getForeground());
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
public void dispose() {
if (fInformationControl != null) {
fInformationControl.dispose();
}
super.dispose();
}
/** Change font size
* @param display
*/
private void changeFontSize(Display display) {
FontData[] data = getFont().getFontData();
for (int i = 0; i < data.length; i++) {
data[i].setHeight(font_size);
}
setFont(new Font(display, data));
}
/** Add action listener
* @param actionListener
*/
public void addActionListener(IIconCanvasActionListener actionListener) {
actionListeners.add(actionListener);
}
/** Remove action listener
* @param actionListener
*/
public void removeActionListener(IIconCanvasActionListener actionListener) {
actionListeners.remove(actionListener);
}
/** Fire action
* @param type type of action
*/
protected void fireAction(final int type) {
Object[] array = actionListeners.getListeners();
for (int i = 0; i < array.length; i++) {
final IIconCanvasActionListener l = (IIconCanvasActionListener) array[i];
SafeRunnable.run(new SafeRunnable() {
public void run() {
l.handleAction(type, getSelectedIndexes());
}
});
}
}
/** Fire action
* @param type type of action
* @param index element index
*/
protected void fireAction(final int type, final int index) {
if (index > -1) {
Object[] array = actionListeners.getListeners();
for (int i = 0; i < array.length; i++) {
final IIconCanvasActionListener l = (IIconCanvasActionListener) array[i];
SafeRunnable.run(new SafeRunnable() {
public void run() {
l.handleAction(type, index);
}
});
}
}
}
/** Reset canvas setting
*
*/
public void resetCanvas() {
checkWidget();
current_top_row = -1;
actualScrollStart_y = 0;
autoScrollDirection = SWT.NULL;
verticalScrollOffset = 0;
unselectAllElements();
firstSelectedIndex = -1;
secondSelectedIndex = -1;
selection = null;
resetMargin();
resetInfo();
getVerticalBar().setSelection(0);
calculateVerticalScrollBar();
redraw();
}
/** Get tooltip provider
* @return
*/
public IToolTipProvider getToolTipProvider() {
return toolTipProvider;
}
/** Set tooltip provider
* @param toolTipProvider
*/
public void setToolTipProvider(IToolTipProvider toolTipProvider) {
this.toolTipProvider = toolTipProvider;
}
public void setShowTooltip(boolean show) {
this.show_tooltip = show;
}
/** Get image provider
* @return
*/
public IImageProvider getImageProvider() {
return imageProvider;
}
/** Set image provider
* @param imageProvider
*/
public void setImageProvider(IImageProvider imageProvider) {
this.imageProvider = imageProvider;
}
/** Get content provider
* @return
*/
public IContentProvider getContentProvider() {
return contentProvider;
}
/** Set content provider
* @param contentProvider
*/
public void setContentProvider(IContentProvider contentProvider) {
this.contentProvider = contentProvider;
}
/** Get totla elements
* @param total total elements
*/
public void setTotal(int total) {
if (total < 0) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
this.total_elements = total;
resetCanvas();
}
/** Reset margin of view
*
*/
private void resetMargin() {
e_offset_x = DEFAULT_OFFSET;
if (isDisplayRuler()) {
GC newGC = getGC();
newGC.setFont(getFont());
if (total_elements > 0) {
//Get the last index number to determine the width of ruler bar
Object obj = contentProvider.getObject(total_elements-1);
if (obj != null) {
String text = contentProvider.getRulerIndex(obj, total_elements-1);
e_offset_x = newGC.stringExtent(text).x + e_spacing_x + margin_text;
}
}
newGC.dispose();
}
}
public void setFontSizeSmaller() {
setFontSize(font_size-1);
}
public void setFontSizeBigger() {
setFontSize(font_size+1);
}
public void setFontSize(int fontSize) {
if (fontSize < 5) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
this.font_size = fontSize;
changeFontSize(getDisplay());
}
/** Set icon spacing
* @param e_spacing_x
* @param e_spacing_y
*/
public void setIconSpace(int e_spacing_x, int e_spacing_y) {
if (e_spacing_x < 0 || e_spacing_y < 0) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
this.e_spacing_x = e_spacing_x;
this.e_spacing_y = e_spacing_y;
}
/** Set icon size
* @param e_width
* @param e_height
*/
public void setIconSize(int e_width, int e_height) {
if (e_width <= 0 || e_height <= 0) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
this.e_height = e_height;
this.e_width = e_width;
}
/** Set tooltip setting
* @param showAllTime
* @param timeout
* @param isWrap
*/
public void setTooltip(boolean showAllTime, long timeout, boolean isWrap) {
showTooltipAllthetime(showAllTime);
setTooltipTimeout(timeout);
setTooltipWrap(isWrap);
}
/** Set tooltip timeout
* @param timeout
*/
public void setTooltipTimeout(long timeout) {
if (timeout <= 0) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
tooltip_timeout = timeout;
}
/** Set tooltip to show all the time
* @param isAll
*/
public void showTooltipAllthetime(boolean isAll) {
show_tooltip_allthetime = isAll;
}
/** Set tooltip content displaying
* @param isWrap
*/
public void setTooltipWrap(boolean isWrap) {
tooltip_wrap = isWrap;
}
/** Get total elements
* @return total elements
*/
public int getTotalElements() {
return total_elements;
}
/** Set selection size
* @param size
*/
public void setSelectionSize(int size) {
this.sel_size = size;
}
/** Set selection color
* @param colorIndex
*/
public void setSelectionColor(int colorIndex) {
checkWidget();
this.sel_color = getDisplay().getSystemColor(colorIndex);
}
/**Show ruler
* @param displayRuler
*/
public void setDisplayRuler(boolean displayRuler) {
this.displayRuler = displayRuler;
resetCanvas();
}
/** Is ruler displayed
* @return
*/
public boolean isDisplayRuler() {
return displayRuler;
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Control#getBackground()
*/
public Color getBackground() {
checkWidget();
if (background == null) {
return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
}
return background;
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
*/
public void setBackground(Color color) {
checkWidget();
background = color;
super.setBackground(getBackground());
redraw();
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Control#getForeground()
*/
public Color getForeground() {
checkWidget();
if (foreground == null) {
return getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
}
return foreground;
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Control#setForeground(org.eclipse.swt.graphics.Color)
*/
public void setForeground(Color color) {
checkWidget();
foreground = color;
super.setForeground(getForeground());
redraw();
}
/** Get element height
* @return element height
*/
protected int getElementHeight() {
return (e_spacing_y + e_height);
}
/** Get element width
* @return element width
*/
protected int getElementWidth() {
return (e_spacing_x + e_width);
}
/** Get maximum column to display
* @return maximum column
*/
protected int getMaxCol() {
if (max_e_col == -1) {
int width = getClientArea().width - getVerticalBar().getSize().x;
max_e_col = Math.max(0, (width - e_offset_x) / getElementWidth() + 1);
}
return max_e_col;
}
/** Get maximum client row
* @return maximum row number
*/
protected int getMaxClientRow() {
return (getClientArea().height - e_offset_y) / getElementHeight();
}
/** Get maximum row
* @return maximum row
*/
protected int getMaxRow() {
if (max_e_row == -1) {
int total = getTotalElements();
if (total == 0)
return 0;
int max_col = getMaxCol();
if (max_col == 0)
return 0;
int max_row = total / max_col;
max_e_row = total % max_col == 0 ? max_row : max_row + 1;
}
return max_e_row;
}
/** Get maximum height of view
* @return maximum height
*/
protected int getMaxHeight() {
return getMaxRow() * getElementHeight();
}
/** Get vertical increment
* @return
*/
protected int getVerticalIncrement() {
return e_spacing_y + e_height;
}
/** Calculate vertical scrollbar
*
*/
protected void calculateVerticalScrollBar() {
setVerticalScrollBar(getVerticalBar());
}
/** Set vertical scrollbar
* @param verticalBar
*/
protected void setVerticalScrollBar(ScrollBar verticalBar) {
if (verticalBar != null) {
Rectangle clientArea = getClientArea();
final int INACTIVE = 1;
int max_height = getMaxHeight() + e_offset_y + sel_size;
if (clientArea.height < max_height) {
verticalBar.setValues(verticalBar.getSelection(), verticalBar.getMinimum(), max_height, clientArea.height, getVerticalIncrement(), clientArea.height);
} else if (verticalBar.getThumb() != INACTIVE || verticalBar.getMaximum() != INACTIVE) {
verticalBar.setValues(verticalBar.getSelection(), verticalBar.getMinimum(), INACTIVE, INACTIVE, getVerticalIncrement(), INACTIVE);
}
}
}
/** Claim bottom free space
* @return
*/
protected boolean claimBottomFreeSpace() {
int newVerticalOffset = Math.max(0, getMaxHeight() - getClientArea().height);
if (newVerticalOffset < verticalScrollOffset) {
return setVerticalScrollOffset(newVerticalOffset, true);
}
return false;
}
/** Get current top row
* @return top row number
*/
protected int getCurrentTopRow() {
return current_top_row;
}
/** Get key
* @param key unique key
* @return keyboard key ID
*/
public int getKeyBinding(int key) {
checkWidget();
Integer action = keyActionMap.get(new Integer(key));
int intAction;
if (action == null) {
intAction = SWT.NULL;
} else {
intAction = action.intValue();
}
return intAction;
}
/** Set key
* @param key unique key
* @param action keyboard key ID
*/
public void setKeyBinding(int key, int action) {
checkWidget();
int keyValue = key & SWT.KEY_MASK;
int modifierValue = key & SWT.MODIFIER_MASK;
char keyChar = (char) keyValue;
if (Character.isLetter(keyChar)) {
char ch = Character.toUpperCase(keyChar);
int newKey = ch | modifierValue;
if (action == SWT.NULL) {
keyActionMap.remove(new Integer(newKey));
} else {
keyActionMap.put(new Integer(newKey), new Integer(action));
}
ch = Character.toLowerCase(keyChar);
newKey = ch | modifierValue;
if (action == SWT.NULL) {
keyActionMap.remove(new Integer(newKey));
} else {
keyActionMap.put(new Integer(newKey), new Integer(action));
}
} else {
if (action == SWT.NULL) {
keyActionMap.remove(new Integer(key));
} else {
keyActionMap.put(new Integer(key), new Integer(action));
}
}
}
/** Create keyboard binding
*
*/
protected void createKeyBindings() {
// Navigation
setKeyBinding(SWT.ARROW_UP, ST.LINE_UP);
setKeyBinding(SWT.ARROW_DOWN, ST.LINE_DOWN);
setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_PREVIOUS);
setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_NEXT);
setKeyBinding(SWT.HOME, ST.LINE_START);
setKeyBinding(SWT.END, ST.LINE_END);
setKeyBinding(SWT.PAGE_UP, ST.PAGE_UP);
setKeyBinding(SWT.PAGE_DOWN, ST.PAGE_DOWN);
// Selection
setKeyBinding('A' | SWT.MOD1, ST.SELECT_ALL);
setKeyBinding(SWT.ARROW_UP | SWT.MOD2, ST.SELECT_LINE_UP);
setKeyBinding(SWT.ARROW_DOWN | SWT.MOD2, ST.SELECT_LINE_DOWN);
setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS);
setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_NEXT);
setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_LINE_START);
setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_LINE_END);
setKeyBinding(SWT.PAGE_UP | SWT.MOD2, ST.SELECT_PAGE_UP);
setKeyBinding(SWT.PAGE_DOWN | SWT.MOD2, ST.SELECT_PAGE_DOWN);
// Modification
// Cut, Copy, Paste, delete
setKeyBinding('X' | SWT.MOD1, ST.CUT);
setKeyBinding('C' | SWT.MOD1, ST.COPY);
setKeyBinding('V' | SWT.MOD1, ST.PASTE);
setKeyBinding(SWT.BS, ST.DELETE_PREVIOUS);
setKeyBinding(SWT.DEL, ST.DELETE_NEXT);
}
/** Invoke action
* @param action action ID
*/
public void invokeAction(int action) {
checkWidget();
switch (action) {
// Navigation
case ST.LINE_UP:
doUp(false);
break;
case ST.LINE_DOWN:
doDown(false);
break;
case ST.COLUMN_PREVIOUS:
doPrevious(false);
break;
case ST.COLUMN_NEXT:
doNext(false);
break;
case ST.LINE_START:
doLineStart(false);
break;
case ST.LINE_END:
doLineEnd(false);
break;
case ST.PAGE_UP:
doPageUp(getMaxClientRow());
break;
case ST.PAGE_DOWN:
doPageDown(getMaxClientRow());
break;
// Selection
case ST.SELECT_ALL:
doSelectionAll();
break;
case ST.SELECT_LINE_UP:
doUp(true);
break;
case ST.SELECT_LINE_DOWN:
doDown(true);
break;
case ST.SELECT_COLUMN_PREVIOUS:
doPrevious(true);
break;
case ST.SELECT_COLUMN_NEXT:
doNext(true);
break;
case ST.SELECT_LINE_START:
doLineStart(true);
break;
case ST.SELECT_LINE_END:
doLineEnd(true);
break;
case ST.SELECT_PAGE_UP:
doSelectionPageUp(getMaxClientRow());
break;
case ST.SELECT_PAGE_DOWN:
doSelectionPageDown(getMaxClientRow());
break;
// Modification
case ST.CUT:
doCut();
break;
case ST.COPY:
doCopy();
break;
case ST.PASTE:
doPaste();
break;
case ST.DELETE_PREVIOUS:
doDelete();
break;
case ST.DELETE_NEXT:
doDelete();
break;
default:
break;
}
}
/** initial accessiable
*
*/
protected void initializeAccessible() {
final Accessible accessible = getAccessible();
accessible.addAccessibleListener(new AccessibleAdapter() {
public void getHelp(AccessibleEvent e) {
e.result = getToolTipText();
}
});
accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
public void getRole(AccessibleControlEvent e) {
e.detail = ACC.ROLE_TEXT;
}
public void getState(AccessibleControlEvent e) {
int state = 0;
if (isEnabled())
state |= ACC.STATE_FOCUSABLE;
if (isFocusControl())
state |= ACC.STATE_FOCUSED;
if (isVisible() == false)
state |= ACC.STATE_INVISIBLE;
e.detail = state;
}
});
addListener(SWT.FocusIn, new Listener() {
public void handleEvent(Event event) {
accessible.setFocus(ACC.CHILDID_SELF);
}
});
}
/** install listeners
*
*/
protected void installListeners() {
ScrollBar verticalBar = getVerticalBar();
listener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose:
handleDispose(event);
break;
case SWT.KeyDown:
handleKeyDown(event);
break;
case SWT.KeyUp:
handleKeyUp(event);
break;
case SWT.MouseDown:
handleMouseDown(event);
break;
case SWT.MouseUp:
handleMouseUp(event);
break;
case SWT.MouseDoubleClick:
handleMouseDoubleClick(event);
break;
case SWT.MouseMove:
handleMouseMove(event);
break;
case SWT.MouseHover:
handleMouseHover(event);
break;
case SWT.Paint:
handlePaint(event);
break;
case SWT.Resize:
handleResize(event);
break;
case SWT.FocusOut:
handleFocusOut(event);
break;
}
}
};
addListener(SWT.Dispose, listener);
addListener(SWT.KeyDown, listener);
addListener(SWT.KeyUp, listener);
addListener(SWT.MouseDown, listener);
addListener(SWT.MouseUp, listener);
addListener(SWT.MouseDoubleClick, listener);
addListener(SWT.MouseMove, listener);
addListener(SWT.MouseHover, listener);
addListener(SWT.Paint, listener);
addListener(SWT.Resize, listener);
addListener(SWT.FocusOut, listener);
if (verticalBar != null) {
verticalBar.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
setVerticalScrollOffset(getVerticalBar().getSelection(), true);
}
});
}
}
/** Handle key
* @param event
*/
protected void handleKey(Event event) {
int action;
if (event.keyCode != 0) {
action = getKeyBinding(event.keyCode | event.stateMask);
} else {
action = getKeyBinding(event.character | event.stateMask);
if (action == SWT.NULL) {
if ((event.stateMask & SWT.CTRL) != 0 && (event.character >= 0) && event.character <= 31) {
int c = event.character + 64;
action = getKeyBinding(c | event.stateMask);
}
}
}
if (action != SWT.NULL) {
invokeAction(action);
}
}
/** Is reached top of view
* @return true if vertical scroll offset is 0
*/
protected boolean isReachTop() {
return (verticalScrollOffset <= 0);
}
/** Is reach bottom of view
* @return true if vertical scroll to bottom of view
*/
protected boolean isReachBottom() {
return (getMaxRow() - current_top_row <= getMaxClientRow());
}
/** Do auto scrolling
* @param x_loc
* @param y_loc
*/
protected void doAutoScroll(int x_loc, int y_loc) {
if (y_loc > getClientArea().height && !isReachBottom()) {
hideToolTip();
doAutoScroll(SWT.DOWN, getVerticalIncrement(), x_loc, y_loc);
} else if (y_loc < 0 && !isReachTop()) {
hideToolTip();
doAutoScroll(SWT.UP, -getVerticalIncrement(), x_loc, y_loc);
} else {
if (movingSelectionStart == null) {
movingSelectionStart = new Point(selection.x, selection.y);
} else {
doMouseSelection(movingSelectionStart.x, movingSelectionStart.y, x_loc, y_loc, false);
}
endAutoScroll();
}
}
/** Do auto scrolling
* @param direction
* @param distance
* @param x_loc
* @param y_loc
*/
protected void doAutoScroll(int direction, final int distance, final int x_loc, final int y_loc) {
// If we're already autoscrolling in the given direction do nothing
if (autoScrollDirection == direction) {
return;
}
Runnable timer = null;
final int TIMER_INTERVAL = 50;
final Display display = getDisplay();
if (direction == SWT.UP) {
timer = new Runnable() {
public void run() {
if (autoScrollDirection == SWT.UP && !isReachTop()) {
doSelectionPageUp(distance, x_loc, y_loc, true);
display.timerExec(TIMER_INTERVAL, this);
}
}
};
} else if (direction == SWT.DOWN) {
timer = new Runnable() {
public void run() {
if (autoScrollDirection == SWT.DOWN && !isReachBottom()) {
doSelectionPageDown(distance, x_loc, y_loc, true);
display.timerExec(TIMER_INTERVAL, this);
}
}
};
}
if (timer != null) {
autoScrollDirection = direction;
display.timerExec(TIMER_INTERVAL, timer);
}
}
/** Do selection page up
* @param distance
*/
protected void doSelectionPageUp(int distance) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > 0) {
int max_col = getMaxCol();
int max_row = getMaxClientRow() - 1;
int total_in_page = max_col * max_row;
int start_index = Math.max(0, (index - total_in_page));
actualScrollStart_y -= max_row * getElementHeight();
if (actualScrollStart_y - verticalScrollOffset < 0) {
doPageUp(max_row);
}
selection.y = Math.max(0, actualScrollStart_y - verticalScrollOffset);
selectElements(start_index, index);
redraw(start_index, index);
}
}
/** Do selection page down
* @param distance
*/
protected void doSelectionPageDown(int distance) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1) {
int max_col = getMaxCol();
int max_row = getMaxClientRow() - 1;
int total_in_page = max_col * max_row;
int end_index = Math.min(getTotalElements(), (index + total_in_page));
actualScrollStart_y += max_row * getElementHeight();
if (actualScrollStart_y - verticalScrollOffset > (max_row + 1) * getElementHeight()) {
doPageDown(max_row);
}
selection.y = Math.max(0, actualScrollStart_y - verticalScrollOffset);
selectElements(index, end_index);
redraw(index, end_index);
}
}
/** Do selection page up
* @param distance
* @param x_loc
* @param y_loc
* @param isSelect
*/
protected void doSelectionPageUp(int distance, int x_loc, int y_loc, boolean isSelect) {
doPageUp(distance / getElementHeight());
if (movingSelectionStart != null && isSelect) {
movingSelectionStart.y += getVerticalIncrement();
doMouseSelection(movingSelectionStart.x, movingSelectionStart.y, x_loc, y_loc, true);
}
}
/** Do selection page down
* @param distance
* @param x_loc
* @param y_loc
* @param isSelect
*/
protected void doSelectionPageDown(int distance, int x_loc, int y_loc, boolean isSelect) {
doPageDown(distance / getElementHeight());
if (movingSelectionStart != null && isSelect) {
movingSelectionStart.y -= getVerticalIncrement();
doMouseSelection(movingSelectionStart.x, movingSelectionStart.y, x_loc, y_loc, true);
}
}
/** Do delete
*
*/
protected void doDelete() {
fireAction(IIconCanvasActionListener.DELETE_ACTION);
}
/** Do copy
*
*/
protected void doCopy() {
fireAction(IIconCanvasActionListener.COPY_ACTION);
}
/** Do cut
*
*/
protected void doCut() {
fireAction(IIconCanvasActionListener.CUT_ACTION);
}
/** Do paste
*
*/
protected void doPaste() {
fireAction(IIconCanvasActionListener.PASTE_ACTION);
}
/** Do page up
* @param rows number of row to page up
*/
protected void doPageUp(int rows) {
if (current_top_row >= 0 && verticalScrollOffset > 0) {
int scrollRows = Math.max(1, Math.min(current_top_row, rows));
current_top_row -= scrollRows;
if (current_top_row < 0)
current_top_row = 0;
// scroll one page up or to the top
int scrollOffset = Math.max(0, verticalScrollOffset - scrollRows * getVerticalIncrement());
if (scrollOffset < verticalScrollOffset) {
setVerticalScrollOffset(scrollOffset, true);
}
}
}
/** Do page down
* @param rows number of row to page down
*/
protected void doPageDown(int rows) {
int max_row = getMaxRow();
int max_client_row = getMaxClientRow();
if (current_top_row < max_row - max_client_row) {
int scrollRows = Math.max(1, Math.min(max_row - current_top_row - max_client_row, rows));
current_top_row += scrollRows;
// scroll one page down or to the bottom
int scrollOffset = Math.min(verticalScrollOffset + (scrollRows * getVerticalIncrement()), (max_row - max_client_row) * getElementHeight());
if (scrollOffset > verticalScrollOffset) {
setVerticalScrollOffset(scrollOffset, true);
}
}
}
/** Do up
* @param isSelect true if element is selected
*/
protected void doUp(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > 0) {
int max_col = getMaxCol();
if ((index - max_col) > -1) {
actualScrollStart_y -= getElementHeight();
if (selection.y < getVerticalIncrement()) {
doPageUp(1);
}
selection.y = actualScrollStart_y - verticalScrollOffset;
boolean redrawAll = !selectedElements.isEmpty();
if (!isSelect) {
unselectAllElements();
selectedElements.set(index - max_col);
}
else {
if (!isSelected(index - max_col))
selectElements(index-max_col, index);
else
unselectElements(index-max_col+1, index);
}
if (redrawAll)
redraw();
else
redraw(index - max_col, index);
}
}
}
/** Do down
* @param isSelect true if element is selected
*/
protected void doDown(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1) {
int max_col = getMaxCol();
if ((index + max_col) < getTotalElements()) {
actualScrollStart_y += getElementHeight();
if (selection.y + getVerticalIncrement() > getMaxClientRow() * getElementHeight()) {
doPageDown(1);
}
selection.y = actualScrollStart_y - verticalScrollOffset;
boolean redrawAll = !selectedElements.isEmpty();
if (!isSelect) {
unselectAllElements();
selectedElements.set(index + max_col);
}
else {
if (!isSelected(index + max_col))
selectElements(index, index+max_col);
else
unselectElements(index, index+max_col-1);
}
if (redrawAll)
redraw();
else
redraw(index, index + max_col);
}
}
}
/** Go previous
* @param isSelect true if element is selected
*/
protected void doPrevious(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > 0) {
selection.x -= getElementWidth();
if (selection.x < e_offset_x) {
actualScrollStart_y -= getElementHeight();
if (actualScrollStart_y - verticalScrollOffset < getVerticalIncrement()) {
doPageUp(1);
}
selection.x = e_offset_x + (getMaxCol() * getElementWidth()) - e_width;
selection.y = actualScrollStart_y - verticalScrollOffset;
}
boolean redrawAll = !selectedElements.isEmpty();
if (!isSelect) {
unselectAllElements();
}
if (!isSelected(index - 1))
autoSelectUnselectElement(index - 1);
else
selectedElements.clear(index);
if (redrawAll)
redraw();
else
redraw(index-1, index);
}
}
/** Go next
* @param isSelect true if element is selected
*/
protected void doNext(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1 && index < getTotalElements() - 1) {
selection.x += getElementWidth();
if (selection.x > (getMaxCol() * getElementWidth() + e_offset_x)) {
actualScrollStart_y += getElementHeight();
if (selection.y + getVerticalIncrement() > getMaxClientRow() * getElementHeight()) {
doPageDown(1);
}
selection.x = e_offset_x + e_spacing_x;
selection.y = actualScrollStart_y - verticalScrollOffset;
}
boolean redrawAll = !selectedElements.isEmpty();
if (!isSelect) {
unselectAllElements();
}
if (!isSelected(index + 1))
autoSelectUnselectElement(index + 1);
else
selectedElements.clear(index);
if (redrawAll)
redraw();
else
redraw(index, index+1);
}
}
/** Go to line start
* @param isSelect true if element is selected
*/
protected void doLineStart(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1) {
int start_pos_x = e_offset_x + e_spacing_x;
int start_index = findSelectedIndexByLocation(start_pos_x, (actualScrollStart_y - verticalScrollOffset), false);
if (start_index > -1) {
selection.x = start_pos_x;
if (!isSelect) {
selectedElements.clear(index);
autoSelectUnselectElement(start_index);
}
else {
selectElements(start_index, index);
}
redraw(start_index, index);
}
}
}
/** Go to line end
* @param isSelect true if element is selected
*/
protected void doLineEnd(boolean isSelect) {
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1) {
if (!isSelect)
selectedElements.clear(index);
int total = getTotalElements() - 1;
if (index > total - getMaxCol()) {
int end_counter = total - index;
selection.x = (end_counter + 1) * getElementWidth() + e_offset_x;
if (!isSelect)
autoSelectUnselectElement(index + end_counter);
else
selectElements(index, index + end_counter);
redraw(index, index + end_counter);
} else {
int end_pos_x = e_offset_x + (getMaxCol() * getElementWidth()) - e_width;
int end_index = findSelectedIndexByLocation(end_pos_x, (actualScrollStart_y - verticalScrollOffset), false);
if (end_index > -1) {
selection.x = end_pos_x;
if (!isSelect)
autoSelectUnselectElement(end_index);
else
selectElements(index, end_index);
redraw(index, end_index);
} else {
redraw(index, index);
}
}
}
}
/** Select all elements
*
*/
protected void doSelectionAll() {
selectedElements.set(0, getTotalElements());
redraw();
}
/** Set vertical scrollbar offset
* @param pixelOffset
* @param adjustScrollBar
* @return
*/
protected boolean setVerticalScrollOffset(int pixelOffset, boolean adjustScrollBar) {
if (pixelOffset == verticalScrollOffset) {
return false;
}
ScrollBar verticalBar = getVerticalBar();
if (verticalBar != null && adjustScrollBar) {
verticalBar.setSelection(pixelOffset);
}
Rectangle clientArea = getClientArea();
scroll(0, 0, 0, pixelOffset - verticalScrollOffset, clientArea.width, clientArea.height, adjustScrollBar);
verticalScrollOffset = pixelOffset;
calculateTopIndex();
return true;
}
/** Finished auto scrolling
*
*/
protected void endAutoScroll() {
autoScrollDirection = SWT.NULL;
}
/** Calculate top index
*
*/
protected void calculateTopIndex() {
int verticalIncrement = getVerticalIncrement();
if (verticalIncrement == 0) {
return;
}
current_top_row = verticalScrollOffset / verticalIncrement;
if (current_top_row > 0) {
int max_row = getMaxRow();
int clientAreaHeight = getClientArea().height;
if (clientAreaHeight > 0) {
int fullRowTopPixel = current_top_row * verticalIncrement;
if (verticalScrollOffset < fullRowTopPixel) {
current_top_row--;
}
} else if (current_top_row >= max_row) {
current_top_row = max_row - 1;
}
}
}
/** Get selected column
* @param x_loc
* @param isApproximate
* @return column number
*/
protected int getSelectedCol(int x_loc, boolean isApproximate) {
int col = Math.min(x_loc / getElementWidth(), getMaxCol() - 1);
if (isApproximate)
return col;
int test_loc_x = getElementWidth() * col;
if (x_loc > test_loc_x && x_loc < (test_loc_x + e_width)) {
return col;
}
return -1;
}
/** Get selected row
* @param y_loc
* @param isApproximate
* @return row number
*/
protected int getSelectedRow(int y_loc, boolean isApproximate) {
int row = Math.max(0, (verticalScrollOffset + y_loc) / getElementHeight());
if (isApproximate)
return row;
int test_loc_y = (getElementHeight() * row) - verticalScrollOffset;
if (y_loc > test_loc_y && y_loc < (test_loc_y + e_height)) {
return row;
}
return -1;
}
/** Find selected index
* @param row
* @param col
* @return selected index
*/
protected int findSelectedIndex(int row, int col) {
return row * getMaxCol() + col;
}
/** Find selected index
* @param loc_x
* @param loc_y
* @param isApproximate true if searching is approximate
* @return -1 if not found
*/
protected int findSelectedIndexByLocation(int loc_x, int loc_y, boolean isApproximate) {
int col = getSelectedCol(loc_x - e_offset_x, isApproximate);
if (col > -1) {
int row = getSelectedRow(loc_y - e_offset_y, isApproximate);
if (row > -1) {
int index = findSelectedIndex(row, col);
if (index < getTotalElements())
return index;
}
}
return -1;
}
/** Find column and row
* @param index element index
* @return x is column and y is row
*/
protected Point findSection(int index) {
int max_col = getMaxCol();
int col = (int) Math.floor(index % max_col);
int row = (int) Math.floor(index / max_col);
return new Point(col, row);
}
/** Find location
* @param index element index
* @return location of target element
*/
protected Point findLocation(int index) {
Point section = findSection(index);
int x_loc = (section.x * getElementWidth() + e_offset_x + 1); //plus 1 for margin
int y_loc = (section.y * getElementHeight() + e_offset_y + 1) - verticalScrollOffset;
return new Point(x_loc, y_loc);
}
/** Get direction
* @param s_x
* @param s_y
* @param e_x
* @param e_y
* @return
*/
protected int getDirection(int s_x, int s_y, int e_x, int e_y) {
int direction = SE;
if (s_x > e_x) {
direction = SW;
}
if (s_y > e_y) {
if (direction == SW)
direction = NW;
else
direction = NE;
}
return direction;
}
/** Get select elements
* @param col_start
* @param col_end
* @param row_start
* @param row_end
* @return selected elements
*/
protected BitSet selectElements(int col_start, int col_end, int row_start, int row_end) {
BitSet newElements = new BitSet();
int total = getTotalElements();
for (int row_count = row_start; row_count < row_end; row_count++) {
for (int col_count = col_start; col_count < col_end; col_count++) {
int index = findSelectedIndex(row_count, col_count);
if (index > -1 && index < total) {
newElements.set(index);
}
//indicate the first selected element when dragging
if (firstSelectedIndex == -1 || firstSelectedIndex > index) {
firstSelectedIndex = index;
}
}
}
return newElements;
}
/** Get started point
* @param x
* @param y
* @return
*/
private Point getStartedPoint(int x, int y) {
return new Point(Math.max(e_offset_x-e_spacing_x, x), Math.max(0, Math.min((getMaxRow() - current_top_row) * getElementHeight() + sel_size, y)));
}
/** Get finished point
* @param x
* @param y
* @return
*/
private Point getFinishedPoint(int x, int y) {
return new Point(Math.min(getMaxCol()*getElementWidth() + e_offset_x - e_spacing_x, Math.max(e_offset_x-e_spacing_x, x)), Math.min((getMaxRow() - current_top_row) * getElementHeight() + sel_size, Math.max(0 + sel_size, y)));
}
/** Do mouse selection
* @param mouse_start_x
* @param mouse_start_y
* @param mouse_end_x
* @param mouse_end_y
* @param isScrolling
*/
protected void doMouseSelection(int mouse_start_x, int mouse_start_y, int mouse_end_x, int mouse_end_y, boolean isScrolling) {
if (mouse_start_x < (e_offset_x - getElementWidth()) || mouse_start_y > (getMaxRow() - current_top_row + 1) * getElementHeight())
return;
boolean isInitialPage = (mouse_start_y - verticalScrollOffset == actualScrollStart_y);
Point start_pt = getStartedPoint(mouse_start_x, mouse_start_y);
Point end_pt = getFinishedPoint(mouse_end_x, mouse_end_y);
int direction = getDirection(movingSelectionStart.x, movingSelectionStart.y, end_pt.x, end_pt.y);
int s_x = start_pt.x;
int e_x = end_pt.x;
int s_y = isInitialPage ? start_pt.y : (actualScrollStart_y - verticalScrollOffset);
int e_y = end_pt.y;
switch (direction) {
case SW:
s_x = end_pt.x;
e_x = start_pt.x;
break;
case NW:
s_x = end_pt.x;
e_x = start_pt.x;
s_y = end_pt.y;
e_y = start_pt.y;
break;
case NE:
s_y = end_pt.y;
e_y = start_pt.y;
break;
}
int d_sx = s_x - e_offset_x + e_spacing_x;
int d_ex = e_x - e_offset_x;
int d_sy = s_y - e_offset_y + e_spacing_y;
int d_ey = e_y - e_offset_y;
int col_start = Math.max(0, getSelectedCol(d_sx, true));
int col_end = Math.min(getSelectedCol(d_ex, true) + 1, getMaxCol());
int row_start = Math.max(0, getSelectedRow(d_sy, true));
int row_end = Math.min(getSelectedRow(d_ey, true) + 1, getMaxRow());
tempSelectedElements.clear();
tempSelectedElements.or(selectElements(col_start, col_end, row_start, row_end));
if (movingSelectionEnd != null) {
int last_end_x = movingSelectionEnd.x;
int last_end_y = movingSelectionEnd.y;
// redraw whole view if changed the direction
if (getDirection(movingSelectionStart.x, movingSelectionStart.y, last_end_x, last_end_y) != direction || (isScrolling && (isReachTop() || isReachBottom()))) {
movingSelectionEnd.x = end_pt.x;
movingSelectionEnd.y = end_pt.y;
redraw();
return;
}
switch (direction) {
case SE:
if (e_x < last_end_x) {
d_ex = last_end_x - e_offset_x - e_spacing_x;
col_end = Math.min(getSelectedCol(d_ex, true) + 1, getMaxCol());
}
if (e_y < last_end_y) {
d_ey = last_end_y - e_offset_y - e_spacing_y;
row_end = Math.min(getSelectedRow(d_ey, true) + 1, getMaxRow());
}
break;
case SW:
if (e_x > last_end_x) {
d_sx = last_end_x - e_offset_x + e_spacing_x;
col_start = Math.max(0, getSelectedCol(d_sx, true));
}
if (e_y < last_end_y) {
d_ey = last_end_y - e_offset_y - e_spacing_y;
row_end = Math.min(getSelectedRow(d_ey, true) + 1, getMaxRow());
}
break;
case NW:
if (e_x > last_end_x) {
d_sx = last_end_x - e_offset_x + e_spacing_x;
col_start = Math.max(0, getSelectedCol(d_sx, true));
}
if (e_y > last_end_y) {
d_sy = last_end_y - e_offset_y + e_spacing_y;
row_start = Math.max(0, getSelectedRow(d_sy, true));
}
break;
case NE:
if (e_x < last_end_x) {
d_ex = last_end_x - e_offset_x - e_spacing_x;
col_end = Math.min(getSelectedCol(d_ex, true) + 1, getMaxCol());
}
if (e_y > last_end_y) {
d_sy = last_end_y - e_offset_y + e_spacing_y;
row_start = Math.max(0, getSelectedRow(d_sy, true));
}
break;
}
}
movingSelectionEnd = new Point(end_pt.x, end_pt.y);
redrawByIndex(col_start, col_end, row_start, row_end, direction, isScrolling);
//redrawByLocation(d_sx, d_ex, d_sy, d_ey, direction, isScrolling);
}
/** Redraw by location
* @param d_sx
* @param d_ex
* @param d_sy
* @param d_ey
* @param direction
* @param isScrolling
*/
protected void redrawByLocation(int d_sx, int d_ex, int d_sy, int d_ey, int direction, boolean isScrolling) {
int d_x = d_sx;
int d_y = d_sy + ((direction==NW||direction==NE)?(isScrolling ? getVerticalIncrement():0):0);
int d_w = e_offset_x + Math.abs(d_ex - d_sx);
int d_h = e_offset_y + Math.abs(d_ey - d_sy) + ((direction==SE||direction==SW)?(isScrolling ? getVerticalIncrement():0):0);
redraw(d_x, d_y, d_w, d_h, false);
}
/** Redraw by index
* @param col_start
* @param col_end
* @param row_start
* @param row_end
* @param direction
* @param isScrolling
*/
protected void redrawByIndex(int col_start, int col_end, int row_start, int row_end, int direction, boolean isScrolling) {
int redrawStart_x = e_offset_x + (col_start * getElementWidth()) - e_spacing_x;
int redrawEnd_x = e_offset_x + (col_end * getElementWidth()) + e_spacing_x;
int redrawStart_y = e_offset_y + (row_start * getElementHeight()) - verticalScrollOffset;
int redrawEnd_y = e_offset_y + (row_end * getElementHeight()) + verticalScrollOffset;
int margin_x = getElementWidth() + sel_size;
int margin_y = getElementHeight() + sel_size;
int d_x = Math.max(0, (redrawStart_x - margin_x));
int d_y = Math.max(0, (redrawStart_y - margin_y)) + ((direction==NW||direction==NE)?(isScrolling ? getVerticalIncrement():0):0);
int d_w = Math.abs(redrawEnd_x - redrawStart_x) + (margin_x*2);
int d_h = Math.abs(redrawEnd_y - redrawStart_y) + (margin_y*2) + ((direction==SE||direction==SW)?(isScrolling ? getVerticalIncrement():0):0);
if (d_x < e_offset_x) {
d_x = 0;
d_w += e_offset_x;
}
redraw(d_x, d_y, d_w, d_h, false);
}
/** Redraw
* @param start_index
* @param end_index
*/
protected void redraw(int start_index, int end_index) {
int max_col = getMaxCol();
int start_row = (int) Math.floor(start_index / max_col);
int start_y_loc = (start_row * getElementHeight() + e_offset_y) - verticalScrollOffset;
int end_row = (int) Math.floor(end_index / max_col);
int end_y_loc = (end_row * getElementHeight() + e_offset_y) - verticalScrollOffset;
int diff = Math.abs(end_row - start_row) + 1;
redraw(0, Math.min(start_y_loc, end_y_loc), (max_col * getElementWidth() + e_offset_x), diff * getElementHeight(), false);
}
/** select elements
* @param start_index
* @param end_index
* @param checkStatus
* @return true if element can be selected
*/
protected boolean canSelectElements(int start_index, int end_index, boolean checkStatus) {
if (start_index == -1 || end_index == -1)
return false;
selectElements(start_index, end_index, checkStatus);
return true;
}
/** unselect all elements
*
*/
public void unselectAllElements() {
selectedElements.clear();
tempSelectedElements.clear();
}
/** Select element
* @param index Element index
*/
public void autoSelectUnselectElement(int index) {
if (isSelected(index)) {
selectedElements.clear(index);
} else {
selectedElements.set(index);
}
}
/** Is element selected
* @param index
* @return true if element is selected
*/
public boolean isSelected(int index) {
return selectedElements.get(index);
}
/** unselect element
* @param index Target element index
*/
public void unselectElement(int index) {
selectedElements.clear(index);
}
/** select element
* @param index
*/
public void selectElement(int index) {
selectedElements.set(index);
firstSelectedIndex = index;
//selection = findLocation(index);
//actualScrollStart_y = selection.y + verticalScrollOffset;
}
/** Select elements
* @param from_index
* @param to_index
*/
public void selectElements(int from_index, int to_index) {
selectElements(from_index, to_index, false);
}
/** Select elements
* @param from_index
* @param to_index
* @param checkStatus
*/
public void selectElements(int from_index, int to_index, boolean checkStatus) {
for (int index = from_index; index < to_index + 1; index++) {
if (checkStatus)
autoSelectUnselectElement(index);
else
selectedElements.set(index);
}
}
public void unselectElements(int from_index, int to_index) {
for (int index = from_index; index < to_index + 1; index++) {
selectedElements.clear(index);
}
}
/** Paint the view
* @param gc
* @param col_start
* @param col_end
* @param row_start
* @param row_end
* @param render_x
* @param render_y
* @param renderWidth
* @param renderHeight
*/
protected void performPaint(GC gc, int col_start, int col_end, int row_start, int row_end, int render_x, int render_y, int renderWidth, int renderHeight) {
Image imageBuffer = null;
GC newGC = null;
if (DOUBLE_BUFFER) {
imageBuffer = new Image(getDisplay(), renderWidth, renderHeight);
newGC = new GC(imageBuffer, SWT.LEFT_TO_RIGHT);
} else {
newGC = gc;
}
newGC.setFont(getFont());
//draw margin background
if (isDisplayRuler()) {
newGC.setBackground(margin_color);
newGC.fillRectangle(0, 0, e_offset_x - e_spacing_x, getClientArea().height);
}
int total = getTotalElements();
for (int row_count = row_start; row_count < row_end; row_count++) {
for (int col_count = col_start; col_count < col_end; col_count++) {
int index = findSelectedIndex(row_count, col_count);
if (index > -1 && index < total) {
Object obj = getObject(index);
int x_loc = e_offset_x + ((col_count) * getElementWidth());
int y_loc = e_offset_y + ((row_count) * getElementHeight()) - verticalScrollOffset;
if (col_count == 0 && isDisplayRuler()) {
drawIndex(newGC, obj, index, y_loc);
}
drawImage(newGC, obj, index, x_loc, y_loc, (selectedElements.get(index) || tempSelectedElements.get(index)));
}
}
}
if (movingSelectionStart != null && movingSelectionEnd != null) {
drawSelection(newGC);
}
if (DOUBLE_BUFFER) {
gc.drawImage(imageBuffer, render_x, render_y);
newGC.dispose();
imageBuffer.dispose();
}
clearMargin(gc, getBackground());
}
/** Draw index
* @param gc
* @param obj
* @param index
* @param y_loc
*/
protected void drawIndex(GC gc, Object obj, int index, int y_loc) {
String text = contentProvider.getRulerIndex(obj, index);
Point text_size = gc.stringExtent(text);
int align = e_offset_x - e_spacing_x - text_size.x;
int valign = y_loc + e_height/2 - text_size.y/2 ;
gc.drawText(text, align, valign);
}
/** Draw image
* @param gc
* @param obj
* @param x_loc
* @param y_loc
* @param isSelected
*/
protected void drawImage(GC gc, Object obj, int index, int x_loc, int y_loc, boolean isSelected) {
Image statusImage = getStatusIcon(obj, index, isSelected);
if (statusImage != null) {
gc.drawImage(statusImage, x_loc, y_loc);
drawSpecial(obj, index, gc, x_loc, y_loc, e_width, e_height);
}
}
/** Draw selection
* @param gc
*/
private void drawSelection(GC gc) {
gc.setForeground(sel_color);
gc.setLineWidth(sel_size);
Point stationary_pt = getStartedPoint(movingSelectionStart.x, movingSelectionStart.y);
int start_x = stationary_pt.x;
int start_y = stationary_pt.y;
int end_x = 0;
int end_y = 0;
switch (getDirection(movingSelectionStart.x, movingSelectionStart.y, movingSelectionEnd.x, movingSelectionEnd.y)) {
case SE:
while (start_x < movingSelectionEnd.x) {
gc.drawLine(start_x, stationary_pt.y, start_x + sel_length, stationary_pt.y);
start_x += (sel_length * sel_gap);
}
while (start_y < movingSelectionEnd.y) {
gc.drawLine(stationary_pt.x, start_y, stationary_pt.x, start_y + sel_length);
start_y += (sel_length * sel_gap);
}
start_x -= sel_gap;
start_y -= sel_gap;
end_x = start_x;
end_y = start_y;
if (isReachBottom() || movingSelectionEnd.y < getClientArea().height) {
while (end_x > stationary_pt.x) {
gc.drawLine(end_x - sel_length, start_y, end_x, start_y);
end_x -= (sel_length * sel_gap);
}
}
while (end_y > stationary_pt.y) {
gc.drawLine(start_x, end_y - sel_length, start_x, end_y);
end_y -= (sel_length * sel_gap);
}
break;
case SW:
while (start_x > movingSelectionEnd.x) {
gc.drawLine(start_x - sel_length, stationary_pt.y, start_x, stationary_pt.y);
start_x -= (sel_length * sel_gap);
}
while (start_y < movingSelectionEnd.y) {
gc.drawLine(stationary_pt.x, start_y, stationary_pt.x, start_y + sel_length);
start_y += (sel_length * sel_gap);
}
start_x += sel_gap;
start_y -= sel_gap;
end_x = start_x;
end_y = start_y;
if (isReachBottom() || movingSelectionEnd.y < getClientArea().height) {
while (end_x < stationary_pt.x) {
gc.drawLine(end_x, start_y, end_x + sel_length, start_y);
end_x += (sel_length * sel_gap);
}
}
while (end_y > stationary_pt.y) {
gc.drawLine(start_x, end_y - sel_length, start_x, end_y);
end_y -= (sel_length * sel_gap);
}
break;
case NW:
while (start_x > movingSelectionEnd.x) {
gc.drawLine(start_x - sel_length, stationary_pt.y, start_x, stationary_pt.y);
start_x -= (sel_length * sel_gap);
}
while (start_y > movingSelectionEnd.y) {
gc.drawLine(stationary_pt.x, start_y - sel_length, stationary_pt.x, start_y);
start_y -= (sel_length * sel_gap);
}
start_x += sel_gap;
start_y += sel_gap;
end_x = start_x;
end_y = start_y;
if (isReachTop() || movingSelectionEnd.y > 1) {
while (end_x < stationary_pt.x) {
gc.drawLine(end_x, start_y, end_x + sel_length, start_y);
end_x += (sel_length * sel_gap);
}
}
while (end_y < stationary_pt.y) {
gc.drawLine(start_x, end_y, start_x, end_y + sel_length);
end_y += (sel_length * sel_gap);
}
break;
case NE:
while (start_x < movingSelectionEnd.x) {
gc.drawLine(start_x, stationary_pt.y, start_x + sel_length, stationary_pt.y);
start_x += (sel_length * sel_gap);
}
while (start_y > movingSelectionEnd.y) {
gc.drawLine(stationary_pt.x, start_y - sel_length, stationary_pt.x, start_y);
start_y -= (sel_length * sel_gap);
}
start_x -= sel_gap;
start_y += sel_gap;
end_x = start_x;
end_y = start_y;
if (isReachTop() || movingSelectionEnd.y > 1) {
while (end_x > stationary_pt.x) {
gc.drawLine(end_x - sel_length, start_y, end_x, start_y);
end_x -= (sel_length * sel_gap);
}
}
while (end_y < stationary_pt.y) {
gc.drawLine(start_x, end_y, start_x, end_y + sel_length);
end_y += (sel_length * sel_gap);
}
break;
}
}
/** Clear margin background
* @param gc
* @param background
*/
protected void clearMargin(GC gc, Color background) {
gc.setBackground(background);
}
/** Get GC
* @return
*/
public GC getGC() {
return getGC(SWT.NONE);
}
/** Get GC by creating a new
* @param style
* @return
*/
protected GC getGC(int style) {
return new GC(this, style);
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Control#setCursor(org.eclipse.swt.graphics.Cursor)
*/
public void setCursor(Cursor cursor) {
if (cursor == null) {
super.setCursor(defaultCursor);
} else {
super.setCursor(cursor);
}
}
/** Do mouse moving
* @param event
*/
protected void doMouseMoving(Event event) {
int index = findSelectedIndexByLocation(event.x, event.y, false);
if (index > -1) {
setCursor(new Cursor(getDisplay(), SWT.CURSOR_HAND));
} else {
setCursor(null);
}
hideToolTip();
}
/** Hide tooltip
*
*/
protected void hideToolTip() {
if (fInformationControl != null) {
fInformationControl.setVisible(false);
if (fInformationControl != null)
fInformationControl.dispose();
}
disableTooltipTimer();
}
protected void disableTooltipTimer() {
if (hoverTimer != null) {
hoverTimer.cancel();
//hoverTimer.purge();
hoverTimer = null;
}
}
protected void enableTooltipTimer() {
if (!show_tooltip_allthetime && fInformationControl != null) {
getHoverTimer().schedule(new TimerTask() {
public void run() {
getDisplay().asyncExec(new Runnable() {
public void run() {
hideToolTip();
}
});
}
}, tooltip_timeout);
}
}
/** Get hover timer
* @return
*/
private Timer getHoverTimer() {
if (hoverTimer == null) {
hoverTimer = new Timer();
}
return hoverTimer;
}
/** Reset info
*
*/
protected void resetInfo() {
hideToolTip();
mouseDown = false;
mouseDoubleClick = false;
movingSelectionStart = null;
movingSelectionEnd = null;
max_e_row = -1;
max_e_col = -1;
setCursor(null);
}
/** Handle dispose event
* @param event
*/
protected void handleDispose(Event event) {
removeListener(SWT.Dispose, listener);
event.type = SWT.None;
resetInfo();
keyActionMap = null;
defaultCursor.dispose();
defaultCursor = null;
actionListeners.clear();
total_elements = 0;
}
/** Handle key down event
* @param event
*/
protected void handleKeyDown(Event event) {
if (event.doit == true) {
handleKey(event);
}
}
/** Handle key up event
* @param event
*/
protected void handleKeyUp(Event event) {
resetInfo();
}
/** Handle mouse down event
* @param event
*/
protected void handleMouseDown(Event event) {
mouseDown = true;
mouseDoubleClick = false;
if (getTotalElements() == 0 || (event.button != 1) || (IS_CARBON && (event.stateMask & SWT.MOD4) != 0)) {
return;
}
boolean isCtrl = (event.stateMask & SWT.MOD1) != 0;
boolean isShift = (event.stateMask & SWT.MOD2) != 0;
int end = findSelectedIndexByLocation(event.x, event.y, false);
int start = isShift?firstSelectedIndex:end;
if (start == -1)
start = end;
if (start > end) {// swarp
int tmp = start;
start = end;
end = tmp;
}
if (IS_CARBON) {// mac
if (start > -1 && end > -1 && !isCtrl) {
firstSelectedIndex = start;
secondSelectedIndex = end;
}
if (isShift) {
if (firstSelectedIndex > -1 && secondSelectedIndex > -1 && firstSelectedIndex < secondSelectedIndex) {
end = secondSelectedIndex;
}
}
}
else if (IS_GTK || IS_MOTIF) {// linux
if (isShift && isCtrl) {//only apply ctrl if both keys pressed
isShift = false;
if (start < secondSelectedIndex)
end = start;
else
start = end;
}
if (start > -1 && end > -1 && (!isShift || start == end)) {//get last selection if no shift or start==end
firstSelectedIndex = start;
secondSelectedIndex = end;
}
}
else {// others eg. windows
if (start > -1 && end > -1 && (!isShift || start == end)) {//get last selection if no shift or start==end
firstSelectedIndex = start;
}
}
if (!isShift && !isCtrl) { //no shift, no ctrl
unselectAllElements();
}
if (start > -1 && end > -1 && isShift && !isCtrl) { //shift
unselectAllElements();
}
if ((start == -1 || end == -1) && !isShift && !isCtrl) {//clear all elementd if no selected
unselectAllElements();
firstSelectedIndex = -1;
secondSelectedIndex = -1;
}
selection = new Point(event.x, event.y);
actualScrollStart_y = selection.y + verticalScrollOffset;
canSelectElements(start, end, (isCtrl && !isShift));
redraw();
}
/** Handle mouse up event
* @param event
*/
protected void handleMouseUp(Event event) {
selectedElements.or(tempSelectedElements);
if (movingSelectionStart != null) {
redraw();
}
resetInfo();
endAutoScroll();
}
/** Handle mouse double click event
* @param event
*/
protected void handleMouseDoubleClick(Event event) {
if (event.button != 1) {
return;
}
resetInfo();
mouseDoubleClick = true;
int index = findSelectedIndexByLocation(event.x, event.y, false);
if (index > -1) {
fireAction(IIconCanvasActionListener.DOUBLE_CLICK_ACTION, index);
redraw(index, index);
}
}
protected void handleMouseHover(Event event) {
int index = findSelectedIndexByLocation(event.x, event.y, false);
if (index > -1) {
if (fInformationControl == null)
showToolTip(index, event);
enableTooltipTimer();
} else {
hideToolTip();
}
}
/** Handle mouse move event
* @param event
*/
protected void handleMouseMove(Event event) {
if (autoScrollDirection == SWT.NULL)
doMouseMoving(event);
if (!mouseDown || mouseDoubleClick || getTotalElements() == 0)
return;
if ((event.stateMask & SWT.BUTTON1) == 0) {
return;
}
if ((event.stateMask & SWT.MOD2) != 0) { //shift key
return;
}
update();
doAutoScroll(event.x, event.y);
}
/** Handle paint event
* @param event
*/
protected void handlePaint(Event event) {
Rectangle clientArea = getClientArea();
if (getTotalElements() == 0 || event.height == 0 || (clientArea.width == 0 && clientArea.height == 0)) {
// Check if there is work to do
return;
}
// default
int renderWidth = clientArea.width;
int renderHeight = clientArea.height;
int col_start = 0;
int col_end = getMaxCol();
int row_start = 0;
int row_end = getMaxClientRow();
if (event.y > 0) {
Point start_pt = null;
if (movingSelectionStart != null)
start_pt = getStartedPoint(movingSelectionStart.x, movingSelectionStart.y);
else
start_pt = getStartedPoint(event.x + event.width, event.y + event.height);
Point end_pt = getFinishedPoint(event.x, event.y);
int s_x = start_pt.x;
int e_x = end_pt.x;
int s_y = start_pt.y;
int e_y = end_pt.y;
switch (getDirection(start_pt.x, start_pt.y, end_pt.x, end_pt.y)) {
case SW:
s_x = end_pt.x;
e_x = start_pt.x;
break;
case NW:
s_x = end_pt.x;
e_x = start_pt.x;
s_y = end_pt.y;
e_y = start_pt.y;
break;
case NE:
s_y = end_pt.y;
e_y = start_pt.y;
break;
}
col_start = Math.max(0, getSelectedCol(s_x - e_offset_x, true));
col_end = Math.min(getSelectedCol(e_x + event.width - e_offset_x, true) + 1, getMaxCol());
row_start = Math.max(0, getSelectedRow(s_y - e_offset_y, true));
row_end = Math.min(getSelectedRow(e_y + event.height - e_offset_y, true) + 1, getMaxRow());
renderWidth = s_x + e_x + event.width;
renderHeight = s_y + e_y + event.height;
} else {
row_start = Math.max(0, current_top_row);
row_end = Math.min(row_end + row_start + 1, getMaxRow());
}
// System.out.println("performPaint: " + col_start + "," + col_end + " - " + row_start + "," + row_end);
performPaint(event.gc, col_start, col_end, row_start, row_end, 0, 0, renderWidth, renderHeight);
}
/** Handle resize event
* @param event
*/
protected void handleResize(Event event) {
/*
int index = selection == null ? -1 : findSelectedIndexByLocation(selection.x, (actualScrollStart_y - verticalScrollOffset), false);
if (index > -1) {
selectedElements.clear(index);
selection = null;
}
*/
resetInfo();
setVerticalScrollBar(getVerticalBar());
if (!claimBottomFreeSpace())
calculateTopIndex();
}
/** Handle focus out event
* @param event
*/
protected void handleFocusOut(Event event) {
//hideToolTip();
}
/** Show tooltip
* @param index Target element index
* @param event mouse move event
*/
protected void showToolTip(int index, Event event) {
if (!show_tooltip || index == -1) {
hideToolTip();
return;
}
boolean isShift = (event.stateMask & SWT.MOD2) != 0;
boolean isCtrl = (event.stateMask & SWT.MOD1) != 0;
showToolTip(index, (!isShift && !isCtrl));
}
protected void showToolTip(int index, boolean showExtra) {
String[] tooltipTexts = getToolTipText(getObject(index));
// confirm to show extra if array is larger than 1
if (showExtra)
showExtra = (tooltipTexts.length>1);
IIconInformationControl informationControl = getInformationControl(showExtra);
if (informationControl != null) {
Rectangle clientArea = getClientArea();
//informationControl.setSizeConstraints(clientArea.width, clientArea.height);
informationControl.setHeader(tooltipTexts[0]);
if (showExtra) {
informationControl.setInformation(tooltipTexts[1]);
}
Point location = findLocation(index);
Point t_size = informationControl.getShellSize();
final int x_gap = getElementWidth()/2;
final int y_gap = showExtra?(getElementHeight()* 1/2):getElementHeight();
int display_x = location.x + x_gap;
int display_y = location.y + y_gap;
if (display_x + t_size.x > clientArea.width) {
int lx = location.x - t_size.x + x_gap;
if (lx > 0)
display_x = lx;
}
if (display_y + t_size.y > clientArea.height) {
int ly = location.y - t_size.y + y_gap;
if (ly > 0)
display_y = ly;
}
Point real_location = getViewActualLocation(this, null, display_x-2, display_y-2);
informationControl.setLocation(real_location);
informationControl.setVisible(true);
//informationControl.setFocus();
}
}
/** Get actual view location
* @param from
* @param to
* @param mx
* @param my
* @return
*/
protected Point getViewActualLocation(Control from, Control to, int mx, int my) {
Point mappedpt = getDisplay().map(from, to, 0, 0);
Point newpt = new Point(mx, my);
newpt.x += mappedpt.x;
newpt.y += mappedpt.y;
return newpt;
}
/** Get selected indexes
* @return selected indexes
*/
public int[] getSelectedIndexes() {
int[] retValue = new int[selectedElements.cardinality()];
for (int i = selectedElements.nextSetBit(0), j = 0; i >= 0; i = selectedElements.nextSetBit(i + 1), j++) {
retValue[j] = i;
}
return retValue;
}
/** Get tooltip text
* @param obj
* @return text of tooltip
*/
protected String[] getToolTipText(Object obj) {
if (toolTipProvider == null)
return IToolTipProvider.NO_TOOLTIP;
return toolTipProvider.toolTipText(obj);
}
/** Get object from selected elementindex
* @param index element index
* @return
*/
protected Object getObject(int index) {
if (contentProvider == null) {
return null;
}
return contentProvider.getObject(index);
}
/** Get status image
* @param obj
* @param index target index position
* @param isSelected true if element is selected
* @return
*/
protected Image getStatusIcon(Object obj, int index, boolean isSelected) {
if (imageProvider == null)
return null;
return imageProvider.getStatusIcon(obj, index, isSelected);
}
/** Draw special on selected element
* @param obj
* @param gc
* @param x_loc
* @param y_loc
* @param width
* @param height
*/
protected void drawSpecial(Object obj, int index, GC gc, int x_loc, int y_loc, int width, int height) {
if (imageProvider != null) {
imageProvider.drawSpecial(obj, index, gc, x_loc, y_loc, width, height);
}
}
/** Get information control
* @param showDetails
* @return
*/
protected IIconInformationControl getInformationControl(boolean showDetails) {
if (fInformationControl == null) {
fInformationControl= iconHover.getHoverControlCreator(getShell(), showDetails, tooltip_wrap);
fInformationControl.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
handleInformationControlDisposed();
}
});
}
return fInformationControl;
}
/** Handle information control disposed event
*
*/
protected void handleInformationControlDisposed() {
fInformationControl= null;
}
/*******************************************************************************************************************************************************************************************************************************************************************************************************
* Self testing
******************************************************************************************************************************************************************************************************************************************************************************************************/
public static void main(String[] args) {
final int totalImage = 200;
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLocation(100, 200);
shell.setSize(600, 300);
shell.setLayout(new FillLayout());
//File normalFile = new File("D:/eclipse3.1/workspace/org.eclipse.ptp.ui/icons/node/node_running.gif");
//File selectedFile = new File("D:/eclipse3.1/workspace/org.eclipse.ptp.ui/icons/node/node_running_sel.gif");
File normalFile = new File("/home/clement/Desktop/workspace_1.1/org.eclipse.ptp.ui/icons/node/node_running.gif");
File selectedFile = new File("/home/clement/Desktop/workspace_1.1/org.eclipse.ptp.ui/icons/node/node_running_sel.gif");
URL normalURL = null;
URL selectedlURL = null;
try {
normalURL = normalFile.toURI().toURL();
selectedlURL = selectedFile.toURI().toURL();
} catch (Exception e) {
System.out.println("Cannot create the URL: " + e.getMessage());
return;
}
final Image normalImage1 = ImageDescriptor.createFromURL(normalURL).createImage();
final Image selectedImage1 = ImageDescriptor.createFromURL(selectedlURL).createImage();
int w = 16;
int h = 16;
final Image normalImage = new Image(normalImage1.getDevice(), normalImage1.getImageData().scaledTo(w, h));
final Image selectedImage = new Image(selectedImage1.getDevice(), selectedImage1.getImageData().scaledTo(w, h));
IconCanvas iconCanvas = new IconCanvas(shell, SWT.NONE);
iconCanvas.setShowTooltip(false);
iconCanvas.setIconSize(w, h);
iconCanvas.setFontSize(10);
iconCanvas.setIconSpace(1, 4);
iconCanvas.setTooltipWrap(true);
iconCanvas.setContentProvider(new IContentProvider() {
public Object getObject(int index) {
return new Integer(index);
}
public String getRulerIndex(Object obj, int index) {
return String.valueOf(index);
}
});
iconCanvas.setImageProvider(new IImageProvider() {
public Image getStatusIcon(Object obj, int index, boolean isSelected) {
return isSelected?selectedImage:normalImage;
}
public void drawSpecial(Object obj, int index, GC gc, int x_loc, int y_loc, int width, int height) {
}
});
iconCanvas.setToolTipProvider(new IToolTipProvider() {
public String[] toolTipText(Object obj) {
//if (obj.toString().indexOf("1") > -1) {
String t = "<i>12345678901234567890123456789a<br>";
t += "12345678901234567890</i>1<b>23456789</b>a";
t += "12345678901234567890123456789a";
return new String[] { "Object: " + obj, t };
//return new String[] { "" };
//}
/*
String[] texts = new String[2];
String contentText = "<u>Variables</u><br>";
contentText += "<ind>abc: <key>PrintStream</key><br>";
contentText += "<ind><hl>aaaaaaaaaaa hhhhhhhhhh gggggggggggggggg bbbbbbbbbbbbbbb ccccccccccccccc:</hl> PrintStream<br>";
contentText += "<ind><hl>aaaaaaa hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh ccccccccccccccc dddddddddddddddd eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee:</hl> PrintStream<br>";
contentText += "<ind><hl>1aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>2aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>3aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>4aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>5aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>6aasdbc:</hl> PrintStream<br>";
contentText += "<ind><hl>7aasdbc:</hl> PrintStream<br>";
contentText += "<ind><i>8ab99213 32c:</i> PrintStream<br>";
texts[0] = "abc\nObject: " + obj;
texts[1] = contentText;
return texts;
*/
}
public void update(Object obj, String content) {
}
});
iconCanvas.setTotal(totalImage);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
}