All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.lessvoid.nifty.html.NiftyVisitor Maven / Gradle / Ivy

Go to download

This module adds basic HTML support to Nifty. It creates Nifty elements from HTML directly. This is useful if you need to display messages or info boxes that contain more than simple elements.

There is a newer version: 1.4.3
Show newest version
package de.lessvoid.nifty.html;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.builder.ElementBuilder;
import de.lessvoid.nifty.builder.ImageBuilder;
import de.lessvoid.nifty.builder.PanelBuilder;
import de.lessvoid.nifty.spi.render.RenderFont;
import org.htmlparser.Tag;
import org.htmlparser.Text;
import org.htmlparser.util.Translate;
import org.htmlparser.visitors.NodeVisitor;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * A NodeVisitor for the HTML Parser project that will visit all HTML tags
 * and translate them into Nifty elements using the Nifty Builder pattern.
 * @author void
 */
public class NiftyVisitor extends NodeVisitor {
  // errors in processing are added to that list
  @Nonnull
  private final List errors = new ArrayList();

  // the PanelBuilder for the body tag
  private PanelBuilder bodyPanel;

  // helper class to create new builders
  private final NiftyBuilderFactory niftyBuilderFactory;

  // to allow nested block level elements later we must stack them
  @Nonnull
  private final Stack blockElementStack = new Stack();

  // the current block level element
  @Nullable
  private PanelBuilder currentBlockElement;

  // default font we use for generating text elements
  @Nullable
  private final String defaultFontName;
  private final String defaultFontBoldName;

  // current color
  @Nullable
  private String currentColor;

  // this will be set to a different font name when a corresponding tag is being processed
  @Nullable
  private String differentFont;

  // we collect all text nodes into this string buffer
  @Nonnull
  private final StringBuffer currentText = new StringBuffer();

  // table
  @Nullable
  private PanelBuilder table;

  // table row
  @Nullable
  private PanelBuilder tableRow;

  // table data
  @Nullable
  private PanelBuilder tableData;

  @Nonnull
  private String fontHeight;

  /**
   * Create the NiftyVisitor.
   * @param nifty the Nifty instance
   * @param niftyBuilderFactory a helper class to create Nifty Builders
   */
  public NiftyVisitor(@Nonnull final Nifty nifty, final NiftyBuilderFactory niftyBuilderFactory, @Nullable final String defaultFontName, final String defaultFontBoldName) {
    this.niftyBuilderFactory = niftyBuilderFactory;
    this.defaultFontName = defaultFontName;
    this.defaultFontBoldName = defaultFontBoldName;
    fontHeight = "0";
    if (defaultFontName != null) {
      RenderFont defaultFont = nifty.createFont(defaultFontName);
      if (defaultFont != null) {
        fontHeight = Integer.toString(defaultFont.getHeight());
      }
    }
  }

  /*
   * (non-Javadoc)
   * @see org.htmlparser.visitors.NodeVisitor#beginParsing()
   */
  @Override
  public void beginParsing () {
    errors.clear();
  }

