001 /** 002 * This library is free software; you can redistribute it and/or modify it 003 * under the terms of the GNU Lesser General Public License (LGPL) as 004 * published by the Free Software Foundation; either version 3.0 of the 005 * License, or (at your option) any later version. 006 * 007 * This library is distributed in the hope that it will be useful, but 008 * WITHOUT ANY WARRANTY; without even the implied warranty of 009 * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the GNU 010 * Lesser General Public License for more details. 011 */ 012 013 /** 014 * Title: JBarcodeBean 015 * Description: Barcode JavaBeans Component 016 * Copyright: Copyright (C) 2004 017 * Company: Dafydd Walters 018 */ 019 package net.sourceforge.jbarcodebean; 020 021 import javax.swing.*; 022 import java.awt.*; 023 import java.awt.geom.*; 024 import javax.accessibility.*; 025 026 import net.sourceforge.jbarcodebean.model.BarcodeStrategy; 027 import net.sourceforge.jbarcodebean.model.Codabar; 028 import net.sourceforge.jbarcodebean.model.Codabar_2to1; 029 import net.sourceforge.jbarcodebean.model.Code128; 030 import net.sourceforge.jbarcodebean.model.Code39; 031 import net.sourceforge.jbarcodebean.model.Code39_2to1; 032 import net.sourceforge.jbarcodebean.model.Ean13; 033 import net.sourceforge.jbarcodebean.model.Ean8; 034 import net.sourceforge.jbarcodebean.model.ExtendedCode39; 035 import net.sourceforge.jbarcodebean.model.ExtendedCode39_2to1; 036 import net.sourceforge.jbarcodebean.model.Interleaved25; 037 import net.sourceforge.jbarcodebean.model.Interleaved25_2to1; 038 import net.sourceforge.jbarcodebean.model.MSI; 039 040 import java.io.*; 041 import java.net.URL; 042 import java.util.Properties; 043 import java.awt.image.*; 044 045 /** 046 * <p> 047 * JFC Swing-compatible JavaBeans 048 * <sup><small>TM</small></sup> 049 * component that renders barcodes in a variety of different formats. 050 * <p> 051 * [<a href='#skip_copyright'>skip over license and copyright</a>] 052 * <hr> 053 * <p><b>LICENSE INFORMATION</b></p> 054 * <p> 055 * This library is free software; you can redistribute it and/or modify it 056 * under the terms of the GNU Lesser General Public License (LGPL) as 057 * published by the Free Software Foundation; either version 3.0 of the 058 * License, or (at your option) any later version. 059 * </p><p> 060 * This library is distributed in the hope that it will be useful, but 061 * WITHOUT ANY WARRANTY; without even the implied warranty of 062 * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the GNU 063 * Lesser General Public License for more details. 064 * </p> 065 * <p>See <a href='http://www.gnu.org/licenses/lgpl.html' 066 * >http://www.gnu.org/licenses/lgpl.html</a>. 067 * </p> 068 * <hr> 069 * <A NAME="skip_copyright"><!-- --></A> 070 * <p> 071 * <strong>JBarcodeBean</strong> employs the <strong>Strategy</strong> design pattern<b>*</b> 072 * to abstract the encoding algorithm. The 073 * {@link #setCodeType(BarcodeStrategy) codeType} 074 * property can be set to any class that implements the {@link BarcodeStrategy} 075 * interface to determine how the {@link #setCode(String) code} property is encoded. 076 * This version of JBarcodeBean is bundled with the following concrete implementations 077 * of {@link BarcodeStrategy}: 078 * 079 * <ul> 080 * <li>{@link Code128} 081 * <li>{@link Code39} 082 * <li>{@link Code39_2to1} 083 * <li>{@link ExtendedCode39} 084 * <li>{@link ExtendedCode39_2to1} 085 * <li>{@link Interleaved25} 086 * <li>{@link Interleaved25_2to1} 087 * <li>{@link Codabar} 088 * <li>{@link Codabar_2to1} 089 * <li>{@link MSI} 090 * <li>{@link Ean8} 091 * <li>{@link Ean13} 092 * </ul> 093 * <p> 094 * 095 * <blockquote><b>*</b>See <i>"Design Patterns Elements of Reusable Object-Oriented Software", 096 * Erich Gamma et al.</i> for more information about design patterns.</blockquote> 097 * 098 * @version 1.1 099 */ 100 public class JBarcodeBean extends JComponent implements java.io.Serializable, Accessible { 101 102 // Property change constants 103 104 /** Identifies a change in the <b>showText</b> property. */ 105 private static final String SHOW_TEXT_CHANGED_PROPERTY = "showText"; 106 /** Identifies a change in the <b>code</b> property. */ 107 private static final String CODE_CHANGED_PROPERTY = "code"; 108 /** Identifies a change in the <b>codeType</b> property. */ 109 private static final String CODE_TYPE_CHANGED_PROPERTY = "codeType"; 110 /** Identifies a change in the <b>checkDigit</b> property. */ 111 private static final String CHECK_DIGIT_CHANGED_PROPERTY = "checkDigit"; 112 /** Identifies a change in the <b>narrowestBarWidth</b> property. */ 113 private static final String NARROWEST_BAR_WIDTH_CHANGED_PROPERTY = "narrowestBarWidth"; 114 /** Identifies a change in the <b>barcodeHeight</b> property. */ 115 private static final String BARCODE_HEIGHT_CHANGED_PROPERTY = "barcodeHeight"; 116 /** Identifies a change in the <b>barcodeBackground</b> property. */ 117 private static final String BARCODE_BACKGROUND_CHANGED_PROPERTY = "barcodeBackground"; 118 /** Identifies a change in the <b>angleDegrees</b> property. */ 119 private static final String ANGLE_DEGREES_CHANGED_PROPERTY = "angleDegrees"; 120 121 /** 122 * Identifies a change of the horizontal alignment property. 123 */ 124 private static final String HORIZONTAL_ALIGNMENR_PROPERTY ="horizontalAlignment"; 125 126 /** 127 * Constant indicating that the barcode should be left aligned along the 128 * x-axis. 129 */ 130 public static final int ALIGN_LEFT =1; 131 132 /** 133 * Constant indicating that the barcode should be centered along the x-axis. 134 * (This is the default behaviour) 135 */ 136 public static final int ALIGN_CENTER =2; 137 138 /** 139 * Constant indicating that the barcode should be right aligned along the 140 * x-axis. 141 */ 142 public static final int ALIGN_RIGHT =3; 143 144 145 /** 146 * Identifies a change of the label position property. 147 */ 148 private static final String LABEL_POSITION_PROPERTY ="labelPosition"; 149 150 /** 151 * Constant indicating that the human readable barcode text should be 152 * printed at the top of the barcode. 153 */ 154 public static final int LABEL_TOP = 1; 155 156 /** 157 * Constant indicating that the human readable barcode text should be 158 * printed at the bottom of the barcode. (This is the default behaviour) 159 */ 160 public static final int LABEL_BOTTOM = 2; 161 162 /** 163 * Constant indicating that the human readable barcode text should not be 164 * printed at all. 165 */ 166 public static final int LABEL_NONE = 0; 167 168 169 170 // Private fields. 171 private String code; 172 private BarcodeStrategy codeType; 173 private boolean checkDigit = false; 174 private EncodedBarcode encoded = null; 175 private int narrowestBarWidth = 1; 176 private int barcodeHeight = 40; 177 private Color barcodeBackground = Color.white; 178 private Dimension minimumSize; 179 private Dimension preferredSize; 180 private double angleDegrees; 181 private int labelHeight; // calculated 182 private int labelWidth; // calculated 183 private int barcodeWidth; // calculated 184 private String encodeError = ""; 185 private int horizontalAlignment = ALIGN_CENTER; 186 private int labelPosition = LABEL_BOTTOM; 187 188 /** 189 * <p>Contructor that allows an initial barcode and code type to be specified. 190 * 191 * @param code The text to encode. 192 * @param codeType The type of barcode. 193 */ 194 public JBarcodeBean(String code, BarcodeStrategy codeType) { 195 196 // Set some Component and JComponent properties. 197 setForeground(Color.black); 198 setFont(new Font("Monospaced", Font.PLAIN, 12)); 199 200 // Set bean properties - don't fire property changes here since this is c'tor 201 this.code = code; 202 this.codeType = codeType; 203 if (codeType.requiresChecksum() == BarcodeStrategy.MANDATORY_CHECKSUM) { 204 checkDigit = true; 205 } else if (codeType.requiresChecksum() == BarcodeStrategy.NO_CHECKSUM) { 206 checkDigit = false; 207 } 208 209 // Disable double buffering, so that Java-2 printing is hi-res 210 setDoubleBuffered(false); 211 212 // Render the bean. 213 encode(); 214 recalculateSizes(); 215 repaint(); 216 } 217 218 /** 219 * <p> 220 * Parameterless constructor. Creates a <tt>JBarcodeBean</tt> object with default 221 * property values, so that the bean will render as a typical barcode 222 * when initially added to a GUI with a GUI Builder. 223 * <p> 224 * Defaulat values are:<b> 225 * <p><code>code = "1234"</code><br> 226 * <code>codeType = new Code39()</code></b><br> 227 * <p> 228 * @see Code39 229 * 230 */ 231 public JBarcodeBean() { 232 this("1234", new Code39()); 233 } 234 235 /** 236 * Accessor method for the <tt><b>angleDegrees</b></tt> property, 237 * which determines the angle (from horizontal) at which the barcode 238 * is rendered. 239 */ 240 public double getAngleDegrees() { 241 return angleDegrees; 242 } 243 244 /** 245 * Mutator method for the <tt><b>angleDegrees</b></tt> property, 246 * which determines the angle (from horizontal) at which the barcode 247 * is rendered. 248 */ 249 public void setAngleDegrees(double angleDegrees) { 250 double oldValue = this.angleDegrees; 251 this.angleDegrees = angleDegrees; 252 firePropertyChange(ANGLE_DEGREES_CHANGED_PROPERTY, oldValue, angleDegrees); 253 recalculateSizes(); 254 repaint(); 255 } 256 257 /** 258 * Accessor method for the <tt><b>showText</b></tt> property, which 259 * determines whether or not the text caption is visible below the 260 * barcode. <tt>true</tt> = visible, <tt>false</tt> = not visible. 261 * @deprecated As of 1.2.0, replaced by {@link #getLabelPosition()}. 262 * This will return <tt>true</tt> if label position is {@link #LABEL_BOTTOM} 263 * and <tt>false</tt> otherwise. 264 */ 265 public boolean isShowText() { 266 return this.labelPosition==LABEL_BOTTOM; 267 } 268 269 /** 270 * Mutator method for the <tt><b>showText</b></tt> property, which 271 * determines whether or not the text caption is visible below the 272 * barcode. <tt>true</tt> = visible, <tt>false</tt> = not visible. 273 * @deprecated As of 1.2.0, replaced by {@link #setLabelPosition(int)}. When 274 * setting this property to <tt>true</tt> the label position will be set to 275 * {@link #LABEL_BOTTOM}, setting the property to <tt>false</tt> will set 276 * the label position to {@link #LABEL_NONE}. 277 */ 278 public void setShowText(boolean showText) { 279 boolean oldValue = isShowText(); 280 setLabelPosition(showText?LABEL_BOTTOM:LABEL_NONE); 281 firePropertyChange(SHOW_TEXT_CHANGED_PROPERTY, oldValue, showText); 282 } 283 284 /** 285 * Always returns <tt>true</tt>, as this component renders its entire 286 * drawing area. 287 */ 288 public boolean isOpaque() { 289 return true; 290 } 291 292 /** 293 * Accessor method for the <tt><b>foreground</b></tt> property, which 294 * determines the color of the bars and caption text (typically black). 295 */ 296 public Color getForeground() { 297 return super.getForeground(); 298 } 299 300 /** 301 * Mutator method for the <tt><b>foreground</b></tt> property, which 302 * determines the color of the bars and caption text (typically black). 303 */ 304 public void setForeground(Color c) { 305 super.setForeground(c); 306 repaint(); 307 } 308 309 /** 310 * Accessor method for the <tt><b>background</b></tt> property, which 311 * determines the control background color (the space around the barcode, 312 * and behind the text caption). Note that this is not the 313 * same as the {@link #getBarcodeBackground barcodeBackground} property 314 * (which is the color of the spaces between the bars in the barcode). 315 */ 316 public Color getBackground() { 317 return super.getBackground(); 318 } 319 320 /** 321 * Mutator method for the <tt><b>background</b></tt> property, which 322 * determines the control background color (the space around the barcode, 323 * and behind the text caption). Note that this is not the 324 * same as the {@link #setBarcodeBackground barcodeBackground} property 325 * (which is the color of the spaces between the bars in the barcode). 326 */ 327 public void setBackground(Color c) { 328 super.setBackground(c); 329 repaint(); 330 } 331 332 /** 333 * Accessor method for the <tt><b>barcodeBackground</b></tt> property, which 334 * determines the color of the spaces between the bars in the barcode 335 * (typically white). 336 * 337 * @see #setBackground 338 */ 339 public Color getBarcodeBackground() { 340 return barcodeBackground; 341 } 342 343 /** 344 * Mutator method for the <tt><b>barcodeBackground</b></tt> property, which 345 * determines the color of the spaces between the bars in the barcode 346 * (typically white). 347 * 348 * @see #setBackground 349 */ 350 public void setBarcodeBackground(Color barcodeBackground) { 351 Color oldValue = this.barcodeBackground; 352 this.barcodeBackground = barcodeBackground; 353 firePropertyChange(BARCODE_BACKGROUND_CHANGED_PROPERTY, oldValue, barcodeBackground); 354 repaint(); 355 } 356 357 /** 358 * Accessor methor for the <tt><b>border</b></tt> property. 359 */ 360 public javax.swing.border.Border getBorder() { 361 return super.getBorder(); 362 } 363 364 /** 365 * Mutator methor for the <tt><b>border</b></tt> property. 366 */ 367 public void setBorder(javax.swing.border.Border border) { 368 super.setBorder(border); 369 recalculateSizes(); 370 repaint(); 371 } 372 373 /** 374 * Accessor method for the <tt><b>preferredSize</b></tt> property. 375 */ 376 public Dimension getPreferredSize() { 377 return preferredSize(); 378 } 379 380 /** 381 * Mutator method for the <tt><b>preferredSize</b></tt> property. 382 */ 383 public void setPreferredSize(Dimension preferredSize) { 384 Dimension oldValue = this.preferredSize; 385 this.preferredSize = preferredSize; 386 firePropertyChange("preferredSize", oldValue, preferredSize); 387 } 388 389 /** 390 * Returns the preferred size of the component. 391 * 392 * @deprecated Use {@link #getPreferredSize}. 393 */ 394 public Dimension preferredSize() { 395 if (preferredSize != null) { 396 return preferredSize; 397 } else { 398 return new Dimension(getWidth(), getHeight()); 399 } 400 } 401 402 /** 403 * Accessor method for <tt><b>minimumSize</b></tt> property. 404 */ 405 public Dimension getMinimumSize() { 406 return minimumSize(); 407 } 408 409 /** 410 * Mutator method for the <tt><b>minimumSize</b></tt> property. 411 */ 412 public void setMinimumSize(Dimension minimumSize) { 413 Dimension oldValue = this.minimumSize; 414 this.minimumSize = minimumSize; 415 firePropertyChange("minimumSize", oldValue, minimumSize); 416 } 417 418 /** 419 * Returns the minimum size of the component. 420 * 421 * @deprecated Use {@link #getMinimumSize}. 422 */ 423 public Dimension minimumSize() { 424 if (minimumSize != null) { 425 return minimumSize; 426 } else { 427 return new Dimension(getWidth(), getHeight()); 428 } 429 } 430 431 /** 432 * Accessor method for the <tt><b>font</b></tt> property. 433 */ 434 public Font getFont() { 435 return super.getFont(); 436 } 437 438 /** 439 * Mutator method for the <tt><b>font</b></tt> property. 440 */ 441 public void setFont(Font font) { 442 super.setFont(font); 443 recalculateSizes(); 444 repaint(); 445 } 446 447 /** 448 * Accessor method for the <tt><b>barcodeHeight</b></tt> property, which 449 * determines the height of the barcode (excluding caption text) in pixels. 450 */ 451 public int getBarcodeHeight() { 452 return barcodeHeight; 453 } 454 455 /** 456 * Mutator method for the <tt><b>barcodeHeight</b></tt> property, which 457 * determines the height of the barcode (excluding caption text) in pixels. 458 */ 459 public void setBarcodeHeight(int barcodeHeight) { 460 int oldValue = this.barcodeHeight; 461 this.barcodeHeight = barcodeHeight; 462 firePropertyChange(BARCODE_HEIGHT_CHANGED_PROPERTY, oldValue, barcodeHeight); 463 recalculateSizes(); 464 repaint(); 465 } 466 467 /** 468 * Accessor method for the <tt><b>narrowestBarWidth</b></tt> property, 469 * which determines the width (in pixels) of the narrowest bar in the barcode. 470 */ 471 public int getNarrowestBarWidth() { 472 return narrowestBarWidth; 473 } 474 475 /** 476 * Mutator method for the <tt><b>narrowestBarWidth</b></tt> property, 477 * which determines the width (in pixels) of the narrowest bar in the barcode. 478 */ 479 public void setNarrowestBarWidth(int narrowestBarWidth) { 480 int oldValue = this.narrowestBarWidth; 481 this.narrowestBarWidth = narrowestBarWidth; 482 firePropertyChange(NARROWEST_BAR_WIDTH_CHANGED_PROPERTY, oldValue, narrowestBarWidth); 483 recalculateSizes(); 484 repaint(); 485 } 486 487 /** 488 * Always returns <tt>false</tt>, as this control cannot receive focus. 489 */ 490 public boolean isFocusTraversable() { 491 return false; 492 } 493 494 /** 495 * Always returns the value of the {@link #getCode code} property. 496 */ 497 protected String paramString() { 498 return code; 499 } 500 501 /** 502 * Always returns the value of the {@link #getCode code} property. 503 */ 504 public String toString() { 505 return code; 506 } 507 508 /** 509 * Accessor method for the <tt><b>code</b></tt> property, 510 * which is the text encoded in the barcode. 511 */ 512 public String getCode() { 513 return code; 514 } 515 516 /** 517 * Mutator method for the <tt><b>code</b></tt> property, 518 * which is the text encoded in the barcode. 519 */ 520 public void setCode(String code) { 521 String oldValue = this.code; 522 this.code = code; 523 firePropertyChange(CODE_CHANGED_PROPERTY, oldValue, code); 524 encode(); 525 recalculateSizes(); 526 repaint(); 527 } 528 529 /** 530 * Accessor method for the <tt><b>codeType</b></tt> property, 531 * which is the barcode type. 532 */ 533 public BarcodeStrategy getCodeType() { 534 return codeType; 535 } 536 537 /** 538 * Mutator method for the <tt><b>codeType</b></tt> property, 539 * which is the barcode type. 540 */ 541 public void setCodeType(BarcodeStrategy codeType) { 542 BarcodeStrategy oldValue = this.codeType; 543 this.codeType = codeType; 544 firePropertyChange(CODE_TYPE_CHANGED_PROPERTY, oldValue, codeType); 545 if (codeType != null && codeType.requiresChecksum() == BarcodeStrategy.MANDATORY_CHECKSUM && checkDigit == false) { 546 setCheckDigit(true); 547 // encode(), recalculateSizes(), and repaint() will be done in setChecked(). 548 } else if (codeType != null && codeType.requiresChecksum() == BarcodeStrategy.NO_CHECKSUM && checkDigit == true) { 549 setCheckDigit(false); 550 // encode(), recalculateSizes(), and repaint() will be done in setChecked(). 551 } else { 552 encode(); 553 recalculateSizes(); 554 repaint(); 555 } 556 } 557 558 /** 559 * Accessor method for the <tt><b>checkDigit</b></tt> property, 560 * which determines whether a check digit is encoded in the 561 * barcode. <tt>true</tt> = check digit is encoded, <tt>false</tt> 562 * = check digit is not encoded. 563 */ 564 public boolean isCheckDigit() { 565 return checkDigit; 566 } 567 568 /** 569 * Mutator method for the <tt><b>checkDigit</b></tt> property, 570 * which determines whether a check digit is encoded in the 571 * barcode. <tt>true</tt> = check digit is encoded, <tt>false</tt> 572 * = check digit is not encoded. 573 */ 574 public void setCheckDigit(boolean checkDigit){ 575 if (codeType != null) { 576 if (codeType.requiresChecksum() == BarcodeStrategy.MANDATORY_CHECKSUM && checkDigit == false) { 577 // Cannot disable checksum 578 // although the checksum cannot be disabled there should be no exception 579 // the call should simply be ignored (requestid 1329396) 580 return; 581 } else if (codeType.requiresChecksum() == BarcodeStrategy.NO_CHECKSUM && checkDigit == true) { 582 // Cannot enable checksum 583 // although the checksum cannot be enabled there should be no exception 584 // the call should simply be ignored (requestid 1329396) 585 return; 586 } 587 } 588 boolean oldValue = this.checkDigit; 589 this.checkDigit = checkDigit; 590 firePropertyChange(CHECK_DIGIT_CHANGED_PROPERTY, oldValue, checkDigit); 591 encode(); 592 recalculateSizes(); 593 repaint(); 594 } 595 596 /** 597 * Component paint method. 598 */ 599 protected void paintComponent(Graphics graphics) { 600 doPaint(graphics, getSize(), getInsets()); 601 } 602 603 private void doPaint(Graphics graphics, Dimension d, Insets insets) { 604 605 Graphics2D g = (Graphics2D) graphics; 606 607 // Save graphics properties 608 AffineTransform tran = g.getTransform(); 609 Shape oldClip = g.getClip(); 610 Color oldColor = g.getColor(); 611 Font oldFont = g.getFont(); 612 613 // Fill control background 614 g.setColor(getBackground()); 615 g.fillRect(0, 0, d.width, d.height); 616 617 // Set clip rectangle to prevent barcode overwriting border 618 619 // also regard the clip the graphics object already has to avoid paint 620 // outside the clip of the graphics. therefore we make an intersect of both 621 // clips 622 Area areaOldClip = null; 623 Rectangle newClip = new Rectangle(insets.left, insets.top, 624 d.width - insets.left - insets.right, d.height - insets.top - insets.bottom); 625 Area areaNewClip = new Area(newClip); 626 if (oldClip != null) 627 { 628 areaOldClip = new Area(oldClip); 629 areaOldClip.intersect(areaNewClip); 630 } 631 else 632 { 633 areaOldClip = areaNewClip; 634 } 635 g.setClip(areaOldClip); 636 637 // Apply rotate and transale transform 638 g.rotate(angleDegrees / 180 * Math.PI, d.width / 2.0, d.height / 2.0); 639 640 int barcodeTop = (d.height - (barcodeHeight + labelHeight)) / 2; 641 if(labelPosition!=LABEL_TOP){ 642 barcodeTop=(d.height - (barcodeHeight + labelHeight)) / 2; 643 } else{ 644 barcodeTop=(d.height - (barcodeHeight + labelHeight)) / 2+labelHeight; 645 } 646 647 // Draw barcode 648 if (encoded != null) { 649 int x; 650 if(horizontalAlignment==ALIGN_LEFT){ 651 x=0; 652 } else if (horizontalAlignment==ALIGN_RIGHT){ 653 x=d.width-barcodeWidth; 654 } else { 655 x=(d.width-barcodeWidth)/2; 656 } 657 for(int i = 0; i < encoded.elements.length; i++) { 658 if (encoded.elements[i].getType()==BarcodeElement.TYPE_BAR) { 659 // bar 660 g.setColor(getForeground()); 661 } else { 662 // space 663 g.setColor(barcodeBackground); 664 } 665 int barWidth = encoded.elements[i].getWidth() * narrowestBarWidth; 666 g.fillRect(x, barcodeTop, barWidth, barcodeHeight); 667 x += barWidth; 668 } 669 670 // Draw text 671 if (labelPosition!=LABEL_NONE) { 672 g.setFont(this.getFont()); 673 g.setColor(getForeground()); 674 FontMetrics fm = getFontMetrics(g.getFont()); 675 int labelTop; 676 if(labelPosition==LABEL_BOTTOM) { 677 labelTop = barcodeTop + barcodeHeight + fm.getAscent(); 678 } else { 679 labelTop = barcodeTop - labelHeight + fm.getAscent(); 680 } 681 g.drawString(encoded.barcodeLabelText, 682 (d.width - labelWidth) / 2, labelTop); 683 } 684 } else if (!encodeError.equals("")) { 685 // Display error 686 g.setFont(new Font("Monospaced", Font.PLAIN, 10)); 687 FontMetrics fm = getFontMetrics(g.getFont()); 688 int labelWidth = fm.stringWidth(encodeError); 689 g.setColor(getBarcodeBackground()); 690 g.fillRect((d.width - labelWidth) / 2, barcodeTop, 691 labelWidth, fm.getHeight()); 692 g.setColor(getForeground()); 693 g.drawString(encodeError, 694 (d.width - labelWidth) / 2, 695 barcodeTop + fm.getAscent() 696 ); 697 } 698 699 // Restore graphics properties 700 g.setTransform(tran); 701 g.setClip(oldClip); 702 g.setColor(oldColor); 703 g.setFont(oldFont); 704 } 705 706 private void recalculateSizes() { 707 708 if (labelPosition!=LABEL_NONE) { 709 FontMetrics fm = getFontMetrics(getFont()); 710 labelHeight = fm.getAscent() + fm.getDescent(); 711 } else { 712 labelHeight = 0; 713 } 714 715 Dimension d = calculateControlSize(getRequiredWidth(), barcodeHeight + labelHeight); 716 setPreferredSize(d); 717 setMinimumSize(d); 718 revalidate(); 719 } 720 721 private Dimension calculateControlSize(int rectWidth, int rectHeight) { 722 723 Insets insets = getInsets(); 724 Dimension d = new Dimension(); 725 double angleRadians = angleDegrees / 180.0 * Math.PI; 726 727 d.height = (int) (Math.abs(rectWidth * Math.sin(angleRadians)) + Math.abs(rectHeight * Math.cos(angleRadians))) 728 + insets.top + insets.bottom; 729 730 d.width = (int) (Math.abs(rectWidth * Math.cos(angleRadians)) + Math.abs(rectHeight * Math.sin(angleRadians))) 731 + insets.left + insets.right; 732 733 return d; 734 } 735 736 private int getRequiredWidth() { 737 738 this.barcodeWidth = 0; 739 this.labelWidth = 0; 740 741 if (encoded != null) { 742 743 FontMetrics fm = getFontMetrics(getFont()); 744 labelWidth = fm.stringWidth(encoded.barcodeLabelText); 745 746 for(int i = 0; i < encoded.elements.length; i++) { 747 barcodeWidth += encoded.elements[i].getWidth() * narrowestBarWidth; 748 } 749 } else if (!encodeError.equals("")) { 750 // error message only 751 FontMetrics fm = getFontMetrics(getFont()); 752 labelWidth = fm.stringWidth(encodeError); 753 } 754 755 int width = (barcodeWidth > labelWidth) ? barcodeWidth : labelWidth; 756 return width; 757 } 758 759 private void encode() { 760 encodeError = ""; 761 if ((codeType != null) && (!code.equals(""))) { 762 try { 763 encoded = codeType.encode(code, checkDigit); 764 } catch (BarcodeException e) { 765 encoded = null; 766 encodeError = e.getMessage(); 767 } 768 } else { 769 encoded = null; 770 } 771 } 772 773 /** 774 * Returns a simple subclass of <tt>AccessibleContext</tt>. 775 */ 776 public AccessibleContext getAccessibleContext() { 777 return new JComponent.AccessibleJComponent() { 778 public String getAccessibleName() { 779 return "barcode " + code; 780 } 781 public AccessibleRole getAccessibleRole() { 782 return AccessibleRole.LABEL; 783 } 784 }; 785 } 786 787 /** 788 * Returns the version of this JBarcodeBean implementation. 789 * @return The version string in format: <i>major.minor[.micro]</i> 790 */ 791 public static String getVersion() { 792 793 Class cl=JBarcodeBean.class; 794 URL url = cl.getResource("/META-INF/maven/net.sourceforge.jbarcodebean/jbarcodebean/pom.properties"); 795 Properties props=new Properties(); 796 try { 797 if(url==null){ 798 return "unknown"; 799 } 800 InputStream in=url.openStream(); 801 props.load(in); 802 in.close(); 803 } catch (IOException e) { 804 return "unknown"; 805 } 806 return props.getProperty("version"); 807 } 808 809 /** 810 * Draws the current barcode into the given image and returns it. 811 * @param image The image the barcode will be drawn into or 812 * <code>null</code> if a new image should be created using the preferred 813 * size of the barcode. 814 * @return The image containing the barcode. 815 */ 816 public BufferedImage draw(BufferedImage image) { 817 if(image==null) { 818 Dimension pref=getPreferredSize(); 819 image=(BufferedImage) createImage(pref.width, pref.height); 820 } 821 encode(); 822 recalculateSizes(); 823 Graphics2D g = image.createGraphics(); 824 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 825 doPaint(g, new Dimension(image.getWidth(), image.getHeight()), new Insets(0, 0, 0, 0)); 826 return image; 827 } 828 829 /** 830 * Returns the alignment of the barcode along the X axis. 831 * @return The value of the horizontalAlignment property, one of the 832 * following constants: {@link #ALIGN_LEFT}, {@link #ALIGN_RIGHT}, 833 * {@link #ALIGN_CENTER} 834 * @see #setHorizontalAlignment(int) 835 * @since 1.2.0 836 */ 837 public int getHorizontalAlignment() { 838 return horizontalAlignment; 839 } 840 841 /** 842 * Sets the alignment of the barcode along the X axis. 843 * This is a JavaBeans bound property. 844 * @param horizontalAlignment One of the following constants : 845 * {@link #ALIGN_LEFT}, {@link #ALIGN_RIGHT}, 846 * {@link #ALIGN_CENTER} (the default) 847 * @see #getHorizontalAlignment() 848 * @since 1.2.0 849 */ 850 public void setHorizontalAlignment(int horizontalAlignment) { 851 int oldValue=this.horizontalAlignment; 852 this.horizontalAlignment = horizontalAlignment; 853 firePropertyChange(HORIZONTAL_ALIGNMENR_PROPERTY , oldValue, horizontalAlignment); 854 recalculateSizes(); 855 repaint(); 856 } 857 858 /** 859 * Returns the label position of the human readable barcode text. 860 * @return The value of the labelPosition property, one of the following 861 * constants: {@link #LABEL_BOTTOM}, {@link #LABEL_TOP} or 862 * {@link #LABEL_NONE}. 863 * @see #setLabelPosition(int) 864 * @since 1.2.0 865 */ 866 public int getLabelPosition() { 867 return labelPosition; 868 } 869 870 /** 871 * Sets the label position of the human readable bacode text. 872 * This is a JavaBeans bound property. 873 * @param labelPosition One of the following constants: 874 * {@link #LABEL_BOTTOM}, {@link #LABEL_TOP} or {@link #LABEL_NONE}. 875 * @see #getLabelPosition() 876 * @since 1.2.0 877 */ 878 public void setLabelPosition(int labelPosition) { 879 int oldValue=this.labelPosition; 880 this.labelPosition = labelPosition; 881 firePropertyChange(LABEL_POSITION_PROPERTY, oldValue, labelPosition); 882 recalculateSizes(); 883 repaint(); 884 } 885 886 } 887