| By Chris Muir | Article Rating: |
|
| November 3, 2010 03:47 AM EDT | Reads: |
354 |
We recently had the requirement to provide our users global hotkeys to switch between tabs within the ADF UI Shell (a.k.a. Dynamic Tab Shell) in JDev 11g. Luckily I caught a presentation at Open World this year where Frank Nimphius showed off support for creating global hotkeys in ADF applications. Frank was kind enough to give me his source code allowing me to modify it to suit the ADF UI Shell specifically. The following code shows the general technique for getting global hotkeys workings, as well as specific code to suit the ADF UI Shell implementation. The following code was built and tested under JDev 11.1.1.2.0.ADF UI Shell Extension – global hotkeys
Readers familiar with the current incarnation of the ADF UI Shell will know it has the ability to spawn 1 to 15 "activity" tabs displaying whatever the programmer chooses. This provides an ideal framework for users to spawn multiple bounded task flows (BTFs) and work on several data sets all within the one browser window.
Our users have taken to the UI Shell and have been asking for extensions ever since. Of particular note they wanted the ability to open a set of activity tabs, and then flip between them using keyboard shortcuts rather than mouse clicks.
Frank's solution to the rescue.
Solution
The solution requires 3 working parts:
a) JavaScript
b) ViewScoped Managed Bean
c) Changes to the ADF UI Shell derived page to support the hotkeys to call "a" and "b"
The following code shows the general technique.
JavaScript
var keyRegistry = new Array();You'll note the hotkey mapping only goes upto 10 (1 to 9 plus zero). The UI Shell does support 15 tabs, but I couldn't think of a nice key combination beyond the 10th.... that can be left up to you.
keyRegistry[0] = "alt 1";
keyRegistry[1] = "alt 2";
keyRegistry[2] = "alt 3";
keyRegistry[3] = "alt 4";
keyRegistry[4] = "alt 5";
keyRegistry[5] = "alt 6";
keyRegistry[6] = "alt 7";
keyRegistry[7] = "alt 8";
keyRegistry[8] = "alt 9";
keyRegistry[9] = "alt 0";
function registerKeyBoardHandler(serverListener, afdocument) {
_serverListener = serverListener;
var document = AdfPage.PAGE.findComponentByAbsoluteId(afdocument);
_document = document;
for (var i = keyRegistry.length - 1; i >= 0; i--) {
var keyStroke = AdfKeyStroke.getKeyStrokeFromMarshalledString(keyRegistry[i]);
AdfRichUIPeer.registerKeyStroke(document, keyStroke, callBack);
}
}
function callBack(keyCode) {
var activeComponentClientId = AdfPage.PAGE.getActiveComponentId();
// Send the marshalled key code to the server listener for the developer
// To handle the function key in a managed bean method
var marshalledKeyCode = keyCode.toMarshalledString();
// {AdfUIComponent} component Component to queue the custom event on
// {String} name of serverListener
// {Object} params a set of parameters to include on the event.
// {Boolean} immediate whether the custom event is "immediate" -
// which will cause it to be delivered during Apply Request
// Values on the server, or not immediate, in which
// case it will be delivered during Invoke Application.
// Note that if one of the keyboard functions is to create ADF
// bound rows, immediate must be set to false. There is no
// option yet for the ClientEvent to be queued for later -
// InvokeApplication - on the server.
AdfCustomEvent.queue(_document,
_serverListener, {keycode:marshalledKeyCode,
activeComponentClientId:activeComponentClientId}, false);
// indicate to the client that the key was handled and that there
// is no need to pass the event to the browser to handle it
return true;
}
import java.util.List;Of specific importance the handleKeyboardEvent() method makes use of the ADF UI Shell TabContext class to set the current activity-tab according to the hotkey pressed.
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import oracle.adf.view.rich.render.ClientEvent;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
import waosr.ui.pattern.dynamicShell.TabContext;
public class KeyboardHandler {
public void registerKeyboardMapping(PhaseEvent phaseEvent) {
if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExtendedRenderKitService extRenderKitService =
Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
ListchildComponents = facesContext.getViewRoot().getChildren();
//First child component in an ADF Faces page - and the only child - is af:document
//Thus no need to parse the child components and check for their component family
//type
String id = ((UIComponent)childComponents.get(0)).getClientId(facesContext);
StringBuffer script = new StringBuffer();
script.append("window.registerKeyBoardHandler('keyboardToServerNotify','" + id + "')");
extRenderKitService.addScript(facesContext, script.toString());
}
}
public void handleKeyboardEvent(ClientEvent clientEvent) {
String keyCode = (String)clientEvent.getParameters().get("keycode");
// The alt+keyboard combination opens the relating ADF UI Shell tab if open
if (keyCode.equalsIgnoreCase("alt 1") || keyCode.equalsIgnoreCase("alt 2") || keyCode.equalsIgnoreCase("alt 3") ||
keyCode.equalsIgnoreCase("alt 4") || keyCode.equalsIgnoreCase("alt 5") || keyCode.equalsIgnoreCase("alt 6") ||
keyCode.equalsIgnoreCase("alt 7") || keyCode.equalsIgnoreCase("alt 8") || keyCode.equalsIgnoreCase("alt 9")) {
String keyIndexStr = keyCode.substring(keyCode.length() - 1, keyCode.length());
int keyIndex = Integer.parseInt(keyIndexStr);
TabContext.getCurrentInstance().setSelectedTabIndex(keyIndex - 1);
}
}
}
ADF UI Shell page
Note:xmlns:h="http://java.sun.com/jsf/html" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
a) The beforePhase property in the view tag
b) The loading of the JavaScript via the resource tag
c) The serverlistener that calls the bean methods
How This Works
1) Before the page is rendered, JavaScript is added to call the registerKeyBoardHandler method in the attached JavaScript library when the page is rendered
2) The JavaScript method registers (but does not invoke) for the defined keys a server side event
3) On the page rendering, if the user clicks one of the keys, the interaction of the JavaScript server side event *and* the serverListener in the page calls the bean handleKeyboardEvent method
4) Finally the method calls the ADF UI Shell TabContext class to switch tabs based on the hotkey number
Caveat
Frank notes some minor cross browser compatibility issues and certain hotkey combinations not working. Rather than highlighting the specific problems in this release, as this solution is reliant on JavaScript the ever unreliable-pain-in-the-butt-that-it-is-across-different-browser-versions, readers are highly recommended to do their own cross-browser testing.
Read the original blog entry...
Published November 3, 2010 Reads 354
Copyright © 2010 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Chris Muir
Chris Muir, an Oracle ACE Director, senior developer and trainer, and frequent blogger at http://one-size-doesnt-fit-all.blogspot.com, has been hacking away as an Oracle consultant with Australia's SAGE Computing Services for too many years. Taking a pragmatic approach to all things Oracle, Chris has more recently earned battle scars with JDeveloper, Apex, OID and web services, and has some very old war-wounds from a dark and dim past with Forms, Reports and even Designer 100% generation. He is a frequent presenter and contributor to the local Australian Oracle User Group scene, as well as a contributor to international user group magazines such as the IOUG and UKOUG.
- The Top 250 Players in the Cloud Computing Ecosystem
- Cloud Expo 2011 East To Attract 10,000 Delegates and 600 Exhibitors
- Dynamic Clustering for J2EE Cloud Environments
- Agile Testing Solution for Java
- Amazon Scales MySQL for Heavy Traffic
- Release of RESERVOIR Cloud Stack
- IBM Abandons Harmony for Java Unity with Oracle
- The Answer Is the Cloud – Now What’s the Question?
- How to Pick a Cloud Storage Gateway?
- Hadoop and Realtime Cloud Computing
- Rightsizing Your Risk Architecture
- Greenplum and Cloudera New BFFs
- The Top 250 Players in the Cloud Computing Ecosystem
- Cloud Expo 2011 East To Attract 10,000 Delegates and 600 Exhibitors
- Dynamic Clustering for J2EE Cloud Environments
- Agile Testing Solution for Java
- Amazon Scales MySQL for Heavy Traffic
- Release of RESERVOIR Cloud Stack
- IBM Abandons Harmony for Java Unity with Oracle
- The Answer Is the Cloud – Now What’s the Question?
- Red Hat Makes Step Toward Common Cloud Computing API with DMTF
- United Planet presents next generation portal software at the Gartner Portals, Content & Collaboration Summit 2010 in London
- How to Pick a Cloud Storage Gateway?
- Hadoop and Realtime Cloud Computing
- Web Services Using ColdFusion and Apache CXF
- The Top 250 Players in the Cloud Computing Ecosystem
- Eclipse "Pollinate" Project to Integrate with Apache Beehive
- Red Hat Named "Platinum Sponsor" of Virtualization Conference & Expo
- Apache's Tomcat 5.5 is First Release Ever to Use Eclipse JDT Java Compiler
- The Top 250 Players in the Cloud Computing Ecosystem
- Beehive Code Now Available in Apache
- An Introduction to Ant
- "Beehive" Now Officially an Open Source Project: Apache Beehive
- SourceLabs Completes Open Source Java Middleware Platform With Apache Tomcat
- Cloud Expo New York Call for Papers Now Open
- Apache Announces Jetspeed 2.0 Open Source Enterprise Portal



































