package nota.oxygen.epub.headings; import java.util.List; import javax.swing.text.BadLocationException; import nota.oxygen.common.BaseAuthorOperation; 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.AuthorDocumentFragment; import ro.sync.ecss.extensions.api.node.AuthorElement; import ro.sync.ecss.extensions.api.node.AuthorNode; public class InsertHeadingOperation extends BaseAuthorOperation { private static String ARG_HEADER_FRAGMENT = "header fragment"; private String headerFragment; private static String ARG_PARENT_SECTION_XPATH = "parent section xpath"; private String parentSectionXPath; private static String ARG_HEADING_OPERATION_TYPE = "heading operation type"; private String headingOperationType; private static String SUBLEVEL_OPERATION_TYPE = "Sublevel"; private static String SAME_LEVEL_OPERATION_TYPE = "Same level"; private static String ARG_PREVIOUS_HEADING_XPATH = "previous heading xpath"; private String previousHeadingXPath; @Override public ArgumentDescriptor[] getArguments() { return new ArgumentDescriptor[]{ new ArgumentDescriptor(ARG_HEADER_FRAGMENT, ArgumentDescriptor.TYPE_FRAGMENT, "Header fragment"), new ArgumentDescriptor(ARG_PARENT_SECTION_XPATH, ArgumentDescriptor.TYPE_XPATH_EXPRESSION, "Parent section XPath"), new ArgumentDescriptor(ARG_HEADING_OPERATION_TYPE, ArgumentDescriptor.TYPE_CONSTANT_LIST, "Heading operation type", new String[] {SAME_LEVEL_OPERATION_TYPE, SUBLEVEL_OPERATION_TYPE}, "Same level"), new ArgumentDescriptor(ARG_PREVIOUS_HEADING_XPATH, ArgumentDescriptor.TYPE_XPATH_EXPRESSION, "Previous heading XPath") }; } @Override protected void parseArguments(ArgumentsMap args) throws IllegalArgumentException { headerFragment = (String)args.getArgumentValue(ARG_HEADER_FRAGMENT); parentSectionXPath = (String)args.getArgumentValue(ARG_PARENT_SECTION_XPATH); headingOperationType = (String)args.getArgumentValue(ARG_HEADING_OPERATION_TYPE); previousHeadingXPath = (String)args.getArgumentValue(ARG_PREVIOUS_HEADING_XPATH); } @Override public String getDescription() { return "Inserts a heading, with the side-effect of updating the ePub navigation documents"; } @Override protected void doOperation() throws AuthorOperationException { try { int selectionStartBefore = getAuthorAccess().getEditorAccess().getSelectionStart(); int selectionEndBefore = getAuthorAccess().getEditorAccess().getSelectionEnd(); int selectionOffset = 0; AuthorElement headingCandidate; try { headingCandidate = getCurrentElement(); } catch (BadLocationException e) { showMessage("No element is selected"); return; } AuthorElement parentSection = findElementByXPath(parentSectionXPath, headingCandidate); if (parentSection != headingCandidate.getParent()) { showMessage("The selected element is not a direct child of a section"); return; } try { if (findElementByXPath(previousHeadingXPath) == null) { showMessage("The selected element is before the heading of it's parent section"); return; } AuthorDocumentController ctrl = getAuthorAccess().getDocumentController(); ctrl.surroundInFragment( headerFragment, headingCandidate.getStartOffset()+1, headingCandidate.getEndOffset()-1); AuthorDocumentFragment headingFragment = ctrl.createDocumentFragment(headingCandidate.getContentNodes().get(0), true); int headingStartOffset = headingCandidate.getStartOffset(); ctrl.deleteNode(headingCandidate); ctrl.insertFragment(headingStartOffset, headingFragment); List<AuthorNode> nodes = parentSection.getContentNodes(); AuthorNode lastNode = nodes.get(nodes.size()-1); ctrl.surroundInFragment( String.format("<%s xmlns='%s'/>", parentSection.getLocalName(), parentSection.getNamespace()), headingStartOffset, lastNode.getEndOffset()); AuthorElement newSection = (AuthorElement)lastNode.getParent(); int offset = newSection.getStartOffset(); if (SAME_LEVEL_OPERATION_TYPE.equals(headingOperationType)) { AuthorDocumentFragment newSectionFragment = ctrl.createDocumentFragment(newSection, true); ctrl.deleteNode(newSection); offset = parentSection.getEndOffset()+1; ctrl.insertFragment(offset, newSectionFragment); selectionOffset = 2; } else if (SUBLEVEL_OPERATION_TYPE.equals(headingOperationType)) { selectionOffset = 1; } getAuthorAccess().getEditorAccess().select(selectionStartBefore+selectionOffset, selectionEndBefore+selectionOffset); } catch (BadLocationException e) { throw new AuthorOperationException( String.format("Unexpected BadLocationException while moving new level section: %s", e.getMessage()), e); } } catch (AuthorOperationException e) { throw e; } catch (Exception e) { throw new AuthorOperationException( String.format("An unexpected %s occured: %s", e.getClass().getName(), e.getMessage()), e); } } }