/*
* Copyright 2003-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.nodeEditor.selection;
import jetbrains.mps.openapi.editor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.CellAction;
import jetbrains.mps.openapi.editor.cells.CellActionType;
import jetbrains.mps.openapi.editor.cells.CellInfo;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.selection.Selection;
import jetbrains.mps.openapi.editor.selection.SelectionStoreException;
import jetbrains.mps.openapi.editor.selection.SingularSelection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class EditorCellSelection extends AbstractSelection implements SingularSelection {
private static final String CARET_X_PROPERTY_NAME = "caretX";
private static final String CARET_X_RELATIVE_PROPERTY_NAME = "caretXRelative";
private static final String SIDE_SELECT_DIRECTION_PROPERTY_NAME = "sideSelectDirection";
private EditorCell myEditorCell;
private int myCaretX;
private int myCaretXRelative;
private boolean myActivateUsingRelativeCaretX = true;
private boolean myActive = false;
private SideSelectDirection mySideSelectDirection = SideSelectDirection.NONE;
public EditorCellSelection(EditorComponent editorComponent, Map<String, String> properties, CellInfo cellInfo) throws SelectionStoreException,
SelectionRestoreException {
super(editorComponent);
if (cellInfo == null) {
throw new SelectionStoreException("Required CellInfo parameter is null");
}
// TODO: think about better way to restore relevant selection in case of deleted cell (EditorManager.EditorCell_STHint)
myEditorCell = cellInfo.findClosestCell(editorComponent);
if (myEditorCell == null) {
throw new SelectionRestoreException();
}
// Using absolute coordinates to restore caret X in case different cell was found.
myActivateUsingRelativeCaretX = cellInfo.equals(myEditorCell.getCellInfo());
myCaretX = SelectionInfoImpl.Util.getIntProperty(properties, CARET_X_PROPERTY_NAME);
myCaretXRelative = SelectionInfoImpl.Util.getIntProperty(properties, CARET_X_RELATIVE_PROPERTY_NAME);
mySideSelectDirection =
(SideSelectDirection) SelectionInfoImpl.Util.getEnumProperty(properties, SIDE_SELECT_DIRECTION_PROPERTY_NAME, SideSelectDirection.class,
mySideSelectDirection);
}
public EditorCellSelection(@NotNull EditorCell editorCell) {
super(editorCell.getEditorComponent());
myEditorCell = editorCell;
myCaretX = editorCell.getCaretX();
myCaretXRelative = getRelativeCaretX(editorCell);
}
@NotNull
@Override
public EditorCell getEditorCell() {
return myEditorCell;
}
@Override
public void setSideSelectDirection(SideSelectDirection direction) {
mySideSelectDirection = direction;
}
@Override
public SideSelectDirection getSideSelectDirection() {
return mySideSelectDirection;
}
public int getCaretX() {
return isActive() ? myEditorCell.getCaretX() : myCaretX;
}
public int getCaretXRelative() {
return isActive() ? getRelativeCaretX(myEditorCell) : myCaretXRelative;
}
@Override
public void activate() {
myEditorCell.setSelected(true);
if (myActivateUsingRelativeCaretX) {
setRelativeCaretX(myEditorCell, getCaretXRelative());
} else {
myEditorCell.setCaretX(getCaretX());
myActivateUsingRelativeCaretX = true;
}
myActive = true;
}
@Override
public void deactivate() {
myActive = false;
myEditorCell.setSelected(false);
myCaretX = myEditorCell.getCaretX();
myCaretXRelative = getRelativeCaretX(myEditorCell);
}
public boolean isActive() {
return myActive;
}
@Override
public SelectionInfoImpl getSelectionInfo() throws SelectionStoreException {
SelectionInfoImpl selectionInfo = new SelectionInfoImpl(this.getClass().getName());
selectionInfo.setCellInfo(myEditorCell.getCellInfo());
selectionInfo.getPropertiesMap().put(CARET_X_PROPERTY_NAME, Integer.toString(getCaretX()));
selectionInfo.getPropertiesMap().put(CARET_X_RELATIVE_PROPERTY_NAME, Integer.toString(getCaretXRelative()));
selectionInfo.getPropertiesMap().put(SIDE_SELECT_DIRECTION_PROPERTY_NAME, mySideSelectDirection.name());
return selectionInfo;
}
@Override
public boolean isSame(Selection another) {
if (this == another) {
return true;
}
if (another == null || getClass() != another.getClass()) {
return false;
}
EditorCellSelection that = (EditorCellSelection) another;
if (!myEditorCell.equals(that.myEditorCell)) {
return false;
}
if (mySideSelectDirection != that.mySideSelectDirection) {
return false;
}
if (getCaretX() != that.getCaretX()) {
return false;
}
return true;
}
@Override
public boolean canExecuteAction(CellActionType type) {
if ((type == CellActionType.DELETE || type == CellActionType.BACKSPACE) && suppressDelete(type)) {
return false;
}
CellAction applicableCellAction = getEditorComponent().getActionHandler().getApplicableCellAction(myEditorCell, type);
return applicableCellAction != null;
}
@Override
public void executeAction(CellActionType type) {
((jetbrains.mps.nodeEditor.EditorComponent) getEditorComponent()).assertModelNotDisposed();
if (canExecuteAction(type)) {
getEditorComponent().getActionHandler().executeAction(myEditorCell, type);
}
}
protected boolean suppressDelete(CellActionType type) {
return !myEditorCell.isBig() && myEditorCell.getAction(type) == null;
}
@NotNull
@Override
public List<EditorCell> getSelectedCells() {
return Collections.singletonList(getEditorCell());
}
@NotNull
@Override
public List<SNode> getSelectedNodes() {
SNode sNode = getEditorCell().getSNode();
return sNode == null ? Collections.EMPTY_LIST : Collections.singletonList(sNode);
}
@Override
public void ensureVisible() {
myEditorCell.getEditorComponent().scrollToCell(myEditorCell);
}
private static int getRelativeCaretX(EditorCell editorCell) {
return editorCell.getCaretX() - editorCell.getLeftGap() - editorCell.getX();
}
private static void setRelativeCaretX(EditorCell editorCell, int relativeCaretX) {
editorCell.setCaretX(editorCell.getX() + editorCell.getLeftGap() + relativeCaretX);
}
}