Repository: incubator-wave Updated Branches: refs/heads/master 47cd2e99f -> d88962765
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/box/webclient/stat/gwtevent/GwtStatisticsHandler.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/webclient/stat/gwtevent/GwtStatisticsHandler.java b/src/org/waveprotocol/box/webclient/stat/gwtevent/GwtStatisticsHandler.java new file mode 100644 index 0000000..f3096c1 --- /dev/null +++ b/src/org/waveprotocol/box/webclient/stat/gwtevent/GwtStatisticsHandler.java @@ -0,0 +1,94 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.box.webclient.stat.gwtevent; + +import org.waveprotocol.box.stat.Timer; +import org.waveprotocol.box.stat.Timing; + +import java.util.Iterator; + +/** + * Transformer of GWT statistic. + * + * @author [email protected] (A. Kaplanov) + */ +public class GwtStatisticsHandler implements StatisticsEventListener { + static private String GWT_PREFIX = "GWT."; + + static private String PARAM_TYPE = "type"; + static private String TYPE_BEGIN = "begin"; + static private String TYPE_END = "end"; + + private Timer requestTimer; + private String currentGroup; + private long previousCallTimestamp; + + @Override + public void onStatisticsEvent(StatisticsEvent event) { + String group = event.getEventGroupKey(); + String type = (String)event.getExtraParameter(PARAM_TYPE); + if (TYPE_BEGIN.equals(type)) { + enterGroup(group, (long)event.getMillis()); + } else { + if (TYPE_END.equals(type)) { + leaveGroup((long)event.getMillis()); + } else { + if (!group.equals(currentGroup)) { + leaveGroup((long)event.getMillis()); + enterGroup(group, (long)event.getMillis()); + } + Timing.record(GWT_PREFIX + type, (int)((long)event.getMillis()-previousCallTimestamp)); + } + } + previousCallTimestamp = (long)event.getMillis(); + } + + private void enterGroup(String group, long time) { + if (Timing.isEnabled()) { + Timing.enterScope(); + requestTimer = Timing.startRequest(GWT_PREFIX + group); + requestTimer.start(time); + currentGroup = group; + } + } + + private void leaveGroup(long time) { + if (Timing.isEnabled() && currentGroup != null) { + Timing.stop(requestTimer, time); + requestTimer = null; + currentGroup = null; + Timing.exitScope(); + } + } + + private static String getExtraParameters(StatisticsEvent event) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + Iterator<String> names = event.getExtraParameterNames(); + if (names.hasNext()) { + String n = names.next(); + sb.append(n).append(" = ").append(event.getExtraParameter(n)); + while (names.hasNext()) { + sb.append(", ").append(n = names.next()).append(" = ").append(event.getExtraParameter(n)); + } + } + sb.append("}"); + return sb.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEvent.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEvent.java b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEvent.java new file mode 100644 index 0000000..d833e67 --- /dev/null +++ b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEvent.java @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.box.webclient.stat.gwtevent; + +import java.util.Iterator; + +/** + * Java "Overlay" object of the JavaScript event objects fired by the stats + * system. + */ +public interface StatisticsEvent { + + /** + * Answers with the name of the module that caused this event. + */ + public String getModuleName(); + + /** + * Answers with the name of the sub system (rpc, boot strap, etc..) that + * caused this event. + */ + public String getSubSystem(); + + /** + * Answers with a key unique to the group of events that this event belongs + * to. Along with the module and sub system this forms a unique key for + * timing related events. Note that each group requires at least two events: + * one to signal the start of the measured period and one to signal the end. + */ + public String getEventGroupKey(); + + /** + * Answers with the time stamp (millis since the epoch) at which this event + * occurred. Using double, since long is not natively supported in + * JavaScript (see {@link com.google.gwt.core.client.Duration}). + */ + public double getMillis(); + + /** + * Answers with a read-only iterator over the names of any extra parameters + * associated with this event. + */ + public Iterator<String> getExtraParameterNames(); + + /** + * Answers with the given named extra parameter. Since most events are fired + * from within JavaScript or another module, the returned value is either a + * String, Double, Boolean or a JavaScriptObject. + */ + public Object getExtraParameter(String name); +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventDispatcher.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventDispatcher.java b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventDispatcher.java new file mode 100644 index 0000000..8809059 --- /dev/null +++ b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventDispatcher.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.box.webclient.stat.gwtevent; + +import com.google.gwt.core.client.JavaScriptObject; + +/** + * Helps with creating and dispatching the events for the debug panel. + */ +public interface StatisticsEventDispatcher { + + /** + * Returns {@code true} if there is somebody listening to events on the other + * side. + */ + public boolean enabled(); + + /** + * Creates a new event object to be dispatched. + + * @see StatisticsEvent + */ + public StatisticsEvent newEvent(String system, String group, double millis, String type); + + /** + * Sets the given extra parameter's value as a JavaScriptObject. + * + * @param event the event to set the parameter on. This has to be an instance + * returned by @{link {@link #newEvent(String, String, double, String)}. + */ + public void setExtraParameter(StatisticsEvent event, String name, JavaScriptObject value); + + /** + * Sets the given extra parameter's value as a String. + * + * @param event the event to set the parameter on. This has to be an instance + * returned by @{link {@link #newEvent(String, String, double, String)}. + */ + public void setExtraParameter(StatisticsEvent event, String name, String value); + + /** + * Dispatches the given event. + * + * @param event the event to dispatch. This has to be an instance + * returned by @{link {@link #newEvent(String, String, double, String)}. + */ + public void dispatch(StatisticsEvent event); +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventListener.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventListener.java b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventListener.java new file mode 100644 index 0000000..42b9497 --- /dev/null +++ b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventListener.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.box.webclient.stat.gwtevent; + + +/** + * Receiver of {@link StatisticsEvent} events. + */ +public interface StatisticsEventListener { + public void onStatisticsEvent(StatisticsEvent event); +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventSystem.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventSystem.java b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventSystem.java new file mode 100644 index 0000000..e4bd203 --- /dev/null +++ b/src/org/waveprotocol/box/webclient/stat/gwtevent/StatisticsEventSystem.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.box.webclient.stat.gwtevent; + +import java.util.Iterator; + +/** + * The statistics event system is responsible for managing the statistics + * {@link StatisticsEventListener event listeners} and dispatching the + * {@link StatisticsEvent events}. + */ +public interface StatisticsEventSystem { + + /** + * Register a listener to receive future {@link StatisticsEvent events}. + * + * @param replay if true, past (recorded) events will be replayed on the + * given listener. + */ + public void addListener(StatisticsEventListener listener, boolean replay); + + /** + * Removes a listener so it will no longer receive any + * {@link StatisticsEvent events}. + */ + public void removeListener(StatisticsEventListener listener); + + /** + * Provides read-only access to all the recorded events. + */ + public Iterator<StatisticsEvent> pastEvents(); + + /** + * Clears the event history. + */ + public void clearEventHistory(); +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/Stages.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/Stages.java b/src/org/waveprotocol/wave/client/Stages.java index 52ade26..f0cab51 100644 --- a/src/org/waveprotocol/wave/client/Stages.java +++ b/src/org/waveprotocol/wave/client/Stages.java @@ -20,12 +20,15 @@ package org.waveprotocol.wave.client; -import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwt.user.client.Command; +import org.waveprotocol.box.stat.Timer; +import org.waveprotocol.box.stat.Timing; import org.waveprotocol.wave.client.common.util.AsyncHolder; import org.waveprotocol.wave.client.common.util.AsyncHolder.Accessor; +import org.waveprotocol.wave.client.scheduler.Scheduler; +import org.waveprotocol.wave.client.scheduler.SchedulerInstance; /** * Loads Undercurrent's stages in order. @@ -71,18 +74,22 @@ public abstract class Stages { } private void loadStageZero() { + final Timer timer = Timing.start("Stage Zero"); createStageZeroLoader().call(new Accessor<StageZero>() { @Override public void use(StageZero x) { + Timing.stop(timer); loadStageOne(x); } }); } private void loadStageOne(final StageZero zero) { + final Timer timer = Timing.start("Stage One"); createStageOneLoader(zero).call(new Accessor<StageOne>() { @Override public void use(StageOne x) { + Timing.stop(timer); loadStageTwo(x); } }); @@ -90,12 +97,15 @@ public abstract class Stages { private void loadStageTwo(final StageOne one) { - GWT.runAsync(new SimpleAsyncCallback() { + final Timer timer = Timing.start("Stage Two"); + SchedulerInstance.getHighPriorityTimer().schedule(new Scheduler.Task() { + @Override - public void onSuccess() { + public void execute() { createStageTwoLoader(one).call(new Accessor<StageTwo>() { @Override public void use(StageTwo x) { + Timing.stop(timer); loadStageThree(x); } }); @@ -104,12 +114,15 @@ public abstract class Stages { } private void loadStageThree(final StageTwo two) { - GWT.runAsync(new SimpleAsyncCallback() { + final Timer timer = Timing.start("Stage Tree"); + SchedulerInstance.getHighPriorityTimer().schedule(new Scheduler.Task() { + @Override - public void onSuccess() { + public void execute() { createStageThreeLoader(two).call(new Accessor<StageThree>() { @Override public void use(StageThree x) { + Timing.stop(timer); finish(); } }); http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/scheduler/BrowserBackedScheduler.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/scheduler/BrowserBackedScheduler.java b/src/org/waveprotocol/wave/client/scheduler/BrowserBackedScheduler.java index 6cc57e6..2b54546 100644 --- a/src/org/waveprotocol/wave/client/scheduler/BrowserBackedScheduler.java +++ b/src/org/waveprotocol/wave/client/scheduler/BrowserBackedScheduler.java @@ -22,6 +22,8 @@ package org.waveprotocol.wave.client.scheduler; import com.google.gwt.user.client.ui.Widget; +import org.waveprotocol.box.stat.Timer; +import org.waveprotocol.box.stat.Timing; import org.waveprotocol.wave.model.util.CollectionUtils; import org.waveprotocol.wave.model.util.CopyOnWriteSet; @@ -272,30 +274,43 @@ public class BrowserBackedScheduler implements Scheduler { double start = timer.getTime(); - if (job instanceof IncrementalTask) { - boolean isFinished = !jobs.getRemovedJobAsProcess().execute(); - - if (isFinished) { - // Remove all trace - cancel(job); - } else { - TaskInfo task = taskInfos.get(job); - // If the job has more work to do, we add it back into the job queue, unless it has has - // already been cancelled during execution (which would imply !hasJob) - if (task != null && hasJob(job)) { - // if it is a repeating job, add it to a delay before we contiune - if (task.calculateNextExecuteTime(start)) { - delayedJobs.addDelayedJob(task); - } else if (!delayedJobs.has(task.id)) { - jobs.add(priority, job); + TaskInfo taskInfo = taskInfos.get(job); + Timer profilingTimer = null; + if (taskInfo != null && Timing.isEnabled()) { + Timing.enterScope(taskInfo.scopeValues); + profilingTimer = Timing.start("schedule " + job.getClass().getSimpleName()); + } + try { + if (job instanceof IncrementalTask) { + boolean isFinished = !jobs.getRemovedJobAsProcess().execute(); + + if (isFinished) { + // Remove all trace + cancel(job); + } else { + TaskInfo task = taskInfos.get(job); + // If the job has more work to do, we add it back into the job queue, unless it has has + // already been cancelled during execution (which would imply !hasJob) + if (task != null && hasJob(job)) { + // if it is a repeating job, add it to a delay before we contiune + if (task.calculateNextExecuteTime(start)) { + delayedJobs.addDelayedJob(task); + } else if (!delayedJobs.has(task.id)) { + jobs.add(priority, job); + } } } + } else { + Task task = jobs.getRemovedJobAsTask(); + // Remove all trace. + cancel(job); + task.execute(); + } + } finally { + if (profilingTimer != null) { + Timing.stop(profilingTimer); + Timing.exitScope(); } - } else { - Task task = jobs.getRemovedJobAsTask(); - // Remove all trace. - cancel(job); - task.execute(); } int timeSpent = (int) ( timer.getTime() - start); http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/scheduler/TaskInfo.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/scheduler/TaskInfo.java b/src/org/waveprotocol/wave/client/scheduler/TaskInfo.java index 23c3f97..420807e 100644 --- a/src/org/waveprotocol/wave/client/scheduler/TaskInfo.java +++ b/src/org/waveprotocol/wave/client/scheduler/TaskInfo.java @@ -20,15 +20,20 @@ package org.waveprotocol.wave.client.scheduler; +import org.waveprotocol.box.stat.RequestScope; +import org.waveprotocol.box.stat.Timing; import org.waveprotocol.wave.client.scheduler.Scheduler.Priority; import org.waveprotocol.wave.client.scheduler.Scheduler.Schedulable; +import java.util.Map; + /** * Some information about a scheduled task. * Gives each a unique id, and also stores the priority. * * @author [email protected] (Daniel Danilatos) */ +@SuppressWarnings("rawtypes") final class TaskInfo { private static int nextId; final String id = Integer.toString(++nextId); @@ -36,6 +41,7 @@ final class TaskInfo { final double startTime; final double interval; final Schedulable job; + final Map<Class, RequestScope.Value> scopeValues; private double nextExecuteTime; public TaskInfo(Priority p, Schedulable job) { @@ -48,6 +54,7 @@ final class TaskInfo { this.interval = interval; this.nextExecuteTime = startTime; this.job = job; + this.scopeValues = Timing.getScope().cloneValues(); } @Override http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/wavepanel/event/EventDispatcherPanel.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/wavepanel/event/EventDispatcherPanel.java b/src/org/waveprotocol/wave/client/wavepanel/event/EventDispatcherPanel.java index cb0822a..24313e8 100644 --- a/src/org/waveprotocol/wave/client/wavepanel/event/EventDispatcherPanel.java +++ b/src/org/waveprotocol/wave/client/wavepanel/event/EventDispatcherPanel.java @@ -37,6 +37,8 @@ import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; +import org.waveprotocol.box.stat.Timer; +import org.waveprotocol.box.stat.Timing; import org.waveprotocol.wave.client.common.util.LogicalPanel; import org.waveprotocol.wave.model.util.CollectionUtils; @@ -302,7 +304,19 @@ public final class EventDispatcherPanel extends ComplexPanel @Override boolean dispatch(ChangeEvent event, Element context, WaveChangeHandler handler) { - return handler.onChange(event, context); + Timer timer = null; + if (Timing.isEnabled()) { + Timing.enterScope(); + timer = Timing.start("Mouse event dispatch"); + } + try { + return handler.onChange(event, context); + } finally { + if (timer != null) { + Timing.stop(timer); + Timing.exitScope(); + } + } } @Override http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/wavepanel/event/FocusManager.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/wavepanel/event/FocusManager.java b/src/org/waveprotocol/wave/client/wavepanel/event/FocusManager.java index 461a3ce..6704ae1 100644 --- a/src/org/waveprotocol/wave/client/wavepanel/event/FocusManager.java +++ b/src/org/waveprotocol/wave/client/wavepanel/event/FocusManager.java @@ -24,6 +24,7 @@ import com.google.common.base.Preconditions; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.KeyEvent; @@ -34,6 +35,10 @@ import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.RootPanel; +import org.waveprotocol.box.stat.ExecutionTree; +import org.waveprotocol.box.stat.Timer; +import org.waveprotocol.box.stat.Timing; +import org.waveprotocol.box.webclient.stat.dialog.StatDialog; import org.waveprotocol.wave.client.common.util.EventWrapper; import org.waveprotocol.wave.client.common.util.KeyCombo; @@ -82,7 +87,7 @@ public final class FocusManager implements Focusable, KeySignalHandler { /** Unique top-level focus manager. */ private final static FocusManager ROOT = new FocusManager(null, true); - static { + public static void init() { DocumentPanel.install(ROOT); } @@ -228,6 +233,8 @@ public final class FocusManager implements Focusable, KeySignalHandler { private final KeySignalHandler globalHandler; + private int statDialogCondition = 0; + private DocumentPanel(KeySignalHandler handler) { this.globalHandler = handler; } @@ -256,7 +263,11 @@ public final class FocusManager implements Focusable, KeySignalHandler { @Override public void onKeyDown(KeyDownEvent event) { - dispatch(event); + if (checkStatDialogCondition(event)) { + StatDialog.show(); + } else { + dispatch(event); + } } @Override @@ -270,22 +281,54 @@ public final class FocusManager implements Focusable, KeySignalHandler { } private void dispatch(KeyEvent<?> event) { - // Only respond to key events on the body element. Otherwise, the key - // event was probably targeted to some editable input element, and that - // should own the events. - NativeEvent realEvent = event.getNativeEvent(); - Element target = realEvent.getEventTarget().cast(); - if (!"body".equals(target.getTagName().toLowerCase())) { - return; + Timer timer = null; + if (Timing.isEnabled()) { + Timing.enterScope(); + Timing.getScope().set(ExecutionTree.class, new ExecutionTree()); + timer = Timing.start("Key event dispatch"); } - // Test that the event is meaningful (and stop bubbling if it is not). - SignalEvent signal = SignalEventImpl.create(realEvent.<Event>cast(), true); - if (signal != null) { - KeyCombo key = EventWrapper.getKeyCombo(signal); - if (globalHandler.onKeySignal(key)) { - event.preventDefault(); + try { + // Only respond to key events on the body element. Otherwise, the key + // event was probably targeted to some editable input element, and that + // should own the events. + NativeEvent realEvent = event.getNativeEvent(); + Element target = realEvent.getEventTarget().cast(); + if (!"body".equals(target.getTagName().toLowerCase())) { + return; + } + // Test that the event is meaningful (and stop bubbling if it is not). + SignalEvent signal = SignalEventImpl.create(realEvent.<Event>cast(), true); + if (signal != null) { + KeyCombo key = EventWrapper.getKeyCombo(signal); + if (globalHandler.onKeySignal(key)) { + event.preventDefault(); + } } + } finally { + Timing.stop(timer); + Timing.exitScope(); + } + } + + private boolean checkStatDialogCondition(KeyDownEvent event) { + int code = event.getNativeEvent().getKeyCode(); + switch (statDialogCondition) { + case 0: + if (code == KeyCodes.KEY_CTRL) { + statDialogCondition = 1; + } + break; + case 1: + statDialogCondition = (code == KeyCodes.KEY_ALT)?2:0; + break; + case 2: + statDialogCondition = 0; + if (code == KeyCodes.KEY_CTRL) { + return true; + } + break; } + return false; } } } http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/wavepanel/view/dom/full/WavePanelResourceLoader.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/wavepanel/view/dom/full/WavePanelResourceLoader.java b/src/org/waveprotocol/wave/client/wavepanel/view/dom/full/WavePanelResourceLoader.java index 2f16cb2..46fa5ac 100644 --- a/src/org/waveprotocol/wave/client/wavepanel/view/dom/full/WavePanelResourceLoader.java +++ b/src/org/waveprotocol/wave/client/wavepanel/view/dom/full/WavePanelResourceLoader.java @@ -26,6 +26,7 @@ import org.waveprotocol.wave.client.editor.EditorImpl; import org.waveprotocol.wave.client.wavepanel.view.dom.CssProvider; import org.waveprotocol.wave.client.wavepanel.view.dom.full.i18n.BlipMessages; import org.waveprotocol.wave.client.wavepanel.view.dom.full.i18n.ReplyBoxMessages; +import org.waveprotocol.wave.client.widget.dialog.Dialog; /** * This class is responsible for loading all the Css resources needed by the @@ -48,6 +49,8 @@ public final class WavePanelResourceLoader { GWT.create(TopConversationViewBuilder.Resources.class); private final static ParticipantsViewBuilder.Resources participants = GWT.create(ParticipantsViewBuilder.Resources.class); + private final static Dialog.Resources dialog = + GWT.create(Dialog.Resources.class); private final static BlipMessages blipMessages = GWT.create(BlipMessages.class); @@ -70,6 +73,7 @@ public final class WavePanelResourceLoader { StyleInjector.inject(inlineContinuation.css().getText(), isSynchronous); StyleInjector.inject(conversation.css().getText(), isSynchronous); StyleInjector.inject(participants.css().getText(), isSynchronous); + StyleInjector.inject(dialog.css().getText(), isSynchronous); } private WavePanelResourceLoader() { @@ -103,6 +107,10 @@ public final class WavePanelResourceLoader { return participants; } + public static Dialog.Resources getDialog() { + return dialog; + } + public static BlipMessages getBlipMessages() { return blipMessages; } http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/widget/dialog/Dialog.css ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/widget/dialog/Dialog.css b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.css new file mode 100644 index 0000000..874ad37 --- /dev/null +++ b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.css @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +.errorLabel { + color: red; + font-weight: bold; + padding: 5px; + text-align: center; +} + +.warningLabel { + color: red; + font-weight: bold; + padding: 5px; + text-align: center; +} + +.infoLabel { + font-weight: bold; + padding: 5px; + text-align: center; +} + +.dialogButtonPanel { + padding: 5px; +} + +.dialogButton { + min-width: 80px; + margin: 5px; +} + +.glassPanel { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0; +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/widget/dialog/Dialog.gwt.xml ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/widget/dialog/Dialog.gwt.xml b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.gwt.xml new file mode 100644 index 0000000..8dbf371 --- /dev/null +++ b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.gwt.xml @@ -0,0 +1,6 @@ +<module> + <inherits name="com.google.gwt.user.User" /> + <inherits name="org.waveprotocol.wave.client.widget.popup.Popup" /> + <inherits name="org.waveprotocol.wave.client.widget.common.Common" /> + <source path=""/> +</module> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/widget/dialog/Dialog.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/widget/dialog/Dialog.java b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.java new file mode 100644 index 0000000..b73d359 --- /dev/null +++ b/src/org/waveprotocol/wave/client/widget/dialog/Dialog.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.wave.client.widget.dialog; + +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import org.waveprotocol.wave.client.wavepanel.view.dom.full.WavePanelResourceLoader; + +/** + * Resources and common functions library for dialog widgets. + * + * @author Denis Konovalchik ([email protected]) + */ +public class Dialog { + /** Resources used by this widget. */ + public interface Resources extends ClientBundle { + @ClientBundle.Source("Dialog.css") + Css css(); + } + + /** CSS for this widget. */ + public interface Css extends CssResource { + String errorLabel(); + String warningLabel(); + String infoLabel(); + String dialogButtonPanel(); + String dialogButton(); + String glassPanel(); + } + + private static Css css; + + public static Css getCss() { + if (css == null) { + css = WavePanelResourceLoader.getDialog().css(); + } + return css; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/src/org/waveprotocol/wave/client/widget/dialog/DialogBox.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/wave/client/widget/dialog/DialogBox.java b/src/org/waveprotocol/wave/client/widget/dialog/DialogBox.java new file mode 100644 index 0000000..4a8a61c --- /dev/null +++ b/src/org/waveprotocol/wave/client/widget/dialog/DialogBox.java @@ -0,0 +1,119 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.waveprotocol.wave.client.widget.dialog; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; + +import org.waveprotocol.wave.client.widget.popup.UniversalPopup; + +/** + * Standard dialog box with title, message and set of buttons. + * + * @author Denis Konovalchik ([email protected]) + * @author [email protected] (A. Kaplanov) + */ +public class DialogBox { + + public static class DialogButton { + private String title; + private Command onClick; + private Button button; + + public DialogButton(String title) { + this.title = title; + } + + public DialogButton(String title, Command onClick) { + this.title = title; + this.onClick = onClick; + } + + public void setTitle(String title) { + this.title = title; + if (button != null) { + button.setText(title); + } + } + + public void setOnClick(Command onClick) { + this.onClick = onClick; + } + + public String getTitle() { + return title; + } + + public void execute() { + if (onClick != null) { + onClick.execute(); + } + } + + void link(Button button) { + this.button = button; + button.setText(title); + button.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + execute(); + } + }); + } + } + + /** + * Creates dialog box. + * + * @param popup - UniversalPopup on which the dialog is based + * @param title - title placed in the title bar + * @param innerWidget - the inner widget of the dialog + * @param dialogButtons - buttons + */ + static public void create(UniversalPopup popup, String title, Widget innerWidget, DialogButton[] dialogButtons) { + // Title + popup.getTitleBar().setTitleText(title); + + VerticalPanel contents = new VerticalPanel(); + popup.add(contents); + + // Message + contents.add(innerWidget); + + // Buttons + HorizontalPanel buttonPanel = new HorizontalPanel(); + for(DialogButton dialogButton : dialogButtons) { + Button button = new Button(dialogButton.getTitle()); + button.setStyleName(Dialog.getCss().dialogButton()); + buttonPanel.add(button); + dialogButton.link(button); + } + contents.add(buttonPanel); + buttonPanel.setStyleName(Dialog.getCss().dialogButtonPanel()); + contents.setCellHorizontalAlignment(buttonPanel, HasHorizontalAlignment.ALIGN_RIGHT); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/test/org/waveprotocol/box/server/rpc/RpcTest.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/box/server/rpc/RpcTest.java b/test/org/waveprotocol/box/server/rpc/RpcTest.java index 689d5c6..ca28bff 100644 --- a/test/org/waveprotocol/box/server/rpc/RpcTest.java +++ b/test/org/waveprotocol/box/server/rpc/RpcTest.java @@ -46,6 +46,7 @@ import java.net.InetSocketAddress; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.waveprotocol.box.server.CoreSettings; @@ -74,7 +75,8 @@ public class RpcTest extends TestCase { */ server = new ServerRpcProvider(new InetSocketAddress[] {new InetSocketAddress("localhost", 0)}, - new String[] {"./war"}, sessionManager, null, null, false, null, null); + new String[] {"./war"}, sessionManager, null, null, false, null, null, + Executors.newCachedThreadPool()); Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/d8896276/test/org/waveprotocol/box/server/waveserver/LucenePerUserWaveViewProviderTest.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/box/server/waveserver/LucenePerUserWaveViewProviderTest.java b/test/org/waveprotocol/box/server/waveserver/LucenePerUserWaveViewProviderTest.java index b4d02e4..078203c 100644 --- a/test/org/waveprotocol/box/server/waveserver/LucenePerUserWaveViewProviderTest.java +++ b/test/org/waveprotocol/box/server/waveserver/LucenePerUserWaveViewProviderTest.java @@ -29,6 +29,7 @@ import org.waveprotocol.box.server.persistence.lucene.RAMIndexDirectory; import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; import java.io.IOException; +import java.util.concurrent.Executors; /** * @author [email protected] (Yuri Zelikov) @@ -57,7 +58,8 @@ public class LucenePerUserWaveViewProviderTest extends PerUserWaveViewProviderTe @Override protected PerUserWaveViewHandler createPerUserWaveViewHandler() { handler = - new LucenePerUserWaveViewHandlerImpl(directory, waveletProvider, textCollator, DOMAIN); + new LucenePerUserWaveViewHandlerImpl(directory, waveletProvider, textCollator, DOMAIN, + Executors.newCachedThreadPool()); return handler; }
