Michael
Michael

Reputation: 27

Start to edit the newest row added in a tableviewer

I have a treeviewer with one column containing Strings. I made an "add button".

what I want is when the user add a row, I want to move the "edit cursor" to the new row.

I have 2 problems:

  1. when I add new data with

    tableViewer.add()

tableViewer.getTable().getItemCount() is not updated ! So i can't select the last row...

Plus, when I set ColumnViewerEditorActivationStrategy. I cannot select anymore with tableViewer.setSelection()

  1. I don't know how to trigger the edition mode

Here the detailled source code

public class CompositeTableViewer extends Composite {
private TableViewer tableViewer;

private List<String> columnNames;

int correctionSelection = 0;

public CompositeTableViewer(Composite parent, int style, List<String> columnNames, boolean rowAddable)
{
    this(parent, style, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER, columnNames, rowAddable);
}

public CompositeTableViewer(Composite parent, int style, int tableViewerStyle, List<String> columnNames, boolean rowAddable)
{
    super(parent, style);

    GridLayout layout = new GridLayout(3, false);
    layout.marginWidth = 4;
    this.setLayout(layout);

    this.setBackground(SWTResourceManager.getColor(SWT.COLOR_DARK_RED));
    setTableViewer(new TableViewer(this, tableViewerStyle));

    TextCellEditor columnEditor = new TextCellEditor(tableViewer.getTable());
    CellEditor[] editors = { columnEditor };
    this.columnNames = columnNames;
    tableViewer.setColumnProperties(this.columnNames.toArray(new String[this.columnNames.size()]));
    tableViewer.setContentProvider(new ArrayContentProvider());
    tableViewer.setLabelProvider(new LabelProvider());
    tableViewer.setCellEditors(editors);
    tableViewer.setCellModifier(new StringListCellModifier(this));

    //here I restricted the edit activation to double-click 
    changeColumnViewerEditorActivationStrategy();

    final Table table = tableViewer.getTable();
    table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
    table.setLinesVisible(true);

    createButtons(this, rowAddable);

}

    public void setInput(List<Object> dataList)
    {
        this.tableViewer.setInput(dataList);
    }
    /**
     * change the edition activation to double click
     * otherwise that's block multi selection :/
     * 
     */
    public TableViewerFocusCellManager changeColumnViewerEditorActivationStrategy()
    {
        TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tableViewer, new FocusCellOwnerDrawHighlighter(tableViewer));

        ColumnViewerEditorActivationStrategy activationSupport = new ColumnViewerEditorActivationStrategy(tableViewer)
        {
            protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event)
            {
                // Enable editor only with mouse double click
                if (event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION)
                {
                    EventObject source = event.sourceEvent;
                    if (source instanceof MouseEvent && ((MouseEvent) source).button == 3)
                        return false;

                    return true;
                }

                return false;
            }
        };

        TableViewerEditor.create(tableViewer, focusCellManager, activationSupport, ColumnViewerEditor.TABBING_HORIZONTAL
                | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION);

        return focusCellManager;
    }


    /**
     * Add the "Add" and "Delete" buttons
     * 
     * @param parent
     *            the parent composite
     */
    private void createButtons(Composite parent, boolean rowAddable)
    {

        // Create and configure the "Add" button
        Button add = new Button(parent, SWT.PUSH | SWT.CENTER);
        add.setText("Add");

        GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.widthHint = 80;
        add.setLayoutData(gridData);
        add.setEnabled(rowAddable);
        add.addSelectionListener(new SelectionAdapter()
        {

            public void widgetSelected(SelectionEvent e)
            {
                tableViewer.add("-_-"); // suppose to be an empty string

                int selection = CompositeTableViewer.this.tableViewer.getTable().getItemCount();

                CompositeTableViewer.this.tableViewer.setSelection(
                        new StructuredSelection(tableViewer.getElementAt(selection - 1 + correctionSelection)), true);
                tableViewer.setSelection(new StructuredSelection(CompositeTableViewer.this.tableViewer.getElementAt(selection - 1)), true);


            }
        });

        // Create and configure the "Delete" button
        Button delete = new Button(parent, SWT.PUSH | SWT.CENTER);
        delete.setText("Delete");
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.widthHint = 80;
        delete.setLayoutData(gridData);

        delete.addSelectionListener(new SelectionAdapter()
        {
            // Remove the selection and refresh the view
            public void widgetSelected(SelectionEvent e)
            {
                Object[] dataTable = (Object[]) ((IStructuredSelection) tableViewer.getSelection()).toArray();
                if (dataTable != null)
                {
                    tableViewer.remove(dataTable);
                }
            }
        });

    }
}

EDIT The problem was ArraycontentProvider can't be used for an editable table. and I should not use a list as a model. I change for a List. I put in comment my new source code

Upvotes: 1

Views: 1543

Answers (2)

pandaadb
pandaadb

Reputation: 6456

I imported your code and modified it a little bit, and there's some things that seems to be wrong from what I can see.

