package org.bundlemaker.core.ui.editor.dsm.widget.internal.matrix;
import java.util.concurrent.CopyOnWriteArrayList;
import org.bundlemaker.core.ui.editor.dsm.widget.IDsmColorScheme;
import org.bundlemaker.core.ui.editor.dsm.widget.IDsmContentProvider;
import org.bundlemaker.core.ui.editor.dsm.widget.IMatrixListener;
import org.bundlemaker.core.ui.editor.dsm.widget.MatrixEvent;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.util.BoxSize;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.zoom.ZoomContainer;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.widgets.Display;
/**
* <p>
* The {@link Figure} that implements the matrix.
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class Matrix extends Figure {
/** the model */
protected IDsmContentProvider _dsmContentProvider;
/** - */
private IDsmColorScheme _matrixColorScheme;
/** - */
private ILabelProvider _matrixLabelProvider;
/** - */
protected CopyOnWriteArrayList<IMatrixListener> _matrixListeners;
/** - */
protected int _x = -1;
/** - */
protected int _y = -1;
/** - */
private BoxSize _boxSize;
/**
* <p>
* Creates a new instance of type {@link Matrix}.
* </p>
*
* @param model
* @param matrixConfiguration
* @param labelProvider
* @param matrixCycleDetector
*/
public Matrix(IDsmContentProvider model, ILabelProvider labelProvider, IDsmColorScheme colorScheme) {
//
Assert.isNotNull(model);
Assert.isNotNull(labelProvider);
Assert.isNotNull(colorScheme);
// set the model
_dsmContentProvider = model;
_matrixColorScheme = colorScheme;
_matrixLabelProvider = labelProvider;
//
_matrixListeners = new CopyOnWriteArrayList<IMatrixListener>();
//
_boxSize = new BoxSize();
//
addMouseListener(new MatrixMouseListener());
addMouseMotionListener(new MatrixMouseMotionListener());
}
public BoxSize getBoxSize() {
return _boxSize;
}
public void setBoxSize(BoxSize boxSize) {
Assert.isNotNull(boxSize);
_boxSize = boxSize;
}
/**
* <p>
* </p>
*
* @param colorScheme
*/
protected final void setMatrixColorScheme(IDsmColorScheme colorScheme) {
_matrixColorScheme = colorScheme;
}
/**
* <p>
* </p>
*
* @return
*/
public IDsmContentProvider getModel() {
return _dsmContentProvider;
}
public void setModel(IDsmContentProvider model) {
_dsmContentProvider = model;
}
/**
* <p>
* </p>
*
* @return
*/
protected final IDsmColorScheme getMatrixConfiguration() {
return _matrixColorScheme;
}
/**
* {@inheritDoc}
*/
@Override
protected void paintClientArea(Graphics graphics) {
super.paintClientArea(graphics);
// reset the size
resetSize();
// push the current state
graphics.pushState();
// draw the background for the complete matrix
graphics.setBackgroundColor(_matrixColorScheme.getMatrixBackgroundColor());
graphics.fillRectangle(0, 0, getSize().width, getSize().height);
// draw the diagonal
graphics.setBackgroundColor(_matrixColorScheme.getMatrixDiagonalColor());
for (int i = 0; i < _dsmContentProvider.getItemCount(); i++) {
graphics.fillRectangle(getHorizontalSliceSize(i), getVerticalSliceSize(i), getHorizontalSliceSize(i + 1)
- getHorizontalSliceSize(i) + 1, getVerticalSliceSize(i + 1) - getVerticalSliceSize(i) + 1);
}
// draw the cycles
for (int[] cycle : _dsmContentProvider.getCycles()) {
graphics.setBackgroundColor(_matrixColorScheme.getCycleSideMarkerColor());
int lenght = cycle[cycle.length - 1] - cycle[0] + 1;
graphics.fillRectangle(getHorizontalSliceSize(cycle[0]), getVerticalSliceSize(cycle[0]),
getHorizontalSliceSize(lenght) + 1, getVerticalSliceSize(lenght) + 1);
for (int i = 0; i < cycle.length; i++) {
graphics.setBackgroundColor(_matrixColorScheme.getCycleMatrixDiagonalColor());
graphics.fillRectangle(getHorizontalSliceSize(cycle[i]), getVerticalSliceSize(cycle[i]),
getHorizontalSliceSize(cycle[i] + 1) - getHorizontalSliceSize(cycle[i]) + 1,
getVerticalSliceSize(cycle[i] + 1) - getVerticalSliceSize(cycle[i]) + 1);
}
}
//
onPaintClientArea(graphics);
// draw the text
graphics.setForegroundColor(_matrixColorScheme.getMatrixTextColor());
int[] visibleSlices = getVisibleSlices();
for (int i = visibleSlices[0]; (i <= visibleSlices[1]); i++) {
for (int j = visibleSlices[2]; j < _dsmContentProvider.getItemCount(); j++) {
if (i != j) {
String value = _matrixLabelProvider.getText(_dsmContentProvider.getDependency(i, j));
if (value != null) {
graphics.drawString(value, getHorizontalSliceSize(i) + 4, getVerticalSliceSize(j));
}
}
}
}
// draw the separator lines
graphics.setForegroundColor(_matrixColorScheme.getMatrixSeparatorColor());
for (int i = 0; i <= _dsmContentProvider.getItemCount(); i++) {
graphics.drawLine(new Point(0, getVerticalSliceSize(i)), new Point(getBoxSize().getHorizontalBoxSize()
* _dsmContentProvider.getItemCount(), getVerticalSliceSize(i)));
graphics.drawLine(new Point(getHorizontalSliceSize(i), 0), new Point(getHorizontalSliceSize(i), getBoxSize()
.getVerticalBoxSize() * _dsmContentProvider.getItemCount()));
}
// draw the cycle separator lines
graphics.setForegroundColor(_matrixColorScheme.getCycleSideMarkerSeparatorColor());
for (int[] cycle : _dsmContentProvider.getCycles()) {
int current = 0;
for (int i : cycle) {
current = i;
graphics.drawLine(getHorizontalSliceSize(i), getVerticalSliceSize(cycle[0]), getHorizontalSliceSize(i),
getVerticalSliceSize(cycle[cycle.length - 1] + 1));
graphics.drawLine(getHorizontalSliceSize(cycle[0]), getVerticalSliceSize(i),
getHorizontalSliceSize(cycle[cycle.length - 1] + 1), getVerticalSliceSize(i));
}
current++;
graphics.drawLine(getHorizontalSliceSize(current), getVerticalSliceSize(cycle[0]),
getHorizontalSliceSize(current), getVerticalSliceSize(cycle[cycle.length - 1] + 1));
graphics.drawLine(getHorizontalSliceSize(cycle[0]), getVerticalSliceSize(current),
getHorizontalSliceSize(cycle[cycle.length - 1] + 1), getVerticalSliceSize(current));
}
// restore state
graphics.popState();
}
private int[] getVisibleSlices() {
if (!(this.getParent() instanceof ZoomContainer)) {
return new int[] { 0, _dsmContentProvider.getItemCount() - 1, 0, _dsmContentProvider.getItemCount() - 1 };
}
ZoomContainer zoomContainer = (ZoomContainer) this.getParent();
Viewport viewport = ((Viewport) this.getParent().getParent());
int horMin = (int) (viewport.getViewLocation().x / (getBoxSize().getHorizontalBoxSize() * zoomContainer.zoom));
int horVisibleSlicesCount = (int) (viewport.getSize().width / (getBoxSize().getHorizontalBoxSize() * zoomContainer.zoom));
//
int verMin = (int) (viewport.getViewLocation().y / (getBoxSize().getVerticalBoxSize() * zoomContainer.zoom));
int verVisibleSlicesCount = (int) (viewport.getSize().height / (getBoxSize().getVerticalBoxSize() * zoomContainer.zoom));
return new int[] {
horMin,
horMin + horVisibleSlicesCount > _dsmContentProvider.getItemCount() - 1 ? _dsmContentProvider.getItemCount() - 1
: horMin + horVisibleSlicesCount,
verMin,
verMin + verVisibleSlicesCount > _dsmContentProvider.getItemCount() - 1 ? _dsmContentProvider.getItemCount() - 1
: verMin + verVisibleSlicesCount };
}
/**
* <p>
* </p>
*/
public void resetSize() {
//
Dimension dimension = new Dimension(getBoxSize().getHorizontalBoxSize() * _dsmContentProvider.getItemCount() + 1,
getBoxSize().getVerticalBoxSize() * _dsmContentProvider.getItemCount() + 1);
//
if (!getSize().equals(dimension)) {
setSize(dimension);
}
}
protected final int getHorizontalSliceSize(int count) {
return getBoxSize().getHorizontalBoxSize() * count;
}
/**
* <p>
* </p>
*
* @param count
* @return
*/
protected final int getVerticalSliceSize(int count) {
return getBoxSize().getVerticalBoxSize() * count;
}
/**
* <p>
* </p>
*
* @param listener
*/
public void addMatrixListener(IMatrixListener listener) {
_matrixListeners.addIfAbsent(listener);
}
/**
* <p>
* </p>
*
* @param listener
*/
public void removeMatrixLIstener(IMatrixListener listener) {
_matrixListeners.remove(listener);
}
/**
* {@inheritDoc}
*/
protected void onPaintClientArea(Graphics graphics) {
// draw marked rows and columns
if (_x != -1 && _y != -1) {
// draw column
if (_dsmContentProvider.isInCycle(_x, _y)) {
graphics.setBackgroundColor(getMatrixConfiguration().getCycleMatrixMarkedColumnRowColor());
} else {
graphics.setBackgroundColor(getMatrixConfiguration().getMatrixMarkedColumnRowColor());
}
graphics.fillRectangle(0, getVerticalSliceSize(_y), getHorizontalSliceSize(_x + 1) + 1,
getVerticalSliceSize(_y + 1) - getVerticalSliceSize(_y) + 1);
// draw row
graphics.fillRectangle(getHorizontalSliceSize(_x), 0, getHorizontalSliceSize(_x + 1) - getHorizontalSliceSize(_x)
+ 1, getVerticalSliceSize(_y + 1) + 1);
// // draw square
// if (true) {
// graphics.fillRectangle(getHorizontalSliceSize(_x), 0, getHorizontalSliceSize(_x + 1)
// - getHorizontalSliceSize(_x) + 1, getVerticalSliceSize(_x + 1) + 1);
// graphics.fillRectangle(getHorizontalSliceSize(_x), getVerticalSliceSize(_y), getHorizontalSliceSize(_y + 1)
// - getHorizontalSliceSize(_x), getVerticalSliceSize(1));
// graphics.fillRectangle(getHorizontalSliceSize(_x), getVerticalSliceSize(_x), getHorizontalSliceSize(_y)
// - getHorizontalSliceSize(_x), getVerticalSliceSize(1));
// graphics.fillRectangle(getHorizontalSliceSize(_y), getVerticalSliceSize(_y), getHorizontalSliceSize(1),
// getVerticalSliceSize(_x) - getVerticalSliceSize(_y));
// }
// draw marked cell
if (_dsmContentProvider.isInCycle(_x, _y)) {
graphics.setBackgroundColor(getMatrixConfiguration().getCycleMatrixMarkedCellColor());
} else {
graphics.setBackgroundColor(getMatrixConfiguration().getMatrixMarkedCellColor());
}
graphics.fillRectangle(getHorizontalSliceSize(_x), getVerticalSliceSize(_y), getHorizontalSliceSize(_x + 1)
- getHorizontalSliceSize(_x) + 1, getVerticalSliceSize(_y + 1) - getVerticalSliceSize(_y) + 1);
graphics.fillRectangle(getHorizontalSliceSize(_y), getVerticalSliceSize(_x), getHorizontalSliceSize(_y + 1)
- getHorizontalSliceSize(_y) + 1, getVerticalSliceSize(_x + 1) - getVerticalSliceSize(_x) + 1);
}
}
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
private final class MatrixMouseMotionListener extends MouseMotionListener.Stub {
/**
* {@inheritDoc}
*/
@Override
public void mouseMoved(MouseEvent me) {
//
final Point location = me.getLocation();
//
final int x = (location.x / getBoxSize().getHorizontalBoxSize());
final int y = (location.y / getBoxSize().getVerticalBoxSize());
//
if (x != _x || y != _y) {
//
if (x >= _dsmContentProvider.getItemCount() || y >= _dsmContentProvider.getItemCount()) {
_x = -1;
_y = -1;
}
//
else {
_x = x;
_y = y;
}
// start the tool tip listener
Display.getCurrent().timerExec(1000, new Runnable() {
@Override
public void run() {
// set the new cell
if (_x == x && _y == y) {
// notify listener
MatrixEvent event = new MatrixEvent(_x, _y);
for (IMatrixListener listener : _matrixListeners.toArray(new IMatrixListener[0])) {
listener.toolTip(event);
}
}
}
});
// repaint
repaint();
// notify listener
MatrixEvent event = new MatrixEvent(_x, _y);
for (IMatrixListener listener : _matrixListeners.toArray(new IMatrixListener[0])) {
listener.marked(event);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void mouseExited(MouseEvent me) {
//
_x = -1;
_y = -1;
// repaint
repaint();
// notify listener
MatrixEvent event = new MatrixEvent(_x, _y);
for (IMatrixListener listener : _matrixListeners.toArray(new IMatrixListener[0])) {
listener.marked(event);
}
}
}
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
private final class MatrixMouseListener extends MouseListener.Stub {
/**
* {@inheritDoc}
*/
@Override
public void mouseDoubleClicked(MouseEvent me) {
// notify listener
MatrixEvent event = new MatrixEvent(_x, _y);
for (IMatrixListener listener : _matrixListeners) {
listener.doubleClick(event);
}
}
@Override
public synchronized void mouseReleased(MouseEvent me) {
// notify listener
MatrixEvent event = new MatrixEvent(_x, _y);
for (IMatrixListener listener : _matrixListeners) {
listener.singleClick(event);
}
}
}
}