Seltsame Warung: Prevented recursive attempt to activate part...

dzim

Top Contributor
Hallo zusammen,

vor einiger Zeit hab ich mal eines ISelectionProvider implementiert (ein Composite, das dafür zuständig ist), der von einem Editor in der createPartControl-Methode angemeldet wird, nachdem das Composite ordentlich angelegt wird
Java:
  getSite().setSelectionProvider(composite);
Beim disposen des Editors, wird das auch ordentlich wieder in der entsprechenden Methode abgemeldet
Java:
  getSite().setSelectionProvider(null);
Ein passender View hört auf diese Änderungen und registriert sich wieder in der createPartControl als Listener
Java:
  getSite().getWorkbenchWindow().getSelectionService()
				.addSelectionListener(this);
und in der dispose Methode wird es wieder entfernt
Java:
  getSite().getWorkbenchWindow().getSelectionService()
				.removePostSelectionListener(MyEditor.ID, this);
meine Methode, um auf ISelections zu hören, die die zentrale Stelle propagiert, ist folgende:
Java:
	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if (RecordCorrectionEditor.ID.equals(part.getSite().getId())
				&& selection instanceof RecordProcessingSelection) {
			this.selection = (RecordProcessingSelection) selection;
			setInternalModelData();
		} else {
			resetAll();
		}
	}
Das schöne war bislang: Es ging! doch nun stelle ich im Log fest, das manchmal eine Exception geworfen wird, die ich nicht verstehe!
Hier kurz mein Vorgehen: Ich wähle eine Zeile in meinem Composite (dort ist ein TreeViewer, der wirft ein SelectionChanged-Event. welches ich im Composite selbst fange und dann per fireSelectionChanged an die Zentrale Stelle weiter leite - nachdem ich da noch ein bisschen mit einer eigenen ISelection-Klasse herumgezaubert habe ;-) ) und sehe den Inhalt in meinem View. Dort editere ich einen Wert der Zeile über ein Text-Feld (im Hintergrund wird das gemeinsame Model geupdated und wirft PropertyChange-Events, welche vom Composite verarbeitet werden - das klappt auch wunderbar!). Jetzt klicke ich eine andere Zeie an und sehe dann im Log folgende Exception:
Code:
java.lang.RuntimeException: WARNING: Prevented recursive attempt to activate part com.***.ui.view.MyView while still in the middle of activating part com.***.ui.editor.MyEditor
	at org.eclipse.ui.internal.WorkbenchPage.setActivePart(WorkbenchPage.java:3481)
	at org.eclipse.ui.internal.WorkbenchPage.requestActivation(WorkbenchPage.java:3071)
	at org.eclipse.ui.internal.PartPane.requestActivation(PartPane.java:279)
	at org.eclipse.ui.internal.PartPane.handleEvent(PartPane.java:237)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1176)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1200)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1181)
	at org.eclipse.swt.widgets.Shell.setActiveControl(Shell.java:1321)
	at org.eclipse.swt.widgets.Control.sendFocusEvent(Control.java:3392)
	at org.eclipse.swt.widgets.Control.gtk_event_after(Control.java:2756)
	at org.eclipse.swt.widgets.Text.gtk_event_after(Text.java:1280)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:1565)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4594)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4191)
	at org.eclipse.swt.internal.gtk.OS._gtk_widget_grab_focus(Native Method)
	at org.eclipse.swt.internal.gtk.OS.gtk_widget_grab_focus(OS.java:12084)
	at org.eclipse.swt.widgets.Control.forceFocus(Control.java:2153)
	at org.eclipse.swt.widgets.Control.forceFocus(Control.java:2146)
	at org.eclipse.swt.widgets.Control.setFocus(Control.java:3734)
	at org.eclipse.swt.widgets.Composite.setFocus(Composite.java:1253)
	at org.eclipse.swt.widgets.Control.fixFocus(Control.java:144)
	at org.eclipse.swt.widgets.Control.setEnabled(Control.java:3714)
	at com.***.view.MyView.setOverviewSectionData(MyView.java:1041)
	at com.***.view.MyView.selectionChanged(MyView.java:837)
	at org.eclipse.ui.internal.AbstractSelectionService.fireSelection(AbstractSelectionService.java:156)
	at org.eclipse.ui.internal.AbstractSelectionService.setActivePart(AbstractSelectionService.java:282)
	at org.eclipse.ui.internal.WWinPartService.updateActivePart(WWinPartService.java:132)
	at org.eclipse.ui.internal.WWinPartService.access$0(WWinPartService.java:122)
	at org.eclipse.ui.internal.WWinPartService$WWinListener.partDeactivated(WWinPartService.java:50)
	at org.eclipse.ui.internal.PartListenerList2$4.run(PartListenerList2.java:115)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.runtime.Platform.run(Platform.java:888)
	at org.eclipse.ui.internal.PartListenerList2.fireEvent(PartListenerList2.java:55)
	at org.eclipse.ui.internal.PartListenerList2.firePartDeactivated(PartListenerList2.java:113)
	at org.eclipse.ui.internal.PartService.firePartDeactivated(PartService.java:242)
	at org.eclipse.ui.internal.PartService.setActivePart(PartService.java:300)
	at org.eclipse.ui.internal.WorkbenchPagePartList.fireActivePartChanged(WorkbenchPagePartList.java:57)
	at org.eclipse.ui.internal.PartList.setActivePart(PartList.java:136)
	at org.eclipse.ui.internal.WorkbenchPage.setActivePart(WorkbenchPage.java:3531)
	at org.eclipse.ui.internal.WorkbenchPage.requestActivation(WorkbenchPage.java:3071)
	at org.eclipse.ui.internal.PartPane.requestActivation(PartPane.java:279)
	at org.eclipse.ui.internal.EditorPane.requestActivation(EditorPane.java:98)
	at org.eclipse.ui.internal.PartPane.handleEvent(PartPane.java:237)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1176)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1200)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1181)
	at org.eclipse.swt.widgets.Shell.setActiveControl(Shell.java:1321)
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:2628)
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:2564)
	at org.eclipse.swt.widgets.Composite.gtk_button_press_event(Composite.java:650)
	at org.eclipse.swt.widgets.Tree.gtk_button_press_event(Tree.java:1866)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:1558)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4594)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4191)
	at org.eclipse.swt.internal.gtk.OS._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.OS.gtk_main_do_event(OS.java:7603)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1185)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1860)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3110)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at com.ipoque.p2p.tracker.rcp.pfs.ssdtool.SSDToolApplication.start(SSDToolApplication.java:119)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1287)

