Disable Commands
In Apache OpenOffice, there may be situations where functions should be disabled to prevent users from changing or destroying documents inadvertently. Apache OpenOffice maintains a list of disabled commands that can be maintained by users and developers through the configuration API.
A command request can be created by any object, but in most cases, user interface objects create these requests. Consider, for instance, a toolbox where different functions acting on the office component are presented as buttons. Once a button is clicked, the desired functionality should be executed. If the code assigned to the button is provided with a suitable command URL, the dispatch framework can handle the user action by creating the request and finding a component that can handle it.
The dispatch framework works with the design pattern chain of responsibility: everything a component needs to know if it wants to execute a request is the last link in a chain of objects capable of executing requests. If this object gets the request, it checks whether it can handle it or otherwise passes it to the next chain member until the request is executed or the end of the chain is reached. The disable commands implementation is the first chain member and can therefore work as a wall for all disabled commands. They are not be sent to the next chain member, and disappear.
The illustration below shows how the disable commands feature affects the normal command application flow.
Since the disable commands implementation is the first part in the dispatch chain, there is no way to circumvent it. The disabled command must be removed from the list, otherwise it remains disabled. |
Configuration
The disable commands feature uses the configuration branch org.openoffice.Office.Commands to read which commands should be disabled. The following schema applies:
<?xml version='1.0' encoding='UTF-8'?>
<oor:component-schema oor:name="Commands"
oor:package="org.openoffice.Office"
xml:lang="en-US"
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<templates>
<group oor:name="CommandType">
<prop oor:name="Command" oor:type="xs:string"/>
</group>
</templates>
<component>
<group oor:name="Execute">
<set oor:name="Disabled" oor:node-type="CommandType"/>
</group>
</component>
</oor:component-schema>
The configuration schema for disabled commands is very simple. The org.openoffice.Office.Commands branch has a group called Execute
. This group has only one set called Disabled
. The Disabled
set supports nodes of the type CommandType
. The following table describes the supported properties of CommandType
.
Properties of the CommandType group
| |
---|---|
oor:component-data
|
string. It must be unique inside the Disabled set, but has no additional meaning for the implementation of the disable commands feature. Use a consecutive numbering scheme; even numbers are allowed.
|
Command
|
string. This is the command name with the preceding protocol. That means the command URL .uno:Open (which shows the File – Open dialog) must be written as Open .
The valid commands can be found in the document Index of Command Names in the Documentation section of the framework project on the Apache OpenOffice web page. The Apache OpenOffice SDK also includes the latest list of command names. Additional information regarding Command names is available in: OpenOffice.org 3.x Commands |
The example below shows a configuration file that disables the commands for File – Open, Edit – Select All, Help – About Apache OpenOffice and File – Exit.
<?xml version="1.0" encoding="UTF-8" ?>
<oor:component-data oor:name="Commands"
oor:package="org.openoffice.Office"
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node oor:name="Execute">
<node oor:name="Disabled">
<node oor:name="com.mycompany.a-chosen-unique-name.m1" oor:op="replace">
<prop oor:name="Command">
<value>Open</value>
</prop>
</node>
<node oor:name="com.mycompany.a-chosen-unique-name.m2" oor:op="replace">
<prop oor:name="Command">
<value>SelectAll</value>
</prop>
</node>
<node oor:name="com.mycompany.a-chosen-unique-name.m3" oor:op="replace">
<prop oor:name="Command">
<value>About</value>
</prop>
</node>
<node oor:name="com.mycompany.a-chosen-unique-name.m4" oor:op="replace">
<prop oor:name="Command">
<value>Quit</value>
</prop>
</node>
</node>
</node>
</oor:component-data>
A few lines on the node name 'com.mycompany.a-chosen-unique-name.m1' in the xml example above.
The node name is chosen in order to be unique in the 'Disable' data set, and is given as a suggestion.
You can use whatever name you like, it has no additional meaning for the implementation of the disable commands feature.
A good idea would be to use a consecutive numbering at the name end, the name must be unique.
Disabling Commands at Runtime
The following code example first removes all commands that were defined in the user layer of the configuration branch org.openoffice.Office.Commands
as having a defined starting point. Then it checks if it can get dispatch objects for some pre-defined commands.Then the example disables these commands and tries to get dispatch objects for them again. At the end, the code removes the disabled commands again, otherwise Apache OpenOffice would not be fully usable any longer.
import com.sun.star.bridge.XUnoUrlResolver;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.beans.XPropertySet;
import com.sun.star.beans.PropertyValue;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.util.XURLTransformer;
import com.sun.star.frame.XDesktop;
import com.sun.star.beans.UnknownPropertyException;
/*
* Provides example code how to enable/disable
* commands.
*/
public class DisableCommandsTest extends java.lang.Object {
/*
* A list of command names
*/
final static private String[] aCommandURLTestSet =
{
"Open",
"About",
"SelectAll",
"Quit",
};
private static XComponentContext xRemoteContext = null;
private static XMultiComponentFactory xRemoteServiceManager = null;
private static XURLTransformer xTransformer = null;
private static XMultiServiceFactory xConfigProvider = null;
/*
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
// connect
XComponentContext xLocalContext =
com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager();
Object urlResolver = xLocalServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalContext);
XUnoUrlResolver xUnoUrlResolver = (XUnoUrlResolver) UnoRuntime.queryInterface(
XUnoUrlResolver.class, urlResolver );
Object initialObject = xUnoUrlResolver.resolve(
"uno:socket,host=localhost,port=2083;urp;StarOffice.ServiceManager");
XPropertySet xPropertySet = (XPropertySet)UnoRuntime.queryInterface(
XPropertySet.class, initialObject);
Object context = xPropertySet.getPropertyValue("DefaultContext");
xRemoteContext = (XComponentContext)UnoRuntime.queryInterface(
XComponentContext.class, context);
xRemoteServiceManager = xRemoteContext.getServiceManager();
Object transformer = xRemoteServiceManager.createInstanceWithContext(
"com.sun.star.util.URLTransformer", xRemoteContext);
xTransformer = (com.sun.star.util.XURLTransformer)UnoRuntime.queryInterface(
com.sun.star.util.XURLTransformer.class, transformer);
Object configProvider = xRemoteServiceManager.createInstanceWithContext(
"com.sun.star.configuration.ConfigurationProvider", xRemoteContext);
xConfigProvider = (com.sun.star.lang.XMultiServiceFactory)UnoRuntime.queryInterface(
com.sun.star.lang.XMultiServiceFactory.class, configProvider);
// First we need a defined starting point. So we have to remove
// all commands from the disabled set!
enableCommands();
// Check if the commands are usable
testCommands(false);
// Disable the commands
disableCommands();
// Now the commands should not be usable anymore
testCommands(true);
// Remove disable commands to make Office usable again
enableCommands();
}
catch (java.lang.Exception e){
e.printStackTrace();
}
finally {
System.exit(0);
}
}
/**
* Test the commands that we enabled/disabled
*/
private static void testCommands(boolean bDisabledCmds) throws com.sun.star.uno.Exception {
// We need the desktop to get access to the current frame
Object desktop = xRemoteServiceManager.createInstanceWithContext(
"com.sun.star.frame.Desktop", xRemoteContext );
com.sun.star.frame.XDesktop xDesktop = (com.sun.star.frame.XDesktop)UnoRuntime.queryInterface(
com.sun.star.frame.XDesktop.class, desktop);
com.sun.star.frame.XFrame xFrame = xDesktop.getCurrentFrame();
com.sun.star.frame.XDispatchProvider xDispatchProvider = null;
if (xFrame != null) {
// We have a frame. Now we need access to the dispatch provider.
xDispatchProvider = (com.sun.star.frame.XDispatchProvider)UnoRuntime.queryInterface(
com.sun.star.frame.XDispatchProvider.class, xFrame );
if (xDispatchProvider != null) {
// As we have the dispatch provider we can now check if we get a dispatch
// object or not.
for (int n = 0; n < aCommandURLTestSet.length; n++) {
// Prepare the URL
com.sun.star.util.URL[] aURL = new com.sun.star.util.URL[1];
aURL[0] = new com.sun.star.util.URL();
com.sun.star.frame.XDispatch xDispatch = null;
aURL[0].Complete = ".uno:" + aCommandURLTestSet[n];
xTransformer.parseSmart(aURL, ".uno:");
// Try to get a dispatch object for our URL
xDispatch = xDispatchProvider.queryDispatch(aURL[0], "", 0);
if (xDispatch != null) {
if (bDisabledCmds)
System.out.println("Something is wrong, I got dispatch object for "
+ aURL[0].Complete);
else
System.out.println("Ok, dispatch object for " + aURL[0].Complete);
}
else {
if (!bDisabledCmds)
System.out.println("Something is wrong, I cannot get dispatch object for "
+ aURL[0].Complete);
else
System.out.println("Ok, no dispatch object for " + aURL[0].Complete);
}
resetURL(aURL[0]);
}
}
else
System.out.println("Couldn't get XDispatchProvider from Frame!");
}
else
System.out.println("Couldn't get current Frame from Desktop!");
}
/**
* Ensure that there are no disabled commands in the user layer. The
* implementation removes all commands from the disabled set!
*/
private static void enableCommands() {
// Set the root path for our configuration access
com.sun.star.beans.PropertyValue[] lParams = new com.sun.star.beans.PropertyValue[1];
lParams[0] = new com.sun.star.beans.PropertyValue();
lParams[0].Name = "nodepath";
lParams[0].Value = "/org.openoffice.Office.Commands/Execute/Disabled";
try {
// Create configuration update access to have write access to the configuration
Object xAccess = xConfigProvider.createInstanceWithArguments(
"com.sun.star.configuration.ConfigurationUpdateAccess", lParams);
com.sun.star.container.XNameAccess xNameAccess = (com.sun.star.container.XNameAccess)
UnoRuntime.queryInterface(com.sun.star.container.XNameAccess.class, xAccess);
if (xNameAccess != null) {
// We need the XNameContainer interface to remove the nodes by name
com.sun.star.container.XNameContainer xNameContainer =
(com.sun.star.container.XNameContainer)
UnoRuntime.queryInterface(com.sun.star.container.XNameContainer.class, xAccess);
// Retrieves the names of all Disabled nodes
String[] aCommandsSeq = xNameAccess.getElementNames();
for (int n = 0; n < aCommandsSeq.length; n++) {
try {
// remove the node
xNameContainer.removeByName( aCommandsSeq[n]);
}
catch (com.sun.star.lang.WrappedTargetException e) {
}
catch (com.sun.star.container.NoSuchElementException e) {
}
}
}
// Commit our changes
com.sun.star.util.XChangesBatch xFlush =
(com.sun.star.util.XChangesBatch)UnoRuntime.queryInterface(
com.sun.star.util.XChangesBatch.class, xAccess);
xFlush.commitChanges();
}
catch (com.sun.star.uno.Exception e) {
System.out.println("Exception detected!");
System.out.println(e);
}
}
/**
* Disable all commands defined in the aCommandURLTestSet array
*/
private static void disableCommands() {
// Set the root path for our configuration access
com.sun.star.beans.PropertyValue[] lParams = new com.sun.star.beans.PropertyValue[1];
lParams[0] = new com.sun.star.beans.PropertyValue();
lParams[0].Name = "nodepath";
lParams[0].Value = "/org.openoffice.Office.Commands/Execute/Disabled";
try {
// Create configuration update access to have write access to the configuration
Object xAccess = xConfigProvider.createInstanceWithArguments(
"com.sun.star.configuration.ConfigurationUpdateAccess", lParams);
com.sun.star.lang.XSingleServiceFactory xSetElementFactory =
(com.sun.star.lang.XSingleServiceFactory)UnoRuntime.queryInterface(
com.sun.star.lang.XSingleServiceFactory.class, xAccess);
com.sun.star.container.XNameContainer xNameContainer =
(com.sun.star.container.XNameContainer)UnoRuntime.queryInterface(
com.sun.star.container.XNameContainer.class, xAccess );
if (xSetElementFactory != null && xNameContainer != null) {
Object[] aArgs = { };
for (int i = 0; i < aCommandURLTestSet.length; i++) {
// Create the nodes with the XSingleServiceFactory of the configuration
Object xNewElement = xSetElementFactory.createInstanceWithArguments( aArgs );
if (xNewElement != null) {
// We have a new node. To set the properties of the node we need
// the XPropertySet interface.
com.sun.star.beans.XPropertySet xPropertySet =
(com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface( com.sun.star.beans.XPropertySet.class,
xNewElement );
if (xPropertySet != null) {
// Create a unique node name.
String aCmdNodeName = "Command-";
aCmdNodeName += i;
// Insert the node into the Disabled set
xPropertySet.setPropertyValue("Command", aCommandURLTestSet[i]);
xNameContainer.insertByName(aCmdNodeName, xNewElement);
}
}
}
// Commit our changes
com.sun.star.util.XChangesBatch xFlush = (com.sun.star.util.XChangesBatch)
UnoRuntime.queryInterface(com.sun.star.util.XChangesBatch.class, xAccess);
xFlush.commitChanges();
}
}
catch (com.sun.star.uno.Exception e) {
System.out.println("Exception detected!");
System.out.println(e);
}
}
/**
* reset URL so it can be reused
*
* @param aURL
* the URL that should be reseted
*/
private static void resetURL(com.sun.star.util.URL aURL) {
aURL.Protocol = "";
aURL.User = "";
aURL.Password = "";
aURL.Server = "";
aURL.Port = 0;
aURL.Path = "";
aURL.Name = "";
aURL.Arguments = "";
aURL.Mark = "";
aURL.Main = "";
aURL.Complete = "";
}
}
Content on this page is licensed under the Public Documentation License (PDL). |