1 /* 2 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details ( see the LICENSE file ). 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 package com.aelitis.azureus.ui.swt.skin; 20 21 import java.util.ArrayList; 22 23 import org.eclipse.swt.SWT; 24 import org.eclipse.swt.events.PaintEvent; 25 import org.eclipse.swt.events.PaintListener; 26 import org.eclipse.swt.graphics.*; 27 import org.eclipse.swt.layout.FillLayout; 28 import org.eclipse.swt.layout.FormData; 29 import org.eclipse.swt.widgets.*; 30 31 import org.gudy.azureus2.core3.util.AERunnable; 32 import org.gudy.azureus2.core3.util.Debug; 33 import org.gudy.azureus2.ui.swt.Utils; 34 35 import com.aelitis.azureus.ui.swt.imageloader.ImageLoader; 36 37 /** 38 * @author TuxPaper 39 * @created Jun 8, 2006 40 * 41 */ 42 public class SWTBGImagePainter 43 implements Listener 44 { 45 private static boolean DEBUG = false; 46 47 private static boolean TEST_SWT_PAINTING = false; //Constants.isOSX; 48 49 private Rectangle lastResizeRect = Utils.EMPTY_RECT; 50 51 private final Shell shell; 52 53 private String imgSrcID; 54 55 private String imgSrcLeftID; 56 57 private String imgSrcRightID; 58 59 private Image imgSrc; 60 61 private Image imgSrcLeft; 62 63 private Image imgSrcRight; 64 65 private Rectangle imgSrcBounds; 66 67 private Rectangle imgSrcLeftBounds; 68 69 private Rectangle imgSrcRightBounds; 70 71 private Image lastImage = null; 72 73 boolean inEvent = false; 74 75 Rectangle lastBounds = Utils.EMPTY_RECT; 76 77 Point lastShellBGSize = new Point(0, 0); 78 79 private final int tileMode; 80 81 private final Control control; 82 83 private boolean bDirty; 84 85 private int fdWidth = -1; 86 87 private int fdHeight = -1; 88 89 private ImageLoader imageLoader = null; 90 SWTBGImagePainter(Control control, int tileMode)91 private SWTBGImagePainter(Control control, int tileMode) { 92 this.control = control; 93 this.shell = control.getShell(); 94 this.tileMode = tileMode; 95 control.setData("BGPainter", this); 96 } 97 SWTBGImagePainter(Control control, Image bgImage, int tileMode)98 public SWTBGImagePainter(Control control, Image bgImage, int tileMode) { 99 this(control, null, null, bgImage, tileMode); 100 } 101 SWTBGImagePainter(Control control, Image bgImageLeft, Image bgImageRight, Image bgImage, int tileMode)102 public SWTBGImagePainter(Control control, Image bgImageLeft, 103 Image bgImageRight, Image bgImage, int tileMode) { 104 this(control, tileMode); 105 setImages(bgImageLeft, bgImageRight, bgImage); 106 107 if (bDirty) { 108 if (control.isVisible()) { 109 buildBackground(control); 110 } 111 } 112 113 if (!TEST_SWT_PAINTING) { 114 control.addListener(SWT.Resize, this); 115 control.addListener(SWT.Paint, this); 116 control.getShell().addListener(SWT.Show, this); 117 } 118 119 control.addListener(SWT.Dispose, this); 120 } 121 SWTBGImagePainter(Control control, ImageLoader imageLoader, String bgImageLeftId, String bgImageRightId, String bgImageId, int tileMode)122 public SWTBGImagePainter(Control control, ImageLoader imageLoader, 123 String bgImageLeftId, 124 String bgImageRightId, String bgImageId, int tileMode) { 125 this(control, tileMode); 126 setImage(imageLoader, bgImageLeftId, bgImageRightId, bgImageId); 127 128 if (bDirty) { 129 if (control.isVisible()) { 130 buildBackground(control); 131 } 132 } 133 134 if (!TEST_SWT_PAINTING) { 135 control.addListener(SWT.Resize, this); 136 control.addListener(SWT.Paint, this); 137 control.getShell().addListener(SWT.Show, this); 138 } 139 140 control.addListener(SWT.Dispose, this); 141 } 142 dispose()143 public void dispose() { 144 if (control == null || control.isDisposed()) { 145 return; 146 } 147 148 if (!TEST_SWT_PAINTING) { 149 control.removeListener(SWT.Resize, this); 150 control.removeListener(SWT.Paint, this); 151 control.getShell().removeListener(SWT.Show, this); 152 } 153 154 control.removeListener(SWT.Dispose, this); 155 control.setBackgroundImage(null); 156 FormData formData = (FormData) control.getLayoutData(); 157 formData.width = SWT.DEFAULT; 158 formData.height = SWT.DEFAULT; 159 control.setData("BGPainter", null); 160 } 161 162 /** 163 * @param bgImageLeft 164 * @param bgImageRight 165 * @param bgImage 166 */ setImage(Image bgImageLeft, Image bgImageRight, Image bgImage)167 public void setImage(Image bgImageLeft, Image bgImageRight, Image bgImage) { 168 setImages(bgImageLeft, bgImageRight, bgImage); 169 if (bDirty) { 170 Utils.execSWTThread(new AERunnable() { 171 public void runSupport() { 172 if (!control.isVisible()) { 173 return; 174 } 175 buildBackground(control); 176 } 177 }); 178 } 179 } 180 setImage(ImageLoader imageLoader, String idLeft, String idRight, String id)181 public void setImage(ImageLoader imageLoader, String idLeft, String idRight, 182 String id) { 183 setImages(imageLoader, idLeft, idRight, id); 184 if (bDirty) { 185 Utils.execSWTThread(new AERunnable() { 186 public void runSupport() { 187 if (!control.isVisible()) { 188 return; 189 } 190 buildBackground(control); 191 } 192 }); 193 } 194 } 195 imagesEqual(Image image1, Image image2)196 private boolean imagesEqual(Image image1, Image image2) { 197 if (image1 == image2) { 198 return true; 199 } 200 201 if (!ImageLoader.isRealImage(image1) && !ImageLoader.isRealImage(image2)) { 202 return true; 203 } 204 205 return false; 206 } 207 setImages(Image bgImageLeft, Image bgImageRight, Image bgImage)208 private void setImages(Image bgImageLeft, Image bgImageRight, Image bgImage) { 209 if (imagesEqual(imgSrc, bgImage) && imagesEqual(imgSrcLeft, bgImageLeft) 210 && imagesEqual(imgSrcRight, bgImageRight)) { 211 if (DEBUG) { 212 System.out.println("same"); 213 } 214 return; 215 } 216 217 imgSrcLeftID = null; 218 imgSrcRightID = null; 219 imgSrcID = null; 220 221 222 if (DEBUG) { 223 System.out.println("SI " + bgImageLeft + ";" + bgImageRight + ";" 224 + bgImage + ";" + control.getData("SkinObject") + "/" + control.isVisible() + control.getSize() + "\\" 225 + Debug.getStackTrace(true, false)); 226 } 227 228 imgSrc = bgImage; 229 if (imgSrc != null) { 230 imgSrcBounds = imgSrc.getBounds(); 231 } 232 lastShellBGSize = new Point(0, 0); 233 if (ImageLoader.isRealImage(bgImageLeft)) { 234 imgSrcLeft = bgImageLeft; 235 imgSrcLeftBounds = imgSrcLeft.getBounds(); 236 } else { 237 imgSrcLeft = null; 238 imgSrcLeftBounds = Utils.EMPTY_RECT; 239 } 240 if (ImageLoader.isRealImage(bgImageRight)) { 241 imgSrcRight = bgImageRight; 242 imgSrcRightBounds = imgSrcRight.getBounds(); 243 } else { 244 imgSrcRight = null; 245 imgSrcRightBounds = Utils.EMPTY_RECT; 246 } 247 248 249 if (TEST_SWT_PAINTING) { 250 control.removeListener(SWT.Resize, this); 251 control.removeListener(SWT.Paint, this); 252 253 if (imgSrcRight == null && imgSrcLeft == null 254 && tileMode == SWTSkinUtils.TILE_NONE) { 255 control.setBackgroundImage(imgSrc); 256 } else { 257 control.addListener(SWT.Resize, this); 258 control.addListener(SWT.Paint, this); 259 bDirty = true; 260 buildBackground(control); 261 } 262 } else { 263 bDirty = true; 264 } 265 266 267 if ((tileMode & SWTSkinUtils.TILE_BOTH) != SWTSkinUtils.TILE_BOTH) { 268 int width = SWT.DEFAULT; 269 int height = SWT.DEFAULT; 270 271 if (tileMode == SWTSkinUtils.TILE_Y || tileMode == SWTSkinUtils.TILE_NONE) { 272 width = imgSrcBounds.width + imgSrcLeftBounds.width 273 + imgSrcRightBounds.width; 274 } 275 if (tileMode == SWTSkinUtils.TILE_X || tileMode == SWTSkinUtils.TILE_NONE) { 276 height = imgSrcBounds.height; 277 } 278 FormData fd = (FormData) control.getLayoutData(); 279 if (fd == null) { 280 fd = new FormData(); 281 } 282 283 if (fd.width == fdWidth || fd.height == fdHeight) { 284 285 if (fd.width == fdWidth) { 286 fdWidth = fd.width = width; 287 } 288 if (fd.height == fdHeight) { 289 fdHeight = fd.height = height; 290 } 291 control.setLayoutData(fd); 292 if (control.isVisible()) { 293 bDirty = true; 294 control.getParent().layout(true, true); 295 } 296 } 297 } 298 299 } 300 301 /** 302 * @param bgImageLeftId 303 * @param bgImageRightId 304 * @param bgImageId 305 * 306 * @since 4.0.0.5 307 */ setImages(ImageLoader imageLoader, String bgImageLeftId, String bgImageRightId, String bgImageId)308 public void setImages(ImageLoader imageLoader, String bgImageLeftId, String bgImageRightId, 309 String bgImageId) { 310 this.imageLoader = imageLoader; 311 imgSrcLeftID = bgImageLeftId; 312 imgSrcRightID = bgImageRightId; 313 imgSrcID = bgImageId; 314 315 imgSrcLeftBounds = Utils.EMPTY_RECT; 316 imgSrcRightBounds = Utils.EMPTY_RECT; 317 318 if (imgSrcID != null) { 319 Image imgSrc = imageLoader.getImage(imgSrcID); 320 imgSrcBounds = imgSrc.getBounds(); 321 imageLoader.releaseImage(imgSrcID); 322 } 323 Image imgSrcLeft = imageLoader.getImage(imgSrcLeftID); 324 if (ImageLoader.isRealImage(imgSrcLeft)) { 325 imgSrcLeftBounds = imgSrcLeft.getBounds(); 326 } 327 imageLoader.releaseImage(imgSrcLeftID); 328 329 Image imgSrcRight = imageLoader.getImage(imgSrcRightID); 330 if (ImageLoader.isRealImage(imgSrcRight)) { 331 imgSrcRightBounds = imgSrcRight.getBounds(); 332 } 333 imageLoader.releaseImage(imgSrcRightID); 334 335 if (TEST_SWT_PAINTING) { 336 control.removeListener(SWT.Resize, this); 337 control.removeListener(SWT.Paint, this); 338 339 control.addListener(SWT.Resize, this); 340 control.addListener(SWT.Paint, this); 341 bDirty = true; 342 buildBackground(control); 343 } else { 344 bDirty = true; 345 } 346 347 348 if ((tileMode & SWTSkinUtils.TILE_BOTH) != SWTSkinUtils.TILE_BOTH) { 349 int width = SWT.DEFAULT; 350 int height = SWT.DEFAULT; 351 352 if (tileMode == SWTSkinUtils.TILE_Y || tileMode == SWTSkinUtils.TILE_NONE) { 353 width = imgSrcBounds.width + imgSrcLeftBounds.width 354 + imgSrcRightBounds.width; 355 } 356 if (tileMode == SWTSkinUtils.TILE_X || tileMode == SWTSkinUtils.TILE_NONE) { 357 height = imgSrcBounds.height; 358 } 359 FormData fd = (FormData) control.getLayoutData(); 360 if (fd == null) { 361 fd = new FormData(); 362 } 363 364 if (fd.width == fdWidth || fd.height == fdHeight) { 365 366 if (fd.width == fdWidth) { 367 fdWidth = fd.width = width; 368 } 369 if (fd.height == fdHeight) { 370 fdHeight = fd.height = height; 371 } 372 control.setLayoutData(fd); 373 if (control.isVisible()) { 374 bDirty = true; 375 control.getParent().layout(true, true); 376 } 377 } 378 } 379 380 } 381 382 buildBackground(Control control)383 public void buildBackground(Control control) { 384 if (inEvent || shell == null || shell.isDisposed() || control == null 385 || control.isDisposed()) { 386 return; 387 } 388 389 //System.out.println("BB: " + control.getData("ConfigID")); 390 391 inEvent = true; 392 393 ArrayList<String> imagesToRelease = new ArrayList<String>(0); 394 395 if (imgSrcLeftID != null && imageLoader.imageExists(imgSrcLeftID)) { 396 imagesToRelease.add(imgSrcLeftID); 397 imgSrcLeft = imageLoader.getImage(imgSrcLeftID); 398 imgSrcLeftBounds = imgSrcLeft.getBounds(); 399 } 400 if (imgSrcRightID != null && imageLoader.imageExists(imgSrcRightID)) { 401 imagesToRelease.add(imgSrcRightID); 402 imgSrcRight = imageLoader.getImage(imgSrcRightID); 403 imgSrcRightBounds = imgSrcRight.getBounds(); 404 } 405 if (imgSrcID != null) { 406 Image[] images = imageLoader.getImages(imgSrcID); 407 imagesToRelease.add(imgSrcID); 408 if (images.length == 1) { 409 imgSrc = images[0]; 410 imgSrcBounds = imgSrc.getBounds(); 411 } else if (images.length == 2) { 412 imgSrcLeft = images[0]; 413 imgSrcLeftBounds = imgSrcLeft.getBounds(); 414 imgSrc = images[1]; 415 imgSrcBounds = imgSrc.getBounds(); 416 imgSrcRight = images[1]; 417 imgSrcRightBounds = imgSrcRight.getBounds(); 418 } else if (images.length == 3) { 419 imgSrcLeft = images[0]; 420 imgSrcLeftBounds = imgSrcLeft.getBounds(); 421 imgSrc = images[1]; 422 imgSrcBounds = imgSrc.getBounds(); 423 imgSrcRight = images[2]; 424 imgSrcRightBounds = imgSrcRight.getBounds(); 425 } 426 } 427 428 try { 429 430 Point size = control.getSize(); 431 if (size.x <= 0 || size.y <= 0 || imgSrc == null || imgSrc.isDisposed()) { 432 if (DEBUG) { 433 System.out.println("- size " + control.getData("ConfigID")); 434 } 435 Image image = new Image(shell.getDisplay(), 1, 1); 436 control.setBackgroundImage(image); 437 438 if (lastImage != null) { 439 lastImage.dispose(); 440 } 441 442 lastImage = image; 443 imgSrc = image; 444 imgSrcBounds = new Rectangle(0,0,1,1); 445 446 lastBounds = control.getBounds(); 447 448 inEvent = false; 449 return; 450 } 451 452 Composite parent = control.getParent(); 453 Image imgBG = parent.getBackgroundImage(); 454 455 if (imgBG != null && imgBG.isDisposed()) { 456 imgBG = null; 457 } 458 459 Rectangle imgBGBounds = imgBG == null ? new Rectangle(0, 0, 1, 1) 460 : imgBG.getBounds(); 461 Rectangle compositeArea = control.getBounds(); 462 463 boolean bTileY = (tileMode & SWTSkinUtils.TILE_Y) > 0; 464 boolean bTileX = (tileMode & SWTSkinUtils.TILE_X) > 0; 465 466 // TODO: Can also exit early if size shrunk but position 467 // same and imgBGBounds same. 468 469 if (!bDirty && imgBG == null && bTileX && bTileY) { 470 inEvent = false; 471 return; 472 } 473 474 if (!bDirty && imgBG == null && compositeArea.width == lastBounds.width 475 && compositeArea.height == lastBounds.height) { 476 inEvent = false; 477 return; 478 } 479 480 if (!bDirty && compositeArea.equals(lastBounds) 481 && imgBGBounds.width == lastShellBGSize.x 482 && imgBGBounds.height == lastShellBGSize.y) { 483 inEvent = false; 484 return; 485 } 486 487 if (TEST_SWT_PAINTING && !bDirty && compositeArea.width == lastBounds.width 488 && compositeArea.height == lastBounds.height) { 489 inEvent = false; 490 return; 491 } 492 493 //control.setRedraw(false); 494 if (DEBUG) { 495 System.out.println(System.currentTimeMillis() + "@" 496 + Integer.toHexString(hashCode()) + "BGPain: " 497 + control.getData("SkinObject") + "/" + "; image" + size + ";" 498 + tileMode + ";lB=" + lastBounds + "/" + compositeArea + ";" 499 + "lBG=" + lastShellBGSize + "/" + imgBGBounds.width + "x" 500 + imgBGBounds.height + ";" + bDirty); 501 //+ "\n" + Debug.getCompressedStackTrace()); 502 } 503 504 lastBounds = compositeArea; 505 lastShellBGSize = new Point(imgBGBounds.width, imgBGBounds.height); 506 //System.out.println(size); 507 508 //size.x = 10; 509 //size.y = 10; 510 Image newImage = new Image(shell.getDisplay(), size.x, size.y); 511 512 // GC gc = new GC(newImage); 513 // gc.setBackground(shell.getDisplay().getSystemColor( 514 // (int) (Math.random() * 16))); 515 // gc.fillRectangle(0, 0, size.x, size.y); 516 // gc.dispose(); 517 518 Point ofs; 519 520 if (control.getParent() == shell) { 521 ofs = control.getLocation(); 522 Rectangle clientArea = shell.getClientArea(); 523 ofs.x += clientArea.x; 524 ofs.y += clientArea.y; 525 } else { 526 Point controlPos = new Point(0, 0); 527 if (control instanceof Composite) { 528 Composite composite = (Composite) control; 529 Rectangle compArea = composite.getClientArea(); 530 //System.out.println("comparea=" + compArea); 531 controlPos.x = compArea.x; 532 controlPos.y = compArea.y; 533 } 534 535 Point locControl = control.toDisplay(controlPos.x, controlPos.y); 536 Rectangle clientArea = shell.getClientArea(); 537 Point locShell = control.getParent().toDisplay(clientArea.x, 538 clientArea.y); 539 //System.out.println("locC="+ locControl + ";locS=" + locShell); 540 541 ofs = new Point(locControl.x - locShell.x, locControl.y - locShell.y); 542 } 543 544 ofs.x = (ofs.x % imgBGBounds.width); 545 ofs.y = (ofs.y % imgBGBounds.height); 546 547 GC gc = new GC(newImage); 548 try { 549 550 control.setBackgroundImage(null); 551 gc.setBackground(control.getBackground()); 552 gc.fillRectangle(0, 0, size.x, size.y); 553 554 if (imgBG != null) { 555 for (int y = 0; y < size.y; y += imgBGBounds.height) { 556 for (int x = 0; x < size.x; x += imgBGBounds.width) { 557 gc.drawImage(imgBG, x - ofs.x, y - ofs.y); 558 } 559 } 560 } 561 562 int maxY = bTileY ? size.y : imgSrcBounds.height; 563 int maxX = bTileX ? size.x : imgSrcBounds.width; 564 int x0 = 0; 565 566 if ((tileMode & SWTSkinUtils.TILE_CENTER_X) > 0) { 567 x0 = (size.x - imgSrcBounds.width) / 2; 568 maxX += x0; 569 } 570 int y0 = 0; 571 if ((tileMode & SWTSkinUtils.TILE_CENTER_Y) > 0) { 572 y0 = (size.y - imgSrcBounds.height) / 2; 573 maxY += y0; 574 } 575 576 if (imgSrcRight != null) { 577 int width = imgSrcRightBounds.width; 578 579 maxX -= width; 580 } 581 582 if (imgSrcLeft != null) { 583 // TODO: Tile down 584 gc.drawImage(imgSrcLeft, 0, 0); 585 586 x0 += imgSrcLeftBounds.width; 587 } 588 589 for (int y = y0; y < maxY; y += imgSrcBounds.height) { 590 for (int x = x0; x < maxX; x += imgSrcBounds.width) { 591 if (x + imgSrcBounds.width >= maxX) { 592 int width = maxX - x; 593 gc.drawImage(imgSrc, 0, 0, width, imgSrcBounds.height, x, y, 594 width, imgSrcBounds.height); 595 } else { 596 gc.drawImage(imgSrc, x, y); 597 } 598 } 599 } 600 601 if (imgSrcRight != null) { 602 // TODO: Tile down 603 gc.drawImage(imgSrcRight, maxX, 0); 604 } 605 } finally { 606 gc.dispose(); 607 } 608 609 control.setBackgroundImage(newImage); 610 611 if (lastImage != null) { 612 lastImage.dispose(); 613 } 614 615 lastImage = newImage; 616 617 bDirty = false; 618 619 } finally { 620 for (String key : imagesToRelease) { 621 imageLoader.releaseImage(key); 622 } 623 if (imgSrcID != null && imgSrc != null) { 624 imgSrc = null; 625 } 626 if (imgSrcLeftID != null && imgSrcLeft != null) { 627 imgSrcLeft = null; 628 } 629 if (imgSrcRightID != null && imgSrcRight != null) { 630 imgSrcRight = null; 631 } 632 633 //control.setRedraw(true); 634 //control.update(); 635 //control.getShell().update(); 636 // if (control instanceof Composite) { 637 // Control[] children = ((Composite)control).getChildren(); 638 // ((Composite)control).layout(true, true); 639 // for (int i = 0; i < children.length; i++) { 640 // Control control2 = children[i]; 641 // control2.redraw(); 642 // control2.update(); 643 // } 644 // } 645 646 inEvent = false; 647 } 648 } 649 main(String[] args)650 public static void main(String[] args) { 651 Display display = Display.getDefault(); 652 Shell shell = new Shell(display, SWT.DIALOG_TRIM); 653 shell.setLayout(new FillLayout()); 654 655 Composite c = new Composite(shell, SWT.BORDER); 656 c.setLayout(new FillLayout()); 657 c.addPaintListener(new PaintListener() { 658 public void paintControl(PaintEvent e) { 659 e.gc.drawLine(0, 0, 100, 50); 660 } 661 }); 662 663 Label lbl = new Label(c, SWT.NONE); 664 lbl.setText("text"); 665 666 shell.open(); 667 668 while (!shell.isDisposed()) { 669 if (display.readAndDispatch()) { 670 display.sleep(); 671 } 672 } 673 } 674 handleEvent(final Event event)675 public void handleEvent(final Event event) { 676 if (event.type == SWT.Resize) { 677 Control control = (Control) event.widget; 678 679 Rectangle resizeRect = control.getBounds(); 680 if (resizeRect.equals(lastResizeRect)) { 681 return; 682 } 683 684 lastResizeRect = resizeRect; 685 686 if (DEBUG) { 687 System.out.println("BGPaint:HE: " + control.getData("ConfigID") + ";" 688 + event + ";" + control.isVisible()); 689 } 690 buildBackground(control); 691 } else if (event.type == SWT.Paint) { 692 Control control = (Control) event.widget; 693 if (DEBUG) { 694 System.out.println("BGPaint:P: " + control.getData("ConfigID") + ";" 695 + event + ";" + control.isVisible()); 696 } 697 698 if (!TEST_SWT_PAINTING) { 699 buildBackground(control); 700 } 701 } else if (event.type == SWT.Show) { 702 if (DEBUG) { 703 System.out.println("BGPaint:S: " + control.getData("ConfigID") + ";" 704 + event + ";" + control.isVisible()); 705 } 706 707 if (!TEST_SWT_PAINTING) { 708 buildBackground(control); 709 } 710 } else if (event.type == SWT.Dispose) { 711 if (DEBUG) { 712 System.out.println("dispose.. " + lastImage + ";" 713 + control.getData("SkinObject")); 714 } 715 if (lastImage != null && !lastImage.isDisposed()) { 716 lastImage.dispose(); 717 lastImage = null; 718 } 719 } 720 } 721 } 722