/** * Copyright (c) 2014 - 2017 Frank Appel * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Frank Appel - initial API and implementation */ package com.codeaffine.eclipse.swt.widget.scrollable.context; import static com.codeaffine.eclipse.swt.util.ControlReflectionUtil.$; import static java.util.stream.Collectors.toList; import java.util.stream.Stream; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Scrollable; import com.codeaffine.eclipse.swt.util.ControlReflectionUtil; class LayoutReconciliation { private final ScrollableControl<? extends Scrollable> scrollable; private final ControlReflectionUtil controlReflectionUtil; private final Composite adapter; LayoutReconciliation( Composite adapter, ScrollableControl<? extends Scrollable> scrollable ) { this.controlReflectionUtil = new ControlReflectionUtil(); this.scrollable = scrollable; this.adapter = adapter; registerSourceViewerRulerLayoutActorIfNeeded( scrollable, adapter ); } void run() { if( adapter.getParent() != null ) { if( adapter.getParent().getLayout() instanceof StackLayout ) { reconcileStackLayout(); } if( adapter.getParent() instanceof ViewForm ) { reconcileViewFormLayout(); } if( adapter.getParent().getClass().getName().equals( "org.eclipse.ui.part.PageBook" ) ) { reconcilePageBookLayout(); } if( adapter.getParent() instanceof SashForm ) { reconcileSashLayout(); } if( adapter.getParent() instanceof CTabFolder ) { reconcileCTabFolder(); } } } private static void registerSourceViewerRulerLayoutActorIfNeeded( ScrollableControl<? extends Scrollable> scrollable, Composite adapter ) { Composite parent = adapter.getParent(); if( parent != null ) { Layout layout = parent.getLayout(); String rulerLayoutTypeName = "org.eclipse.jface.text.source.SourceViewer$RulerLayout"; if( layout != null && layout.getClass().getName().equals( rulerLayoutTypeName ) ) { parent.setLayout( new LayoutActor( layout, scrollable, adapter ) ); } } } private void reconcileStackLayout() { StackLayout stackLayout = ( StackLayout )adapter.getParent().getLayout(); if( scrollable.isSameAs( stackLayout.topControl ) ) { stackLayout.topControl = adapter; adapter.getParent().layout(); } } private void reconcileViewFormLayout() { ViewForm viewForm = ( ViewForm )adapter.getParent(); if( scrollable.isSameAs( viewForm.getContent() ) ) { viewForm.setContent( adapter ); relayout( viewForm ); } if( scrollable.isSameAs( viewForm.getTopCenter() ) ) { viewForm.setTopCenter( adapter ); relayout( viewForm ); } if( scrollable.isSameAs( viewForm.getTopLeft() ) ) { viewForm.setTopLeft( adapter ); relayout( viewForm ); } if( scrollable.isSameAs( viewForm.getTopRight() ) ) { viewForm.setTopRight( adapter ); relayout( viewForm ); } } private void reconcilePageBookLayout() { Composite parent = adapter.getParent(); if( scrollable.isSameAs( controlReflectionUtil.getField( parent, "currentPage", Control.class ) ) ) { controlReflectionUtil.invoke( parent, "showPage", $( adapter, Control.class ) ); adapter.getParent().layout(); } } private void reconcileSashLayout() { SashForm parent = ( SashForm )adapter.getParent(); if( needsReparenting( parent ) ) { scrollable.setParent( adapter ); controlReflectionUtil.setField( scrollable.getControl(), "parent", adapter.getParent() ); adapter.getParent().layout(); } if( scrollable.isSameAs( controlReflectionUtil.getField( parent, "maxControl", Control.class ) ) ) { controlReflectionUtil.setField( parent, "maxControl", adapter ); adapter.getParent().layout(); } } private void reconcileCTabFolder() { CTabFolder parent = ( CTabFolder )adapter.getParent(); Stream.of( parent.getItems() ).forEach( item -> reconcileCItemScrollable( item ) ); } private void reconcileCItemScrollable( CTabItem item ) { if( scrollable.isSameAs( item.getControl() ) ) { item.setControl( adapter ); adapter.getParent().layout(); adapter.setVisible( true ); } } private boolean needsReparenting( Composite parent ) { return !Stream.of( parent.getChildren() ) .filter( control -> scrollable.isSameAs( control ) ) .collect( toList() ) .isEmpty(); } private void relayout( Composite composite ) { adapter.setSize( 0, 0 ); composite.layout(); } }