A TreeCellEditor for Multiple Node Editing - java

Can someone show an example of a TreeCellEditor that can update multiple nodes on a single edit? From what I can tell, GetCellEditorValue() will only update a single node.
My editor currently takes in the selected Nodes, compares them and displays differing values as while displaying the other values that the nodes have in common.
My Constructor which initializes "myDevice".
public DeviceEditor(Collection<DefaultMutableTreeNode> nodes) throws NoSuchFieldException {
System.out.println("CREATING NEW EDITOR \n");
this.nodes = nodes;
ObjectMatcher matcher = new ObjectMatcher();
try {
myDevice = matcher.match(nodes, DefaultDevice.CREATE_MULTIVALUE_DEFAULTDEVICE(), new DefaultDevice());
//System.out.println("Device= " + myDevice.getAddress() + " " + myDevice.getHostName());
} catch (Exception e) {
System.out.println(e);
}
initComponents();
}
The methods of TreeCellEditor
#Override
public Component getTreeCellEditorComponent(JTree jtree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
// this.tree = jtree;
return this;
}
#Override
public Object getCellEditorValue() {
//This value is what is populated into the JTree
return this.myDevice;
}
#Override
public boolean isCellEditable(EventObject eo) {
//should be true only if it's a leaf.
return true;
}
#Override
public boolean shouldSelectCell(EventObject eo) {
//Don't Select
return false;
}
#Override
public boolean stopCellEditing() {
try {
System.out.println("\n Cell Editing Stopped");
//update myDevice
if (!this.addressField.getText().equals(DefaultDevice.MULTIVALUE)) {
myDevice.setAddress(this.addressField.getText());
}
myDevice.setDeviceType(this.deviceTypeField.getText());
myDevice.setLocation(this.locationField.getText());
myDevice.setSerialNumber(this.serialField.getText());
myDevice.setUser(this.userField.getText());
myDevice.setPassword(new String(this.passwordField.getPassword()));
myDevice.setVendor(this.vendorField.getText());
myDevice.setModel(this.modelField.getText());
myDevice.setOS(this.osField.getText());
myDevice.setDescription(this.descriptionField.getText());
myDevice.setVersion(this.versionField.getText());
myDevice.setDeviceType(this.deviceTypeField.getText());
myDevice.setDisplayHostName(this.hostNameCheckBox.isSelected());
myDevice.setDisplayIPV4Address(this.ipV4checkBox.isSelected());
myDevice.setDisplayIPV6Address(this.ipV6CheckBox.isSelected());
DeviceEditor.UPDATE_DEVICES(nodes, myDevice);
return true;
} catch (IPConverter.InvalidIPException ex) {
Exceptions.printStackTrace(ex);
return false;
}
}

Related

Java TableViewer - change cell image on selection

I have followed Vogella's tutorial on Table Viewer and using the StyledCellLabelProvider presented there. It creates a CHECKED or UNCHECKED icon on the third column
col = createTableViewerColumn(titles[3], bounds[3], 3);
col.setLabelProvider(new ColumnLabelProvider() {
#Override
public String getText(Object element) {
return null;
}
#Override
public Image getImage(Object element) {
if (((Person) element).isMarried()) {
return CHECKED;
} else {
return UNCHECKED;
}
}
});
col.setEditingSupport(new MarriedEditingSupport(viewer));
The column images get painted accordingly when the table is created but how can I change the icon when the user clicks a cell ? (I want to simulate a check box)
You can use an EditingSupport class based on CheckboxCellEditor for this:
class MarriedEditingSupport extends EditingSupport
{
private final CheckboxCellEditor _editor;
MarriedEditingSupport(TableViewer viewer)
{
super(viewer);
_editor = new CheckboxCellEditor(viewer.getTable());
}
#Override
protected CellEditor getCellEditor(Object element)
{
return _editor;
}
#Override
protected boolean canEdit(Object element)
{
return true;
}
#Override
protected Object getValue(Object element)
{
return Boolean.valueOf(((Person)element).isMarried());
}
#Override
protected void setValue(Object element, Object value)
{
((Person)element).setMarried(((Boolean)value).booleanValue());
getViewer().update(element, null);
}
}

Wrapper for JComboBox enabling search through Model Elements has error related to Caret

