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 }