Example #1
0
  public void morph(Element element) throws DocumentValidationException {

    VEXDocument doc = this.getDocument();
    int offset = this.getCaretOffset();
    VEXElement currentElement = doc.getElementAt(offset);

    if (currentElement == doc.getRootElement()) {
      throw new DocumentValidationException("Cannot morph the root element.");
    }

    boolean success = false;
    try {
      this.beginWork();
      this.moveTo(currentElement.getStartOffset() + 1, false);
      this.moveTo(currentElement.getEndOffset(), true);
      VEXDocumentFragment frag = this.getSelectedFragment();
      this.deleteSelection();
      this.moveBy(-1, false);
      this.moveBy(2, true);
      this.deleteSelection();
      this.insertElement(element);
      if (frag != null) {
        this.insertFragment(frag);
      }
      this.moveTo(offset, false);
      success = true;
    } finally {
      this.endWork(success);
    }
  }
Example #2
0
  public boolean canUnwrap() {
    VEXDocument doc = this.getDocument();
    if (doc == null) {
      return false;
    }

    Validator validator = doc.getValidator();
    if (validator == null) {
      return false;
    }

    VEXElement element = doc.getElementAt(this.getCaretOffset());
    VEXElement parent = element.getParent();
    if (parent == null) {
      // can't unwrap the root
      return false;
    }

    EList<String> seq1 = doc.getNodeNames(parent.getStartOffset() + 1, element.getStartOffset());

    EList<String> seq2 = doc.getNodeNames(element.getStartOffset() + 1, element.getEndOffset());

    EList<String> seq3 = doc.getNodeNames(element.getEndOffset() + 1, parent.getEndOffset());

    return validator.isValidSequence(parent.getName(), seq1, seq2, seq3, true);
  }
Example #3
0
  public void deleteNextChar() throws DocumentValidationException {
    if (this.hasSelection()) {
      this.deleteSelection();
    } else {
      int offset = this.getCaretOffset();
      VEXDocument doc = this.getDocument();
      int n = doc.getLength() - 1;
      VEXElement element = doc.getElementAt(offset);

      if (offset == n) {
        // nop
      } else if (this.isBetweenMatchingElements(offset)) {
        this.joinElementsAt(offset);
      } else if (this.isBetweenMatchingElements(offset + 1)) {
        this.joinElementsAt(offset + 1);
      } else if (element.isEmpty()) {
        // deleting the right sentinel of an empty element
        // so just delete the whole element an move on
        this.moveTo(offset - 1, false);
        this.moveTo(offset + 1, true);
        this.deleteSelection();
      } else if (doc.getElementAt(offset + 1).isEmpty()) {
        // deleting the left sentinel of an empty element
        // so just delete the whole element an move on
        this.moveTo(offset + 2, true);
        this.deleteSelection();
      } else {
        if (doc.getCharacterAt(offset) != 0) {
          this.moveTo(offset, false);
          this.moveTo(offset + 1, true);
          this.deleteSelection();
        }
      }
    }
  }
Example #4
0
  /** Returns true if text can be inserted at the current position. */
  public boolean canInsertText() {

    VEXDocument doc = this.getDocument();
    if (doc == null) {
      return false;
    }

    Validator validator = this.document.getValidator();
    if (validator == null) {
      return true;
    }

    int startOffset = this.getCaretOffset();
    int endOffset = this.getCaretOffset();
    if (this.hasSelection()) {
      startOffset = this.getSelectionStart();
      endOffset = this.getSelectionEnd();
    }

    VEXElement parent = this.getDocument().getElementAt(startOffset);
    EList<String> seq1 = doc.getNodeNames(parent.getStartOffset() + 1, startOffset);

    EList<String> seq2 = new BasicEList<String>();
    seq2.add(Validator.PCDATA);

    EList<String> seq3 = doc.getNodeNames(endOffset, parent.getEndOffset());

    return validator.isValidSequence(parent.getName(), seq1, seq2, seq3, true);
  }
