Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/swt/apps/ImageViewer1.java


1   package com.port80.swt.apps;
2   
3   import java.io.InputStream;
4   import java.net.URL;
5   import java.text.MessageFormat;
6   
7   import org.eclipse.swt.SWT;
8   import org.eclipse.swt.SWTException;
9   import org.eclipse.swt.custom.StyledText;
10  import org.eclipse.swt.events.ControlAdapter;
11  import org.eclipse.swt.events.ControlEvent;
12  import org.eclipse.swt.events.DisposeEvent;
13  import org.eclipse.swt.events.DisposeListener;
14  import org.eclipse.swt.events.MouseEvent;
15  import org.eclipse.swt.events.MouseMoveListener;
16  import org.eclipse.swt.events.PaintEvent;
17  import org.eclipse.swt.events.PaintListener;
18  import org.eclipse.swt.events.SelectionAdapter;
19  import org.eclipse.swt.events.SelectionEvent;
20  import org.eclipse.swt.events.ShellAdapter;
21  import org.eclipse.swt.events.ShellEvent;
22  import org.eclipse.swt.graphics.Color;
23  import org.eclipse.swt.graphics.Cursor;
24  import org.eclipse.swt.graphics.Font;
25  import org.eclipse.swt.graphics.GC;
26  import org.eclipse.swt.graphics.Image;
27  import org.eclipse.swt.graphics.ImageData;
28  import org.eclipse.swt.graphics.ImageLoader;
29  import org.eclipse.swt.graphics.RGB;
30  import org.eclipse.swt.graphics.Rectangle;
31  import org.eclipse.swt.layout.GridData;
32  import org.eclipse.swt.layout.GridLayout;
33  import org.eclipse.swt.layout.RowLayout;
34  import org.eclipse.swt.widgets.Button;
35  import org.eclipse.swt.widgets.Canvas;
36  import org.eclipse.swt.widgets.Combo;
37  import org.eclipse.swt.widgets.Composite;
38  import org.eclipse.swt.widgets.Dialog;
39  import org.eclipse.swt.widgets.Display;
40  import org.eclipse.swt.widgets.FileDialog;
41  import org.eclipse.swt.widgets.Label;
42  import org.eclipse.swt.widgets.Menu;
43  import org.eclipse.swt.widgets.MenuItem;
44  import org.eclipse.swt.widgets.MessageBox;
45  import org.eclipse.swt.widgets.Sash;
46  import org.eclipse.swt.widgets.ScrollBar;
47  import org.eclipse.swt.widgets.Shell;
48  import org.eclipse.swt.widgets.Text;
49  
50  import com.port80.eclipse.util.UIUtil;
51  import com.port80.util.Msg;
52  import com.port80.util.Sprint;
53  import com.port80.util.SystemWatch;
54  
55  /**
56   * An image viewer using swt.
57   * 
58   * <li>A GC can be created on an Image and then use it to draw into the Image.</li>
59   * <li>To display very large image, pixel data is loaded into ImageData and then
60   * tiles of the data are used to create Image's for display.</li>
61   * 
62   * @author chrisl
63   */
64  public class ImageViewer1 {
65  
66    ////////////////////////////////////////////////////////////////////////
67  
68    private static final String NAME = "ImageViewer1";
69  
70    private static final String[] IMAGE_SUFFICES =
71      new String[] {
72        "*.bmp; *.gif; *.ico; *.jpg; *.pcx; *.png; *.tif",
73        "*.bmp",
74        "*.gif",
75        "*.ico",
76        "*.jpg",
77        "*.pcx",
78        "*.png",
79        "*.tif" };
80  
81    private static final String[] IMAGE_FILTER_NAMES =
82      new String[] {
83        i18n("All_images") + " (bmp, gif, ico, jpg, pcx, png, tif)",
84        "BMP (*.bmp)",
85        "GIF (*.gif)",
86        "ICO (*.ico)",
87        "JPEG (*.jpg)",
88        "PCX (*.pcx)",
89        "PNG (*.png)",
90        "TIFF (*.tif)" };
91  
92    ////////////////////////////////////////////////////////////////////////
93  
94    private Display fDisplay;
95    private Shell fShell;
96    private Font fFont;
97    private Color fWhiteColor, fBlackColor, fLightColor;
98    private Cursor fCrossCursor;
99    private GC fImageCanvasGC;
100   private Image fImage;
101   private ImageData[] fImageDatas;
102   private ImageData fImageData; // the currently-displayed image data
103   private int fImageDataIndex;
104   private double fScale;
105   private int fX = 0, fY = 0; // Top left corner, used to scroll the image and palette
106   private String fLastPath;
107   private boolean fTransparent, fShowMask;
108   private boolean fIncremental;
109   //
110   private long fLoadTime;
111   private String fFilename;
112   //
113   // Widgets
114   private Combo fScaleCombo;
115   private Canvas fImageCanvas;
116   private Sash fSash;
117   private Label fDataLabel, fStatusLabel;
118   private StyledText fDataText;
119   private Label fInfoLabel;
120   //
121   private boolean isResizing;
122 
123   ////////////////////////////////////////////////////////////////////////
124 
125   public static void main(String[] args) {
126 
127     Display display = new Display();
128     ImageViewer1 app = new ImageViewer1();
129     Shell shell = app.open(display);
130 
131     while (!shell.isDisposed())
132       if (!display.readAndDispatch())
133         display.sleep();
134     display.dispose();
135   }
136 
137   ////////////////////////////////////////////////////////////////////////
138 
139   public Shell open(Display display) {
140 
141     // Create a window and set its title.
142     this.fDisplay = display;
143     this.fShell = new Shell(fDisplay);
144 
145     // Create colors and fonts.
146     fWhiteColor = new Color(display, 255, 255, 255);
147     fBlackColor = new Color(display, 0, 0, 0);
148     fLightColor = new Color(display, 0xd8, 0xd8, 0xd8);
149     fFont = new Font(display, "verdana", 11, 0);
150     fCrossCursor = new Cursor(display, SWT.CURSOR_CROSS);
151 
152     fShell.setText(NAME);
153 
154     // Hook resize and dispose listeners.
155     fShell.addControlListener(new ControlAdapter() {
156       public void controlResized(ControlEvent event) {
157         resizeShell(event);
158       }
159     });
160     fShell.addShellListener(new ShellAdapter() {
161       public void shellClosed(ShellEvent e) {
162         e.doit = true;
163       }
164     });
165     fShell.addDisposeListener(new DisposeListener() {
166       public void widgetDisposed(DisposeEvent e) {
167         dispose();
168       }
169     });
170 
171     // Add a menu bar and widgets.
172     createMenuBar();
173     createWidgets();
174     fShell.pack();
175 
176     // Create a GC for drawing, and hook the listener to dispose it.
177     fImageCanvasGC = new GC(fImageCanvas);
178     fImageCanvas.addDisposeListener(new DisposeListener() {
179       public void widgetDisposed(DisposeEvent e) {
180         disposeImageCanvasGC();
181       }
182     });
183 
184     // Open the window
185     fShell.open();
186     return fShell;
187   }
188 
189   void dispose() {
190     // Clean up.
191     fWhiteColor.dispose();
192     fBlackColor.dispose();
193     fLightColor.dispose();
194     fFont.dispose();
195     fCrossCursor.dispose();
196   }
197 
198   void disposeImageCanvasGC() {
199     fImageCanvasGC.dispose();
200   }
201 
202   Shell getShell() {
203     return fShell;
204   }
205   
206   Display getDisplay() {
207     return fDisplay;
208   }
209   
210   Image getImage() {
211     return fImage;
212   }
213 
214   void createWidgets() {
215     // Add the widgets to the shell in a grid layout.
216     GridLayout layout = new GridLayout();
217     layout.marginHeight = 0;
218     layout.numColumns = 2;
219     fShell.setLayout(layout);
220 
221     // Add a composite to contain some control widgets across the top.
222     Composite controls = new Composite(fShell, SWT.NULL);
223     RowLayout rowLayout = new RowLayout();
224     rowLayout.marginTop = 2;
225     rowLayout.marginBottom = 2;
226     rowLayout.spacing = 8;
227     controls.setLayout(rowLayout);
228     controls.setLayoutData(UIUtil.fillCell(1, 1, false, false));
229 
230     // RowLayout is top aligned. To make label text at middle, need to set label height.
231     fInfoLabel = new Label(fShell, SWT.NULL);
232     fInfoLabel.setToolTipText("Image info");
233     fInfoLabel.setText("Image info");
234     fInfoLabel.setLayoutData(UIUtil.fillCell(1, 1, true, false));
235     // Combo to change the x scale.
236     String[] values =
237       {
238         "5 %",
239         "10 %",
240         "25 %",
241         "33 %",
242         "50 %",
243         "75 %",
244         "100 %",
245         "125 %",
246         "133 %",
247         "150 %",
248         "175 %",
249         "200 %",
250         "300 %",
251         "500 %",
252         "750 %",
253         "1000 %",
254         };
255     fScaleCombo = new Combo(controls, SWT.DROP_DOWN);
256     for (int i = 0; i < values.length; i++) {
257       fScaleCombo.add(values[i]);
258     }
259     fScaleCombo.setToolTipText("Scale");
260     fScaleCombo.select(fScaleCombo.indexOf("100 %"));
261     fScaleCombo.addSelectionListener(new SelectionAdapter() {
262       public void widgetSelected(SelectionEvent event) {
263         scaleImage();
264       }
265     });
266 
267     // Canvas to show the image.
268     fImageCanvas = new Canvas(fShell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.NO_REDRAW_RESIZE);
269     fImageCanvas.setBackground(fWhiteColor);
270     fImageCanvas.setCursor(fCrossCursor);
271     fImageCanvas.setLayoutData(UIUtil.fillCell(15, 2, 1024, 768, true, true));
272     fImageCanvas.addPaintListener(new PaintListener() {
273       public void paintControl(PaintEvent event) {
274         paintImage(event);
275       }
276     });
277     fImageCanvas.addMouseMoveListener(new MouseMoveListener() {
278       public void mouseMove(MouseEvent event) {
279         showColorAt(event.x, event.y);
280       }
281     });
282 
283     // Set up the image canvas scroll bars.
284     ScrollBar horizontal = fImageCanvas.getHorizontalBar();
285     horizontal.setVisible(true);
286     horizontal.setMinimum(0);
287     horizontal.setEnabled(false);
288     horizontal.addSelectionListener(new SelectionAdapter() {
289       public void widgetSelected(SelectionEvent event) {
290         scrollHorizontally((ScrollBar) event.widget);
291       }
292     });
293     ScrollBar vertical = fImageCanvas.getVerticalBar();
294     vertical.setVisible(true);
295     vertical.setMinimum(0);
296     vertical.setEnabled(false);
297     vertical.addSelectionListener(new SelectionAdapter() {
298       public void widgetSelected(SelectionEvent event) {
299         scrollVertically((ScrollBar) event.widget);
300       }
301     });
302 
303     // Label to show status and cursor location in image.
304     fStatusLabel = new Label(fShell, SWT.NULL);
305     fStatusLabel.setText("");
306     fStatusLabel.setLayoutData(UIUtil.fillCell(1, 2, true, false));
307   }
308 
309   Menu createMenuBar() {
310     // Menu bar.
311     Menu menuBar = new Menu(fShell, SWT.BAR);
312     fShell.setMenuBar(menuBar);
313     createFileMenu(menuBar);
314     return menuBar;
315   }
316 
317   void createFileMenu(Menu menuBar) {
318     // File menu
319     MenuItem item = new MenuItem(menuBar, SWT.CASCADE);
320     item.setText("File");
321     Menu fileMenu = new Menu(fShell, SWT.DROP_DOWN);
322     item.setMenu(fileMenu);
323 
324     item = new MenuItem(fileMenu, SWT.NULL);
325     item.setText("&Open");
326     item.setAccelerator(SWT.CTRL + 'O');
327     item.addSelectionListener(new SelectionAdapter() {
328       public void widgetSelected(SelectionEvent event) {
329         openFile();
330       }
331     });
332 
333     item = new MenuItem(fileMenu, SWT.NULL);
334     item.setText("Open &URL");
335     item.setAccelerator(SWT.CTRL + 'U');
336     item.addSelectionListener(new SelectionAdapter() {
337       public void widgetSelected(SelectionEvent event) {
338         openURL();
339       }
340     });
341 
342     new MenuItem(fileMenu, SWT.SEPARATOR);
343 
344     // File -> Exit
345     item = new MenuItem(fileMenu, SWT.NULL);
346     item.setText("Exit");
347     item.addSelectionListener(new SelectionAdapter() {
348       public void widgetSelected(SelectionEvent event) {
349         getShell().close();
350       }
351     });
352 
353     // Test menu
354     item = new MenuItem(menuBar, SWT.CASCADE);
355 
356   }
357 
358   ////////////////////////////////////////////////////////////////////////
359 
360   public void openFile() {
361     resetScaleCombo();
362 
363     // Get the user to choose an image file.
364     FileDialog fileChooser = new FileDialog(fShell, SWT.OPEN);
365     if (fLastPath != null)
366       fileChooser.setFilterPath(fLastPath);
367     fileChooser.setFilterExtensions(IMAGE_SUFFICES);
368     fileChooser.setFilterNames(IMAGE_FILTER_NAMES);
369     String filename = fileChooser.open();
370     fLastPath = fileChooser.getFilterPath();
371     if (filename == null)
372       return;
373 
374     Cursor waitCursor = new Cursor(fDisplay, SWT.CURSOR_WAIT);
375     fShell.setCursor(waitCursor);
376     fImageCanvas.setCursor(waitCursor);
377     try {
378       clear();
379       ImageLoader loader = new ImageLoader();
380       // Read the new image(s) from the chosen file.
381       SystemWatch timer = new SystemWatch().start();
382       long startTime = System.currentTimeMillis();
383       fImageDatas = loader.load(filename);
384       fLoadTime = System.currentTimeMillis() - startTime;
385       System.err.println(NAME + ".open(): load time=" + timer.stop().toString());
386       if (fImageDatas.length > 0) {
387         // Cache the filename.
388         fFilename = filename;
389 
390         // Display the first image in the file.
391         fImageDataIndex = 0;
392         displayImage(fImageDatas[fImageDataIndex]);
393         resetScrollBars();
394       }
395     } catch (SWTException e) {
396       showErrorDialog(i18n("Loading_lc"), filename, e);
397     } finally {
398       fShell.setCursor(null);
399       fImageCanvas.setCursor(fCrossCursor);
400       waitCursor.dispose();
401     }
402   }
403 
404   public void openURL() {
405     resetScaleCombo();
406 
407     // Get the user to choose an image URL.
408     TextPrompter textPrompter = new TextPrompter(fShell, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
409     textPrompter.setText(i18n("OpenURLDialog"));
410     textPrompter.setMessage(i18n("EnterURL"));
411     String urlname = textPrompter.open();
412     if (urlname == null)
413       return;
414 
415     Cursor waitCursor = new Cursor(fDisplay, SWT.CURSOR_WAIT);
416     fShell.setCursor(waitCursor);
417     fImageCanvas.setCursor(waitCursor);
418     try {
419       clear();
420       URL url = new URL(urlname);
421       InputStream stream = url.openStream();
422       ImageLoader loader = new ImageLoader();
423       // Read the new image(s) from the chosen file.
424       long startTime = System.currentTimeMillis();
425       fImageDatas = loader.load(stream);
426       fLoadTime = System.currentTimeMillis() - startTime;
427       if (fImageDatas.length > 0) {
428         fFilename = null;
429         // Display the first image in the file.
430         fImageDataIndex = 0;
431         displayImage(fImageDatas[fImageDataIndex]);
432         resetScrollBars();
433       }
434     } catch (Exception e) {
435       showErrorDialog(i18n("Loading_lc"), urlname, e);
436     } finally {
437       fShell.setCursor(null);
438       fImageCanvas.setCursor(fCrossCursor);
439       waitCursor.dispose();
440     }
441   }
442 
443   void displayImage(ImageData newImageData) {
444     // Dispose of the old image, if there was one.
445     if (fImage != null)
446       fImage.dispose();
447 
448     try {
449       // Cache the new image and imageData.
450       fImage = new Image(fDisplay, newImageData);
451       fImageData = newImageData;
452     } catch (SWTException e) {
453       showErrorDialog(i18n("Creating_from") + " ", fFilename, e);
454       fImage = null;
455       return;
456     }
457 
458     // Update the widgets with the new image info.
459     String string = createMsg(i18n("Analyzer_on"), fFilename);
460     fShell.setText(string);
461 
462     fInfoLabel.setText(
463       fFilename
464         + ": w="
465         + fImageData.width
466         + ", h="
467         + fImageData.height
468         + ", depth="
469         + fImageData.depth
470         + Sprint.f(" (%.2f)", fLoadTime / 1000f));
471     // Redraw both canvases.
472     fImageCanvas.redraw();
473   }
474 
475   void paintImage(PaintEvent event) {
476     //    Image paintImage = fImage;
477     //    int transparentPixel = fImageData.transparentPixel;
478     //    if (transparentPixel != -1 && !fTransparent) {
479     //      fImageData.transparentPixel = -1;
480     //      paintImage = new Image(fDisplay, fImageData);
481     //    }
482     //    int w = (int) Math.round(fImageData.width * fScale);
483     //    int h = (int) Math.round(fImageData.height * fScale);
484     if (false)
485       Msg.err(
486         NAME
487           + ".paintImage(): event="
488           + event.x
489           + ","
490           + event.y
491           + ","
492           + event.width
493           + ","
494           + event.height
495           + ", fX,fY="
496           + fX
497           + ","
498           + fY);
499     if (fImageData == null)
500       return;
501     int w = fImageData.width;
502     int h = fImageData.height;
503     event.gc.drawImage(fImage, 0, 0, w, h, fX + fImageData.x, fY + fImageData.y, w, h);
504     if (fShowMask && (fImageData.getTransparencyType() != SWT.TRANSPARENCY_NONE)) {
505       ImageData maskImageData = fImageData.getTransparencyMask();
506       Image maskImage = new Image(fDisplay, maskImageData);
507       event.gc.drawImage(
508         maskImage,
509         0,
510         0,
511         fImageData.width,
512         fImageData.height,
513         w + 10 + fX + fImageData.x,
514         fY + fImageData.y,
515         w,
516         h);
517       maskImage.dispose();
518     }
519     //    if (transparentPixel != -1 && !fTransparent) {
520     //      fImageData.transparentPixel = transparentPixel;
521     //      paintImage.dispose();
522     //    }
523   }
524 
525   /*
526    * Called when the mouse moves in the image canvas.
527    * Show the color of the image at the point under the mouse.
528    */
529   void showColorAt(int mx, int my) {
530     if (fImageData == null)
531       return;
532     int x = mx - fImageData.x - fX;
533     int y = my - fImageData.y - fY;
534     showColorForPixel(x, y);
535   }
536 
537   /*
538    * Set the status label to show color information
539    * for the specified pixel in the image.
540    */
541   void showColorForPixel(int x, int y) {
542     if (x >= 0 && x < fImageData.width && y >= 0 && y < fImageData.height) {
543       int pixel = fImageData.getPixel(x, y);
544       RGB rgb = fImageData.palette.getRGB(pixel);
545 
546       Object[] args =
547         { new Integer(x), new Integer(y), new Integer(pixel), Integer.toHexString(pixel), rgb };
548       if (pixel == fImageData.transparentPixel) {
549         fStatusLabel.setText(createMsg("Color at transparent pixel: ", args));
550       } else {
551         fStatusLabel.setText(Sprint.f("Color at: %d,%d=%06x").a(x).a(y).a(pixel).end());
552       }
553     } else {
554       fStatusLabel.setText("");
555     }
556   }
557 
558   /*
559    * Called when a mouse down or key press is detected
560    * in the data text. Show the color of the pixel at
561    * the caret position in the data text.
562    */
563   void showColorForData() {
564   }
565 
566   ////////////////////////////////////////////////////////////////////////
567 
568   /*
569    * Called when the image canvas' horizontal scrollbar is selected.
570    */
571   void scrollHorizontally(ScrollBar scrollBar) {
572     if (fImage == null)
573       return;
574     Rectangle canvasBounds = fImageCanvas.getClientArea();
575     int width = (int) Math.round(fImageData.width);
576     int height = (int) Math.round(fImageData.height);
577     if (width > canvasBounds.width) {
578       // Only scroll if the image is bigger than the canvas.
579       int x = -scrollBar.getSelection();
580       if (x + width < canvasBounds.width) {
581         // Don't scroll past the end of the image.
582         x = canvasBounds.width - width;
583       }
584       fImageCanvas.scroll(x, fY, fX, fY, width, height, false);
585       fX = x;
586     }
587   }
588 
589   /*
590    * Called when the image canvas' vertical scrollbar is selected.
591    */
592   void scrollVertically(ScrollBar scrollBar) {
593     if (fImage == null)
594       return;
595     Rectangle canvasBounds = fImageCanvas.getClientArea();
596     int width = (int) Math.round(fImageData.width);
597     int height = (int) Math.round(fImageData.height);
598     if (height > canvasBounds.height) {
599       // Only scroll if the image is bigger than the canvas.
600       int y = -scrollBar.getSelection();
601       if (y + height < canvasBounds.height) {
602         // Don't scroll past the end of the image.
603         y = canvasBounds.height - height;
604       }
605       fImageCanvas.scroll(fX, y, fX, fY, width, height, false);
606       fY = y;
607     }
608   }
609 
610   /*
611    * Called when the ScaleX combo selection changes.
612    */
613   void scaleImage() {
614     try {
615       String text = fScaleCombo.getText();
616       int index = text.indexOf(' ');
617       fScale = Float.parseFloat(text.substring(0, index)) / 100;
618     } catch (NumberFormatException e) {
619       fScale = 1;
620       fScaleCombo.select(fScaleCombo.indexOf("100 %"));
621     }
622     if (fImage == null)
623       return;
624     // Scale image to a new buffer.
625     fImageData = fImageDatas[fImageDataIndex];
626     if (fScale != 1) {
627       fImageData =
628         fImageData.scaledTo(
629           (int) Math.round(fImageData.width * fScale),
630           (int) Math.round(fImageData.height * fScale));
631     }
632     resizeScrollBars();
633     fX = -fImageCanvas.getHorizontalBar().getSelection();
634     fY = -fImageCanvas.getVerticalBar().getSelection();
635     displayImage(fImageData);
636   }
637 
638   // Reset the scale combos to 1.
639   void resetScaleCombo() {
640     fScale = 1;
641     fScaleCombo.select(fScaleCombo.indexOf("100 %"));
642   }
643 
644   // Reset the scroll bars to 0.
645   void resetScrollBars() {
646     if (fImage == null)
647       return;
648     fX = 0;
649     fY = 0;
650     resizeScrollBars();
651     fImageCanvas.getHorizontalBar().setSelection(0);
652     fImageCanvas.getVerticalBar().setSelection(0);
653   }
654 
655   void resizeScrollBars() {
656     // Set the max and thumb for the image canvas scroll bars.
657     ScrollBar horizontal = fImageCanvas.getHorizontalBar();
658     ScrollBar vertical = fImageCanvas.getVerticalBar();
659     Rectangle canvasBounds = fImageCanvas.getClientArea();
660     int width = (int) Math.round(fImageData.width);
661     if (width > canvasBounds.width) {
662       // The image is wider than the canvas.
663       // Set selection such as to keep top left corner of the image stationary.
664       int x = horizontal.getSelection() * width / horizontal.getMaximum();
665       horizontal.setEnabled(true);
666       horizontal.setMaximum(width);
667       horizontal.setSelection(x);
668       horizontal.setThumb(canvasBounds.width);
669       horizontal.setPageIncrement(canvasBounds.width);
670     } else {
671       // The canvas is wider than the image.
672       horizontal.setEnabled(false);
673       if (fX != 0) {
674         // Make sure the image is completely visible.
675         fX = 0;
676         fImageCanvas.redraw();
677       }
678     }
679     int height = (int) Math.round(fImageData.height);
680     if (height > canvasBounds.height) {
681       // The image is taller than the canvas.
682       // Set selection such as to keep top left corner of the image stationary.
683       vertical.setEnabled(true);
684       vertical.setMaximum(height);
685       vertical.setThumb(canvasBounds.height);
686       vertical.setPageIncrement(canvasBounds.height);
687     } else {
688       // The canvas is taller than the image.
689       vertical.setEnabled(false);
690       if (fY != 0) {
691         // Make sure the image is completely visible.
692         fY = 0;
693         fImageCanvas.redraw();
694       }
695     }
696   }
697 
698   void resizeShell(ControlEvent event) {
699     if (isResizing)
700       return;
701     if (fImage == null || fShell.isDisposed())
702       return;
703     isResizing = true;
704     resizeScrollBars();
705     isResizing = false;
706   }
707 
708   void clear() {
709     fImageDatas = null;
710     fImageData = null;
711     if (fImage != null)
712       fImage.dispose();
713     fImage = null;
714   }
715 
716   ////////////////////////////////////////////////////////////////////////
717 
718   /*
719    * Open an error dialog displaying the specified information.
720    */
721   void showErrorDialog(String operation, String filename, Exception e) {
722     MessageBox box = new MessageBox(fShell, SWT.ICON_ERROR);
723     String message = createMsg(i18n("Error"), new String[] { operation, filename });
724     String errorMessage = "";
725     if (e != null) {
726       if (e instanceof SWTException) {
727         SWTException swte = (SWTException) e;
728         errorMessage = swte.getMessage();
729         if (swte.throwable != null) {
730           errorMessage += ":\n" + swte.throwable.toString();
731         }
732       } else {
733         errorMessage = e.toString();
734       }
735     }
736     box.setMessage(message + errorMessage);
737     box.open();
738   }
739 
740   /*
741    * Return a String describing the specified image file type.
742    */
743   static String fileTypeString(int filetype) {
744     if (filetype == SWT.IMAGE_BMP)
745       return "BMP";
746     if (filetype == SWT.IMAGE_GIF)
747       return "GIF";
748     if (filetype == SWT.IMAGE_ICO)
749       return "ICO";
750     if (filetype == SWT.IMAGE_JPEG)
751       return "JPEG";
752     if (filetype == SWT.IMAGE_PNG)
753       return "PNG";
754     return i18n("Unknown_ac") + ": " + filetype;
755   }
756 
757   static String createMsg(String msg, Object arg) {
758     MessageFormat formatter = new MessageFormat(msg);
759     return formatter.format(new Object[] { arg });
760   }
761 
762   static String i18n(String str) {
763     return str;
764   }
765 
766   ////////////////////////////////////////////////////////////////////////
767 
768   class TextPrompter extends Dialog {
769     String message = "";
770     String result = null;
771     Shell dialog;
772     Text text;
773     public TextPrompter(Shell parent, int style) {
774       super(parent, style);
775     }
776     public TextPrompter(Shell parent) {
777       this(parent, SWT.APPLICATION_MODAL);
778     }
779     public String getMessage() {
780       return message;
781     }
782     public void setMessage(String string) {
783       message = string;
784     }
785     public String open() {
786       dialog = new Shell(getParent(), getStyle());
787       dialog.setText(getText());
788       dialog.setLayout(new GridLayout());
789       Label label = new Label(dialog, SWT.NULL);
790       label.setText(message);
791       label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
792       text = new Text(dialog, SWT.SINGLE | SWT.BORDER);
793       GridData data = new GridData(GridData.FILL_HORIZONTAL);
794       data.widthHint = 300;
795       text.setLayoutData(data);
796       Composite buttons = new Composite(dialog, SWT.NONE);
797       GridLayout grid = new GridLayout();
798       grid.numColumns = 2;
799       buttons.setLayout(grid);
800       buttons.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
801       Button ok = new Button(buttons, SWT.PUSH);
802       ok.setText(i18n("OK"));
803       data = new GridData();
804       data.widthHint = 75;
805       ok.setLayoutData(data);
806       ok.addSelectionListener(new SelectionAdapter() {
807         public void widgetSelected(SelectionEvent e) {
808           result = text.getText();
809           dialog.dispose();
810         }
811       });
812       Button cancel = new Button(buttons, SWT.PUSH);
813       cancel.setText(i18n("Cancel"));
814       data = new GridData();
815       data.widthHint = 75;
816       cancel.setLayoutData(data);
817       cancel.addSelectionListener(new SelectionAdapter() {
818         public void widgetSelected(SelectionEvent e) {
819           dialog.dispose();
820         }
821       });
822       dialog.setDefaultButton(ok);
823       dialog.pack();
824       dialog.open();
825       while (!dialog.isDisposed()) {
826         if (!getDisplay().readAndDispatch())
827           getDisplay().sleep();
828       }
829       return result;
830     }
831   }
832 
833   ////////////////////////////////////////////////////////////////////////
834 
835 }