Bug 25274 - [Working Sets] Work Space includes unselected children packages
Summary: [Working Sets] Work Space includes unselected children packages
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 2.0.1   Edit
Hardware: PC Windows 2000
: P2 minor (vote)
Target Milestone: 2.1 RC1   Edit
Assignee: Dirk Baeumer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 28026 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-10-23 15:15 EDT by John Groppe CLA
Modified: 2003-02-20 12:58 EST (History)
4 users (show)

See Also:


Attachments
JavaElementAdapterFactory with support for IContainmentAdapter (5.21 KB, text/plain)
2003-01-17 11:11 EST, Knut Radloff CLA
no flags Details
JavaWorkbenchAdapter implementing IContainmentAdapter (3.78 KB, text/plain)
2003-01-17 11:13 EST, Knut Radloff CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description John Groppe CLA 2002-10-23 15:15:16 EDT
If a parent package is included in a working set, child packages are 
automatically included even if they are explicitly un-selected.

e.g. A working set is created.  In it I have selected com.foo to be a member, 
but I did not select child package com.foo.bar.  When I use the working set to 
filter against tasks.  Tasks related to com.foo.bar appear even thought they 
are explicitly not selected in the working set.

p.s. Searching the bug data base it appears there used to be a working set 
component, but I couldn't find it posting this bug. Hopefully it will get to 
the correct place.

Thanks, John Groppe
Comment 1 Knut Radloff CLA 2002-10-24 13:50:47 EDT
The problem is that Java working sets and resource working sets are not 
interchangeable. They should be.
Using a resource working set works in the Tasks view. Using a Java working set 
in the Navigator (or in the Tasks view) does not work.
Bug 14441 was reopened to address this issue. Closing bug 14441 since this one 
is more specific.
Here is the relevant discussion from bug 14441

------- Additional Comments From Shash Chatterjee 2002-05-22 15:14 -------

Hi!

I just tested this using the F1 build.  It is better in the sense that I can 
filter based on a working set, and only errors/warnings from that working set 
are being shown in the task view.  But if I edit the working set to uncheck one 
or more particular packages in the source hierarchy (those that have errors 
that I can neglect), the errors are still showing up in the Task view.

Shash


------- Additional Comments From Knut Radloff 2002-05-24 18:41 -------

The problem is a combination of the fact that the 
org.eclipse.ui.views.tasklist.TasksFilter is resource based and the way working 
set elements are collected in the Resource- and JavaWorkingSetPage.
Given a structure
A
 a
  A.java
 a.b
  AB.java

The TasksFilter assumes that if folder a is checked and included in a working 
set all of a's children should be displayed. This works with a resource working 
set because a is only checked if all its children are checked in the 
ResourceWorkingSetPage. Otherwise only the checked children are placed in the 
working set. I.e., if b below a is not checked a is grayed out and A.java is 
added instead of a.

This does not work with Java working sets because package a may be included in 
the working set but a.b may not. a is checked and a.b is not but the working 
set contains a instead of a/A.java.
There are two possible solutions:
1) Change TasksFilter.isEnclosed to test the path of a resource for equality 
with a working set element. This means that all leaf elements of folders have 
to be included in a working set. 
This would change the semantics of the ResourceWorkingSetPage since currently, 
checking a folder means the actual folder is placed in the working set vs. all 
its children. New children are automatically considered to be included in the 
working set.
It would also degrade performance since working sets would contain a 
potentially huge number of leaf elements vs. a single folder or project. 
Filtering in the resource navigator would be slower.

2) Change JavaWorkingSetPage to mimic the ResourceWorkingSetPage. Leave the UI 
the way it is but explicitly include children of packages in the working set 
instead of the packages themselves if not all package fragments are checked 
(e.g, a is but a.b is not). This would mimic the graying out of a in the 
ResourceWorkingSetPage.

There is another option which I don't think we can/should seriously consider. 
That would be to allow for a custom working set filter in the 
org.eclipse.ui.workingSet extension point.

I hacked the JavaWorkingSetPage to simply test if a checked element is a 
package fragment. This is a lesss optimal but quick version of solution 2). It 
would cause leaf elements to be included even if all packages are selected.

Moving to JDT UI for comment/fix.

See the changed JavaWorkingSetPage.findCheckedElements:

Object[] children= fTreeContentProvider.getChildren(parent);
for (int i= 0; i < children.length; i++) {
	if (fTree.getGrayed(children[i]))
		findCheckedElements(checkedResources, children[i]);
	else if (fTree.getChecked(children[i])) {
		// don't add package fragments directly
		if ((children[i] instanceof PackageFragment))
			findCheckedElements(checkedResources, children[i]);
		else
		        checkedResources.add(children[i]);
	}
}