  /*
   * (non-Javadoc)
   * @see org.htmlparser.visitors.NodeVisitor#visitTag(org.htmlparser.Tag)
   */
  @Override
  public void visitTag(@Nonnull final Tag tag) {
    try {
      if (isBody(tag)) {
        // we'll add a main panel for the body which will be the parent element for everything we generate
        // this way we can decide the childLayout and other properties of the body panel.
        bodyPanel = niftyBuilderFactory.createBodyPanelBuilder();
      } else if (isParagraph(tag)) {
        assertBodyPanelNotNull();
        currentBlockElement = niftyBuilderFactory.createParagraphPanelBuilder();
        blockElementStack.push(currentBlockElement);
      } else if (isImageTag(tag)) {
        ImageBuilder image = niftyBuilderFactory.createImageBuilder(
            tag.getAttribute("src"),
            tag.getAttribute("align"),
            tag.getAttribute("width"),
            tag.getAttribute("height"),
            tag.getAttribute("bgcolor"),
            tag.getAttribute("vspace"));
        if (currentBlockElement != null) {
          currentBlockElement.image(image);
        } else {
          bodyPanel.image(image);
        }
      } else if (isBreak(tag)) {
        if (currentBlockElement != null) {
          currentText.append("\n");
        } else {
          PanelBuilder breakPanelBuilder = niftyBuilderFactory.createBreakPanelBuilder(fontHeight);
          bodyPanel.panel(breakPanelBuilder);
        }
      } else if (isTableTag(tag)) {
        assertBodyPanelNotNull();
        table = niftyBuilderFactory.createTableTagPanelBuilder(
            tag.getAttribute("width"),
            tag.getAttribute("bgcolor"),
            tag.getAttribute("border"),
            tag.getAttribute("bordercolor"));
      } else if (isTableRowTag(tag)) {
        assertTableNotNull();
        tableRow = niftyBuilderFactory.createTableRowPanelBuilder(
            tag.getAttribute("width"),
            tag.getAttribute("bgcolor"),
            tag.getAttribute("border"),
            tag.getAttribute("bordercolor"));
      } else if (isTableDataTag(tag)) {
        assertTableRowNotNull();
        tableData = niftyBuilderFactory.createTableDataPanelBuilder(
            tag.getAttribute("width"),
            tag.getAttribute("bgcolor"),
            tag.getAttribute("border"),
            tag.getAttribute("bordercolor"));
      } else if (isFontTag(tag)) {
        String color = tag.getAttribute("color");
        if (color != null) {
          currentColor = color;
        }
      } else if (isStrongTag(tag)) {
        differentFont = defaultFontBoldName;
      }
    } catch (Exception e) {
      addError(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.htmlparser.visitors.NodeVisitor#visitEndTag(org.htmlparser.Tag)
   */
  @SuppressWarnings("StatementWithEmptyBody")
  @Override
  public void visitEndTag(@Nonnull final Tag tag) {
    try {
      if (isBody(tag)) {
        // currently there is nothing to do when a body tag ends
      } else if (isParagraph(tag)) {
        if (bodyPanel == null) {
          throw new Exception("This looks like HTML with a missing  tag");
        }
        if (currentBlockElement == null) {
          throw new Exception("This looks like broken HTML. currentBlockElement seems null. Maybe a duplicate close tag?");
        }

        String textElement = currentText.toString();
        if (textElement.length() > 0) {
          addTextElement(currentBlockElement, textElement);
          currentText.setLength(0);
        }

        if (currentBlockElement.getElementBuilders().isEmpty()) {
          currentBlockElement.height(fontHeight);
        }
        bodyPanel.panel(currentBlockElement);
        currentBlockElement = blockElementStack.pop();
        differentFont = null;
      } else if (isImageTag(tag)) {
        // nothing to do
      } else if (isBreak(tag)) {
        // nothing to do
      } else if (isTableTag(tag)) {
        if (bodyPanel == null || table == null) {
          throw new Exception("This looks like HTML with a missing  tag");
        }
        bodyPanel.panel(table);
        table = null;
      } else if (isTableRowTag(tag)) {
        if (table == null || tableRow == null) {
          throw new Exception("This looks like a  element with a missing  tag");
        }
        table.panel(tableRow);
        tableRow = null;
      } else if (isTableDataTag(tag)) {
        if (tableRow == null) {
          throw new Exception("This looks like a  tag");
        }
        if (tableData == null) {
          throw new Exception("This looks like a  tag");
        }

        addTextElement(tableData, currentText.toString());
        currentText.setLength(0);

        tableRow.panel(tableData);
        tableData = null;
        differentFont = null;
      } else if (isFontTag(tag)) {
        currentColor = null;
      }
    } catch (Exception e) {
      addError(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.htmlparser.visitors.NodeVisitor#visitStringNode(org.htmlparser.Text)
   */
  @Override
  public void visitStringNode(@Nonnull final Text textNode) {
    if (tableData != null) {
      appendText(textNode);
    } else if (currentBlockElement != null) {
      appendText(textNode);
    }
  }

  private void appendText(@Nonnull final Text textNode) {
    if (currentColor != null) {
      currentText.append("\\");
      currentText.append(currentColor);
      currentText.append("#");
    }
    currentText.append(removeNewLineAndTabs(translateHTMLEntities(textNode.getText())));
  }

  public ElementBuilder builder() throws Exception {
    try {
      assertBodyPanelNotNull();
    } catch (Exception e) {
      addAsFirstError(e);
    }

    assertNoErrors();
    return bodyPanel;
  }

  // private stuff

  private void addError(@Nonnull final Exception e) {
    if (!errors.contains(e.getMessage())) {
      errors.add(e.getMessage());
    }
  }

  private void addAsFirstError(@Nonnull final Exception e) {
    if (!errors.contains(e.getMessage())) {
      errors.add(0, e.getMessage());
    }
  }

  private void assertBodyPanelNotNull() throws Exception {
    if (bodyPanel == null) {
      throw new Exception("This looks like HTML with a missing  tag");
    }
  }

  private void assertTableNotNull() throws Exception {
    if (table == null) {
      throw new Exception("This looks like a  element with a missing 
element with a missing
element with a missing
tag"); } } private void assertTableRowNotNull() throws Exception { if (tableRow == null) { throw new Exception("This looks like a tag"); } } private void addTextElement(@Nonnull final PanelBuilder panelBuilder, @Nonnull final String text) { String font = defaultFontName; if (differentFont != null) { font = differentFont; } if (font == null) { return; } panelBuilder.text(niftyBuilderFactory.createTextBuilder(text, font, currentColor)); } private void assertNoErrors() throws Exception { if (!errors.isEmpty()) { StringBuilder message = new StringBuilder(); for (int i=0; i









element with a missing