blob: 1ac5939dcc03a450952975c48d29b245a7a1a0bc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2013 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Wind River Systems - initial API and implementation
* IBM Corporation - bug fixing
*******************************************************************************/
package org.eclipse.debug.tests.viewer.model;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.function.Function;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.tests.AbstractDebugTest;
import org.eclipse.debug.tests.TestUtil;
import org.eclipse.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.XMLMemento;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Tests to verify that the viewer properly handles initial columns width.
*/
public class ColumnPresentationTests extends AbstractDebugTest implements ITestModelUpdatesListenerConstants {
private Display fDisplay;
private Shell fShell;
private TreeModelViewer fViewer;
private TestModelUpdatesListener fListener;
private boolean fResized = false;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
createViewer();
}
@Override
@After
public void tearDown() throws Exception {
destroyViewer();
super.tearDown();
}
void createViewer() {
fDisplay = PlatformUI.getWorkbench().getDisplay();
fShell = new Shell(fDisplay);
fShell.setSize(800, 600);
fShell.setLayout(new FillLayout());
fViewer = new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer")); //$NON-NLS-1$
fViewer.getTree().addControlListener(new ControlListener() {
@Override
public void controlResized(ControlEvent e) {
fResized = true;
}
@Override
public void controlMoved(ControlEvent e) {
}
});
fListener = new TestModelUpdatesListener(fViewer, false, false);
fShell.open();
TestUtil.processUIEvents();
}
void destroyViewer() throws Exception {
fListener.dispose();
fViewer.getPresentationContext().dispose();
// Close the shell.
fShell.close();
TestUtil.processUIEvents();
}
void recreateViewer() throws Exception {
destroyViewer();
createViewer();
}
static class MyColumnPresentation implements IColumnPresentation {
private IPresentationContext fContext;
protected String[] columnIds;
MyColumnPresentation() {
this (makeDefaultColumnIds());
}
static String[] makeDefaultColumnIds() {
String[] columnIds = new String[5];
for (int i = 0; i < columnIds.length; i++) {
columnIds[i] = "ColumnId_" + i; //$NON-NLS-1$
}
return columnIds;
}
MyColumnPresentation(String[] columnIds) {
this.columnIds = columnIds;
}
@Override
public void init(IPresentationContext context) {
fContext = context;
}
@Override
public void dispose() {
fContext = null;
}
@Override
public ImageDescriptor getImageDescriptor(String id) {
return null;
}
protected IPresentationContext getPresentationContext() {
return fContext;
}
@Override
public String[] getAvailableColumns() {
return columnIds;
}
@Override
public String[] getInitialColumns() {
return columnIds;
}
@Override
public String getHeader(String id) {
if (Arrays.asList(columnIds).indexOf(id) != -1) {
return id;
}
return null;
}
@Override
public String getId() {
return "MyColumnPresentationID"; //$NON-NLS-1$
}
@Override
public boolean isOptional() {
return true;
}
}
static class MyColumnPresentation2 extends MyColumnPresentation implements IColumnPresentation2 {
int[] repliedWidths;
MyColumnPresentation2() {
super();
for (int i = 0; i < columnIds.length; i++) {
columnIds[i] += "_2"; //$NON-NLS-1$
}
repliedWidths = new int[columnIds.length];
Arrays.fill(repliedWidths, -2);
}
@Override
public int getInitialColumnWidth(String id, int treeWidgetWidth,
String[] visibleColumnIds) {
for (int i = 0; i < columnIds.length; i++) {
if (id.equals(columnIds[i]) && i == 0) {
repliedWidths[i] = 2 * (treeWidgetWidth / visibleColumnIds.length);
return repliedWidths[i];
}
if (id.equals(columnIds[i]) && (i == 1 || i == 2)) {
repliedWidths[i] = (treeWidgetWidth / visibleColumnIds.length) / 2;
return repliedWidths[i];
}
if (id.equals(columnIds[i]) && i == 3) {
repliedWidths[i] = (treeWidgetWidth / visibleColumnIds.length);
return repliedWidths[i];
}
if (id.equals(columnIds[i]) && i == 4) {
repliedWidths[i] = -1;
return repliedWidths[i];
}
}
return -1;
}
@Override
public String getId() {
return "MyColumnPresentation2ID"; //$NON-NLS-1$
}
}
static class MyModel extends TestModel implements IColumnPresentationFactory {
MyColumnPresentation colPresenation;
MyModel(MyColumnPresentation cp1) {
colPresenation = cp1;
}
@Override
public IColumnPresentation createColumnPresentation(
IPresentationContext context, Object element) {
if (colPresenation != null) {
return colPresenation;
}
return null;
}
@Override
public String getColumnPresentationId(IPresentationContext context,
Object element) {
if (colPresenation != null) {
return colPresenation.getId();
}
return null;
}
}
private TestModel makeModel(MyColumnPresentation cp, String rootSufffix) throws Exception {
MyModel model = new MyModel(cp);
model.setRoot(new TestElement(model, "root" + rootSufffix, new TestElement[] { //$NON-NLS-1$
new TestElement(model, "1", true, true, new TestElement[0]), //$NON-NLS-1$
new TestElement(model, "2", true, false, new TestElement[0]), //$NON-NLS-1$
new TestElement(model, "3", false, true, new TestElement[0]), //$NON-NLS-1$
new TestElement(model, "4", false, false, new TestElement[0]), //$NON-NLS-1$
new TestElement(model, "5", new TestElement[0]), //$NON-NLS-1$
new TestElement(model, "6", new TestElement[0]) })); //$NON-NLS-1$
fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
fViewer.setInput(model.getRootElement());
waitWhile(t -> !fListener.isFinished(), createListenerErrorMessage());
model.validateData(fViewer, TreePath.EMPTY);
return model;
}
/**
* In this test: verify that tree viewer can handle IColumnPresentation
* implementation without requiring the presentation being
* IColumnPresentation2 (i.e. ensure we do not break backward compatibility
* of interface). Also, we verify that the initial columns width is the
* average of tree width / number of visible columns, which is the logic in
* InternalTreeModelViewer.
*/
@Test
public void testInitialColumnAverageWidth() throws Exception {
fResized = false;
MyColumnPresentation colPre = new MyColumnPresentation();
makeModel(colPre, "m1"); //$NON-NLS-1$
Tree tree = fViewer.getTree();
TreeColumn[] columns = tree.getColumns();
int treeWidth = tree.getSize().x;
int avgWidth = treeWidth / columns.length;
// Resizing the tree invalidates the test.
if (fResized) {
return;
}
for (int i = 0; i < columns.length - 1; i++) {
assertEquals(avgWidth, columns[i].getWidth());
}
// Checking of the width of the last column is not reliable.
// I.e. it's handled differenty on different platforms.
//int remainder = treeWidth % columns.length;
//assertEquals(avgWidth + remainder, columns[columns.length - 1].getWidth());
}
/**
* In this test: verify that tree viewer can handle IColumnPresentation2.
* Also, we verify that the initial columns width is the width computed by
* the IColumnPresentation2 implementation.
*/
@Test
public void testInitialColumnWidth() throws Exception {
fResized = false;
MyColumnPresentation2 colPre = new MyColumnPresentation2();
makeModel(colPre, "m2"); //$NON-NLS-1$
Tree tree = fViewer.getTree();
TreeColumn[] columns = tree.getColumns();
// Resizing the tree invalidates the test.
if (fResized) {
return;
}
for (int i = 0; i < columns.length; i++) {
int width = colPre.repliedWidths[i];
if (width != -1) {
assertEquals(width, columns[i].getWidth());
}
}
}
/**
* In this test: verify that tree viewer can handle IColumnPresentation2.
* Also, we verify that the initial columns width from IColumnPresentation2
* is not used when there are user settings inside the viewer which are
* created from user resizing columns.
*/
@Test
public void testRespectUserSettings() throws Exception {
MyColumnPresentation2 colPre = new MyColumnPresentation2();
makeModel(colPre, "m2"); //$NON-NLS-1$
TreeColumn[] columns = fViewer.getTree().getColumns();
// simulate user resizing each column width
int[] newWidths = new int[columns.length];
for (int i = 0; i < columns.length; i++) {
newWidths[i] = columns[i].getWidth() + 10;
columns[i].setWidth(newWidths[i]);
}
for (int i = 0; i < columns.length; i++) {
assertEquals(newWidths[i], columns[i].getWidth());
}
// get InternalTreeModelViewer to rebuild columns due to change of
// model and presentation - first set to another model and column
// presentation, then switch to a model with original presentation.
makeModel(new MyColumnPresentation(), "m1"); //$NON-NLS-1$
makeModel(colPre, "m3"); //$NON-NLS-1$
// verify user resized widths are used instead of the initial widths from IColumnPresentation2
columns = fViewer.getTree().getColumns();
for (int i = 0; i < columns.length; i++) {
assertEquals(newWidths[i], columns[i].getWidth());
}
// get InternalTreeModelViewer to rebuild columns due to hide and show columns
fViewer.setShowColumns(false);
TestUtil.processUIEvents();
waitWhile(t -> fViewer.getTree().getColumns().length > 0, createColumnsErrorMessage());
fViewer.setShowColumns(true);
TestUtil.processUIEvents();
waitWhile(t -> fViewer.getTree().getColumns().length != newWidths.length, createColumnsErrorMessage());
// verify user resized widths are used instead of the initial widths from IColumnPresentation2
columns = fViewer.getTree().getColumns();
for (int i = 0; i < columns.length; i++) {
assertEquals(newWidths[i], columns[i].getWidth());
}
}
/**
* In this test: verify that tree viewer can handle IColumnPresentation2.
* Also, we verify that the initial columns width from IColumnPresentation2
* is not used when there are user settings inside the viewer which are
* restored from memento, e.g., restoring workspace, etc.
*/
@Test
public void testRespectMemento() throws Exception {
MyColumnPresentation2 colPre = new MyColumnPresentation2();
makeModel(colPre, "m2"); //$NON-NLS-1$
TreeColumn[] columns = fViewer.getTree().getColumns();
// simulate user resizing each column width
int[] newWidths = new int[columns.length];
for (int i = 0; i < columns.length; i++) {
newWidths[i] = columns[i].getWidth() + 10;
columns[i].setWidth(newWidths[i]);
}
for (int i = 0; i < columns.length; i++) {
assertEquals(newWidths[i], columns[i].getWidth());
}
// save memento
final XMLMemento memento = XMLMemento.createWriteRoot("TEST"); //$NON-NLS-1$
fViewer.saveState(memento);
// throw away any settings inside the viewer and create a new viewer
// with memento settings, this is the same effect resulted from closing
// and opening workspace again.
recreateViewer();
fViewer.initState(memento);
// get InternalTreeModelViewer to rebuild columns
makeModel(colPre, "m2"); //$NON-NLS-1$
// verify widths from memento are used instead of the initial widths from IColumnPresentation2
columns = fViewer.getTree().getColumns();
for (int i = 0; i < columns.length; i++) {
assertEquals(newWidths[i], columns[i].getWidth());
}
}
/**
* In this test: verify that tree viewer can handle the column presentation
* changing its available column IDs between runs (bug 360015).
*/
@Test
public void testChangedColumnIds() throws Exception {
MyColumnPresentation colPre = new MyColumnPresentation();
makeModel(colPre, "m1"); //$NON-NLS-1$
TreeColumn[] columns = fViewer.getTree().getColumns();
// Select visible columns
fViewer.setVisibleColumns(new String[] { colPre.columnIds[0] });
TestUtil.processUIEvents();
waitWhile(t -> fViewer.getTree().getColumns().length != 1, createColumnsErrorMessage());
// get InternalTreeModelViewer to rebuild columns due to change of
// model and presentation - first set to another model and column
// presentation, then switch to a model with original presentation.
makeModel(new MyColumnPresentation2(), "m2"); //$NON-NLS-1$
String[] newColumnIds = MyColumnPresentation.makeDefaultColumnIds();
newColumnIds[0] = "new_column_id"; //$NON-NLS-1$
colPre = new MyColumnPresentation(newColumnIds);
makeModel(colPre, "m3"); //$NON-NLS-1$
// verify user resized widths are used instead of the initial widths from IColumnPresentation2
columns = fViewer.getTree().getColumns();
for (int i = 0; i < columns.length; i++) {
assertEquals(newColumnIds[i], columns[i].getText());
}
}
private Function<AbstractDebugTest, String> createColumnsErrorMessage() {
return t -> "Unexpected columns number: " + fViewer.getTree().getColumns().length;
}
private Function<AbstractDebugTest, String> createListenerErrorMessage() {
return t -> "Listener not finished: " + fListener;
}
}