I built a treeviewer for a specific project, but now I need to select a specific item/node in this treeviewer.
To build the treeviewer, I did this:
viewer = new TreeViewer(composite);
viewer.getTree().setLayoutData(gridData);
viewer.setContentProvider(new FileTreeContentProvider());
viewer.setLabelProvider(new FileTreeLabelProvider());
viewer.setInput(ResourcesPlugin.getWorkspace().getRoot().getProject(folderName.getText()));
viewer.expandAll();
Until here, everything is ok, but now, I don't know how to use listeners to do something when I select a specific item in my tree. Any idea? Thanks.
Edit: I got it!
viewer.addSelectionChangedListener(
new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event) {
if(event.getSelection() instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
Object o = selection.getFirstElement();
if (o instanceof IFile){
IFile file = (IFile)o;
}else {
//what ?
}
}
}
}
);
This is an excellent first step but there is even a better way which is more in the heart and soul of Eclipse.
Your code is listening to local changes but you want to make your code extendable so that other plugins in Eclipse are also notified when someone selects something in your viewer.
Eclipse 4 API
For this to happen you inject ESelectionService into your part and then forward the selection to the workbench by using the listener you already provided.
#Inject
private ESelectionService selectionService;
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
// set the selection to the service
selectionService.setSelection(
selection.size() == 1 ? selection.getFirstElement() : selection.toArray());
Then, to catch your own selection:
#Inject
void setSelection(#Optional #Named(IServiceConstants.ACTIVE_SELECTION) IFile pFile) {
if (pFile == null) {
//what ?
} else {
// magic!
}
}
Eclipse 3 API
For this to happen you have to register your viewer with the selection framework. Add this in the createPartControl method of the part where you have added your viewer:
getSite().setSelectionProvider(viewer);
Then, to catch your own selection:
getSite().getPage().addPostSelectionListener(this); // Implement ISelectionListener
References: https://wiki.eclipse.org/E4/EAS/Selection
Related
I have a window built with scene builder with a menuBar.
In the menuBar there are a couple of Menuitems that only open other windows.
So I want to write only one function that can be used by each one of those menuItems, and open the appropriate window.
I tried to give an id for each menuItem, and with this function
public void openWindow(ActionEvent event){
System.out.println( event);
}
I can see that id (example : customer menuItem) ,
javafx.event.ActionEvent[source=MenuItem[id=customers, styleClass=[menu-item]]]
But I dont know how to get it to use it to open the customer window.
In order to get id from ActionEvent you should cast the source of it to MenuItem:
public void openWindow(ActionEvent event){
MenuItem source = (MenuItem) event.getSource();
System.out.println(source.getId());
}
note, that if you are not sure that the source of event is of type MenuItem you can check it like so:
if (event.getSource() instanceof MenuItem) {
MenuItem source = (MenuItem) event.getSource();
System.out.println(source.getId());
}
One option is to get the source of the event (the MenuItem) and retrieve some appropriate data from it (e.g. the id or the userData), as shown in other answers. This will work, but it feels a little fragile as you are relying on string binding and having to perform casts on the types all over the place.
I prefer in this situation just to define a separate method for handling each menu item. Obviously, you can still refactor common functionality into a separate method, in the usual way.
public class MyController {
#FXML
private void openCustomersWindow() {
openWindow("/path/to/customers.fxml");
}
#FXML
private void openOrdersWindow() {
openWindow("/path/to/orders.fxml");
}
// ...
private void openWindow(String resource) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
Scene scene = new Scene(loader.load());
Stage newWindow = new Stage();
newWindow.setScene(scene);
newWindow.show();
} catch (Exception exc) {
// handle errors....
}
}
}
and then just use onAction="#openCustomersWindow" for one menu item and onAction="#openOrdersWindow" for another, etc.
Clearly, there is a little repeated code here, but it's not bad (certainly no worse than the amount of repetition in the FXML). If you had enough MenuItems that this were problematic, you would probably want to consider defining them in Java code instead of FXML anyway.
If everything has an ID you can try this.
#FXML void openWindow(ActionEvent event){
try
{
MenuItem tempMenuItem = (MenuItem)event.getSource();
System.out.println(tempMenuItem.getId());
switch(tempMenuItem.getId())
{
case "yourFirstID":
//open your first window here
break;
case "yourSecondID":
//open your second window here
break;
}
}
catch (IOException ex)
{
//catch errors here
}
}
at first I checked the other topics about the IStructuredSelection here on StackOverflow but they doesn´t solve my problem.
So I have 2 Views. In both Views I have a TreeViewer and implemented getSite().setSelectionProvider(viewer);
In the MainView everything is working correctly, when I click on a TreeNode (NOTE: These TreeNode's are from a custom class, lets say myTreeNode) the PropertiesView gets updated and my popup menu with different handlers calls the correct function.
One of these functions create a new TreeItem in the other View, which should display some values in different columns. These values get updated every second. This part is also working correctly.
But now the problem occur. When I click on one of the TreeItem's, the PropertiesView does not get updated and the popup menu handler is also not working correctly. The IStructuredSelection strucSelection = (IStructuredSelection) selection; always returns null.
Here is my getAdapter method from my adapter for the PropertiesView:
#Override
public Object getAdapter(Object adaptableObject, Class adapterType)
{
if(adapterType == IPropertySource.class && adaptableObject instanceof UATreeNode)
return new UATreeNodeAdapter((UATreeNode) adaptableObject);
else if(adapterType == IPropertySource.class && adaptableObject instanceof TreeItem)
{
MainView.printOnOPCUAConsole(OPCUAConsoleMessageTypeEnum.NULL, "Instanceof TreeItem");
return new TreeItemAdapter((TreeItem) adaptableObject);
}
else if(adapterType == IPropertySheetPage.class)
{
if(propertyPage == null)
propertyPage = new PropertySheetPage();
return propertyPage;
}
return null;
}
And here is my Handler, which should be called, when the menu in the second view is opend and a command is executed:
#Override
public Object execute(ExecutionEvent event) throws ExecutionException
{
ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event).getSelectionService().getSelection();
if(selection instanceof IStructuredSelection)
{
IStructuredSelection strucSelection = (IStructuredSelection) selection;
if(strucSelection.getFirstElement() != null)
{
TreeItem treeItem = (TreeItem) strucSelection.getFirstElement();
UaSubscription uaSubscription = (UaSubscription) treeItem.getData("uaSubscription");
}
}
return null;
}
In both cases, the selection is null but I can see that something is selected, because otherwise I think the popup menu would not be displayed.
So my question now, does anybody know how to get the selection from my second View ? And what am I doing wrong?
Ok, I solved this problem with implementing my own elements and provide them via ContentProvider to the TreeViewer.
Then I added a new adaptableType(the new created class) for the adapter-extension in the plugin.xml and added the new Class to the adapter-factory.
I have spent almost three days trying to do a simple enable / disable of Actions in the netbeans plaform, something that I though was going to be simple, and should be a common feature is more complex than I thought.
At the begging I tried to see if there was an setEnable() method on the default actions generated and to my surprise there is not. Then I started looking into that and I found that most common method to do it was setting a conditionally enabled action (which depends on a Cookie class), So I figured out how to add a fake class to the Lookup so it gets enabled and disabled, I did it the following way. To test it out I added the following code to another action which should enable or disable the second one.
private final PlottingStarted plottingStarted = new PlottingStarted();
#Override
public void actionPerformed(ActionEvent e) {
// TODO implement action body
if (Lookup.getDefault().lookup(PlottingStarted.class) == null) {
ic.add(plottingStarted);
}else{
ic.remove(plottingStarted);
}
So PlottingStarted is a fake object I created which only purpose is being in the lookup to disable or enable the action.
For some reason it did not do anything at all an the Action was always disabled. I tried many things and finally I gave up.
Then I tried a different approach and was using AbstractActions which do have the setEnabled() ability.
To retrieve the action I based myself on one the Geertjan blogs and I created the following method
public Action findAction(String actionName) {
FileObject myActionsFolder = FileUtil.getConfigFile("Actions/RealTimeViewer");
if (myActionsFolder != null){
FileObject[] myActionsFolderKids = myActionsFolder.getChildren();
for (FileObject fileObject : myActionsFolderKids) {
//Probably want to make this more robust,
//but the point is that here we find a particular Action:
if (fileObject.getName().contains(actionName)) {
try {
DataObject dob = DataObject.find(fileObject);
InstanceCookie ic = dob.getLookup().lookup(InstanceCookie.class);
if (ic != null) {
Object instance = ic.instanceCreate();
if (instance instanceof Action) {
Action a = (Action) instance;
return a;
}
}
} catch (Exception e) {
ErrorManager.getDefault().notify(ErrorManager.WARNING, e);
return null;
}
}
}
}
return null;
}
This method worked perfectly and I was able to retrieve the action and call its setEnabled() method. Unfortunately no matter why I did the Action was always enabled.
Reading some literature I found that I should add the following to the registration of the action "lazy = false" and finally I was able to enable and disable the Action... But off course the default registration is lost and I have no Icons and Names.
Now I decided to post again because I cannot believe that it need to be that complex, there must be a way to do it easier. The only thing I need is to have a PLAY / STOP functionality, when PLAY is enabled STOP is disabled and vice-versa.
I have not done this myself but it seems to be covered in Chapter 5.1.2.1 "Complex Enablement" of the book "Netbeans Platform for Beginners". https://leanpub.com/nbp4beginners
The book is not free but the corresponding code sample is available on
github. https://github.com/walternyland/nbp4beginners/tree/master/chapters/ch05/5.1.2.1 He extends AbstractAction overrides the resultChanged method and uses super.setEnabled().
#ActionID(id = "org.carsales.evaluator.EvaluateCarAction1", category = "Car")
#ActionRegistration(displayName = "not-used", lazy = false)
public class EvaluateCarAction extends AbstractAction
implements ContextAwareAction, LookupListener {
// ...
#Override
public void resultChanged(LookupEvent le) {
//Optionally, check if the property is set to the value you're interested in
//prior to enabling the Action.
super.setEnabled(result.allInstances().size() > 0);
}
Thanks to everybody for your responses. I finally got it to work by extending AbstractAction, it seems that even if you register "lazy = false" some of the registration is still being done by the platform and you just need some minor tweaking in the Action constructor. The final result was
#ActionID(
category = "RealTimeViewer",
id = "main.java.com.graph.actions.StopPlotting"
)
#ActionRegistration(
//iconBase = "main/java/com/graph/images/stop-plotting-24x24.png",
displayName = "#CTL_StopPlotting",
lazy = false
)
#ActionReference(path = "Toolbars/RealTimeViewer", position = 600)
#Messages("CTL_StopPlotting=Stop Plotting")
public final class StopPlotting extends AbstractAction{
private static final String ICON = "main/java/com/dacsys/cna/core/graph/images/stop-plotting-24x24.png";
public StopPlotting() {
putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON, false));
putValue(NAME, Bundle.CTL_StopPlotting());
this.setEnabled(false);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO implement action body
Action a = new ActionsHelper().findAction("StartPlotting");
if (a != null){
if (a != null){
if (a.isEnabled()){
a.setEnabled(false);
this.setEnabled(true);
}else{
a.setEnabled(true);
this.setEnabled(false);
}
}
}
}
}
all related
With JFace TableViewer, I want to select some entry(e.g select a file) by single-click, and do some other operations(e.g go into a directory) by double-click.
Noticing addSelectionChangedListener() and addDoubleClickListener() via a webpage: http://javafact.com/2010/08/07/example-tableviewer-events/ , I add SelectionChangedListener and DoubleClickListener for my TableViwer, and find out:
Either of the two listeners can work, but they can't work together - actually it's DoubleClickListener that can't work.
What's the problem? How I should implement listeners for single-click and double-clicks?
Any comments is appreciated.
About code:
I created a tableViewer, and want to show filesystem structure.
The expected behavior: User can double click a directory entry and tableViewer will show the structure of selected directory; user select a generic file by single-click. For other operations, warning message dialog will be shown.
The following is just code related with event handlers.
tableView.addSelectionChangedListener( new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection sel = (IStructuredSelection) tableView.getSelection();
File selFile = (File) sel.getFirstElement();
if(selFile != null){
if (selFile.isDirectory()) {
MessageDialog.openWarning(getShell(), "Warning", "You select a directory");
return;
}
System.out.println("Selected : "+ selFile.getAbsolutePath());
selectFileName = selFile.getAbsolutePath();
}
}
});
tableView.addDoubleClickListener( new IDoubleClickListener() {
#Override
public void doubleClick(DoubleClickEvent arg0) {
Object selected;
IStructuredSelection selection = (IStructuredSelection) tableView.getSelection();
if (selection.size() != 1) return;
selected = selection.getFirstElement();
File file = (File) selected;
if (file.isFile()) {
MessageDialog.openInformation(getShell(),"Warning", "You double-clicks a generic file");
return;
}
if (file.isDirectory()) {
System.out.println("Clicked direcotry: " + file.getAbsolutePath());
//applyNewDirectory(file);
}
}
});
Regards & Thanks from
Sunzen
(prolog: still working with JFace/SWT here, so this might be of interest to someone)
The problem is that the API allows you to do this, but it does not work (oh SWT...).
You cannot have both listeners on the TableView, as the SelectionChangedListener will always grab the click and consume the event.
The solution is to attach the SelectionChangedListener to the underlying table, and the DoubleClickListener to the TableViewer.
This way you can have both, e.g.:
table.addSelectionChangedListener(new ISelectionChangedListener(...));
tableViewer.addDoubleClickListener(new IDoubleClickListener(...));
In the eclipse toolbar when you mouse over the build button it comes up with a tooltip
saying which projects are currently selected to be build. Is there any way to get that information in my eclipse plugin? I thought about implementing something with ISelectionListener to keep tracking which projects are selected but there is no reason to do that if I can get them from the same place the build button is taking them.
Ok the answer to this question was to create my own ISelectionListener.
#Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
Object[] allselections= null;
selectedProjects.clear();
// TODO Auto-generated method stub
if(selection instanceof IStructuredSelection) {
allselections = ((IStructuredSelection)selection).toArray();
for(Object element: allselections){
if (element instanceof IResource) {
selectedProjects.add(((IResource)element).getProject());
} else if (element instanceof IAdaptable) {
IResource resource = null;
IAdaptable a = (IAdaptable)element;
resource = (IResource)a.getAdapter(IResource.class);
selectedProjects.add(resource.getProject());
}
}
}
};