------- Additional Comments From Knut Radloff 2002-05-24 18:42 -------

Shash, 
Please confirm that the scenario I describe above matches your scenario.
I.e., you deselect package a.b, keep package a selected and still see errors 
for a.b.


------- Additional Comments From Shash Chatterjee 2002-05-24 19:54 -------

Yes, I confirm this is exactly what is happening.

I have (with the project source directory being WEB-INF/src):
WEB-INF/
       src/
          com/
             jcorporate/
                       expresso/
                               X.java
                               core/
                                   Y.java
                                   security/
                                           Z.java
                                           strongencryption/
                                                           A.java
                                                           B.java
                                           weakencryption/
                                                         C.java
                                                         D.java
In this enviornment, because I didn't install the required JAR(s), 
strongencryption/*.java all have compilation errors.  So, I unchecked the
com.jcorporate.expresso.core.security.strongencryption.  But those errors
still show up in the task view, until I uncheck the following as well:

com.jcorporate.expresso.core.security
com.jcorporate.expresso.core
com.jcorporate.expresso
com.jcorporate
WEB-INF/src



------- Additional Comments From Erich Gamma 2002-05-25 17:12 -------

This problem is real so that we should tolerate a minor hack that get's us 
there. Should investigate for F1.


------- Additional Comments From Erich Gamma 2002-05-26 14:15 -------

Thinking of it again. Option 2) isn't an option. The main reason why we wanted 
to have support for Java specific working set is that you can define working 
sets with the Java semantics. This is already leveraged for Java specific 
searching. We do not want to loose this functionality.

The original idea for handling this problem was to leverage the 
IWorkbenchAdapter. Did you ever investigate more into this path? There were 
some issues but the path looked promising to me. 

This was Nick's latest proposal:
- The working set has the shape as proposed in 2, and contains IJavaElements, 
e.g.  { package fragment: java.lang }
- This is mapped to the corresponding resource using getAdapter
(IResource.class):
    IAdaptable item = workingSet.getItems()[0];
    IResource resource =       (IResource) item.getAdapter(IResource.class);
    // e.g. resource is folder /JCL/src/java/lang
- We get the children using IWorkbenchAdapter on the working set item (not the 
resource):
    IWorkbenchAdapter a = (IWorbenchAdapter) item.getAdapter
(IWorkbenchAdapter.class);
    Object[] children = a.getChildren(item);   // the adapter doesn't wrap the 
item, so we need to pass it back
    // e.g. children now contains CU: Object.java, etc., but not package 
fragment: java.lang.reflect
    for (int i = ...) {
        IResource childResource = (IResource) children[i].getAdapter
(IResource.class);
        // e.g. children[i] is the CU for Object.java, childResource is the 
corresponding IFile
    }


Comment 2 Knut Radloff CLA 2002-10-24 13:54:58 EDT
Marking P2 to reflect priority of bug 14441.
Comment 3 Knut Radloff CLA 2002-10-24 17:52:27 EDT
A note from the newsgroup and my reply, related to JRE_LIB and resource working 
sets in the package explorer:

Did you use a Resource working set or a Java working set?
When I use a Resource working set I see strange behavior wrt. the JRE_LIB.
I can't select the JRE_LIB when creating the working set (it doesn't exist in 
the content provider) but I still see JRE_LIB when I select the working set in 
the package explorer. When I expand the JRE_LIB I only see the copyright.txt.
This may be related to bug 25274.

"Colin Sharples" <sharples@nz1.ibm.com> wrote in message 
news:3DB86399.5030602@nz1.ibm.com...
> I had an odd problem yesterday where I couldn't expand the JRE_LIB jar 
> file when I had a working set selected. It worked fine if I deselected 
> the working set. I put in bug #25291, but I couldn't reproduce the 
> problem today, so I closed the bug.
[...]
Comment 4 Sonia Dimitrov CLA 2002-12-11 10:36:05 EST
*** Bug 28026 has been marked as a duplicate of this bug. ***
Comment 5 Knut Radloff CLA 2003-01-09 14:40:20 EST
I tried reimplementing the ResourceWorkingSetFilter (used in the 
ResorceNavigator) using the IWorkbenchAdapter approach.
There's one problem when a java project is selected in the Java working set. 
When I expand the project to displays its files and folders the filter is 
called with the children, which are IFiles and IFolders.
When I get the children for the Java project they include the package fragment 
root which then contains the children in the IResource project.
At this point I stop because I don't find the filter elements as direct 
children of the working set item.
This approach seems correct to me. Am I missing something?
Comment 6 Knut Radloff CLA 2003-01-09 14:42:20 EST
To clarify: The problem is that the children of the JavaProject workbench 
adapter are not the files and folders but an indirect level above them.
Comment 7 Nick Edgar CLA 2003-01-09 16:31:34 EST
The following is a bit of a rambling brain-dump.

When a Java working set is selected in the Navigator, we want to show the 
resources corresponding to:
- the Java elements in the working set,
- all their children,
- all their parents (to allow you to navigate to the elements in the working 
set),
being careful to use the Java parent-child relationship, not the Resource one.
So package a.b is not a child of package a.  Likewise, package a is not a 
parent of package a.b.

For the Tasks view, the problem is similar except we don't want to include 
parents.  We want to show only the tasks on the resources corresponding to:
- the Java elements in the working set,
- all their children (again in terms of the Java parent-child relationship)

One way to do this is to take the elements in the working set, recursively 
collect all the parents and children via IWorkbenchAdapter, map all these to 
resources, and put them in a set.  Then, the Navigator's filter just has to 
check for membership in this set.
For the Tasks view, it would have to check if the marker's resource is in the 
set.

This approach has two problems: 
- it's pretty expensive in terms of space, and
- it's hard to maintain incrementally when elements are added or removed from 
the workspace or Java model (changes to the working set itself are easier to 
deal with)

The question is: can we do better?  Is there a way to determine whether a 
resource is in that set without actually maintaining the complete picture of 
the set?  My proposal above (2002-05-26 14:15) really only explains how to 
calculate the set, not how to check if an arbitrary resource is in the set 
without calculating it.

This is complicated by the fact that there is not necessarily any direct 
parallel between the Java hierarchy and the Resource hierarchy.  As you've 
discovered, a resource in the set ChildrenOf(ResourceOf(SomeJavaElement)) is 
not necessarily in the set ResourcesOf(ChildrenOf(SomeJavaElement)), but it may 
still be in the overall set of resources corresponding to elements in the 
working set.  So we can't assume that you can descend both structures 
simultaneously.

And simply looking up the parent chain of a resource to find one that is in 
ResourcesOf(ElementsIn(WorkingSet)), since that would include children of 
package a.b if a is included, even if a.b is not.

For the Java working set case, what we really need to do is map the resource in 
question to the corresponding Java element, then see if it is in the working 
set, or if it is a descendent or ancestor of any of the elements in the working 
set.  Unfortunately, the Navigator filter can't do this because it doesn't know 
anything about JDT.

Maybe the only way we can do this is to give more smarts to the working set 
after all.  E.g.
/**
 * Returns whether the given element is an element in the working set.
 *
 * @param includeDescendents whether to consider descendents of the working set 
elements as being in the working set
 * @param includeAncestors whether to consider ancestors of the working set 
elements as being in the working set
 */
