blob: 66dd6df920f60e93d53bf1c634486dd1d57e2544 [file] [log] [blame]
// 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.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtexpui.user.client.PluginSafePopupPanel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
public class KeyHelpPopup extends PluginSafePopupPanel implements
KeyPressHandler {
private static final String S = "gwtexpui-globalkey-KeyboardShortcuts";
private final FocusPanel focus;
public KeyHelpPopup() {
super(true/* autohide */, true/* modal */);
setStyleName(S);
final Anchor closer = new Anchor(Util.C.closeButton());
closer.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
hide();
}
});
final Grid header = new Grid(1, 3);
header.setStyleName(S + "-Header");
header.setText(0, 0, Util.C.keyboardShortcuts());
header.setWidget(0, 2, closer);
final CellFormatter fmt = header.getCellFormatter();
fmt.addStyleName(0, 1, S + "-HeaderGlue");
fmt.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_RIGHT);
final Grid lists = new Grid(0, 7);
lists.setStyleName(S + "-Table");
populate(lists);
lists.getCellFormatter().addStyleName(0, 3, S + "-TableGlue");
final FlowPanel body = new FlowPanel();
body.add(header);
DOM.appendChild(body.getElement(), DOM.createElement("hr"));
body.add(lists);
focus = new FocusPanel(body);
DOM.setStyleAttribute(focus.getElement(), "outline", "0px");
DOM.setElementAttribute(focus.getElement(), "hideFocus", "true");
focus.addKeyPressHandler(this);
add(focus);
}
@Override
public void setVisible(final boolean show) {
super.setVisible(show);
if (show) {
focus.setFocus(true);
}
}
@Override
public void onKeyPress(final KeyPressEvent event) {
if (KeyCommandSet.toMask(event) == ShowHelpCommand.INSTANCE.keyMask) {
// Block the '?' key from triggering us to show right after
// we just hide ourselves.
//
event.stopPropagation();
event.preventDefault();
}
hide();
}
private void populate(final Grid lists) {
int end[] = new int[5];
int column = 0;
for (final KeyCommandSet set : combinedSetsByName()) {
int row = end[column];
row = formatGroup(lists, row, column, set);
end[column] = row;
if (column == 0) {
column = 4;
} else {
column = 0;
}
}
}
/**
* @return an ordered collection of KeyCommandSet, combining sets which share
* the same name, so that each set name appears at most once.
*/
private static Collection<KeyCommandSet> combinedSetsByName() {
final LinkedHashMap<String, KeyCommandSet> byName =
new LinkedHashMap<String, KeyCommandSet>();
for (final KeyCommandSet set : GlobalKey.active.all.getSets()) {
KeyCommandSet v = byName.get(set.getName());
if (v == null) {
v = new KeyCommandSet(set.getName());
byName.put(v.getName(), v);
}
v.add(set);
}
return byName.values();
}
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
public int compare(KeyCommand arg0, KeyCommand arg1) {
if (arg0.keyMask < arg1.keyMask) {
return -1;
} else if (arg0.keyMask > arg1.keyMask) {
return 1;
}
return 0;
}
});
return keys;
}
}