public void decreaseIndent() {
    if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
      XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
      XMLTagPair pair =
          xhtmlCodeEditor.findSurroundingTags(new XHTMLCodeEditor.BlockTagInspector());
      if (pair != null) {
        logger.info("found xml block tag " + pair.getTagName());
        String tagAtttributes =
            xhtmlCodeEditor.getRange(pair.getOpenTagEnd(), pair.getTagAttributesEnd());

        Matcher regexMatcher = indentRegex.matcher(tagAtttributes);
        if (regexMatcher.find()) {
          String currentIndentStr = regexMatcher.group(2);
          int currentIndent = NumberUtils.toInt(currentIndentStr, 0);
          String currentUnit = regexMatcher.group(3);
          switch (currentUnit) {
            case "%":
            case "rem":
            case "em":
              currentIndent--;
              break;
            case "px":
              currentIndent = currentIndent - 10;
              break;
          }
          insertStyle("text-indent", currentIndent + currentUnit);
        } else {
          insertStyle("text-indent", "-1em");
        }
      }
    }
  }
 public boolean isInsertablePosition() {
   boolean result = false;
   if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
     XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
     XMLTagPair pair =
         xhtmlCodeEditor.findSurroundingTags(
             new XHTMLCodeEditor.TagInspector() {
               @Override
               public boolean isTagFound(EditorToken token) {
                 String type = token.getType();
                 if ("tag".equals(type)) {
                   String content = token.getContent();
                   if ("head".equals(content)
                       || "body".equals(content)
                       || "html".equals(content)) {
                     return true;
                   }
                 }
                 return false;
               }
             });
     result =
         !(pair == null
             || "head".equals(pair.getTagName())
             || "html".equals(pair.getTagName())
             || StringUtils.isEmpty(pair.getTagName()));
   }
   return result;
 }
  public void scrollTo(Deque<ElementPosition> nodeChain) {
    if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
      XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
      String code = xhtmlCodeEditor.getCode();
      /*            int index = code.indexOf(html);
      logger.info("index of clicked html " + index + " html: " + html);
      xhtmlCodeEditor.scrollTo(index);*/
      LocatedJDOMFactory factory = new LocatedJDOMFactory();
      try {
        org.jdom2.Document document = XHTMLUtils.parseXHTMLDocument(code, factory);
        org.jdom2.Element currentElement = document.getRootElement();
        ElementPosition currentElementPosition = nodeChain.pop();
        while (currentElementPosition != null) {
          IteratorIterable<org.jdom2.Element> children;
          if (StringUtils.isNotEmpty(currentElementPosition.getNamespaceUri())) {
            List<Namespace> namespaces = currentElement.getNamespacesInScope();
            Namespace currentNamespace = null;
            for (Namespace namespace : namespaces) {
              if (namespace.getURI().equals(currentElementPosition.getNamespaceUri())) {
                currentNamespace = namespace;
                break;
              }
            }
            Filter<org.jdom2.Element> filter =
                Filters.element(currentElementPosition.getNodeName(), currentNamespace);
            children = currentElement.getDescendants(filter);
          } else {
            Filter<org.jdom2.Element> filter =
                Filters.element(currentElementPosition.getNodeName());
            children = currentElement.getDescendants(filter);
          }

          int currentNumber = 0;
          for (org.jdom2.Element child : children) {
            if (currentNumber == currentElementPosition.getPosition()) {
              currentElement = child;
              break;
            }
            currentNumber++;
          }

          try {
            currentElementPosition = nodeChain.pop();
          } catch (NoSuchElementException e) {
            logger.info("no more element in node chain");
            currentElementPosition = null;
          }
        }

        LocatedElement locatedElement = (LocatedElement) currentElement;
        EditorPosition pos =
            new EditorPosition(locatedElement.getLine() - 1, locatedElement.getColumn());
        logger.info("pos for scrolling to is " + pos.toJson());
        xhtmlCodeEditor.scrollTo(pos);
      } catch (IOException | JDOMException e) {
        logger.error("", e);
      }
    }
  }
 public void refreshPreview() {
   XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
   if (xhtmlCodeEditor != null && currentXHTMLResource.get() != null) {
     try {
       currentXHTMLResource.get().setData(xhtmlCodeEditor.getCode().getBytes("UTF-8"));
     } catch (UnsupportedEncodingException e) {
       // never happens
     }
     needsRefresh.setValue(true);
     needsRefresh.setValue(false);
   }
 }
 public void surroundSelectionWithTag(String tagName) {
   if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
     XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
     EditorRange range = xhtmlCodeEditor.getSelection();
     xhtmlCodeEditor.replaceRange(
         "<" + tagName + ">" + range.getSelection() + "</" + tagName + ">",
         range.getFrom(),
         range.getTo());
     refreshPreview();
     xhtmlCodeEditor.requestFocus();
   }
 }
 public void surroundParagraphWithTag(String tagName) {
   if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
     XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
     XMLTagPair pair =
         xhtmlCodeEditor.findSurroundingTags(new XHTMLCodeEditor.BlockTagInspector());
     if (pair != null) {
       logger.info("found xml block tag " + pair.getTagName());
       // erst das schließende Tag ersetzen, da sich sonst die Koordinaten verschieben können
       xhtmlCodeEditor.replaceRange(tagName, pair.getCloseTagBegin(), pair.getCloseTagEnd());
       xhtmlCodeEditor.replaceRange(tagName, pair.getOpenTagBegin(), pair.getOpenTagEnd());
       refreshPreview();
     }
   }
 }
 public void insertStyle(String styleName, String value) {
   if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
     XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
     XMLTagPair pair =
         xhtmlCodeEditor.findSurroundingTags(new XHTMLCodeEditor.BlockTagInspector());
     if (pair != null) {
       logger.info("found xml block tag " + pair.getTagName());
       String tagAtttributes =
           xhtmlCodeEditor.getRange(pair.getOpenTagEnd(), pair.getTagAttributesEnd());
       if (tagAtttributes.contains(
           "style=")) // wenn bereits styles vorhanden, dann diese modifizieren
       {
         tagAtttributes =
             tagAtttributes.replaceAll(
                 "style\\s*=\\s*\"(.*)" + styleName + ":([^;]*)(;?)(.*)\\s*\"",
                 "style=\"$1" + styleName + ":" + value + "$3$4\"");
         xhtmlCodeEditor.replaceRange(
             tagAtttributes, pair.getOpenTagEnd(), pair.getTagAttributesEnd());
       } else {
         EditorPosition pos =
             new EditorPosition(
                 pair.getOpenTagBegin().getLine(),
                 pair.getOpenTagBegin().getColumn() + pair.getTagName().length());
         xhtmlCodeEditor.insertAt(" style=\"" + styleName + ":" + value + "\"", pos);
       }
       refreshPreview();
       xhtmlCodeEditor.requestFocus();
     }
   }
 }
  public boolean splitXHTMLFile() {
    boolean result = false;
    if (currentEditor.getValue().getMediaType().equals(MediaType.XHTML)) {
      XHTMLCodeEditor xhtmlCodeEditor = (XHTMLCodeEditor) currentEditor.getValue();
      EditorPosition pos = xhtmlCodeEditor.getEditorCursorPosition();
      XMLTagPair pair =
          xhtmlCodeEditor.findSurroundingTags(
              token -> {
                String type = token.getType();
                if ("tag".equals(type)) {
                  String content = token.getContent();
                  if ("head".equals(content) || "body".equals(content) || "html".equals(content)) {
                    return true;
                  }
                }
                return false;
              });
      if (pair == null
          || "head".equals(pair.getTagName())
          || "html".equals(pair.getTagName())
          || StringUtils.isEmpty(pair.getTagName())) {
        Dialogs.create()
            .owner(tabPane)
            .title("Teilung nicht möglich")
            .message(
                "Kann Datei nicht an dieser Position teilen. Eine Teilung ist nur innerhalb des XHTML-Bodys möglich.")
            .showWarning();
        return false;
      }
      logger.debug("umgebendes pair " + pair);
      // wir sind innerhalb des Body
      int index = xhtmlCodeEditor.getIndexFromPosition(pos);
      try {
        String originalCode = xhtmlCodeEditor.getCode();
        org.jdom2.Document originalDocument = XHTMLUtils.parseXHTMLDocument(originalCode);
        List<Content> originalHeadContent = getOriginalHeadContent(originalDocument);

        byte[] frontPart = originalCode.substring(0, index).getBytes("UTF-8");
        Resource oldResource = currentXHTMLResource.getValue();
        oldResource.setData(frontPart);
        HtmlCleanerBookProcessor processor = new HtmlCleanerBookProcessor();
        processor.processResource(oldResource);
        xhtmlCodeEditor.setCode(new String(oldResource.getData(), "UTF-8"));

        byte[] backPart =
            originalCode.substring(index, originalCode.length() - 1).getBytes("UTF-8");
        String fileName = book.getNextStandardFileName(MediaType.XHTML);
        Resource resource = MediaType.XHTML.getResourceFactory().createResource("Text/" + fileName);
        byte[] backPartXHTML = XHTMLUtils.repairWithHead(backPart, originalHeadContent);
        resource.setData(backPartXHTML);

        int spineIndex = book.getSpine().getResourceIndex(oldResource);
        book.addSpineResource(resource, spineIndex + 1);
        openFileInEditor(resource, MediaType.XHTML);

        bookBrowserManager.refreshBookBrowser();
        needsRefresh.setValue(true);
        needsRefresh.setValue(false);
      } catch (IOException | JDOMException | ResourceDataException e) {
        logger.error("", e);
        Dialogs.create()
            .owner(tabPane)
            .title("Teilung nicht möglich")
            .message("Kann Datei nicht teilen. Bitte Fehlermeldung an den Hersteller übermitteln.")
            .showException(e);
      }

      result = true;
    }
    return result;
  }