package edu.ualberta.med.biobank.widgets.grids.selection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.MouseTrackListener;
import edu.ualberta.med.biobank.common.util.RowColPos;
import edu.ualberta.med.biobank.widgets.grids.ContainerDisplayWidget;
import edu.ualberta.med.biobank.widgets.grids.cell.AbstractUICell;
public class MultiSelectionManager {
private ContainerDisplayWidget container;
private MouseListener selectionMouseListener;
private MouseTrackListener selectionMouseTrackListener;
private enum SelectionMode {
NONE, MULTI, RANGE;
}
private boolean selectionTrackOn = false;
private SelectionMode selectionMode = SelectionMode.NONE;
private Map<RowColPos, AbstractUICell> selectedCells;
private AbstractUICell lastSelectedCell;
private List<MultiSelectionListener> listeners;
private MultiSelectionSpecificBehaviour specificBehaviour;
private boolean enabled = false;
public MultiSelectionManager(ContainerDisplayWidget container) {
this.container = container;
selectedCells = new TreeMap<RowColPos, AbstractUICell>();
listeners = new ArrayList<MultiSelectionListener>();
}
public Collection<AbstractUICell> getSelectedCells() {
return selectedCells.values();
}
public Set<RowColPos> getSelectedPositions() {
return selectedCells.keySet();
}
public void enableMultiSelection(MultiSelectionSpecificBehaviour t) {
initListeners();
this.specificBehaviour = t;
container.addMouseListener(selectionMouseListener);
container.addMouseTrackListener(selectionMouseTrackListener);
enabled = true;
}
public void disableMultiSelection() {
container.removeMouseListener(selectionMouseListener);
container.removeMouseTrackListener(selectionMouseTrackListener);
clearMultiSelection();
for (AbstractUICell cell : container.getCells().values()) {
specificBehaviour.removeSelection(cell);
}
enabled = false;
}
public void clearMultiSelection() {
clearMultiSelection(true);
}
public void clearMultiSelection(boolean notify) {
for (AbstractUICell cell : selectedCells.values()) {
cell.setSelected(false);
}
selectedCells.clear();
if (notify) {
notifyListeners();
}
}
private void notifyListeners() {
notifyListeners(new MultiSelectionEvent(this, selectedCells.size()));
}
private void addAllCellsInRange(AbstractUICell cell) {
AbstractUICell firstCell = lastSelectedCell;
int startRow = firstCell.getRow();
int endRow = cell.getRow();
if (startRow > endRow) {
startRow = cell.getRow();
endRow = firstCell.getRow();
}
for (int indexRow = startRow; indexRow <= endRow; indexRow++) {
int startCol = firstCell.getCol();
int endCol = cell.getCol();
if (startCol > endCol) {
startCol = cell.getCol();
endCol = firstCell.getCol();
}
for (int indexCol = startCol; indexCol <= endCol; indexCol++) {
AbstractUICell cellToAdd = container.getCells().get(
new RowColPos(indexRow, indexCol));
if (cellToAdd != null
&& specificBehaviour.isSelectable(cellToAdd)) {
if (!selectedCells.values().contains(cellToAdd)) {
selectCell(cellToAdd);
}
}
}
}
}
private void initListeners() {
if (selectionMouseListener == null) {
selectionMouseListener = new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
selectionTrackOn = true;
AbstractUICell cell = container.getObjectAtCoordinates(e.x,
e.y);
if (cell != null && specificBehaviour.isSelectable(cell)) {
switch (selectionMode) {
case MULTI:
if (selectedCells.containsValue(cell)) {
selectedCells.remove(new RowColPos(cell
.getRow(), cell.getCol()));
cell.setSelected(false);
} else {
selectCell(cell);
}
break;
case RANGE:
if (selectedCells.size() > 0) {
addAllCellsInRange(cell);
} else {
selectCell(cell);
}
break;
default:
boolean alreadySelected = selectedCells
.containsValue(cell);
if (alreadySelected && selectedCells.size() == 1) {
selectedCells.clear();
cell.setSelected(false);
lastSelectedCell = null;
} else {
clearMultiSelection(false);
selectCell(cell);
}
break;
}
notifyListeners();
container.redraw();
}
}
@Override
public void mouseUp(MouseEvent e) {
selectionTrackOn = false;
}
};
}
if (selectionMouseTrackListener == null) {
selectionMouseTrackListener = new MouseTrackAdapter() {
@Override
public void mouseHover(MouseEvent e) {
if (selectionTrackOn) {
AbstractUICell cell = container.getObjectAtCoordinates(
e.x, e.y);
if (cell != null && !cell.equals(lastSelectedCell)) {
selectCell(cell);
notifyListeners();
container.redraw();
}
}
}
};
container.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.SHIFT) {
selectionMode = SelectionMode.RANGE;
} else if (e.keyCode == SWT.CTRL) {
selectionMode = SelectionMode.MULTI;
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.keyCode == SWT.SHIFT || e.keyCode == SWT.CTRL) {
selectionMode = SelectionMode.NONE;
}
}
});
}
}
private void selectCell(AbstractUICell cell) {
selectedCells.put(new RowColPos(cell.getRow(), cell.getCol()), cell);
cell.setSelected(true);
lastSelectedCell = cell;
}
public void addMultiSelectionListener(MultiSelectionListener listener) {
listeners.add(listener);
}
public void removeMultiSelectionListener(MultiSelectionListener listener) {
listeners.remove(listener);
}
public void notifyListeners(MultiSelectionEvent event) {
for (MultiSelectionListener listener : listeners) {
listener.selectionChanged(event);
}
}
public boolean isEnabled() {
return enabled;
}
}