Example #5
0
  /**
   * Joins the elements at the given offset. Only works if isBetweenMatchingElements returns true
   * for the same offset. Afterwards, the caret is left at the point where the join occurred.
   *
   * @param offset Offset where the two elements meet.
   */
  private void joinElementsAt(int offset) throws DocumentValidationException {

    if (!isBetweenMatchingElements(offset)) {
      throw new DocumentValidationException("Cannot join elements at offset " + offset);
    }

    boolean success = false;
    try {
      this.beginWork();
      this.moveTo(offset + 1);
      VEXElement element = this.getCurrentElement();
      boolean moveContent = !element.isEmpty();
      VEXDocumentFragment frag = null;
      if (moveContent) {
        this.moveTo(element.getEndOffset(), true);
        frag = this.getSelectedFragment();
        this.deleteSelection();
      }
      this.moveBy(-1);
      this.moveBy(2, true);
      this.deleteSelection();
      this.moveBy(-1);
      if (moveContent) {
        int savedOffset = this.getCaretOffset();
        this.insertFragment(frag);
        this.moveTo(savedOffset, false);
      }
      success = true;
    } finally {
      this.endWork(success);
    }
  }
Example #6
0
  /**
   * Returns the start offset of the next sibling of the parent element. Returns -1 if there is no
   * previous sibling in the parent.
   *
   * @param vexWidget VexWidget to use.
   */
  public static int getPreviousSiblingStart(IVexWidget vexWidget) {
    int startOffset;

    if (vexWidget.hasSelection()) {
      startOffset = vexWidget.getSelectionStart();
    } else {
      Box box =
          vexWidget.findInnermostBox(
              new IBoxFilter() {
                public boolean matches(Box box) {
                  return box instanceof BlockBox && box.getElement() != null;
                }
              });

      if (box.getElement() == vexWidget.getDocument().getRootElement()) {
        return -1;
      }

      startOffset = box.getElement().getStartOffset();
    }

    int previousSiblingStart = -1;
    VEXElement parent = vexWidget.getDocument().getElementAt(startOffset);
    List<VEXNode> children = parent.getChildNodes();
    for (VEXNode child : children) {
      if (startOffset == child.getStartOffset()) {
        break;
      }
      previousSiblingStart = child.getStartOffset();
    }
    return previousSiblingStart;
  }
Example #7
0
 public void removeAttribute(String attributeName) {
   try {
     VEXElement element = this.getCurrentElement();
     if (element.getAttribute(attributeName) != null) {
       element.removeAttribute(attributeName);
     }
   } catch (DocumentValidationException ex) {
     ex.printStackTrace(); // TODO: when can this happen?
   }
 }
Example #8
0
  public void split() throws DocumentValidationException {

    long start = System.currentTimeMillis();

    VEXDocument doc = this.getDocument();
    VEXElement element = doc.getElementAt(this.getCaretOffset());
    Styles styles = this.getStyleSheet().getStyles(element);
    while (!styles.isBlock()) {
      element = element.getParent();
      styles = this.getStyleSheet().getStyles(element);
    }

    boolean success = false;
    try {
      this.beginWork();
      if (styles.getWhiteSpace().equals(CSS.PRE)) {
        // can't call this.insertText() or we'll get an infinite loop
        int offset = this.getCaretOffset();
        doc.insertText(offset, "\n");
        this.moveTo(offset + 1);
      } else {
        VEXDocumentFragment frag = null;
        int offset = this.getCaretOffset();
        boolean atEnd = (offset == element.getEndOffset());
        if (!atEnd) {
          this.moveTo(element.getEndOffset(), true);
          frag = this.getSelectedFragment();
          this.deleteSelection();
        }

        // either way, we are now at the end offset for the element
        // let's move just outside
        this.moveTo(this.getCaretOffset() + 1);

        this.insertElement(new Element(element.getName()));
        // TODO: clone attributes

        if (!atEnd) {
          offset = this.getCaretOffset();
          this.insertFragment(frag);
          this.moveTo(offset, false);
        }
      }
      success = true;
    } finally {
      this.endWork(success);
    }

    if (this.isDebugging()) {
      long end = System.currentTimeMillis();
      System.out.println("split() took " + (end - start) + "ms");
    }
  }
Example #9
0
 public void setAttribute(String attributeName, String value) {
   try {
     VEXElement element = this.getCurrentElement();
     if (value == null) {
       this.removeAttribute(attributeName);
     } else if (!value.equals(element.getAttribute(attributeName))) {
       element.setAttribute(attributeName, value);
     }
   } catch (DocumentValidationException ex) {
     ex.printStackTrace(); // TODO: mebbe throw the exception instead
   }
 }
