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