package nota.oxygen.dtbook;
import java.util.List;
import javax.swing.text.BadLocationException;
import nota.oxygen.common.BaseAuthorOperation;
import nota.oxygen.common.Utils;
import ro.sync.ecss.extensions.api.ArgumentDescriptor;
import ro.sync.ecss.extensions.api.ArgumentsMap;
import ro.sync.ecss.extensions.api.AuthorDocumentController;
import ro.sync.ecss.extensions.api.AuthorOperationException;
import ro.sync.ecss.extensions.api.node.AttrValue;
import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;
/**
* @author OHA
* Markup current element as a level heading, including surrounding level
*/
public class MarkupLevelHeadingOperation extends BaseAuthorOperation {
private static String ARG_LEVEL_TYPE = "level-type";
private static String ARG_NS = "namespace";
private static String ARG_GENERIC_LEVEL_TAG = "generic-level-tag";
private static String ARG_GENERIC_HEADING_TAG = "generic-heading-tag";
private static String ARG_FIXED_LEVEL_TAGS = "fixed-level-tags";
private static String ARG_FIXED_HEADING_TAGS = "fixed-heading-tags";
@Override
public ArgumentDescriptor[] getArguments() {
return new ArgumentDescriptor[] {
new ArgumentDescriptor(ARG_LEVEL_TYPE, ArgumentDescriptor.TYPE_STRING, "Type of level to markup - possible values are 'sub-level' and 'same-level'"),
new ArgumentDescriptor(ARG_NS, ArgumentDescriptor.TYPE_STRING, "Namespace of level container and heading elements"),
new ArgumentDescriptor(ARG_GENERIC_LEVEL_TAG, ArgumentDescriptor.TYPE_STRING, "Name of the generic level container element"),
new ArgumentDescriptor(ARG_GENERIC_HEADING_TAG, ArgumentDescriptor.TYPE_STRING, "Name of the generic level heading element"),
new ArgumentDescriptor(ARG_FIXED_LEVEL_TAGS, ArgumentDescriptor.TYPE_STRING, "Names of the fixed-depth level container elements, separated by |"),
new ArgumentDescriptor(ARG_FIXED_HEADING_TAGS, ArgumentDescriptor.TYPE_STRING, "Name of the fixed-depth level heading elements, separated by |")};
}
String levelType;
String ns;
String genericLevelTag;
String genericHeadingTag;
String[] fixedLevelTags;
String[] fixedHeadingTags;
@Override
protected void parseArguments(ArgumentsMap args)
throws IllegalArgumentException {
levelType = (String)args.getArgumentValue(ARG_LEVEL_TYPE);
ns = (String)args.getArgumentValue(ARG_NS);
if (ns==null) ns = "";
genericLevelTag = (String)args.getArgumentValue(ARG_GENERIC_LEVEL_TAG);
if (genericLevelTag==null) genericLevelTag = "";
genericHeadingTag = (String)args.getArgumentValue(ARG_GENERIC_HEADING_TAG);
if (genericHeadingTag==null) genericHeadingTag = "";
fixedLevelTags = ((String)args.getArgumentValue(ARG_FIXED_LEVEL_TAGS)).split("\\|");
fixedHeadingTags = ((String)args.getArgumentValue(ARG_FIXED_HEADING_TAGS)).split("\\|");
}
@Override
public String getDescription() {
return "Markup current element as a level heading, including surrounding level";
}
protected int getLevelDepth(AuthorNode node) {
int res = 0;
if (node!=null) {
res = getLevelDepth(node.getParent());
if (node instanceof AuthorElement) {
if (((AuthorElement) node).getLocalName().equals("level")) res++;
}
}
return res;
}
protected boolean isLevelElement(AuthorElement elem) {
if (elem.getNamespace()!=ns) return false;
if (elem.getLocalName().equals(genericLevelTag)) return true;
for (int i=0; i<fixedLevelTags.length; i++) {
if (elem.getLocalName().equals(fixedLevelTags[i])) return true;
}
return false;
}
protected void doSubLevelOperation() throws AuthorOperationException, BadLocationException {
AuthorDocumentController docCtrl = getAuthorAccess().getDocumentController();
int startSel = getSelectionStart();
AuthorElement firstAthElem = (AuthorElement)docCtrl.getNodeAtOffset(startSel);
if (isLevelElement(firstAthElem)) {
showMessage("Current element is a level container can therefore not become a level heading ");
}
int depth = getLevelDepth(firstAthElem)+1;
AuthorElement parent = (AuthorElement)firstAthElem.getParent();
String newLevelName = "";
String newHeadingName = "";
if (parent.getNamespace().equals(ns)) {
String localName = parent.getLocalName();
if (localName.equals(genericLevelTag)) {
newLevelName = genericLevelTag;
newHeadingName = genericHeadingTag;
}
else {
for (int i=0; i<fixedLevelTags.length-1; i++) {
if (localName.equals(fixedLevelTags[i])) {
newLevelName = fixedLevelTags[i+1];
newHeadingName = fixedHeadingTags[i+1];
}
}
}
}
if (newHeadingName.isEmpty()) {
showMessage("The current element is not the child of a level container that can have sub-level container children");
return;
}
List<AuthorNode> siblings = parent.getContentNodes();
AuthorElement lastAthElem = firstAthElem;
for (int i = siblings.indexOf(firstAthElem)+1; i<siblings.size(); i++) {
if (siblings.get(i) instanceof AuthorElement)
{
AuthorElement elem = (AuthorElement)siblings.get(i);
if (elem.getLocalName().equals(newLevelName)) break;
lastAthElem = elem;
}
}
String nsAttr = "";
if (!ns.isEmpty()) nsAttr = " xmlns='"+ns+"'";
docCtrl.surroundInFragment("<"+newLevelName+nsAttr+" depth='"+depth+"'></"+newLevelName+">", firstAthElem.getStartOffset(), lastAthElem.getEndOffset());
docCtrl.renameElement(firstAthElem, newHeadingName);
docCtrl.setAttribute("depth", new AttrValue(""+depth), firstAthElem);
getAuthorAccess().getEditorAccess().setCaretPosition(firstAthElem.getStartOffset()+1);
}
@Override
protected void doOperation() throws AuthorOperationException {
if (fixedLevelTags==null) throw new AuthorOperationException("Names of fixed level container elements are missing");
if (fixedHeadingTags==null) throw new AuthorOperationException("Names of fixed heading elements are missing");
if (fixedLevelTags.length!=fixedHeadingTags.length) {
//showMessage("fixed levels: "+flt+" fixed headings: "+fht);
throw new AuthorOperationException(
"Different number names of elements for fixed level containers and headings are different"
+"- counts are "+fixedLevelTags.length+" and "+fixedHeadingTags.length+" respectively");
}
try
{
if (levelType.equalsIgnoreCase("sub-level"))
{
doSubLevelOperation();
}
else if (levelType.equalsIgnoreCase("same-level"))
{
doSameLevelOperation();
}
else
{
throw new AuthorOperationException("Unknown levelType "+levelType);
}
}
catch (Exception e)
{
if (e instanceof AuthorOperationException)
{
throw (AuthorOperationException)e;
}
else
{
throw new AuthorOperationException(
"Unexpected "+e.getClass().getName()+" occured: "+e.getMessage(),
e);
}
}
}
protected void doSameLevelOperation() throws AuthorOperationException, BadLocationException {
AuthorDocumentController docCtrl = getAuthorAccess().getDocumentController();
int startSel = getSelectionStart();
AuthorElement firstAthElem = (AuthorElement)docCtrl.getNodeAtOffset(startSel);
if (isLevelElement(firstAthElem)) {
showMessage("Current element is a level container can therefore not become a level heading ");
}
int depth = getLevelDepth(firstAthElem);
AuthorElement parent = (AuthorElement)firstAthElem.getParent();
String newLevelName = parent.getLocalName();
String newHeadingName = "";
if (parent.getNamespace().equals(ns)) {
if (newLevelName.equals(genericLevelTag)) {
newHeadingName = genericHeadingTag;
}
for (int i=0; i<fixedLevelTags.length; i++) {
if (newLevelName.equals(fixedLevelTags[i])) {
newHeadingName = fixedHeadingTags[i];
}
}
}
if (newHeadingName.isEmpty()) {
showMessage("The current element is not the child of a level container element");
return;
}
docCtrl.renameElement(firstAthElem, newHeadingName);
docCtrl.setAttribute("depth", new AttrValue(""+depth), firstAthElem);
parent = (AuthorElement)firstAthElem.getParent();
AuthorDocumentFragment newLevelContent
= docCtrl.createDocumentFragment(firstAthElem.getStartOffset(), Utils.getLastChild(parent).getEndOffset());
String nsAttr = "";
if (!ns.isEmpty()) nsAttr = " xmlns='"+ns+"'";
String newLevelXml = "<"+newLevelName+nsAttr+" depth='"+depth+"'>"+docCtrl.serializeFragmentToXML(newLevelContent)+"</"+newLevelName+">";
docCtrl.delete(firstAthElem.getStartOffset(), Utils.getLastChild(parent).getEndOffset());
docCtrl.insertXMLFragment(newLevelXml, parent.getEndOffset()+1);
}
}