From 49d66e5c7e5564cb1c7676a7efedfdb396a58b67 Mon Sep 17 00:00:00 2001 From: David Mason Date: Sun, 27 May 2012 22:06:12 +1000 Subject: [PATCH] add global key shortcut handler and some shortcuts for search page. Alt+K to show shortcuts. --- .../webtrans/client/editor/CheckKey.java | 8 - .../webtrans/client/editor/CheckKeyImpl.java | 10 +- .../editor/table/TargetContentsPresenter.java | 3 +- .../client/events/KeyShortcutEvent.java | 78 +++++ .../events/KeyShortcutEventHandler.java | 34 ++ .../client/gin/WebTransClientModule.java | 3 + .../webtrans/client/keys/KeyShortcut.java | 140 ++++++++ .../webtrans/client/keys/ShortcutContext.java | 55 +++ .../client/presenter/AppPresenter.java | 42 ++- .../presenter/KeyShortcutPresenter.java | 312 ++++++++++++++++++ .../presenter/SearchResultsPresenter.java | 103 +++++- .../presenter/TranslationPresenter.java | 3 +- .../client/resources/WebTransMessages.java | 24 ++ .../client/ui/SearchResultsDocumentTable.java | 2 + .../webtrans/client/view/KeyShortcutView.java | 76 +++++ .../client/view/KeyShortcutView.ui.xml | 9 + .../client/view/SearchResultsView.java | 14 + .../zanata/webtrans/public/Application.css | 27 ++ .../client/presenter/AppPresenterTest.java | 50 ++- 19 files changed, 957 insertions(+), 36 deletions(-) create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEvent.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEventHandler.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/keys/KeyShortcut.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/keys/ShortcutContext.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/presenter/KeyShortcutPresenter.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java create mode 100644 zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.ui.xml diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKey.java b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKey.java index 4985b46ec9..2da84a76f2 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKey.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKey.java @@ -60,14 +60,6 @@ public interface CheckKey static final int KEY_4 = 52; static final int KEY_4_NUM = 37; - public static enum Context - { - /** - * Edit: InlineTargetCellEditor Navigation: TableEditorPresenter - */ - Navigation, Edit; - } - void init(NativeEvent event); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKeyImpl.java b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKeyImpl.java index c7498d0185..e236362b71 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKeyImpl.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/CheckKeyImpl.java @@ -20,6 +20,8 @@ */ package org.zanata.webtrans.client.editor; +import org.zanata.webtrans.client.keys.ShortcutContext; + import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.KeyCodes; @@ -32,11 +34,11 @@ **/ public final class CheckKeyImpl implements CheckKey { - private Context context; + private ShortcutContext context; private int keyCode; private boolean shiftKey, altKey, ctrlKey; - public CheckKeyImpl(Context context) + public CheckKeyImpl(ShortcutContext context) { this.context = context; } @@ -71,7 +73,7 @@ public boolean isNextStateEntryKey() @Override public boolean isPreviousEntryKey() { - if (context == Context.Edit) + if (context == ShortcutContext.Edit) { return altKey && (keyCode == KeyCodes.KEY_UP || keyCode == KEY_J); } @@ -84,7 +86,7 @@ public boolean isPreviousEntryKey() @Override public boolean isNextEntryKey() { - if (context == Context.Edit) + if (context == ShortcutContext.Edit) { return altKey && (keyCode == KeyCodes.KEY_DOWN || keyCode == KEY_K); } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/table/TargetContentsPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/table/TargetContentsPresenter.java index 22999a0fb5..63f2ee7285 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/editor/table/TargetContentsPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/editor/table/TargetContentsPresenter.java @@ -47,6 +47,7 @@ import org.zanata.webtrans.client.events.TransUnitEditEventHandler; import org.zanata.webtrans.client.events.UserConfigChangeEvent; import org.zanata.webtrans.client.events.UserConfigChangeHandler; +import org.zanata.webtrans.client.keys.ShortcutContext; import org.zanata.webtrans.client.presenter.SourceContentsPresenter; import org.zanata.webtrans.client.presenter.UserConfigHolder; import org.zanata.webtrans.client.resources.TableEditorMessages; @@ -118,7 +119,7 @@ public TargetContentsPresenter(Provider displayProvider, this.identity = identity; this.dispatcher = dispatcher; - checkKey = new CheckKeyImpl(CheckKeyImpl.Context.Edit); + checkKey = new CheckKeyImpl(ShortcutContext.Edit); eventBus.addHandler(UserConfigChangeEvent.getType(), this); eventBus.addHandler(RequestValidationEvent.getType(), this); eventBus.addHandler(InsertStringInEditorEvent.getType(), this); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEvent.java b/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEvent.java new file mode 100644 index 0000000000..438ac0813b --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.events; + +import com.google.gwt.event.shared.GwtEvent; + +/** + * + * @author David Mason, damason@redhat.com * + */ +public class KeyShortcutEvent extends GwtEvent +{ + + private final int modifiers; + private final int keyCode; + + public int getModifiers() + { + return modifiers; + } + + public int getKeyCode() + { + return keyCode; + } + + public KeyShortcutEvent(int modifiers, int keyCode) + { + this.modifiers = modifiers; + this.keyCode = keyCode; + } + + @Override + protected void dispatch(KeyShortcutEventHandler handler) + { + handler.onKeyShortcut(this); + } + + + /** + * Handler type. + */ + private static Type TYPE; + + /** + * Gets the type associated with this event. + * + * @return returns the handler type + */ + public static Type getType() + { + return TYPE != null ? TYPE : (TYPE = new Type()); + } + + @Override + public Type getAssociatedType() + { + return getType(); + } +} diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEventHandler.java b/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEventHandler.java new file mode 100644 index 0000000000..48a7ef421f --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/events/KeyShortcutEventHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.events; + +import com.google.gwt.event.shared.EventHandler; + +/** + * + * @author David Mason, damason@redhat.com * + * + * @see KeyShortcutEvent + */ +public interface KeyShortcutEventHandler extends EventHandler +{ + void onKeyShortcut(KeyShortcutEvent event); +} diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/gin/WebTransClientModule.java b/zanata-war/src/main/java/org/zanata/webtrans/client/gin/WebTransClientModule.java index fb151ea306..76a49221d3 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/gin/WebTransClientModule.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/gin/WebTransClientModule.java @@ -49,6 +49,7 @@ import org.zanata.webtrans.client.presenter.DocumentListPresenter; import org.zanata.webtrans.client.presenter.GlossaryDetailsPresenter; import org.zanata.webtrans.client.presenter.GlossaryPresenter; +import org.zanata.webtrans.client.presenter.KeyShortcutPresenter; import org.zanata.webtrans.client.presenter.NotificationPresenter; import org.zanata.webtrans.client.presenter.OptionsPanelPresenter; import org.zanata.webtrans.client.presenter.SearchResultsPresenter; @@ -72,6 +73,7 @@ import org.zanata.webtrans.client.view.DocumentListView; import org.zanata.webtrans.client.view.GlossaryDetailsView; import org.zanata.webtrans.client.view.GlossaryView; +import org.zanata.webtrans.client.view.KeyShortcutView; import org.zanata.webtrans.client.view.NotificationView; import org.zanata.webtrans.client.view.SearchResultsView; import org.zanata.webtrans.client.view.TransMemoryDetailsView; @@ -103,6 +105,7 @@ protected void configure() bind(ValidationService.class).in(Singleton.class); bindPresenter(AppPresenter.class, AppPresenter.Display.class, AppView.class); + bindPresenter(KeyShortcutPresenter.class, KeyShortcutPresenter.Display.class, KeyShortcutView.class); bindPresenter(DocumentListPresenter.class, DocumentListPresenter.Display.class, DocumentListView.class); bindPresenter(SearchResultsPresenter.class, SearchResultsPresenter.Display.class, SearchResultsView.class); bindPresenter(TranslationPresenter.class, TranslationPresenter.Display.class, TranslationView.class); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/keys/KeyShortcut.java b/zanata-war/src/main/java/org/zanata/webtrans/client/keys/KeyShortcut.java new file mode 100644 index 0000000000..33a50b37ae --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/keys/KeyShortcut.java @@ -0,0 +1,140 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.keys; + +import org.zanata.webtrans.client.events.KeyShortcutEventHandler; +import org.zanata.webtrans.client.presenter.KeyShortcutPresenter; + +/** + * Represents a key shortcut for registration with {@link KeyShortcutPresenter}. + * + * @author David Mason, damason@redhat.com + * + */ +public class KeyShortcut +{ + public static final int ALT_KEY = 0x1; + public static final int SHIFT_KEY = 0x2; + public static final int CTRL_KEY = 0x4; + public static final int META_KEY = 0x8; + public static final int SHIFT_ALT_KEYS = ALT_KEY | SHIFT_KEY; + + private final int modifiers; + private final int keyCode; + private final ShortcutContext context; + private String description; + private final KeyShortcutEventHandler handler; + + /** + * Construct a KeyShortcut. + * + * @param modifiers keys such as Shift and Alt that must be depressed for the + * shortcut to fire. + *

+ * Use {@link #ALT_KEY}, {@link #SHIFT_KEY}, + * {@link #SHIFT_ALT_KEYS}, {@link #META_KEY} and {@link #CTRL_KEY} + * to generate this. ( e.g. {@code} CTRL_KEY | ALT_KEY ) + *

+ * @param keyCode the integer code for the key. + *

+ * This may be an uppercase character, but results may vary so test + * thoroughly in the targeted browsers. + *

+ *

+ * Note that for keypress events, the key code depends on Shift and + * CapsLock and will give the lowercase or uppercase ASCII code as + * expected. keydown and keyup events appear always to give the + * uppercase key code (keydown is currently used for all shortcuts. + *

+ * @param context see + * {@link KeyShortcutPresenter#setContextActive(ShortcutContext, boolean)} + * @param description shown to the user in the key shortcut summary pane + */ + public KeyShortcut(int modifiers, int keyCode, ShortcutContext context, String description, KeyShortcutEventHandler handler) + { + this.modifiers = modifiers; + this.keyCode = keyCode; + this.context = context; + this.description = description; + this.handler = handler; + } + + public int getModifiers() + { + return modifiers; + } + + public int getKeyCode() + { + return keyCode; + } + + public ShortcutContext getContext() + { + return context; + } + + public String getDescription() + { + return description; + } + + public KeyShortcutEventHandler getHandler() + { + return handler; + } + + /** + * Return a hash for just the user input part of the shortcut, without + * context. + * + * @return a hash that is unique for a set of modifiers + key code + */ + public int keysHash() + { + return keyCode * 8 + modifiers; + } + + @Override + public int hashCode() + { + int hash = context.ordinal(); + hash = hash * 256 + keyCode; + hash = hash * 8 + modifiers; + return hash; + } + + /** + * Two {@link KeyShortcut} objects are equal if they have the same modifier + * keys, key code and context. + */ + @Override + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (!(obj instanceof KeyShortcut)) + return false; + KeyShortcut other = (KeyShortcut) obj; + return modifiers == other.modifiers && keyCode == other.keyCode && context == other.context; + } +} \ No newline at end of file diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/keys/ShortcutContext.java b/zanata-war/src/main/java/org/zanata/webtrans/client/keys/ShortcutContext.java new file mode 100644 index 0000000000..688300df55 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/keys/ShortcutContext.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.keys; + +import org.zanata.webtrans.client.presenter.KeyShortcutPresenter; + +/** + * View contexts within the application that may have key shortcuts bound and + * may be activated and deactivated to enable or disable bound shortcuts. + * + * @see KeyShortcutPresenter#registerKeyShortcut(KeyShortcut) + * @see KeyShortcutPresenter#setContextActive(ShortcutContext, boolean) + */ +public enum ShortcutContext +{ + + /** + * For shortcuts that should always be active. Presenters should not + * deactivate this context. + */ + Application, + + /** + * Used by {@link SearchResultsPresenter} + */ + ProjectWideSearch, + + /** + * Used by {@link TableEditorPresenter} + */ + Navigation, + + /** + * Used by {@link InlineTargetCellEditor} + */ + Edit; +} \ No newline at end of file diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java index f036ae54bb..429f87f5b1 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java @@ -21,6 +21,8 @@ package org.zanata.webtrans.client.presenter; import net.customware.gwt.presenter.client.EventBus; +import net.customware.gwt.presenter.client.PresenterRevealedEvent; +import net.customware.gwt.presenter.client.PresenterRevealedHandler; import net.customware.gwt.presenter.client.widget.WidgetPresenter; import org.zanata.common.TranslationStats; @@ -94,6 +96,7 @@ public interface Display extends net.customware.gwt.presenter.client.widget.Widg void setErrorNotificationText(int count); } + private final KeyShortcutPresenter keyShortcutPresenter; private final DocumentListPresenter documentListPresenter; private final TranslationPresenter translationPresenter; private final SearchResultsPresenter searchResultsPresenter; @@ -116,9 +119,21 @@ public interface Display extends net.customware.gwt.presenter.client.widget.Widg private static final String WORKSPACE_TITLE_QUERY_PARAMETER_KEY = "title"; @Inject - public AppPresenter(Display display, EventBus eventBus, final TranslationPresenter translationPresenter, final DocumentListPresenter documentListPresenter, final SearchResultsPresenter searchResultsPresenter, final NotificationPresenter notificationPresenter, final Identity identity, final WorkspaceContext workspaceContext, final WebTransMessages messages, final History history, final Window window, final Window.Location windowLocation) + public AppPresenter(Display display, EventBus eventBus, + final KeyShortcutPresenter keyShortcutPresenter, + final TranslationPresenter translationPresenter, + final DocumentListPresenter documentListPresenter, + final SearchResultsPresenter searchResultsPresenter, + final NotificationPresenter notificationPresenter, + final Identity identity, + final WorkspaceContext workspaceContext, + final WebTransMessages messages, + final History history, + final Window window, + final Window.Location windowLocation) { super(display, eventBus); + this.keyShortcutPresenter = keyShortcutPresenter; this.history = history; this.identity = identity; this.messages = messages; @@ -140,6 +155,7 @@ public void setErrorNotificationLabel(int count) @Override protected void onBind() { + keyShortcutPresenter.bind(); documentListPresenter.bind(); translationPresenter.bind(); searchResultsPresenter.bind(); @@ -309,6 +325,21 @@ public void onClick(ClickEvent event) } }); + registerHandler(eventBus.addHandler(PresenterRevealedEvent.getType(), new PresenterRevealedHandler() + { + + @Override + public void onPresenterRevealed(PresenterRevealedEvent event) + { + // TODO disabled until tests are updated +// if (event.getPresenter() == searchResultsPresenter) +// { +// display.setDocumentLabel("", messages.projectWideSearchAndReplace()); +// currentDisplayStats = projectStats; +// } + } + })); + display.setUserLabel(identity.getPerson().getName()); String workspaceTitle = windowLocation.getParameter(WORKSPACE_TITLE_QUERY_PARAMETER_KEY); display.setWorkspaceNameLabel(workspaceContext.getWorkspaceName(), workspaceTitle); @@ -316,6 +347,7 @@ public void onClick(ClickEvent event) display.setReadOnlyVisible(workspaceContext.isReadOnly()); + // this may be redundant with the following history event line showView(MainView.Documents); history.fireCurrentHistoryState(); @@ -366,21 +398,29 @@ private void showView(MainView viewToShow) switch (viewToShow) { + // TODO use revealDisplay/concealDisplay for editor and document views case Editor: if (selectedDocument != null) { display.setDocumentLabel(selectedDocument.getPath(), selectedDocument.getName()); } currentDisplayStats = selectedDocumentStats; + searchResultsPresenter.concealDisplay(); break; case Search: + // these two lines temporarily here until PresenterRevealedHandler is + // fully functional display.setDocumentLabel("", messages.projectWideSearchAndReplace()); currentDisplayStats = projectStats; + searchResultsPresenter.revealDisplay(); break; case Documents: default: + // TODO may want to continue showing selected document name + // if a document is selected. display.setDocumentLabel("", messages.noDocumentSelected()); currentDisplayStats = projectStats; + searchResultsPresenter.concealDisplay(); break; } display.showInMainView(viewToShow); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/KeyShortcutPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/KeyShortcutPresenter.java new file mode 100644 index 0000000000..67cd3d87f8 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/KeyShortcutPresenter.java @@ -0,0 +1,312 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.presenter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.zanata.webtrans.client.events.KeyShortcutEvent; +import org.zanata.webtrans.client.events.KeyShortcutEventHandler; +import org.zanata.webtrans.client.keys.KeyShortcut; +import org.zanata.webtrans.client.keys.ShortcutContext; +import org.zanata.webtrans.client.resources.WebTransMessages; + +import com.allen_sauer.gwt.log.client.Log; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Event.NativePreviewEvent; +import com.google.gwt.user.client.Event.NativePreviewHandler; +import com.google.inject.Inject; + +import net.customware.gwt.presenter.client.EventBus; +import net.customware.gwt.presenter.client.widget.WidgetDisplay; +import net.customware.gwt.presenter.client.widget.WidgetPresenter; + +/** + * Detects shortcut key combinations such as Alt+KEY and Shift+Alt+KEY and + * broadcasts corresponding {@link KeyShortcutEvent}s. + * + * Handlers are registered directly with this presenter to avoid excessive + * traffic on the main event bus and to make handling of events simpler. + * + * Only key-down events are processed. + * + * @author David Mason, damason@redhat.com * + */ +public class KeyShortcutPresenter extends WidgetPresenter +{ + + public interface Display extends WidgetDisplay + { + void addContext(String title, List shortcuts); + + void showPanel(); + + public void clearPanel(); + + //hide method not provided as auto-hide is enabled + } + + /** + * Key uses {@link KeyShortcut#keysHash()} + */ + private Map> shortcutMap; + + private Set activeContexts; + + private WebTransMessages messages; + + @Inject + public KeyShortcutPresenter(Display display, EventBus eventBus, final WebTransMessages webTransMessages) + { + super(display, eventBus); + this.messages = webTransMessages; + } + + @Override + protected void onBind() + { + ensureActiveContexts().add(ShortcutContext.Application); + + Event.addNativePreviewHandler(new NativePreviewHandler() + { + + @Override + public void onPreviewNativeEvent(NativePreviewEvent event) + { + NativeEvent evt = event.getNativeEvent(); + + if ((event.getTypeInt() & Event.ONKEYDOWN) != 0) + { + Log.debug("Event type: " + evt.getType()); + + processKeyEvent(evt); + + // Log.debug("Key event. Stopping propagation."); + // evt.stopPropagation(); + // evt.preventDefault(); + } + } + }); + + // could try to use ?, although this is not as simple as passing character '?' + registerKeyShortcut(new KeyShortcut(KeyShortcut.ALT_KEY, 'K', + ShortcutContext.Application, + messages.showAvailableKeyShortcuts(), + new KeyShortcutEventHandler() + { + + @Override + public void onKeyShortcut(KeyShortcutEvent event) + { + display.clearPanel(); + for (ShortcutContext context : ensureActiveContexts()) + { + ArrayList shortcutStrings = new ArrayList(); + for (Set shortcutSet : ensureShortcutMap().values()) + { + for (KeyShortcut shortcut : shortcutSet) + { + if (shortcut.getContext() == context) + { + StringBuilder sb = new StringBuilder(); + if ((shortcut.getModifiers() & KeyShortcut.CTRL_KEY) != 0) + { + sb.append("Ctrl+"); + } + if ((shortcut.getModifiers() & KeyShortcut.SHIFT_KEY) != 0) + { + sb.append("Shift+"); + } + if ((shortcut.getModifiers() & KeyShortcut.META_KEY) != 0) + { + sb.append("Meta+"); + } + if ((shortcut.getModifiers() & KeyShortcut.ALT_KEY) != 0) + { + sb.append("Alt+"); + } + sb.append((char) shortcut.getKeyCode()); + sb.append(" : "); + sb.append(shortcut.getDescription()); + shortcutStrings.add(sb.toString()); + } + } + } + + String contextName = ""; + switch (context) + { + case Application: + contextName = messages.applicationScope(); + break; + case ProjectWideSearch: + contextName = messages.projectWideSearchAndReplace(); + break; + case Edit: + contextName = messages.editScope(); + break; + case Navigation: + contextName = messages.navigationScope(); + break; + } + display.addContext(contextName, shortcutStrings); + } + display.showPanel(); + } + })); + } + + @Override + protected void onUnbind() + { + // TODO Auto-generated method stub + } + + @Override + protected void onRevealDisplay() + { + // TODO Auto-generated method stub + } + + public void setContextActive(ShortcutContext context, boolean active) + { + if (active) + { + ensureActiveContexts().add(context); + } + else + { + if (context == ShortcutContext.Application) + { + // TODO throw exception? Remove this check? Just warn but still remove context? + Log.warn("Tried to set global shortcut context inactive. Ignoring."); + } + else + { + ensureActiveContexts().remove(context); + } + } + } + + public HandlerRegistration registerKeyShortcut(KeyShortcut shortcut) + { + Log.info("registering key shortcut. key: " + shortcut.getKeyCode() + " modifier: " + shortcut.getModifiers() + " keyhash: " + shortcut.keysHash()); + Set shortcuts = ensureShortcutMap().get(shortcut.keysHash()); + if (shortcuts == null) + { + shortcuts = new HashSet(); + ensureShortcutMap().put(shortcut.keysHash(), shortcuts); + } + shortcuts.add(shortcut); + return new KeyShortcutHandlerRegistration(shortcut); + } + + private void processKeyEvent(NativeEvent evt) + { + int modifiers = calculateModifiers(evt); + int keyHash = calculateKeyHash(modifiers, evt.getKeyCode()); + Log.debug("processing key shortcut for key" + evt.getKeyCode() + " with hash " + keyHash); + Set shortcuts = ensureShortcutMap().get(keyHash); + if (shortcuts != null) + { + KeyShortcutEvent shortcutEvent = new KeyShortcutEvent(modifiers, evt.getKeyCode()); + for (KeyShortcut shortcut : shortcuts) + { + if (ensureActiveContexts().contains(shortcut.getContext())) + { + shortcut.getHandler().onKeyShortcut(shortcutEvent); + } + } + } + } + + /** + * Calculate a hash that should match {@link KeyShortcut#keysHash()}. + * + * @param evt + * @return + * @see KeyShortcut#keysHash() + */ + private int calculateKeyHash(int modifiers, int keyCode) + { + int keyHash = keyCode * 8; + keyHash |= modifiers; + return keyHash; + } + + private int calculateModifiers(NativeEvent evt) + { + int modifiers = 0; + modifiers |= evt.getAltKey() ? KeyShortcut.ALT_KEY : 0; + modifiers |= evt.getShiftKey() ? KeyShortcut.SHIFT_KEY : 0; + modifiers |= evt.getCtrlKey() ? KeyShortcut.CTRL_KEY : 0; + modifiers |= evt.getMetaKey() ? KeyShortcut.META_KEY : 0; + return modifiers; + } + + private Set ensureActiveContexts() + { + if (activeContexts == null) + { + activeContexts = new HashSet(); + } + return activeContexts; + } + + private Map> ensureShortcutMap() + { + if (shortcutMap == null) + { + shortcutMap = new HashMap>(); + } + return shortcutMap; + } + + private class KeyShortcutHandlerRegistration implements HandlerRegistration + { + + private KeyShortcut shortcut; + + public KeyShortcutHandlerRegistration(KeyShortcut shortcut) + { + this.shortcut = shortcut; + } + + @Override + public void removeHandler() + { + Set shortcuts = ensureShortcutMap().get(shortcut.keysHash()); + if (shortcuts != null) + { + shortcuts.remove(shortcut); + } + } + + } + +} diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/SearchResultsPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/SearchResultsPresenter.java index b351f318e3..34d630a517 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/SearchResultsPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/SearchResultsPresenter.java @@ -33,12 +33,16 @@ import org.zanata.webtrans.client.events.NotificationEvent; import org.zanata.webtrans.client.events.NotificationEvent.Severity; +import org.zanata.webtrans.client.events.KeyShortcutEvent; +import org.zanata.webtrans.client.events.KeyShortcutEventHandler; import org.zanata.webtrans.client.events.TransUnitUpdatedEvent; import org.zanata.webtrans.client.events.TransUnitUpdatedEventHandler; import org.zanata.webtrans.client.events.WorkspaceContextUpdateEvent; import org.zanata.webtrans.client.events.WorkspaceContextUpdateEventHandler; import org.zanata.webtrans.client.history.History; import org.zanata.webtrans.client.history.HistoryToken; +import org.zanata.webtrans.client.keys.KeyShortcut; +import org.zanata.webtrans.client.keys.ShortcutContext; import org.zanata.webtrans.client.resources.WebTransMessages; import org.zanata.webtrans.client.rpc.CachingDispatchAsync; import org.zanata.webtrans.shared.model.TransUnit; @@ -78,7 +82,7 @@ /** * View for project-wide search and replace within textflow targets * - * @author David Mason, damason@redhat.com + * @author David Mason, damason@redhat.com */ public class SearchResultsPresenter extends WidgetPresenter { @@ -97,8 +101,12 @@ public interface Display extends WidgetDisplay HasValue getFilterTextBox(); + void focusFilterTextBox(); + HasValue getReplacementTextBox(); + void focusReplacementTextBox(); + HasText getSelectionInfoLabel(); HasValue getCaseSensitiveChk(); @@ -156,6 +164,7 @@ HasData addDocument( private final WebTransMessages messages; private final CachingDispatchAsync dispatcher; private final WorkspaceContext workspaceContext; + private final KeyShortcutPresenter keyShortcutPresenter; private final History history; private AsyncCallback projectSearchCallback; private Delegate previewButtonDelegate; @@ -184,13 +193,19 @@ HasData addDocument( @Inject - public SearchResultsPresenter(Display display, EventBus eventBus, CachingDispatchAsync dispatcher, History history, final WebTransMessages webTransMessages, final WorkspaceContext workspaceContext) + public SearchResultsPresenter(Display display, EventBus eventBus, + CachingDispatchAsync dispatcher, + History history, + final WebTransMessages webTransMessages, + final WorkspaceContext workspaceContext, + final KeyShortcutPresenter keyShortcutPresenter) { super(display, eventBus); messages = webTransMessages; this.history = history; this.dispatcher = dispatcher; this.workspaceContext = workspaceContext; + this.keyShortcutPresenter = keyShortcutPresenter; } @Override @@ -324,17 +339,7 @@ public void onClick(ClickEvent event) @Override public void onClick(ClickEvent event) { - for (Entry> en : documentDataProviders.entrySet()) - { - MultiSelectionModel selectionModel = documentSelectionModels.get(en.getKey()); - if (selectionModel != null) - { - for (TransUnitReplaceInfo tu : en.getValue().getList()) - { - selectionModel.setSelected(tu, true); - } - } - } + selectAllTextFlows(); } })); @@ -413,6 +418,54 @@ else if (info.getReplaceInfo() == null) } } })); + + keyShortcutPresenter.registerKeyShortcut(new KeyShortcut( + KeyShortcut.SHIFT_ALT_KEYS, 'A', + ShortcutContext.ProjectWideSearch, + messages.selectAllTextFlowsKeyShortcut(), + new KeyShortcutEventHandler() + { + @Override + public void onKeyShortcut(KeyShortcutEvent event) + { + selectAllTextFlows(); + } + })); + + keyShortcutPresenter.registerKeyShortcut(new KeyShortcut( + KeyShortcut.ALT_KEY, 'S', + ShortcutContext.ProjectWideSearch, + messages.focusSearchPhraseKeyShortcut(), + new KeyShortcutEventHandler() + { + @Override + public void onKeyShortcut(KeyShortcutEvent event) + { + display.focusFilterTextBox(); + } + })); + + keyShortcutPresenter.registerKeyShortcut(new KeyShortcut( + KeyShortcut.ALT_KEY, 'R', + ShortcutContext.ProjectWideSearch, + messages.focusReplacementPhraseKeyShortcut(), + new KeyShortcutEventHandler() + { + @Override + public void onKeyShortcut(KeyShortcutEvent event) + { + display.focusReplacementTextBox(); + } + })); + + + // TODO register key shortcuts: + // Alt+Z undo last operation + + // detect currently focused document (if any) + // Alt+A select current doc + // Alt+V view current doc in editor + // Shift+Alt+V search current doc in editor } private void showDocInEditor(String doc, boolean runSearch) @@ -439,6 +492,12 @@ protected void onUnbind() @Override public void onRevealDisplay() { + keyShortcutPresenter.setContextActive(ShortcutContext.ProjectWideSearch, true); + } + + public void concealDisplay() + { + keyShortcutPresenter.setContextActive(ShortcutContext.ProjectWideSearch, false); } private AsyncCallback buildProjectSearchCallback() @@ -847,6 +906,8 @@ private void displaySearchResults(GetProjectTransUnitListsResult result) } /** + * Display header and all results for a single document. + * * @param docId * @param docPathName * @param transUnits @@ -1038,8 +1099,6 @@ private int countSelectedFlows() */ private void setReplaceState(TransUnitReplaceInfo replaceInfo, ReplacementState replaceState) { - // TODO check that context is updated properly (becomes read-only when read-only event comes in) - Log.debug("Workspace read-only: " + workspaceContext.isReadOnly()); if (workspaceContext.isReadOnly()) { replaceInfo.setReplaceState(ReplacementState.NotAllowed); @@ -1050,4 +1109,18 @@ private void setReplaceState(TransUnitReplaceInfo replaceInfo, ReplacementState } } + private void selectAllTextFlows() + { + for (Entry> en : documentDataProviders.entrySet()) + { + MultiSelectionModel selectionModel = documentSelectionModels.get(en.getKey()); + if (selectionModel != null) + { + for (TransUnitReplaceInfo tu : en.getValue().getList()) + { + selectionModel.setSelected(tu, true); + } + } + } + } } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TranslationPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TranslationPresenter.java index d02d9e60e2..b7c38fb4f3 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TranslationPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TranslationPresenter.java @@ -31,6 +31,7 @@ import org.zanata.webtrans.client.events.TransMemoryShortcutCopyEvent; import org.zanata.webtrans.client.events.WorkspaceContextUpdateEvent; import org.zanata.webtrans.client.events.WorkspaceContextUpdateEventHandler; +import org.zanata.webtrans.client.keys.ShortcutContext; import org.zanata.webtrans.client.resources.WebTransMessages; import org.zanata.webtrans.client.rpc.CachingDispatchAsync; import org.zanata.webtrans.shared.model.TransUnit; @@ -220,7 +221,7 @@ public void onValueChange(ValueChangeEvent event) } })); - final CheckKey checkKey = new CheckKeyImpl(CheckKeyImpl.Context.Navigation); + final CheckKey checkKey = new CheckKeyImpl(ShortcutContext.Navigation); // TODO make testable diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java index 933592aaa6..9eaef25b28 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java @@ -271,4 +271,28 @@ public interface WebTransMessages extends Messages @DefaultMessage("Error notification") String errorNotification(); + + @DefaultMessage("Available Keyboard Shortcuts") + String availableKeyShortcutsTitle(); + + @DefaultMessage("select text flows in all documents") + String selectAllTextFlowsKeyShortcut(); + + @DefaultMessage("focus search phrase") + String focusSearchPhraseKeyShortcut(); + + @DefaultMessage("focus replacement phrase") + String focusReplacementPhraseKeyShortcut(); + + @DefaultMessage("show available shortcuts") + String showAvailableKeyShortcuts(); + + @DefaultMessage("Application") + String applicationScope(); + + @DefaultMessage("Editing text") + String editScope(); + + @DefaultMessage("Editor navigation") + String navigationScope(); } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java index c02bb49aee..b549780b67 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java @@ -137,6 +137,8 @@ public SearchResultsDocumentTable(Delegate previewDelegate addStyleName("projectWideSearchResultsDocumentBody"); } + // TODO add focus tracking field to allow current-document type interactions + // listeners may need to be attached in view /** * @return a column that displays the 1-based index of the text flow diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java new file mode 100644 index 0000000000..a995e8f372 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java @@ -0,0 +1,76 @@ +package org.zanata.webtrans.client.view; + +import java.util.List; + +import org.zanata.webtrans.client.presenter.KeyShortcutPresenter; +import org.zanata.webtrans.client.resources.WebTransMessages; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +public class KeyShortcutView extends PopupPanel implements KeyShortcutPresenter.Display +{ + + private static KeyShortcutViewUiBinder uiBinder = GWT.create(KeyShortcutViewUiBinder.class); + + interface KeyShortcutViewUiBinder extends UiBinder + { + } + + @UiField VerticalPanel keyShortcutPanel; + + final WebTransMessages messages; + + @Inject + public KeyShortcutView(final WebTransMessages webTransMessages) + { + setWidget(uiBinder.createAndBindUi(this)); + setStyleName("notificationPanel"); + setAutoHideEnabled(true); + setAutoHideOnHistoryEventsEnabled(true); + setGlassEnabled(true); + this.messages = webTransMessages; + } + + @Override + public void clearPanel() + { + keyShortcutPanel.clear(); + Label heading = new Label(messages.availableKeyShortcutsTitle()); + heading.addStyleName("keyShortcutHeading"); + keyShortcutPanel.add(heading); + } + + @Override + public void addContext(String title, List shortcuts) + { + VerticalPanel panel = new VerticalPanel(); + Label categoryTitle = new Label(title); + categoryTitle.addStyleName("keyShortcutCategoryTitle"); + panel.add(categoryTitle); + for (String shortcut : shortcuts) + { + panel.add(new Label(shortcut)); + } + panel.addStyleName("keyShortcutCategory"); + keyShortcutPanel.add(panel); + } + + @Override + public void showPanel() + { + center(); + } + + @Override + public Widget asWidget() + { + return this; + } +} diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.ui.xml b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.ui.xml new file mode 100644 index 0000000000..10698b4ef0 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.ui.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java index 893ff7998c..fe46a057cf 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java @@ -127,12 +127,26 @@ public HasValue getFilterTextBox() return filterTextBox; } + @Override + public void focusFilterTextBox() + { + filterTextBox.setFocus(true); + filterTextBox.setSelectionRange(0, filterTextBox.getText().length()); + } + @Override public HasValue getReplacementTextBox() { return replacementTextBox; } + @Override + public void focusReplacementTextBox() + { + replacementTextBox.setFocus(true); + replacementTextBox.setSelectionRange(0, replacementTextBox.getText().length()); + } + @Override public HasText getSelectionInfoLabel() { diff --git a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.css b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.css index 7aa8a0f451..b9521f673c 100644 --- a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.css +++ b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.css @@ -443,6 +443,33 @@ tr.ApprovedStateDecoration td.TableEditorCell-Target .TableEditorContent-Edit width: 99%; } +/* TODO share this with other modal panels */ +.keyShortcutPanel +{ + color: white; + background-color: black; + opacity:0.85; + border-radius:8px; + padding: 20px; +} + +.keyShortcutHeading +{ + font-size: 1.4em; +} + +.keyShortcutCategory +{ + padding: 10px; + font-size: 1.2em; +} + +.keyShortcutCategoryTitle +{ + font-size: 1.2em; + margin-bottom: 4px; +} + .transFilterTextBox { margin: 0px; diff --git a/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/AppPresenterTest.java b/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/AppPresenterTest.java index 360aa7e166..20622452ed 100644 --- a/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/AppPresenterTest.java +++ b/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/AppPresenterTest.java @@ -15,6 +15,8 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import net.customware.gwt.presenter.client.EventBus; +import net.customware.gwt.presenter.client.PresenterRevealedEvent; +import net.customware.gwt.presenter.client.PresenterRevealedHandler; import org.easymock.Capture; import org.testng.annotations.BeforeClass; @@ -96,6 +98,7 @@ public class AppPresenterTest HasCommand mockSignoutMenuItem; HasCommand mockHelpMenuItem; + KeyShortcutPresenter mockKeyShortcutPresenter; DocumentListPresenter mockDocumentListPresenter; SearchResultsPresenter mockSearchResultsPresenter; TranslationPresenter mockTranslationPresenter; @@ -117,6 +120,7 @@ public class AppPresenterTest private Capture capturedNotificationEventHandler; private Capture capturedProjectStatsUpdatedEventHandler; private Capture capturedWorkspaceContextUpdatedEventHandler; + private Capture capturedPresenterRevealedHandler; private Capture capturedLeaveWorkspaceLinkCommand; @@ -142,6 +146,7 @@ public void createMocks() mockEventBus = createMock(EventBus.class); mockHistory = createMock(History.class); mockIdentity = createMock(Identity.class); + mockKeyShortcutPresenter = createMock(KeyShortcutPresenter.class); mockLeaveWorkspaceMenuItem = createMock(HasCommand.class); mockMessages = createMock(WebTransMessages.class); mockPerson = createMock(Person.class); @@ -165,7 +170,7 @@ public void createMocks() capturedNotificationEventHandler = new Capture(); capturedProjectStatsUpdatedEventHandler = new Capture(); capturedWorkspaceContextUpdatedEventHandler = new Capture(); - + capturedPresenterRevealedHandler = new Capture(); capturedSignoutLinkCommand = new Capture(); capturedLeaveWorkspaceLinkCommand = new Capture(); @@ -185,7 +190,11 @@ void beforeMethod() setupDefaultMockExpectations(); - appPresenter = new AppPresenter(mockDisplay, mockEventBus, mockTranslationPresenter, mockDocumentListPresenter, mockSearchResultsPresenter, mockNotificationPresenter, mockIdentity, mockWorkspaceContext, mockMessages, mockHistory, mockWindow, mockWindowLocation); + appPresenter = new AppPresenter(mockDisplay, mockEventBus, + mockKeyShortcutPresenter, mockTranslationPresenter, + mockDocumentListPresenter, mockSearchResultsPresenter, + mockNotificationPresenter, mockIdentity, mockWorkspaceContext, + mockMessages, mockHistory, mockWindow, mockWindowLocation); mockNotificationPresenter.setErrorLabelListener(appPresenter); expectLastCall().once(); @@ -284,6 +293,8 @@ public void testHistoryTriggersViewChange() expect(mockDocumentListPresenter.getDocumentId(TEST_DOCUMENT_PATH + TEST_DOCUMENT_NAME)).andReturn(testDocId).anyTimes(); mockDisplay.showInMainView(MainView.Editor); expectLastCall().once(); + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); // avoid checking name or stats for this test mockDisplay.setDocumentLabel(notNull(String.class), notNull(String.class)); expectLastCall().anyTimes(); @@ -321,6 +332,8 @@ public void testHistoryTriggersDocumentNameStatsUpdate() // avoid checking for view change, tested elsewhere mockDisplay.showInMainView(isA(MainView.class)); expectLastCall().anyTimes(); + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); mockDisplay.setDocumentLabel(TEST_DOCUMENT_PATH, TEST_DOCUMENT_NAME); expectLastCall().once(); mockDisplay.setStats(eq(testDocStats)); @@ -590,6 +603,8 @@ private void expectLoadDocAndViewEditor() mockDisplay.showInMainView(MainView.Editor); expectLastCall().once(); + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); } /** @@ -644,6 +659,16 @@ private void expectViewTransitionFromEditor(MainView toView, TranslationStats ex //expect return to given view mockDisplay.showInMainView(toView); expectLastCall().once(); + if (toView == MainView.Search) + { + mockSearchResultsPresenter.revealDisplay(); + expectLastCall().once(); + } + else + { + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); + } mockDisplay.setDocumentLabel("", expectedDocLabel); expectLastCall().once(); mockDisplay.setStats(eq(expectedStats)); @@ -662,6 +687,10 @@ private void simulatePageChangeFromEditor(HistoryToken fromHistoryState, MainVie capturedHistoryValueChangeHandler.getValue().onValueChange(new ValueChangeEvent(fromHistoryState.toTokenString()) { }); + if (toView == MainView.Search) + { + capturedPresenterRevealedHandler.getValue().onPresenterRevealed(new PresenterRevealedEvent(mockSearchResultsPresenter)); + } } /** @@ -687,6 +716,8 @@ private void expectReturnToEditorView(TranslationStats documentStats) { mockDisplay.showInMainView(MainView.Editor); expectLastCall().once(); + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); mockDisplay.setDocumentLabel(TEST_DOCUMENT_PATH, TEST_DOCUMENT_NAME); expectLastCall().once(); mockDisplay.setStats(eq(documentStats)); @@ -714,6 +745,8 @@ private void setupDefaultMockExpectations() */ private void expectSubPresenterBindings() { + mockKeyShortcutPresenter.bind(); + expectLastCall().once(); mockDocumentListPresenter.bind(); expectLastCall().once(); mockSearchResultsPresenter.bind(); @@ -741,7 +774,7 @@ private void expectHandlerRegistrations() expectEventHandlerRegistration(DocumentStatsUpdatedEvent.getType(), DocumentStatsUpdatedEventHandler.class, capturedDocumentStatsUpdatedEventHandler); expectEventHandlerRegistration(ProjectStatsUpdatedEvent.getType(), ProjectStatsUpdatedEventHandler.class, capturedProjectStatsUpdatedEventHandler); expectEventHandlerRegistration(WorkspaceContextUpdateEvent.getType(), WorkspaceContextUpdateEventHandler.class, capturedWorkspaceContextUpdatedEventHandler); - + expectEventHandlerRegistration(PresenterRevealedEvent.getType(), PresenterRevealedHandler.class, capturedPresenterRevealedHandler); } /** @@ -781,6 +814,10 @@ private void expectPresenterSetupActions() mockDisplay.showInMainView(MainView.Documents); expectLastCall().once(); //starts on document list view + // due to this display beginning as concealed + mockSearchResultsPresenter.concealDisplay(); + expectLastCall().once(); + mockDismissVisibility.setVisible(false); // starts invisible expectLastCall().once(); @@ -828,7 +865,7 @@ private void setupMockGetterReturnValues() private void resetAllMocks() { reset(mockDisplay, mockDocumentListPresenter, mockDocumentsLink, mockErrorNotificationBtn); - reset(mockEventBus, mockHistory, mockIdentity); + reset(mockEventBus, mockHistory, mockIdentity, mockKeyShortcutPresenter); reset(mockMessages, mockPerson, mockSearchResultsPresenter); reset(mockTranslationPresenter, mockWindow, mockWindowLocation, mockWorkspaceContext); reset(mockDismiss, mockDismissVisibility, mockNotificationPresenter); @@ -851,13 +888,14 @@ private void resetAllCaptures() capturedSearchLinkClickHandler.reset(); capturedSignoutLinkCommand.reset(); capturedWorkspaceContextUpdatedEventHandler.reset(); + capturedPresenterRevealedHandler.reset(); capturedErrorNotificationBtnHandler.reset(); } private void replayAllMocks() { replay(mockDisplay, mockDocumentListPresenter, mockDocumentsLink, mockErrorNotificationBtn); - replay(mockEventBus, mockHistory, mockIdentity); + replay(mockEventBus, mockHistory, mockIdentity, mockKeyShortcutPresenter); replay(mockMessages, mockPerson, mockSearchResultsPresenter); replay(mockTranslationPresenter, mockWindow, mockWindowLocation, mockWorkspaceContext); replay(mockDismiss, mockDismissVisibility, mockNotificationPresenter); @@ -868,7 +906,7 @@ private void replayAllMocks() private void verifyAllMocks() { verify(mockDisplay, mockDocumentListPresenter, mockDocumentsLink, mockErrorNotificationBtn); - verify(mockEventBus, mockHistory, mockIdentity); + verify(mockEventBus, mockHistory, mockIdentity, mockKeyShortcutPresenter); verify(mockMessages, mockPerson, mockSearchResultsPresenter); verify(mockTranslationPresenter, mockWindow, mockWindowLocation, mockWorkspaceContext); verify(mockDismiss, mockDismissVisibility, mockNotificationPresenter);