Die Exception wird von dem Text-Feld geworfen, das zuletzt geändert wurde - und zwar bei einem text.setEnabled(false) - diese methode ist die setInternalModelData (siehe ganz oben) die derzeit noch einigen Initialisierungskram macht - es werden erst mal alle textfelder deaktiviert, leer gemacht (leerer String) und dann gefüllt und anhand einiger Constraints wieder enabled.

Ich weiß, dass das ein SEHR SPEZIELLES Problem ist, aber vielleicht hatte jemand von euch ja was ähnliches schon mal oder kann mir sonste wie ein paar hinweise geben.

BTW: Auch Google war hier nicht unbedingt ein sehr informativer Freund - außer dem, dass ich jetzt weiß, dass es noch andere Leidensgenoßen gibt...

Vielen Dank und viele Grüße und einen schönen verschitzten Abdend,
Daniel
 

Wildcard

Top Contributor
Editor X ist ein selection provider, View Y reagiert auf die Selection.
-Der Anwender aktiviert den Editor (klickt irgendwo auf dessen Fläche)
-Eclipse aktiviert den Part und feuert ein selection changed event
-View Y bekommt das Event und verändert die UI
-Irgendwie in den SWT Tiefen führt diese veränderung dazu das ein Widget der View denkt es müsse nun den Fokus bekommen
-Eclipse bekommt mit das View Y den Fokus möchte
-Eclipse weiß das der Part X noch am initialisieren ist
-Eclipse logged ein Warning das der Fokuswechsel verhindert wurde

Dein Code wird trotzdem wie gewollt funktionieren, der log entry ist erstmal nur eine Warnung. In der Regel bekommt man das Problem in den griff in dem man nicht synchron, sondern asynchron auf einen Selektionswechsel reagiert. Im einfachsten Fall durch ein Display.asyncExec.
 

dzim

Top Contributor
Ok... Das heißt?
Ich weiß, das man mit asyncExec Threads ausführen kann und hab das mal in Aktion gesehen, als es darum ging kontinuierlich Daten in eine Tabelle zu schreiben, aber ich versteh' jetzt nicht ganz, wie mir das hier weiter hilft.
Meinst du ich soll das Aktualisieren des Views im dem EventListener fangen, dann aber innerhalb eines asyncExec-Blocks durchführen?
 

dzim

Top Contributor
Die seltsame Exception, Warning, oder was auch immer, fliegt nicht mehr, wenn man beim registrieren noch die Editor.ID mit angibt.
Allerdings ist mir noch aufgefallen, das es immer noch zu WidgetDisposedExceptions gekommen ist - der Grund war aber recht schnell gefunden: Man sollte schon removeSelectionListener und nicht removePostSelectionListener eintragen... ;-)
 

Neue Themen


Oben