/*
* Copyright 2007, Plutext Pty Ltd.
*
* This file is part of Docx4all.
Docx4all is free software: you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
Docx4all is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Docx4all. If not, see <http://www.gnu.org/licenses/>.
*/
package org.docx4all.swing.text;
import java.util.List;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter.FilterBypass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.docx4all.util.DocUtil;
import org.docx4all.xml.ElementML;
import org.docx4all.xml.RunContentML;
/**
* @author Jojada Tirtowidjojo - 10/01/2008
*/
public class TextRemover implements TextProcessor {
private static Logger log = LoggerFactory.getLogger(TextRemover.class);
private TextSelector textSelector;
private FilterBypass filterBypass;
public TextRemover(FilterBypass fb, int offset, int length)
throws BadSelectionException {
this.textSelector =
new TextSelector((WordMLDocument) fb.getDocument(), offset, length);
this.filterBypass = fb;
}
public void doAction() throws BadLocationException {
WordMLDocument doc = (WordMLDocument) filterBypass.getDocument();
int offset = textSelector.getOffset();
int length = textSelector.getLength();
if (log.isDebugEnabled()) {
log.debug("doAction(): offset=" + offset + " length=" + length);
}
List<DocumentElement> list = textSelector.getDocumentElements();
DocumentElement tempE = list.get(0);
//Handle the first leaf element specially.
if (tempE.isLeaf() && !textSelector.isFullySelected(tempE)) {
if (list.size() == 1) {
// A single partially selected leaf element
// is treated as normal string deletion.
// A normal string deletion does not involve
// ElementML manipulation.
filterBypass.remove(offset, length);
if (log.isDebugEnabled()) {
log.debug("doAction(): Resulting Structure...");
DocUtil.displayStructure(doc);
}
return;
}
//Process deletion by manipulating ElementML
int count = offset - tempE.getStartOffset();
String text = doc.getText(tempE.getStartOffset(), count);
RunContentML rcml = (RunContentML) tempE.getElementML();
rcml.setTextContent(text);
// first leaf element has been processed.
// Remove from list
list.remove(0);
}
// Handle the last leaf element specially
tempE = list.get(list.size() - 1);
if (tempE.isLeaf() && !textSelector.isFullySelected(tempE)) {
int count = tempE.getEndOffset() - (offset + length);
String text = doc.getText(offset + length, count);
RunContentML rcml = (RunContentML) tempE.getElementML();
rcml.setTextContent(text);
// last leaf element has been processed.
// Remove from list
list.remove(list.size() - 1);
}
DocUtil.deleteElementML(list);
DocumentElement firstPara =
(DocumentElement) doc.getParagraphMLElement(offset, false);
DocumentElement lastPara = null;
if (offset == firstPara.getEndOffset() - 1 && length == 1) {
//deleting an implied newline character
lastPara =
(DocumentElement)
doc.getParagraphMLElement(offset + length, false);
} else {
lastPara =
(DocumentElement)
doc.getParagraphMLElement(offset + length - 1, false);
}
if (firstPara.getStartOffset() < offset
&& offset + length < lastPara.getEndOffset() - 1
&& firstPara != lastPara
&& firstPara.getParentElement() == lastPara.getParentElement()) {
//Merge firstPara and lastPara if both are siblings and not fully selected.
mergeElementML(firstPara, lastPara);
}
//Time to refresh affected paragraphs.
offset = firstPara.getStartOffset();
length = lastPara.getEndOffset() - offset;
doc.refreshParagraphs(offset, length);
}
private void mergeElementML(DocumentElement para1, DocumentElement para2) {
//Grab all lastPara's content from offset + length position
WordMLDocument doc = (WordMLDocument) filterBypass.getDocument();
int offset = textSelector.getOffset();
int length = textSelector.getLength();
int start = offset + length;
int count = (para2.getEndOffset() - 1) - start;
TextSelector ts = null;
try {
ts = new TextSelector(doc, start, count);
} catch (BadSelectionException exc) {
;//should be fine
}
//Delete the merged para2
List<DocumentElement> elemsToMerge = ts.getDocumentElements();
//delete the ElementMLs of elemsToMerge
//so that they are ready for merging
DocUtil.deleteElementML(elemsToMerge);
//Delete the whole para2's ElementML
para2.getElementML().delete();
//Find element where merging start
DocumentElement targetE = (DocumentElement) doc.getCharacterElement(offset - 1);
ElementML targetML = targetE.getElementML();
//elemsToMerge can only consist of RunML's DocumentElement
//and RunContentML's DocumentElement.
//If there is one or more RunContentML's DocumentElement
//they should be at the top of the list.
for (DocumentElement de: elemsToMerge) {
if (!de.isLeaf() && targetE.isLeaf()) {
targetE = (DocumentElement) targetE.getParentElement();
targetML = targetE.getElementML();
}
ElementML ml = de.getElementML();
if (!ml.isImplied()) {
targetML.addSibling(ml, true);
targetML = ml;
}
}
}
}// TextRemover class