JFace TreeViewer expand or collapse on selection - java

I've implemented a selection listener for my treeviewer to expand or collapse a node on selection.
This impementation works fine for collapsing, but does not expand a node.
this.getTree().addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event event) {
TreeItem treeItem = (TreeItem) event.item;
if (treeItem.getItems().length > 0) {
if (MyTreeViewer.this.getExpandedState(treeItem)) {
MyTreeViewer.this.collapseToLevel(treeItem, MyTreeViewer.this.ALL_LEVELS);
} else {
MyTreeViewer.this.expandToLevel(treeItem, 1);
}
MyTreeViewer.this.refresh();
}
}
});
Do you have any suggestions how to fix this?

For a JFace TreeViewer you should use a ISelectionChangedListener or a IDoubleClickListener - do not use the underlying Tree listeners as they may not interact correctly with the viewer.
This is what I use for double click:
public class TreeDoubleClickListener implements IDoubleClickListener
{
#Override
public void doubleClick(final DoubleClickEvent event)
{
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
if (selection == null || selection.isEmpty())
return;
Object sel = selection.getFirstElement();
TreeViewer treeViewer = (TreeViewer)event.getViewer();
IContentProvider provider = treeViewer.getContentProvider();
if (provider instanceof ITreeContentProvider)
{
ITreeContentProvider treeProvider = (ITreeContentProvider)provider;
if (!treeProvider.hasChildren(sel))
return;
if (treeViewer.getExpandedState(sel))
treeViewer.collapseToLevel(sel, AbstractTreeViewer.ALL_LEVELS);
else
treeViewer.expandToLevel(sel, 1);
}
}
}
The key thing here is to use the selection as the argument to collapseToLevel / expandToLevel.
Just change to implement ISelectionChangedListener to work on selection.
Add the listener with TreeViewer addDoubleClickListener or addSelectionChangedListener

Related

Deselect a TableItem after clicking in an empty slot in the table

I have a table with many TableItems (Not a tableViewer), when I click on one of the table Items it get selected . The only way to deselect it is by selecting another TableItem. I want to implement a way to deselect The Table selection when The user click on the table Where there is no TableItems, or when ReSelecting the same TableItem.
table.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
if(e.item != ItemSelectioner ) {
ItemSelectioner = (TableItem)e.item;
// Blabla
}else {
ItemSelectioner = null;
table.deselectAll();
//blabla
}
}
});
As you can see, am using a selectionEvent which I think is the probleme, and using:
e.doit = false;
didn't work also.
Selection events are not generated for the empty parts of the table so you can't use a selection listener to do this.
You can use a mouse down listener and check if there is a table item at the mouse location:
table.addListener(SWT.MouseDown, event -> {
TableItem item = table.getItem(new Point(event.x, event.y));
if (item == null) { // No table item at the click location?
table.deselectAll();
}
});
To clear the selection the second time an item is clicked use something like this:
table.addListener(SWT.Selection, new Listener()
{
private int lastSelected = -1;
#Override
public void handleEvent(final Event event)
{
final int selectedIndex = table.getSelectionIndex();
if (selectedIndex < 0) {
lastSelected = -1;
return;
}
if (selectedIndex == lastSelected) {
table.deselect(selectedIndex);
lastSelected = -1;
}
else {
lastSelected = selectedIndex;
}
}
});

JFace tableviewer item delete cannot refresh

I'm a newer in SWT and JFace, recently, I used JFace tableviewer in my project. And I need to delete items by a delete button. But it doesn't work if i refresh the tableviewer after deleting it. I want to know the reason.My code shows below:
btnDeleteConstraint.addSelectionListener(
new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
ISelection selection = tableViewer.getSelection();
logger.debug("datatype selected");
if (selection != null || selection instanceof
IStructuredSelection) {
IStructuredSelection sel = (IStructuredSelection) selection;
Iterator iterator = sel.iterator();
while(iterator.hasNext()) {
Object obj = iterator.next();
tableViewer.remove(obj);
}
tableViewer.refresh();
}
}
});
And i use another method called update() to set input and refresh the table in the end:
public void update()
{
tableViewer.setInput(DataTypeFactory.
getInstance().getCastList(wizard.getSourceInfo().getDBType()));
tableViewer.refresh();
}
When you call refresh the table is updated from your 'content provider' - so when you delete things you must update the data that your content provider returns in its getElements method.

