tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/java/com/google/scrollview/ui/SVWindow.java
Go to the documentation of this file.
00001 // Copyright 2007 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License"); You may not
00004 // use this file except in compliance with the License. You may obtain a copy of
00005 // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
00006 // applicable law or agreed to in writing, software distributed under the
00007 // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
00008 // OF ANY KIND, either express or implied. See the License for the specific
00009 // language governing permissions and limitations under the License.
00010 
00011 package com.google.scrollview.ui;
00012 
00013 import com.google.scrollview.ScrollView;
00014 import com.google.scrollview.events.SVEvent;
00015 import com.google.scrollview.events.SVEventHandler;
00016 import com.google.scrollview.events.SVEventType;
00017 import com.google.scrollview.ui.SVMenuBar;
00018 import com.google.scrollview.ui.SVPopupMenu;
00019 
00020 import org.piccolo2d.PCamera;
00021 import org.piccolo2d.PCanvas;
00022 import org.piccolo2d.PLayer;
00023 import org.piccolo2d.extras.swing.PScrollPane;
00024 import org.piccolo2d.nodes.PImage;
00025 import org.piccolo2d.nodes.PPath;
00026 import org.piccolo2d.nodes.PText;
00027 import org.piccolo2d.util.PPaintContext;
00028 
00029 import java.awt.BasicStroke;
00030 import java.awt.BorderLayout;
00031 import java.awt.Color;
00032 import java.awt.Font;
00033 import java.awt.GraphicsEnvironment;
00034 import java.awt.Rectangle;
00035 import java.awt.TextArea;
00036 import java.awt.geom.IllegalPathStateException;
00037 import java.util.regex.Matcher;
00038 import java.util.regex.Pattern;
00039 
00040 import javax.swing.JFrame;
00041 import javax.swing.JOptionPane;
00042 import javax.swing.SwingUtilities;
00043 import javax.swing.WindowConstants;
00044 
00052 public class SVWindow extends JFrame {
00056   private static final int MAX_WINDOW_X = 1000;
00057   private static final int MAX_WINDOW_Y = 800;
00058 
00059   /* Constant defining the (approx) height of the default message box*/
00060   private static final int DEF_MESSAGEBOX_HEIGHT = 200;
00061 
00063   public static final double SCALING_FACTOR = 2;
00064 
00066   PLayer layer;
00067 
00069   Color currentPenColor;
00070 
00075   Color currentBrushColor;
00076 
00079   Font currentFont;
00080 
00082   // This really needs to be a fixed width stroke as the basic stroke is
00083   // anti-aliased and gets too faint, but the piccolo fixed width stroke
00084   // is too buggy and generates missing initial moveto in path definition
00085   // errors with a IllegalPathStateException that cannot be caught because
00086   // it is in the automatic repaint function. If we can fix the exceptions
00087   // in piccolo, then we can use the following instead of BasicStroke:
00088   //   import edu.umd.cs.piccolox.util.PFixedWidthStroke;
00089   //   PFixedWidthStroke stroke = new PFixedWidthStroke(0.5f);
00090   // Instead we use the BasicStroke and turn off anti-aliasing.
00091   BasicStroke stroke = new BasicStroke(0.5f);
00092 
00097   public int hash;
00098 
00103   public static int nrWindows = 0;
00104 
00109   private SVEventHandler svEventHandler = null;
00110   private SVMenuBar svMenuBar = null;
00111   private TextArea ta = null;
00112   public SVPopupMenu svPuMenu = null;
00113   public PCanvas canvas;
00114   private int winSizeX;
00115   private int winSizeY;
00116 
00118   public void brush(int red, int green, int blue) {
00119     brush(red, green, blue, 255);
00120   }
00121 
00123   public void brush(int red, int green, int blue, int alpha) {
00124     // If alpha is zero, use a null brush to save rendering time.
00125     if (alpha == 0) {
00126       currentBrushColor = null;
00127     } else {
00128       currentBrushColor = new Color(red, green, blue, alpha);
00129     }
00130   }
00131 
00133   public void clear() {
00134     // Manipulation of Piccolo's scene graph should be done from Swings
00135     // event dispatch thread since Piccolo is not thread safe. This code calls
00136     // removeAllChildren() from that thread and releases the latch.
00137     final java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
00138     SwingUtilities.invokeLater(new Runnable() {
00139       public void run() {
00140         layer.removeAllChildren();
00141         repaint();
00142         latch.countDown();
00143       }
00144     });
00145     try {
00146       latch.await();
00147     } catch (InterruptedException e) {
00148     }
00149   }
00150 
00157   public void createPolyline(int length) {
00158     ScrollView.polylineXCoords = new float[length];
00159     ScrollView.polylineYCoords = new float[length];
00160     ScrollView.polylineSize = length;
00161     ScrollView.polylineScanned = 0;
00162   }
00163 
00167   public void drawPolyline() {
00168     int numCoords = ScrollView.polylineXCoords.length;
00169     if (numCoords < 2) {
00170       return;
00171     }
00172     PPath pn = PPath.createLine(ScrollView.polylineXCoords[0],
00173                                 ScrollView.polylineYCoords[0],
00174                                 ScrollView.polylineXCoords[1],
00175                                 ScrollView.polylineYCoords[1]);
00176     pn.reset();
00177     pn.moveTo(ScrollView.polylineXCoords[0], ScrollView.polylineYCoords[0]);
00178     for (int p = 1; p < numCoords; ++p) {
00179       pn.lineTo(ScrollView.polylineXCoords[p], ScrollView.polylineYCoords[p]);
00180     }
00181     pn.closePath();
00182     ScrollView.polylineSize = 0;
00183     pn.setStrokePaint(currentPenColor);
00184     pn.setPaint(null);  // Don't fill the polygon - this is just a polyline.
00185     pn.setStroke(stroke);
00186     layer.addChild(pn);
00187   }
00188 
00202   public SVWindow(String name, int hash, int posX, int posY, int sizeX,
00203                   int sizeY, int canvasSizeX, int canvasSizeY) {
00204     super(name);
00205 
00206     // Provide defaults for sizes.
00207     if (sizeX == 0) sizeX = canvasSizeX;
00208     if (sizeY == 0) sizeY = canvasSizeY;
00209     if (canvasSizeX == 0) canvasSizeX = sizeX;
00210     if (canvasSizeY == 0) canvasSizeY = sizeY;
00211 
00212     // Initialize variables
00213     nrWindows++;
00214     this.hash = hash;
00215     this.svEventHandler = new SVEventHandler(this);
00216     this.currentPenColor = Color.BLACK;
00217     this.currentBrushColor = Color.BLACK;
00218     this.currentFont = new Font("Times New Roman", Font.PLAIN, 12);
00219 
00220     // Determine the initial size and zoom factor of the window.
00221     // If the window is too big, rescale it and zoom out.
00222     int shrinkfactor = 1;
00223 
00224     if (sizeX > MAX_WINDOW_X) {
00225       shrinkfactor = (sizeX + MAX_WINDOW_X - 1) / MAX_WINDOW_X;
00226     }
00227     if (sizeY / shrinkfactor > MAX_WINDOW_Y) {
00228       shrinkfactor = (sizeY + MAX_WINDOW_Y - 1) / MAX_WINDOW_Y;
00229     }
00230     winSizeX = sizeX / shrinkfactor;
00231     winSizeY = sizeY / shrinkfactor;
00232     double initialScalingfactor = 1.0 / shrinkfactor;
00233     if (winSizeX > canvasSizeX || winSizeY > canvasSizeY) {
00234       initialScalingfactor = Math.min(1.0 * winSizeX / canvasSizeX,
00235                                       1.0 * winSizeY / canvasSizeY);
00236     }
00237 
00238     // Setup the actual window (its size, camera, title, etc.)
00239     if (canvas == null) {
00240       canvas = new PCanvas();
00241       getContentPane().add(canvas, BorderLayout.CENTER);
00242     }
00243 
00244     layer = canvas.getLayer();
00245     canvas.setBackground(Color.BLACK);
00246 
00247     // Disable anitaliasing to make the lines more visible.
00248     canvas.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING);
00249 
00250     setLayout(new BorderLayout());
00251 
00252     setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
00253 
00254     validate();
00255     canvas.requestFocus();
00256 
00257     // Manipulation of Piccolo's scene graph should be done from Swings
00258     // event dispatch thread since Piccolo is not thread safe. This code calls
00259     // initialize() from that thread once the PFrame is initialized, so you are
00260     // safe to start working with Piccolo in the initialize() method.
00261     SwingUtilities.invokeLater(new Runnable() {
00262       public void run() {
00263         repaint();
00264       }
00265     });
00266 
00267     setSize(winSizeX, winSizeY);
00268     setLocation(posX, posY);
00269     setTitle(name);
00270 
00271     // Add a Scrollpane to be able to scroll within the canvas
00272     PScrollPane scrollPane = new PScrollPane(canvas);
00273     getContentPane().add(scrollPane);
00274     scrollPane.setWheelScrollingEnabled(false);
00275     PCamera lc = canvas.getCamera();
00276     lc.scaleViewAboutPoint(initialScalingfactor, 0, 0);
00277 
00278     // Disable the default event handlers and add our own.
00279     addWindowListener(svEventHandler);
00280     canvas.removeInputEventListener(canvas.getPanEventHandler());
00281     canvas.removeInputEventListener(canvas.getZoomEventHandler());
00282     canvas.addInputEventListener(svEventHandler);
00283     canvas.addKeyListener(svEventHandler);
00284 
00285     // Make the window visible.
00286     validate();
00287     setVisible(true);
00288 
00289   }
00290 
00295   public void addMessageBox() {
00296     if (ta == null) {
00297       ta = new TextArea();
00298       ta.setEditable(false);
00299       getContentPane().add(ta, BorderLayout.SOUTH);
00300     }
00301     // We need to make the window bigger to accomodate the message box.
00302     winSizeY += DEF_MESSAGEBOX_HEIGHT;
00303     setSize(winSizeX, winSizeY);
00304   }
00305 
00311   public void setStrokeWidth(float width) {
00312     // If this worked we wouldn't need the antialiased rendering off.
00313     // stroke = new PFixedWidthStroke(width);
00314     stroke = new BasicStroke(width);
00315   }
00316 
00322   public void drawEllipse(int x, int y, int width, int height) {
00323     PPath pn = PPath.createEllipse(x, y, width, height);
00324     pn.setStrokePaint(currentPenColor);
00325     pn.setStroke(stroke);
00326     pn.setPaint(currentBrushColor);
00327     layer.addChild(pn);
00328   }
00329 
00335   public void drawImage(PImage img, int xPos, int yPos) {
00336     img.setX(xPos);
00337     img.setY(yPos);
00338     layer.addChild(img);
00339   }
00340 
00344   public void drawLine(int x1, int y1, int x2, int y2) {
00345     PPath pn = PPath.createLine(x1, y1, x2, y2);
00346     pn.setStrokePaint(currentPenColor);
00347     pn.setPaint(null);  // Null paint may render faster than the default.
00348     pn.setStroke(stroke);
00349     pn.moveTo(x1, y1);
00350     pn.lineTo(x2, y2);
00351     layer.addChild(pn);
00352   }
00353 
00359   public void drawRectangle(int x1, int y1, int x2, int y2) {
00360 
00361     if (x1 > x2) {
00362       int t = x1;
00363       x1 = x2;
00364       x2 = t;
00365     }
00366     if (y1 > y2) {
00367       int t = y1;
00368       y1 = y2;
00369       y2 = t;
00370     }
00371 
00372     PPath pn = PPath.createRectangle(x1, y1, x2 - x1, y2 - y1);
00373     pn.setStrokePaint(currentPenColor);
00374     pn.setStroke(stroke);
00375     pn.setPaint(currentBrushColor);
00376     layer.addChild(pn);
00377   }
00378 
00386   public void drawText(int x, int y, String text) {
00387     int unreadableCharAt = -1;
00388     char[] chars = text.toCharArray();
00389     PText pt = new PText(text);
00390     pt.setTextPaint(currentPenColor);
00391     pt.setFont(currentFont);
00392 
00393     // Check to see if every character can be displayed by the current font.
00394     for (int i = 0; i < chars.length; i++) {
00395       if (!currentFont.canDisplay(chars[i])) {
00396         // Set to the first not displayable character.
00397         unreadableCharAt = i;
00398         break;
00399       }
00400     }
00401 
00402     // Have to find some working font and use it for this text entry.
00403     if (unreadableCharAt != -1) {
00404       Font[] allfonts =
00405           GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
00406       for (int j = 0; j < allfonts.length; j++) {
00407         if (allfonts[j].canDisplay(chars[unreadableCharAt])) {
00408           Font tempFont =
00409               new Font(allfonts[j].getFontName(), currentFont.getStyle(),
00410                   currentFont.getSize());
00411           pt.setFont(tempFont);
00412           break;
00413         }
00414       }
00415     }
00416 
00417     pt.setX(x);
00418     pt.setY(y);
00419     layer.addChild(pt);
00420   }
00421 
00423   public void pen(int red, int green, int blue) {
00424     pen(red, green, blue, 255);
00425   }
00426 
00428   public void pen(int red, int green, int blue, int alpha) {
00429     currentPenColor = new Color(red, green, blue, alpha);
00430   }
00431 
00435   public void textAttributes(String font, int pixelSize, boolean bold,
00436       boolean italic, boolean underlined) {
00437 
00438     // For legacy reasons convert "Times" to "Times New Roman"
00439     if (font.equals("Times")) {
00440       font = "Times New Roman";
00441     }
00442 
00443     int style = Font.PLAIN;
00444     if (bold) {
00445       style += Font.BOLD;
00446     }
00447     if (italic) {
00448       style += Font.ITALIC;
00449     }
00450     currentFont = new Font(font, style, pixelSize);
00451   }
00452 
00457   public void zoomRectangle(int x1, int y1, int x2, int y2) {
00458     if (x2 > x1 && y2 > y1) {
00459       winSizeX = getWidth();
00460       winSizeY = getHeight();
00461       int width = x2 - x1;
00462       int height = y2 - y1;
00463       // Since piccolo doesn't do this well either, pad with a margin
00464       // all the way around.
00465       int wmargin = width / 2;
00466       int hmargin = height / 2;
00467       double scalefactor = Math.min(winSizeX / (2.0 * wmargin + width),
00468                                     winSizeY / (2.0 * hmargin + height));
00469       PCamera lc = canvas.getCamera();
00470       lc.scaleView(scalefactor / lc.getViewScale());
00471       lc.animateViewToPanToBounds(new Rectangle(x1 - hmargin, y1 - hmargin,
00472                                                 2 * wmargin + width,
00473                                                 2 * hmargin + height), 0);
00474     }
00475   }
00476 
00483   public void update() {
00484     // TODO(rays) fix bugs in piccolo or use something else.
00485     // The repaint function generates many
00486     // exceptions for no good reason. We catch and ignore as many as we
00487     // can here, but most of them are generated by the system repaints
00488     // caused by resizing/exposing parts of the window etc, and they
00489     // generate unwanted stack traces that have to be piped to /dev/null
00490     // (on linux).
00491     try {
00492       repaint();
00493     } catch (NullPointerException e) {
00494       // Do nothing so the output isn't full of stack traces.
00495     } catch (IllegalPathStateException e) {
00496       // Do nothing so the output isn't full of stack traces.
00497     }
00498   }
00499 
00501   public void addMenuBarItem(String parent, String name, int id,
00502                              boolean checked) {
00503     svMenuBar.add(parent, name, id, checked);
00504   }
00505 
00507   public void addMenuBarItem(String parent, String name) {
00508     addMenuBarItem(parent, name, -1);
00509   }
00510 
00512   public void addMenuBarItem(String parent, String name, int id) {
00513     if (svMenuBar == null) {
00514       svMenuBar = new SVMenuBar(this);
00515 
00516     }
00517     svMenuBar.add(parent, name, id);
00518   }
00519 
00521   public void addMessage(String message) {
00522     if (ta != null) {
00523       ta.append(message + "\n");
00524     } else {
00525       System.out.println(message + "\n");
00526     }
00527   }
00528 
00539   private static String convertIntegerStringToUnicodeString(String input) {
00540     StringBuffer sb = new StringBuffer(input);
00541     Pattern numbers = Pattern.compile("0x[0-9a-fA-F]{4}");
00542     Matcher matcher = numbers.matcher(sb);
00543 
00544     while (matcher.find()) {
00545       // Find the next match which resembles a hexadecimal value and convert it
00546       // to
00547       // its char value
00548       char a = (char) (Integer.decode(matcher.group()).intValue());
00549 
00550       // Replace the original with the new character
00551       sb.replace(matcher.start(), matcher.end(), String.valueOf(a));
00552 
00553       // Start again, since our positions have switched
00554       matcher.reset();
00555     }
00556     return sb.toString();
00557   }
00558 
00569   public void showInputDialog(String msg, String def, int id,
00570                               SVEventType evtype) {
00571     svEventHandler.timer.stop();
00572     String tmp =
00573         (String) JOptionPane.showInputDialog(this, msg, "",
00574             JOptionPane.QUESTION_MESSAGE, null, null, def);
00575 
00576     if (tmp != null) {
00577       tmp = convertIntegerStringToUnicodeString(tmp);
00578       SVEvent res = new SVEvent(evtype, this, id, tmp);
00579       ScrollView.addMessage(res);
00580     }
00581     svEventHandler.timer.restart();
00582   }
00583 
00584 
00591   public void showInputDialog(String msg) {
00592     showInputDialog(msg, null, -1, SVEventType.SVET_INPUT);
00593   }
00594 
00601   public void showYesNoDialog(String msg) {
00602     // res returns 0 on yes, 1 on no. Seems to be a bit counterintuitive
00603     int res =
00604         JOptionPane.showOptionDialog(this, msg, "", JOptionPane.YES_NO_OPTION,
00605             JOptionPane.QUESTION_MESSAGE, null, null, null);
00606     SVEvent e = null;
00607 
00608     if (res == 0) {
00609       e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0, "y");
00610     } else if (res == 1) {
00611       e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0, "n");
00612     }
00613     ScrollView.addMessage(e);
00614   }
00615 
00617   public void addPopupMenuItem(String parent, String name) {
00618     if (svPuMenu == null) {
00619       svPuMenu = new SVPopupMenu(this);
00620     }
00621     svPuMenu.add(parent, name, -1);
00622   }
00623 
00625   public void addPopupMenuItem(String parent, String name, int cmdEvent,
00626       String value, String desc) {
00627     if (svPuMenu == null) {
00628       svPuMenu = new SVPopupMenu(this);
00629     }
00630     svPuMenu.add(parent, name, cmdEvent, value, desc);
00631   }
00632 
00634   public void destroy() {
00635     ScrollView.addMessage(new SVEvent(SVEventType.SVET_DESTROY, this, 0,
00636         "SVET_DESTROY"));
00637     setVisible(false);
00638     // dispose();
00639   }
00640 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines