package at.ac.tuwien.dbai.pdfwrap.gui.layer; import at.ac.tuwien.dbai.pdfwrap.model.document.AttributeTuple; import at.ac.tuwien.dbai.pdfwrap.model.document.GenericSegment; import java.awt.*; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; /** * Combines a segment ({@link GenericSegment}) of the PDF analysis output with a {@link Style} object * that contains information about how to visualize the segment. * * @author Timo Schleicher * */ public class StyledSegment implements Comparable<StyledSegment> { // TODO: deal with XYTextComparator and sorting issues 2013-11-29 //Local coordinates considering the current scaling factors private float x, y; private float width, height; private GenericSegment segment; private Style style; private boolean isSelected; /** * The constructor of a styled Segment. * * @param segment The segment that will be enriched by styling information * @param style The information about styling */ public StyledSegment(GenericSegment segment, Style style) { this.segment = segment; this.style = style; //Default value indicating that the segment is not selected in the beginning this.isSelected = false; } /** * Calculates and updates the local coordinates with respect to the current * screen scaling factor. * * @param screenfactor The current screen scaling factor * @param pageWidth The width of the original PDF page * @param pageHeight The height of the original PDF page */ public void updateLocalCoordinates(float screenfactor, float pageWidth, float pageHeight) { screenfactor /= pageWidth; x = segment.getX1()*screenfactor; width = segment.getWidth()*screenfactor; y = (pageHeight - segment.getY2())*screenfactor; height = segment.getHeight()*screenfactor; } /** * Paint this segment by considering all the given style information. * * @param g2 The Graphics object on which the painting is done */ public void paintSegments(Graphics2D g2) { //Check whether the segment is printed or not if (!style.isPrintable()) { return; } //Check for selection and set color accordingly if (isSelected) { g2.setColor(new Color(255, 200, 50, 63)); g2.setStroke(new BasicStroke(2.0f)); } else { g2.setColor(style.getColor()); g2.setStroke(new BasicStroke(style.getStrokeWidth())); } //Check for the correct shape and draw the corresponding lines //New shapes should be handled here as well as in the enumeration -> Shapes switch (style.getShape()) { //Rectangle shape case rectangle: if (style.isfilled()) { g2.fill(new Rectangle2D.Float(x, y, width, height)); } else { g2.draw(new Rectangle2D.Float(x, y, width, height)); } break; //Line shape case line: g2.draw(new Line2D.Float(x, y, x+width, y+height)); break; //Add further shapes here! default: break; } } /** * Checks whether the point x,y lies within the segment or not. * * @param iX The x coordinate of the point * @param iY The y coordinate of the point * @return Returns true if the point lies within the segment, false otherwise */ public boolean intersects(int iX, int iY) { //If segment is not printed at all the user can't select it if (!style.isPrintable()) { return false; } //Set an offset value for lines in order to be able to select them properly int offSet = style.getShape() == Shapes.line ? 1 : 0; if ((iX >= x-offSet && iX <= x+width+offSet) && (iY >= y-offSet && iY <= y+height+offSet)) { return true; } return false; } /** * Checks whether the rectangular intersects the shape of the segment. * * @param rec The rectangular you want to check * @return Returns true if the rectangular intersects the shape of the segment, false otherwise */ public boolean intersects(Rectangle2D rec) { //If segment is not printed at all the user can't select it if (!style.isPrintable()) { return false; } //Make sure to check whether its a lined shape or a rectangular one return (style.getShape() == Shapes.line) ? rec.intersectsLine(x, y, x+width, y+height) : rec.intersects(x, y, width, height); } /** * Specifies the selection of the segment. * * @param selected sets the selection flag for this segment */ public void setSelected(boolean selected) { isSelected = selected; } /** * Checks whether this styled segment is visible or not. * * @return true if this segment is visible, false otherwise */ public boolean isVisible() { return style.isPrintable(); } @Override public String toString() { //Need this new toString method for easy displaying different segments if more than one is selected String ret = segment.tagName() + " - "; String text = null; String position = ","; for (AttributeTuple att : segment.getAttributes()) { if (att.getAttributeName().equals("text")) { text = att.getAttributeValue(); break; } else if (att.getAttributeName().equals("x1")) { position = "(" + att.getAttributeValue() + position; } else if (att.getAttributeName().equals("y1")) { position += att.getAttributeValue() + ")"; } } ret+= (text == null) ? position : text.split(" ")[0]; return ret; } /** * Getter method for the underlying segment. * * @return the underlying segment e.g. kind of a {@link GenericSegment} */ public GenericSegment getSegment() { return segment; } /** * Checks whether the class of this segment and the input segment is equal or not. * * @param seg the segment you want to compare the class with * @return true if the class of this segment and the input segment equals, false otherwise */ public boolean isClassEqual(StyledSegment seg) { return seg.getSegment().getClass().getCanonicalName().equals(segment.getClass().getCanonicalName()); } /** * Getter method for the local y coordinate. * * @return the local y coordinate regarding the current screen settings like window size etc. */ public float getLocalY() { return y; } /** * Getter method for the local x coordinate. * * @return the local x coordinate regarding the current screen settings like window size etc. */ public float getX() { return x; } @Override public int compareTo(StyledSegment seg) { //Use the natural appearance of a textual document to sort a segment //First sort from top to bottom (like one "line" after the other) if (y < seg.getLocalY()) { return -1; } else if (y > seg.getLocalY()) { return 1; } //Within a "line" sort from left to right if (x < seg.getX()) { return -1; } else if (x > seg.getX()) { return 1; } return 0; } }