package bd.amazed.docscissors.view; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import org.rr.commons.log.LoggerFactory; import org.rr.commons.mufs.IResourceHandler; import bd.amazed.docscissors.doc.DocumentInfo; import bd.amazed.docscissors.doc.JDocumentDecoderPanel; import bd.amazed.docscissors.model.ModelListener; import bd.amazed.docscissors.model.PageGroup; import bd.amazed.docscissors.model.RectChangeListener; /** * * @author Gagan */ public class DocPanel extends JDocumentDecoderPanel implements ModelListener, RectChangeListener, UIHandlerListener { protected UIHandler uiHandler; public DocPanel(UIHandler uiHandler) { super(); this.uiHandler = uiHandler; MouseHandler handler = new MouseHandler(); addMouseListener(handler); addMouseMotionListener(handler); } private void debug(String string) { LoggerFactory.getLogger(DocPanel.class).log(Level.INFO, string); } @Override public void paintComponent(Graphics g) { if (uiHandler.isShowMergedMode()) { Image image = getImage(); if (image != null) { g.drawImage(image, 0, 0, this); } else { g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(Color.black); String text = "No stacked view. View individual pages using the bottom toolbar."; int textWidth = g.getFontMetrics().stringWidth(text); int textHeight = g.getFontMetrics().getHeight(); g.setColor(Color.black); g.drawString(text, (getWidth() - textWidth)/2, (getHeight() - textHeight)/2); } } else { super.paintComponent(g); } Rectangle clipRect = g.getClipBounds(); Iterator<Rect> iter = uiHandler.getRectIterator(); while (iter.hasNext()) { (iter.next()).draw(g, clipRect); } // whole page area g.setColor(Color.BLACK); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); } private Image getImage() { Image image = null; if(uiHandler.getCurrentPageGroup() != null) image = uiHandler.getCurrentPageGroup().getStackImage(); return image; } private void updateSize() { Image image = getImage(); if (image != null) { int width = image.getWidth(this); int height = image.getHeight(this); debug("Setting pdf size : " + width + "x" + height); setPreferredSize(new Dimension(width, height)); setSize(new Dimension(width, height)); } invalidate(); repaint(); } @Override public void newDocLoaded(DocumentInfo pdfFile) { try { super.openPdfFile(pdfFile); super.decodePage(uiHandler.getPage()); invalidate(); } catch (Exception e) { LoggerFactory.getLogger(this).log(Level.WARNING, "Loading pdf " + pdfFile + " failed", e); e.printStackTrace(); } } @Override public void docLoadFailed(IResourceHandler failedFile, Throwable cause) { // nothing to do } @Override public void zoomChanged(double oldZoomFactor, double newZoomFactor) { updateSize(); } @Override public void clipboardCopy(boolean isCut, Rect onClipboard) { } @Override public void clipboardPaste(boolean isCut, Rect onClipboard) { if (onClipboard != null) { try { Rect cloned = (Rect) onClipboard.clone(); cloned.translate(5, 5, getWidth(), getHeight()); // a little to right bottom, so that user can see there // is a new one on top if (isCut) { uiHandler.delete(onClipboard); } uiHandler.addRect(cloned); uiHandler.setSelectedRect(cloned); } catch (CloneNotSupportedException e) { e.printStackTrace(); } // we dont modify the old } } @Override public void rectUpdated(Rect rect, Rectangle repaintArea) { if (repaintArea != null) { repaint(repaintArea); } else { repaint(); } } protected Rect getRectAt(Point pt) { ArrayList<Rect> allRects = uiHandler.getAllRects(); for (int i = allRects.size() - 1; i >= 0; i--) { Rect r = (Rect) allRects.get(i); if (r.inside(pt)) return r; } return null; } public void updateCursor() { if (uiHandler.getEditingMode() == UIHandler.EDIT_MODE_DRAW) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { setCursor(Cursor.getDefaultCursor()); } } @Override public void editingModeChanged(int newMode) { updateCursor(); repaint(); } @Override public void pageChanged(int index) { } @Override public void pageGroupChanged(List<PageGroup> pageGroups) { } @Override public void pageGroupSelected(PageGroup pageGroup) { repaint(); } @Override public void rectsStateChanged() { } protected class MouseHandler extends MouseAdapter implements MouseMotionListener { private Point dragAnchor; // variables using to track state during drag operations private int dragStatus; private static final int DRAG_NONE = 0; private static final int DRAG_CREATE = 1; private static final int DRAG_RESIZE = 2; private static final int DRAG_MOVE = 3; /** * When the mouse is pressed we need to figure out what action to take. If the tool mode is arrow, the click * might be a select, move or reisze. If the tool mode is one of the rects, the click initiates creation of a * new rect. */ public void mousePressed(MouseEvent event) { Rect clicked = null; Point curPt = event.getPoint(); if (uiHandler.getEditingMode() == UIHandler.EDIT_MODE_SELECT) { // first, determine if click was on resize knob of selected rect if (uiHandler.getSelectedRect() != null && (dragAnchor = uiHandler.getSelectedRect().getAnchorForResize(curPt)) != null) { dragStatus = DRAG_RESIZE; // drag will resize this rect } else if ((clicked = getRectAt(curPt)) != null) { // if not check if any rect was clicked uiHandler.setSelectedRect(clicked); dragStatus = DRAG_MOVE; // drag will move this rect dragAnchor = curPt; } else { // else this was a click in empty area, deselect // selected rect, uiHandler.setSelectedRect(null); dragStatus = DRAG_NONE; // drag does nothing in this case } } else { Rect newRect = new Rect(curPt, uiHandler); // create rect here newRect.addListener(DocPanel.this); uiHandler.addRect(newRect); uiHandler.setSelectedRect(newRect); dragStatus = DRAG_CREATE; // drag will create (resize) this rect dragAnchor = curPt; } } /** * As the mouse is dragged, our listener will receive periodic updates as mouseDragged events. When we get an * update position, we update the move/resize event that is in progress. */ public void mouseDragged(MouseEvent event) { Point pointer = event.getPoint(); switch (dragStatus) { case DRAG_MOVE: uiHandler.getSelectedRect().translate(pointer.x - dragAnchor.x, pointer.y - dragAnchor.y, getWidth(), getHeight()); uiHandler.notifyRectsStateChanged(); dragAnchor = pointer; // update for next dragged event break; case DRAG_CREATE: case DRAG_RESIZE: uiHandler.getSelectedRect().resize(dragAnchor, pointer, getWidth(), getHeight()); uiHandler.notifyRectsStateChanged(); break; } } @Override public void mouseMoved(MouseEvent event) { Point pointer = event.getPoint(); if (uiHandler.getEditingMode() == UIHandler.EDIT_MODE_SELECT) { // select mode if (getRectAt(pointer) != null) { // move setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else if (uiHandler.getSelectedRect() != null) { // resize int whichCornerbox = uiHandler.getSelectedRect().getCornerboxContainingPoint(pointer); if (whichCornerbox != Rect.CORNER_NONE) { switch (whichCornerbox) { case Rect.CORNER_TOP_LEFT: setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); break; case Rect.CORNER_TOP_RIGHT: setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)); break; case Rect.CORNER_BOTTOM_LEFT: setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)); break; case Rect.CORNER_BUTTOM_RIGHT: setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)); break; } } else { setCursor(Cursor.getDefaultCursor()); } } else {// normal setCursor(Cursor.getDefaultCursor()); } } else if (uiHandler.getEditingMode() == UIHandler.EDIT_MODE_DRAW) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { setCursor(Cursor.getDefaultCursor()); } } @Override public void mouseReleased(MouseEvent e) { Rect selectedRect = uiHandler.getSelectedRect(); if (selectedRect != null && selectedRect.bounds != null && (selectedRect.bounds.getWidth() <= 0 || selectedRect.bounds.getHeight() <= 10)) { // TOO // small, we dont add those uiHandler.deleteSelected(); } if (uiHandler.getEditingMode() == UIHandler.EDIT_MODE_DRAW) { uiHandler.setEditingMode(UIHandler.EDIT_MODE_SELECT); } } @Override public void mouseEntered(MouseEvent e) { super.mouseEntered(e); updateCursor(); } @Override public void mouseExited(MouseEvent e) { super.mouseExited(e); setCursor(Cursor.getDefaultCursor()); } } }