First, ArraycontentProvider says this in the java doc:

this implementation of IStructuredContentProvider handles the case where the viewer input is an unchanging array or collection of elements

So your first task would be to write your own content provider. This is important because you will need to update the input you've set, and this content provider will likely not do that for you.

Second, you need to add columns to make them editable. For example:

        TableViewerColumn c1 = new TableViewerColumn(tableViewer, tableViewerStyle);
        c1.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(ViewerCell cell) {
            }
        });
        c1.getColumn().setWidth(200);
        c1.setEditingSupport(new FirstNameEditingSupport(tableViewer));

This will make your column editable with a dedicated editor. (Text in that case. I stole the editor from a nice tutorial that you can find here:

http://www.vogella.com/tutorials/EclipseJFaceTableAdvanced/article.html#jfaceeditor

Now with these changes, I managed to solve your problem of adding. You will need to have a model object that you can update. In my case, I created:

public static class TestObject {

    private String text;

    public TestObject(String text) {
        this.text = text;
    }
 }

This is needed because in the editor, you will have to update the viewer's content with the edited content.

What I didn't do was to create a proper ContentProvider, so in my example I never persist my updates. However, the adding works, the double click works, and the editing works.

Now to your selection. The tableviewer add method says:

This method should be called (by the content provider) when a single element has been added to the model, in order to cause the viewer to accurately reflect the model. This method only affects the viewer, not the model. Note that there is another method for efficiently processing the simultaneous addition of multiple elements.

This comes back to your content provider. It needs to handle the fact that content has been added/edited/removed and update the model object accordingly.

This should get you started for now. Have a look at the tutorial by Lars vogel, it is very good and clear what to do. Let me know if there's more issues and i'll attempt to create a better example.

Artur

P.S.: Copy/pasting your code did not compile for me. Try providing a mini standalone example for your problem. That way it's easier to code against it and give you more detailed pointers.

Upvotes: 1

Michael
Michael

Reputation: 27

Here my new version

package features.dataManagement.entity.table.ui;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import features.dataManagement.entity.table.edit.StringEditingSupport;
import features.dataManagement.entity.table.model.RowStringContentProvider;
import features.dataManagement.entity.table.model.RowStringModel;

public class CompositeTableViewer extends Composite
{
    private TableViewer tableViewer;

    private List<String> columnNames;

    private List<RowStringModel> modelList;
    private Button addButton;

    public CompositeTableViewer(Composite parent, int style, List<String> columnNames, boolean rowAddable)
    {
        this(parent, style, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER, columnNames, rowAddable);
    }

    public CompositeTableViewer(Composite parent, int style, int tableViewerStyle, List<String> columnNames, boolean rowAddable)
    {
        super(parent, style);
        modelList = new ArrayList<RowStringModel>();
        this.columnNames = columnNames;

        GridLayout layout = new GridLayout(3, false);
        layout.marginWidth = 4;
        this.setLayout(layout);

        Composite tableComposite = new Composite(this, SWT.NONE);
        // set 3 columns for the buttons
        tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));

        setTableViewer(new TableViewer(tableComposite, tableViewerStyle));
        TableViewerColumn tableViewerColumn = createColumn(tableComposite, tableViewer, 0);
        tableViewerColumn.setEditingSupport(new StringEditingSupport(tableViewer));
        TableColumnLayout tableColumnLayout = new TableColumnLayout();
        tableColumnLayout.setColumnData(tableViewerColumn.getColumn(), new ColumnWeightData(1, 100, true));
        tableComposite.setLayout(tableColumnLayout);

        tableViewer.setContentProvider(new RowStringContentProvider(tableViewer, modelList));

        final Table table = tableViewer.getTable();
        table.setLinesVisible(true);

        createButtons(this, rowAddable);

    }

    /*
     * this is specific to my project you can directly use a
     * List<RowStringModel> modelList
     */
    public void setInput(List<Object> dataList)
    {

        List<RowStringModel> dataStringList = new ArrayList<RowStringModel>();
        for (Object str : dataList)
        {
            if (str instanceof String)
                dataStringList.add(new RowStringModel((String) str));
        }
        modelList.addAll(dataStringList);
        this.tableViewer.setInput(modelList);
    }

    /*
     * this is specific to my project you can directly use a
     * List<RowStringModel> modelList
     */
    public List<Object> getInput()
    {
        List<Object> objectsInGui = new ArrayList<Object>();

        for (RowStringModel rowStr : modelList)
        {
            objectsInGui.add(rowStr.getContent());
        }
        return objectsInGui;
    }

    public void addButtonEnable(boolean enabled)
    {
        this.addButton.setEnabled(enabled);
    }

    // create the columns for the table
    private TableViewerColumn createColumn(final Composite parent, final TableViewer viewer, int colNumber)
    {
        TableViewerColumn col = createTableViewerColumn(this.columnNames.get(colNumber), colNumber);
        col.setLabelProvider(new ColumnLabelProvider()
        {
            @Override
            public String getText(Object element)
            {
                RowStringModel rsm = (RowStringModel) element;
                return rsm.getContent();
            }

            /* slight difference for the actual lines */
            @Override
            public Color getBackground(final Object element)
            {
                if (element instanceof RowStringModel)
                {
                    return new Color(Display.getDefault(), 245, 255, 250);
                }

                return super.getBackground(element);
            }
        });

        return col;

    }

    private TableViewerColumn createTableViewerColumn(String title, final int colNumber)
    {
        final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
        final TableColumn column = viewerColumn.getColumn();
        column.setText(title);
        column.setResizable(true);
        column.setMoveable(true);
        return viewerColumn;
    }

    /**
     * Add the "Add" and "Delete" buttons
     * 
     * @param parent
     *            the parent composite
     */
    private void createButtons(Composite parent, boolean rowAddable)
    {

        // Create and configure the "Add" button
        this.addButton = new Button(parent, SWT.PUSH | SWT.CENTER);
        this.addButton.setText("Add");

        GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.widthHint = 80;
        gridData.horizontalSpan = 1;
        this.addButton.setLayoutData(gridData);
        this.addButton.setEnabled(rowAddable);
        this.addButton.addSelectionListener(new SelectionAdapter()
        {
            public void widgetSelected(SelectionEvent e)
            {
                modelList.add(new RowStringModel(""));
                tableViewer.refresh();
                CompositeTableViewer.this.setFocus();
                int selection = CompositeTableViewer.this.tableViewer.getTable().getItemCount();
                CompositeTableViewer.this.tableViewer.setSelection(new StructuredSelection(tableViewer.getElementAt(selection - 1)), true);
            }
        });

        // Create and configure the "Delete" button
        Button delete = new Button(parent, SWT.PUSH | SWT.CENTER);
        delete.setText("Delete");
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.widthHint = 80;
        delete.setLayoutData(gridData);

        delete.addSelectionListener(new SelectionAdapter()
        {
            // Remove the selection and refresh the view
            public void widgetSelected(SelectionEvent e)
            {
                Object[] dataTable = (Object[]) ((IStructuredSelection) tableViewer.getSelection()).toArray();
                if (dataTable != null)
                {
                    for (Object data : dataTable)
                    {
                        modelList.remove(data);
                    }

                    tableViewer.refresh();
                }
            }
        });

    }

    public TableViewer getTableViewer()
    {
        return tableViewer;
    }

    public void setTableViewer(TableViewer tableViewer)
    {
        this.tableViewer = tableViewer;
    }

    public List<String> getColumnNames()
    {
        return columnNames;
    }

    public void setColumnNames(List<String> columnNames)
    {
        this.columnNames = columnNames;
    }

}

