001    /*
002      Copyright (C) 2001-2003 Renaud Pawlak <renaud@aopsys.com>
003                              Laurent Martelli <laurent@aopsys.com>
004      
005      This program is free software; you can redistribute it and/or modify
006      it under the terms of the GNU Lesser General Public License as
007      published by the Free Software Foundation; either version 2 of the
008      License, or (at your option) any later version.
009    
010      This program is distributed in the hope that it will be useful,
011      but WITHOUT ANY WARRANTY; without even the implied warranty of
012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013      GNU Lesser General Public License for more details.
014    
015      You should have received a copy of the GNU Lesser General Public License
016      along with this program; if not, write to the Free Software
017      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
018    
019    package org.objectweb.jac.aspects.gui.swing;
020    
021    import java.awt.BorderLayout;
022    import java.awt.Component;
023    import java.awt.Container;
024    import java.awt.Dimension;
025    import java.awt.Rectangle;
026    import java.awt.Toolkit;
027    import java.awt.event.ActionEvent;
028    import java.awt.event.ActionListener;
029    import java.awt.event.ContainerEvent;
030    import java.awt.event.ContainerListener;
031    import java.awt.event.KeyEvent;
032    import java.awt.event.KeyListener;
033    import java.awt.event.WindowAdapter;
034    import java.awt.event.WindowEvent;
035    import java.util.Arrays;
036    import java.util.Map;
037    import javax.swing.BorderFactory;
038    import javax.swing.JButton;
039    import javax.swing.JDialog;
040    import javax.swing.JEditorPane;
041    import javax.swing.JPanel;
042    import org.apache.log4j.Logger;
043    import org.objectweb.jac.aspects.gui.*;
044    import org.objectweb.jac.core.Collaboration;
045    import org.objectweb.jac.core.rtti.FieldItem;
046    import org.objectweb.jac.core.rtti.MethodItem;
047    import org.objectweb.jac.util.Semaphore;
048    import org.objectweb.jac.util.Strings;
049    
050    /**
051     * This dialog is used to ask the parameters values when a method is
052     * called on a viewed JAC object.<p>
053     *
054     * @see View
055     *
056     * @author <a href="mailto:renaud@cnam.fr">Renaud Pawlak</a>
057     * @author <a href="mailto:laurent@aopsys.com">Laurent Martelli</a>
058     */
059    public class Dialog extends JDialog 
060        implements ActionListener, KeyListener, ContainerListener, DialogView
061    {
062        static Logger loggerEvents = Logger.getLogger("gui.events");
063    
064        String label;
065        DisplayContext context;
066        int width;
067        int height;
068        ViewFactory factory;
069        Object[] parameters;
070        String type;
071    
072        boolean ok = false;
073    
074        private JButton okButton;
075        private JButton cancelButton;
076    
077        Semaphore semaphore = new Semaphore();
078        String description;
079        View contentView;
080    
081       /**
082        * Construct a dialog window.
083        *
084        * @param content the content of the dialog
085        * @param parent the parent window of the dialog
086        * @param description a text describing the dialog to the user
087        */
088        public Dialog(View content, Object parent,
089                      String title, String description) {
090            this.description = description;
091            this.contentView = content;
092            setModal(true);
093            setTitle(title);
094    
095            Container contentPane = getContentPane();
096    
097            addWindowListener( new WindowAdapter() {
098                    public void windowClosing(WindowEvent e) {
099                        e.getWindow().dispose();
100                    }
101                }
102            );
103    
104            contentPane.add(BorderLayout.CENTER, (Component)content);
105            content.setParentView(this);
106    
107            if (description != null)
108            {
109                JEditorPane descr = new JEditorPane("text/plain",description);
110                descr.setEditable(false);
111                descr.setBackground(null);
112                contentPane.add(BorderLayout.NORTH,descr);
113            }
114    
115            JPanel p2 = new JPanel();
116            p2.setBorder(BorderFactory.createEtchedBorder());
117            okButton = addButton(p2,"Ok");
118            cancelButton = addButton(p2,"Cancel");
119            getRootPane().setDefaultButton(okButton);
120            contentPane.add(BorderLayout.SOUTH,p2);
121            pack();
122    
123          // open the box centerd in the screen...
124            Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
125            Rectangle rect = getBounds();
126            double left = (screenDim.getWidth()-rect.getWidth())/2;
127            double top = (screenDim.getHeight()-rect.getHeight())/2;
128            Rectangle newRect = new Rectangle(
129                (int)left,(int)top,
130                (int)rect.getWidth(),(int)rect.getHeight());
131            setBounds(newRect);
132          
133            addKeyAndContainerListenerRecursively(this);
134    
135            attributes = Collaboration.get().getAttributes();   
136    
137            setVisible (true);
138            // Do not place anything after this, since this a blocking call
139        }
140    
141        /** Stores context attributes at creation time so they can be
142            restored by components when invoking methods */
143        Map attributes;
144    
145        // View interface
146    
147        Border viewBorder;
148       
149        /**
150         * Get the value of viewBorder.
151         * @return value of viewBorder.
152         */
153        public Border getViewBorder() {
154            return viewBorder;
155        }
156       
157        /**
158         * Set the value of viewBorder.
159         * @param v  Value to assign to viewBorder.
160         */
161        public void setViewBorder(Border  v) {
162            this.viewBorder = v;
163        }
164       
165        // style used to change display (css for web)
166        String style;
167    
168        public void setStyle(String style) {
169            this.style = style;
170        }
171    
172        public String getStyle() {
173            return style;
174        }
175    
176        MethodItem message;
177       
178        /**
179         * Get the value of message.
180         * @return value of message.
181         */
182        public MethodItem getMessage() {
183            return message;
184        }
185    
186        /**
187         * Get the value of description.
188         * @return value of description.
189         */
190        public String getDescription() {
191            return description;
192        }
193       
194        /**
195         * Set the value of description.
196         * @param v  Value to assign to description.
197         */
198        public void setDescription(String  v) {
199            this.description = v;
200        }
201       
202        View parentView;
203       
204       /**
205        * Get the value of parentView.
206        * @return value of parentView.
207        */
208        public View getParentView() {
209            return parentView;
210        }
211       
212        /**
213        * Set the value of parentView.
214        * @param v  Value to assign to parentView.
215        */
216        public void setParentView(View  v) {
217            this.parentView = v;
218        }
219    
220        public View getRootView() {
221            if (parentView==null)
222                return this;
223            return parentView.getRootView();
224        }
225    
226        public boolean isDescendantOf(View ancestor) {
227            if (this==ancestor)
228                return true;
229            else if (parentView==null)
230                return false;
231            else
232                return parentView.isDescendantOf(ancestor);
233        }
234    
235        /**
236        * Set the value of message.
237        * @param v  Value to assign to message.
238        */
239        public void setMessage(MethodItem  v) {
240            this.message = v;
241        }
242    
243        public void setContext(DisplayContext context) {
244            this.context = context;
245        }
246    
247        public DisplayContext getContext() {
248            return context;
249        }
250    
251        public void setFactory(ViewFactory factory) {
252            this.factory = factory;
253        }
254    
255        public ViewFactory getFactory() {
256            return factory;
257        }
258    
259        public void setLabel(String label) {
260            this.label = label;
261            setTitle(label);
262        }
263    
264        public String getLabel() {
265            return label;
266        }
267    
268        public void setWidth(int width) {
269            this.width = width;
270        }
271    
272        public void setHeight(int height) {
273            this.height = height;
274        }
275    
276        public void setType(String type) {
277            this.type = type;
278        }
279    
280        public String getType() {
281            return type;
282        }
283    
284        public void setParameters(Object[] parameters) {
285            this.parameters = parameters;
286        }
287       
288        public Object[] getParameters() {
289            return parameters;
290        }
291    
292        public boolean equalsView(ViewIdentity view) {
293            return 
294                ( ( type!=null && 
295                    type.equals(view.getType()) )
296                  || (type==null && view.getType()==null ) )
297                && ( ( parameters!=null && 
298                       Arrays.equals(parameters,view.getParameters()) ) 
299                     || (parameters==null && view.getParameters()==null) );
300        }
301    
302        public boolean equalsView(String type, Object[] parameters) {
303            return this.type.equals(type)
304                && Arrays.equals(this.parameters,parameters);
305        }
306    
307        public void close(boolean validate) {
308            contentView.close(validate);
309            closed = true;
310            dispose();
311        }
312    
313        boolean closed = false;
314    
315        public boolean isClosed() {
316            return closed;
317        }
318    
319        public void setFocus(FieldItem field, Object option) {
320        }
321    
322        // DialogView interface
323    
324        public boolean waitForClose() {
325            loggerEvents.debug("waiting for "+Strings.hex(this)+" to be closed");
326            semaphore.acquire();
327            loggerEvents.debug("closed "+Strings.hex(this)+" -> "+ok);
328            return ok;
329        }
330    
331        public View getContentView() {
332            return contentView;
333        }
334    
335        public void restoreContext() {
336            loggerEvents.debug("Restoring attributes: "+attributes.keySet());
337            Collaboration.get().setAttributes(attributes);
338        }
339    
340        /**
341         * For internal use.<p>
342         */
343        JButton addButton(Container c, String name)  {
344            JButton button = new JButton(name);
345            button.addActionListener(this);
346            c.add(button);
347            return button;
348        }
349    
350        /**
351         * Implements what is done when a button is pressed (may be either
352         * OK or CANCEL).<p>
353         *
354         * @param evt tell what button was pressed 
355         */
356        public void actionPerformed(ActionEvent evt) {
357            try {
358                Object source = evt.getSource();
359                if (source==okButton) {
360                    ok = true;
361                    semaphore.release();
362                } else if (source == cancelButton) {
363                    ok = false;
364                    semaphore.release();
365                }
366                dispose();
367            } catch (Exception e) {
368                e.printStackTrace();
369            }
370        }
371    
372        // KeyListener interface
373        public void keyPressed(KeyEvent event) {
374            int code = event.getKeyCode();
375            switch (code) {
376                case KeyEvent.VK_ESCAPE:
377                    ok = false;
378                    semaphore.release();
379                    dispose();
380                    break;
381                default:
382            }
383        }
384        public void keyTyped(KeyEvent event) {}
385        public void keyReleased(KeyEvent event) {}
386    
387        // ContainerListener interface
388        // Copied from http://www.javaworld.com/javaworld/javatips/jw-javatip69.html
389    
390        public void componentAdded(ContainerEvent event) {
391            addKeyAndContainerListenerRecursively(event.getChild());
392        }
393    
394        /**
395         * Register as a KeyListener and ContainerListener on the component
396         * and its children recursively.
397         * @param c the component
398         */
399        protected void addKeyAndContainerListenerRecursively(Component c) {
400            c.addKeyListener(this);
401            if (c instanceof Container) {
402                Container cont = (Container)c;
403                cont.addContainerListener(this);
404                Component[] children = cont.getComponents();
405                for(int i=0; i<children.length; i++){
406                    addKeyAndContainerListenerRecursively(children[i]);
407                }
408            }
409        }
410    
411        public void componentRemoved(ContainerEvent event) {
412            removeKeyAndContainerListenerRecursively(event.getChild());
413        }
414    
415        /**
416         * Unregister as a KeyListener and ContainerListener on the
417         * component and its children recursively.
418         * @param c the component 
419         */
420        protected void removeKeyAndContainerListenerRecursively(Component c) {
421            c.removeKeyListener(this);
422            if (c instanceof Container) {
423                Container cont = (Container)c;
424                cont.removeContainerListener(this);
425                Component[] children = cont.getComponents();
426                for(int i=0; i<children.length; i++){
427                    removeKeyAndContainerListenerRecursively(children[i]);
428                }
429            }
430        }
431    }