001    // This file is part of the Attempto Java Packages.
002    // Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003    //
004    // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005    // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006    // either version 3 of the License, or (at your option) any later version.
007    //
008    // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009    // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010    // PURPOSE. See the GNU Lesser General Public License for more details.
011    //
012    // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013    // Java Packages. If not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.echocomp;
016    
017    import java.util.HashMap;
018    
019    import nextapp.echo2.app.ApplicationInstance;
020    import nextapp.echo2.app.Column;
021    import nextapp.echo2.app.Component;
022    import nextapp.echo2.app.TaskQueueHandle;
023    
024    /**
025     * This abstract class can be used to create components that are initialized asynchronously in the background.
026     * This is makes sense for components that require some time to create themselves (e.g. because of time
027     * expensive calculations). The possibly time consuming creation of the component can be done in a synchronized
028     * way so that at most one such creation process (per application instance) is running at a time.
029     * 
030     * @author Tobias Kuhn
031     */
032    public abstract class DelayedComponent extends Column {
033            
034            private static HashMap<ApplicationInstance, TaskQueueHandle> taskQueues = new HashMap<ApplicationInstance, TaskQueueHandle>();
035            
036            /**
037             * Creates a new delayed component which shows the temporary component until the real component is
038             * ready.
039             * 
040             * @param tempComponent The temporary component.
041             * @param synchronize Defines whether the calculation should be performed in a synchronized way.
042             */
043            public DelayedComponent(Component tempComponent, boolean synchronize) {
044                    if (tempComponent != null) {
045                            add(tempComponent);
046                    }
047                    
048                    final ApplicationInstance application = ApplicationInstance.getActive();
049                    TaskQueueHandle taskQueueTemp = taskQueues.get(application);
050                    if (taskQueueTemp == null) {
051                            taskQueueTemp = application.createTaskQueue();
052                            taskQueues.put(application, taskQueueTemp);
053                    }
054                    final TaskQueueHandle taskQueue = taskQueueTemp;
055                    
056                    if (synchronize) {
057                            
058                            Thread thread = new Thread() {
059                                    public void run() {
060                                            synchronized (application) {
061                                                    final Component c = initComponent();
062                                                    application.enqueueTask(
063                                                            taskQueue,
064                                                            new Runnable() {
065                                                                    public void run() {
066                                                                            DelayedComponent.this.removeAll();
067                                                                            DelayedComponent.this.add(c);
068                                                                            finalizeAction();
069                                                                    }
070                                                            }
071                                                    );
072                                                    try {
073                                                            sleep(500);
074                                                    } catch (InterruptedException ex) {}
075                                            }
076                                    }
077                            };
078                            thread.setPriority(Thread.MIN_PRIORITY);
079                            thread.start();
080                            
081                    } else {
082                            
083                            Thread thread = new Thread() {
084                                    public void run() {
085                                            final Component c = initComponent();
086                                            application.enqueueTask(
087                                                    taskQueue,
088                                                    new Runnable() {
089                                                            public void run() {
090                                                                    DelayedComponent.this.removeAll();
091                                                                    DelayedComponent.this.add(c);
092                                                                    finalizeAction();
093                                                            }
094                                                    }
095                                            );
096                                    }
097                            };
098                            thread.start();
099                            
100                    }
101                    
102            }
103            
104            
105            /**
106             * Creates a new delayed component with the given temporary component. The calculation is
107             * not synchronized.
108             * 
109             * @param tempComponent The temporary component.
110             */
111            public DelayedComponent(Component tempComponent) {
112                    this(tempComponent, false);
113            }
114            
115            
116            /**
117             * Creates a new delayed component with no temporary component.
118             * 
119             * @param synchronize Defines whether the calculation should be performed in a synchronized way.
120             */
121            public DelayedComponent(boolean synchronize) {
122                    this(null, synchronize);
123            }
124            
125            
126            /**
127             * Creates a new delayed component with no temporary component. The calculation is
128             * not synchronized.
129             */
130            public DelayedComponent() {
131                    this(null, false);
132            }
133            
134            /**
135             * This method should contain the (possibly time-consuming) operations to create the actual GUI
136             * component. This operation will be performed asynchronously. As soon as it is finished, the
137             * temporary component (if present) is replaced by the component this method returns.
138             * 
139             * @return The GUI component.
140             */
141            public abstract Component initComponent();
142            
143            /**
144             * Override this method to run code in the appliction context (e.g. for GUI changes) after the
145             * asynchronous operation has finished.
146             */
147            public void finalizeAction() {
148            }
149    
150    }