Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 362432

Summary: [TableViewer] TableViewer's background color is not fully applied
Product: [RT] RAP Reporter: Setya Nugdjaja <jsetya>
Component: JFaceAssignee: Project Inbox <rap-inbox>
Status: RESOLVED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: ivan
Version: 1.4   
Target Milestone: ---   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
RAP TableViewer's row with short text
none
RAP TableViewer's row with long text
none
RCP TableViewer's row with short text
none
RCP TableViewer's row with long text
none
RCP (Windows) long text
none
RCP (Windows) short text
none
TableViewer after resized none

Description Setya Nugdjaja CLA 2011-10-30 10:36:59 EDT
Hi all,

When I override ColumnLabelProvider#getBackGround to draw background color, it's only drawn partially. 

Snippets:

...
@Override
public void createPartControl(Composite parent)
{
parent.setLayout(GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 5).create());

Composite container = toolkit.createComposite(parent);
container.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
container.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
	  
Button button = toolkit.createButton(container, "Short Text", SWT.PUSH);
button.addSelectionListener
(
new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
labelProvider.setLongText(false);
tableViewer.setInput(list);
tableViewer.getTable().getColumns()[0].pack();
}
}
);
	  
button = toolkit.createButton(container, "Long Text", SWT.PUSH);
button.addSelectionListener
(
new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
labelProvider.setLongText(true);
tableViewer.setInput(list);
tableViewer.getTable().getColumns()[0].pack();
}
}
);
    
Composite tableContainer = toolkit.createComposite(container);
tableContainer.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).span(2, 1).create());
	
tableViewer = new TableViewer(toolkit.createTable(tableContainer, SWT.SINGLE | SWT.BORDER));
tableViewer.getTable().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
	  
TableColumnLayout layout = new TableColumnLayout();
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
layout.setColumnData(tableViewerColumn.getColumn(), new ColumnWeightData(1, ColumnWeightData.MINIMUM_WIDTH, false));
tableContainer.setLayout(layout);
	  
tableViewer.setContentProvider(createTableContentProvider());
tableViewer.setLabelProvider(labelProvider);

for (int i = 0; i < 50; i++)
list.add(new String[]{"Item " + (i+1),"Item " + (i+1) + " so looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"});
}

private IContentProvider createTableContentProvider()
{
return new IStructuredContentProvider()
{
public void inputChanged(Viewer viewer, Object oldInput, Object newInput){}
public void dispose(){}
			
@SuppressWarnings("rawtypes")
public Object[] getElements(Object element){return element != null ? ((java.util.List)element).toArray() : new Object[]{};}
};
}
	
private static class CustomLabelProvider extends ColumnLabelProvider
{
private boolean longText;
		
void setLongText(boolean longText){this.longText = longText;}

@Override
public String getText(Object element)
{
String[] texts = (String[])element; 
					
return longText ? texts[1] : texts[0];
}

@Override
public Color getBackground(Object element)
{
return Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
}
}
...

Steps to reproduce:

1. Apply above snippet:
2. Click around 'Short Text' and 'Long Text' button.
3. Inspect that background color is applied as far as text's length.
4. Compare with TableViewer in RCP which background is fully drawn up to the TableViewer's width.

I reproduce this under 1.4.1

Best Regards,

Setya
Comment 1 Setya Nugdjaja CLA 2011-10-30 10:38:43 EDT
Created attachment 206180 [details]
RAP TableViewer's row with short text
Comment 2 Setya Nugdjaja CLA 2011-10-30 10:39:25 EDT
Created attachment 206181 [details]
RAP TableViewer's row with long text
Comment 3 Setya Nugdjaja CLA 2011-10-30 10:40:43 EDT
Created attachment 206182 [details]
RCP TableViewer's row with short text
Comment 4 Setya Nugdjaja CLA 2011-10-30 10:41:41 EDT
Created attachment 206183 [details]
RCP TableViewer's row with long text
Comment 5 Ivan Furnadjiev CLA 2011-10-31 04:24:03 EDT
Setya, could you attach a *complete* self-running snippet to reproduce it? Thanks.
Comment 6 Setya Nugdjaja CLA 2011-10-31 11:06:33 EDT
Hi,

Just realized that I forgot to include the following variable declarations to the above snippet.

private CustomLabelProvider labelProvider = new CustomLabelProvider();
private java.util.List<String[]> list = new LinkedList<String[]>();
private TableViewer tableViewer;

Regards,

