source: release-kits/shared/ant-installer/src/org/tp23/antinstaller/runtime/SwingRunner.java@ 17578

Last change on this file since 17578 was 17578, checked in by oranfry, 16 years ago

more HCI changes to the installer: an animated activity indicator during install, better target names for the greenstone2 installers

File size: 12.0 KB
Line 
1/*
2 * Copyright 2005 Paul Hinds
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.tp23.antinstaller.runtime;
17
18import java.awt.GraphicsConfiguration;
19import java.awt.Toolkit;
20import java.awt.Dimension;
21import java.io.ByteArrayOutputStream;
22import java.io.InputStream;
23import java.util.ArrayList;
24import java.util.List;
25import java.util.ResourceBundle;
26
27import javax.swing.ImageIcon;
28import javax.swing.JFrame;
29
30import org.tp23.antinstaller.InstallException;
31import org.tp23.antinstaller.Installer;
32import org.tp23.antinstaller.InstallerContext;
33import org.tp23.antinstaller.ValidationException;
34import org.tp23.antinstaller.antmod.FeedbackListener;
35import org.tp23.antinstaller.page.Page;
36import org.tp23.antinstaller.renderer.AntOutputRenderer;
37import org.tp23.antinstaller.renderer.RendererFactory;
38import org.tp23.antinstaller.renderer.swing.PageCompletionListener;
39import org.tp23.antinstaller.renderer.swing.SizeConstants;
40import org.tp23.antinstaller.renderer.swing.SwingInstallerContext;
41import org.tp23.antinstaller.renderer.swing.SwingMessageRenderer;
42import org.tp23.antinstaller.renderer.swing.SwingPageRenderer;
43
44/**
45 * <p>Runs the installer in a JFrame window </p>
46 * <p>This class uses the Installer object tree as its data source and renderers
47 * from the org.tp23.antinstaller.renderer.swing package </p>
48 * Runners must also create a MessageRenderer and make it available in the
49 * InstallerContext
50 * <p>Copyright: Copyright (c) 2004</p>
51 * <p>Company: tp23</p>
52 *
53 * @author Paul Hinds
54 * @version $Id: SwingRunner.java,v 1.11 2007/01/19 00:24:36 teknopaul Exp $
55 */
56public class SwingRunner extends AntRunner implements Runner, PageCompletionListener {
57
58 protected SwingInstallerContext swingCtx = null;
59 private JFrame frame = new JFrame();
60 private List pageRenderers;
61 private volatile boolean doAnt = false;
62 protected Thread initialThread;
63 protected IfPropertyHelper ifHelper;
64 // context local property refs
65 protected InstallerContext ctx;
66 protected Logger logger;
67 protected Installer installer;
68
69 public SwingRunner(InstallerContext ctx) {
70 super(ctx);
71 swingCtx = new SwingInstallerContext(ctx, frame);
72
73 SwingMessageRenderer smr = new SwingMessageRenderer();
74 smr.setOwner(frame);
75 ctx.setMessageRenderer(smr);
76
77 ctx.setBuildListener(new FeedbackListener(swingCtx));
78
79 ifHelper = new IfPropertyHelper(ctx);
80 logger = ctx.getLogger();
81 installer = ctx.getInstaller();
82 this.ctx = ctx;
83 }
84
85 /**
86 * Renders the installer in a Swing GUI, this method blocks until
87 * the UI has finished
88 *
89 * @return boolean false implies user aborted
90 * @throws InstallException
91 */
92 public boolean runInstaller() throws InstallException {
93 try {
94 frame.setTitle(installer.getName());
95 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
96 frame.setSize(SizeConstants.PAGE_WIDTH, SizeConstants.PAGE_HEIGHT);
97 frame.getRootPane().setDoubleBuffered(true);
98 frame.setResizable( true );
99
100 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
101 frame.setLocation(screenSize.width/2 - frame.getWidth()/2, screenSize.height/2 - frame.getHeight()/2);
102
103 //setLocation(frame);
104 setIcon(frame, installer);
105
106 preparePages(installer.getPages(), ctx);
107 showFirstPage();
108 // need to block here until pages are complete
109 initialThread = Thread.currentThread();
110 try {
111 Thread.sleep(Long.MAX_VALUE);
112 }
113 catch (InterruptedException ex1) {
114
115 }
116 return doAnt;
117 }
118 catch (Exception ex) {
119 logger.log("Fatal exception: " + ex.getMessage());
120 if (ctx.getInstaller().isVerbose()) {
121 logger.log(ex);
122 }
123 ctx.getMessageRenderer().printMessage("Fatal exception: " + ex.getMessage());
124 throw new InstallException("", ex);
125 }
126 }
127
128 public void pageBack(Page page) {
129 if (page.isAbort()) {
130 abort();
131 return;
132 }
133 Page[] pages = installer.getPages();
134 for (int i = 0; i < pages.length; i++) {
135 if (pages[i] == page) {
136 // found current page
137 if (i > 0) {
138
139 //skip pages if the ifTarget or ifProperty attributes exist and fail
140 int nextIdx = i - 1;
141 try {
142 while (true) {
143 if (!ifHelper.ifTarget(pages[nextIdx], pages) ||
144 !ifHelper.ifProperty(pages[nextIdx])) {
145 //Continue looping
146 --nextIdx;
147 } else {
148 break;
149 }
150 }
151 }
152 catch (InstallException instExc) {
153 logger.log("InstallException rendering page:" + page.getName());
154 logger.log(installer, instExc);
155 }
156
157 //for(;ifTargetSkip(pages[nextIdx], pages);nextIdx--);
158
159 SwingPageRenderer renderer = (SwingPageRenderer) pageRenderers.get(nextIdx);
160 ctx.setCurrentPage(pages[nextIdx]);
161 try {
162 renderNext(renderer);
163 }
164 catch (InstallException ex) {
165 logger.log("InstallExcepiton rendering page:" + page.getName());
166 logger.log(installer, ex);
167 }
168 catch (ClassNotFoundException ex) {
169 logger.log("ClassNotFoundException rendering page:" + page.getName());
170 logger.log(installer, ex);
171 }
172 return;
173 }
174 }
175 }
176 }
177
178 /**
179 * Called when a page is complete and the next button is pressed.
180 * This method is called by the event thread that looses exceptions so Throwable
181 * is caught
182 *
183 * @param page Page
184 */
185 public void pageComplete(Page page) {
186 try {
187 if (page.isAbort()) {
188 abort();
189 return;
190 }
191 runPost(page);
192 Page[] pages = installer.getPages();
193 SwingPageRenderer currentRenderer;
194 for (int i = 0; i < pages.length; i++) {
195 if (pages[i] == page) { // found current page
196 currentRenderer = (SwingPageRenderer) pageRenderers.get(i);
197 // check validation
198 boolean validationPassed = false;
199 try {
200 currentRenderer.updateInputFields();
201 validationPassed = currentRenderer.validateFields();
202 } catch (ValidationException ve) {
203 logger.log("ValidationException rendering page:" + page.getName());
204 logger.log(installer, ve);
205 return;
206 }
207 if (!validationPassed) {
208 return;
209 }
210
211
212 if (i < pages.length - 1) {
213
214 //more pages left
215
216 // skip the page if the ifTarget or ifProperty dictate it
217 int nextIdx = i + 1;
218 while (true) {
219 if (!ifHelper.ifTarget(pages[nextIdx], pages) ||
220 !ifHelper.ifProperty(pages[nextIdx])) {
221 //Continue looping
222 nextIdx++;
223 } else {
224 break;
225 }
226 }
227
228
229 SwingPageRenderer renderer = (SwingPageRenderer) pageRenderers.get(nextIdx);
230 ctx.setCurrentPage(pages[nextIdx]);
231 try {
232 renderNext(renderer);
233 }
234 catch (InstallException ex) {
235 logger.log("InstallException rendering page:" + page.getName());
236 logger.log(installer, ex);
237 }
238 catch (ClassNotFoundException ex) {
239 logger.log("ClassNotFoundException rendering page:" + page.getName());
240 logger.log(installer, ex);
241 }
242 return;
243 }
244 if (i == pages.length - 1) {
245 // all done
246 currentRenderer.getBackButton().setEnabled(false);
247 currentRenderer.getNextButton().setEnabled(false);
248 currentRenderer.getFinishButton().setEnabled(false);
249 doAnt = true;
250 initialThread.interrupt();
251 return;
252 }
253 }
254 }
255 }
256 catch (Throwable e) {
257 ctx.log("Throwable during page completion:" + e.getMessage());
258 if (ctx.getInstaller().isVerbose()) {
259 ctx.log(e);
260 }
261 }
262 }
263
264 protected void showFirstPage() throws Exception {
265 ctx.setCurrentPage(installer.getPages()[0]);
266 renderNext((SwingPageRenderer) pageRenderers.get(0));
267 }
268
269
270 private void preparePages(Page[] pages, InstallerContext ctx) throws Exception {
271 pageRenderers = new ArrayList();
272 for (int i = 0; i < pages.length; i++) {
273 SwingPageRenderer renderer = RendererFactory.getSwingPageRenderer(pages[i]);
274 if (i == 0) renderer.getBackButton().setEnabled(false);
275 renderer.setContext(swingCtx);
276 renderer.setPageCompletionListener(this);
277 renderer.setPage(pages[i]);
278 renderer.instanceInit();
279 pageRenderers.add(renderer);
280 if (renderer instanceof AntOutputRenderer) {
281 ctx.setAntOutputRenderer((AntOutputRenderer) renderer);
282 }
283 }
284 }
285
286 protected void renderNext(SwingPageRenderer renderer) throws ClassNotFoundException, InstallException {
287 renderer.reInit();
288 renderer.reInstanceInit();
289
290 renderer.updateDefaultValues();
291 frame.getContentPane().removeAll();
292 frame.getContentPane().add(renderer);
293 frame.getContentPane().repaint();
294 frame.show();
295 if (renderer.getNextButton().isEnabled()) {
296 renderer.getNextButton().requestFocus();
297 } else if (renderer.getFinishButton().isEnabled()) {
298 renderer.getFinishButton().requestFocus();
299 }
300 }
301
302 private void setLocation(JFrame frame) {
303 GraphicsConfiguration config = frame.getGraphicsConfiguration();
304 int x = (int) config.getBounds().getCenterX() - (SizeConstants.PAGE_WIDTH / 2);
305 int y = (int) config.getBounds().getCenterY() - (SizeConstants.PAGE_HEIGHT / 2);
306 frame.setLocation(x, y);
307 frame.setResizable(false);
308 }
309
310 private void setIcon(JFrame frame, Installer installer) {
311 String iconResource = installer.getWindowIcon();
312 try {
313 if (iconResource == null) {
314 return;
315 }
316 InputStream in = this.getClass().getResourceAsStream(iconResource);
317 ByteArrayOutputStream baos = new ByteArrayOutputStream();
318 byte[] buffer = new byte[256];
319 int read = 0; // The number of bytes read from the stream
320 for (read = in.read(buffer); read != -1; read = in.read(buffer)) {
321 baos.write(buffer, 0, read);
322 }
323 ImageIcon icon = new ImageIcon(baos.toByteArray());
324 //Image icon = Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
325 frame.setIconImage(icon.getImage());
326 }
327 catch (Exception ex) {
328 // we can live with out an icon
329 logger.log("Can not load icon resource: " + iconResource);
330 logger.log(installer, ex);
331 }
332 }
333
334 public void antFinished() {
335 SwingPageRenderer renderer = (SwingPageRenderer) pageRenderers.get(pageRenderers.size() - 1);
336 renderer.getBackButton().setEnabled(false);
337 renderer.getNextButton().setEnabled(false);
338 renderer.getCancelButton().setEnabled(false);
339 renderer.getFinishButton().setText(org.tp23.antinstaller.Installer.langPack.getString("exit"));
340 renderer.getFinishButton().setEnabled(true);
341 renderer.getFinishButton().requestFocus();
342 renderer.getTitleLabel().setText(org.tp23.antinstaller.Installer.langPack.getString("complete"));
343 renderer.stopPage();
344 ctx.getAntOutputRenderer().getErr().flush();
345 ctx.getAntOutputRenderer().getOut().flush();
346 ctx.getMessageRenderer().printMessage(org.tp23.antinstaller.Installer.langPack.getString("finished"));
347 }
348
349 public void fatalError() {
350 List renderers = getPageRenderers();
351 if ((renderers != null) && (renderers.size() > 0)) {
352 SwingPageRenderer renderer = (SwingPageRenderer) renderers.get(renderers.size() - 1);
353 renderer.getBackButton().setEnabled(false);
354 renderer.getNextButton().setEnabled(false);
355 renderer.getCancelButton().setEnabled(false);
356 renderer.getFinishButton().setText(org.tp23.antinstaller.Installer.langPack.getString("exit"));
357 renderer.getFinishButton().setEnabled(true);
358 renderer.getFinishButton().requestFocus();
359 renderer.stopPage();
360 renderer.getTitleLabel().setText(org.tp23.antinstaller.Installer.langPack.getString("failed"));
361 }
362 // else - we're done here, or should we call abort()?
363 }
364
365 /**
366 * Returns a string representation of the object.
367 *
368 * @return a string representation of the object.
369 */
370 public String toString() {
371 return "SwingRunner";
372 }
373
374 private void abort() {
375 this.doAnt = false;
376 initialThread.interrupt();
377 }
378
379 /**
380 * @return Returns the frame.
381 */
382 public JFrame getFrame() {
383 return frame;
384 }
385
386 /**
387 * This method is only valid after the PageRenderers have been generated
388 *
389 * @return Returns the pageRenderers.
390 */
391 public List getPageRenderers() {
392 return pageRenderers;
393 }
394}
Note: See TracBrowser for help on using the repository browser.