Swing text components don't have a context menu with cut/copy/paste/etc. I want to add one so it behaves more fluently and like a native app. I've written a menu for this and it works fine. I add it to each text box using:
someTextBox.setComponentPopupMenu(TextContextMenu.INSTANCE);
The thing is, adding this everywhere is annoying. Secondly, if I forget it for a text box somewhere, the application is inconsistent. Thirdly, I can't add it for text boxes where I don't control the creation code, like the ones from JOptionPane.showInputDialog
or JFileChooser
dialogs.
Is there any way to override the default context menu of JTextComponent
application-wide? I know this would be a form of spooky action at a distance but I'm okay with that. Comments on the menu itself are also welcome.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.JTextComponent;
public class TextContextMenu extends JPopupMenu implements ActionListener {
public static final TextContextMenu INSTANCE = new TextContextMenu();
private final JMenuItem itemCut;
private final JMenuItem itemCopy;
private final JMenuItem itemPaste;
private final JMenuItem itemDelete;
private final JMenuItem itemSelectAll;
private TextContextMenu() {
itemCut = newItem("Cut", 'T');
itemCopy = newItem("Copy", 'C');
itemPaste = newItem("Paste", 'P');
itemDelete = newItem("Delete", 'D');
addSeparator();
itemSelectAll = newItem("Select All", 'A');
}
private JMenuItem newItem(String text, char mnemonic) {
JMenuItem item = new JMenuItem(text, mnemonic);
item.addActionListener(this);
return add(item);
}
@Override
public void show(Component invoker, int x, int y) {
JTextComponent tc = (JTextComponent)invoker;
boolean changeable = tc.isEditable() && tc.isEnabled();
itemCut.setVisible(changeable);
itemPaste.setVisible(changeable);
itemDelete.setVisible(changeable);
super.show(invoker, x, y);
}
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent tc = (JTextComponent)getInvoker();
tc.requestFocus();
boolean haveSelection = tc.getSelectionStart() != tc.getSelectionEnd();
if (e.getSource() == itemCut) {
if (!haveSelection) tc.selectAll();
tc.cut();
} else if (e.getSource() == itemCopy) {
if (!haveSelection) tc.selectAll();
tc.copy();
} else if (e.getSource() == itemPaste) {
tc.paste();
} else if (e.getSource() == itemDelete) {
if (!haveSelection) tc.selectAll();
tc.replaceSelection("");
} else if (e.getSource() == itemSelectAll) {
tc.selectAll();
}
}
}