12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019 |
- /*
- @ITMillApache2LicenseForJavaFiles@
- */
-
- package com.itmill.toolkit.terminal.gwt.client;
-
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Vector;
-
- import com.google.gwt.core.client.JavaScriptObject;
- import com.google.gwt.http.client.Request;
- import com.google.gwt.http.client.RequestBuilder;
- import com.google.gwt.http.client.RequestCallback;
- import com.google.gwt.http.client.RequestException;
- import com.google.gwt.http.client.Response;
- import com.google.gwt.json.client.JSONArray;
- import com.google.gwt.json.client.JSONObject;
- import com.google.gwt.json.client.JSONParser;
- import com.google.gwt.json.client.JSONString;
- import com.google.gwt.json.client.JSONValue;
- import com.google.gwt.user.client.Command;
- import com.google.gwt.user.client.DOM;
- import com.google.gwt.user.client.DeferredCommand;
- import com.google.gwt.user.client.Element;
- import com.google.gwt.user.client.Event;
- import com.google.gwt.user.client.Timer;
- import com.google.gwt.user.client.Window;
- import com.google.gwt.user.client.WindowCloseListener;
- import com.google.gwt.user.client.ui.FocusWidget;
- import com.google.gwt.user.client.ui.HasFocus;
- import com.google.gwt.user.client.ui.HasWidgets;
- import com.google.gwt.user.client.ui.Widget;
- import com.itmill.toolkit.terminal.gwt.client.ui.IContextMenu;
- import com.itmill.toolkit.terminal.gwt.client.ui.Field;
- import com.itmill.toolkit.terminal.gwt.client.ui.IView;
- import com.itmill.toolkit.terminal.gwt.client.ui.INotification;
- import com.itmill.toolkit.terminal.gwt.client.ui.INotification.HideEvent;
-
- /**
- * Entry point classes define <code>onModuleLoad()</code>.
- */
- public class ApplicationConnection {
- private static final String MODIFIED_CLASSNAME = "i-modified";
-
- private static final String REQUIRED_CLASSNAME_EXT = "-required";
-
- private static final String ERROR_CLASSNAME_EXT = "-error";
-
- public static final String VAR_RECORD_SEPARATOR = "\u001e";
-
- public static final String VAR_FIELD_SEPARATOR = "\u001f";
-
- private final HashMap resourcesMap = new HashMap();
-
- private static Console console;
-
- private static boolean testingMode;
-
- private final Vector pendingVariables = new Vector();
-
- private final HashMap idToPaintable = new HashMap();
-
- private final HashMap paintableToId = new HashMap();
-
- /** Contains ExtendedTitleInfo by paintable id */
- private final HashMap paintableToTitle = new HashMap();
-
- private final WidgetSet widgetSet;
-
- private IContextMenu contextMenu = null;
-
- private Timer loadTimer;
- private Timer loadTimer2;
- private Timer loadTimer3;
- private Element loadElement;
-
- private final IView view;
-
- private boolean applicationRunning = false;
-
- /**
- * True if each Paintable objects id is injected to DOM. Used for Testing
- * Tools.
- */
- private boolean usePaintableIdsInDOM = false;
-
- /**
- * Contains reference for client wrapper given to Testing Tools.
- *
- * Used in JSNI functions
- *
- * @SuppressWarnings
- */
- private final JavaScriptObject ttClientWrapper = null;
-
- private int activeRequests = 0;
-
- private final ApplicationConfiguration configuration;
-
- private final Vector pendingVariableBursts = new Vector();
-
- public ApplicationConnection(WidgetSet widgetSet,
- ApplicationConfiguration cnf) {
- this.widgetSet = widgetSet;
- configuration = cnf;
-
- if (isDebugMode()) {
- console = new IDebugConsole(this, cnf);
- } else {
- console = new NullConsole();
- }
-
- if (checkTestingMode()) {
- usePaintableIdsInDOM = true;
- initializeTestingTools();
- Window.addWindowCloseListener(new WindowCloseListener() {
- public void onWindowClosed() {
- uninitializeTestingTools();
- }
-
- public String onWindowClosing() {
- return null;
- }
- });
- }
-
- initializeClientHooks();
-
- // TODO remove hard coded id name
- view = new IView(cnf.getRootPanelId());
-
- makeUidlRequest("", true);
- applicationRunning = true;
- }
-
- /**
- * Method to check if application is in testing mode. Can be used after
- * application init.
- *
- * @return true if in testing mode
- */
- public static boolean isTestingMode() {
- return testingMode;
- }
-
- /**
- * Check is application is run in testing mode.
- *
- * @return true if in testing mode
- */
- private native static boolean checkTestingMode()
- /*-{
- @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode = $wnd.top.itmill && $wnd.top.itmill.registerToTT ? true : false;
- return @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode;
- }-*/;
-
- private native void initializeTestingTools()
- /*-{
- var ap = this;
- var client = {};
- client.isActive = function() {
- return ap.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::hasActiveRequest()();
- }
- var vi = ap.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::getVersionInfo()();
- if (vi) {
- client.getVersionInfo = function() {
- return vi;
- }
- }
- $wnd.top.itmill.registerToTT(client);
- this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper = client;
- }-*/;
-
- /**
- * Helper for tt initialization
- */
- private JavaScriptObject getVersionInfo() {
- return configuration.getVersionInfoJSObject();
- }
-
- private native void uninitializeTestingTools()
- /*-{
- $wnd.top.itmill.unregisterFromTT(this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper);
- }-*/;
-
- /**
- * Publishes a JavaScript API for mash-up applications.
- * <ul>
- * <li><code>itmill.forceSync()</code> sends pending variable changes, in
- * effect synchronizing the server and client state. This is done for all
- * applications on host page.</li>
- * </ul>
- *
- * TODO make this multi-app aware
- */
- private native void initializeClientHooks()
- /*-{
- var app = this;
- var oldSync;
- if($wnd.itmill.forceSync) {
- oldSync = $wnd.itmill.forceSync;
- }
- $wnd.itmill.forceSync = function() {
- if(oldSync) {
- oldSync();
- }
- app.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::sendPendingVariableChanges()();
- }
- }-*/;
-
- public static Console getConsole() {
- return console;
- }
-
- private native static boolean isDebugMode()
- /*-{
- var uri = $wnd.location;
- var re = /debug[^\/]*$/;
- return re.test(uri);
- }-*/;
-
- public String getAppUri() {
- return configuration.getApplicationUri();
- };
-
- public boolean hasActiveRequest() {
- return (activeRequests > 0);
- }
-
- private void makeUidlRequest(String requestData, boolean repaintAll) {
- startRequest();
-
- console.log("Making UIDL Request with params: " + requestData);
- String uri = getAppUri() + "UIDL" + configuration.getPathInfo();
- if (repaintAll) {
- uri += "?repaintAll=1";
- }
- final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
- // rb.setHeader("Content-Type",
- // "application/x-www-form-urlencoded; charset=utf-8");
- rb.setHeader("Content-Type", "text/plain;charset=utf-8");
- try {
- rb.sendRequest(requestData, new RequestCallback() {
- public void onError(Request request, Throwable exception) {
- // TODO Better reporting to user
- console.error("Got error");
- endRequest();
- }
-
- public void onResponseReceived(Request request,
- Response response) {
- handleReceivedJSONMessage(response);
- }
-
- });
-
- } catch (final RequestException e) {
- ClientExceptionHandler.displayError(e);
- endRequest();
- }
- }
-
- private void startRequest() {
- activeRequests++;
- showLoadingIndicator();
- }
-
- private void endRequest() {
-
- checkForPendingVariableBursts();
-
- activeRequests--;
- // deferring to avoid flickering
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- if (activeRequests == 0) {
- hideLoadingIndicator();
- }
- }
- });
- }
-
- /**
- * This method is called after applying uidl change set to application.
- *
- * It will clean current and queued variable change sets. And send next
- * change set if it exists.
- */
- private void checkForPendingVariableBursts() {
- cleanVariableBurst(pendingVariables);
- if (pendingVariableBursts.size() > 0) {
- for (Iterator iterator = pendingVariableBursts.iterator(); iterator
- .hasNext();) {
- cleanVariableBurst((Vector) iterator.next());
- }
- Vector nextBurst = (Vector) pendingVariableBursts.firstElement();
- pendingVariableBursts.remove(0);
- buildAndSendVariableBurst(nextBurst);
- }
- }
-
- /**
- * Cleans given queue of variable changes of such changes that came from
- * components that do not exist anymore.
- *
- * @param variableBurst
- */
- private void cleanVariableBurst(Vector variableBurst) {
- for (int i = 1; i < variableBurst.size(); i += 2) {
- String id = (String) variableBurst.get(i);
- id = id.substring(0, id.indexOf(VAR_FIELD_SEPARATOR));
- if (!idToPaintable.containsKey(id)) {
- // variable owner does not exist anymore
- variableBurst.remove(i - 1);
- variableBurst.remove(i - 1);
- i -= 2;
- ApplicationConnection.getConsole().log(
- "Removed variable from removed component: " + id);
- }
- }
- }
-
- private void showLoadingIndicator() {
- // show initial throbber
- if (loadTimer == null) {
- loadTimer = new Timer() {
- public void run() {
- // show initial throbber
- if (loadElement == null) {
- loadElement = DOM.createDiv();
- DOM.setStyleAttribute(loadElement, "position",
- "absolute");
- DOM.appendChild(view.getElement(), loadElement);
- ApplicationConnection.getConsole().log(
- "inserting load indicator");
- // Position
- DOM.setStyleAttribute(loadElement, "top", (view
- .getAbsoluteTop() + 6)
- + "px");
- }
- DOM.setElementProperty(loadElement, "className",
- "i-loading-indicator");
- DOM.setStyleAttribute(loadElement, "display", "block");
- final int updatedX = Window.getScrollLeft()
- + view.getAbsoluteLeft()
- + view.getOffsetWidth()
- - DOM.getElementPropertyInt(loadElement,
- "offsetWidth") - 5;
- DOM.setStyleAttribute(loadElement, "left", updatedX + "px");
- final int updatedY = Window.getScrollTop() + 6
- + view.getAbsoluteTop();
- DOM.setStyleAttribute(loadElement, "top", updatedY + "px");
- // Initialize other timers
- loadTimer2 = new Timer() {
- public void run() {
- DOM.setElementProperty(loadElement, "className",
- "i-loading-indicator-delay");
- }
- };
- // Second one kicks in at 1500ms
- loadTimer2.schedule(1200);
-
- loadTimer3 = new Timer() {
- public void run() {
- DOM.setElementProperty(loadElement, "className",
- "i-loading-indicator-wait");
- }
- };
- // Third one kicks in at 5000ms
- loadTimer3.schedule(4700);
- }
- };
- // First one kicks in at 300ms
- loadTimer.schedule(300);
- }
- }
-
- private void hideLoadingIndicator() {
- if (loadTimer != null) {
- loadTimer.cancel();
- if (loadTimer2 != null) {
- loadTimer2.cancel();
- loadTimer3.cancel();
- }
- loadTimer = null;
- }
- if (loadElement != null) {
- DOM.removeChild(view.getElement(), loadElement);
- loadElement = null;
- }
- }
-
- private void handleReceivedJSONMessage(Response response) {
- final Date start = new Date();
- String jsonText = response.getText();
- // for(;;);[realjson]
- jsonText = jsonText.substring(9, jsonText.length() - 1);
- JSONValue json;
- try {
- json = JSONParser.parse(jsonText);
- } catch (final com.google.gwt.json.client.JSONException e) {
- endRequest();
- console.log(e.getMessage() + " - Original JSON-text:");
- console.log(jsonText);
- return;
- }
- // Handle redirect
- final JSONObject redirect = (JSONObject) ((JSONObject) json)
- .get("redirect");
- if (redirect != null) {
- final JSONString url = (JSONString) redirect.get("url");
- if (url != null) {
- console.log("redirecting to " + url.stringValue());
- redirect(url.stringValue());
- return;
- }
- }
-
- // Store resources
- final JSONObject resources = (JSONObject) ((JSONObject) json)
- .get("resources");
- for (final Iterator i = resources.keySet().iterator(); i.hasNext();) {
- final String key = (String) i.next();
- resourcesMap.put(key, ((JSONString) resources.get(key))
- .stringValue());
- }
-
- // Store locale data
- if (((JSONObject) json).containsKey("locales")) {
- final JSONArray l = (JSONArray) ((JSONObject) json).get("locales");
- for (int i = 0; i < l.size(); i++) {
- LocaleService.addLocale((JSONObject) l.get(i));
- }
- }
-
- JSONObject meta = null;
- if (((JSONObject) json).containsKey("meta")) {
- meta = ((JSONObject) json).get("meta").isObject();
- if (meta.containsKey("repaintAll")) {
- view.clear();
- idToPaintable.clear();
- paintableToId.clear();
- }
- }
-
- // Process changes
- final JSONArray changes = (JSONArray) ((JSONObject) json)
- .get("changes");
- for (int i = 0; i < changes.size(); i++) {
- try {
- final UIDL change = new UIDL((JSONArray) changes.get(i));
- try {
- console.dirUIDL(change);
- } catch (final Exception e) {
- ClientExceptionHandler.displayError(e);
- // TODO: dir doesn't work in any browser although it should
- // work (works in hosted mode)
- // it partially did at some part but now broken.
- }
- final UIDL uidl = change.getChildUIDL(0);
- final Paintable paintable = getPaintable(uidl.getId());
- if (paintable != null) {
- paintable.updateFromUIDL(uidl, this);
- } else {
- if (!uidl.getTag().equals("window")) {
- ClientExceptionHandler
- .displayError("Received update for "
- + uidl.getTag()
- + ", but there is no such paintable ("
- + uidl.getId() + ") rendered.");
- } else {
- view.updateFromUIDL(uidl, this);
- }
- }
- } catch (final Throwable e) {
- ClientExceptionHandler.displayError(e);
- }
- }
-
- if (meta != null) {
- if (meta.containsKey("focus")) {
- final String focusPid = meta.get("focus").isString()
- .stringValue();
- final Paintable toBeFocused = getPaintable(focusPid);
- if (toBeFocused instanceof HasFocus) {
- final HasFocus toBeFocusedWidget = (HasFocus) toBeFocused;
- toBeFocusedWidget.setFocus(true);
- } else if (toBeFocused instanceof Focusable) {
- ((Focusable) toBeFocused).focus();
- } else {
- getConsole().log("Could not focus component");
- }
-
- }
- if (meta.containsKey("appError")) {
- JSONObject error = meta.get("appError").isObject();
- JSONValue val = error.get("caption");
- String html = "";
- if (val.isString() != null) {
- html += "<h1>" + val.isString().stringValue() + "</h1>";
- }
- val = error.get("message");
- if (val.isString() != null) {
- html += "<p>" + val.isString().stringValue() + "</p>";
- }
- val = error.get("url");
- String url = null;
- if (val.isString() != null) {
- url = val.isString().stringValue();
- }
-
- if (html.length() != 0) {
- INotification n = new INotification(1000 * 60 * 45); // 45min
- n.addEventListener(new NotificationRedirect(url));
- n.show(html, INotification.CENTERED_TOP, "system");
- } else {
- redirect(url);
- }
- applicationRunning = false;
- }
- }
-
- final long prosessingTime = (new Date().getTime()) - start.getTime();
- console.log(" Processing time was " + String.valueOf(prosessingTime)
- + "ms for " + jsonText.length() + " characters of JSON");
- console.log("Referenced paintables: " + idToPaintable.size());
-
- endRequest();
- }
-
- // Redirect browser, null reloads current page
- private static native void redirect(String url)
- /*-{
- if (url) {
- $wnd.location = url;
- } else {
- $wnd.location = $wnd.location;
- }
- }-*/;
-
- public void registerPaintable(String id, Paintable paintable) {
- idToPaintable.put(id, paintable);
- paintableToId.put(paintable, id);
- }
-
- public void unregisterPaintable(Paintable p) {
- Object id = paintableToId.get(p);
- idToPaintable.remove(id);
- paintableToTitle.remove(id);
- paintableToId.remove(p);
-
- if (p instanceof HasWidgets) {
- unregisterChildPaintables((HasWidgets) p);
- }
- }
-
- public void unregisterChildPaintables(HasWidgets container) {
- final Iterator it = container.iterator();
- while (it.hasNext()) {
- final Widget w = (Widget) it.next();
- if (w instanceof Paintable) {
- unregisterPaintable((Paintable) w);
- } else if (w instanceof HasWidgets) {
- unregisterChildPaintables((HasWidgets) w);
- }
- }
- }
-
- /**
- * Returns Paintable element by its id
- *
- * @param id
- * Paintable ID
- */
- public Paintable getPaintable(String id) {
- return (Paintable) idToPaintable.get(id);
- }
-
- private void addVariableToQueue(String paintableId, String variableName,
- String encodedValue, boolean immediate, char type) {
- final String id = paintableId + VAR_FIELD_SEPARATOR + variableName
- + VAR_FIELD_SEPARATOR + type;
- for (int i = 1; i < pendingVariables.size(); i += 2) {
- if ((pendingVariables.get(i)).equals(id)) {
- pendingVariables.remove(i - 1);
- pendingVariables.remove(i - 1);
- break;
- }
- }
- pendingVariables.add(encodedValue);
- pendingVariables.add(id);
- if (immediate) {
- sendPendingVariableChanges();
- }
- }
-
- /**
- * This method sends currently queued variable changes to server. It is
- * called when immediate variable update must happen.
- *
- * To ensure correct order for variable changes (due servers multithreading
- * or network), we always wait for active request to be handler before
- * sending a new one. If there is an active request, we will put varible
- * "burst" to queue that will be purged after current request is handled.
- *
- */
- public void sendPendingVariableChanges() {
- if (applicationRunning) {
- if (hasActiveRequest()) {
- // skip empty queues if there are pending bursts to be sent
- if (pendingVariables.size() > 0
- || pendingVariableBursts.size() == 0) {
- Vector burst = (Vector) pendingVariables.clone();
- pendingVariableBursts.add(burst);
- }
- } else {
- buildAndSendVariableBurst(pendingVariables);
- }
- }
- }
-
- private void buildAndSendVariableBurst(Vector pendingVariables) {
- final StringBuffer req = new StringBuffer();
-
- for (int i = 0; i < pendingVariables.size(); i++) {
- if (i > 0) {
- if (i % 2 == 0) {
- req.append(VAR_RECORD_SEPARATOR);
- } else {
- req.append(VAR_FIELD_SEPARATOR);
- }
- }
- req.append(pendingVariables.get(i));
- }
-
- pendingVariables.clear();
- makeUidlRequest(req.toString(), false);
- }
-
- public void updateVariable(String paintableId, String variableName,
- String newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, newValue, immediate, 's');
- }
-
- public void updateVariable(String paintableId, String variableName,
- int newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
- 'i');
- }
-
- public void updateVariable(String paintableId, String variableName,
- long newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
- 'l');
- }
-
- public void updateVariable(String paintableId, String variableName,
- float newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
- 'f');
- }
-
- public void updateVariable(String paintableId, String variableName,
- double newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
- 'd');
- }
-
- public void updateVariable(String paintableId, String variableName,
- boolean newValue, boolean immediate) {
- addVariableToQueue(paintableId, variableName, newValue ? "true"
- : "false", immediate, 'b');
- }
-
- public void updateVariable(String paintableId, String variableName,
- Object[] values, boolean immediate) {
- final StringBuffer buf = new StringBuffer();
- for (int i = 0; i < values.length; i++) {
- if (i > 0) {
- buf.append(",");
- }
- buf.append(values[i].toString());
- }
- addVariableToQueue(paintableId, variableName, buf.toString(),
- immediate, 'a');
- }
-
- /**
- * Update generic component features.
- *
- * <h2>Selecting correct implementation</h2>
- *
- * <p>
- * The implementation of a component depends on many properties, including
- * styles, component features, etc. Sometimes the user changes those
- * properties after the component has been created. Calling this method in
- * the beginning of your updateFromUIDL -method automatically replaces your
- * component with more appropriate if the requested implementation changes.
- * </p>
- *
- * <h2>Caption, icon, error messages and description</h2>
- *
- * <p>
- * Component can delegate management of caption, icon, error messages and
- * description to parent layout. This is optional an should be decided by
- * component author
- * </p>
- *
- * <h2>Component visibility and disabling</h2>
- *
- * This method will manage component visibility automatically and if
- * component is an instanceof FocusWidget, also handle component disabling
- * when needed.
- *
- * @param component
- * Widget to be updated, expected to implement an instance of
- * Paintable
- * @param uidl
- * UIDL to be painted
- * @param manageCaption
- * True if you want to delegate caption, icon, description and
- * error message management to parent.
- *
- * @return Returns true iff no further painting is needed by caller
- */
- public boolean updateComponent(Widget component, UIDL uidl,
- boolean manageCaption) {
-
- // If the server request that a cached instance should be used, do
- // nothing
- if (uidl.getBooleanAttribute("cached")) {
- return true;
- }
-
- // Visibility
- boolean visible = !uidl.getBooleanAttribute("invisible");
- component.setVisible(visible);
- if (!visible) {
- return true;
- }
-
- // Switch to correct implementation if needed
- if (!widgetSet.isCorrectImplementation(component, uidl)) {
- final Container parent = Util.getParentLayout(component);
- if (parent != null) {
- final Widget w = (Widget) widgetSet.createWidget(uidl);
- parent.replaceChildComponent(component, w);
- registerPaintable(uidl.getId(), (Paintable) w);
- ((Paintable) w).updateFromUIDL(uidl, this);
- return true;
- }
- }
-
- updateComponentSize(component, uidl);
-
- boolean enabled = !uidl.getBooleanAttribute("disabled");
- if (component instanceof FocusWidget) {
- FocusWidget fw = (FocusWidget) component;
- fw.setEnabled(enabled);
- if (uidl.hasAttribute("tabindex")) {
- fw.setTabIndex(uidl.getIntAttribute("tabindex"));
- }
- }
-
- StringBuffer styleBuf = new StringBuffer();
- final String primaryName = component.getStylePrimaryName();
- styleBuf.append(primaryName);
-
- // first disabling and read-only status
- if (!enabled) {
- styleBuf.append(" ");
- styleBuf.append("i-disabled");
- }
- if (uidl.getBooleanAttribute("readonly")) {
- styleBuf.append(" ");
- styleBuf.append("i-readonly");
- }
-
- // add additional styles as css classes, prefixed with component default
- // stylename
- if (uidl.hasAttribute("style")) {
- final String[] styles = uidl.getStringAttribute("style").split(" ");
- for (int i = 0; i < styles.length; i++) {
- styleBuf.append(" ");
- styleBuf.append(primaryName);
- styleBuf.append("-");
- styleBuf.append(styles[i]);
- }
- }
-
- // add modified classname to Fields
- if (uidl.hasAttribute("modified") && component instanceof Field) {
- styleBuf.append(" ");
- styleBuf.append(MODIFIED_CLASSNAME);
- }
-
- TooltipInfo tooltipInfo = getTitleInfo((Paintable) component);
- if (uidl.hasAttribute("description")) {
- tooltipInfo.setTitle(uidl.getStringAttribute("description"));
- } else {
- tooltipInfo.setTitle(null);
- }
-
- // add error classname to components w/ error
- if (uidl.hasAttribute("error")) {
- styleBuf.append(" ");
- styleBuf.append(primaryName);
- styleBuf.append(ERROR_CLASSNAME_EXT);
-
- tooltipInfo.setErrorUidl(uidl.getErrors());
- } else {
- tooltipInfo.setErrorUidl(null);
- }
-
- // add required style to required components
- if (uidl.hasAttribute("required")) {
- styleBuf.append(" ");
- styleBuf.append(primaryName);
- styleBuf.append(REQUIRED_CLASSNAME_EXT);
- }
-
- // Styles + disabled & readonly
- component.setStyleName(styleBuf.toString());
-
- // Set captions
- if (manageCaption) {
- final Container parent = Util.getParentLayout(component);
- if (parent != null) {
- parent.updateCaption((Paintable) component, uidl);
- }
- }
-
- if (usePaintableIdsInDOM) {
- DOM.setElementProperty(component.getElement(), "id", uidl.getId());
- }
-
- return false;
- }
-
- private void updateComponentSize(Widget component, UIDL uidl) {
- String w = uidl.hasAttribute("width") ? uidl
- .getStringAttribute("width") : "";
- component.setWidth(w);
- String h = uidl.hasAttribute("height") ? uidl
- .getStringAttribute("height") : "";
- component.setHeight(h);
- }
-
- /**
- * Get either existing or new Paintable for given UIDL.
- *
- * If corresponding Paintable has been previously painted, return it.
- * Otherwise create and register a new Paintable from UIDL. Caller must
- * update the returned Paintable from UIDL after it has been connected to
- * parent.
- *
- * @param uidl
- * UIDL to create Paintable from.
- * @return Either existing or new Paintable corresponding to UIDL.
- */
- public Paintable getPaintable(UIDL uidl) {
- final String id = uidl.getId();
- Paintable w = getPaintable(id);
- if (w != null) {
- return w;
- }
- w = widgetSet.createWidget(uidl);
- registerPaintable(id, w);
- return w;
- }
-
- public String getResource(String name) {
- return (String) resourcesMap.get(name);
- }
-
- /**
- * Singleton method to get instance of app's context menu.
- *
- * @return IContextMenu object
- */
- public IContextMenu getContextMenu() {
- if (contextMenu == null) {
- contextMenu = new IContextMenu();
- if (usePaintableIdsInDOM) {
- DOM.setElementProperty(contextMenu.getElement(), "id",
- "PID_TOOLKIT_CM");
- }
- }
- return contextMenu;
- }
-
- /**
- * Translates custom protocols in UIRL URI's to be recognizable by browser.
- * All uri's from UIDL should be routed via this method before giving them
- * to browser due URI's in UIDL may contain custom protocols like theme://.
- *
- * @param toolkitUri
- * toolkit URI from uidl
- * @return translated URI ready for browser
- */
- public String translateToolkitUri(String toolkitUri) {
- if (toolkitUri == null) {
- return null;
- }
- if (toolkitUri.startsWith("theme://")) {
- final String themeUri = configuration.getThemeUri();
- if (themeUri == null) {
- console
- .error("Theme not set: ThemeResource will not be found. ("
- + toolkitUri + ")");
- }
- toolkitUri = themeUri + toolkitUri.substring(7);
- }
- return toolkitUri;
- }
-
- public String getThemeUri() {
- return configuration.getThemeUri();
- }
-
- /**
- * Listens for Notification hide event, and redirects. Used for system
- * messages, such as session expired.
- *
- */
- private class NotificationRedirect implements INotification.EventListener {
- String url;
-
- NotificationRedirect(String url) {
- this.url = url;
- }
-
- public void notificationHidden(HideEvent event) {
- redirect(url);
- }
-
- }
-
- /* Extended title handling */
-
- /**
- * Data showed in tooltips are stored centrilized as it may be needed in
- * varios place: caption, layouts, and in owner components themselves.
- *
- * Updating TooltipInfo is done in updateComponent method.
- *
- */
- public TooltipInfo getTitleInfo(Paintable titleOwner) {
- TooltipInfo info = (TooltipInfo) paintableToTitle.get(titleOwner);
- if (info == null) {
- info = new TooltipInfo();
- paintableToTitle.put(titleOwner, info);
- }
- return info;
- }
-
- private final ITooltip tooltip = new ITooltip(this);
-
- /**
- * Component may want to delegate Tooltip handling to client. Layouts add
- * Tooltip (description, errors) to caption, but some components may want
- * them to appear one other elements too.
- *
- * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS
- *
- * @param event
- * @param owner
- */
- public void handleTooltipEvent(Event event, Paintable owner) {
- tooltip.handleTooltipEvent(event, owner);
-
- }
-
- /**
- * Adds PNG-fix conditionally (only for IE6) to the specified IMG -element.
- *
- * @param el
- * the IMG element to fix
- */
- public void addPngFix(Element el) {
- BrowserInfo b = BrowserInfo.get();
- if (b.isIE6()) {
- Util.addPngFix(el, getThemeUri()
- + "/../default/common/img/blank.gif");
- }
- }
-
- /*
- * Helper to run layout functions triggered by child components with a
- * decent interval.
- */
- private final Timer layoutTimer = new Timer() {
-
- private boolean isPending = false;
-
- public void schedule(int delayMillis) {
- if (!isPending) {
- super.schedule(delayMillis);
- isPending = true;
- }
- }
-
- public void run() {
- getConsole().log("Running re-layout");
- Util.runDescendentsLayout(view);
- isPending = false;
- }
- };
-
- /**
- * Components can call this function to run all layout functions. This is
- * usually done, when component knows that its size has changed.
- */
- public void requestLayoutPhase() {
- layoutTimer.schedule(500);
- }
- }
|