Setya
Comment 7 Ivan Furnadjiev CLA 2011-10-31 11:24:48 EDT
Created attachment 206219 [details]
RCP (Windows) long text
Comment 8 Ivan Furnadjiev CLA 2011-10-31 11:25:23 EDT
Created attachment 206220 [details]
RCP (Windows) short text
Comment 9 Ivan Furnadjiev CLA 2011-10-31 11:27:21 EDT
Setya, I'm sorry, but my tests show that RAP behaves exactly the same like RCP on Windows (see attached images). I'm about to close this bug as INVALID too.
Comment 10 Setya Nugdjaja CLA 2011-10-31 11:58:51 EDT
Hi,

> Setya, I'm sorry, but my tests show that RAP behaves exactly the same like RCP
> on Windows (see attached images). I'm about to close this bug as INVALID too.

Feel free to do so.

One question tough, is there any way to make the background color expand to the maximum length of the table ?


Regards,

Setya
Comment 11 Ivan Furnadjiev CLA 2011-10-31 12:11:48 EDT
(In reply to comment #10)
> Feel free to do so.
> 
> One question tough, is there any way to make the background color expand to the
> maximum length of the table ?
To my knowledge, using ColumnLabelProvider#getBackground colorize the the corresponding column cell. If you want to expand the background color to the width of the table you have to set the column width to the table width or set the background on the Table itself.
Comment 12 Setya Nugdjaja CLA 2011-10-31 12:18:58 EDT
Hi,

> To my knowledge, using ColumnLabelProvider#getBackground colorize the the
> corresponding column cell. If you want to expand the background color to the
> width of the table you have to set the column width to the table width or set
> the background on the Table itself.

The thing is, I need to give different background color on row based on certain conditions and in my case the table contains only one column which spans the entire table's width.

Regards,

Setya
Comment 13 Ivan Furnadjiev CLA 2011-10-31 12:29:00 EDT
Setya,
could you try this:
tableViewer.getTable().addControlListener( new ControlListener() {
      public void controlResized( ControlEvent e ) {
        Table table = tableViewer.getTable();
        table.getColumns()[ 0 ].setWidth( table.getClientArea().width );
      }
      public void controlMoved( ControlEvent e ) {        
      }
    } );
Comment 14 Setya Nugdjaja CLA 2011-11-05 04:11:40 EDT
Hi Ivan,

I've added your snippet, but it behaves differently than RCP. Here's the complete snippet:

...
private FormToolkit toolkit = new FormToolkit(Display.getCurrent());
private CustomLabelProvider labelProvider = new CustomLabelProvider();
private java.util.List<String[]> list = new LinkedList<String[]>();
private TableViewer tableViewer;

@Override
public void createPartControl(Composite parent)
{
parent.setLayout(GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 5).create());

Composite container = toolkit.createComposite(parent);
container.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
container.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
  
Composite tableContainer = toolkit.createComposite(container);
tableContainer.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).span(2, 1).create());
	
tableViewer = new TableViewer(toolkit.createTable(tableContainer, SWT.SINGLE | SWT.BORDER));
tableViewer.getTable().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
	  
tableViewer.getTable().addControlListener
(
new ControlAdapter()
{
@Override
public void controlResized(ControlEvent e)
{
Table table = (Table)e.getSource();
TableColumn column = table.getColumns()[0];
					
column.setWidth(table.getClientArea().width);
}
}
);
	  
TableColumnLayout layout = new TableColumnLayout();
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
layout.setColumnData(tableViewerColumn.getColumn(), new ColumnWeightData(1, ColumnWeightData.MINIMUM_WIDTH, false));
tableContainer.setLayout(layout);
	  
tableViewer.setContentProvider(createTableContentProvider());
tableViewer.setLabelProvider(labelProvider);

for (int i = 0; i < 50; i++)
list.add(new String[]{"Item " + (i+1),"Item " + (i+1) + " so looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"});
		
tableViewer.setInput(list);
}

private IContentProvider createTableContentProvider()
{
return new IStructuredContentProvider()
{
public void inputChanged(Viewer viewer, Object oldInput, Object newInput){}
public void dispose(){}
			
@SuppressWarnings("rawtypes")
public Object[] getElements(Object element){return element != null ? ((java.util.List)element).toArray() : new Object[]{};}
};
}
	
private static class CustomLabelProvider extends ColumnLabelProvider
{
private boolean longText;
		
void setLongText(boolean longText){this.longText = longText;}

@Override
public String getText(Object element)
{
String[] texts = (String[])element; 
					
return longText ? texts[1] : texts[0];
}

@Override
public Color getBackground(Object element)
{
return Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
}
}
...

