Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.shaman.rpg.editor.dialog; import java.awt.*; import java.awt.dnd.DropTarget; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.event.*; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import org.apache.commons.lang3.ArrayUtils; import org.netbeans.core.spi.multiview.CloseOperationState; import org.netbeans.core.spi.multiview.MultiViewElement; import org.netbeans.core.spi.multiview.MultiViewElementCallback; import org.netbeans.core.spi.multiview.MultiViewFactory; import org.openide.awt.UndoRedo; import org.openide.filesystems.FileChangeAdapter; import org.openide.filesystems.FileEvent; import org.openide.loaders.DataObject; import org.openide.util.EditableProperties; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; import org.shaman.rpg.editor.dialog.panels.*; import org.shaman.rpg.engine.dialog.model.*; //TODO: add localization of text (TextTypePanel and QuestionTypePanel) over Property Bundle @MultiViewElement.Registration(displayName = "#LBL_Dialog_VISUAL", iconBase = "org/shaman/rpg/editor/dialog/speech-bubble.png", mimeType = "text/rpg-dialog+xml", persistenceType = TopComponent.PERSISTENCE_NEVER, preferredID = "DialogVisual", position = 0) @Messages("LBL_Dialog_VISUAL=Visual") public final class DialogVisualElement extends JPanel implements MultiViewElement { private static final Logger LOG = Logger.getLogger(DialogVisualElement.class.getName()); private static final int GAP_Y = 2; private DialogDataObject obj; private JToolBar toolbar = new JToolBar(); private transient MultiViewElementCallback callback; private final UndoRedo.Manager undoRedo; private final JumpListener jumpListener; private final DropListener dropListener; private JComponent contentParent; private JPanel contentPanel; private List<JComponent> overlayComponents = new ArrayList<>(); private List<CommandPanel> commandPanels = new ArrayList<>(); private DialogType dialog; private boolean isInsideSetupVisuals = false; public DialogVisualElement(Lookup lkp) { obj = lkp.lookup(DialogDataObject.class); assert obj != null; undoRedo = new UndoRedo.Manager(); undoRedo.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { obj.setModified(true); } }); initComponents(); contentPanel = new JPanel() { @Override public void paint(Graphics g) { super.paint(g); for (JComponent c : overlayComponents) { c.setBounds(this.getBounds()); c.paint(g); } } }; contentPanel.setLayout(new VerticalFlowLayout(GAP_Y * 2)); contentPanel.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (!e.isConsumed()) { requestFocus(); callback.requestActive(); } } }); personsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { personsListSelectionEvent(); } }); removeButton.setEnabled(false); Action editNames = new EditListAction(); ListAction ls = new ListAction(personsList, editNames); personsList.getModel().addListDataListener(new ListDataListener() { @Override public void intervalAdded(ListDataEvent e) { updatePersons(); } @Override public void intervalRemoved(ListDataEvent e) { updatePersons(); } @Override public void contentsChanged(ListDataEvent e) { updatePersons(); } }); setupVisuals(); contentParent = new JPanel(); contentParent.setLayout(new BorderLayout()); // contentPanel.setBounds(contentPanel.getBounds()); // contentParent.setBounds(contentPanel.getBounds()); contentParent.add(contentPanel); scrollPane.setViewportView(contentParent); jumpListener = new JumpListener(this); dropListener = new DropListener(this); DropTarget dt = new DropTarget(contentParent, dropListener); contentParent.setDropTarget(dt); obj.getPrimaryFile().addFileChangeListener(new FileChangeAdapter() { @Override public void fileChanged(FileEvent fe) { refresh(); } }); obj.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName()) && callback != null) { if (obj.isModified()) { callback.updateTitle("<html><b>" + obj.getName() + "</b></html>"); } else { callback.updateTitle("<html>" + obj.getName() + "</html>"); } } } }); } private void refresh() { setupVisuals(); } void preSave() { EditableProperties editableProperties; try { editableProperties = obj.getResourceBundle(); } catch (IOException ex) { LOG.log(Level.WARNING, "unable to load properties file", ex); return; } for (CommandPanel p : commandPanels) { p.updateResourceBundle(editableProperties, true); } try { obj.saveResourceBundle(editableProperties); } catch (IOException ex) { LOG.log(Level.WARNING, "unable to save properties file", ex); } } public String getPropertyFilePrefix() { return obj.getPrimaryFile().getName(); } private void setupVisuals() { isInsideSetupVisuals = true; LOG.info("setup visuals"); contentPanel.removeAll(); commandPanels.clear(); //load dialog dialog = obj.load(); if (dialog == null) { contentPanel.add(new JLabel("unable to load the dialog")); isInsideSetupVisuals = false; return; } EditableProperties editableProperties = null; try { editableProperties = obj.getResourceBundle(); } catch (IOException ex) { LOG.log(Level.WARNING, "unable to load properties file", ex); } //set header nameTextField.getDocument().removeUndoableEditListener(undoRedo); nameTextField.setText(dialog.getName()); nameTextField.getDocument().addUndoableEditListener(undoRedo); String[] persons = dialog.getPersonList(); @SuppressWarnings("unchecked") DefaultListModel<String> listModel = (DefaultListModel<String>) personsList.getModel(); listModel.clear(); listModel.ensureCapacity(persons.length); for (String p : persons) { listModel.addElement(p); } personsList.clearSelection(); //set commands for (Command c : dialog.getCommands()) { CommandPanel p = null; if (c instanceof TextType) { p = new TextTypePanel(); } else if (c instanceof StopType) { p = new StopTypePanel(); } else if (c instanceof SetvarType) { p = new SetVarTypePanel(); } else if (c instanceof AddvarType) { p = new AddVarTypePanel(); } else if (c instanceof IfType) { p = new IfTypePanel(); } else if (c instanceof LabelType) { p = new LabelTypePanel(); } else if (c instanceof GotoType) { p = new GotoTypePanel(); } else if (c instanceof QuestionType) { p = new QuestionTypePanel(); } else { LOG.info("unknown command: " + c); continue; } p.setVisualElement(this); p.setDialog(dialog); p.setCommand(c); if (editableProperties != null) { p.updateResourceBundle(editableProperties, false); } p.setUndoRedo(undoRedo); contentPanel.add(p); commandPanels.add(p); } repaint(); recursiveValidate(contentPanel); repaint(); recursiveValidate(contentPanel); EventQueue.invokeLater(new Runnable() { @Override public void run() { recursiveValidate(contentPanel); contentPanel.repaint(); } }); isInsideSetupVisuals = false; } private void recursiveValidate(Component p) { if (p instanceof Container) { for (Component c : ((Container) p).getComponents()) { recursiveValidate(c); } } p.invalidate(); p.validate(); } public void deleteCommand(CommandPanel toDelete) { int panelIndex = ArrayUtils.indexOf(contentPanel.getComponents(), toDelete); int commandIndex = dialog.getCommands().indexOf(toDelete.getCommand()); if (panelIndex < 0 || commandIndex < 0) { return; } contentPanel.remove(panelIndex); dialog.getCommands().remove(commandIndex); commandPanels.remove(panelIndex); contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); undoRedo.undoableEditHappened(new UndoableEditEvent(dialog, new DeleteCommandUndoableEdit(commandIndex, toDelete.getCommand(), panelIndex, toDelete))); LOG.info("delete " + toDelete); } public JComponent getContentPanel() { return contentPanel; } public List<JComponent> getOverlayComponents() { return overlayComponents; } public List<? extends CommandPanel> getCommandPanels() { return commandPanels; } public Collection<DropLocation> collectDropLocations() { ArrayList<DropLocation> locations = new ArrayList<>(); for (int i = 0; i < commandPanels.size(); ++i) { CommandPanel c = commandPanels.get(i); locations.add(new DropLocationImpl(c.getY() - GAP_Y, i)); locations.addAll(c.getDropLocations()); } if (commandPanels.isEmpty()) { locations.add(new DropLocationImpl(0, -1)); } else { Component c = commandPanels.get(commandPanels.size() - 1); locations.add(new DropLocationImpl(c.getY() + c.getHeight() + GAP_Y, -1)); } return locations; } public Collection<JumpLocation> collectJumpLocations() { ArrayList<JumpLocation> locations = new ArrayList<>(); for (CommandPanel c : commandPanels) { locations.addAll(c.getJumpLocations()); } return locations; } private void updateDialogPersons() { for (CommandPanel p : commandPanels) { p.setDialog(dialog); } } private void updatePersons() { if (isInsideSetupVisuals) { return; } //Extract persons @SuppressWarnings("unchecked") final DefaultListModel<String> listModel = (DefaultListModel<String>) personsList.getModel(); final String[] newPersons = new String[listModel.size()]; listModel.copyInto(newPersons); LOG.info("settings persons to " + Arrays.toString(newPersons)); final String[] oldPersons = dialog.getPersonList(); //send to dialog dialog.setPersonList(newPersons); updateDialogPersons(); // undo/redo undoRedo.undoableEditHappened(new UndoableEditEvent(dialog, new AbstractUndoableEdit() { @Override public void undo() throws CannotUndoException { super.undo(); isInsideSetupVisuals = true; listModel.clear(); listModel.ensureCapacity(oldPersons.length); for (String s : oldPersons) { listModel.addElement(s); } LOG.info("settings persons to " + Arrays.toString(oldPersons)); dialog.setPersonList(oldPersons); updateDialogPersons(); isInsideSetupVisuals = false; } @Override public void redo() throws CannotRedoException { super.redo(); isInsideSetupVisuals = true; listModel.clear(); listModel.ensureCapacity(newPersons.length); for (String s : newPersons) { listModel.addElement(s); } LOG.info("settings persons to " + Arrays.toString(newPersons)); dialog.setPersonList(newPersons); updateDialogPersons(); isInsideSetupVisuals = false; } })); } @Override public String getName() { return "DialogVisualElement"; } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { scrollPane = new javax.swing.JScrollPane(); jLabel1 = new javax.swing.JLabel(); nameTextField = new javax.swing.JTextField(); jLabel2 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); personsList = new javax.swing.JList(); addButton = new javax.swing.JButton(); removeButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle .getMessage(DialogVisualElement.class, "DialogVisualElement.jLabel1.text")); // NOI18N nameTextField.setText(org.openide.util.NbBundle.getMessage(DialogVisualElement.class, "DialogVisualElement.nameTextField.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle .getMessage(DialogVisualElement.class, "DialogVisualElement.jLabel2.text")); // NOI18N personsList.setModel(new DefaultListModel()); personsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); personsList.setToolTipText(org.openide.util.NbBundle.getMessage(DialogVisualElement.class, "DialogVisualElement.personsList.toolTipText")); // NOI18N personsList.setLayoutOrientation(javax.swing.JList.VERTICAL_WRAP); personsList.setVisibleRowCount(-1); jScrollPane1.setViewportView(personsList); org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle .getMessage(DialogVisualElement.class, "DialogVisualElement.addButton.text")); // NOI18N addButton.setToolTipText(org.openide.util.NbBundle.getMessage(DialogVisualElement.class, "DialogVisualElement.addButton.toolTipText")); // NOI18N addButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addButtonEvent(evt); } }); org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle .getMessage(DialogVisualElement.class, "DialogVisualElement.removeButton.text")); // NOI18N removeButton.setToolTipText(org.openide.util.NbBundle.getMessage(DialogVisualElement.class, "DialogVisualElement.removeButton.toolTipText")); // NOI18N removeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeButtonEvent(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(removeButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(addButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addComponent(scrollPane)); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel2)) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup().addComponent(addButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(removeButton))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 296, Short.MAX_VALUE))); }// </editor-fold>//GEN-END:initComponents private void addButtonEvent(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonEvent @SuppressWarnings("unchecked") DefaultListModel<String> listModel = (DefaultListModel<String>) personsList.getModel(); listModel.addElement("NoName"); }//GEN-LAST:event_addButtonEvent private void removeButtonEvent(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonEvent int index = personsList.getSelectedIndex(); if (index < 0) { return; //This should not happen } @SuppressWarnings("unchecked") DefaultListModel<String> listModel = (DefaultListModel<String>) personsList.getModel(); listModel.remove(index); }//GEN-LAST:event_removeButtonEvent private void personsListSelectionEvent() { int index = personsList.getSelectedIndex(); if (index < 0) { removeButton.setEnabled(false); } else { removeButton.setEnabled(true); } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addButton; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField nameTextField; private javax.swing.JList personsList; private javax.swing.JButton removeButton; private javax.swing.JScrollPane scrollPane; // End of variables declaration//GEN-END:variables @Override public JComponent getVisualRepresentation() { return this; } @Override public JComponent getToolbarRepresentation() { return toolbar; } @Override public Action[] getActions() { return new Action[0]; } @Override public Lookup getLookup() { return obj.getLookup(); } @Override public void componentOpened() { obj.visualElement = this; } @Override public void componentClosed() { obj.visualElement = null; } @Override public void componentShowing() { recursiveValidate(contentPanel); } @Override public void componentHidden() { } @Override public void componentActivated() { recursiveValidate(contentPanel); callback.updateTitle(obj.getName()); } @Override public void componentDeactivated() { } @Override public UndoRedo getUndoRedo() { return undoRedo; } @Override public void setMultiViewCallback(MultiViewElementCallback callback) { this.callback = callback; } @Override public CloseOperationState canCloseElement() { if (obj.isModified()) { return MultiViewFactory.createUnsafeCloseState("unsavedChanges", obj.saveAction, null); } else { return CloseOperationState.STATE_OK; } } private class AddCommandUndoableEdit extends AbstractUndoableEdit { private int dialogIndex; private Command c; private int panelIndex; private CommandPanel p; public AddCommandUndoableEdit(int dialogIndex, Command c, int panelIndex, CommandPanel p) { this.dialogIndex = dialogIndex; this.panelIndex = panelIndex; this.c = c; this.p = p; } @Override public void undo() throws CannotUndoException { super.undo(); contentPanel.remove(p); commandPanels.remove(p); dialog.getCommands().remove(dialogIndex); contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); } @Override public void redo() throws CannotRedoException { super.redo(); LOG.info("redo, index=" + panelIndex + " component count=" + contentPanel.getComponentCount()); contentPanel.add(p, panelIndex); commandPanels.add(panelIndex, p); dialog.getCommands().add(dialogIndex, c); contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); } } private class DeleteCommandUndoableEdit extends AbstractUndoableEdit { private int dialogIndex; private Command c; private int panelIndex; private CommandPanel p; public DeleteCommandUndoableEdit(int dialogIndex, Command c, int panelIndex, CommandPanel p) { this.dialogIndex = dialogIndex; this.panelIndex = panelIndex; this.c = c; this.p = p; } @Override public void undo() throws CannotUndoException { super.undo(); contentPanel.add(p, panelIndex); commandPanels.add(panelIndex, p); dialog.getCommands().add(dialogIndex, c); contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); } @Override public void redo() throws CannotRedoException { super.redo(); contentPanel.remove(p); commandPanels.remove(p); dialog.getCommands().remove(dialogIndex); contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); } } private class DropLocationImpl implements DropLocation { private final int y; private final int index; private Point pos; public DropLocationImpl(int y, int index) { this.y = y; this.index = index; pos = new Point(100, y); } @Override public Point getPosition() { return pos; } @Override public boolean canDrop(Object obj) { return (obj instanceof CommandPanel); } @Override public void drop(Object obj) { CommandPanel p = (CommandPanel) obj; if (commandPanels.contains(p)) { //D`n`D within the current panels //TODO } else { //Add a new command p.setVisualElement(DialogVisualElement.this); p.setDialog(dialog); Command c = p.createNewCommand(); p.setCommand(c); p.setUndoRedo(undoRedo); int dialogIndex; int panelIndex; if (index == -1) { dialogIndex = dialog.getCommands().size(); panelIndex = commandPanels.size(); contentPanel.add(p); commandPanels.add(p); dialog.getCommands().add(c); } else { CommandPanel next = commandPanels.get(index); panelIndex = index; dialogIndex = dialog.getCommands().indexOf(next.getCommand()); contentPanel.add(p, panelIndex); commandPanels.add(panelIndex, p); dialog.getCommands().add(dialogIndex, c); } contentPanel.invalidate(); contentPanel.validate(); contentPanel.repaint(); undoRedo.undoableEditHappened( new UndoableEditEvent(dialog, new AddCommandUndoableEdit(dialogIndex, c, panelIndex, p))); contentParent.requestFocus(); callback.requestActive(); } } } /* * Add an Action to a JList that can be invoked either by using * the keyboard or a mouse. * * By default the Enter will will be used to invoke the Action * from the keyboard although you can specify and KeyStroke you wish. * * A double click with the mouse will invoke the same Action. * * The Action can be reset at any time. */ private static class ListAction implements MouseListener { private static final KeyStroke ENTER = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); private JList list; private KeyStroke keyStroke; /* * Add an Action to the JList bound by the default KeyStroke */ public ListAction(JList list, Action action) { this(list, action, ENTER); } /* * Add an Action to the JList bound by the specified KeyStroke */ public ListAction(JList list, Action action, KeyStroke keyStroke) { this.list = list; this.keyStroke = keyStroke; // Add the KeyStroke to the InputMap InputMap im = list.getInputMap(); im.put(keyStroke, keyStroke); // Add the Action to the ActionMap setAction(action); // Handle mouse double click list.addMouseListener(this); } /* * Add the Action to the ActionMap */ public void setAction(Action action) { list.getActionMap().put(keyStroke, action); } // Implement MouseListener interface public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { Action action = list.getActionMap().get(keyStroke); if (action != null) { ActionEvent event = new ActionEvent(list, ActionEvent.ACTION_PERFORMED, ""); action.actionPerformed(event); } } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } } /* * A simple popup editor for a JList that allows you to change * the value in the selected row. * * The default implementation has a few limitations: * * a) the JList must be using the DefaultListModel * b) the data in the model is replaced with a String object * * If you which to use a different model or different data then you must * extend this class and: * * a) invoke the setModelClass(...) method to specify the ListModel you need * b) override the applyValueToModel(...) method to update the model */ private static class EditListAction extends AbstractAction { private JList list; private JPopupMenu editPopup; private JTextField editTextField; private Class<?> modelClass; public EditListAction() { setModelClass(DefaultListModel.class); } protected void setModelClass(Class modelClass) { this.modelClass = modelClass; } protected void applyValueToModel(String value, ListModel model, int row) { DefaultListModel dlm = (DefaultListModel) model; dlm.set(row, value); } /* * Display the popup editor when requested */ public void actionPerformed(ActionEvent e) { list = (JList) e.getSource(); ListModel model = list.getModel(); if (!modelClass.isAssignableFrom(model.getClass())) { return; } // Do a lazy creation of the popup editor if (editPopup == null) { createEditPopup(); } // Position the popup editor over top of the selected row int row = list.getSelectedIndex(); Rectangle r = list.getCellBounds(row, row); editPopup.setPreferredSize(new Dimension(r.width, r.height)); editPopup.show(list, r.x, r.y); // Prepare the text field for editing editTextField.setText(list.getSelectedValue().toString()); editTextField.selectAll(); editTextField.requestFocusInWindow(); } /* * Create the popup editor */ private void createEditPopup() { // Use a text field as the editor editTextField = new JTextField(); Border border = UIManager.getBorder("List.focusCellHighlightBorder"); editTextField.setBorder(border); // Add an Action to the text field to save the new value to the model editTextField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String value = editTextField.getText(); ListModel model = list.getModel(); int row = list.getSelectedIndex(); applyValueToModel(value, model, row); editPopup.setVisible(false); } }); // Add the editor to the popup editPopup = new JPopupMenu(); editPopup.setBorder(new EmptyBorder(0, 0, 0, 0)); editPopup.add(editTextField); } } }