Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SVWindow.java
Go to the documentation of this file.
1 // Copyright 2007 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); You may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
6 // applicable law or agreed to in writing, software distributed under the
7 // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
8 // OF ANY KIND, either express or implied. See the License for the specific
9 // language governing permissions and limitations under the License.
10
11 package com.google.scrollview.ui;
12
13 import com.google.scrollview.ScrollView;
14 import com.google.scrollview.events.SVEvent;
15 import com.google.scrollview.events.SVEventHandler;
16 import com.google.scrollview.events.SVEventType;
17 import com.google.scrollview.ui.SVImageHandler;
18 import com.google.scrollview.ui.SVMenuBar;
19 import com.google.scrollview.ui.SVPopupMenu;
20
21 import edu.umd.cs.piccolo.PCamera;
22 import edu.umd.cs.piccolo.PCanvas;
23 import edu.umd.cs.piccolo.PLayer;
24
25 import edu.umd.cs.piccolo.nodes.PImage;
26 import edu.umd.cs.piccolo.nodes.PPath;
27 import edu.umd.cs.piccolo.nodes.PText;
28 import edu.umd.cs.piccolo.util.PPaintContext;
29 import edu.umd.cs.piccolox.swing.PScrollPane;
30
31 import java.awt.BasicStroke;
32 import java.awt.BorderLayout;
33 import java.awt.Color;
34 import java.awt.Font;
35 import java.awt.GraphicsEnvironment;
36 import java.awt.geom.IllegalPathStateException;
37 import java.awt.Rectangle;
38 import java.awt.TextArea;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41
42 import javax.swing.JFrame;
43 import javax.swing.JOptionPane;
44 import javax.swing.SwingUtilities;
45 import javax.swing.WindowConstants;
46
54 public class SVWindow extends JFrame {
58 private static final int MAX_WINDOW_X = 1000;
59 private static final int MAX_WINDOW_Y = 800;
60
61 /* Constant defining the (approx) height of the default message box*/
62 private static final int DEF_MESSAGEBOX_HEIGHT = 200;
63
65 public static final double SCALING_FACTOR = 2;
66
68 PLayer layer;
69
71 Color currentPenColor;
72
77 Color currentBrushColor;
78
81 Font currentFont;
82
84 // This really needs to be a fixed width stroke as the basic stroke is
85 // anti-aliased and gets too faint, but the piccolo fixed width stroke
86 // is too buggy and generates missing initial moveto in path definition
87 // errors with a IllegalPathStateException that cannot be caught because
88 // it is in the automatic repaint function. If we can fix the exceptions
89 // in piccolo, then we can use the following instead of BasicStroke:
90 // import edu.umd.cs.piccolox.util.PFixedWidthStroke;
91 // PFixedWidthStroke stroke = new PFixedWidthStroke(0.5f);
92 // Instead we use the BasicStroke and turn off anti-aliasing.
93 BasicStroke stroke = new BasicStroke(0.5f);
94
99 public int hash;
100
105 public static int nrWindows = 0;
106
111 private SVEventHandler svEventHandler = null;
112 private SVMenuBar svMenuBar = null;
113 private TextArea ta = null;
114 public SVPopupMenu svPuMenu = null;
115 public PCanvas canvas;
116 private int winSizeX;
117 private int winSizeY;
118
120 public void brush(int red, int green, int blue) {
121 brush(red, green, blue, 255);
122 }
123
125 public void brush(int red, int green, int blue, int alpha) {
126 // If alpha is zero, use a null brush to save rendering time.
127 if (alpha == 0) {
128 currentBrushColor = null;
129 } else {
130 currentBrushColor = new Color(red, green, blue, alpha);
131 }
132 }
133
135 public void clear() {
136 layer.removeAllChildren();
137 }
138
149 public void createImage(String internalName, int width, int height,
150 int bitsPerPixel) {
151 SVImageHandler.createImage(internalName, width, height, bitsPerPixel);
152 }
153
160 public void createPolyline(int length) {
161 ScrollView.polylineXCoords = new float[length];
162 ScrollView.polylineYCoords = new float[length];
163 ScrollView.polylineSize = length;
164 ScrollView.polylineScanned = 0;
165 }
166
170 public void drawPolyline() {
171 PPath pn = PPath.createPolyline(ScrollView.polylineXCoords,
172 ScrollView.polylineYCoords);
173 ScrollView.polylineSize = 0;
174 pn.setStrokePaint(currentPenColor);
175 pn.setPaint(null); // Don't fill the polygon - this is just a polyline.
176 pn.setStroke(stroke);
177 layer.addChild(pn);
178 }
179
193 public SVWindow(String name, int hash, int posX, int posY, int sizeX,
194 int sizeY, int canvasSizeX, int canvasSizeY) {
195 super(name);
196
197 // Provide defaults for sizes.
198 if (sizeX == 0) sizeX = canvasSizeX;
199 if (sizeY == 0) sizeY = canvasSizeY;
200 if (canvasSizeX == 0) canvasSizeX = sizeX;
201 if (canvasSizeY == 0) canvasSizeY = sizeY;
202
203 // Initialize variables
204 nrWindows++;
205 this.hash = hash;
206 this.svEventHandler = new SVEventHandler(this);
207 this.currentPenColor = Color.BLACK;
208 this.currentBrushColor = Color.BLACK;
209 this.currentFont = new Font("Times New Roman", Font.PLAIN, 12);
210
211 // Determine the initial size and zoom factor of the window.
212 // If the window is too big, rescale it and zoom out.
213 int shrinkfactor = 1;
214
215 if (sizeX > MAX_WINDOW_X) {
216 shrinkfactor = (sizeX + MAX_WINDOW_X - 1) / MAX_WINDOW_X;
217 }
218 if (sizeY / shrinkfactor > MAX_WINDOW_Y) {
219 shrinkfactor = (sizeY + MAX_WINDOW_Y - 1) / MAX_WINDOW_Y;
220 }
221 winSizeX = sizeX / shrinkfactor;
222 winSizeY = sizeY / shrinkfactor;
223 double initialScalingfactor = 1.0 / shrinkfactor;
224 if (winSizeX > canvasSizeX || winSizeY > canvasSizeY) {
225 initialScalingfactor = Math.min(1.0 * winSizeX / canvasSizeX,
226 1.0 * winSizeY / canvasSizeY);
227 }
228
229 // Setup the actual window (its size, camera, title, etc.)
230 if (canvas == null) {
231 canvas = new PCanvas();
232 getContentPane().add(canvas, BorderLayout.CENTER);
233 }
234
235 layer = canvas.getLayer();
236 canvas.setBackground(Color.BLACK);
237
238 // Disable anitaliasing to make the lines more visible.
239 canvas.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING);
240
241 setLayout(new BorderLayout());
242
243 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
244
245 validate();
246 canvas.requestFocus();
247
248 // Manipulation of Piccolo's scene graph should be done from Swings
249 // event dispatch thread since Piccolo is not thread safe. This code calls
250 // initialize() from that thread once the PFrame is initialized, so you are
251 // safe to start working with Piccolo in the initialize() method.
252 SwingUtilities.invokeLater(new Runnable() {
253 public void run() {
254 repaint();
255 }
256 });
257
258 setSize(winSizeX, winSizeY);
259 setLocation(posX, posY);
260 setTitle(name);
261
262 // Add a Scrollpane to be able to scroll within the canvas
263 PScrollPane scrollPane = new PScrollPane(canvas);
264 getContentPane().add(scrollPane);
265 scrollPane.setWheelScrollingEnabled(false);
266 PCamera lc = canvas.getCamera();
267 lc.scaleViewAboutPoint(initialScalingfactor, 0, 0);
268
269 // Disable the default event handlers and add our own.
270 addWindowListener(svEventHandler);
271 canvas.removeInputEventListener(canvas.getPanEventHandler());
272 canvas.removeInputEventListener(canvas.getZoomEventHandler());
273 canvas.addInputEventListener(svEventHandler);
274 canvas.addKeyListener(svEventHandler);
275
276 // Make the window visible.
277 validate();
278 setVisible(true);
279
280 }
281
286 public void addMessageBox() {
287 if (ta == null) {
288 ta = new TextArea();
289 ta.setEditable(false);
290 getContentPane().add(ta, BorderLayout.SOUTH);
291 }
292 // We need to make the window bigger to accomodate the message box.
293 winSizeY += DEF_MESSAGEBOX_HEIGHT;
294 setSize(winSizeX, winSizeY);
295 }
296
302 public void setStrokeWidth(float width) {
303 // If this worked we wouldn't need the antialiased rendering off.
304 // stroke = new PFixedWidthStroke(width);
305 stroke = new BasicStroke(width);
306 }
307
313 public void drawEllipse(int x, int y, int width, int height) {
314 PPath pn = PPath.createEllipse(x, y, width, height);
315 pn.setStrokePaint(currentPenColor);
316 pn.setStroke(stroke);
317 pn.setPaint(currentBrushColor);
318 layer.addChild(pn);
319 }
320
326 public void drawImage(String internalName, int x_pos, int y_pos) {
327 PImage img = SVImageHandler.getImage(internalName);
328 img.setX(x_pos);
329 img.setY(y_pos);
330 layer.addChild(img);
331 }
332
336 public void drawLine(int x1, int y1, int x2, int y2) {
337 PPath pn = PPath.createLine(x1, y1, x2, y2);
338 pn.setStrokePaint(currentPenColor);
339 pn.setPaint(null); // Null paint may render faster than the default.
340 pn.setStroke(stroke);
341 pn.moveTo(x1, y1);
342 pn.lineTo(x2, y2);
343 layer.addChild(pn);
344 }
345
351 public void drawRectangle(int x1, int y1, int x2, int y2) {
352
353 if (x1 > x2) {
354 int t = x1;
355 x1 = x2;
356 x2 = t;
357 }
358 if (y1 > y2) {
359 int t = y1;
360 y1 = y2;
361 y2 = t;
362 }
363
364 PPath pn = PPath.createRectangle(x1, y1, x2 - x1, y2 - y1);
365 pn.setStrokePaint(currentPenColor);
366 pn.setStroke(stroke);
367 pn.setPaint(currentBrushColor);
368 layer.addChild(pn);
369 }
370
378 public void drawText(int x, int y, String text) {
379 int unreadableCharAt = -1;
380 char[] chars = text.toCharArray();
381 PText pt = new PText(text);
382 pt.setTextPaint(currentPenColor);
383 pt.setFont(currentFont);
384
385 // Check to see if every character can be displayed by the current font.
386 for (int i = 0; i < chars.length; i++) {
387 if (!currentFont.canDisplay(chars[i])) {
388 // Set to the first not displayable character.
389 unreadableCharAt = i;
390 break;
391 }
392 }
393
394 // Have to find some working font and use it for this text entry.
395 if (unreadableCharAt != -1) {
396 Font[] allfonts =
397 GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
398 for (int j = 0; j < allfonts.length; j++) {
399 if (allfonts[j].canDisplay(chars[unreadableCharAt])) {
400 Font tempFont =
401 new Font(allfonts[j].getFontName(), currentFont.getStyle(),
402 currentFont.getSize());
403 pt.setFont(tempFont);
404 break;
405 }
406 }
407 }
408
409 pt.setX(x);
410 pt.setY(y);
411 layer.addChild(pt);
412 }
413
415 public void pen(int red, int green, int blue) {
416 pen(red, green, blue, 255);
417 }
418
420 public void pen(int red, int green, int blue, int alpha) {
421 currentPenColor = new Color(red, green, blue, alpha);
422 }
423
427 public void textAttributes(String font, int pixelSize, boolean bold,
428 boolean italic, boolean underlined) {
429
430 // For legacy reasons convert "Times" to "Times New Roman"
431 if (font.equals("Times")) {
432 font = "Times New Roman";
433 }
434
435 int style = Font.PLAIN;
436 if (bold) {
437 style += Font.BOLD;
438 }
439 if (italic) {
440 style += Font.ITALIC;
441 }
442 currentFont = new Font(font, style, pixelSize);
443 }
444
449 public void zoomRectangle(int x1, int y1, int x2, int y2) {
450 if (x2 > x1 && y2 > y1) {
451 winSizeX = getWidth();
452 winSizeY = getHeight();
453 int width = x2 - x1;
454 int height = y2 - y1;
455 // Since piccolo doesn't do this well either, pad with a margin
456 // all the way around.
457 int wmargin = width / 2;
458 int hmargin = height / 2;
459 double scalefactor = Math.min(winSizeX / (2.0 * wmargin + width),
460 winSizeY / (2.0 * hmargin + height));
461 PCamera lc = canvas.getCamera();
462 lc.scaleView(scalefactor / lc.getViewScale());
463 lc.animateViewToPanToBounds(new Rectangle(x1 - hmargin, y1 - hmargin,
464 2 * wmargin + width,
465 2 * hmargin + height), 0);
466 }
467 }
468
475 public void update() {
476 // TODO(rays) fix bugs in piccolo or use something else.
477 // The repaint function generates many
478 // exceptions for no good reason. We catch and ignore as many as we
479 // can here, but most of them are generated by the system repaints
480 // caused by resizing/exposing parts of the window etc, and they
481 // generate unwanted stack traces that have to be piped to /dev/null
482 // (on linux).
483 try {
484 repaint();
485 } catch (NullPointerException e) {
486 // Do nothing so the output isn't full of stack traces.
487 } catch (IllegalPathStateException e) {
488 // Do nothing so the output isn't full of stack traces.
489 }
490 }
491
493 public void addMenuBarItem(String parent, String name, int id,
494 boolean checked) {
495 svMenuBar.add(parent, name, id, checked);
496 }
497
499 public void addMenuBarItem(String parent, String name) {
500 addMenuBarItem(parent, name, -1);
501 }
502
504 public void addMenuBarItem(String parent, String name, int id) {
505 if (svMenuBar == null) {
506 svMenuBar = new SVMenuBar(this);
507
508 }
509 svMenuBar.add(parent, name, id);
510 }
511
513 public void addMessage(String message) {
514 if (ta != null) {
515 ta.append(message + "\n");
516 } else {
517 System.out.println(message + "\n");
518 }
519 }
520
531 private static String convertIntegerStringToUnicodeString(String input) {
532 StringBuffer sb = new StringBuffer(input);
533 Pattern numbers = Pattern.compile("0x[0-9a-fA-F]{4}");
534 Matcher matcher = numbers.matcher(sb);
535
536 while (matcher.find()) {
537 // Find the next match which resembles a hexadecimal value and convert it
538 // to
539 // its char value
540 char a = (char) (Integer.decode(matcher.group()).intValue());
541
542 // Replace the original with the new character
543 sb.replace(matcher.start(), matcher.end(), String.valueOf(a));
544
545 // Start again, since our positions have switched
546 matcher.reset();
547 }
548 return sb.toString();
549 }
550
561 public void showInputDialog(String msg, String def, int id,
562 SVEventType evtype) {
563 svEventHandler.timer.stop();
564 String tmp =
565 (String) JOptionPane.showInputDialog(this, msg, "",
566 JOptionPane.QUESTION_MESSAGE, null, null, def);
567
568 if (tmp != null) {
569 tmp = convertIntegerStringToUnicodeString(tmp);
570 SVEvent res = new SVEvent(evtype, this, id, tmp);
571 ScrollView.addMessage(res);
572 }
573 svEventHandler.timer.restart();
574 }
575
576
583 public void showInputDialog(String msg) {
584 showInputDialog(msg, null, -1, SVEventType.SVET_INPUT);
585 }
586
593 public void showYesNoDialog(String msg) {
594 // res returns 0 on yes, 1 on no. Seems to be a bit counterintuitive
595 int res =
596 JOptionPane.showOptionDialog(this, msg, "", JOptionPane.YES_NO_OPTION,
597 JOptionPane.QUESTION_MESSAGE, null, null, null);
598 SVEvent e = null;
599
600 if (res == 0) {
601 e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0, "y");
602 } else if (res == 1) {
603 e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0, "n");
604 }
605 ScrollView.addMessage(e);
606 }
607
609 public void addPopupMenuItem(String parent, String name) {
610 if (svPuMenu == null) {
611 svPuMenu = new SVPopupMenu(this);
612 }
613 svPuMenu.add(parent, name, -1);
614 }
615
617 public void addPopupMenuItem(String parent, String name, int cmdEvent,
618 String value, String desc) {
619 if (svPuMenu == null) {
620 svPuMenu = new SVPopupMenu(this);
621 }
622 svPuMenu.add(parent, name, cmdEvent, value, desc);
623 }
624
626 public void destroy() {
627 ScrollView.addMessage(new SVEvent(SVEventType.SVET_DESTROY, this, 0,
628 "SVET_DESTROY"));
629 setVisible(false);
630 // dispose();
631 }
632
639 public void openImage(String filename) {
640 SVImageHandler.openImage(filename);
641 }
642
643 }