first question...
I've read the tutorial at http://www.orbital-computer.de/JComboBox/ and based on that I have made modifications to create a class that you pass an existing JComboBox in order to make it searchable.
I've managed to make the JComboBox modify the results but there seems to be something going on with the caret that I've broken.
Specifically I want any JComboBox passed to this class, to auto-select any existing items in the list that return true for my .indexOf statement.
Code:
public class SearchableJComboBox extends PlainDocument {
JComboBox comboBox;
ComboBoxModel model;
JTextComponent editor;
// flag to indicate if setSelectedItem has been called
// subsequent calls to remove/insertString should be ignored
boolean selecting=false;
boolean hidePopupOnFocusLoss;
boolean hitBackspace=false;
boolean hitBackspaceOnSelection;
public SearchableJComboBox(final JComboBox comboBox) {
this.comboBox = comboBox;
model = comboBox.getModel();
editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
editor.setDocument(this);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
editor.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (comboBox.isDisplayable()) comboBox.setPopupVisible(true);
hitBackspace=false;
}
});
// Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5");
// Highlight whole text when gaining focus
editor.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent e) {
// Workaround for Bug 5100422 - Hide Popup on focus loss
if (hidePopupOnFocusLoss) comboBox.setPopupVisible(false);
}
});
// Handle initially selected object
Object selected = comboBox.getSelectedItem();
if (selected!=null) setText(selected.toString());
}
void setPrototypeValue(Object value, JList list) {
comboBox.setPrototypeDisplayValue(value);
list.setPrototypeCellValue(value);
}
JList getListBox() {
JList listBox;
try {
Field field = JComponent.class.getDeclaredField("ui");
field.setAccessible(true);
BasicComboBoxUI ui = (BasicComboBoxUI) field.get(comboBox);
field = BasicComboBoxUI.class.getDeclaredField("listBox");
field.setAccessible(true);
listBox = (JList) field.get(ui);
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
} catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
return listBox;
}
public void remove(int offs, int len) throws BadLocationException {
// return immediately when selecting an item
if (selecting) return;
if (hitBackspace) {
// user hit backspace => move the selection backwards
// old item keeps being selected
if (offs>0) {
if (hitBackspaceOnSelection) offs--;
} else {
// User hit backspace with the cursor positioned on the start => beep
comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
}
} else {
super.remove(offs, len);
}
}
private void setText(String text) {
try {
super.remove(0, getLength());
super.insertString(0, text, null);
} catch (BadLocationException e) {
throw new RuntimeException(e.toString());
}
}
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
// return immediately when selecting an item
if (selecting) return;
// insert the string into the document
super.insertString(offs, str, a);
// lookup and select a matching item
Object item = lookupItem(getText(0, getLength()));
if (item != null)
setSelectedItem(item);
}
private void setSelectedItem(Object item) {
selecting = true;
model.setSelectedItem(item);
selecting = false;
}
private Object findStringWithin(String pattern) {
for(int i=0; i<model.getSize();i++)
{
if(model.getElementAt(i).toString().toLowerCase().indexOf(pattern.toLowerCase())!=-1)
return model.getElementAt(i);
}
return null;
}
private Object lookupItem(String pattern) {
return this.findStringWithin(pattern);
}
}
I checked your code and the website you reference.
No where do you include the line from the "curser" section:
editor.setCaretPosition(getLength());
This causes your caret to get stuck at the beginning, and essentially as you type you over-write the previous characters.
Give it a try ...

How to select all text in JTable cell when editing but not when typing?

