My eclipse 3.x RCP app has 2 perspectives. When the app starts and Perspective A is active then all parts are created and displayed correctly. When the app starts and Perspective B is active then most parts are empty and createControl is never called. If I reset the perspective then all parts are created properly.
So far I have found that part in PartActivationHistory.activate has a null context and this causes a NullPointerException. Why might this be? Who sets the context and when?
void activate(MPart part, boolean activateBranch) {
IEclipseContext context = part.getContext();
if (activateBranch) {
context.activateBranch();
} else {
IEclipseContext parent = context.getParent();
do {
context.activate();
context = parent;
parent = parent.getParent();
} while (parent.get(MWindow.class) != null);
}
prepend(part);
}
The problem was caused by performing certain actions before the Workbench was fully initialised. This does not seem to have been a problem in the past but I have recently updated the platform from Kepler to 2020/6.
Related
I have a slightly odd issue and unfortunately it's not one I can easily write a standalone class for.
Within my application I have a TableView (on a tab) which is clickable. Clicking on a row in this TableView opens a new Tab with a data relating to the clicked row in a new TableView.
The TableViews are bound to a custom class that extends ModifiableObservableListBase. This allows a Scrollbar to be used to request new data from the server based on the top and bottom rows of the viewport.
This all works well.
I also have a Service in my subclass of ModifiableObservableListBase that is used to improve the rendering of data under high load. It uses a LinkedBlockingQueue and countDownLatch so that only most recent view is updated to the UI preventing unnecessary redraws. Using the following:
setAll(list);
This also works well.
So far so good!
What I've noticed is that when I open and close these tabs multiple times (no fixed number), at some point the TableView will stop updating with data. The data is requested from the server and received but the Service which is used to control how data is added to the ModifiableObservableListBase fails to move out of the SCHEDULED state. This means that the Task that has been created never runs. I'm struggling to see why this would work correctly x times and then stop working.
Any help would be really welcomed, sorry I don't have a standaone application that replicates this issue. I will try to recreate it.
The following Service is constructed in the constructor of my subclass of ModifiableObservableListBase which is constructed each time a new tab(including the corresponding TableView which is bound to the ModifiableObservableListBase ) is added to the UI.
Service upDateService = new Service() {
#Override
protected Task createTask() {
//when the code fails it still calls to here.
return new Task() {
#Override
protected Object call() throws Exception {
//when the code fails it doesn't call the call() method
while (true) {
List<T> list = updateQueue.take();
updateLatch = new CountDownLatch(1);
//now put on the FX Application Thread
Platform.runLater(() -> {
if (list.size() > 0 && list.get(0) instanceof TableStructure) {
totalRowCount.set(((TableStructure) list.get(0)).getTotalDbRowCount());
}
setAll(list);
updateLatch.countDown();
});
try {
updateLatch.await(1, TimeUnit.MINUTES);
updateLatch = null;
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};
}
};
upDateService.start();
In e3 to create not restorable View I set field "restorable" to false in extension org.eclipse.ui.views and it works. In my e4 application I create PartDescriptor with tag "NoRestore" but it do nothing. After restart Part is shown. What I do wrong? Or it is bug?
If you let e4 save the workbench model on exit it is restored exactly as saved the next time the RCP is started. There is no support for a NoRestore tag.
Specifying the -clearPersistedState flag on startup will reset the model to the initial state. You can also specify -persistState false to stop the model being saved on exit.
If you just want to deal with one part you can alter the model in your life cycle class during startup. Something like:
#ProcessAdditions
public void processAdditions(MApplication app, EModelService modelService)
{
MUIElement el = modelService.find("your part id", app);
if (el != null) {
el.setToBeRendered(false);
}
}
which just finds a part and turns off the 'to be rendered' flag.
For compatibility with future versions, in which the IPresentationEngine.NO_RESTORE("NoRestore") tag will be present, you can use the following code.
#PreSave
void preSave(MApplication a_app, EModelService a_modelService){
ArrayList<MElementContainer<MUIElement>> containers = new ArrayList<>();
List<MPart> parts = a_modelService.findElements(a_app, null, MPart.class, Arrays.asList("NoRestore"));
parts.forEach(p -> {
p.setToBeRendered(false); // hide parts
containers.add(p.getParent()); // collect containers with no restorable parts
});
// hide containers which contains only no restorable parts
containers.stream().filter(c -> c.getChildren().stream().allMatch(ch -> ch.getTags().contains("NoRestore"))).forEach(c -> c.setToBeRendered(false));
}
NOTE. Attempts to add the same code to methods with annotations #ProcessAdditions or #ProcessRemovals did not help: errors occurred and after the restart of the application no parts were displayed. So I added my code to the #PreSave method.
I'm developing an RCP that has two product versions, a core app and one with some extensions. If a user opens the core app after having opened the extended app in the same workspace, eclipse detects a perspective used only in the extended app and makes a local copy of it, so it shows up in the perspective toolbar as an orphaned extension.
I created an activity to hide the extended app perspective when running the core app. That hides it from the perspective menu and the perspective shortcut menu, but it doesn't remove it from the perspective toolbar.I also tried detecting orphaned perspectives from the active page of the active workbench window (by looking for angle brackets in the label) and removing them with PlatformUI.getWorkbench().getPerspectiveRegistry().deletePerspective(perspective), but this doesn't affect the perspective toolbar either. The perspective I'm removing is not present in the core app.
Is there a way I can access the perspective toolbar programmatically so I can remove any orphaned perspectives? Or any other approach tha would work?
I thought a good solution would be creating a custom perspective switcher, but that path was blocked by an eclipse bug. There is a suggested workaround, but it did not work for me. I created a custom perspective switcher toolbar, but I could find no way to make it update when perspectives are opened or activated. My attempts are documented here.
I removed the orphan perspectives in a workspace shutdown hook, but for some reason an NPE is thrown by the E4 workbench (LazyStackRenderer line 238) when I select a perspective in the switcher that was opened but not selected when I launched the app.
I got it to work as desired by closing all open perspectives on shutdown, after storing their IDs in a preference value, and then opening them again when the app is launched in the WorkbenchWindowAdvisor. It's a bit of a hack, but it's the only way I could find to avoid the E4 workbench NPE, which also prevents setting the perspective from the toolbar until it's closed and re-opened from the Window menu.
Here's my code.
...
IWorkbench workbench = ...
static final String PERPSECTIVE_ID_1 = ...
static fnal String PERSPECTIVE_ID_2 = ...
static final String PREFERENCE_KEY = ...
workbench.addWorkbenchListener( new IWorkbenchListener() {
public boolean preShutdown( IWorkbench workbench, boolean forced ) {
IPerspectiveDescriptor[] openPerspectives = page.getOpenPerspectives();
page.closeAllPerspectives(false, false);
StringBuilder sb = new StringBuilder();
String delim = "";
for (IPerspectiveDescriptor persp : openPerspectives) {
if (!persp.getId().equals(PERSPECTIVE_ID_1) && !persp.getId().equals(PERSPECTIVE_ID_2) {
sb.append(delim + persp.getId());
delim = ";";
}
}
getPreferenceStore().setValue(PREF_KEY, sb.toString());
return true;
}
public void postShutdown( IWorkbench workbench ) {
}
});
class MyWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
static final String PRODUCT_ID_1 = ...
static final String PRODUCT_ID_2 = ...
static final String PREFERENCE_KEY = ...
...
#Override
public void postWindowOpen() {
IWorkbenchPage page = getWindowConfigurer().getWindow().getActivePage();
String savedOpenPerspectiveStr = getPreferenceStore().getString(PREFERENCE_KEY);
if (!"".equals(savedOpenPerspectiveStr)) {
List<IPerspectiveDescriptor> openPerspectives = new ArrayList<IPerspectiveDescriptor>();
String[] perspectiveIds = savedOpenPerspectiveStr.split(";");
if (perspectiveIds.length == 0) {
openPerspectives.add(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(savedOpenPerspectiveStr));
} else {
for (String id : perspectiveIds) {
openPerspectives.add(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id));
}
}
//successively setting perspectives causes them to appear in the perspective switcher toolbar
for (IPerspectiveDescriptor persp : openPerspectives) {
page.setPerspective(persp);
}
}
//now we set the appropriate perspective
if (Platform.getProduct().getId().equals(PRODUCT_ID_1)) {
page.setPerspective(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(PERSPECTIVE_ID_1));
} else if (Platform.getProduct().getId().equals(PRODUCT_ID_2)) {
page.setPerspective(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(PERSPECTIVE_ID_2));
}
}
...
}
i'm working on an Eclipse RCP4 project. I have different perspectives showing a set of Parts to choose informations from. After selecting what i want to see, a new Part opens and displays the objet i want to edit / view attibutes of.
I can open many parts of the same type. If i close the application, the eclipse framwork persists the position of all opened Parts. If i restart the application all previously opened Parts are open but without informations.
-How to prevent Eclipseframwork from persisting the state of Parts?
-How to close Parts on exit?
I'm searching for a way to add an "removeOnExit" tag to a Part and than close such a marked Part on exit.
Thanks in advance :)
With this you can close MParts with a specific Tag.
It seems you have to switch to the Perspective the Part is on, else it's not removed from the context wich will cause nullpointer exceptions.
#Inject
#Optional
public void doEvent(#EventTopic(EventConstants.EventTopics.CLOSE_PARTS_WITH_TAGS) String tagToClose, MApplication app,
EModelService eModelService, EPartService ePartService) {
MUIElement activePart = ePartService.getActivePart();
EPartService activePeServcie = null;
MPerspective activePerspective = null;
if (activePart instanceof MPart) {
activePeServcie = ((MPart) activePart).getContext().get(EPartService.class);
activePerspective = eModelService.getPerspectiveFor(activePart);
}
List<String> tags = new ArrayList<String>();
tags.add(tagToClose);
List<MPart> elementsWithTags = eModelService.findElements(app, null, MPart.class, tags);
for (MPart part : elementsWithTags) {
try {
logger.info("Closing part " + part.toString());
EPartService peService = part.getContext().get(EPartService.class);
peService.switchPerspective(eModelService.getPerspectiveFor(part));
peService.hidePart(part);
} catch (Exception e) {
logger.error(e);
}
}
if (activePart instanceof MPart && activePeServcie != null && activePerspective != null) {
activePeServcie.switchPerspective(activePerspective);
}
}
We too tried to migrate from Eclipse 3 to Eclipse 4.We used the comp layer and had a lot of problems with the migration. I had a similar problem with persistent store of the eclipse workbench. So parts and views had the same position as before restart.
The persistence paradigma in Eclipse 4 has changed. Please take a look here:
As far as I remember the call of configurer.setSaveAndRestore(false) does not work in Eclipse 4 correctly.
I'm not sure if what I'm experiencing is the same as here: Silverlight ChildWindow Memory Leak
but...:
I've got a Silverlight ChildWindow with 3 radio buttons in the same group with IsChecked all set to false in XAML, I don't want any of them selected upon opening. I open up the ChildWindow from my viewmodel:
if (_NewChildWindowCommand == null)
_NewChildWindowCommand = new RelayCommand(param => _cwService.ShowDialog(_newLocation, new NewViewModel(), closed =>
{
if (_newLocation.DialogResult.HasValue && _newLocation.DialogResult.Value)
{
//do something
}
_newLocation = null;
_newLocation = _container.GetExportedValue<INewChildWindow>();
}));
I then select one of the radio buttons hit OK. It Closes, I open it up again and the ChildWindow seems to have been disposed since upon opening, none of those radio buttons are selected (the way it should be). So I select a radio button again,hit OK, It Closes...But the third time I open the ChildWindow, it has the same radio button selected as when I closed it. This is what I don't understand. I thought by setting _newLocation=null like I did and then getting INewChildWindow from the container would give me a new ChildWindow but it doesn't seem to be the case. I tried calling GC.Collect() after setting _newLocation to null but that didn't work, and I tried setting the PartCreationPolicy to NonShared on the ChildWindow, however that doesn't make a difference since the instance of the ChildWindow is being stored in _newLocation and the class containing _newLocation isn't disposed of:
[ImportingConstructor]
public HomeViewModel(IChildWindowService cwService, INewLocationChildWindow newLocationChildWindow)
{
if (!IsDesignTime)
{
_cwService = cwService;
_newLocation = newLocationChildWindow;
_catalog = new AggregateCatalog();
_catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(_catalog);
}
}
Is there something else going on here?
Set the creation policy of the ChildWindow to NonShared. Then replace _container.GetExportedValue<INewChildWindow>() with _container.GetExport<INewChildWindow>(). This will give you a Lazy<INewChildWindow>, and you can use the Value property to get the child window. Then to release the export call _container.ReleaseExport, passing in the Lazy that was returned by the call to GetExport.