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 }