[kune-commits] r1877 - in trunk/src/main/java/cc/kune: core/client/sn/actions gspace/client/viewers wave/client
Vicente J. Ruiz Jurado
vjrj_ at ourproject.org
Wed May 30 12:46:30 CEST 2012
Author: vjrj_
Date: 2012-05-30 12:46:29 +0200 (Wed, 30 May 2012)
New Revision: 1877
Added:
trunk/src/main/java/cc/kune/wave/client/WaveUnsavedIndicator.java
Modified:
trunk/src/main/java/cc/kune/core/client/sn/actions/SessionAction.java
trunk/src/main/java/cc/kune/gspace/client/viewers/ContentViewerPanel.java
trunk/src/main/java/cc/kune/wave/client/KuneStagesProvider.java
trunk/src/main/java/cc/kune/wave/client/WebClient.java
Log:
CLOSED - # 278: Implements a custom UnsavedDataListener
http://kune.ourproject.org/issues/ticket/278
Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/SessionAction.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/SessionAction.java 2012-05-24 13:19:59 UTC (rev 1876)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/SessionAction.java 2012-05-30 10:46:29 UTC (rev 1877)
@@ -27,9 +27,22 @@
import com.google.inject.Inject;
+/**
+ * The Class SessionAction is used to create actions that depends of current
+ * session auth status
+ */
public abstract class SessionAction extends AbstractExtendedAction {
+
protected final Session session;
+ /**
+ * Instantiates a new session action.
+ *
+ * @param session
+ * the kune session
+ * @param authNeed
+ * if user authentication is needed
+ */
@Inject
public SessionAction(final Session session, final boolean authNeed) {
this.session = session;
@@ -42,6 +55,14 @@
});
}
+ /**
+ * Refresh status.
+ *
+ * @param authNeed
+ * the auth need
+ * @param isLogged
+ * the is logged
+ */
public void refreshStatus(final boolean authNeed, final boolean isLogged) {
boolean visible = false;
final boolean noLogged = !isLogged;
@@ -54,6 +75,12 @@
setVisible(visible);
}
+ /**
+ * Sets the visible.
+ *
+ * @param visible
+ * the new visible
+ */
public void setVisible(final boolean visible) {
setEnabled(visible);
putValue(GuiActionDescrip.VISIBLE, visible);
Modified: trunk/src/main/java/cc/kune/gspace/client/viewers/ContentViewerPanel.java
===================================================================
--- trunk/src/main/java/cc/kune/gspace/client/viewers/ContentViewerPanel.java 2012-05-24 13:19:59 UTC (rev 1876)
+++ trunk/src/main/java/cc/kune/gspace/client/viewers/ContentViewerPanel.java 2012-05-30 10:46:29 UTC (rev 1877)
@@ -48,6 +48,7 @@
import cc.kune.wave.client.WaveClientProvider;
import cc.kune.wave.client.WaveClientUtils;
import cc.kune.wave.client.WaveClientView;
+import cc.kune.wave.client.WaveUnsavedIndicator;
import cc.kune.wave.client.WebClientMock;
import com.google.gwt.core.client.GWT;
@@ -80,12 +81,14 @@
@UiField
DeckPanel deck;
private final ContentDropController dropController;
+ private FramedPanel dummyWaveFrame;
private final GSpaceArmor gsArmor;
private final I18nTranslationService i18n;
private IdGenerator idGenerator;
private Element loading;
@UiField
InlineHTML onlyViewPanel;
+
private ProfileManager profiles;
private final StateManager stateManager;
@@ -94,27 +97,28 @@
private KuneStagesProvider wave;
private final WaveClientProvider waveClientProv;
-
private ImplPanel waveHolder;
@UiField
ImplPanel waveHolderParent;
+
private final WaveStore waveStore = new SimpleWaveStore();
+ private final WaveUnsavedIndicator waveUnsavedIndicator;
+
private final Widget widget;
- private FramedPanel dummyWaveFrame;
-
@Inject
public ContentViewerPanel(final GSpaceArmor wsArmor, final WaveClientProvider waveClient,
final ContentCapabilitiesRegistry capabilitiesRegistry, final I18nTranslationService i18n,
final EventBus eventBus, final StateManager stateManager,
- final ContentDropController dropController) {
+ final ContentDropController dropController, final WaveUnsavedIndicator waveUnsavedIndicator) {
this.gsArmor = wsArmor;
this.waveClientProv = waveClient;
this.capabilitiesRegistry = capabilitiesRegistry;
this.i18n = i18n;
this.stateManager = stateManager;
this.dropController = dropController;
+ this.waveUnsavedIndicator = waveUnsavedIndicator;
widget = uiBinder.createAndBindUi(this);
contentTitle = new ContentTitleWidget(i18n, gsArmor, capabilitiesRegistry.getIconsRegistry());
eventBus.addHandler(WaveClientClearEvent.getType(),
@@ -228,9 +232,10 @@
// UIObject.setVisible(waveFrame.getElement(), true);
waveHolder.getElement().appendChild(loading);
final Element holder = waveHolder.getElement().appendChild(Document.get().createDivElement());
- final KuneStagesProvider wave = new KuneStagesProvider(holder, (com.google.gwt.dom.client.Element) new Label().getElement(), waveHolder, dummyWaveFrame, waveRef, channel,
- idGenerator, profiles, waveStore, isNewWave,
- org.waveprotocol.box.webclient.client.Session.get().getDomain(), true, i18n);
+ final KuneStagesProvider wave = new KuneStagesProvider(holder, new Label().getElement(),
+ waveHolder, dummyWaveFrame, waveRef, channel, idGenerator, profiles, waveStore, isNewWave,
+ org.waveprotocol.box.webclient.client.Session.get().getDomain(), true, i18n,
+ waveUnsavedIndicator);
this.wave = wave;
wave.load(new Command() {
@Override
Modified: trunk/src/main/java/cc/kune/wave/client/KuneStagesProvider.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/client/KuneStagesProvider.java 2012-05-24 13:19:59 UTC (rev 1876)
+++ trunk/src/main/java/cc/kune/wave/client/KuneStagesProvider.java 2012-05-30 10:46:29 UTC (rev 1877)
@@ -19,7 +19,6 @@
package cc.kune.wave.client;
import org.waveprotocol.box.webclient.client.RemoteViewServiceMultiplexer;
-import org.waveprotocol.box.webclient.client.SavedStateIndicator;
import org.waveprotocol.box.webclient.client.StageTwoProvider;
import org.waveprotocol.box.webclient.client.WindowTitleHandler;
import org.waveprotocol.box.webclient.search.WaveContext;
@@ -73,31 +72,46 @@
private final static AsyncHolder<Object> HALT = new AsyncHolder<Object>() {
@Override
- public void call(Accessor<Object> accessor) {
+ public void call(final Accessor<Object> accessor) {
// Never ready, so never notify the accessor.
}
};
- private final Element wavePanelElement;
- private final Element unsavedIndicatorElement;
- private final FramedPanel waveFrame;
- private final LogicalPanel rootPanel;
- private final WaveRef waveRef;
+ /**
+ * Finds the blip that should receive the focus and selects it.
+ */
+ private static void selectAndFocusOnBlip(final Reader reader, final ModelAsViewProvider views,
+ final ConversationView wave, final FocusFramePresenter focusFrame, final WaveRef waveRef) {
+ final FocusBlipSelector blipSelector =
+ FocusBlipSelector.create(wave, views, reader, new ViewTraverser());
+ final BlipView blipUi = blipSelector.selectBlipByWaveRef(waveRef);
+ // Focus on the selected blip.
+ if (blipUi != null) {
+ focusFrame.focus(blipUi);
+ }
+ }
private final RemoteViewServiceMultiplexer channel;
+ private boolean closed;
+ private final I18nTranslationService i18n;
private final IdGenerator idGenerator;
- private final ProfileManager profiles;
- private final WaveStore waveStore;
private final boolean isNewWave;
private final String localDomain;
+ private StageOne one;
+ private final ProfileManager profiles;
+ private final LogicalPanel rootPanel;
+ private final boolean showParticipantsPanel;
- private boolean closed;
- private StageOne one;
+ private StageThree three;
private StageTwo two;
- private StageThree three;
+ private final Element unsavedIndicatorElement;
private WaveContext wave;
- private final boolean showParticipantsPanel;
- private final I18nTranslationService i18n;
+ private final FramedPanel waveFrame;
+ private final Element wavePanelElement;
+ private final WaveRef waveRef;
+ private final WaveStore waveStore;
+ private final WaveUnsavedIndicator waveUnsavedIndicator;
+
/**
* @param wavePanelElement the DOM element to become the wave panel.
* @param unsavedIndicatorElement the element that displays the wave saved state.
@@ -110,10 +124,10 @@
* @param isNewWave true if the wave is a new client-created wave
* @param idGenerator
*/
- public KuneStagesProvider(Element wavePanelElement, Element unsavedIndicatorElement,
- LogicalPanel rootPanel, FramedPanel waveFrame, WaveRef waveRef, RemoteViewServiceMultiplexer channel,
- IdGenerator idGenerator, ProfileManager profiles, WaveStore store, boolean isNewWave,
- String localDomain, boolean showParticipantsPanel, I18nTranslationService i18n) {
+ public KuneStagesProvider(final Element wavePanelElement, final Element unsavedIndicatorElement,
+ final LogicalPanel rootPanel, final FramedPanel waveFrame, final WaveRef waveRef, final RemoteViewServiceMultiplexer channel,
+ final IdGenerator idGenerator, final ProfileManager profiles, final WaveStore store, final boolean isNewWave,
+ final String localDomain, final boolean showParticipantsPanel, final I18nTranslationService i18n, final WaveUnsavedIndicator waveUnsavedIndicator) {
this.wavePanelElement = wavePanelElement;
this.unsavedIndicatorElement = unsavedIndicatorElement;
this.waveFrame = waveFrame;
@@ -127,49 +141,25 @@
this.localDomain = localDomain;
this.showParticipantsPanel = showParticipantsPanel;
this.i18n = i18n;
+ this.waveUnsavedIndicator = waveUnsavedIndicator;
}
@Override
- protected AsyncHolder<StageZero> createStageZeroLoader() {
- return haltIfClosed(super.createStageZeroLoader());
- }
-
- @Override
- protected AsyncHolder<StageOne> createStageOneLoader(StageZero zero) {
+ protected AsyncHolder<StageOne> createStageOneLoader(final StageZero zero) {
return haltIfClosed(new StageOne.DefaultProvider(zero) {
@Override
- protected Element createWaveHolder() {
- return wavePanelElement;
+ protected LogicalPanel createWaveContainer() {
+ return rootPanel;
}
@Override
- protected LogicalPanel createWaveContainer() {
- return rootPanel;
+ protected Element createWaveHolder() {
+ return wavePanelElement;
}
});
}
@Override
- protected AsyncHolder<StageTwo> createStageTwoLoader(StageOne one) {
- return haltIfClosed(new StageTwoProvider(this.one = one, waveRef, channel, isNewWave,
- idGenerator, profiles, new SavedStateIndicator(unsavedIndicatorElement)) {
- // Kune patch
- @Override
- protected DomRenderer createRenderer() {
- return KuneFullDomWaveRendererImpl.create(getConversations(), getProfileManager(),
- getBlipDetailer(), getViewIdMapper(), getBlipQueue(), getThreadReadStateMonitor(),
- createViewFactories(), showParticipantsPanel);
-
- // Warning: this run into issue #73
- // @Override
- // protected void installFeatures() {
- // WavePanelResourceLoader.loadCss();
- // // KuneWavePanelResourceLoader.loadCss();
- // }
-
- }});}
-
- @Override
protected AsyncHolder<StageThree> createStageThreeLoader(final StageTwo two) {
return haltIfClosed(new StageThree.DefaultProvider(this.two = two) {
@Override
@@ -177,7 +167,7 @@
// Prepend an init wave flow onto the stage continuation.
super.create(new Accessor<StageThree>() {
@Override
- public void use(StageThree x) {
+ public void use(final StageThree x) {
onStageThreeLoaded(x, whenReady);
}
});
@@ -216,53 +206,32 @@
});
}
-
- private void onStageThreeLoaded(StageThree x, Accessor<StageThree> whenReady) {
- if (closed) {
- // Stop the loading process.
- return;
- }
- three = x;
- if (isNewWave) {
- initNewWave(x);
- } else {
- handleExistingWave(x);
- }
- wave = new WaveContext(
- two.getWave(), two.getConversations(), two.getSupplement(), two.getReadMonitor());
- waveStore.add(wave);
- install();
- whenReady.use(x);
- }
- private void initNewWave(StageThree three) {
- // Do the new-wave flow.
- ModelAsViewProvider views = two.getModelAsViewProvider();
- BlipQueueRenderer blipQueue = two.getBlipQueue();
- ConversationView wave = two.getConversations();
+ @Override
+ protected AsyncHolder<StageTwo> createStageTwoLoader(final StageOne one) {
+ return haltIfClosed(new StageTwoProvider(this.one = one, waveRef, channel, isNewWave,
+ idGenerator, profiles, waveUnsavedIndicator) {
+ // Kune patch
+ @Override
+ protected DomRenderer createRenderer() {
+ return KuneFullDomWaveRendererImpl.create(getConversations(), getProfileManager(),
+ getBlipDetailer(), getViewIdMapper(), getBlipQueue(), getThreadReadStateMonitor(),
+ createViewFactories(), showParticipantsPanel);
+
+ // Warning: this run into issue #73
+ // @Override
+ // protected void installFeatures() {
+ // WavePanelResourceLoader.loadCss();
+ // // KuneWavePanelResourceLoader.loadCss();
+ // }
- // Force rendering to finish.
- blipQueue.flush();
- BlipView blipUi = views.getBlipView(wave.getRoot().getRootThread().getFirstBlip());
- three.getEditActions().startEditing(blipUi);
- }
+ }});}
- private void handleExistingWave(StageThree three) {
- if (waveRef.hasDocumentId()) {
- BlipQueueRenderer blipQueue = two.getBlipQueue();
- blipQueue.flush();
- selectAndFocusOnBlip(two.getReader(), two.getModelAsViewProvider(), two.getConversations(),
- one.getFocusFrame(), waveRef);
+ @Override
+ protected AsyncHolder<StageZero> createStageZeroLoader() {
+ return haltIfClosed(super.createStageZeroLoader());
}
- }
-
- /**
- * A hook to install features that are not dependent an a certain stage.
- */
- protected void install() {
- WindowTitleHandler.install(waveStore, waveFrame);
- }
-
+
public void destroy() {
if (wave != null) {
waveStore.remove(wave);
@@ -294,26 +263,58 @@
}
closed = true;
}
- /**
- * Finds the blip that should receive the focus and selects it.
- */
- private static void selectAndFocusOnBlip(Reader reader, ModelAsViewProvider views,
- ConversationView wave, FocusFramePresenter focusFrame, WaveRef waveRef) {
- FocusBlipSelector blipSelector =
- FocusBlipSelector.create(wave, views, reader, new ViewTraverser());
- BlipView blipUi = blipSelector.selectBlipByWaveRef(waveRef);
- // Focus on the selected blip.
- if (blipUi != null) {
- focusFrame.focus(blipUi);
- }
- }
/**
* @return a halting provider if this stage is closed. Otherwise, returns the
* given provider.
*/
@SuppressWarnings("unchecked") // HALT is safe as a holder for any type
- private <T> AsyncHolder<T> haltIfClosed(AsyncHolder<T> provider) {
+ private <T> AsyncHolder<T> haltIfClosed(final AsyncHolder<T> provider) {
return closed ? (AsyncHolder<T>) HALT : provider;
}
+
+ private void handleExistingWave(final StageThree three) {
+ if (waveRef.hasDocumentId()) {
+ final BlipQueueRenderer blipQueue = two.getBlipQueue();
+ blipQueue.flush();
+ selectAndFocusOnBlip(two.getReader(), two.getModelAsViewProvider(), two.getConversations(),
+ one.getFocusFrame(), waveRef);
+ }
+ }
+
+ private void initNewWave(final StageThree three) {
+ // Do the new-wave flow.
+ final ModelAsViewProvider views = two.getModelAsViewProvider();
+ final BlipQueueRenderer blipQueue = two.getBlipQueue();
+ final ConversationView wave = two.getConversations();
+
+ // Force rendering to finish.
+ blipQueue.flush();
+ final BlipView blipUi = views.getBlipView(wave.getRoot().getRootThread().getFirstBlip());
+ three.getEditActions().startEditing(blipUi);
+ }
+ /**
+ * A hook to install features that are not dependent an a certain stage.
+ */
+ protected void install() {
+ WindowTitleHandler.install(waveStore, waveFrame);
+ }
+
+ private void onStageThreeLoaded(final StageThree x, final Accessor<StageThree> whenReady) {
+ if (closed) {
+ // Stop the loading process.
+ return;
+ }
+ three = x;
+ if (isNewWave) {
+ initNewWave(x);
+ } else {
+ handleExistingWave(x);
+ }
+ wave = new WaveContext(
+ two.getWave(), two.getConversations(), two.getSupplement(), two.getReadMonitor());
+ waveStore.add(wave);
+ install();
+ whenReady.use(x);
+ }
}
Added: trunk/src/main/java/cc/kune/wave/client/WaveUnsavedIndicator.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/client/WaveUnsavedIndicator.java (rev 0)
+++ trunk/src/main/java/cc/kune/wave/client/WaveUnsavedIndicator.java 2012-05-30 10:46:29 UTC (rev 1877)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cc.kune.wave.client;
+
+import org.waveprotocol.wave.client.scheduler.Scheduler;
+import org.waveprotocol.wave.client.scheduler.SchedulerInstance;
+import org.waveprotocol.wave.client.scheduler.TimerService;
+import org.waveprotocol.wave.concurrencycontrol.common.UnsavedDataListener;
+
+import cc.kune.common.client.notify.NotifyUser;
+import cc.kune.core.client.i18n.I18n;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+ at Singleton
+public class WaveUnsavedIndicator implements UnsavedDataListener {
+
+ private enum SavedState {
+ SAVED, UNSAVED;
+ }
+
+ private static final int UPDATE_DELAY_MS = 300;
+
+ private SavedState currentSavedState = null;
+
+ private final TimerService scheduler;
+
+ private final Scheduler.Task updateTask = new Scheduler.Task() {
+ @Override
+ public void execute() {
+ updateDisplay();
+ }
+ };
+
+ private SavedState visibleSavedState = SavedState.SAVED;
+
+ /**
+ * Simple saved state indicator.
+ *
+ * @author danilatos at google.com (Daniel Danilatos)
+ * @author yurize at apache.org (Yuri Zelikov)
+ */
+ @Inject
+ public WaveUnsavedIndicator() {
+ this.scheduler = SchedulerInstance.getLowPriorityTimer();
+ }
+
+ private void maybeUpdateDisplay() {
+ if (needsUpdating()) {
+ switch (currentSavedState) {
+ case SAVED:
+ scheduler.scheduleDelayed(updateTask, UPDATE_DELAY_MS);
+ break;
+ case UNSAVED:
+ updateDisplay();
+ break;
+ default:
+ throw new AssertionError("unknown " + currentSavedState);
+ }
+ } else {
+ scheduler.cancel(updateTask);
+ }
+ }
+
+ private boolean needsUpdating() {
+ return visibleSavedState != currentSavedState;
+ }
+
+ @Override
+ public void onClose(final boolean everythingCommitted) {
+ if (everythingCommitted) {
+ saved();
+ } else {
+ unsaved();
+ }
+ }
+
+ @Override
+ public void onUpdate(final UnsavedDataInfo unsavedDataInfo) {
+ if (unsavedDataInfo.estimateUnacknowledgedSize() != 0) {
+ currentSavedState = SavedState.UNSAVED;
+ unsaved();
+ } else {
+ currentSavedState = SavedState.SAVED;
+ saved();
+ }
+ }
+
+ public void saved() {
+ maybeUpdateDisplay();
+ }
+
+ public void unsaved() {
+ maybeUpdateDisplay();
+ }
+
+ private void updateDisplay() {
+ visibleSavedState = currentSavedState;
+ switch (visibleSavedState) {
+ case SAVED:
+ NotifyUser.hideProgress();
+ break;
+ case UNSAVED:
+ NotifyUser.showProgress(I18n.t("Saving"));
+ break;
+ default:
+ throw new AssertionError("unknown " + currentSavedState);
+ }
+ }
+
+}
Modified: trunk/src/main/java/cc/kune/wave/client/WebClient.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/client/WebClient.java 2012-05-24 13:19:59 UTC (rev 1876)
+++ trunk/src/main/java/cc/kune/wave/client/WebClient.java 2012-05-30 10:46:29 UTC (rev 1877)
@@ -106,27 +106,126 @@
interface Binder extends UiBinder<DockLayoutPanel, WebClient> {
}
+ /**
+ * An exception handler that reports exceptions using a <em>shiny banner</em>
+ * (an alert placed on the top of the screen). Once the stack trace is
+ * prepared, it is revealed in the banner via a link.
+ */
+ public static class ErrorHandler implements UncaughtExceptionHandler {
+ public static void getStackTraceAsync(final Throwable t, final Accessor<SafeHtml> whenReady) {
+ // TODO: Request stack-trace de-obfuscation. For now, just use the
+ // javascript stack trace.
+ //
+ // Use minimal services here, in order to avoid the chance that reporting
+ // the error produces more errors. In particular, do not use WIAB's
+ // scheduler to run this command.
+ // Also, this code could potentially be put behind a runAsync boundary, to
+ // save whatever dependencies it uses from the initial download.
+ new Timer() {
+ @Override
+ public void run() {
+ final SafeHtmlBuilder stack = new SafeHtmlBuilder();
+
+ Throwable error = t;
+ while (error != null) {
+ final String token = String.valueOf((new Date()).getTime());
+ stack.appendHtmlConstant("Token: " + token + "<br> ");
+ stack.appendEscaped(String.valueOf(error.getMessage())).appendHtmlConstant("<br>");
+ for (final StackTraceElement elt : error.getStackTrace()) {
+ stack.appendHtmlConstant(" ")
+ .appendEscaped(maybe(elt.getClassName(), "??")).appendHtmlConstant(".") //
+ .appendEscaped(maybe(elt.getMethodName(), "??")).appendHtmlConstant(" (") //
+ .appendEscaped(maybe(elt.getFileName(), "??")).appendHtmlConstant(":") //
+ .appendEscaped(maybe(elt.getLineNumber(), "??")).appendHtmlConstant(")") //
+ .appendHtmlConstant("<br>");
+ }
+ error = error.getCause();
+ if (error != null) {
+ stack.appendHtmlConstant("Caused by: ");
+ }
+ }
+
+ whenReady.use(stack.toSafeHtml());
+ }
+ }.schedule(1);
+ }
+
+ public static void install() {
+ GWT.setUncaughtExceptionHandler(new ErrorHandler(GWT.getUncaughtExceptionHandler()));
+ }
+
+ private static String maybe(final int value, final String otherwise) {
+ return value != -1 ? String.valueOf(value) : otherwise;
+ }
+
+ private static String maybe(final String value, final String otherwise) {
+ return value != null ? value : otherwise;
+ }
+
+ /**
+ * Indicates whether an error has already been reported (at most one error
+ * is ever reported by this handler).
+ */
+ private boolean hasFired;
+
+ /** Next handler in the handler chain. */
+ private final UncaughtExceptionHandler next;
+
+ private ErrorHandler(final UncaughtExceptionHandler next) {
+ this.next = next;
+ }
+
+ @Override
+ public void onUncaughtException(final Throwable e) {
+ if (!hasFired) {
+ hasFired = true;
+ // final ErrorIndicatorPresenter error =
+ // ErrorIndicatorPresenter.create(RootPanel.get("banner"));
+ getStackTraceAsync(e, new Accessor<SafeHtml>() {
+ @Override
+ public void use(final SafeHtml stack) {
+ // error.addDetail(stack, null);
+ // REMOTE_LOG.severe(stack.asString().replace("<br>", "\n"));
+ final String message = stack.asString().replace("<br>", "\n");
+ REMOTE_LOG.severe(message);
+ NotifyUser.logError(message);
+ NotifyUser.showProgress("Error");
+ new Timer() {
+ @Override
+ public void run() {
+ NotifyUser.hideProgress();
+ }}.schedule(5000);
+ }
+ });
+ }
+
+ if (next != null) {
+ next.onUncaughtException(e);
+ }
+ }
+ }
+
interface Style extends CssResource {
}
private static final Binder BINDER = GWT.create(Binder.class);
+ static Log LOG = Log.get(WebClient.class);
- static Log LOG = Log.get(WebClient.class);
// Use of GWT logging is only intended for sending exception reports to the
// server, nothing else in the client should use java.util.logging.
// Please also see WebClientDemo.gwt.xml.
private static final Logger REMOTE_LOG = Logger.getLogger("REMOTE_LOG");
-
/** Creates a popup that warns about network disconnects. */
private static UniversalPopup createTurbulencePopup() {
- PopupChrome chrome = PopupChromeFactory.createPopupChrome();
- UniversalPopup popup =
+ final PopupChrome chrome = PopupChromeFactory.createPopupChrome();
+ final UniversalPopup popup =
PopupFactory.createPopup(null, new CenterPopupPositioner(), chrome, true);
popup.add(new HTML("<div style='color: red; padding: 5px; text-align: center;'>"
+ "<b>A turbulence detected!<br></br>"
+ " Please save your last changes to somewhere and reload the wave.</b></div>"));
return popup;
}
+
private RemoteViewServiceMultiplexer channel;
private final EventBus eventBus;
@@ -136,8 +235,8 @@
private IdGenerator idGenerator;
private final InboxCountPresenter inboxCount;
+ private final Element loading = new LoadingIndicator().getElement();
- private final Element loading = new LoadingIndicator().getElement();
private ParticipantId loggedInUser;
@UiField
@@ -148,10 +247,10 @@
@UiField(provided = true)
final SearchPanelWidget searchPanel;
+
@UiField
SplitLayoutPanel splitPanel;
-
@UiField
Style style;
@@ -162,9 +261,11 @@
@UiField
FramedPanel waveFrame;
-
ImplPanel waveHolder;
private final WaveStore waveStore = new SimpleWaveStore();
+
+ private final WaveUnsavedIndicator waveUnsavedIndicator;
+
/**
* Create a remote websocket to talk to the server-side FedOne service.
*/
@@ -174,11 +275,12 @@
* This is the entry point method.
*/
@Inject
- public WebClient(final EventBus eventBus, final KuneWaveProfileManager profiles, final InboxCountPresenter inboxCount, final TokenMatcher tokenMatcher, final cc.kune.core.client.state.Session session, final I18nTranslationService i18n) {
+ public WebClient(final EventBus eventBus, final KuneWaveProfileManager profiles, final InboxCountPresenter inboxCount, final TokenMatcher tokenMatcher, final cc.kune.core.client.state.Session session, final I18nTranslationService i18n, final WaveUnsavedIndicator waveUnsavedIndicator) {
this.eventBus = eventBus;
this.profiles = profiles;
this.inboxCount = inboxCount;
this.i18n = i18n;
+ this.waveUnsavedIndicator = waveUnsavedIndicator;
searchPanel = new SearchPanelWidget(new SearchPanelRenderer(profiles));
ErrorHandler.install();
eventBus.addHandler(StackErrorEvent.getType(), new StackErrorEvent.StackErrorHandler() {
@@ -268,12 +370,27 @@
public void getStackTraceAsync(final Throwable caught, final Accessor<SafeHtml> accessor) {
ErrorHandler.getStackTraceAsync(caught, accessor);
}
-
@Override
public ImplPanel getWaveHolder() {
return waveHolder;
}
+
@Override
+ public WaveWebSocketClient getWebSocket() {
+ return websocket;
+ }
+
+
+ /**
+ * Returns <code>ws(s)://yourhost[:port]/</code>.
+ */
+ // XXX check formatting wrt GPE
+ private native String getWebSocketBaseUrl(String moduleBase) /*-{
+ return ((window.location.protocol == "https:") ? "wss" : "ws")
+ + /:\/\/[^\/]+/.exec(moduleBase)[0] + "/";
+ }-*/;
+
+ @Override
public void login() {
loginImpl();
}
@@ -287,6 +404,12 @@
}
}
+ /**
+ */
+ private void loginToServer() {
+ assert loggedInUser != null;
+ channel = new RemoteViewServiceMultiplexer(websocket, loggedInUser.getAddress());
+ }
@Override
public void logout() {
@@ -297,130 +420,13 @@
clear();
}
- @Override
- public void setMaximized(final boolean maximized) {
- splitPanel.setWidgetSize(searchPanel, maximized ? 0 : 400);
- }
-
- private void setupUi() {
- // Set up UI
- DockLayoutPanel self = BINDER.createAndBindUi(this);
- // kune-patch
- // RootPanel.get("app").add(self);
- initWidget(self);
- waveHolder = new ImplPanel("");
- waveHolder.addStyleName("k-waveHolder");
- waveFrame.add(waveHolder);
- // DockLayoutPanel forcibly conflicts with sensible layout control, and
- // sticks inline styles on elements without permission. They must be
- // cleared.
- self.getElement().getStyle().clearPosition();
- splitPanel.setWidgetMinSize(searchPanel, 300);
-
- if (LogLevel.showDebug()) {
- logPanel.enable();
- } else {
- logPanel.removeFromParent();
- }
-
- setupSearchPanel();
- setupWavePanel();
- }
-
- @Override
- public WaveWebSocketClient getWebSocket() {
- return websocket;
- }
-
- private void setupSearchPanel() {
- // On wave action fire an event.
- SearchPresenter.WaveActionHandler actionHandler =
- new SearchPresenter.WaveActionHandler() {
- @Override
- public void onCreateWave() {
- ClientEvents.get().fireEvent(WaveCreationEvent.CREATE_NEW_WAVE);
- }
-
- @Override
- public void onWaveSelected(WaveId id) {
- ClientEvents.get().fireEvent(new WaveSelectionEvent(WaveRef.of(id)));
- }
- };
- Search search = SimpleSearch.create(RemoteSearchService.create(), waveStore);
- search.addListener(inboxCount.getSearchListener());
- SearchPresenter.create(search, searchPanel, actionHandler, profiles);
- }
-
- private void setupWavePanel() {
- // Hide the frame until waves start getting opened.
- UIObject.setVisible(waveFrame.getElement(), false);
-
- // Handles opening waves.
- ClientEvents.get().addWaveSelectionEventHandler(new WaveSelectionEventHandler() {
- @Override
- public void onSelection(WaveRef waveRef) {
- openWave(waveRef, false);
- }
- });
- }
-
- private void setupConnectionIndicator() {
- ClientEvents.get().addNetworkStatusEventHandler(new NetworkStatusEventHandler() {
-
- boolean isTurbulenceDetected = false;
-
- @Override
- public void onNetworkStatus(NetworkStatusEvent event) {
- Element element = Document.get().getElementById("netstatus");
- if (element != null) {
- switch (event.getStatus()) {
- case CONNECTED:
- case RECONNECTED:
- element.setInnerText("Online");
- element.setClassName("online");
- isTurbulenceDetected = false;
- turbulencePopup.hide();
- break;
- case DISCONNECTED:
- element.setInnerText("Offline");
- element.setClassName("offline");
- if (!isTurbulenceDetected) {
- isTurbulenceDetected = true;
- turbulencePopup.show();
- }
- break;
- case RECONNECTING:
- element.setInnerText("Connecting...");
- element.setClassName("connecting");
- break;
- }
- }
- }
- });
- }
-
/**
- * Returns <code>ws(s)://yourhost[:port]/</code>.
- */
- // XXX check formatting wrt GPE
- private native String getWebSocketBaseUrl(String moduleBase) /*-{return ((window.location.protocol == "https:") ? "wss" : "ws") + /:\/\/[^\/]+/.exec(moduleBase)[0] + "/";}-*/;
-
- private native boolean useSocketIO() /*-{ return !window.WebSocket }-*/;
-
- /**
- */
- private void loginToServer() {
- assert loggedInUser != null;
- channel = new RemoteViewServiceMultiplexer(websocket, loggedInUser.getAddress());
- }
-
- /**
* Shows a wave in a wave panel.
*
* @param waveRef wave id to open
* @param isNewWave whether the wave is being created by this client session.
*/
- private void openWave(WaveRef waveRef, boolean isNewWave) {
+ private void openWave(final WaveRef waveRef, final boolean isNewWave) {
LOG.info("WebClient.openWave()");
WaveClientClearEvent.fire(eventBus);
@@ -430,9 +436,9 @@
// Release the display:none.
UIObject.setVisible(waveFrame.getElement(), true);
waveHolder.getElement().appendChild(loading);
- Element holder = waveHolder.getElement().appendChild(Document.get().createDivElement());
- KuneStagesProvider wave = new KuneStagesProvider(
- holder, (com.google.gwt.dom.client.Element) new Label().getElement(), waveHolder, waveFrame, waveRef, channel, idGenerator, profiles, waveStore, isNewWave, Session.get().getDomain(), true, i18n);
+ final Element holder = waveHolder.getElement().appendChild(Document.get().createDivElement());
+ final KuneStagesProvider wave = new KuneStagesProvider(
+ holder, new Label().getElement(), waveHolder, waveFrame, waveRef, channel, idGenerator, profiles, waveStore, isNewWave, Session.get().getDomain(), true, i18n, waveUnsavedIndicator);
this.wave = wave;
wave.load(new Command() {
@Override
@@ -446,7 +452,7 @@
WaveRef fromWaveRef;
try {
fromWaveRef = GwtWaverefEncoder.decodeWaveRefFromPath(encodedToken);
- } catch (InvalidWaveRefException e) {
+ } catch (final InvalidWaveRefException e) {
LOG.info("History token contains invalid path: " + encodedToken);
return;
}
@@ -461,102 +467,104 @@
SpaceConfEvent.fire(eventBus, Space.userSpace, tokenFromWaveref);
History.newItem(tokenFromWaveref, false);
}
- /**
- * An exception handler that reports exceptions using a <em>shiny banner</em>
- * (an alert placed on the top of the screen). Once the stack trace is
- * prepared, it is revealed in the banner via a link.
- */
- public static class ErrorHandler implements UncaughtExceptionHandler {
- public static void getStackTraceAsync(final Throwable t, final Accessor<SafeHtml> whenReady) {
- // TODO: Request stack-trace de-obfuscation. For now, just use the
- // javascript stack trace.
- //
- // Use minimal services here, in order to avoid the chance that reporting
- // the error produces more errors. In particular, do not use WIAB's
- // scheduler to run this command.
- // Also, this code could potentially be put behind a runAsync boundary, to
- // save whatever dependencies it uses from the initial download.
- new Timer() {
- @Override
- public void run() {
- SafeHtmlBuilder stack = new SafeHtmlBuilder();
+
+ @Override
+ public void setMaximized(final boolean maximized) {
+ splitPanel.setWidgetSize(searchPanel, maximized ? 0 : 400);
+ }
- Throwable error = t;
- while (error != null) {
- String token = String.valueOf((new Date()).getTime());
- stack.appendHtmlConstant("Token: " + token + "<br> ");
- stack.appendEscaped(String.valueOf(error.getMessage())).appendHtmlConstant("<br>");
- for (StackTraceElement elt : error.getStackTrace()) {
- stack.appendHtmlConstant(" ")
- .appendEscaped(maybe(elt.getClassName(), "??")).appendHtmlConstant(".") //
- .appendEscaped(maybe(elt.getMethodName(), "??")).appendHtmlConstant(" (") //
- .appendEscaped(maybe(elt.getFileName(), "??")).appendHtmlConstant(":") //
- .appendEscaped(maybe(elt.getLineNumber(), "??")).appendHtmlConstant(")") //
- .appendHtmlConstant("<br>");
- }
- error = error.getCause();
- if (error != null) {
- stack.appendHtmlConstant("Caused by: ");
- }
+ private void setupConnectionIndicator() {
+ ClientEvents.get().addNetworkStatusEventHandler(new NetworkStatusEventHandler() {
+
+ boolean isTurbulenceDetected = false;
+
+ @Override
+ public void onNetworkStatus(final NetworkStatusEvent event) {
+ final Element element = Document.get().getElementById("netstatus");
+ if (element != null) {
+ switch (event.getStatus()) {
+ case CONNECTED:
+ case RECONNECTED:
+ element.setInnerText("Online");
+ element.setClassName("online");
+ isTurbulenceDetected = false;
+ turbulencePopup.hide();
+ break;
+ case DISCONNECTED:
+ element.setInnerText("Offline");
+ element.setClassName("offline");
+ if (!isTurbulenceDetected) {
+ isTurbulenceDetected = true;
+ turbulencePopup.show();
+ }
+ break;
+ case RECONNECTING:
+ element.setInnerText("Connecting...");
+ element.setClassName("connecting");
+ break;
}
-
- whenReady.use(stack.toSafeHtml());
}
- }.schedule(1);
- }
+ }
+ });
+ }
+
+ private void setupSearchPanel() {
+ // On wave action fire an event.
+ final SearchPresenter.WaveActionHandler actionHandler =
+ new SearchPresenter.WaveActionHandler() {
+ @Override
+ public void onCreateWave() {
+ ClientEvents.get().fireEvent(WaveCreationEvent.CREATE_NEW_WAVE);
+ }
- public static void install() {
- GWT.setUncaughtExceptionHandler(new ErrorHandler(GWT.getUncaughtExceptionHandler()));
+ @Override
+ public void onWaveSelected(final WaveId id) {
+ ClientEvents.get().fireEvent(new WaveSelectionEvent(WaveRef.of(id)));
+ }
+ };
+ final Search search = SimpleSearch.create(RemoteSearchService.create(), waveStore);
+ search.addListener(inboxCount.getSearchListener());
+ SearchPresenter.create(search, searchPanel, actionHandler, profiles);
+ }
+
+ private void setupUi() {
+ // Set up UI
+ final DockLayoutPanel self = BINDER.createAndBindUi(this);
+ // kune-patch
+ // RootPanel.get("app").add(self);
+ initWidget(self);
+ waveHolder = new ImplPanel("");
+ waveHolder.addStyleName("k-waveHolder");
+ waveFrame.add(waveHolder);
+ // DockLayoutPanel forcibly conflicts with sensible layout control, and
+ // sticks inline styles on elements without permission. They must be
+ // cleared.
+ self.getElement().getStyle().clearPosition();
+ splitPanel.setWidgetMinSize(searchPanel, 300);
+
+ if (LogLevel.showDebug()) {
+ logPanel.enable();
+ } else {
+ logPanel.removeFromParent();
}
+
+ setupSearchPanel();
+ setupWavePanel();
+ }
- private static String maybe(final int value, final String otherwise) {
- return value != -1 ? String.valueOf(value) : otherwise;
- }
+ private void setupWavePanel() {
+ // Hide the frame until waves start getting opened.
+ UIObject.setVisible(waveFrame.getElement(), false);
- private static String maybe(final String value, final String otherwise) {
- return value != null ? value : otherwise;
- }
-
- /**
- * Indicates whether an error has already been reported (at most one error
- * is ever reported by this handler).
- */
- private boolean hasFired;
-
- /** Next handler in the handler chain. */
- private final UncaughtExceptionHandler next;
-
- private ErrorHandler(final UncaughtExceptionHandler next) {
- this.next = next;
- }
-
- @Override
- public void onUncaughtException(final Throwable e) {
- if (!hasFired) {
- hasFired = true;
- // final ErrorIndicatorPresenter error =
- // ErrorIndicatorPresenter.create(RootPanel.get("banner"));
- getStackTraceAsync(e, new Accessor<SafeHtml>() {
- @Override
- public void use(final SafeHtml stack) {
- // error.addDetail(stack, null);
- // REMOTE_LOG.severe(stack.asString().replace("<br>", "\n"));
- final String message = stack.asString().replace("<br>", "\n");
- REMOTE_LOG.severe(message);
- NotifyUser.logError(message);
- NotifyUser.showProgress("Error");
- new Timer() {
- @Override
- public void run() {
- NotifyUser.hideProgress();
- }}.schedule(5000);
- }
- });
+ // Handles opening waves.
+ ClientEvents.get().addWaveSelectionEventHandler(new WaveSelectionEventHandler() {
+ @Override
+ public void onSelection(final WaveRef waveRef) {
+ openWave(waveRef, false);
}
-
- if (next != null) {
- next.onUncaughtException(e);
- }
- }
+ });
}
+ private native boolean useSocketIO() /*-{
+ return !window.WebSocket
+ }-*/;
}
More information about the kune-commits
mailing list