Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,66 @@ void subscribeTopicChildrenChanged(@UIEventTopic(UIEvents.ElementContainer.TOPIC
shouldTopRightAdjusted(event);
}

@Inject
@Optional
void subscribeTopicChildrenMoved(@UIEventTopic(UIEvents.ElementContainer.TOPIC_CHILDREN) Event event) {
if (!UIEvents.isMOVE(event)) {
return;
}
// Ensure that this event is for a MPartStack
Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(element instanceof MPartStack)) {
return;
}

MPartStack stack = (MPartStack) element;
if (stack.getRenderer() != this) {
return;
}

MUIElement movedElement = (MUIElement) event.getProperty(UIEvents.EventTags.NEW_VALUE);

CTabFolder tabFolder = (CTabFolder) stack.getWidget();
if (tabFolder == null || tabFolder.isDisposed()) {
return;
}

CTabItem item = findItemForPart(movedElement, stack);
if (item == null || item.isDisposed()) {
return;
}

int newIndex = calcIndexFor(stack, movedElement);

// Remember the control, it will be disposed with the CTabItem otherwise
Control control = item.getControl();
item.setControl(null);

// As CTabItem cannot be reordered, we need to dispose and recreate it
String text = item.getText();
Image image = item.getImage();
boolean showClose = item.getShowClose();
String toolTipText = item.getToolTipText();
Font font = item.getFont();
Object data = item.getData();

boolean wasSelected = tabFolder.getSelection() == item;

item.dispose();

CTabItem newItem = new CTabItem(tabFolder, (showClose ? SWT.CLOSE : SWT.NONE), newIndex);
newItem.setText(text);
newItem.setImage(image);
newItem.setToolTipText(toolTipText);
newItem.setFont(font);
newItem.setData(data);
newItem.setData(OWNING_ME, movedElement);
newItem.setControl(control);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the currently selected tab is moved, the selection is not preserved. I should try to save it

java boolean wasSelected = tabFolder.getSelection() == item;
// ... dispose and recreate ...
if (wasSelected) {
tabFolder.setSelection(newItem);
}

if (wasSelected) {
tabFolder.setSelection(newItem);
}
}

@Inject
@Optional
void subscribeTopicUILabelChanged(@UIEventTopic(UIEvents.UILabel.TOPIC_ALL) Event event) {
Expand Down Expand Up @@ -623,6 +683,14 @@ void subscribeTopicSelectedelementChanged(
tabStateHandler.handleEvent(event);
}

@Override
public void removeGui(MUIElement element, Object widget) {
if (widget instanceof CTabFolder tabFolder && !tabFolder.isDisposed()) {
tabFolder.dispose();
}
element.setWidget(null);
}

@Override
protected boolean requiresFocus(MPart element) {
MUIElement inStack = element.getCurSharedRef() != null ? element.getCurSharedRef() : element;
Expand Down Expand Up @@ -1010,7 +1078,7 @@ protected void createTab(MElementContainer<MUIElement> stack, MUIElement element
}
}

private int calcIndexFor(MElementContainer<MUIElement> stack, final MUIElement part) {
private int calcIndexFor(MElementContainer<? extends MUIElement> stack, final MUIElement part) {
int index = 0;

// Find the -visible- part before this element
Expand All @@ -1036,7 +1104,7 @@ public void childRendered(final MElementContainer<MUIElement> parentElement, MUI
createTab(parentElement, element);
}

private CTabItem findItemForPart(MUIElement element, MElementContainer<MUIElement> stack) {
private CTabItem findItemForPart(MUIElement element, MElementContainer<? extends MUIElement> stack) {
if (stack == null) {
stack = element.getParent();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.eclipse.e4.ui.workbench.renderers.swt;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;

import jakarta.inject.Inject;
import java.util.List;
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.tests.rules.WorkbenchContextExtension;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

public class StackRendererMoveTest {

@RegisterExtension
public WorkbenchContextExtension contextRule = new WorkbenchContextExtension();

@Inject
private EModelService ems;

@Inject
private MApplication application;

private MWindow window;
private MPartStack partStack;

@BeforeEach
public void setUp() throws Exception {
window = ems.createModelElement(MWindow.class);
application.getChildren().add(window);
application.setSelectedElement(window);

partStack = ems.createModelElement(MPartStack.class);
window.getChildren().add(partStack);
}

@Test
public void testPartMoveUpdatesWidget() throws Exception {
// Create two parts
MPart part1 = ems.createModelElement(MPart.class);
part1.setLabel("Part 1");
partStack.getChildren().add(part1);

MPart part2 = ems.createModelElement(MPart.class);
part2.setLabel("Part 2");
partStack.getChildren().add(part2);

// Render the window (and thus the stack and parts)
contextRule.createAndRunWorkbench(window);

CTabFolder tabFolder = (CTabFolder) partStack.getWidget();
assertEquals(2, tabFolder.getItemCount());

CTabItem item1 = tabFolder.getItem(0);
CTabItem item2 = tabFolder.getItem(1);

assertEquals(part1, item1.getData(AbstractPartRenderer.OWNING_ME));
assertEquals(part2, item2.getData(AbstractPartRenderer.OWNING_ME));
assertEquals(item1.getControl(), part1.getWidget());
assertEquals(item2.getControl(), part2.getWidget());

// Move part1 to the end (index 1)
// We use model service to move to ensure events are fired
ems.move(part1, partStack, 1);

// Verify model update
List<org.eclipse.e4.ui.model.application.ui.basic.MStackElement> children = partStack.getChildren();
assertEquals(part2, children.get(0));
assertEquals(part1, children.get(1));

// Verify UI update
assertEquals(2, tabFolder.getItemCount());
CTabItem newItem1 = tabFolder.getItem(1);
CTabItem newItem2 = tabFolder.getItem(0);

// The old item1 should be disposed
assertTrue(item1.isDisposed(), "Old item for part1 should be disposed");
assertFalse(item2.isDisposed(), "Item2 should not be disposed");

// part1 should have a NEW widget item, but the part's widget (content) should be preserved
assertNotSame(item1, newItem1);
assertEquals(part1, newItem1.getData(AbstractPartRenderer.OWNING_ME), "New item should have OWNING_ME set");
assertEquals(part1.getWidget(), newItem1.getControl(), "Part1 widget should be the control of the new item");

// part2 should still be valid and same widget
assertEquals(item2, newItem2);
assertEquals(part2, newItem2.getData(AbstractPartRenderer.OWNING_ME));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,32 @@ public void testToolbarIsReparentedToNewCompositeForTopRightOfTabFolder() {
assertSame(tabFolder.getTopRight(), toolbarControl.getParent());
}

@Test
public void testPartReordering() {
MPart part1 = ems.createModelElement(MPart.class);
part1.setLabel("Part 1");
MPart part2 = ems.createModelElement(MPart.class);
part2.setLabel("Part 2");

partStack.getChildren().add(part1);
partStack.getChildren().add(part2);

contextRule.createAndRunWorkbench(window);

CTabFolder tabFolder = (CTabFolder) partStack.getWidget();
assertEquals(2, tabFolder.getItemCount());
assertEquals("Part 1", tabFolder.getItem(0).getText());
assertEquals("Part 2", tabFolder.getItem(1).getText());

// Move part2 to index 0
partStack.getChildren().remove(part2);
partStack.getChildren().add(0, part2);

// Verify order in Widget
assertEquals("Part 2", tabFolder.getItem(0).getText());
assertEquals("Part 1", tabFolder.getItem(1).getText());
}

// helper functions

/*
Expand Down
Loading