/*
* Copyright 2008, 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.plutext.client.wrappedTransforms;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.docx4all.swing.text.DocumentElement;
import org.docx4all.swing.text.WordMLDocument;
import org.docx4all.util.XmlUtil;
import org.docx4all.xml.ElementML;
import org.docx4all.xml.SdtBlockML;
import org.docx4j.XmlUtils;
import org.plutext.client.Mediator;
import org.plutext.client.Util;
import org.plutext.client.state.StateChunk;
import org.plutext.transforms.Changesets.Changeset;
import org.plutext.transforms.Transforms.T;
public class TransformInsert extends TransformAbstract {
private static Logger log = LoggerFactory.getLogger(TransformInsert.class);
public TransformInsert(T t) {
super(t);
}
/* Markup the existing sdt with one containing w:ins or w:del*/
@Override
public String markupChanges(String original, Changeset changeset) {
log.debug("markupChanges(): Marking up SdtBlock = "
+ getSdt()
+ " - ID="
+ getPlutextId() );
log.debug("markupChanges(): 'original' param = " + original);
try {
if (original == null) {
this.markedUpSdt = XmlUtil.markupAsInsertion(getSdt(), changeset);
} else {
org.docx4j.wml.SdtBlock origSdt =
(org.docx4j.wml.SdtBlock) XmlUtils.unmarshalString(original);
this.markedUpSdt = XmlUtil.markupDifference(getSdt(), origSdt, changeset);
}
} catch (Exception exc) {
log.error("markupChanges(): Exception caught during marking up:");
exc.printStackTrace();
this.markedUpSdt = null;
}
String result = null;
if (this.markedUpSdt != null) {
result = XmlUtils.marshaltoString(this.markedUpSdt, true);
}
log.debug("markupChanges(): Result = " + result);
return result;
}
public long apply(Mediator mediator, HashMap<String, StateChunk> stateChunks) {
String idStr = getPlutextId();
log.debug("apply(): Inserting SdtBlock = " + getSdt() + " - ID="
+ idStr);
if (this.markedUpSdt == null) {
//Sdt has not been marked up or there was an error during marking up.
//See: markupChanges().
//Silently ignore.
log.error("apply(): No marked up Sdt.");
return -1;
}
// If a Delete is followed by Insert (reinstate),
// the server will not transmit the Delete.
// So here we test whether the sdt is already present
/* Testing this case requires three clients:
*
* Client 1, 2, 3 all open.
*
* Client 1 deletes an sdt; transmits
*
* Client 2 fetches; rejects change (and optionally moves or edits); transmits
*
* Client 3 fetches
*
*/
WordMLDocument doc =
(WordMLDocument) mediator.getWordMLTextPane().getDocument();
DocumentElement elem = Util.getDocumentElement(doc, idStr);
if (elem != null) {
//Treat this element as being moved.
log.debug("apply(): Detected reinstatement.");
log.debug("apply(): Document element=" + elem + " is deleted.");
elem.getElementML().delete();
updateRefreshOffsets(mediator, elem.getStartOffset(), elem.getEndOffset());
mediator.getDivergences().delete(idStr);
}
// Plutext server is trying to use absolute index position for
// locating the insert positon.
Long insertAtIndex = null;
if (this.t.getPosition() == null || this.t.getPosition() < 0) {
log.error("apply(): Invalid insertion location t.getPosition()="
+ t.getPosition());
insertAtIndex = null;
} else {
// if user has locally inserted/deleted sdt's
// we need to adjust the specified position ...
Long pos = t.getPosition();
insertAtIndex = pos + mediator.getDivergences().getOffset(pos);
log.debug("apply(): Insertion location " + pos + " adjusted to "
+ insertAtIndex);
}
if (insertAtIndex == null || insertAtIndex < 0) {
log.error("apply(): Invalid insertAtIndex=" + insertAtIndex);
// TODO - throw error
return -1;
}
DocumentElement root = (DocumentElement) doc.getDefaultRootElement();
ElementML bodyML = root.getElementML().getChild(0);
int idx = Math.min(bodyML.getChildrenCount() - 1, insertAtIndex
.intValue());
log.debug("apply(): SdtBlock will be inserted at idx=" + idx);
ElementML ml = bodyML.getChild(idx);
log.debug("apply(): Currently, ElementML at idx=" + idx + " is " + ml);
SdtBlockML markedUpML =
new SdtBlockML(
(org.docx4j.wml.SdtBlock)
XmlUtils.deepCopy(this.markedUpSdt));
ml.addSibling(markedUpML, false);
elem = (DocumentElement) root.getElement(idx);
if (elem.getElementML() != ml) {
//Just in case.
//hint to refresh the whole document.
updateRefreshOffsets(mediator, 0, doc.getLength());
} else {
updateRefreshOffsets(mediator, elem.getStartOffset(), elem.getEndOffset());
}
//What goes in stateChunks is the *non-marked up*
//sdt that we got from the server.
StateChunk sc = new StateChunk(getSdt());
stateChunks.put(sc.getIdAsString(), sc);
// But also record the marked up version
sc.setMarkedUpSdt(XmlUtils.marshaltoString(this.markedUpSdt, true));
mediator.getDivergences().insert(idStr, Long.valueOf(idx));
return sequenceNumber;
}
} // TransformInsert class