The default behavior of a JTable is to append to the contents when you start typing, and to place the caret at the clicked location when clicking. I want the behavior of both these things to change, so the contents is replaced when I edit a cell, either by typing or by clicking and then typing. When I click a cell and then change the caret position, however, I want the contents to stay so I can change it.
I know how to select all when the cell becomes editing, by replacing the cell editor with one that selects all inside a SwingUtilities.invokeLater (see elsewhere), but that causes the typing behavior to break. When I do this and start typing in a cell, first the typed character is appended to the string, then it is selected (but the selection is invisible!) and when typing another character the contents gets replaced by that.
Is there a way to replace the contents immediately when typing in a highlighted (but not editing) cell, but select all when clicking a cell?
Here is the code I use for the CellEditor:
public class TextFieldCellEditor extends JTextField implements TableCellEditor
{
private CellEditorListener cellEditorListener = null;
private boolean isInteger = false;
private Object oldValue;
// Start editing
#Override
public Component getTableCellEditorComponent(JTable table, Object obj, boolean isSelected, int row, int column)
{
Color color2 = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
super.setBackground(color2 != null && (row & 1) == 1? color2 : table.getBackground());
super.setForeground(table.getForeground());
super.setBorder(DefaultLookup.getBorder(this, ui, "Table.focusCellHighlightBorder"));
super.setText(obj.toString());
isInteger = obj instanceof Integer;
if (isInteger)
{
super.setHorizontalAlignment(SwingConstants.RIGHT);
oldValue = obj;
}
// SwingUtilities.invokeLater(new Runnable()
// {
// public void run()
// {
// TextFieldCellEditor.this.selectAll();
// }
// });
return this;
}
// Retrieve e dited value
#Override
public Object getCellEditorValue()
{
if (isInteger)
{
// Try to convert to integer. If input is invalid, revert.
try
{
return new Integer(super.getText());
}
catch (NumberFormatException e)
{
return oldValue;
}
}
return super.getText();
}
#Override
public boolean isCellEditable(EventObject e)
{
return true;
}
#Override
public boolean shouldSelectCell(EventObject e)
{
return true;
}
#Override
public boolean stopCellEditing()
{
cellEditorListener.editingStopped(new ChangeEvent(this));
return true;
}
#Override
public void cancelCellEditing()
{
cellEditorListener.editingCanceled(new ChangeEvent(this));
}
#Override
public void addCellEditorListener(CellEditorListener celleditorlistener)
{
cellEditorListener = celleditorlistener;
}
#Override
public void removeCellEditorListener(CellEditorListener celleditorlistener)
{
if (cellEditorListener == cellEditorListener) cellEditorListener = null;
}
}
In your getTableCellEditorComponent() implementation, add the following:
if (isSelected) {
this.selectAll();
}
As an aside, why not extend AbstractCellEditor or DefaultCellEditor(JTextField textField)? See also How to Use Tables: Using Other Editors.
Addendum: See also Table Select All Renderer and Table Select All Editor.
The cleanest solution I could find for this case was to overwrite the JTable's editCellAt and inform the CellEditor of how the edit was triggered:
#Override
public boolean editCellAt(int row, int column, EventObject e) {
cellEditor.setKeyTriggered(e instanceof KeyEvent);
return super.editCellAt(row, column, e);
}
And here is the relevant CellEditor code:
public class MyCellEditor extends DefaultCellEditor {
private boolean keyTriggered;
public MyCellEditor() {
super(new JTextField());
final JTextField textField = (JTextField) getComponent();
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!keyTriggered) {
textField.selectAll();
}
}
});
}
});
}
public void setKeyTriggered(boolean keyTriggered) {
this.keyTriggered = keyTriggered;
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
final JTextField textField = (JTextField)
super.getTableCellEditorComponent(table, value, isSelected, row, column);
textField.selectAll();
return textField;
}
}

Jtree getTreeCellRendererComponent execute several times

