/****************************************************************************** * Copyright (c) 2016 Oracle * 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: * Konstantin Komissarchik - initial implementation review and ongoing maintenance ******************************************************************************/ package org.eclipse.sapphire.ui; import org.eclipse.sapphire.services.Service; import org.eclipse.sapphire.services.ServiceEvent; import org.eclipse.sapphire.util.EqualsFactory; import org.eclipse.sapphire.util.HashCodeFactory; /** * TextSelectionService is a conduit between the presentation layer and anything that needs * to observe or change the selection in a text property editor. * * <p>This service is not intended to be implemented by adopters.</p> * * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public final class TextSelectionService extends Service { private Range selection = new Range( 0, 0 ); /** * Returns the current text selection. */ public Range selection() { return this.selection; } /** * Places the caret at the specified position. This is equivalent to setting the selection to a zero-length * range starting at this position. If selection changes, TextSelectionEvent will be fired. * * @param position the desired caret position */ public void select( final int position ) { select( position, position ); } /** * Selects a text range. If selection changes, TextSelectionEvent will be fired. * * @param start the starting position of the text range * @param end the ending position of the text range (non-inclusive) */ public void select( final int start, final int end ) { select( new Range( start, end ) ); } /** * Selects a text range. If selection changes, TextSelectionEvent will be fired. * * @param start the starting position of the text range * @param end the ending position of the text range (non-inclusive) */ public void select( final Range range ) { if( range == null ) { throw new IllegalArgumentException(); } if( ! this.selection.equals( range ) ) { final Range before = this.selection; this.selection = range; broadcast( new TextSelectionEvent( this, before, this.selection ) ); } } /** * Represents an immutable range of characters defined by a starting and an ending position. */ public static final class Range { private final int start; private final int end; /** * Constructs a new Range object. * * @param start the starting position of the text range * @param end the ending position of the text range (non-inclusive) */ public Range( final int start, final int end ) { if( start < 0 ) { throw new IllegalArgumentException(); } if( end < start ) { throw new IllegalArgumentException(); } this.start = start; this.end = end; } @Override public boolean equals( final Object obj ) { if( obj instanceof Range ) { final Range range = (Range) obj; return EqualsFactory.start().add( this.start, range.start ).add( this.end, range.end ).result(); } return false; } @Override public int hashCode() { return HashCodeFactory.start().add( this.start ).add( this.end ).result(); } /** * Returns the starting position of the text range. */ public int start() { return this.start; } /** * Returns the ending position of the text range. */ public int end() { return this.end; } /** * Returns the length of the text range. */ public int length() { return this.end - this.start; } @Override public String toString() { return "[" + this.start + "," + this.end + ")"; } } /** * The event that is fired when text selection changes. */ public static final class TextSelectionEvent extends ServiceEvent { private Range before; private Range after; TextSelectionEvent( final TextSelectionService service, final Range before, final Range after ) { super( service ); this.before = before; this.after = after; } /** * Returns the text selection before the selection was changed. */ public Range before() { return this.before; } /** * Returns the text selection after the selection was changed. */ public Range after() { return this.after; } } }