Support compound key combinations in GlobalKey
Compound keys can now be formed by embedding a KeyCommandSet inside
of a CompoundKeyCommand. The set is only enabled for a short time
(250 ms) after the activation key on the CompoundKeyCommand is hit
by the user. If the timeout expires, the set is disabled. If a
key is selected, the set is disabled.
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/CompoundKeyCommand.java b/src/main/java/com/google/gwtexpui/globalkey/client/CompoundKeyCommand.java
new file mode 100644
index 0000000..304d56e
--- /dev/null
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/CompoundKeyCommand.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// 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 com.google.gwtexpui.globalkey.client;
+
+import com.google.gwt.event.dom.client.KeyPressEvent;
+
+public final class CompoundKeyCommand extends KeyCommand {
+ final KeyCommandSet set;
+
+ public CompoundKeyCommand(int mask, char key, String help, KeyCommandSet s) {
+ super(mask, key, help);
+ set = s;
+ }
+
+ public CompoundKeyCommand(int mask, int key, String help, KeyCommandSet s) {
+ super(mask, key, help);
+ set = s;
+ }
+
+ public KeyCommandSet getSet() {
+ return set;
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ GlobalKey.temporaryWithTimeout(set);
+ }
+}
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/GlobalKey.java b/src/main/java/com/google/gwtexpui/globalkey/client/GlobalKey.java
index 014a673..b99e63f 100644
--- a/src/main/java/com/google/gwtexpui/globalkey/client/GlobalKey.java
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/GlobalKey.java
@@ -20,6 +20,7 @@
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -35,16 +36,29 @@
private static State global;
static State active;
private static CloseHandler<PopupPanel> restoreGlobal;
+ private static Timer restoreTimer;
private static void initEvents() {
if (active == null) {
DocWidget.get().addKeyPressHandler(new KeyPressHandler() {
@Override
public void onKeyPress(final KeyPressEvent event) {
- active.all.onKeyPress(event);
+ final KeyCommandSet s = active.live;
+ if (s != active.all) {
+ active.live = active.all;
+ restoreTimer.cancel();
+ }
+ s.onKeyPress(event);
}
});
+ restoreTimer = new Timer() {
+ @Override
+ public void run() {
+ active.live = active.all;
+ }
+ };
+
global = new State(null);
active = global;
}
@@ -61,6 +75,11 @@
}
}
+ static void temporaryWithTimeout(final KeyCommandSet s) {
+ active.live = s;
+ restoreTimer.schedule(250);
+ }
+
public static void dialog(final PopupPanel panel) {
initEvents();
initDialog();
@@ -127,6 +146,7 @@
final Widget root;
final KeyCommandSet app;
final KeyCommandSet all;
+ KeyCommandSet live;
State(final Widget r) {
root = r;
@@ -136,6 +156,8 @@
all = new KeyCommandSet();
all.add(app);
+
+ live = all;
}
void add(final KeyCommand k) {
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java b/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
index a788639..d190050 100644
--- a/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
@@ -91,8 +91,11 @@
}
}
for (final Iterator<KeyCommand> i = map.values().iterator(); i.hasNext();) {
- if (!filter.include(i.next())) {
+ final KeyCommand kc = i.next();
+ if (!filter.include(kc)) {
i.remove();
+ } else if (kc instanceof CompoundKeyCommand) {
+ ((CompoundKeyCommand) kc).set.filter(filter);
}
}
}
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java b/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
index 3b02f33..802e349 100644
--- a/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
@@ -24,6 +24,7 @@
String keyboardShortcuts();
String closeButton();
String orOtherKey();
+ String thenOtherKey();
String keyCtrl();
String keyAlt();
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties b/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
index 7714ac8..e21daf5 100644
--- a/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
@@ -5,6 +5,7 @@
keyboardShortcuts = Keyboard Shortcuts
closeButton = Close
orOtherKey = or
+thenOtherKey = then
keyCtrl = Ctrl
keyAlt = Alt
diff --git a/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java b/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
index f68c5e7..6e2c276 100644
--- a/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
+++ b/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
@@ -101,7 +101,7 @@
while (setitr.hasNext()) {
final KeyCommandSet set = setitr.next();
int row = end[column];
- row = populate(lists, row, column, set);
+ row = formatGroup(lists, row, column, set);
end[column] = row;
if (column == 0) {
column = 4;
@@ -111,8 +111,82 @@
}
}
- private int populate(final Grid lists, int row, final int col,
+ private int formatGroup(final Grid lists, int row, final int col,
final KeyCommandSet set) {
+ if (set.isEmpty()) {
+ return row;
+ }
+
+ if (lists.getRowCount() < row + 1) {
+ lists.resizeRows(row + 1);
+ }
+ lists.setText(row, col + 2, set.getName());
+ lists.getCellFormatter().addStyleName(row, col + 2, S + "-GroupTitle");
+ row++;
+
+ return formatKeys(lists, row, col, set, null);
+ }
+
+ private int formatKeys(final Grid lists, int row, final int col,
+ final KeyCommandSet set, final SafeHtml prefix) {
+ final CellFormatter fmt = lists.getCellFormatter();
+ final int initialRow = row;
+ final List<KeyCommand> keys = sort(set);
+ if (lists.getRowCount() < row + keys.size()) {
+ lists.resizeRows(row + keys.size());
+ }
+ FORMAT_KEYS: for (int i = 0; i < keys.size(); i++) {
+ final KeyCommand k = keys.get(i);
+
+ if (k instanceof CompoundKeyCommand) {
+ final SafeHtmlBuilder b = new SafeHtmlBuilder();
+ b.append(k.describeKeyStroke());
+ row = formatKeys(lists, row, col, ((CompoundKeyCommand) k).getSet(), b);
+ continue;
+ }
+
+ for (int prior = 0, r = initialRow; prior < i; prior++) {
+ if (KeyCommand.same(keys.get(prior), k)) {
+ final SafeHtmlBuilder b = new SafeHtmlBuilder();
+ b.append(SafeHtml.get(lists, r, col + 0));
+ b.append(" ");
+ b.append(Util.C.orOtherKey());
+ b.append(" ");
+ if (prefix != null) {
+ b.append(prefix);
+ b.append(" ");
+ b.append(Util.C.thenOtherKey());
+ b.append(" ");
+ }
+ b.append(k.describeKeyStroke());
+ SafeHtml.set(lists, r, col + 0, b);
+ continue FORMAT_KEYS;
+ }
+ }
+
+ if (prefix != null) {
+ final SafeHtmlBuilder b = new SafeHtmlBuilder();
+ b.append(prefix);
+ b.append(" ");
+ b.append(Util.C.thenOtherKey());
+ b.append(" ");
+ b.append(k.describeKeyStroke());
+ SafeHtml.set(lists, row, col + 0, b);
+ } else {
+ SafeHtml.set(lists, row, col + 0, k.describeKeyStroke());
+ }
+ lists.setText(row, col + 1, ":");
+ lists.setText(row, col + 2, k.getHelpText());
+
+ fmt.addStyleName(row, col + 0, S + "-TableKeyStroke");
+ fmt.addStyleName(row, col + 1, S + "-TableSeparator");
+ row++;
+ }
+
+ return row;
+ }
+
+ private List<KeyCommand> sort(final KeyCommandSet set) {
final List<KeyCommand> keys = new ArrayList<KeyCommand>(set.getKeys());
Collections.sort(keys, new Comparator<KeyCommand>() {
@Override
@@ -125,45 +199,6 @@
return 0;
}
});
- if (keys.isEmpty()) {
- return row;
- }
-
- if (lists.getRowCount() < row + 1 + keys.size()) {
- lists.resizeRows(row + 1 + keys.size());
- }
-
- final CellFormatter fmt = lists.getCellFormatter();
- lists.setText(row, col + 2, set.getName());
- fmt.addStyleName(row, col + 2, S + "-GroupTitle");
- row++;
-
- final int initialRow = row;
- FORMAT_KEYS: for (int i = 0; i < keys.size(); i++) {
- final KeyCommand k = keys.get(i);
-
- for (int prior = 0, r = initialRow; prior < i; prior++) {
- if (KeyCommand.same(keys.get(prior), k)) {
- final SafeHtmlBuilder b = new SafeHtmlBuilder();
- b.append(SafeHtml.get(lists, r, col + 0));
- b.append(" ");
- b.append(Util.C.orOtherKey());
- b.append(" ");
- b.append(k.describeKeyStroke());
- SafeHtml.set(lists, r, col + 0, b);
- continue FORMAT_KEYS;
- }
- }
-
- SafeHtml.set(lists, row, col + 0, k.describeKeyStroke());
- lists.setText(row, col + 1, ":");
- lists.setText(row, col + 2, k.getHelpText());
-
- fmt.addStyleName(row, col + 0, S + "-TableKeyStroke");
- fmt.addStyleName(row, col + 1, S + "-TableSeparator");
- row++;
- }
-
- return row;
+ return keys;
}
}