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 }