i've got a problem with a custom TreeCellRenderer.
the overridable method getTreeCellRendererComponent is executed about 4 time when i click on a node. Does anybody have an idea about this?
Thanks by advance.
Simon
my code:
#Override
public Component getTreeCellRendererComponent(JTree tree, Object p_value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, p_value, selected, expanded,
leaf, row, hasFocus);
if (row != -1) {
DefaultMutableTreeNode aNode = (DefaultMutableTreeNode) p_value;
TreePath treePath;
treePath = tree.getPathForRow(row);
if (treePath == null) {
return this;
}
// int pathCount = treePath.getPathCount();
JLabel label = (JLabel) this;
if (aNode.getUserObject() instanceof MlCompteMail) {
traiteNomCompte((MlCompteMail) aNode.getUserObject(), label);
// JTreeFactory treeFact = new JTreeFactory();
// treeFact.refreshNode(treePath);
return this;
} else if (aNode.getUserObject() instanceof MlDossier) {
traiteNomDossier((MlDossier) aNode.getUserObject(), label, leaf);
// JTreeFactory treeFact = new JTreeFactory();
// treeFact.refreshNode(treePath);
return this;
}
}
return this;
}
/**
* #param value
* #param treePath
* #param label
* #param p_leaf
*/
private void traiteNomDossier(MlDossier p_dossier, JLabel label,
boolean p_leaf) {
String nomDossier = p_dossier.getNomDossier();
if (nomDossier.equals(EnDossierBase.BROUILLON.getLib())) {
label.setIcon(IconeTreeFactory.getBrouillon());
} else if (nomDossier.equals(EnDossierBase.CORBEILLE.getLib())) {
label.setIcon(IconeTreeFactory.getCorbeille());
} else if (nomDossier.equals(EnDossierBase.ENVOYES.getLib())) {
label.setIcon(IconeTreeFactory.getEnvoye());
} else if (nomDossier.equals(EnDossierBase.RECEPTION.getLib())) {
label.setIcon(IconeTreeFactory.getReception());
} else if (nomDossier.equals(EnDossierBase.SPAM.getLib())) {
label.setIcon(IconeTreeFactory.getSpam());
} else if (p_leaf) {
label.setIcon(IconeTreeFactory.getDossierFerme());
} else {
label.setIcon(IconeTreeFactory.getDossierOuvert());
}
int unreadMess = p_dossier.getUnreadMessCount();
if (unreadMess > 0) {
label.setText(nomDossier + " (" + unreadMess + ")");
label.setFont(Fontfactory.getTREE_FONT_GRAS());
} else {
label.setText(nomDossier);
label.setFont(Fontfactory.getTREE_FONT_PLAIN());
}
return;
}
// }
// }
/**
* #param value
* #param label
*/
private void traiteNomCompte(MlCompteMail p_compteMail, JLabel label) {
int unreadMess = p_compteMail.getUreadMessCount();
if (unreadMess > 0) {
label
.setText(p_compteMail.getNomCompte() + " (" + unreadMess
+ ")");
label.setFont(Fontfactory.getTREE_FONT_GRAS());
} else {
label.setText(p_compteMail.getNomCompte());
label.setFont(Fontfactory.getTREE_FONT_PLAIN());
}
label.setIcon(IconeTreeFactory.getDossierOuvert());
}
That's probably not a problem; the method is called whenever the cell needs to be painted. You don't have the luxury of controlling that.
So design the method to be very efficient and make sure it doesn't have side effects, and you will have no problem.
i found a way to speed up the decoration of my jtree,
the jtree use the method "toString()" to paint a node so i have override the method in my two kind of node, so, in my customTreeCellRenderer, i just call the toString method on my userObject and that work.
Thanks for your help.

Strange blinking of cell on selection with custom Cell Editor

I am new to working with JTables and having trouble with getting my custom JTable editor to work properly.
I have a number of custom panels with lists and buttons. To renderder them in a cell I am using a custom PanelCellRenderer that has various constructors for each type of the panel.
To make the buttons clickable I have created this simple PanelCellEditor that extends DefaultCellEditor. To access the data stored within cells at the time of editting I pass the reference to the PanelCellRenderer.
The problem I am having is that when I select the cell (by clicking at it), from displaying the list with the button, the cell selected becomes completely blank. When the cell gets deselected the list with data and the button reappear again. Any advice on this will be helpful. Thanks.
public class PanelCellEditor extends DefaultCellEditor {
private PanelCellRenderer pcr;
private Object value;
public PanelCellEditor(final PanelCellRenderer pcr) {
super(new JCheckBox());
this.pcr = pcr;
this.pcr.setOpaque(true);
if (pcr.firstPanel != null) {
pcr.firstPanel.Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//do something
fireEditingStopped();
}
});
pcr.firstPanel.List.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
String value = (String) ((javax.swing.JList) e.getSource()).getSelectedValue();
//do something
fireEditingStopped();
}
});
}
else if (pcr.secondPanel != null) {
pcr.secondPanel.Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//do something
fireEditingStopped();
}
});
pcr.secondPanel.List.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
String value = (String) ((javax.swing.JList) e.getSource()).getSelectedValue();
//do something
fireEditingStopped();
}
});
}
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
//// if I comment this whole bit ////
if (isSelected) {
pcr.setForeground(table.getSelectionForeground());
pcr.setBackground(table.getSelectionBackground());
} else {
pcr.setForeground(table.getForeground());
pcr.setBackground(table.getBackground());
}
if (pcr.firstPanel != null)
pcr.firstPanel.list.setListData((String[])value);
else if (pcr.secondPanel != null) {
pcr.secondPanel.list.setListData((String[])value);
}
//////// nothing changes /////////
this.value = value;
return pcr;
}
public Object getCellEditorValue() {
return value;
}
public boolean stopCellEditing() {
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
you could trace the JTable.getTableCellEditor into your objects.
Have you actually registered your editor with the value it should edit with the Jtable?

Categories