/*******************************************************************************
* Copyright (c) 2004, 2005 IBM Corporation and others.
* All rights reserved. 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.gef.examples.text.edit;
import java.util.Iterator;
import org.eclipse.jface.util.Assert;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.GraphicalEditPolicy;
import org.eclipse.gef.examples.text.SelectionRange;
import org.eclipse.gef.examples.text.TextLocation;
import org.eclipse.gef.examples.text.model.Block;
import org.eclipse.gef.examples.text.model.Container;
import org.eclipse.gef.examples.text.model.InlineContainer;
import org.eclipse.gef.examples.text.model.ModelLocation;
import org.eclipse.gef.examples.text.model.Style;
import org.eclipse.gef.examples.text.model.TextRun;
import org.eclipse.gef.examples.text.model.commands.ApplyBooleanStyle;
import org.eclipse.gef.examples.text.model.commands.ApplyMultiStyle;
import org.eclipse.gef.examples.text.model.commands.ChangeString;
import org.eclipse.gef.examples.text.model.commands.CompoundEditCommand;
import org.eclipse.gef.examples.text.model.commands.ConvertElementCommand;
import org.eclipse.gef.examples.text.model.commands.MergeWithPrevious;
import org.eclipse.gef.examples.text.model.commands.MiniEdit;
import org.eclipse.gef.examples.text.model.commands.NestElementCommand;
import org.eclipse.gef.examples.text.model.commands.ProcessMacroCommand;
import org.eclipse.gef.examples.text.model.commands.PromoteElementCommand;
import org.eclipse.gef.examples.text.model.commands.RemoveRange;
import org.eclipse.gef.examples.text.model.commands.RemoveText;
import org.eclipse.gef.examples.text.model.commands.SubdivideElement;
import org.eclipse.gef.examples.text.requests.TextRequest;
/**
* @since 3.1
*/
public class BlockEditPolicy extends GraphicalEditPolicy {
private Command checkForConversion(TextLocation location) {
TextRun run = (TextRun)location.part.getModel();
String prefix = run.getText().substring(0, location.offset);
if (prefix.endsWith("<b>")) {
Container converted = new InlineContainer(Container.TYPE_INLINE);
converted.getStyle().setBold(true);
TextRun boldText = new TextRun("BOLD");
converted.add(boldText);
ProcessMacroCommand command = new ProcessMacroCommand(run, location.offset - 3,
location.offset, converted, new ModelLocation(boldText, 0));
command.setEndLocation(new ModelLocation(boldText, 1));
return command;
} else if (prefix.equals("()")) {
ConvertElementCommand command;
Container list = new Block(Container.TYPE_BULLETED_LIST);
TextRun bullet = new TextRun("", TextRun.TYPE_BULLET);
list.add(bullet);
command = new ConvertElementCommand(run, 0, 2, list, new ModelLocation(bullet, 0));
return command;
} else if (prefix.equals("import")) {
ConvertElementCommand command;
Container imports = new Block(Container.TYPE_IMPORT_DECLARATIONS);
TextRun statement = new TextRun("", TextRun.TYPE_IMPORT);
imports.add(statement);
command = new ConvertElementCommand(run, 0, 6, imports, new ModelLocation(statement,
0));
return command;
}
return null;
}
private Command getBackspaceCommand(TextRequest request) {
TextLocation where = request.getSelectionRange().begin;
CompoundEditCommand command = (CompoundEditCommand)request.getPreviousCommand();
if (command == null)
command = new CompoundEditCommand("Backspace");
TextRun run = (TextRun)where.part.getModel();
MiniEdit remove;
if (where.offset == 0) {
remove = getMergeBackspaceEdit(request);
command.setBeginLocation(new ModelLocation(run, where.offset));
command.setEndLocation(new ModelLocation(run, where.offset));
} else {
remove = new RemoveText(run, where.offset - 1, where.offset);
command.setBeginLocation(new ModelLocation(run, where.offset - 1));
command.setEndLocation(new ModelLocation(run, where.offset));
}
command.pendEdit(remove);
return command;
}
public Command getCommand(Request request) {
if (TextRequest.REQ_STYLE == request.getType())
return getTextStyleApplication((TextRequest)request);
if (TextRequest.REQ_INSERT == request.getType()
|| TextRequest.REQ_OVERWRITE == request.getType()
|| TextRequest.REQ_REMOVE_RANGE == request.getType())
return getChangeTextCommand((TextRequest)request);
if (TextRequest.REQ_BACKSPACE == request.getType())
return getBackspaceCommand((TextRequest)request);
if (TextRequest.REQ_DELETE == request.getType())
return getDeleteCommand((TextRequest)request);
if (TextRequest.REQ_NEWLINE == request.getType())
return getNewlineCommand((TextRequest)request);
if (TextRequest.REQ_UNINDENT == request.getType())
return getUnindentCommand((TextRequest)request);
if (TextRequest.REQ_INDENT == request.getType())
return getIndentCommand((TextRequest)request);
return null;
}
private Command getTextStyleApplication(TextRequest request) {
SelectionRange range = request.getSelectionRange();
ModelLocation start = new ModelLocation(
(TextRun)range.begin.part.getModel(), range.begin.offset);
ModelLocation end = new ModelLocation(
(TextRun)range.end.part.getModel(), range.end.offset);
CompoundEditCommand command = new CompoundEditCommand("Set Style");
command.setBeginLocation(start);
command.setEndLocation(end);
String styleID = request.getStyleKeys()[0];
if (Style.PROPERTY_ALIGNMENT.equals(styleID)
|| Style.PROPERTY_ORIENTATION.equals(styleID)) {
Object value = request.getStyleValues()[0];
for (Iterator iter = range.getLeafParts().iterator(); iter.hasNext();) {
// TODO optimize by ensuring that runs in the same container don't cause
// that container's style to be set multiple times
TextRun run = (TextRun)((TextEditPart)iter.next()).getModel();
command.pendEdit(new ApplyMultiStyle(run.getBlockContainer(), styleID, value));
}
} else if (!range.isEmpty()) {
command.pendEdit(new ApplyBooleanStyle(start, end, request.getStyleKeys(),
request.getStyleValues()));
}
return command;
}
private Command getIndentCommand(TextRequest request) {
SelectionRange range = request.getSelectionRange();
return new NestElementCommand(range.begin.part, range.begin.offset);
}
private Command getUnindentCommand(TextRequest request) {
SelectionRange range = request.getSelectionRange();
return new PromoteElementCommand(range.begin.part, range.begin.offset);
}
private Command getDeleteCommand(TextRequest request) {
TextLocation where = request.getSelectionRange().begin;
if (where.offset == where.part.getLength())
return null;
TextRun run = (TextRun)where.part.getModel();
MiniEdit remove = new RemoveText(run, where.offset, where.offset + 1);
CompoundEditCommand command = (CompoundEditCommand)request.getPreviousCommand();
if (command == null) {
command = new CompoundEditCommand("Delete");
command.setBeginLocation(new ModelLocation(run, where.offset));
command.setEndLocation(new ModelLocation(run, where.offset + 1));
}
command.pendEdit(remove);
return command;
}
private MiniEdit getMergeBackspaceEdit(TextRequest request) {
TextEditPart part = request.getSelectionRange().begin.part;
MergeWithPrevious edit = new MergeWithPrevious(part);
if (edit.canApply())
return edit;
return null;
}
private Command getNewlineCommand(TextRequest request) {
TextLocation where = request.getSelectionRange().end;
TextRun run = (TextRun)where.part.getModel();
SubdivideElement edit = new SubdivideElement(run, where.offset);
CompoundEditCommand command = null;
if (request.getPreviousCommand() instanceof CompoundEditCommand)
command = (CompoundEditCommand)request.getPreviousCommand();
else
command = new CompoundEditCommand("typing");
command.pendEdit(edit);
return command;
}
public EditPart getTargetEditPart(Request request) {
if (request instanceof TextRequest)
return getHost();
return null;
}
private Command getChangeTextCommand(TextRequest request) {
CompoundEditCommand command = null;
if (request.getPreviousCommand() instanceof CompoundEditCommand)
command = (CompoundEditCommand)request.getPreviousCommand();
SelectionRange range = request.getSelectionRange();
if (range.isEmpty() && request.getText().equals(" ")) {
Command result = checkForConversion(request.getSelectionRange().begin);
if (result != null)
return result;
}
TextRun rangeBegin = (TextRun)range.begin.part.getModel();
if (command == null) {
TextRun rangeEnd = (TextRun)range.end.part.getModel();
command = new CompoundEditCommand("typing");
command.setBeginLocation(new ModelLocation(rangeBegin, range.begin.offset));
if (!range.isEmpty()) {
RemoveRange remove;
command.setEndLocation(new ModelLocation(rangeEnd, range.end.offset));
remove = new RemoveRange(rangeBegin, range.begin.offset, rangeEnd,
range.end.offset);
command.pendEdit(remove);
}
} else {
//The range should be empty any time there is a previous command
Assert.isTrue(range.isEmpty());
}
if (request.getText() != null) {
ChangeString insert = new ChangeString(rangeBegin, request.getText(),
range.begin.offset, request.getType() == TextRequest.REQ_OVERWRITE);
command.pendEdit(insert);
}
return command;
}
}