1212 * IBM Corporation - initial API and implementation
1313 *******************************************************************************/
1414package org .eclipse .ui .internal .handlers ;
15-
1615import java .lang .reflect .Method ;
16+ import java .util .Arrays ;
1717import org .eclipse .core .commands .ExecutionEvent ;
1818import org .eclipse .swt .SWT ;
19+ import org .eclipse .swt .custom .CTabFolder ;
20+ import org .eclipse .swt .custom .CTabItem ;
1921import org .eclipse .swt .widgets .Control ;
2022import org .eclipse .swt .widgets .Display ;
2123import org .eclipse .swt .widgets .Shell ;
22-
2324/**
2425 * This handler is an adaptation of the widget method handler that implements
2526 * page traversal via {@link SWT#TRAVERSE_PAGE_NEXT} and
2829 * @since 3.5
2930 */
3031public class TraversePageHandler extends WidgetMethodHandler {
31-
3232 /**
3333 * The parameters for traverse(int).
3434 */
3535 private static final Class <?>[] METHOD_PARAMETERS = { int .class };
36-
3736 @ Override
3837 public final Object execute (final ExecutionEvent event ) {
3938 Control focusControl = Display .getCurrent ().getFocusControl ();
4039 if (focusControl != null ) {
41- int traversal = "next" .equals (methodName ) ? SWT .TRAVERSE_PAGE_NEXT : SWT .TRAVERSE_PAGE_PREVIOUS ; //$NON-NLS-1$
40+ boolean forward = "next" .equals (methodName ); //$NON-NLS-1$
41+ int traversal = getTraversalDirection (forward );
4242 Control control = focusControl ;
4343 do {
44+ if (control instanceof CTabFolder folder && isFinalItemInCTabFolder (folder , forward )
45+ && !areHiddenItems (folder )) {
46+ loopToFirstOrLastItem (folder , forward );
47+ traversal = getTraversalDirection (!forward ); // we are in the second-to-last item in the given
48+ // direction. Now, use the Traverse-event to move back by one
49+ }
4450 if (control .traverse (traversal ))
4551 return null ;
4652 if (control instanceof Shell )
4753 return null ;
4854 control = control .getParent ();
4955 } while (control != null );
5056 }
51-
5257 return null ;
5358 }
5459
60+ private boolean areHiddenItems (CTabFolder folder ) {
61+ return Arrays .stream (folder .getItems ()).anyMatch (i -> !i .isShowing ());
62+ }
63+
64+
65+ private int getTraversalDirection (boolean direction ) {
66+ return direction ? SWT .TRAVERSE_PAGE_NEXT : SWT .TRAVERSE_PAGE_PREVIOUS ;
67+ }
68+
69+ /**
70+ * Sets the current selection to the first or last item the given direction.
71+ *
72+ * @param folder the CTabFolder which we want to inspect
73+ * @param forward whether we want to traverse forwards of backwards
74+ */
75+ private void loopToFirstOrLastItem (CTabFolder folder , boolean forward ) {
76+ if (forward ) {
77+ folder .showItem (folder .getItem (0 ));
78+ folder .setSelection (1 );
79+ } else {
80+ int itemCount = folder .getItemCount ();
81+ folder .setSelection (itemCount - 2 );
82+ }
83+ }
84+
85+ /**
86+ * {@return Returns whether the folder has currently selected the final item in
87+ * the given direction.}
88+ *
89+ * @param folder the CTabFolder which we want to inspect
90+ * @param forward whether we want to traverse forwards of backwards
91+ */
92+ private boolean isFinalItemInCTabFolder (CTabFolder folder , boolean forward ) {
93+ CTabItem currentFolder = folder .getSelection ();
94+ CTabItem lastFolder = null ;
95+ if (forward ) {
96+ int itemCount = folder .getItemCount ();
97+ lastFolder = folder .getItem (itemCount - 1 );
98+ } else {
99+ lastFolder = folder .getItem (0 );
100+ }
101+ return currentFolder .equals (lastFolder );
102+ }
103+
55104 /**
56105 * Looks up the traverse(int) method on the given focus control.
57106 *
@@ -71,4 +120,4 @@ protected Method getMethodToExecute() {
71120 return null ;
72121 }
73122
74- }
123+ }
0 commit comments