diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/handlers/TraversePageHandler.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/handlers/TraversePageHandler.java index ea7b11b14b1..f4ee988051f 100644 --- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/handlers/TraversePageHandler.java +++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/handlers/TraversePageHandler.java @@ -12,14 +12,15 @@ * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.handlers; - import java.lang.reflect.Method; +import java.util.Arrays; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; - /** * This handler is an adaptation of the widget method handler that implements * page traversal via {@link SWT#TRAVERSE_PAGE_NEXT} and @@ -28,19 +29,24 @@ * @since 3.5 */ public class TraversePageHandler extends WidgetMethodHandler { - /** * The parameters for traverse(int). */ private static final Class[] METHOD_PARAMETERS = { int.class }; - @Override public final Object execute(final ExecutionEvent event) { Control focusControl = Display.getCurrent().getFocusControl(); if (focusControl != null) { - int traversal = "next".equals(methodName) ? SWT.TRAVERSE_PAGE_NEXT : SWT.TRAVERSE_PAGE_PREVIOUS; //$NON-NLS-1$ + boolean forward = "next".equals(methodName); //$NON-NLS-1$ + int traversal = getTraversalDirection(forward); Control control = focusControl; do { + if (control instanceof CTabFolder folder && isFinalItemInCTabFolder(folder, forward) + && !areHiddenItems(folder)) { + loopToFirstOrLastItem(folder, forward); + traversal = getTraversalDirection(!forward); // we are in the second-to-last item in the given + // direction. Now, use the Traverse-event to move back by one + } if (control.traverse(traversal)) return null; if (control instanceof Shell) @@ -48,10 +54,52 @@ public final Object execute(final ExecutionEvent event) { control = control.getParent(); } while (control != null); } - return null; } + private boolean areHiddenItems(CTabFolder folder) { + return Arrays.stream(folder.getItems()).anyMatch(i -> !i.isShowing()); + } + + private int getTraversalDirection(boolean direction) { + return direction ? SWT.TRAVERSE_PAGE_NEXT : SWT.TRAVERSE_PAGE_PREVIOUS; + } + + /** + * Sets the current selection to the first or last item the given direction. + * + * @param folder the CTabFolder which we want to inspect + * @param forward whether we want to traverse forwards of backwards + */ + private void loopToFirstOrLastItem(CTabFolder folder, boolean forward) { + if (forward) { + folder.showItem(folder.getItem(0)); + folder.setSelection(1); + } else { + int itemCount = folder.getItemCount(); + folder.setSelection(itemCount - 2); + } + } + + /** + * {@return Returns whether the folder has currently selected the final item in + * the given direction.} + * + * @param folder the CTabFolder which we want to inspect + * @param forward whether we want to traverse forwards of backwards + */ + private boolean isFinalItemInCTabFolder(CTabFolder folder, boolean forward) { + CTabItem currentFolder = folder.getSelection(); + CTabItem lastFolder = null; + if (forward) { + int itemCount = folder.getItemCount(); + lastFolder = folder.getItem(itemCount - 1); + } else { + lastFolder = folder.getItem(0); + } + return currentFolder.equals(lastFolder); + } + /** * Looks up the traverse(int) method on the given focus control. * @@ -71,4 +119,4 @@ protected Method getMethodToExecute() { return null; } -} +} \ No newline at end of file