Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/java/com/google/scrollview/ui/SVWindow.java @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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.SVMenuBar; | |
| 18 import com.google.scrollview.ui.SVPopupMenu; | |
| 19 | |
| 20 import org.piccolo2d.PCamera; | |
| 21 import org.piccolo2d.PCanvas; | |
| 22 import org.piccolo2d.PLayer; | |
| 23 import org.piccolo2d.extras.swing.PScrollPane; | |
| 24 import org.piccolo2d.nodes.PImage; | |
| 25 import org.piccolo2d.nodes.PPath; | |
| 26 import org.piccolo2d.nodes.PText; | |
| 27 import org.piccolo2d.util.PPaintContext; | |
| 28 | |
| 29 import java.awt.BasicStroke; | |
| 30 import java.awt.BorderLayout; | |
| 31 import java.awt.Color; | |
| 32 import java.awt.Font; | |
| 33 import java.awt.GraphicsEnvironment; | |
| 34 import java.awt.Rectangle; | |
| 35 import java.awt.TextArea; | |
| 36 import java.awt.geom.IllegalPathStateException; | |
| 37 import java.util.regex.Matcher; | |
| 38 import java.util.regex.Pattern; | |
| 39 | |
| 40 import javax.swing.JFrame; | |
| 41 import javax.swing.JOptionPane; | |
| 42 import javax.swing.SwingUtilities; | |
| 43 import javax.swing.WindowConstants; | |
| 44 | |
| 45 /** | |
| 46 * The SVWindow is the top-level ui class. It should get instantiated whenever | |
| 47 * the user intends to create a new window. It contains helper functions to draw | |
| 48 * on the canvas, add new menu items, show modal dialogs etc. | |
| 49 * | |
| 50 * @author wanke@google.com | |
| 51 */ | |
| 52 public class SVWindow extends JFrame { | |
| 53 /** | |
| 54 * Constants defining the maximum initial size of the window. | |
| 55 */ | |
| 56 private static final int MAX_WINDOW_X = 1000; | |
| 57 private static final int MAX_WINDOW_Y = 800; | |
| 58 | |
| 59 /* Constant defining the (approx) height of the default message box*/ | |
| 60 private static final int DEF_MESSAGEBOX_HEIGHT = 200; | |
| 61 | |
| 62 /** Constant defining the "speed" at which to zoom in and out. */ | |
| 63 public static final double SCALING_FACTOR = 2; | |
| 64 | |
| 65 /** The top level layer we add our PNodes to (root node). */ | |
| 66 PLayer layer; | |
| 67 | |
| 68 /** The current color of the pen. It is used to draw edges, text, etc. */ | |
| 69 Color currentPenColor; | |
| 70 | |
| 71 /** | |
| 72 * The current color of the brush. It is used to draw the interior of | |
| 73 * primitives. | |
| 74 */ | |
| 75 Color currentBrushColor; | |
| 76 | |
| 77 /** The system name of the current font we are using (e.g. | |
| 78 * "Times New Roman"). */ | |
| 79 Font currentFont; | |
| 80 | |
| 81 /** The stroke width to be used. */ | |
| 82 // This really needs to be a fixed width stroke as the basic stroke is | |
| 83 // anti-aliased and gets too faint, but the piccolo fixed width stroke | |
| 84 // is too buggy and generates missing initial moveto in path definition | |
| 85 // errors with an IllegalPathStateException that cannot be caught because | |
| 86 // it is in the automatic repaint function. If we can fix the exceptions | |
| 87 // in piccolo, then we can use the following instead of BasicStroke: | |
| 88 // import edu.umd.cs.piccolox.util.PFixedWidthStroke; | |
| 89 // PFixedWidthStroke stroke = new PFixedWidthStroke(0.5f); | |
| 90 // Instead we use the BasicStroke and turn off anti-aliasing. | |
| 91 BasicStroke stroke = new BasicStroke(0.5f); | |
| 92 | |
| 93 /** | |
| 94 * A unique representation for the window, also known by the client. It is | |
| 95 * used when sending messages from server to client to identify him. | |
| 96 */ | |
| 97 public int hash; | |
| 98 | |
| 99 /** | |
| 100 * The total number of created Windows. If this ever reaches 0 (apart from the | |
| 101 * beginning), quit the server. | |
| 102 */ | |
| 103 public static int nrWindows = 0; | |
| 104 | |
| 105 /** | |
| 106 * The Canvas, MessageBox, EventHandler, Menubar and Popupmenu associated with | |
| 107 * this window. | |
| 108 */ | |
| 109 private SVEventHandler svEventHandler = null; | |
| 110 private SVMenuBar svMenuBar = null; | |
| 111 private TextArea ta = null; | |
| 112 public SVPopupMenu svPuMenu = null; | |
| 113 public PCanvas canvas; | |
| 114 private int winSizeX; | |
| 115 private int winSizeY; | |
| 116 | |
| 117 /** Set the brush to an RGB color */ | |
| 118 public void brush(int red, int green, int blue) { | |
| 119 brush(red, green, blue, 255); | |
| 120 } | |
| 121 | |
| 122 /** Set the brush to an RGBA color */ | |
| 123 public void brush(int red, int green, int blue, int alpha) { | |
| 124 // If alpha is zero, use a null brush to save rendering time. | |
| 125 if (alpha == 0) { | |
| 126 currentBrushColor = null; | |
| 127 } else { | |
| 128 currentBrushColor = new Color(red, green, blue, alpha); | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 /** Erase all content from the window, but do not destroy it. */ | |
| 133 public void clear() { | |
| 134 // Manipulation of Piccolo's scene graph should be done from Swings | |
| 135 // event dispatch thread since Piccolo is not thread safe. This code calls | |
| 136 // removeAllChildren() from that thread and releases the latch. | |
| 137 final java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1); | |
| 138 SwingUtilities.invokeLater(new Runnable() { | |
| 139 public void run() { | |
| 140 layer.removeAllChildren(); | |
| 141 repaint(); | |
| 142 latch.countDown(); | |
| 143 } | |
| 144 }); | |
| 145 try { | |
| 146 latch.await(); | |
| 147 } catch (InterruptedException e) { | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 /** | |
| 152 * Start setting up a new polyline. The server will now expect | |
| 153 * polyline data until the polyline is complete. | |
| 154 * | |
| 155 * @param length number of coordinate pairs | |
| 156 */ | |
| 157 public void createPolyline(int length) { | |
| 158 ScrollView.polylineXCoords = new float[length]; | |
| 159 ScrollView.polylineYCoords = new float[length]; | |
| 160 ScrollView.polylineSize = length; | |
| 161 ScrollView.polylineScanned = 0; | |
| 162 } | |
| 163 | |
| 164 /** | |
| 165 * Draw the now complete polyline. | |
| 166 */ | |
| 167 public void drawPolyline() { | |
| 168 int numCoords = ScrollView.polylineXCoords.length; | |
| 169 if (numCoords < 2) { | |
| 170 return; | |
| 171 } | |
| 172 PPath pn = PPath.createLine(ScrollView.polylineXCoords[0], | |
| 173 ScrollView.polylineYCoords[0], | |
| 174 ScrollView.polylineXCoords[1], | |
| 175 ScrollView.polylineYCoords[1]); | |
| 176 pn.reset(); | |
| 177 pn.moveTo(ScrollView.polylineXCoords[0], ScrollView.polylineYCoords[0]); | |
| 178 for (int p = 1; p < numCoords; ++p) { | |
| 179 pn.lineTo(ScrollView.polylineXCoords[p], ScrollView.polylineYCoords[p]); | |
| 180 } | |
| 181 pn.closePath(); | |
| 182 ScrollView.polylineSize = 0; | |
| 183 pn.setStrokePaint(currentPenColor); | |
| 184 pn.setPaint(null); // Don't fill the polygon - this is just a polyline. | |
| 185 pn.setStroke(stroke); | |
| 186 layer.addChild(pn); | |
| 187 } | |
| 188 | |
| 189 /** | |
| 190 * Construct a new SVWindow and set it visible. | |
| 191 * | |
| 192 * @param name Title of the window. | |
| 193 * @param hash Unique internal representation. This has to be the same as | |
| 194 * defined by the client, as they use this to refer to the windows. | |
| 195 * @param posX X position of where to draw the window (upper left). | |
| 196 * @param posY Y position of where to draw the window (upper left). | |
| 197 * @param sizeX The width of the window. | |
| 198 * @param sizeY The height of the window. | |
| 199 * @param canvasSizeX The canvas width of the window. | |
| 200 * @param canvasSizeY The canvas height of the window. | |
| 201 */ | |
| 202 public SVWindow(String name, int hash, int posX, int posY, int sizeX, | |
| 203 int sizeY, int canvasSizeX, int canvasSizeY) { | |
| 204 super(name); | |
| 205 | |
| 206 // Provide defaults for sizes. | |
| 207 if (sizeX <= 0) sizeX = canvasSizeX; | |
| 208 if (sizeY <= 0) sizeY = canvasSizeY; | |
| 209 if (canvasSizeX <= 0) canvasSizeX = sizeX; | |
| 210 if (canvasSizeY <= 0) canvasSizeY = sizeY; | |
| 211 | |
| 212 // Avoid later division by zero. | |
| 213 if (sizeX <= 0) { | |
| 214 sizeX = 1; | |
| 215 canvasSizeX = sizeX; | |
| 216 } | |
| 217 if (sizeY <= 0) { | |
| 218 sizeY = 1; | |
| 219 canvasSizeY = sizeY; | |
| 220 } | |
| 221 | |
| 222 // Initialize variables | |
| 223 nrWindows++; | |
| 224 this.hash = hash; | |
| 225 this.svEventHandler = new SVEventHandler(this); | |
| 226 this.currentPenColor = Color.BLACK; | |
| 227 this.currentBrushColor = Color.BLACK; | |
| 228 this.currentFont = new Font("Times New Roman", Font.PLAIN, 12); | |
| 229 | |
| 230 // Determine the initial size and zoom factor of the window. | |
| 231 // If the window is too big, rescale it and zoom out. | |
| 232 int shrinkfactor = 1; | |
| 233 | |
| 234 if (sizeX > MAX_WINDOW_X) { | |
| 235 shrinkfactor = (sizeX + MAX_WINDOW_X - 1) / MAX_WINDOW_X; | |
| 236 } | |
| 237 if (sizeY / shrinkfactor > MAX_WINDOW_Y) { | |
| 238 shrinkfactor = (sizeY + MAX_WINDOW_Y - 1) / MAX_WINDOW_Y; | |
| 239 } | |
| 240 winSizeX = sizeX / shrinkfactor; | |
| 241 winSizeY = sizeY / shrinkfactor; | |
| 242 double initialScalingfactor = 1.0 / shrinkfactor; | |
| 243 if (winSizeX > canvasSizeX || winSizeY > canvasSizeY) { | |
| 244 initialScalingfactor = Math.min(1.0 * winSizeX / canvasSizeX, | |
| 245 1.0 * winSizeY / canvasSizeY); | |
| 246 } | |
| 247 | |
| 248 // Setup the actual window (its size, camera, title, etc.) | |
| 249 if (canvas == null) { | |
| 250 canvas = new PCanvas(); | |
| 251 getContentPane().add(canvas, BorderLayout.CENTER); | |
| 252 } | |
| 253 | |
| 254 layer = canvas.getLayer(); | |
| 255 canvas.setBackground(Color.BLACK); | |
| 256 | |
| 257 // Disable antialiasing to make the lines more visible. | |
| 258 canvas.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); | |
| 259 | |
| 260 setLayout(new BorderLayout()); | |
| 261 | |
| 262 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); | |
| 263 | |
| 264 validate(); | |
| 265 canvas.requestFocus(); | |
| 266 | |
| 267 // Manipulation of Piccolo's scene graph should be done from Swings | |
| 268 // event dispatch thread since Piccolo is not thread safe. This code calls | |
| 269 // initialize() from that thread once the PFrame is initialized, so you are | |
| 270 // safe to start working with Piccolo in the initialize() method. | |
| 271 SwingUtilities.invokeLater(new Runnable() { | |
| 272 public void run() { | |
| 273 repaint(); | |
| 274 } | |
| 275 }); | |
| 276 | |
| 277 setSize(winSizeX, winSizeY); | |
| 278 setLocation(posX, posY); | |
| 279 setTitle(name); | |
| 280 | |
| 281 // Add a Scrollpane to be able to scroll within the canvas | |
| 282 PScrollPane scrollPane = new PScrollPane(canvas); | |
| 283 getContentPane().add(scrollPane); | |
| 284 scrollPane.setWheelScrollingEnabled(false); | |
| 285 PCamera lc = canvas.getCamera(); | |
| 286 lc.scaleViewAboutPoint(initialScalingfactor, 0, 0); | |
| 287 | |
| 288 // Disable the default event handlers and add our own. | |
| 289 addWindowListener(svEventHandler); | |
| 290 canvas.removeInputEventListener(canvas.getPanEventHandler()); | |
| 291 canvas.removeInputEventListener(canvas.getZoomEventHandler()); | |
| 292 canvas.addInputEventListener(svEventHandler); | |
| 293 canvas.addKeyListener(svEventHandler); | |
| 294 | |
| 295 // Make the window visible. | |
| 296 validate(); | |
| 297 setVisible(true); | |
| 298 | |
| 299 } | |
| 300 | |
| 301 /** | |
| 302 * Convenience function to add a message box to the window which can be used | |
| 303 * to output debug information. | |
| 304 */ | |
| 305 public void addMessageBox() { | |
| 306 if (ta == null) { | |
| 307 ta = new TextArea(); | |
| 308 ta.setEditable(false); | |
| 309 getContentPane().add(ta, BorderLayout.SOUTH); | |
| 310 } | |
| 311 // We need to make the window bigger to accommodate the message box. | |
| 312 winSizeY += DEF_MESSAGEBOX_HEIGHT; | |
| 313 setSize(winSizeX, winSizeY); | |
| 314 } | |
| 315 | |
| 316 /** | |
| 317 * Allows you to specify the thickness with which to draw lines, recantgles | |
| 318 * and ellipses. | |
| 319 * @param width The new thickness. | |
| 320 */ | |
| 321 public void setStrokeWidth(float width) { | |
| 322 // If this worked we wouldn't need the antialiased rendering off. | |
| 323 // stroke = new PFixedWidthStroke(width); | |
| 324 stroke = new BasicStroke(width); | |
| 325 } | |
| 326 | |
| 327 /** | |
| 328 * Draw an ellipse at (x,y) with given width and height, using the | |
| 329 * current stroke, the current brush color to fill it and the | |
| 330 * current pen color for the outline. | |
| 331 */ | |
| 332 public void drawEllipse(int x, int y, int width, int height) { | |
| 333 PPath pn = PPath.createEllipse(x, y, width, height); | |
| 334 pn.setStrokePaint(currentPenColor); | |
| 335 pn.setStroke(stroke); | |
| 336 pn.setPaint(currentBrushColor); | |
| 337 layer.addChild(pn); | |
| 338 } | |
| 339 | |
| 340 /** | |
| 341 * Draw the image with the given name at (x,y). Any image loaded stays in | |
| 342 * memory, so if you intend to redraw an image, you do not have to use | |
| 343 * createImage again. | |
| 344 */ | |
| 345 public void drawImage(PImage img, int xPos, int yPos) { | |
| 346 img.setX(xPos); | |
| 347 img.setY(yPos); | |
| 348 layer.addChild(img); | |
| 349 } | |
| 350 | |
| 351 /** | |
| 352 * Draw a line from (x1,y1) to (x2,y2) using the current pen color and stroke. | |
| 353 */ | |
| 354 public void drawLine(int x1, int y1, int x2, int y2) { | |
| 355 PPath pn = PPath.createLine(x1, y1, x2, y2); | |
| 356 pn.setStrokePaint(currentPenColor); | |
| 357 pn.setPaint(null); // Null paint may render faster than the default. | |
| 358 pn.setStroke(stroke); | |
| 359 pn.moveTo(x1, y1); | |
| 360 pn.lineTo(x2, y2); | |
| 361 layer.addChild(pn); | |
| 362 } | |
| 363 | |
| 364 /** | |
| 365 * Draw a rectangle given the two points (x1,y1) and (x2,y2) using the current | |
| 366 * stroke, pen color for the border and the brush to fill the | |
| 367 * interior. | |
| 368 */ | |
| 369 public void drawRectangle(int x1, int y1, int x2, int y2) { | |
| 370 | |
| 371 if (x1 > x2) { | |
| 372 int t = x1; | |
| 373 x1 = x2; | |
| 374 x2 = t; | |
| 375 } | |
| 376 if (y1 > y2) { | |
| 377 int t = y1; | |
| 378 y1 = y2; | |
| 379 y2 = t; | |
| 380 } | |
| 381 | |
| 382 PPath pn = PPath.createRectangle(x1, y1, x2 - x1, y2 - y1); | |
| 383 pn.setStrokePaint(currentPenColor); | |
| 384 pn.setStroke(stroke); | |
| 385 pn.setPaint(currentBrushColor); | |
| 386 layer.addChild(pn); | |
| 387 } | |
| 388 | |
| 389 /** | |
| 390 * Draw some text at (x,y) using the current pen color and text attributes. If | |
| 391 * the current font does NOT support at least one character, it tries to find | |
| 392 * a font which is capable of displaying it and use that to render the text. | |
| 393 * Note: If the font says it can render a glyph, but in reality it turns out | |
| 394 * to be crap, there is nothing we can do about it. | |
| 395 */ | |
| 396 public void drawText(int x, int y, String text) { | |
| 397 int unreadableCharAt = -1; | |
| 398 char[] chars = text.toCharArray(); | |
| 399 PText pt = new PText(text); | |
| 400 pt.setTextPaint(currentPenColor); | |
| 401 pt.setFont(currentFont); | |
| 402 | |
| 403 // Check to see if every character can be displayed by the current font. | |
| 404 for (int i = 0; i < chars.length; i++) { | |
| 405 if (!currentFont.canDisplay(chars[i])) { | |
| 406 // Set to the first not displayable character. | |
| 407 unreadableCharAt = i; | |
| 408 break; | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 // Have to find some working font and use it for this text entry. | |
| 413 if (unreadableCharAt != -1) { | |
| 414 Font[] allfonts = | |
| 415 GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); | |
| 416 for (int j = 0; j < allfonts.length; j++) { | |
| 417 if (allfonts[j].canDisplay(chars[unreadableCharAt])) { | |
| 418 Font tempFont = | |
| 419 new Font(allfonts[j].getFontName(), currentFont.getStyle(), | |
| 420 currentFont.getSize()); | |
| 421 pt.setFont(tempFont); | |
| 422 break; | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 pt.setX(x); | |
| 428 pt.setY(y); | |
| 429 layer.addChild(pt); | |
| 430 } | |
| 431 | |
| 432 /** Set the pen color to an RGB value */ | |
| 433 public void pen(int red, int green, int blue) { | |
| 434 pen(red, green, blue, 255); | |
| 435 } | |
| 436 | |
| 437 /** Set the pen color to an RGBA value */ | |
| 438 public void pen(int red, int green, int blue, int alpha) { | |
| 439 currentPenColor = new Color(red, green, blue, alpha); | |
| 440 } | |
| 441 | |
| 442 /** | |
| 443 * Define how to display text. Note: underlined is not currently not supported | |
| 444 */ | |
| 445 public void textAttributes(String font, int pixelSize, boolean bold, | |
| 446 boolean italic, boolean underlined) { | |
| 447 | |
| 448 // For legacy reasons convert "Times" to "Times New Roman" | |
| 449 if (font.equals("Times")) { | |
| 450 font = "Times New Roman"; | |
| 451 } | |
| 452 | |
| 453 int style = Font.PLAIN; | |
| 454 if (bold) { | |
| 455 style += Font.BOLD; | |
| 456 } | |
| 457 if (italic) { | |
| 458 style += Font.ITALIC; | |
| 459 } | |
| 460 currentFont = new Font(font, style, pixelSize); | |
| 461 } | |
| 462 | |
| 463 /** | |
| 464 * Zoom the window to the rectangle given the two points (x1,y1) | |
| 465 * and (x2,y2), which must be greater than (x1,y1). | |
| 466 */ | |
| 467 public void zoomRectangle(int x1, int y1, int x2, int y2) { | |
| 468 if (x2 > x1 && y2 > y1) { | |
| 469 winSizeX = getWidth(); | |
| 470 winSizeY = getHeight(); | |
| 471 int width = x2 - x1; | |
| 472 int height = y2 - y1; | |
| 473 // Since piccolo doesn't do this well either, pad with a margin | |
| 474 // all the way around. | |
| 475 int wmargin = width / 2; | |
| 476 int hmargin = height / 2; | |
| 477 double scalefactor = Math.min(winSizeX / (2.0 * wmargin + width), | |
| 478 winSizeY / (2.0 * hmargin + height)); | |
| 479 PCamera lc = canvas.getCamera(); | |
| 480 lc.scaleView(scalefactor / lc.getViewScale()); | |
| 481 lc.animateViewToPanToBounds(new Rectangle(x1 - hmargin, y1 - hmargin, | |
| 482 2 * wmargin + width, | |
| 483 2 * hmargin + height), 0); | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 /** | |
| 488 * Flush buffers and update display. | |
| 489 * | |
| 490 * Only actually reacts if there are no more messages in the stack, to prevent | |
| 491 * the canvas from flickering. | |
| 492 */ | |
| 493 public void update() { | |
| 494 // TODO(rays) fix bugs in piccolo or use something else. | |
| 495 // The repaint function generates many | |
| 496 // exceptions for no good reason. We catch and ignore as many as we | |
| 497 // can here, but most of them are generated by the system repaints | |
| 498 // caused by resizing/exposing parts of the window etc, and they | |
| 499 // generate unwanted stack traces that have to be piped to /dev/null | |
| 500 // (on linux). | |
| 501 try { | |
| 502 repaint(); | |
| 503 } catch (NullPointerException e) { | |
| 504 // Do nothing so the output isn't full of stack traces. | |
| 505 } catch (IllegalPathStateException e) { | |
| 506 // Do nothing so the output isn't full of stack traces. | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 /** Adds a checkbox entry to the menubar, c.f. SVMenubar.add(...) */ | |
| 511 public void addMenuBarItem(String parent, String name, int id, | |
| 512 boolean checked) { | |
| 513 svMenuBar.add(parent, name, id, checked); | |
| 514 } | |
| 515 | |
| 516 /** Adds a submenu to the menubar, c.f. SVMenubar.add(...) */ | |
| 517 public void addMenuBarItem(String parent, String name) { | |
| 518 addMenuBarItem(parent, name, -1); | |
| 519 } | |
| 520 | |
| 521 /** Adds a new entry to the menubar, c.f. SVMenubar.add(...) */ | |
| 522 public void addMenuBarItem(String parent, String name, int id) { | |
| 523 if (svMenuBar == null) { | |
| 524 svMenuBar = new SVMenuBar(this); | |
| 525 | |
| 526 } | |
| 527 svMenuBar.add(parent, name, id); | |
| 528 } | |
| 529 | |
| 530 /** Add a message to the message box. */ | |
| 531 public void addMessage(String message) { | |
| 532 if (ta != null) { | |
| 533 ta.append(message + "\n"); | |
| 534 } else { | |
| 535 System.out.println(message + "\n"); | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 /** | |
| 540 * This method converts a string which might contain hexadecimal values to a | |
| 541 * string which contains the respective unicode counterparts. | |
| 542 * | |
| 543 * For example, Hall0x0094chen returns Hall<o umlaut>chen | |
| 544 * encoded as utf8. | |
| 545 * | |
| 546 * @param input The original string, containing 0x values | |
| 547 * @return The converted string which has the replaced unicode symbols | |
| 548 */ | |
| 549 private static String convertIntegerStringToUnicodeString(String input) { | |
| 550 StringBuffer sb = new StringBuffer(input); | |
| 551 Pattern numbers = Pattern.compile("0x[0-9a-fA-F]{4}"); | |
| 552 Matcher matcher = numbers.matcher(sb); | |
| 553 | |
| 554 while (matcher.find()) { | |
| 555 // Find the next match which resembles a hexadecimal value and convert it | |
| 556 // to | |
| 557 // its char value | |
| 558 char a = (char) (Integer.decode(matcher.group()).intValue()); | |
| 559 | |
| 560 // Replace the original with the new character | |
| 561 sb.replace(matcher.start(), matcher.end(), String.valueOf(a)); | |
| 562 | |
| 563 // Start again, since our positions have switched | |
| 564 matcher.reset(); | |
| 565 } | |
| 566 return sb.toString(); | |
| 567 } | |
| 568 | |
| 569 /** | |
| 570 * Show a modal input dialog. The answer by the dialog is then send to the | |
| 571 * client, together with the associated menu id, as SVET_POPUP | |
| 572 * | |
| 573 * @param msg The text that is displayed in the dialog. | |
| 574 * @param def The default value of the dialog. | |
| 575 * @param id The associated commandId | |
| 576 * @param evtype The event this is associated with (usually SVET_MENU | |
| 577 * or SVET_POPUP) | |
| 578 */ | |
| 579 public void showInputDialog(String msg, String def, int id, | |
| 580 SVEventType evtype) { | |
| 581 svEventHandler.timer.stop(); | |
| 582 String tmp = | |
| 583 (String) JOptionPane.showInputDialog(this, msg, "", | |
| 584 JOptionPane.QUESTION_MESSAGE, null, null, def); | |
| 585 | |
| 586 if (tmp != null) { | |
| 587 tmp = convertIntegerStringToUnicodeString(tmp); | |
| 588 SVEvent res = new SVEvent(evtype, this, id, tmp); | |
| 589 ScrollView.addMessage(res); | |
| 590 } | |
| 591 svEventHandler.timer.restart(); | |
| 592 } | |
| 593 | |
| 594 | |
| 595 /** | |
| 596 * Shows a modal input dialog to the user. The return value is automatically | |
| 597 * sent to the client as SVET_INPUT event (with command id -1). | |
| 598 * | |
| 599 * @param msg The text of the dialog. | |
| 600 */ | |
| 601 public void showInputDialog(String msg) { | |
| 602 showInputDialog(msg, null, -1, SVEventType.SVET_INPUT); | |
| 603 } | |
| 604 | |
| 605 /** | |
| 606 * Shows a dialog presenting "Yes" and "No" as answers and returns either a | |
| 607 * "y" or "n" to the client. | |
| 608 * | |
| 609 * Closing the dialog without answering is handled like "No". | |
| 610 * | |
| 611 * @param msg The text that is displayed in the dialog. | |
| 612 */ | |
| 613 public void showYesNoDialog(String msg) { | |
| 614 // res returns 0 on yes, 1 on no. Seems to be a bit counterintuitive | |
| 615 int res = | |
| 616 JOptionPane.showOptionDialog(this, msg, "", JOptionPane.YES_NO_OPTION, | |
| 617 JOptionPane.QUESTION_MESSAGE, null, null, null); | |
| 618 | |
| 619 SVEvent e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0, | |
| 620 res == 0 ? "y" : "n"); | |
| 621 ScrollView.addMessage(e); | |
| 622 } | |
| 623 | |
| 624 /** Adds a submenu to the popup menu, c.f. SVPopupMenu.add(...) */ | |
| 625 public void addPopupMenuItem(String parent, String name) { | |
| 626 if (svPuMenu == null) { | |
| 627 svPuMenu = new SVPopupMenu(this); | |
| 628 } | |
| 629 svPuMenu.add(parent, name, -1); | |
| 630 } | |
| 631 | |
| 632 /** Adds a new menu entry to the popup menu, c.f. SVPopupMenu.add(...) */ | |
| 633 public void addPopupMenuItem(String parent, String name, int cmdEvent, | |
| 634 String value, String desc) { | |
| 635 if (svPuMenu == null) { | |
| 636 svPuMenu = new SVPopupMenu(this); | |
| 637 } | |
| 638 svPuMenu.add(parent, name, cmdEvent, value, desc); | |
| 639 } | |
| 640 | |
| 641 /** Destroys a window. */ | |
| 642 public void destroy() { | |
| 643 ScrollView.addMessage(new SVEvent(SVEventType.SVET_DESTROY, this, 0, | |
| 644 "SVET_DESTROY")); | |
| 645 setVisible(false); | |
| 646 // dispose(); | |
| 647 } | |
| 648 } |
