You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Application.java 28KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. /* *************************************************************************
  2. IT Mill Toolkit
  3. Development of Browser User Interfaces Made Easy
  4. Copyright (C) 2000-2006 IT Mill Ltd
  5. *************************************************************************
  6. This product is distributed under commercial license that can be found
  7. from the product package on license.pdf. Use of this product might
  8. require purchasing a commercial license from IT Mill Ltd. For guidelines
  9. on usage, see licensing-guidelines.html
  10. *************************************************************************
  11. For more information, contact:
  12. IT Mill Ltd phone: +358 2 4802 7180
  13. Ruukinkatu 2-4 fax: +358 2 4802 7181
  14. 20540, Turku email: info@itmill.com
  15. Finland company www: www.itmill.com
  16. Primary source for information and releases: www.itmill.com
  17. ********************************************************************** */
  18. package com.itmill.toolkit;
  19. import com.itmill.toolkit.service.ApplicationContext;
  20. import com.itmill.toolkit.service.License;
  21. import com.itmill.toolkit.terminal.*;
  22. import com.itmill.toolkit.ui.AbstractComponent;
  23. import com.itmill.toolkit.ui.Component;
  24. import com.itmill.toolkit.ui.Window;
  25. import com.itmill.toolkit.ui.Component.Focusable;
  26. import java.util.Collection;
  27. import java.util.Collections;
  28. import java.util.Enumeration;
  29. import java.util.EventListener;
  30. import java.util.EventObject;
  31. import java.util.Hashtable;
  32. import java.util.Iterator;
  33. import java.util.LinkedList;
  34. import java.util.Locale;
  35. import java.util.Properties;
  36. import java.util.Random;
  37. import java.net.MalformedURLException;
  38. import java.net.URL;
  39. /**
  40. * <p>
  41. * Base class required for all IT Mill Toolkit applications. This class provides
  42. * all the basic services required by the toolkit. These services allow external
  43. * discovery and manipulation of the user,
  44. * {@link com.itmill.toolkit.ui.Window windows} and themes, and starting and
  45. * stopping the application.
  46. * </p>
  47. *
  48. * <p>
  49. * As mentioned, all IT Mill Toolkit applications must inherit this class.
  50. * However, this is almost all of what one needs to do to create a fully
  51. * functional application. The only thing a class inheriting the
  52. * <code>Application</code> needs to do is implement the <code>init</code>
  53. * method where it creates the windows it needs to perform its function. Note
  54. * that all applications must have at least one window: the main window. The
  55. * first unnamed window constructed by an application automatically becomes the
  56. * main window which behaves just like other windows with one exception: when
  57. * accessing windows using URLs the main window corresponds to the application
  58. * URL whereas other windows correspond to a URL gotten by catenating the
  59. * window's name to the application URL.
  60. * </p>
  61. *
  62. * <p>
  63. * See the class <code>com.itmill.toolkit.demo.HelloWorld</code> for a simple
  64. * example of a fully working application.
  65. * </p>
  66. *
  67. * <p>
  68. * <strong>Window access.</strong> <code>Application</code> provides methods
  69. * to list, add and remove the windows it contains.
  70. * </p>
  71. *
  72. * <p>
  73. * <strong>Execution control.</strong> This class includes method to start and
  74. * finish the execution of the application. Being finished means basically that
  75. * no windows will be available from the application anymore.
  76. * </p>
  77. *
  78. * <p>
  79. * <strong>Theme selection.</strong> The theme selection process allows a theme
  80. * to be specified at three different levels. When a window's theme needs to be
  81. * found out, the window itself is queried for a preferred theme. If the window
  82. * does not prefer a specific theme, the application containing the window is
  83. * queried. If neither the application prefers a theme, the default theme for
  84. * the {@link com.itmill.toolkit.terminal.Terminal terminal} is used. The
  85. * terminal always defines a default theme.
  86. * </p>
  87. *
  88. * @author IT Mill Ltd.
  89. * @version
  90. * @VERSION@
  91. * @since 3.0
  92. */
  93. public abstract class Application implements URIHandler, Terminal.ErrorListener {
  94. /**
  95. * Random window name generator.
  96. */
  97. private static Random nameGenerator = new Random();
  98. /**
  99. * Application context the application is running in.
  100. */
  101. private ApplicationContext context;
  102. /**
  103. * The current user or <code>null</code> if no user has logged in.
  104. */
  105. private Object user;
  106. /**
  107. * Mapping from window name to window instance.
  108. */
  109. private Hashtable windows = new Hashtable();
  110. /**
  111. * Main window of the application.
  112. */
  113. private Window mainWindow = null;
  114. /**
  115. * The application's URL.
  116. */
  117. private URL applicationUrl;
  118. /**
  119. * Name of the theme currently used by the application.
  120. */
  121. private String theme = null;
  122. /**
  123. * Application status.
  124. */
  125. private boolean applicationIsRunning = false;
  126. /**
  127. * Application properties.
  128. */
  129. private Properties properties;
  130. /**
  131. * Default locale of the application.
  132. */
  133. private Locale locale;
  134. /**
  135. * List of listeners listening user changes.
  136. */
  137. private LinkedList userChangeListeners = null;
  138. /**
  139. * Window attach listeners.
  140. */
  141. private LinkedList windowAttachListeners = null;
  142. /**
  143. * Window detach listeners.
  144. */
  145. private LinkedList windowDetachListeners = null;
  146. /**
  147. * License for running this application.
  148. */
  149. private License license = null;
  150. /**
  151. * Application resource mapping: key <-> resource.
  152. */
  153. private Hashtable resourceKeyMap = new Hashtable();
  154. private Hashtable keyResourceMap = new Hashtable();
  155. private long lastResourceKeyNumber = 0;
  156. /**
  157. * URL the user is redirected to on application close or null if application
  158. * is just closed
  159. */
  160. private String logoutURL = null;
  161. private Focusable pendingFocus;
  162. /**
  163. * Flag to indicate if first ajax request is sent
  164. */
  165. private boolean ajaxInitSent = false;
  166. /**
  167. * This function should anly be called in AjaxApplicationManager to
  168. * tell ajax engine (browser) that this is application restart. Returns
  169. * true on first call, false on subsequent calls.
  170. *
  171. * TODO consider moving this to WebApplicationContext
  172. *
  173. * @return true if in ajax init state
  174. */
  175. public boolean ajaxInit() {
  176. if(this.ajaxInitSent) {
  177. return false;
  178. } else {
  179. return this.ajaxInitSent = true;
  180. }
  181. }
  182. /**
  183. * <p>
  184. * Gets a window by name. Returns <code>null</code> if the application is
  185. * not running or it does not contain a window corresponding to the name.
  186. * </p>
  187. *
  188. * @param name
  189. * the name of the window.
  190. * @return the window associated with the given URI or <code>null</code>
  191. */
  192. public Window getWindow(String name) {
  193. // For closed app, do not give any windows
  194. if (!isRunning())
  195. return null;
  196. // Gets the window by name
  197. Window window = (Window) windows.get(name);
  198. return window;
  199. }
  200. /**
  201. * Adds a new window to the application.
  202. *
  203. * <p>
  204. * This implicitly invokes the
  205. * {@link com.itmill.toolkit.ui.Window#setApplication(Application)} method.
  206. * </p>
  207. *
  208. * @param window
  209. * the new <code>Window</code> to add.
  210. * @throws IllegalArgumentException
  211. * if a window with the same name as the new window already
  212. * exists in the application.
  213. * @throws NullPointerException
  214. * if the given <code>Window</code> or its name is
  215. * <code>null</code>.
  216. */
  217. public void addWindow(Window window) throws IllegalArgumentException,
  218. NullPointerException {
  219. // Nulls can not be added to application
  220. if (window == null)
  221. return;
  222. // Gets the naming proposal from window
  223. String name = window.getName();
  224. // Checks that the application does not already contain
  225. // window having the same name
  226. if (name != null && windows.containsKey(name)) {
  227. // If the window is already added
  228. if (window == windows.get(name))
  229. return;
  230. // Otherwise complain
  231. throw new IllegalArgumentException("Window with name '"
  232. + window.getName()
  233. + "' is already present in the application");
  234. }
  235. // If the name of the window is null, the window is automatically named
  236. if (name == null) {
  237. boolean accepted = false;
  238. while (!accepted) {
  239. // Try another name
  240. name = String.valueOf(Math.abs(nameGenerator.nextInt()));
  241. if (!windows.containsKey(name))
  242. accepted = true;
  243. }
  244. window.setName(name);
  245. }
  246. // Adds the window to application
  247. windows.put(name, window);
  248. window.setApplication(this);
  249. // Fires the window attach event
  250. if (windowAttachListeners != null) {
  251. Object[] listeners = windowAttachListeners.toArray();
  252. WindowAttachEvent event = new WindowAttachEvent(window);
  253. for (int i = 0; i < listeners.length; i++) {
  254. ((WindowAttachListener) listeners[i]).windowAttached(event);
  255. }
  256. }
  257. // If no main window is set, declare the window to be main window
  258. if (getMainWindow() == null)
  259. setMainWindow(window);
  260. }
  261. /**
  262. * Removes the specified window from the application.
  263. *
  264. * @param window
  265. * the window to be removed.
  266. */
  267. public void removeWindow(Window window) {
  268. if (window != null && windows.contains(window)) {
  269. // Removes the window from application
  270. windows.remove(window.getName());
  271. // If the window was main window, clear it
  272. if (getMainWindow() == window)
  273. setMainWindow(null);
  274. // Removes the application from window
  275. if (window.getApplication() == this)
  276. window.setApplication(null);
  277. // Fires the window detach event
  278. if (windowDetachListeners != null) {
  279. Object[] listeners = windowDetachListeners.toArray();
  280. WindowDetachEvent event = new WindowDetachEvent(window);
  281. for (int i = 0; i < listeners.length; i++) {
  282. ((WindowDetachListener) listeners[i]).windowDetached(event);
  283. }
  284. }
  285. }
  286. }
  287. /**
  288. * Gets the user of the application.
  289. *
  290. * @return the User of the application.
  291. */
  292. public Object getUser() {
  293. return user;
  294. }
  295. /**
  296. * <p>
  297. * Sets the user of the application instance. An application instance may
  298. * have a user associated to it. This can be set in login procedure or
  299. * application initialization.
  300. * </p>
  301. * <p>
  302. * A component performing the user login procedure can assign the user
  303. * property of the application and make the user object available to other
  304. * components of the application.
  305. * </p>
  306. *
  307. * @param user
  308. * the new user.
  309. */
  310. public void setUser(Object user) {
  311. Object prevUser = this.user;
  312. if (user != prevUser && (user == null || !user.equals(prevUser))) {
  313. this.user = user;
  314. if (userChangeListeners != null) {
  315. Object[] listeners = userChangeListeners.toArray();
  316. UserChangeEvent event = new UserChangeEvent(this, user,
  317. prevUser);
  318. for (int i = 0; i < listeners.length; i++) {
  319. ((UserChangeListener) listeners[i])
  320. .applicationUserChanged(event);
  321. }
  322. }
  323. }
  324. }
  325. /**
  326. * Gets the URL of the application.
  327. *
  328. * @return the application's URL.
  329. */
  330. public URL getURL() {
  331. return applicationUrl;
  332. }
  333. /**
  334. * Ends the Application. In effect this will cause the application stop
  335. * returning any windows when asked.
  336. */
  337. public void close() {
  338. applicationIsRunning = false;
  339. }
  340. /**
  341. * Starts the application on the given URL.After this call the application
  342. * corresponds to the given URL and it will return windows when asked for
  343. * them.
  344. *
  345. * @param applicationUrl
  346. * the URL the application should respond to.
  347. * @param applicationProperties
  348. * the Application properties as specified by the adapter.
  349. * @param context
  350. * the context application will be running in.
  351. *
  352. */
  353. public void start(URL applicationUrl, Properties applicationProperties,
  354. ApplicationContext context) {
  355. this.applicationUrl = applicationUrl;
  356. this.properties = applicationProperties;
  357. this.context = context;
  358. init();
  359. applicationIsRunning = true;
  360. }
  361. /**
  362. * Tests if the application is running or if it has been finished.
  363. *
  364. * @return <code>true</code> if the application is running,
  365. * <code>false</code> if not.
  366. */
  367. public boolean isRunning() {
  368. return applicationIsRunning;
  369. }
  370. /**
  371. * Gets the set of windows contained by the application.
  372. *
  373. * @return the Unmodifiable collection of windows.
  374. */
  375. public Collection getWindows() {
  376. return Collections.unmodifiableCollection(windows.values());
  377. }
  378. /**
  379. * <p>
  380. * Main initializer of the application. The <code>init</code> method is
  381. * called by the framework when the application is started, and it should
  382. * perform whatever initialization operations the application needs, such as
  383. * creating windows and adding components to them.
  384. * </p>
  385. */
  386. public abstract void init();
  387. /**
  388. * Gets the application's theme. The application's theme is the default
  389. * theme used by all the windows in it that do not explicitly specify a
  390. * theme. If the application theme is not explicitly set, the
  391. * <code>null</code> is returned.
  392. *
  393. * @return the name of the application's theme.
  394. */
  395. public String getTheme() {
  396. return theme;
  397. }
  398. /**
  399. * Sets the application's theme.
  400. * <p>
  401. * Note that this theme can be overridden by the windows. <code>null</code>
  402. * implies the default terminal theme.
  403. * </p>
  404. *
  405. * @param theme
  406. * the new theme for this application.
  407. */
  408. public void setTheme(String theme) {
  409. // Collect list of windows not having the current or future theme
  410. LinkedList toBeUpdated = new LinkedList();
  411. String myTheme = this.getTheme();
  412. for (Iterator i = getWindows().iterator(); i.hasNext();) {
  413. Window w = (Window) i.next();
  414. String windowTheme = w.getTheme();
  415. if ((windowTheme == null)
  416. || (!theme.equals(windowTheme) && windowTheme
  417. .equals(myTheme))) {
  418. toBeUpdated.add(w);
  419. }
  420. }
  421. // Updates the theme
  422. this.theme = theme;
  423. // Ask windows to update themselves
  424. for (Iterator i = toBeUpdated.iterator(); i.hasNext();)
  425. ((Window) i.next()).requestRepaint();
  426. }
  427. /**
  428. * Gets the mainWindow of the application.
  429. *
  430. * @return the main window.
  431. */
  432. public Window getMainWindow() {
  433. return mainWindow;
  434. }
  435. /**
  436. * <p>
  437. * Sets the mainWindow. If the main window is not explicitly set, the main
  438. * window defaults to first created window. Setting window as a main window
  439. * of this application also adds the window to this application.
  440. * </p>
  441. *
  442. * @param mainWindow
  443. * the mainWindow to set.
  444. */
  445. public void setMainWindow(Window mainWindow) {
  446. addWindow(mainWindow);
  447. this.mainWindow = mainWindow;
  448. }
  449. /**
  450. * Returns an enumeration of all the names in this application.
  451. *
  452. * @return an enumeration of all the keys in this property list, including
  453. * the keys in the default property list.
  454. *
  455. */
  456. public Enumeration getPropertyNames() {
  457. return this.properties.propertyNames();
  458. }
  459. /**
  460. * Searches for the property with the specified name in this application.
  461. * This method returns <code>null</code> if the property is not found.
  462. *
  463. * @param name
  464. * the name of the property.
  465. * @return the value in this property list with the specified key value.
  466. */
  467. public String getProperty(String name) {
  468. return this.properties.getProperty(name);
  469. }
  470. /**
  471. * Adds new resource to the application. The resource can be accessed by the
  472. * user of the application.
  473. *
  474. * @param resource
  475. * the resource to add.
  476. */
  477. public void addResource(ApplicationResource resource) {
  478. // Check if the resource is already mapped
  479. if (resourceKeyMap.containsKey(resource))
  480. return;
  481. // Generate key
  482. String key = String.valueOf(++lastResourceKeyNumber);
  483. // Add the resource to mappings
  484. resourceKeyMap.put(resource, key);
  485. keyResourceMap.put(key, resource);
  486. }
  487. /**
  488. * Removes the resource from the application.
  489. *
  490. * @param resource
  491. * the resource to remove.
  492. */
  493. public void removeResource(ApplicationResource resource) {
  494. Object key = resourceKeyMap.get(resource);
  495. if (key != null) {
  496. resourceKeyMap.remove(resource);
  497. keyResourceMap.remove(key);
  498. }
  499. }
  500. /**
  501. * Gets the relative uri of the resource.
  502. *
  503. * @param resource
  504. * the resource to get relative location.
  505. * @return the relative uri of the resource.
  506. */
  507. public String getRelativeLocation(ApplicationResource resource) {
  508. // Gets the key
  509. String key = (String) resourceKeyMap.get(resource);
  510. // If the resource is not registered, return null
  511. if (key == null)
  512. return null;
  513. String filename = resource.getFilename();
  514. if (filename == null)
  515. return "APP/" + key + "/";
  516. else
  517. return "APP/" + key + "/" + filename;
  518. }
  519. /*
  520. * @see com.itmill.toolkit.terminal.URIHandler#handleURI(URL, String)
  521. */
  522. public DownloadStream handleURI(URL context, String relativeUri) {
  523. // If the relative uri is null, we are ready
  524. if (relativeUri == null)
  525. return null;
  526. // Resolves the prefix
  527. String prefix = relativeUri;
  528. int index = relativeUri.indexOf('/');
  529. if (index >= 0)
  530. prefix = relativeUri.substring(0, index);
  531. // Handles the resource requests
  532. if (prefix.equals("APP")) {
  533. // Handles the resource request
  534. int next = relativeUri.indexOf('/', index + 1);
  535. if (next < 0)
  536. return null;
  537. String key = relativeUri.substring(index + 1, next);
  538. ApplicationResource resource = (ApplicationResource) keyResourceMap
  539. .get(key);
  540. if (resource != null)
  541. return resource.getStream();
  542. // Resource requests override uri handling
  543. return null;
  544. }
  545. // If the uri is in some window, handle the window uri
  546. Window window = getWindow(prefix);
  547. if (window != null) {
  548. URL windowContext;
  549. try {
  550. windowContext = new URL(context, prefix + "/");
  551. String windowUri = relativeUri.length() > prefix.length() + 1 ? relativeUri
  552. .substring(prefix.length() + 1)
  553. : "";
  554. return window.handleURI(windowContext, windowUri);
  555. } catch (MalformedURLException e) {
  556. return null;
  557. }
  558. }
  559. // If the uri was not pointing to a window, handle the
  560. // uri in main window
  561. window = getMainWindow();
  562. if (window != null)
  563. return window.handleURI(context, relativeUri);
  564. return null;
  565. }
  566. /**
  567. * Gets the default locale for this application.
  568. *
  569. * @return the locale of this application.
  570. */
  571. public Locale getLocale() {
  572. if (this.locale != null)
  573. return this.locale;
  574. return Locale.getDefault();
  575. }
  576. /**
  577. * Sets the default locale for this application.
  578. *
  579. * @param locale
  580. * the Locale object.
  581. *
  582. */
  583. public void setLocale(Locale locale) {
  584. this.locale = locale;
  585. }
  586. /**
  587. * <p>
  588. * An event that characterizes a change in the current selection.
  589. * </p>
  590. * Application user change event sent when the setUser is called to change
  591. * the current user of the application.
  592. *
  593. * @version
  594. * @VERSION@
  595. * @since 3.0
  596. */
  597. public class UserChangeEvent extends java.util.EventObject {
  598. /**
  599. * Serial generated by eclipse.
  600. */
  601. private static final long serialVersionUID = 3544951069307188281L;
  602. /**
  603. * New user of the application.
  604. */
  605. private Object newUser;
  606. /**
  607. * Previous user of the application.
  608. */
  609. private Object prevUser;
  610. /**
  611. * Contructor for user change event.
  612. *
  613. * @param source
  614. * the application source.
  615. * @param newUser
  616. * the new User.
  617. * @param prevUser
  618. * the previous User.
  619. */
  620. public UserChangeEvent(Application source, Object newUser,
  621. Object prevUser) {
  622. super(source);
  623. this.newUser = newUser;
  624. this.prevUser = prevUser;
  625. }
  626. /**
  627. * Gets the new user of the application.
  628. *
  629. * @return the new User.
  630. */
  631. public Object getNewUser() {
  632. return newUser;
  633. }
  634. /**
  635. * Gets the previous user of the application.
  636. *
  637. * @return the previous Toolkit user, if user has not changed ever on
  638. * application it returns <code>null</code>
  639. */
  640. public Object getPreviousUser() {
  641. return prevUser;
  642. }
  643. /**
  644. * Gets the application where the user change occurred.
  645. *
  646. * @return the Application.
  647. */
  648. public Application getApplication() {
  649. return (Application) getSource();
  650. }
  651. }
  652. /**
  653. * The <code>UserChangeListener</code> interface for listening application
  654. * user changes.
  655. *
  656. * @version
  657. * @VERSION@
  658. * @since 3.0
  659. */
  660. public interface UserChangeListener extends EventListener {
  661. /**
  662. * The <code>applicationUserChanged</code> method Invoked when the
  663. * application user has changed.
  664. *
  665. * @param event
  666. * the change event.
  667. */
  668. public void applicationUserChanged(Application.UserChangeEvent event);
  669. }
  670. /**
  671. * Adds the user change listener.
  672. *
  673. * @param listener
  674. * the user change listener to add.
  675. */
  676. public void addListener(UserChangeListener listener) {
  677. if (userChangeListeners == null)
  678. userChangeListeners = new LinkedList();
  679. userChangeListeners.add(listener);
  680. }
  681. /**
  682. * Removes the user change listener.
  683. *
  684. * @param listener
  685. * the user change listener to remove.
  686. */
  687. public void removeListener(UserChangeListener listener) {
  688. if (userChangeListeners == null)
  689. return;
  690. userChangeListeners.remove(listener);
  691. if (userChangeListeners.isEmpty())
  692. userChangeListeners = null;
  693. }
  694. /**
  695. * Window detach event.
  696. */
  697. public class WindowDetachEvent extends EventObject {
  698. /**
  699. * Serial generated by eclipse.
  700. */
  701. private static final long serialVersionUID = 3544669568644691769L;
  702. private Window window;
  703. /**
  704. * Creates a event.
  705. *
  706. * @param window
  707. * the Detached window.
  708. */
  709. public WindowDetachEvent(Window window) {
  710. super(Application.this);
  711. this.window = window;
  712. }
  713. /**
  714. * Gets the detached window.
  715. *
  716. * @return the detached window.
  717. */
  718. public Window getWindow() {
  719. return window;
  720. }
  721. /**
  722. * Gets the application from which the window was detached.
  723. *
  724. * @return the Application.
  725. */
  726. public Application getApplication() {
  727. return (Application) getSource();
  728. }
  729. }
  730. /**
  731. * Window attach event.
  732. */
  733. public class WindowAttachEvent extends EventObject {
  734. /**
  735. * Serial generated by eclipse.
  736. */
  737. private static final long serialVersionUID = 3977578104367822392L;
  738. private Window window;
  739. /**
  740. * Creates a event.
  741. *
  742. * @param window
  743. * the Attached window.
  744. */
  745. public WindowAttachEvent(Window window) {
  746. super(Application.this);
  747. this.window = window;
  748. }
  749. /**
  750. * Gets the attached window.
  751. *
  752. * @return the attached window.
  753. */
  754. public Window getWindow() {
  755. return window;
  756. }
  757. /**
  758. * Gets the application to which the window was attached.
  759. *
  760. * @return the Application.
  761. */
  762. public Application getApplication() {
  763. return (Application) getSource();
  764. }
  765. }
  766. /**
  767. * Window attach listener interface.
  768. */
  769. public interface WindowAttachListener {
  770. /**
  771. * Window attached
  772. *
  773. * @param event
  774. * the window attach event.
  775. */
  776. public void windowAttached(WindowAttachEvent event);
  777. }
  778. /**
  779. * Window detach listener interface.
  780. */
  781. public interface WindowDetachListener {
  782. /**
  783. * Window detached.
  784. *
  785. * @param event
  786. * the window detach event.
  787. */
  788. public void windowDetached(WindowDetachEvent event);
  789. }
  790. /**
  791. * Adds the window attach listener.
  792. *
  793. * @param listener
  794. * the window attach listener to add.
  795. */
  796. public void addListener(WindowAttachListener listener) {
  797. if (windowAttachListeners == null)
  798. windowAttachListeners = new LinkedList();
  799. windowAttachListeners.add(listener);
  800. }
  801. /**
  802. * Adds the window detach listener.
  803. *
  804. * @param listener
  805. * the window detach listener to add.
  806. */
  807. public void addListener(WindowDetachListener listener) {
  808. if (windowDetachListeners == null)
  809. windowDetachListeners = new LinkedList();
  810. windowDetachListeners.add(listener);
  811. }
  812. /**
  813. * Removes the window attach listener.
  814. *
  815. * @param listener
  816. * the window attach listener to remove.
  817. */
  818. public void removeListener(WindowAttachListener listener) {
  819. if (windowAttachListeners != null) {
  820. windowAttachListeners.remove(listener);
  821. if (windowAttachListeners.isEmpty())
  822. windowAttachListeners = null;
  823. }
  824. }
  825. /**
  826. * Removes the window detach listener.
  827. *
  828. * @param listener
  829. * the window detach listener to remove.
  830. */
  831. public void removeListener(WindowDetachListener listener) {
  832. if (windowDetachListeners != null) {
  833. windowDetachListeners.remove(listener);
  834. if (windowDetachListeners.isEmpty())
  835. windowDetachListeners = null;
  836. }
  837. }
  838. /**
  839. * Returns the URL user is redirected to on application close.If the URL is
  840. * <code>null</code>, the application is closed normally as defined by
  841. * the application running environment.
  842. * <p>
  843. * Desctop application just closes the application window and
  844. * web-application redirects the browser to application main URL.
  845. * </p>
  846. *
  847. * @return the URL.
  848. */
  849. public String getLogoutURL() {
  850. return logoutURL;
  851. }
  852. /**
  853. * Sets the URL user is redirected to on application close. If the URL is
  854. * <code>null</code>, the application is closed normally as defined by
  855. * the application running environment: Desctop application just closes the
  856. * application window and web-application redirects the browser to
  857. * application main URL.
  858. *
  859. * @param logoutURL
  860. * the logoutURL to set.
  861. */
  862. public void setLogoutURL(String logoutURL) {
  863. this.logoutURL = logoutURL;
  864. }
  865. /**
  866. * <p>
  867. * Invoked by the terminal on any exception that occurs in application and
  868. * is thrown by the <code>setVariable</code> to the terminal. The default
  869. * implementation sets the exceptions as <code>ComponentErrors</code> to
  870. * the component that initiated the exception.
  871. * </p>
  872. * <p>
  873. * You can safely override this method in your application in order to
  874. * direct the errors to some other destination (for example log).
  875. * </p>
  876. *
  877. * @param event
  878. * the change event.
  879. * @see com.itmill.toolkit.terminal.Terminal.ErrorListener#terminalError(com.itmill.toolkit.terminal.Terminal.ErrorEvent)
  880. */
  881. public void terminalError(Terminal.ErrorEvent event) {
  882. // Finds the original source of the error/exception
  883. Object owner = null;
  884. if (event instanceof VariableOwner.ErrorEvent) {
  885. owner = ((VariableOwner.ErrorEvent) event).getVariableOwner();
  886. } else if (event instanceof URIHandler.ErrorEvent) {
  887. owner = ((URIHandler.ErrorEvent) event).getURIHandler();
  888. } else if (event instanceof ParameterHandler.ErrorEvent) {
  889. owner = ((ParameterHandler.ErrorEvent) event).getParameterHandler();
  890. }
  891. // Shows the error in AbstractComponent
  892. if (owner instanceof AbstractComponent) {
  893. Throwable e = event.getThrowable();
  894. if (e instanceof ErrorMessage)
  895. ((AbstractComponent) owner).setComponentError((ErrorMessage) e);
  896. else
  897. ((AbstractComponent) owner)
  898. .setComponentError(new SystemError(e));
  899. }
  900. }
  901. /**
  902. * Gets the application context.
  903. * <p>
  904. * The application context is the environment where the application is
  905. * running in.
  906. * </p>
  907. *
  908. * @return the application context.
  909. */
  910. public ApplicationContext getContext() {
  911. return context;
  912. }
  913. /**
  914. * Gets the license this application is running on.
  915. * <p>
  916. * The license is initialized by the <code>ApplicationServlet</code> class
  917. * before application is started. The license-file can not be found in
  918. * <code>WEB-INF/itmill-toolkit-license.xml</code>, you can set its
  919. * source in application <code>init</code> method.
  920. * </p>
  921. *
  922. * @return the License this application is currently using.
  923. */
  924. public License getToolkitLicense() {
  925. return license;
  926. }
  927. /**
  928. * Sets the license this application is currently using.
  929. * <p>
  930. * The license is initialized by the <code>ApplicationServlet</code>
  931. * before application is started. Changing the license after application
  932. * <code>init</code> method has no effect.
  933. * </p>
  934. *
  935. * @param license
  936. * the New license for this application.
  937. */
  938. public void setToolkitLicense(License license) {
  939. this.license = license;
  940. }
  941. public void setFocusedComponent(Focusable focusable) {
  942. this.pendingFocus = focusable;
  943. }
  944. /**
  945. * Gets and nulls focused component in this window
  946. *
  947. * @return Focused component or null if none is focused.
  948. */
  949. public Component.Focusable consumeFocus() {
  950. Component.Focusable f = this.pendingFocus;
  951. this.pendingFocus = null;
  952. return f;
  953. }
  954. }