001    /*
002     * JiuAwtFrame
003     * 
004     * Copyright (c) 2001, 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.gui.awt;
009    
010    import java.awt.BorderLayout;
011    import java.awt.Cursor;
012    import java.awt.Dimension;
013    import java.awt.Frame;
014    import java.awt.Image;
015    import java.awt.Label;
016    import java.awt.ScrollPane;
017    import java.awt.Toolkit;
018    import java.awt.event.ActionEvent;
019    import java.awt.event.ActionListener;
020    import java.awt.event.ComponentListener;
021    import java.awt.event.ComponentEvent;
022    import java.awt.event.WindowAdapter;
023    import java.awt.event.WindowEvent;
024    import net.sourceforge.jiu.apps.EditorState;
025    import net.sourceforge.jiu.apps.ImageDescriptionCreator;
026    import net.sourceforge.jiu.apps.JiuInfo;
027    import net.sourceforge.jiu.apps.StringIndexConstants;
028    import net.sourceforge.jiu.apps.Strings;
029    import net.sourceforge.jiu.data.PixelImage;
030    import net.sourceforge.jiu.gui.awt.AwtMenuWrapper;
031    import net.sourceforge.jiu.gui.awt.ImageCanvas;
032    import net.sourceforge.jiu.gui.awt.dialogs.InfoDialog;
033    import net.sourceforge.jiu.ops.ProgressListener;
034    
035    /**
036     * The frame class for the AWT demo program {@link net.sourceforge.jiu.apps.jiuawt}.
037     * @author Marco Schmidt
038     * @since 0.8.0
039     */
040    public class JiuAwtFrame extends Frame implements ActionListener, ComponentListener, JiuInfo, ProgressListener
041    {
042            /**
043             * The name of this application, jiuawt, plus the version number taken
044             * from {@link JiuInfo}.
045             * Example: <code>jiuawt 0.8.0</code>.
046             * Will be displayed in the title bar of this frame.
047             */
048            public static final String APP_NAME = "jiuawt " + JiuInfo.JIU_VERSION;
049            private EditorState editor;
050            private AwtMenuWrapper menuWrapper;
051            private AwtOperationProcessor processor;
052            private Label statusBar;
053            private ScrollPane scrollPane;
054            private ImageCanvas canvas;
055    
056            /**
057             * Create an object of this class, using the argument editor
058             * state.
059             * String resources to initialize the menu etc. will be taken
060             * from the EditorState object's Strings variable
061             * @param editorState EditorState object used by this frame
062             */
063            public JiuAwtFrame(EditorState editorState)
064            {
065                    super(APP_NAME);
066                    processor = new AwtOperationProcessor(editorState, this);
067                    editor = editorState;
068                    editor.addProgressListener(this);
069                    addComponentListener(this);
070                    addWindowListener(new WindowAdapter()
071                    {
072                    public void windowClosing(WindowEvent e)
073                    {
074                            processor.fileExit();
075                    }
076            });
077                    // MENU
078                    menuWrapper = new AwtMenuWrapper(editor.getStrings(), this);
079                    setMenuBar(menuWrapper.getMenuBar());
080                    menuWrapper.updateEnabled(processor);
081                    // IMAGE CANVAS
082                    // STATUS BAR
083                    statusBar = new Label("");
084                    add(statusBar, BorderLayout.SOUTH);
085                    maximize();
086                    //pack();
087                    repaint();
088                    setVisible(true);
089                    if (editor.getStartupImageName() != null)
090                    {
091                            processor.fileOpen();
092                    }
093            }
094    
095            /**
096             * Processes event objects that get created when menu items are
097             * picked.
098             * Determines the {@link net.sourceforge.jiu.apps.MenuIndexConstants} value for a given
099             * event object and calls the internal {@link AwtOperationProcessor}
100             * object's process method with the menu value.
101             * The operation will then be performed.
102             * @param e the ActionEvent object
103             */
104            public void actionPerformed(ActionEvent e)
105            {
106                    Object source = e.getSource();
107                    int index = menuWrapper.findIndex(source);
108                    if (index != -1)
109                    {
110                            processor.process(index);
111                    }
112            }
113    
114            public void componentHidden(ComponentEvent e)
115            {
116            }
117    
118            public void componentMoved(ComponentEvent e)
119            {
120            }
121    
122            public void componentResized(ComponentEvent e)
123            {
124                    if (scrollPane != null)
125                    {
126                            canvas.computeZoomToFitSize();
127                            scrollPane.doLayout();
128                    }
129            }
130    
131            public void componentShown(ComponentEvent e)
132            {
133            }
134    
135            /**
136             * Maximize the frame on the desktop.
137             * There is no such function in the 1.1 AWT (was added in 1.4), so
138             * this class determines the screen size and sets the frame to be 
139             * a little smaller than that (to make up for task bars etc.).
140             * So this is just a heuristical approach.
141             */
142            public void maximize()
143            {
144                    /*
145                    The following line:
146                    setExtendedState(getExtendedState() | MAXIMIZED_BOTH);
147                    does a nice maximization, but works only with Java 1.4+
148                    */
149                    Toolkit toolkit = Toolkit.getDefaultToolkit();
150                    if (toolkit == null)
151                    {
152                            return;
153                    }
154                    Dimension screenSize = toolkit.getScreenSize();
155                    if (screenSize == null)
156                    {
157                            return;
158                    }
159                    int w = screenSize.width;
160                    int h = screenSize.height;
161                    int x = 20;
162                    int y = 80;
163                    setLocation(x / 2, y / 2);
164                    setSize(w - x, h - y);
165            }
166    
167            /**
168             * Displays the argument text in a message box with
169             * error in the title bar.
170             * @param text the error message to be displayed
171             */
172            public void showError(String text)
173            {
174                    Strings strings = editor.getStrings();
175                    showInfo(strings.get(StringIndexConstants.ERROR_MESSAGE), text);
176            }
177    
178            /**
179             * Sets the current cursor to be {@link java.awt.Cursor#DEFAULT_CURSOR}.
180             */
181            public void setDefaultCursor()
182            {
183                    Cursor cursor = new Cursor(Cursor.DEFAULT_CURSOR);
184                    setCursor(cursor);
185            }
186    
187            /**
188             * If an image is currently loaded,
189             */
190            public void setOriginalSize()
191            {
192                    if (canvas != null && !editor.isZoomOriginalSize())
193                    {
194                            editor.zoomSetOriginalSize();
195                            canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
196                            updateTitle();
197                            menuWrapper.updateEnabled(processor);
198                    }
199            }
200    
201            public void setProgress(int zeroBasedIndex, int totalItems)
202            {
203                    if (totalItems < 1)
204                    {
205                            throw new IllegalArgumentException("Total number of items (second parameter) must be larger than zero.");
206                    }
207                    if (zeroBasedIndex < 0)
208                    {
209                            throw new IllegalArgumentException("Zero-based index must be at least zero.");
210                    }
211                    if (zeroBasedIndex >= totalItems)
212                    {
213                            throw new IllegalArgumentException("Zero-based index must be smaller than total " +
214                                    "number of items; zeroBasedIndex=" + zeroBasedIndex + ", totalItems=" +
215                                    totalItems);
216                    }
217                    setProgress((float)(zeroBasedIndex + 1) / (float)totalItems);
218            }
219    
220            /**
221             * Set a new progress status.
222             * @param progress float from 0.0f to 1.0f, indicating the progress between 0 and 100 percent 
223             */
224            public void setProgress(float progress)
225            {
226                    if (progress >= 0.0f && progress <= 1.0f)
227                    {
228                            setStatusBar(" " + Math.round(progress * 100.0f) + "%");
229                    }
230            }
231    
232            public void setStatusBar(String text)
233            {
234                    statusBar.setText(text);
235            }
236    
237            public void setWaitCursor()
238            {
239                    Cursor cursor = new Cursor(Cursor.WAIT_CURSOR);
240                    setCursor(cursor);
241            }
242    
243            /**
244             * Shows a modal dialog with given title bar and message text.
245             * @param title will be displayed in the dialog's title bar
246             * @param text will be displayed in the dialog's center part
247             */
248            public void showInfo(String title, String text)
249            {
250                    InfoDialog d = new InfoDialog(this, title, text);
251                    d.show();
252            }
253    
254            /**
255             * If there is an image loaded, forces a canvas redraw by 
256             * calling repaint.
257             */
258            public void updateCanvas()
259            {
260                    if (canvas != null)
261                    {
262                            canvas.setInterpolation(editor.getInterpolation());
263                            //canvas.revalidate();
264                            canvas.repaint();
265                    }
266            }
267    
268            /**
269             * Removes the current canvas from the frame (if there
270             * is an image loaded) and creates a new canvas for the
271             * current image.
272             */
273            public void updateImage()
274            {
275                    PixelImage image = editor.getImage();
276                    if (scrollPane != null)
277                    {
278                            remove(scrollPane);
279                    }
280                    if (image != null)
281                    {
282                            //editor.zoomSetOriginalSize();
283                            Image awtImage = ImageCreator.convertToAwtImage(image, RGBA.DEFAULT_ALPHA);
284                            scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
285                            canvas = new ImageCanvas(scrollPane);
286                            canvas.setInterpolation(editor.getInterpolation());
287                            canvas.setZoomToFit(editor.getZoomToFit());
288                            canvas.setImage(awtImage);
289                            canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
290                            //canvas.computeZoomToFitSize();
291                            scrollPane.add(canvas);
292                            add(scrollPane);
293                    }
294                    updateStatusBar();
295                    updateTitle();
296                    validate();
297                    menuWrapper.updateEnabled(processor);
298            }
299    
300            /**
301             * Creates a description string for the current image and sets the
302             * status bar to that text.
303             */
304            public void updateStatusBar()
305            {
306                    PixelImage image = editor.getImage();
307                    String statusBarText;
308                    if (image == null)
309                    {
310                            statusBarText = "";
311                    }
312                    else
313                    {
314                            statusBarText = ImageDescriptionCreator.getDescription(image, editor.getLocale(), editor.getStrings());
315                    }
316                    setStatusBar(statusBarText);
317            }
318    
319            /**
320             * Sets the frame's title bar to the application name, plus the file name of
321             * the currently loaded image file, plus the current zoom factor, plus an
322             * optional asterisk in case the image was modified but not yet saved.
323             */
324            public void updateTitle()
325            {
326                    StringBuffer sb = new StringBuffer(APP_NAME);
327                    String fileName = editor.getFileName();
328                    if (fileName != null && fileName.length() > 0)
329                    {
330                            sb.append(" [");
331                            sb.append(fileName);
332                            if (editor.getModified())
333                            {
334                                    sb.append('*');
335                            }
336                            sb.append(']');
337                    }
338                    if (editor.getImage() != null)
339                    {
340                            double zoom = editor.getZoomFactorX();
341                            int percent = (int)(zoom * 100.0);
342                            sb.append(' ');
343                            sb.append(Integer.toString(percent));
344                            sb.append('%');
345                    }
346                    setTitle(sb.toString());
347            }
348    
349            /**
350             * If an image is currently displayed, zoom in one level.
351             */
352            public void zoomIn()
353            {
354                    if (canvas != null && !editor.isMaximumZoom())
355                    {
356                            editor.zoomIn();
357                            canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
358                            updateTitle();
359                            menuWrapper.updateEnabled(processor);
360                    }
361            }
362    
363            /**
364             * If an image is currently displayed, zoom out one level.
365             */
366            public void zoomOut()
367            {
368                    if (canvas != null && !editor.isMinimumZoom())
369                    {
370                            editor.zoomOut();
371                            canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
372                            updateTitle();
373                            menuWrapper.updateEnabled(processor);
374                    }
375            }
376    }