Steps to reproduce:
1. Resize editor narrow it's width.
2. Resize editor again to expand it's width.
3. Notice that there's still blank space next to the column (see screenshot).

Thanks & Regards,

Setya
Comment 15 Setya Nugdjaja CLA 2011-11-05 04:13:16 EDT
Created attachment 206488 [details]
TableViewer after resized
Comment 16 Ivan Furnadjiev CLA 2011-11-07 06:42:25 EST
Hi Setya, please use:
layout.setColumnData( column, new ColumnWeightData( table.getClientArea().width, ColumnWeightData.MINIMUM_WIDTH, false ) );
instead of:
column.setWidth( table.getClientArea().width );
in the controlResized, where the layout is the TableColumnLayout. This works for me.
Comment 17 Setya Nugdjaja CLA 2011-11-07 23:51:22 EST
Hi Ivan,

Thank you, your snippet worked for the use case.

Now when the Table is filled with texts that exceed the client area's width, how to make a horizontal scrollbar visible ?

Regards,

Setya
Comment 18 Ivan Furnadjiev CLA 2011-11-08 00:45:04 EST
(In reply to comment #17)
> Now when the Table is filled with texts that exceed the client area's width,
> how to make a horizontal scrollbar visible ?
The only idea I have is to call column.pack() when you change the texts and if column.getWidth() < table.getClientArea().width than make them equals by using the same layout.setColumnData.
Comment 19 Setya Nugdjaja CLA 2011-11-10 04:03:22 EST
Hi Ivan,

Sorry your suggestion did not work.

But I've managed to achieve both use cases using the following snippet:

...
@Override
public void createPartControl(Composite parent)
{
  parent.setLayout(GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 5).create());

  Composite container = toolkit.createComposite(parent);
  container.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
  container.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
  
  Composite tableContainer = toolkit.createComposite(container);
  tableContainer.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).span(2, 1).create());

  tableViewer = new TableViewer(toolkit.createTable(tableContainer, SWT.SINGLE | SWT.BORDER));

  TableColumnLayout layout = new TableColumnLayout() 
  {
   @Override
		protected void setColumnWidths(Scrollable tableTree, int[] originalWidths) 
		{
			Table table = (Table)tableTree;
			TextLayout textLayout = new TextLayout(table.getDisplay());

			int[] widths = new int[originalWidths.length];
			for (int index : widths)
			{
				int maxWidth = 0;
				
				for (TableItem item : table.getItems()) 
				{
					textLayout.setText(item.getText(index));

					if (textLayout.getBounds().width > maxWidth)
						maxWidth = textLayout.getBounds().width;
				}
				
				widths[index] = originalWidths[index];
				if (widths[index] < maxWidth)
				{
					widths[index] = maxWidth;
					widths[index] += 15;
				}

				if (maxWidth < table.getClientArea().width)
				{
					if (widths[index] < table.getClientArea().width)
						widths[index] = table.getClientArea().width-1;
				}
			}
			
			textLayout.dispose();

			super.setColumnWidths(tableTree, widths);
		}
	};
  layout.setColumnData(new TableViewerColumn(tableViewer, SWT.NONE).getColumn(), new ColumnWeightData(100, ColumnWeightData.MINIMUM_WIDTH, false));
  tableContainer.setLayout(layout);

	tableViewer.setContentProvider(createTableContentProvider());
	tableViewer.setLabelProvider(labelProvider);
	labelProvider.setLongText(true);

	for (int i = 0; i < 50; i++)
		list.add(new String[]{"Item " + (i+1),"Item " + (i+1) + " so looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"});
	
	tableViewer.setInput(list);
}
...

Just remark code 'labelProvider.setLongText(true)' above to see the effect.

Unfortunately I can not apply the code in RAP since it's missing TextLayout class. What's the equivalent of TextLayout class in RAP ?


Thanks & Regards,

Setya
Comment 20 Setya Nugdjaja CLA 2011-11-15 08:39:44 EST
Hi,

> 
> Unfortunately I can not apply the code in RAP since it's missing TextLayout
> class. What's the equivalent of TextLayout class in RAP ?
> 

In 1.4.1, is TextSizeUtil the way to go ?


Regards,

Setya
Comment 21 Ivan Furnadjiev CLA 2011-11-15 09:12:10 EST
(In reply to comment #20)
> In 1.4.1, is TextSizeUtil the way to go ?
TextSizeUtil is an internal class used by text size determination and you can't use it as a replacement of TextLayout. Unfortunately, there is no alternative of TextLayout in RAP.