Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions eclipse-scout-core/src/desktop/Desktop.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
* Copyright (c) 2010, 2026 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -11,7 +11,7 @@ import {
AbstractLayout, Action, arrays, BenchColumnLayoutData, BusyIndicatorOptions, BusySupport, cookies, DeferredGlassPaneTarget, DesktopBench, DesktopBenchViewActivateEvent, DesktopEventMap, DesktopFormController, DesktopHeader, DesktopLayout,
DesktopModel, DesktopNavigation, DesktopNotification, Device, DisableBrowserF5ReloadKeyStroke, DisableBrowserTabSwitchingKeyStroke, DisplayParent, DisplayViewId, EnumObject, Event, EventEmitter, EventHandler, FileChooser,
FileChooserController, Form, GlassPaneTarget, HtmlComponent, HtmlEnvironment, InitModelOf, KeyStrokeContext, Menu, MessageBox, MessageBoxController, NativeNotificationVisibility, ObjectOrChildModel, ObjectOrModel, objects,
OfflineDesktopNotification, OpenUriHandler, Outline, OutlineContent, OutlineViewButton, Popup, ReloadPageOptions, ResponsiveHandler, scout, SimpleTabArea, SimpleTabBox, Splitter, SplitterMoveEndEvent, SplitterMoveEvent,
OfflineDesktopNotification, OpenUriHandler, Outline, OutlineContent, OutlineViewButton, Popup, PopupManager, ReloadPageOptions, ResponsiveHandler, scout, SimpleTabArea, SimpleTabBox, Splitter, SplitterMoveEndEvent, SplitterMoveEvent,
SplitterPositionChangeEvent, strings, styles, Tooltip, Tree, TreeDisplayStyle, UnsavedFormChangesForm, URL, ViewButton, webstorage, Widget, widgets
} from '../index';
import $ from 'jquery';
Expand Down Expand Up @@ -1861,6 +1861,17 @@ export class Desktop extends Widget implements DesktopModel, DisplayParent {
});
}

repositionPopups() {
const popupManager = this.addOns.find(addOn => addOn instanceof PopupManager) as PopupManager;
if (!popupManager) {
return;
}

for (const popup of popupManager.popups) {
popup.position();
}
}

protected override _renderTrackFocus() {
if (this.trackFocus) {
// Use capture phase because FocusContext stops propagation
Expand Down
5 changes: 4 additions & 1 deletion eclipse-scout-core/src/tile/TileGridLayout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
* Copyright (c) 2010, 2026 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -250,6 +250,9 @@ export class TileGridLayout extends LogicalGridLayout {
protected _onAnimationDone() {
this._updateScrollbar();
this.widget.trigger('layoutAnimationDone');

// tiles may be the anchors of popups, reposition popups after all tiles are at their final position
this.widget.findDesktop()?.repositionPopups();
}

protected _animateTileBounds(tile: Tile, fromBounds: Rectangle, bounds: Rectangle): JQuery.Promise<JQuery> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2010, 2026 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.scout.rt.client.ui.popup;

import static org.junit.Assert.*;

import org.eclipse.scout.rt.client.testenvironment.TestEnvironmentClientSession;
import org.eclipse.scout.rt.client.ui.desktop.IDesktop;
import org.eclipse.scout.rt.client.ui.form.fields.stringfield.AbstractStringField;
import org.eclipse.scout.rt.testing.client.runner.ClientTestRunner;
import org.eclipse.scout.rt.testing.client.runner.RunWithClientSession;
import org.eclipse.scout.rt.testing.platform.runner.RunWithSubject;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(ClientTestRunner.class)
@RunWithSubject("default")
@RunWithClientSession(TestEnvironmentClientSession.class)
public class PopupTest {

@Test
public void testPopupDisposeOnAnchorDispose() {

// dispose current anchor -> popup is closed

MyPopup popup = new MyPopup();
MyStringField anchor = new MyStringField();
popup.setAnchor(anchor);
popup.open();

assertTrue(IDesktop.CURRENT.get().getAddOn(PopupManager.class).getPopups().contains(popup));
assertFalse(popup.isDisposeDone());
assertFalse(anchor.isDisposeDone());

anchor.dispose();

assertFalse(IDesktop.CURRENT.get().getAddOn(PopupManager.class).getPopups().contains(popup));
assertTrue(popup.isDisposeDone());
assertTrue(anchor.isDisposeDone());

// dispose former anchor -> popup is not closed

popup = new MyPopup();
anchor = new MyStringField();
popup.setAnchor(anchor);
popup.open();

assertTrue(IDesktop.CURRENT.get().getAddOn(PopupManager.class).getPopups().contains(popup));
assertFalse(popup.isDisposeDone());
assertFalse(anchor.isDisposeDone());

popup.setAnchor(null);
anchor.dispose();

assertTrue(IDesktop.CURRENT.get().getAddOn(PopupManager.class).getPopups().contains(popup));
assertFalse(popup.isDisposeDone());
assertTrue(anchor.isDisposeDone());
}

protected static class MyStringField extends AbstractStringField {
}

protected static class MyPopup extends AbstractPopup {
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2026 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -9,6 +9,9 @@
*/
package org.eclipse.scout.rt.client.ui.popup;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import org.eclipse.scout.rt.client.ModelContextProxy;
import org.eclipse.scout.rt.client.ModelContextProxy.ModelContext;
import org.eclipse.scout.rt.client.ui.AbstractWidget;
Expand All @@ -24,6 +27,7 @@
public abstract class AbstractPopup extends AbstractWidget implements IPopup {

private IPopupUIFacade m_uiFacade;
private P_AnchorDisposeListener m_anchorDisposeListener;

public AbstractPopup() {
this(true);
Expand Down Expand Up @@ -247,6 +251,15 @@ public void setVerticalSwitch(boolean verticalSwitch) {
protected void initConfig() {
super.initConfig();
m_uiFacade = BEANS.get(ModelContextProxy.class).newProxy(new P_UIFacade(), ModelContext.copyCurrent());
m_anchorDisposeListener = createAnchorDisposeListener();
addPropertyChangeListener(IPopup.PROP_ANCHOR, event -> {
if (event.getOldValue() instanceof IWidget) {
((IWidget) event.getOldValue()).removePropertyChangeListener(IWidget.PROP_DISPOSE_DONE, getAnchorDisposeListener());
}
if (event.getNewValue() instanceof IWidget) {
((IWidget) event.getNewValue()).addPropertyChangeListener(IWidget.PROP_DISPOSE_DONE, getAnchorDisposeListener());
}
});

setAnchor(getConfiguredAnchor());
setAnimateOpening(getConfiguredAnimateOpening());
Expand Down Expand Up @@ -291,4 +304,20 @@ public void close() {
getPopupManager().close(this);
dispose();
}

protected P_AnchorDisposeListener getAnchorDisposeListener() {
return m_anchorDisposeListener;
}

protected P_AnchorDisposeListener createAnchorDisposeListener() {
return new P_AnchorDisposeListener();
}

protected class P_AnchorDisposeListener implements PropertyChangeListener {

@Override
public void propertyChange(PropertyChangeEvent event) {
close();
}
}
}
Loading