/*
* Copyright 2016 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.red.nattable.edit;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* @author Michal Anglart
*
*/
public abstract class DetailCellEditorEntry<D> extends Canvas {
protected static final int HOVER_BLOCK_WIDTH = 10;
protected static final int SPACING_AROUND_LINE = 5;
protected static final int LINE_WIDTH = 2;
protected final int column;
protected final int row;
private final Color hoverColor;
private final Color selectionColor;
private boolean hovered = false;
private boolean selected = false;
private boolean underEdit = false;
private DetailEditorListener editorListener;
protected CellEditorValueValidationJobScheduler<String> validationJobScheduler;
public DetailCellEditorEntry(final Composite parent, final int column, final int row, final Color hoverColor,
final Color selectionColor) {
super(parent, SWT.NO_BACKGROUND);
this.column = column;
this.row = row;
this.hoverColor = hoverColor;
this.selectionColor = selectionColor;
this.validationJobScheduler = new CellEditorValueValidationJobScheduler<>(getValidator());
setBackground(null);
addMouseTrackListener(new MouseTrackAdapter() {
@Override
public void mouseHover(final MouseEvent e) {
if (!isAnySiblingUnderEdit() && e.stateMask == 0) {
select(true, false);
}
}
@Override
public void mouseEnter(final MouseEvent e) {
hovered = true;
redraw();
}
@Override
public void mouseExit(final MouseEvent e) {
hovered = false;
redraw();
}
});
}
protected abstract CellEditorValueValidator<String> getValidator();
public void setEditorListener(final DetailEditorListener listener) {
editorListener = listener;
}
public void removeEditorListener() {
setEditorListener(null);
}
protected boolean isHovered() {
return hovered;
}
public boolean isSelected() {
return selected;
}
public void select(final boolean deselectOther) {
select(deselectOther, true);
}
private void select(final boolean deselectOther, final boolean gainFocus) {
if (deselectOther) {
deselectAllSiblings();
}
selected = true;
if (gainFocus) {
setFocus();
}
redraw();
}
private void deselectAllSiblings() {
for (final Control child : getParent().getChildren()) {
if (child instanceof DetailCellEditorEntry && child != this
&& ((DetailCellEditorEntry<?>) child).isSelected()) {
((DetailCellEditorEntry<?>) child).deselect();
}
}
}
private boolean isAnySiblingUnderEdit() {
for (final Control child : getParent().getChildren()) {
if (child instanceof DetailCellEditorEntry && child != this
&& ((DetailCellEditorEntry<?>) child).underEdit) {
return true;
}
}
return false;
}
public void deselect() {
selected = false;
hovered = false;
redraw();
}
public boolean isEditorOpened() {
return underEdit;
}
public void openForEditing() {
underEdit = true;
}
public void commitEdit() {
if (validationJobScheduler.canCloseCellEditor()) {
final String newValue = getNewValue();
closeEditing();
editorListener.editorApplied(newValue);
}
}
protected abstract String getNewValue();
public void cancelEdit() {
closeEditing();
}
protected void closeEditing() {
underEdit = false;
}
public abstract void update(final D detail);
public static interface DetailEditorListener {
void editorApplied(String value);
}
protected abstract class EntryControlPainter implements PaintListener {
@Override
public void paintControl(final PaintEvent e) {
final Image bufferImage = new Image(e.display, e.width, e.height);
final GC bufferGC = new GC(bufferImage);
paintBackground(e.width, e.height, bufferGC);
paintForeground(e.width, e.height, bufferGC);
e.gc.drawImage(bufferImage, 0, 0);
bufferImage.dispose();
bufferGC.dispose();
}
private void paintBackground(final int width, final int height, final GC bufferGC) {
Color bgColorInUse = bufferGC.getBackground();
if (isSelected() && selectionColor != null) {
bgColorInUse = selectionColor;
bufferGC.setBackground(bgColorInUse);
bufferGC.fillRectangle(0, 0, width, height);
}
if (isHovered() && hoverColor != null) {
bufferGC.setBackground(hoverColor);
bufferGC.fillRectangle(width - HOVER_BLOCK_WIDTH, 0, HOVER_BLOCK_WIDTH, height);
bufferGC.setBackground(bgColorInUse);
}
}
protected abstract void paintForeground(int width, int height, final GC bufferGC);
}
}