boolean contains(Object element, boolean includeDescendents, boolean 
includeAncestors);

This would be sufficient for the Navigator, but would be inefficient for the 
Tasks view.  It would have to gather all markers and check their resources 
individually.  The Tasks view could optimize somewhat by initially asking for 
only those markers under resources corresponding to the working set elements, 
but it would still have to check each one.  E.g. ask for markers under the 
folder corresponding to package a, but still check the resource for each one to 
exclude those under the folder corresponding to package a.b.  Maybe it's not so 
bad after all.
Comment 8 Knut Radloff CLA 2003-01-10 12:46:29 EST
The way I implemented the ResourceWorkingSetFilter now is similar to what the 
contains method would do.
I iterate over the working set elements and do a cheap check whether the 
currently filtered element is one of the working set elements or the parent of 
one (prefixOf check works here).
The expensive part is checking if the filtered element is a child of a working 
set element. I was hoping to only have to descend one level using the workbench 
adapter. Since the resource tree does not map 1:1 to the Java element tree I 
have to do what you suggest and descend down all the way, potentially to the 
leaves. This is not so bad for the Java case if the working set contains mostly 
packages and files. When it contains projects there can be a large number of 
source folders and packages to traverse.

Doing this in a WorkingSet.contains method would make the algorithm available 
to others. You are not suggesting that IWorkingSet be implementable by others 
to provide their own specific "contains" implementation, are you?
Comment 9 Nick Edgar CLA 2003-01-10 13:25:31 EST
Actually I was.  It seems like for the Java working set case, only JDT can 
efficiently determine whether a resource should be included or not.
Comment 10 Knut Radloff CLA 2003-01-10 16:25:48 EST
Recursing into the IWorkbenchAdapter children for every viewer element is 
horribly slow when starting at the project level. This also does not include 
non-Java resources even though they are shown and selected in the Java working 
set edit page.

