This issue presents tips, techniques, and sample code for the following topics:
Undoing Text Edits
A new feature in Java Foundation Classes (JFC) Project Swing is the
ability to undo text edits. For example, suppose you have a
JTextArea that you use in some application. You might want to keep
track of user edits to the text area, and then possibly undo some
of them to change the content of the area back to some previous
state.
Consider the following example that uses undo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
public class undo {
static UndoManager undomanager;
static class UndoHandler implements UndoableEditListener {
public void undoableEditHappened(UndoableEditEvent e) {
if (undomanager != null) {
undomanager.addEdit(e.getEdit());
//System.out.println(e.getEdit());
}
}
}
public static void main(String args[]) {
// set up frames, panels, text areas
JFrame frame = new JFrame("Undo demo");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
final JTextArea textarea = new JTextArea(10, 40);
JPanel textpanel = new JPanel();
textpanel.add(new JScrollPane(textarea));
textarea.getDocument().addUndoableEditListener(
new UndoHandler());
// create buttons and set up listeners for them
JPanel buttonpanel = new JPanel();
JButton startbutton = new JButton("Start Edits");
JButton undobutton = new JButton("Undo Edits");
startbutton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
undomanager = new UndoManager();
undomanager.setLimit(1000);
textarea.requestFocus();
}
});
undobutton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (undomanager != null) {
undomanager.end();
undomanager.undo();
undomanager = null;
}
else {
Toolkit.getDefaultToolkit().beep();
}
textarea.requestFocus();
}
});
buttonpanel.add(startbutton);
buttonpanel.add(undobutton);
panel.add("North", textpanel);
panel.add("South", buttonpanel);
// make frame visible
frame.getContentPane().add("Center", panel);
frame.pack();
frame.setVisible(true);
}
}
The example sets up a JTextArea in the usual way, and then adds an
UndoableEditListener to the area's underlying Document object. This
has the effect of setting up a listener for all document edits. For
example, if a character is added to the text area, this constitutes
an edit, and the listener is notified.
An object of the UndoManager class is used to collect edits. This
object is set up when the Start Edits button is selected, and then
edits are accumulated. An edit limit of 1000 is set, meaning that
at most 1000 edits are accumulated in the UndoManager object. If
you uncomment the "System.out.println" statement in the example,
you can look at a description of each edit as it comes in.
When Undo Edits is selected, all of the accumulated edits are
undone. For example, suppose that you enter the letters "abc" into
the text area, then select Start Edits, then add, delete, cut,
copy, and paste text at will, and then select Undo Edits. This
sequence puts you back where you started, with only "abc" in
the text area. It is also possible to redo undone edits using the
"redo" method of UndoManager.
You can use undo/redo in other areas besides text. The UndoableEdit
interface and the AbstractUndoableEdit class provide a framework
for undo support, and can be applied in a variety of contexts.
Adding Security Features to Applications
JavaTM security has many aspects to it, and in this tip, we
illustrate one simple technique for adding security features to
applications. This technique demonstrates how permissions in a
central policy file can be used to enable application features.
Note that this tip assumes the standard Java 2 default security
setup, which may have been modified in your local environment.
The first thing to look at is a dummy application:
import java.security.*;
import local.*;
public class perm {
public static void main(String args[]) {
MyPermission myp = new MyPermission("perm1");
try {
AccessController.checkPermission(myp);
System.out.println("Permission granted");
}
catch (AccessControlException e) {
System.out.println("Permission denied");
}
}
}
MyPermission is a class, and "myp" an object of that class. The myp
object represents a permission, that is, something that the
application is allowed to do. This class resides in a package called
"local" somewhere on your local system. The class itself looks like
this:
package local;
import java.security.*;
public class MyPermission extends BasicPermission {
public MyPermission(String s) {super(s);}
public MyPermission(String s, String t) {super(s, t);}
}
The class simply defines a couple of constructors, that pass through
their arguments to the superclass, java.security.BasicPermission.
So there is an object of a local permission type, representing some
local policy. AccessController.checkPermission is called with this
object as its argument, and it throws an AccessControlException if
access is not granted. By default this application will print
"Permission denied", that is, the permission "perm1" for the
permission class "MyPermission" is denied.
But how does checkPermission know whether a permission should be
allowed or denied? In the default security setup, permissions are
declared in the file:
jre/lib/security/java.policy
under the installation root, and the "master security properties
file" is:
jre/lib/security/java.security
If you add a line to java.policy just after "grant {", like this:
grant {
permission local.MyPermission "perm1";
then you've enabled this permission locally.
But it's more complicated than simply editing this file. You might
not have the right to edit a central policy file on your local
system. So the security properties file allows an administrator to
specify which policy files are checked, with the default being:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
In other words, the central file is checked, along with a file you
have control over in your home directory. If you want to run
the above example without editing jre/lib/security/java.policy,
you can instead create a file, ".java.policy", in your home
directory. Here is the content of the local .java.policy file:
grant {
permission local.MyPermission "perm1";
};
This feature does not advance the enforcement of centralized
policies. So an administrator may disable the line in the
java.security file that allows for checking of local policy files.
Another aspect of specifying policy files is the default feature
that allows specification of a policy file on the command line:
java -Djava.security.policy=pathname
The line in the java.security file that reads:
policy.allowSystemProperty=true
can be toggled to "false" to disallow this type of override.
The Java Developer ConnectionSM Tech
Tips are written by Glen McCluskey.
|