/**
* 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;
import static com.codeaffine.eclipse.swt.test.util.DisplayHelper.flushPendingEvents;
import static com.codeaffine.eclipse.swt.test.util.ShellHelper.createShell;
import static com.codeaffine.eclipse.swt.widget.scrollable.TreeHelper.createTree;
import static com.codeaffine.eclipse.swt.widget.scrollable.TreeHelper.expandTopBranch;
import static com.codeaffine.test.util.lang.ThrowableCaptor.thrownBy;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Optional;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com.codeaffine.eclipse.swt.test.util.DisplayHelper;
import com.codeaffine.eclipse.swt.test.util.SWTIgnoreConditions.NonWindowsPlatform;
import com.codeaffine.eclipse.swt.util.ReadAndDispatch;
import com.codeaffine.test.util.junit.ConditionalIgnoreRule;
import com.codeaffine.test.util.junit.ConditionalIgnoreRule.ConditionalIgnore;
public class TreeAdapterTest {
private static final int SELECTION = 50;
@Rule public final ConditionalIgnoreRule ignoreRule = new ConditionalIgnoreRule();
@Rule public final DisplayHelper displayHelper = new DisplayHelper();
private ScrollableAdapterFactory adapterFactory;
private TreeAdapter adapter;
private Shell shell;
private Tree tree;
private Object layoutData;
@Before
public void setUp() {
adapterFactory = new ScrollableAdapterFactory();
shell = createShell( displayHelper );
tree = createTree( shell, 4, 6 );
layoutData = new Object();
tree.setLayoutData( layoutData );
adapter = adapterFactory.create( tree, TreeAdapter.class ).get();
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void adapt() {
assertThat( adapter.getChildren() ).contains( tree );
assertThat( adapter.getLayout() ).isInstanceOf( ScrollableLayout.class );
assertThat( adapter.getLayoutData() ).isSameAs( layoutData );
assertThat( adapter.getBounds() ).isEqualTo( shell.getClientArea() );
assertThat( adapter.getScrollable() ).isSameAs( tree );
}
@Test
public void setLayout() {
Throwable actual = thrownBy( () -> adapter.setLayout( new FillLayout() ) );
assertThat( actual ).isInstanceOf( UnsupportedOperationException.class );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void disposalOfAdapter() {
adapter.dispose();
assertThat( tree.isDisposed() ).isTrue();
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void disposalOfTree() {
tree.dispose();
assertThat( adapter.isDisposed() ).isTrue();
assertThat( shell.getChildren() ).isEmpty();
}
@Test
public void disposalWithDragSourceOnTree() {
Tree tree = new TestTreeFactory().create( shell );
ScrollableAdapterFactoryHelper.adapt( tree, TreeAdapter.class );
DragSource dragSource = new DragSource( tree, DND.DROP_MOVE | DND.DROP_COPY );
shell.dispose();
assertThat( dragSource.isDisposed() ).isTrue();
}
@Test
public void constructor() {
Throwable actual = thrownBy( () -> new TreeAdapter() );
assertThat( actual )
.hasMessageContaining( "Subclassing not allowed" )
.isInstanceOf( SWTException.class );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeBounds() {
openShellWithoutLayout();
tree = createTree( shell, 1, 1 );
adapter = adapterFactory.create( tree, TreeAdapter.class ).get();
waitForReconciliation();
tree.setBounds( expectedBounds() );
waitForReconciliation();
assertThat( adapter.getBounds() ).isEqualTo( expectedBounds() );
assertThat( tree.getBounds() ).isEqualTo( expectedBounds() );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeBoundsWithVisibleScrollBars() {
openShellWithoutLayout();
expandTopBranch( tree );
tree.setBounds( expectedBounds() );
waitForReconciliation();
assertThat( adapter.getBounds() ).isEqualTo( expectedBounds() );
assertThat( tree.getBounds() ).isNotEqualTo( expectedBounds() );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeBoundsByTreeEvent() {
openShellWithoutLayout();
Rectangle expected = adapter.getBounds();
Rectangle origin = tree.getBounds();
expandTopBranch( tree );
waitForReconciliation();
assertThat( adapter.getBounds() ).isEqualTo( expected );
assertThat( tree.getBounds() ).isNotEqualTo( origin );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeBoundsWithHorizontalScroll() {
openShellWithoutLayout();
expandTopBranch( tree );
tree.setBounds( expectedBounds() );
waitForReconciliation();
scrollHorizontal( adapter, SELECTION );
assertThat( adapter.getBounds() ).isEqualTo( expectedBounds() );
assertThat( tree.getBounds() ).isNotEqualTo( expectedBounds() );
assertThat( adapter.getHorizontalBar().getSelection() ).isEqualTo( SELECTION );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeVisibility() {
tree.setVisible( false );
waitForReconciliation();
assertThat( adapter.getVisible() ).isFalse();
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeEnablement() {
tree.setEnabled( false );
waitForReconciliation();
assertThat( adapter.getEnabled() ).isFalse();
}
@Test
public void getLayoutData() {
RowData expected = new RowData();
tree.setLayoutData( expected );
Object actual = adapter.getLayoutData();
assertThat( actual ).isSameAs( expected );
}
@Test
public void setLayoutData() {
Object expected = new Object();
adapter.setLayoutData( expected );
Object actual = tree.getLayoutData();
assertThat( actual ).isSameAs( expected );
}
@Test
public void computeSize() {
Point expected = tree.computeSize( SWT.DEFAULT, SWT.DEFAULT, true );
Point actual = adapter.computeSize( SWT.DEFAULT, SWT.DEFAULT, true );
assertThat( actual ).isEqualTo( expected );
}
@Test
public void treeColumnDelegation() {
TreeColumn expected = new TreeColumn( tree, SWT.NONE );
assertThat( adapter.getColumn( 0 ) ).isSameAs( expected );
assertThat( adapter.getColumnCount() ).isEqualTo( 1 );
assertThat( adapter.getColumnOrder() ).isEqualTo( tree.getColumnOrder() );
assertThat( adapter.getColumns() ).hasSize( 1 );
}
@Test
@ConditionalIgnore( condition = NonWindowsPlatform.class )
public void changeTreeItemHeight() {
expandTopBranch( tree );
int expectedHeight = configureTableItemHeightAdjuster();
shell.open();
waitForReconciliation();
assertThat( tree.getItemHeight() ).isEqualTo( expectedHeight );
}
@Test
public void adaptWithoutScrollBarStyle() {
openShellWithoutLayout();
tree = new Tree( shell, SWT.NO_SCROLL );
Optional<TreeAdapter> adapter = adapterFactory.create( tree, TreeAdapter.class );
assertThat( adapter.isPresent() ).isFalse();
}
private int configureTableItemHeightAdjuster() {
int result = 24;
tree.addListener( SWT.MeasureItem, evt -> evt.height = result );
flushPendingEvents();
return result;
}
private void scrollHorizontal( TreeAdapter adapter, int selection ) {
int duration = 100;
displayHelper.getDisplay().timerExec( duration, () -> adapter.getHorizontalBar().setSelection( selection ) );
new ReadAndDispatch().spinLoop( shell, duration * 2 );
}
private void openShellWithoutLayout() {
shell.setLayout( null );
shell.open();
}
private void waitForReconciliation() {
new ReadAndDispatch().spinLoop( shell, WatchDog.DELAY * 6 );
}
private Rectangle expectedBounds() {
Rectangle clientArea = shell.getClientArea();
return new Rectangle( 5, 10, clientArea.width - 10, clientArea.height - 20 );
}
}