blob: 0a97aa806811efa656f3118e8e3ee52505c384f9 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 org.odftoolkit.simple.common.navigation;
import java.util.Hashtable;
import java.util.Vector;
import org.odftoolkit.odfdom.pkg.OdfElement;
/**
* <code>Selection</code> describes one of the matched results, which is
* recognized by the container element, the start index of the text content in
* this element and the text content.
*/
public abstract class Selection {
private OdfElement mElement;
private int mIndex;
protected Navigation search;
public Navigation getNavigation() {
return search;
}
/**
* Get the container element of this <code>Selection</code>.
*
* @return the container element
*/
public OdfElement getElement() {
return mElement;
}
/**
* Get the start index of the text content in the container element. This is
* only meaningful for {@link TextSelection TextSelection} and its sub
* classes, other type of <code>Selection</code> will return 0.
*
* @return the start index of the container element
*/
public int getIndex() {
return mIndex;
}
/**
* Cut current <code>Selection</code>.
*
* @throws InvalidNavigationException
*/
public abstract void cut() throws InvalidNavigationException;
/**
* Paste current <code>Selection</code> at front of the specified position
* <code>Selection</code>.
*
* @param positionItem
* the position <code>Selection</code>
* @throws InvalidNavigationException
*/
public abstract void pasteAtFrontOf(Selection positionItem) throws InvalidNavigationException;
/**
* Paste current <code>Selection</code> at end of the specified position
* <code>Selection</code>.
*
* @param positionItem
* the position <code>Selection</code>
* @throws InvalidNavigationException
*/
public abstract void pasteAtEndOf(Selection positionItem) throws InvalidNavigationException;
/**
* When a selected item has been deleted, the <code>Selection</code>s after
* this deleted <code>Selection</code> should be refreshed, as these
* <code>Selection</code>s index have been changed.
*
* @param deletedItem
* the deleted <code>Selection</code>
*/
protected abstract void refreshAfterFrontalDelete(Selection deletedItem);
/**
* When a selected item has been inserted, the <code>Selection</code> after
* the inserted item should be refresh, as these <code>Selection</code>s
* index have been changed.
*
* @param insertedItem
* the inserted <code>Selection</code>
*/
protected abstract void refreshAfterFrontalInsert(Selection insertedItem);
/**
* A quick method to update the index of this <code>Selection</code>.
*
* @param offset
* the offset that the index should be added.
*/
protected abstract void refresh(int offset);
/**
* SelectionManager can manage all the <code>Selection</code>s that are
* returned to end users. This SelectionManager contains a repository of all
* <code>Selection</code>s, and will refresh the status/index of
* <code>Selection</code>s after certain operation.
*/
static class SelectionManager {
private static Hashtable<OdfElement, Vector<Selection>> repository = new Hashtable<OdfElement, Vector<Selection>>();
/**
* Register the <code>Selection</code> item.
*
* @param item
* the <code>Selection</code> item
*/
public static void registerItem(Selection item) {
OdfElement element = item.getElement();
if (repository.containsKey(element)) {
Vector<Selection> selections = repository.get(element);
int i = 0;
while (i < selections.size()) {
if (selections.get(i).getIndex() > item.getIndex()) {
selections.insertElementAt(item, i);
break;
}
i++;
}
if (i == selections.size()) {
selections.add(item);
}
} else {
Vector<Selection> al = new Vector<Selection>();
al.add(item);
repository.put(element, al);
}
}
/**
* Refresh the <code>Selection</code>s in repository after a item is
* cut.
*
* @param cutItem
* the cut item
*/
public synchronized static void refreshAfterCut(Selection cutItem) {
// travase the whole sub tree
OdfElement element = cutItem.getElement();
if (repository.containsKey(element)) {
Vector<Selection> selections = repository.get(element);
for (int i = 0; i < selections.size(); i++) {
if (selections.get(i).getIndex() > cutItem.getIndex()) {
selections.get(i).refreshAfterFrontalDelete(cutItem);
}
}
}
}
/**
* Refresh the selections in repository after pastedAtFrontOf operation
* is called.
*
* @param item
* the pasted item
* @param positionItem
* the position item
*/
public synchronized static void refreshAfterPasteAtFrontOf(Selection item, Selection positionItem) {
// travase the whole sub tree
OdfElement element = positionItem.getElement();
if (repository.containsKey(element)) {
Vector<Selection> selections = repository.get(element);
for (int i = 0; i < selections.size(); i++) {
if (selections.get(i).getIndex() >= positionItem.getIndex()) {
selections.get(i).refreshAfterFrontalInsert(item);
}
}
}
}
/**
* Refresh the <code>Selection</code>s in repository after pastedAtEndOf
* operation is called.
*
* @param item
* the pasted item
* @param positionItem
* the position item
*/
public synchronized static void refreshAfterPasteAtEndOf(Selection item, Selection positionItem) {
OdfElement element = positionItem.getElement();
int positionIndex;
if (positionItem instanceof TextSelection) {
positionIndex = positionItem.getIndex() + ((TextSelection) positionItem).getText().length();
} else {
positionIndex = positionItem.getIndex();
}
if (repository.containsKey(element)) {
Vector<Selection> selections = repository.get(element);
for (int i = 0; i < selections.size(); i++) {
if (selections.get(i).getIndex() >= positionIndex) {
selections.get(i).refreshAfterFrontalInsert(item);
}
}
}
}
/**
* Remove the <code>Selection</code> from repository.
*
* @param item
* <code>Selection</code> item
*/
public static void unregisterItem(Selection item) {
OdfElement element = item.getElement();
if (repository.containsKey(element)) {
Vector<Selection> selections = repository.get(element);
selections.remove(item);
}
}
/**
* A direct method to update all the <code>Selection</code>s contained
* in a element after a certain position.
*
* @param containerElement
* the container element
* @param offset
* the offset
* @param positionIndex
* the index of a certain position
*/
public synchronized static void refresh(OdfElement containerElement, int offset, int positionIndex) {
if (repository.containsKey(containerElement)) {
Vector<Selection> selections = repository.get(containerElement);
for (int i = 0; i < selections.size(); i++) {
if (selections.get(i).getIndex() >= positionIndex) {
selections.get(i).refresh(offset);
}
}
}
}
private SelectionManager() {
}
}
}