Example #10
0
  public String[] getValidInsertElements() {

    VEXDocument doc = this.getDocument();
    if (doc == null) return new String[0];

    Validator validator = doc.getValidator();
    if (validator == null) return new String[0];

    int startOffset = this.getCaretOffset();
    int endOffset = this.getCaretOffset();
    if (this.hasSelection()) {
      startOffset = this.getSelectionStart();
      endOffset = this.getSelectionEnd();
    }

    VEXElement parent = doc.getElementAt(startOffset);

    Set<String> validItems = validator.getValidItems(parent.getName());
    List<String> candidates = new ArrayList<String>(validItems);
    candidates.remove(Validator.PCDATA);

    // filter invalid sequences
    EList<String> nodesBefore = doc.getNodeNames(parent.getStartOffset() + 1, startOffset);
    EList<String> nodesAfter = doc.getNodeNames(endOffset, parent.getEndOffset());
    int sequenceLength = nodesBefore.size() + 1 + nodesAfter.size();
    for (Iterator<String> iter = candidates.iterator(); iter.hasNext(); ) {
      String candidate = iter.next();
      EList<String> sequence = new BasicEList<String>(sequenceLength);
      sequence.addAll(nodesBefore);
      sequence.add(candidate);
      sequence.addAll(nodesAfter);
      if (!validator.isValidSequence(parent.getName(), sequence, true)) {
        iter.remove();
      }
    }

    // If there's a selection, root out those candidates that can't
    // contain it.
    if (hasSelection()) {
      EList<String> selectedNodes = doc.getNodeNames(startOffset, endOffset);

      for (Iterator<String> iter = candidates.iterator(); iter.hasNext(); ) {
        String candidate = iter.next();
        if (!validator.isValidSequence(candidate, selectedNodes, true)) {
          iter.remove();
        }
      }
    }

    Collections.sort(candidates);
    return (String[]) candidates.toArray(new String[candidates.size()]);
  }
Example #11
0
  /**
   * Iterate over all rows in the table containing the caret.
   *
   * @param vexWidget IVexWidget to iterate over.
   * @param callback Caller-provided callback that this method calls for each row in the current
   *     table.
   */
  public static void iterateTableRows(IVexWidget vexWidget, ElementOrRangeCallback callback) {

    final StyleSheet ss = vexWidget.getStyleSheet();
    final VEXDocument doc = vexWidget.getDocument();
    final int offset = vexWidget.getCaretOffset();

    // This may or may not be a table
    // In any case, it's the element that contains the top-level table
    // children
    VEXElement table = doc.getElementAt(offset);

    while (table != null && !LayoutUtils.isTableChild(ss, table)) {
      table = table.getParent();
    }

    while (table != null && LayoutUtils.isTableChild(ss, table)) {
      table = table.getParent();
    }

    if (table == null || table.getParent() == null) {
      return;
    }

    final List<Element> tableChildren = new ArrayList<Element>();
    final boolean[] found = new boolean[] {false};
    LayoutUtils.iterateChildrenByDisplayStyle(
        ss,
        LayoutUtils.TABLE_CHILD_STYLES,
        table,
        new ElementOrRangeCallback() {
          public void onElement(Element child, String displayStyle) {
            if (offset >= child.getStartOffset() && offset <= child.getEndOffset()) {
              found[0] = true;
            }
            tableChildren.add(child);
          }

          public void onRange(VEXElement parent, int startOffset, int endOffset) {
            if (!found[0]) {
              tableChildren.clear();
            }
          }
        });

    if (!found[0]) {
      return;
    }

    int startOffset = tableChildren.get(0).getStartOffset();
    int endOffset = tableChildren.get(tableChildren.size() - 1).getEndOffset() + 1;
    LayoutUtils.iterateTableRows(ss, table, startOffset, endOffset, callback);
  }
Example #12
0
  /**
   * Returns the innermost Element with style table-row containing the caret, or null if no such
   * element exists.
   *
   * @param vexWidget IVexWidget to use.
   */
  public static VEXElement getCurrentTableRow(IVexWidget vexWidget) {

    StyleSheet ss = vexWidget.getStyleSheet();
    VEXElement element = vexWidget.getCurrentElement();

    while (element != null) {
      if (ss.getStyles(element).getDisplay().equals(CSS.TABLE_ROW)) {
        return element;
      }
      element = element.getParent();
    }

    return null;
  }
Example #13
0
  public String[] getValidMorphElements() {

    VEXDocument doc = this.getDocument();
    if (doc == null) return new String[0];

    Validator validator = doc.getValidator();
    if (validator == null) return new String[0];

    VEXElement element = doc.getElementAt(this.getCaretOffset());
    VEXElement parent = element.getParent();
    if (parent == null) {
      // can't morph the root
      return new String[0];
    }

    Set<String> validItems = validator.getValidItems(parent.getName());
    List<String> result = new ArrayList<String>(validItems);
    result.remove(Validator.PCDATA);
    result.remove(element.getName()); // exclude converting to the same

    // root out those that can't contain the current content
    EList<String> content = doc.getNodeNames(element.getStartOffset() + 1, element.getEndOffset());

    for (Iterator<String> iter = result.iterator(); iter.hasNext(); ) {
      String candidate = iter.next();
      if (!validator.isValidSequence(candidate, content, true)) {
        iter.remove();
      }
    }

    Collections.sort(result);
    return result.toArray(new String[result.size()]);
  }
