blob: c9a95636346a87290afb993b030ff2d31803bed8 [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.io.InputStream;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.OdfSchemaDocument;
import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawImageElement;
import org.odftoolkit.odfdom.dom.element.text.TextSElement;
import org.odftoolkit.odfdom.pkg.OdfElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.manifest.OdfFileEntry;
import org.odftoolkit.simple.common.TextExtractor;
import org.odftoolkit.simple.draw.Image;
import org.odftoolkit.simple.style.StyleTypeDefinitions.AnchorType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This is a decorator class of TextSelection, which help user replace a text content with a Image from Document or from URI.
*
*/
public class ImageSelection extends Selection {
private TextSelection textSelection;
private DrawFrameElement imageContainer;
private boolean mIsInserted;
/**
* Replace the content with a Image
*
* @param image the reference Image to replace.
*
* @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself.
*
*/
public Image replaceWithImage(Image image) {
Image mImage =null;
if(search instanceof TextNavigation){
TextNavigation textSearch = (TextNavigation) search;
int leftLength = textSelection.getText().length();
int index = textSelection.getIndex();
mIsInserted = false;
OdfElement parentElement = textSelection.getContainerElement();
OdfFileDom ownerDom = (OdfFileDom) parentElement.getOwnerDocument();
int nodeLength = TextExtractor.getText(
this.textSelection.getContainerElement()).length();
if (this.textSelection.getText().length() != nodeLength)
this.textSelection.setSelectionReplaced(true);
try {
if (imageContainer == null) {
delete(index, leftLength, parentElement);
// PrepareContainer
imageContainer = ownerDom.newOdfElement(DrawFrameElement.class);
insertOdfElement(imageContainer, index, parentElement);
} else {
NodeList nodeImages = imageContainer.getElementsByTagName("draw:image");
Node nodeImage = nodeImages.item(0);
DrawImageElement im = (DrawImageElement) nodeImage;
Image oldimage = Image.getInstanceof(im);
oldimage.remove();
// PrepareContainer
imageContainer = ownerDom.newOdfElement(DrawFrameElement.class);
insertOdfElement(imageContainer, index, parentElement);
}
// Insert Image resource to package
DrawImageElement imageElement = imageContainer.newDrawImageElement();
InputStream is = image.getImageInputStream();
String internalPath = image.getInternalPath();
String mediaType = OdfFileEntry.getMediaTypeString(internalPath);
OdfSchemaDocument mOdfSchemaDoc = (OdfSchemaDocument) ownerDom.getDocument();
String packagePath = Image.getPackagePath(mOdfSchemaDoc,internalPath);
mOdfSchemaDoc.getPackage().insert(is, packagePath, mediaType);
packagePath = packagePath.replaceFirst(ownerDom.getDocument().getDocumentPath(), "");
Image.configureInsertedImage((OdfSchemaDocument) ownerDom.getDocument(), imageElement,packagePath, false);
// get image object
mImage = Image.getInstanceof(imageElement);
mImage.getStyleHandler().setAchorType(AnchorType.AS_CHARACTER);
mImage.setName("replace" + System.currentTimeMillis());
} catch (Exception e) {
Logger.getLogger(ImageSelection.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
return mImage;
}
/**
* Replace the content with a Image
*
* @param imageUri the URI of the reference Image to replace
*
* @return the new Image in the TextDocument,the image name is set to "replace" + System.currentTimeMillis(), please update the name to others by yourself
*
*/
public Image replaceWithImage(URI imageUri) {
Image mImage =null;
if(search instanceof TextNavigation){
TextNavigation textSearch = (TextNavigation) search;
int leftLength = textSelection.getText().length();
int index = textSelection.getIndex();
mIsInserted = false;
OdfElement parentElement = textSelection.getContainerElement();
OdfFileDom ownerDom = (OdfFileDom) parentElement.getOwnerDocument();
int nodeLength = TextExtractor.getText(
this.textSelection.getContainerElement()).length();
if (this.textSelection.getText().length() != nodeLength)
this.textSelection.setSelectionReplaced(true);
try{
if (imageContainer == null) {
delete(index, leftLength, parentElement);
// PrepareContainer
imageContainer = ownerDom.newOdfElement(DrawFrameElement.class);
insertOdfElement(imageContainer, index, parentElement);
} else {
NodeList nodeImages = imageContainer.getElementsByTagName("draw:image");
Node nodeImage = nodeImages.item(0);
DrawImageElement im = (DrawImageElement) nodeImage;
Image oldimage = Image.getInstanceof(im);
oldimage.remove();
// PrepareContainer
imageContainer = ownerDom.newOdfElement(DrawFrameElement.class);
insertOdfElement(imageContainer, index, parentElement);
}
// Insert Image resource to package
DrawImageElement imageElement = imageContainer.newDrawImageElement();
String imageRef = imageUri.toString();
String mediaType = OdfFileEntry.getMediaTypeString(imageRef);
OdfSchemaDocument mOdfSchemaDoc = (OdfSchemaDocument) ownerDom.getDocument();
String packagePath = Image.getPackagePath(mOdfSchemaDoc, imageRef);
mOdfSchemaDoc.getPackage().insert(imageUri, packagePath, mediaType);
packagePath = packagePath.replaceFirst(ownerDom.getDocument().getDocumentPath(), "");
Image.configureInsertedImage((OdfSchemaDocument) ownerDom.getDocument(), imageElement,packagePath, false);
// get image object
mImage = Image.getInstanceof(imageElement);
mImage.getStyleHandler().setAchorType(AnchorType.AS_CHARACTER);
mImage.setName("replace" + System.currentTimeMillis());
} catch (Exception e) {
Logger.getLogger(ImageSelection.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
return mImage;
}
/*
* Delete the <code>pNode<code> from the <code>fromIndex</code> text, and
* delete <code>leftLength</code> text.
*/
private void delete(int fromIndex, int leftLength, Node pNode) {
if ((fromIndex == 0) && (leftLength == 0)) {
return;
}
int nodeLength = 0;
Node node = pNode.getFirstChild();
while (node != null) {
if ((fromIndex == 0) && (leftLength == 0)) {
return;
}
if (node.getNodeType() == Node.TEXT_NODE) {
nodeLength = node.getNodeValue().length();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
// text:s
if (node.getLocalName().equals("s")) {
try {
nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
.getUri(), "c"));
} catch (Exception e) {
nodeLength = 1;
}
} else if (node.getLocalName().equals("line-break")) {
nodeLength = 1;
} else if (node.getLocalName().equals("tab")) {
nodeLength = 1;
} else {
nodeLength = TextExtractor.getText((OdfElement) node).length();
}
}
if (nodeLength <= fromIndex) {
fromIndex -= nodeLength;
} else {
// the start index is in this node
if (node.getNodeType() == Node.TEXT_NODE) {
String value = node.getNodeValue();
StringBuffer buffer = new StringBuffer();
buffer.append(value.substring(0, fromIndex));
int endLength = fromIndex + leftLength;
int nextLength = value.length() - endLength;
fromIndex = 0;
if (nextLength >= 0) {
// delete the result
buffer.append(value.substring(endLength, value.length()));
leftLength = 0;
} else {
leftLength = endLength - value.length();
}
node.setNodeValue(buffer.toString());
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
// if text:s?????????
// text:s
if (node.getLocalName().equals("s")) {
// delete space
((TextSElement) node).setTextCAttribute(new Integer(nodeLength - fromIndex));
leftLength = leftLength - (nodeLength - fromIndex);
fromIndex = 0;
} else if (node.getLocalName().equals("line-break") || node.getLocalName().equals("tab")) {
fromIndex = 0;
leftLength--;
} else {
delete(fromIndex, leftLength, node);
int length = (fromIndex + leftLength) - nodeLength;
leftLength = length > 0 ? length : 0;
fromIndex = 0;
}
}
}
node = node.getNextSibling();
}
}
/**
* Construct a ImageSelection with TextSelection. Then user can replace text
* content with Image from Document or Image form System
*
* @param selection
* the TextSelection to be decorated.
*/
public ImageSelection(TextSelection selection) {
textSelection = selection;
search = textSelection.getTextNavigation();
imageContainer = null;
}
/**
* Delete the selection from the document the other matched selection in the
* same container element will be updated automatically because the start
* index of the following selections will be changed when the previous
* selection has been deleted.
*
* @throws InvalidNavigationException
* if the selection is unavailable.
*/
@Override
public void cut() throws InvalidNavigationException {
textSelection.cut();
}
/**
* Paste this selection just after a specific selection.
*
* @param positionItem
* a selection that is used to point out the position
* @throws InvalidNavigationException
* if the selection is unavailable.
*/
@Override
public void pasteAtEndOf(Selection positionItem) throws InvalidNavigationException {
textSelection.pasteAtEndOf(positionItem);
}
/**
* Paste this selection just before a specific selection.
*
* @param positionItem
* a selection that is used to point out the position
* @throws InvalidNavigationException
* if the selection is unavailable.
*/
@Override
public void pasteAtFrontOf(Selection positionItem) throws InvalidNavigationException {
textSelection.pasteAtFrontOf(positionItem);
}
protected void refresh(int offset) {
textSelection.refresh(offset);
}
protected void refreshAfterFrontalDelete(Selection deletedItem) {
textSelection.refreshAfterFrontalDelete(deletedItem);
}
protected void refreshAfterFrontalInsert(Selection insertedItem) {
textSelection.refreshAfterFrontalInsert(insertedItem);
}
private void insertOdfElement(OdfElement odfElement, int fromIndex, Node pNode) {
if (fromIndex < 0) {
fromIndex = 0;
}
if (fromIndex == 0 && mIsInserted) {
return;
}
int nodeLength = 0;
Node node = pNode.getFirstChild();
while (node != null) {
if (fromIndex <= 0 && mIsInserted) {
return;
}
if (node.getNodeType() == Node.TEXT_NODE) {
nodeLength = node.getNodeValue().length();
if ((fromIndex != 0) && (nodeLength < fromIndex)) {
fromIndex -= nodeLength;
} else {
// insert result after node, and insert an new text node
// after the result node
String value = node.getNodeValue();
StringBuffer buffer = new StringBuffer();
buffer.append(value.substring(0, fromIndex));
// insert the text span in appropriate position
node.setNodeValue(buffer.toString());
Node nextNode = node.getNextSibling();
Node parNode = node.getParentNode();
Node newNode = node.cloneNode(true);
newNode.setNodeValue(value.substring(fromIndex, value.length()));
if (nextNode != null) {
parNode.insertBefore(odfElement, nextNode);
parNode.insertBefore(newNode, nextNode);
} else {
parNode.appendChild(odfElement);
parNode.appendChild(newNode);
}
mIsInserted = true;
return;
}
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
// text:s
if (node.getLocalName().equals("s")) {
try {
nodeLength = Integer.parseInt(((Element) node).getAttributeNS(OdfDocumentNamespace.TEXT
.getUri(), "c"));
} catch (Exception e) {
nodeLength = 1;
}
fromIndex -= nodeLength;
} else if (node.getLocalName().equals("line-break")) {
nodeLength = 1;
fromIndex--;
} else if (node.getLocalName().equals("tab")) {
nodeLength = 1;
fromIndex--;
} else {
nodeLength = TextExtractor.getText((OdfElement) node).length();
insertOdfElement(odfElement, fromIndex, node);
fromIndex -= nodeLength;
}
}
node = node.getNextSibling();
}
}
}