Custom JComboBox hiding JPopupMenu

I'm having a little headache with a situation. Maybe some of you have been through this before and can show me another way or even my error here.
I need to add a JTree inside a JComboBox and the code below works like a charm.
public class HierarchyComboBox extends JComboBox {
HierarchyTree ht = new HierarchyTree();
HierarchyComboBox box;
JPopupMenu popup;
MouseAdapter adapter = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if (arg0.getClickCount() == 1) {
removeAllItems();
addItem(ht.getSelectedLevel());
// ((JPopupMenu) comp).setVisible(false);
}
}
};
PopupMenuListener listener = new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
if (box == null) {
box = (HierarchyComboBox) e.getSource();
if (popup == null) {
final Object comp = box.getUI().getAccessibleChild(box, 0);
if (!(comp instanceof JPopupMenu))
return;
popup = (JPopupMenu) comp;
}
popup.removeAll();
ht.getTreePane().setBorder(null);
ht.getTreePane().setPreferredSize(new Dimension(box.getWidth(), 200));
MyTree tree = (MyTree)ht.getTreePane().getViewport().getComponent(0);
tree.addMouseListener(adapter);
popup.add(ht.getTreePane());
}
}
#Override
public void popupMenuCanceled(PopupMenuEvent arg0) { }
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) { }
};
public HierarchyComboBox() {
setEditable(true);
addPopupMenuListener(listener);
}
}
but I added this component to 2 different dialogs.
The first one I can click and the selection is added to the JComboBox
and the second, doing EXACTLY the same instantiation, and the same tests
The component has a different behaviour:
- The JPopupMenu disappears
- It doesn't add the selection to the combo
Any ideas here?
Thanks in advance..
As shown in Providing a Custom Renderer, "A combo box uses a renderer to display each item in its menu." You could render the tree in a custom ListCellRenderer. Alternatively,
Render the tree in an adjacent component in response to an ActionListener.
Use a hierarchical model, shown here.
I noticed that the JPopupMenu was loosing it's focus.
The solution was to add the component as the last component of the Panel.

JavaFX 2 TreeView - How to change default behavior of entering edit mode?