RowStringModel

package features.dataManagement.entity.table.model;

public class RowStringModel
{
    private String content;

    public RowStringModel(String content)
    {
        super();
        this.content = content;
    }

    public String getContent()
    {
        return content;
    }

    public void setContent(String content)
    {
        this.content = content;
    }

}

StringEditingSupport

package features.dataManagement.entity.table.edit;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;

import features.dataManagement.entity.table.model.RowStringModel;

public class StringEditingSupport extends EditingSupport
{

  private final TableViewer viewer;
  private final CellEditor editor;

    public StringEditingSupport(TableViewer viewer)
    {
    super(viewer);
    this.viewer = viewer;
    this.editor = new TextCellEditor(viewer.getTable());
  }

  @Override
  protected CellEditor getCellEditor(Object element) {
    return editor;
  }

  @Override
  protected boolean canEdit(Object element) {
    return true;
  }

  @Override
  protected Object getValue(Object element) {
        return ((RowStringModel) element).getContent();
  }

  @Override
  protected void setValue(Object element, Object userInputValue) {
      ((RowStringModel) element).setContent(String.valueOf(userInputValue));
    viewer.update(element, null);
  }
}

RowStringContentProvider

package features.dataManagement.entity.table.model;

import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;

public class RowStringContentProvider implements IStructuredContentProvider, IItemModelListViewer<RowStringModel>
{
    private TableViewer tableViewer;
    private List<RowStringModel> modelList;

    public RowStringContentProvider(TableViewer tableViewer, List<RowStringModel> modelList)
    {
        this.tableViewer = tableViewer;
        this.modelList = modelList;
    }

    public void inputChanged(Viewer v, Object oldInput, Object newInput)
    {
    }

    public void dispose()
    {
    }

    // Return the tasks as an array of Objects
    public Object[] getElements(Object parent)
    {
        return modelList.toArray();
    }


    public void addItemModel(RowStringModel itemModel)
    {
        tableViewer.add(itemModel);
    }

    @Override
    public void removeItemModel(RowStringModel itemModel)
    {
        tableViewer.remove(itemModel);

    }

    @Override
    public void updateItemModel(RowStringModel itemModel)
    {
        tableViewer.update(itemModel, null);

    }

}

Upvotes: 0

Related Questions