A "contains" method on IWorkbenchAdapter would be sufficient. It would return 
true if the given element is a (direct or indirect) child of the receiver.

We could add an IWorkingSetAdapter to support this. In this scenario I would 
iterate over the working set elements and ask each for its working set adapter. 
This seems simpler than opening up WorkingSet itself for 
extension/implementation.
Comment 11 Nick Edgar CLA 2003-01-13 10:12:52 EST
Please provide more details on how the new APIs would look, and how it would 
address the following scenarios:
- Navigator: showing only the resources corresponding to elements included in 
the working set and their children, and the parent resources need to navigate 
to these
- Tasks: showing only the tasks for resources corresponding to elements 
included in the working set and their children
Comment 12 Nick Edgar CLA 2003-01-13 10:13:19 EST
Note that we cannot add new methods to IWorkbenchAdapter since that would break 
existing implementations.
Comment 13 Knut Radloff CLA 2003-01-13 13:42:53 EST
We would add an interface IWorkingSetAdapter with a method "contains".
For greatest flexibility the contains method should be spec'd like you do in 
your comment #7.
For every element I get in the resource filter I iterate over the working set 
elements and use the IWorkingSetAdapter to determine if the element should be 
filtered out or not. The ancestors check for resource and Java working sets is 
trivial and the descendents check should also be quick for a Java specific 
IWorkingSetAdapter.
The Task list filter currently operates (inefficiently) as you describe. It 
gets all markers for the applicable resources (e.g., workspace root) and then 
runs them through the filter. This could indeed be improved by asking for the 
markers of working set resources and their children
With the IWorkingSetAdapter the task filter would use the descendents parameter 
only.
Comment 14 Nick Edgar CLA 2003-01-13 13:54:01 EST
Would the IWorkingSetAdapter be obtained from the working set or the elements 
in the working set?  If it's the latter, how does it know which criteria to 
use?  E.g., if it's on a java element, does this imply that a Java working set 
is in use? 
Comment 15 Nick Edgar CLA 2003-01-13 13:55:06 EST
Silly question.  It has to be on the working set, otherwise it doesn't know the 
working set elements.
Comment 16 Knut Radloff CLA 2003-01-13 15:02:29 EST
Sorry, my description missed some important detail. 
The assumption is that the IWorkingSetAdapter is on the working set element, 
not the working set itself. 
I would say (syntactically incorrect):
IWorkingSetAdapter adapter = workingSet.getElements()[0].getAdapter
(IWorkingSetAdapter.class)
adapter.contains(navigatorElement, true, true)

I know which working set I want to filter on and the working set elements know 
the most efficient way to filter.
Comment 17 Nick Edgar CLA 2003-01-13 15:18:09 EST
This is fine as long as the containment relationship is defined by the model 
elements themselves, and is unaffected by any other state in the working set.
This makes sense to me -- the containment relationship really is defined by the 
model, and the working set is just a simple list of elements.

I think we should try it.
Comment 18 Knut Radloff CLA 2003-01-17 11:09:33 EST
Added IContainmentAdapter with contains method. Changed the name from 
IWorkingSetAdapter since it may be used independent of working sets.
The method signature is 
boolean contains(Object containmentContext, Object element, boolean 
includeDescendents, boolean includeAncestors);
See the JavaDoc for details.

Changed ResourceWorkingSetFilter and TasksFilter to use IContainmentAdapter. 
Both fall back to use the old resource based compare if there is no 
IContainmentAdapter.

JDT needs to implement an IContainmentAdapter for java elements. I tested this 
and it works correctly and fast in both the resource navigator and tasks view.
Comment 19 Knut Radloff CLA 2003-01-17 11:11:04 EST
Created attachment 3028 [details]
JavaElementAdapterFactory with support for IContainmentAdapter
Comment 20 Knut Radloff CLA 2003-01-17 11:13:09 EST
Created attachment 3029 [details]
JavaWorkbenchAdapter implementing IContainmentAdapter

I don't recommend using the attached implementation as a reference. I hacked it
up to see if the adapter approach works to solve this bug.
It seems to work fine for the navigator and tasks view. However, assume I don't
know what I'm doing and that it is bogus.
Comment 21 Knut Radloff CLA 2003-02-17 19:32:00 EST
It would be nice to get this into 2.1
Otherwise there is no benefit of using IContainmentAdapter in Platform UI. 
Please check with Nick or myself first as there are minor changes planned for 
IContainmentAdapter.
Comment 22 Dirk Baeumer CLA 2003-02-20 08:52:21 EST
Implemented a Java specific containment adapter. 

Fixed for RC1 build
Comment 23 Cagatay Kavukcuoglu CLA 2003-02-20 12:58:23 EST
Bug 8043 seems related to this.