Inspired by the JavaFX tutorial on http://docs.oracle.com/javafx/2/ui_controls/tree-view.htm I am wondering how could I change the behaviour to enter a cell in edit mode. The behaviour I would like to get is
on one left mouse-click: just select the cell
on two left mouse-clicks: select cell and invoke some action
on right-mouse-click: enter cell in edit mode
I tried to install a mouse event handler on the TreeView/TreeCell but it seems that the event is already consumed by TreeCellBehavior.
In class TreeCellBehvior there is the following method:
private void simpleSelect(MouseEvent e) {
TreeView tv = getControl().getTreeView();
TreeItem treeItem = getControl().getTreeItem();
int index = getControl().getIndex();
MultipleSelectionModel sm = tv.getSelectionModel();
boolean isAlreadySelected = sm.isSelected(index);
tv.getSelectionModel().clearAndSelect(index);
// handle editing, which only occurs with the primary mouse button
if (e.getButton() == MouseButton.PRIMARY) {
if (e.getClickCount() == 1 && isAlreadySelected) {
tv.edit(treeItem);
} else if (e.getClickCount() == 1) {
// cancel editing
tv.edit(null);
} else if (e.getClickCount() == 2/* && ! getControl().isEditable()*/) {
if (treeItem.isLeaf()) {
// attempt to edit
tv.edit(treeItem);
} else {
// try to expand/collapse branch tree item
treeItem.setExpanded(! treeItem.isExpanded());
}
}
}
}
I am not sure if can replace the TreeCellBehavior with my own implementation. Though this method is private I am not sure if this would be the right way to go. Any idea?
I worked it out by myself. I disable the editable of TreeView by default. For each TreeItem there is a context menu allowing to change the items name. If context menu action is invoked the TreeView is set to editable and TreeView.edit() with the current TreeItem is invoked. Now startEdit() is called behind the scenes and edit mode is active.
However I have got some strange behavior after enter is pressed and commitEdit() is called. This method checks if the cell is still in edit mode (which it is and therefore returns true) causing an internal invocation of cancelEdit()?!?! As a workaround I introduced a commitModeProperty and check in cancelEdit() if it is set.. otherwise the new text value would never be set.
Here is my code:
public class FolderTreeCell extends TreeCell<FolderCellType> {
// workaround for a strange behaviour in commitEdit.. see initTextFieldListener()
private BooleanProperty commitModeProperty = new SimpleBooleanProperty(false);
public FolderTreeCell() {
assert Platform.isFxApplicationThread();
}
private ContextMenu createContextMenu() {
MenuItem menuItem = new MenuItem("Change folder name");
menuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent evt) {
getTreeView().setEditable(true);
getTreeView().edit(getTreeItem());
}
});
return new ContextMenu(menuItem);
}
private void initTextFieldListener() {
getItem().textFieldProperty().get().setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent evt) {
if (evt.getCode() == KeyCode.ENTER) {
commitEdit(getItem()); // TODO calls updateItem() when isEditing() is true causing invocation of cancelEdit() ?!?!
}
}
});
}
#Override
public void commitEdit(FolderCellType newFolderCellType) {
commitModeProperty.set(true);
super.commitEdit(newFolderCellType);
commitModeProperty.set(false);
}
#Override
public void startEdit() {
super.startEdit();
setGraphic(getItem().getEditBox());
if (getItem().textFieldProperty().get().getOnKeyReleased() == null) {
initTextFieldListener();
}
getItem().textFieldProperty().get().selectAll();
getItem().textFieldProperty().get().requestFocus();
}
#Override
public void cancelEdit() {
super.cancelEdit();
getTreeView().setEditable(false);
if (!commitModeProperty.getValue()) {
getItem().resetCurrentEntry();
}
setGraphic(getItem().getViewBox());
}
#Override
public void updateItem(FolderCellType item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
setGraphic(item.getEditBox());
} else {
setGraphic(item.getViewBox());
if (getContextMenu() == null) {
setContextMenu(createContextMenu());
}
}
}
getTreeView().setEditable(false);
}
}

Adding KeyStroke to JCheckBox

I want to add KeyStrokes to group of CheckBoxes ,so when user hits 1, keystroke will selected / deselected first JCheckBox.
I have made this part of code ,but its not working, can somebody point me into correct direction?
for (int i=1;i<11;i++)
{
boxy[i]=new JCheckBox();
boxy[i].getInputMap().put(KeyStroke.getKeyStroke((char) i),("key_"+i));
boxy[i].getActionMap().put(("key_"+i), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox)e.getSource();
checkBox.setSelected(!checkBox.isSelected());
}});
pnlOdpovede.add(boxy[i]);
}
The problem is that you registered the bindings with the checkBox' inputMap of type WHEN_FOCUSED: they will be effective only for that particular checkBox that is focused at the time of the keyPressed.
Assuming that you want to toggle the selected state independent of the focusOwner, an alternative is to register the keyBindings with the parent container of the checkBoxes and add some logic to find the component that's meant to have its selection state toggled:
// a custom action doing the toggle
public static class ToggleSelection extends AbstractAction {
public ToggleSelection(String id) {
putValue(ACTION_COMMAND_KEY, id);
}
#Override
public void actionPerformed(ActionEvent e) {
Container parent = (Container) e.getSource();
AbstractButton child = findButton(parent);
if (child != null) {
child.setSelected(!child.isSelected());
}
}
private AbstractButton findButton(Container parent) {
String childId = (String) getValue(ACTION_COMMAND_KEY);
for (int i = 0; i < parent.getComponentCount(); i++) {
Component child = parent.getComponent(i);
if (child instanceof AbstractButton && childId.equals(child.getName())) {
return (AbstractButton) child;
}
}
return null;
}
}
// register with the checkbox' parent
for (int i=1;i<11;i++) {
String id = "key_" + i;
boxy[i]=new JCheckBox();
boxy[i].setName(id);
pnlOdpovede.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke((char) i), id);
pnlOdpovede.getActionMap().put(id, new ToggleSelection(id));
pnlOdpovede.add(boxy[i]);
}
BTW: assuming your checkBoxes have Actions (which they should :-), the ToggleAction could trigger those Actions instead of toggling the selection manually. This approach is used in a recent thread

Categories