Example #14
0
 /**
  * Returns true if the given offset represents the boundary between two different elements with
  * the same name and parent. This is used to determine if the elements can be joined via
  * joinElementsAt.
  *
  * @param int offset The offset to check.
  */
 private boolean isBetweenMatchingElements(int offset) {
   if (offset <= 1 || offset >= this.getDocument().getLength() - 1) {
     return false;
   }
   VEXElement e1 = this.getDocument().getElementAt(offset - 1);
   VEXElement e2 = this.getDocument().getElementAt(offset + 1);
   return e1 != e2 && e1.getParent() == e2.getParent() && e1.getName().equals(e2.getName());
 }
Example #15
0
 public void testSetElementName() throws Exception {
   VEXElement element = getFixture();
   element.setName("book");
   assertEquals("Element name not set", "book", element.getName());
 }
Example #16
0
 /**
  * Tests the '{@link
  * org.eclipse.wst.xml.vex.core.internal.provisional.dom.I.VEXElement#setNamespace(java.lang.String,
  * java.lang.String) <em>Set Namespace</em>}' operation.
  * <!-- begin-user-doc -->
  * <!-- end-user-doc -->
  *
  * @see
  *     org.eclipse.wst.xml.vex.core.internal.provisional.dom.I.VEXElement#setNamespace(java.lang.String,
  *     java.lang.String)
  * @generated
  */
 public void testSetNamespace__String_String() {
   VEXElement element = getFixture();
   element.setNamespace("docbook", "http://www.docbook.org/");
   assertEquals("Prefix wrong:", "docbook", element.getNamespacePrefix());
   assertEquals("Namespace wrong:", "http://www.docbook.org/", element.getNamespaceURI());
 }
Example #17
0
  public void moveTo(int offset, boolean select) {

    if (offset >= 1 && offset <= this.document.getLength() - 1) {

      // repaint the selection area, if any
      this.repaintCaret();
      this.repaintRange(this.getSelectionStart(), this.getSelectionEnd());

      VEXElement oldElement = this.currentElement;

      this.caretOffset = offset;

      this.currentElement = this.document.getElementAt(offset);

      if (select) {
        this.selectionStart = Math.min(this.mark, this.caretOffset);
        this.selectionEnd = Math.max(this.mark, this.caretOffset);

        // move selectionStart and selectionEnd to make sure we don't
        // select a partial element
        VEXElement commonElement =
            this.document.findCommonElement(this.selectionStart, this.selectionEnd);

        VEXElement element = this.document.getElementAt(this.selectionStart);
        while (element != commonElement) {
          this.selectionStart = element.getStartOffset();
          element = this.document.getElementAt(this.selectionStart);
        }

        element = this.document.getElementAt(this.selectionEnd);
        while (element != commonElement) {
          this.selectionEnd = element.getEndOffset() + 1;
          element = this.document.getElementAt(this.selectionEnd);
        }

      } else {
        this.mark = offset;
        this.selectionStart = offset;
        this.selectionEnd = offset;
      }

      if (this.beginWorkCount == 0) {
        this.relayout();
      }

      Graphics g = this.hostComponent.createDefaultGraphics();
      LayoutContext context = this.createLayoutContext(g);
      this.caret = this.rootBox.getCaret(context, offset);

      VEXElement element = this.getCurrentElement();
      if (element != oldElement) {
        this.caretColor = Color.BLACK;
        while (element != null) {
          Color bgColor = this.styleSheet.getStyles(element).getBackgroundColor();
          if (bgColor != null) {
            int red = ~bgColor.getRed() & 0xff;
            int green = ~bgColor.getGreen() & 0xff;
            int blue = ~bgColor.getBlue() & 0xff;
            this.caretColor = new Color(red, green, blue);
            break;
          }
          element = element.getParent();
        }
      }

      g.dispose();

      this.magicX = -1;

      this.scrollCaretVisible();

      this.hostComponent.fireSelectionChanged();

      this.caretVisible = true;

      this.repaintRange(this.getSelectionStart(), this.getSelectionEnd());
    }
  }