com.github.fengtan.sophie.tables.AbstractSortableTable.java Source code

Java tutorial

Introduction

Here is the source code for com.github.fengtan.sophie.tables.AbstractSortableTable.java

Source

/**
 * Sophie - A Solr browser and administration tool
 * 
 * Copyright (C) 2016 fengtan<https://github.com/fengtan>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.github.fengtan.sophie.tables;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import com.github.fengtan.sophie.Sophie;
import com.github.fengtan.sophie.beans.SophieException;

/**
 * Instantiate a non-virtual table and provide a sortable behavior. Subclasses
 * are expected to use the protected methods in this class to add columns/rows.
 */
public abstract class AbstractSortableTable {

    /**
     * Table.
     */
    private Table table;

    /**
     * List of column names.
     */
    private List<String> columnNames = new ArrayList<String>();

    /**
     * List of rows, each row being represented by a map of values keyed by
     * column name.
     */
    private List<Map<String, String>> rowValues = new ArrayList<Map<String, String>>();

    /**
     * Whether the table is currently sorted in ascending order or not.
     */
    private boolean sortAsc = true;

    /**
     * Name of the column currently sorted (null if the table is not sorted).
     */
    private String sortColumnName;

    /**
     * Instantiate a non-virtual table and provide a sortable behavior.
     * 
     * @param composite
     *            Parent composite.
     * @param listener
     *            Selection listener to attach to the table, or null.
     */
    public AbstractSortableTable(Composite composite, SelectionListener listener) {
        // Instantiate table.
        int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.HIDE_SELECTION
                | SWT.VIRTUAL;
        table = new Table(composite, style);

        // Set layout.
        GridData gridData = new GridData(GridData.FILL_BOTH);
        gridData.grabExcessVerticalSpace = true;
        table.setLayoutData(gridData);

        // Set style.
        table.setLinesVisible(true);
        table.setHeaderVisible(true);

        // Attach selection listener, if one was provided.
        if (listener != null) {
            table.addSelectionListener(listener);
        }
    }

    /**
     * Instantiate a non-virtual table and provide a sortable behavior.
     * 
     * @param composite
     *            Parent composite.
     */
    public AbstractSortableTable(Composite composite) {
        this(composite, null);
    }

    /**
     * Whether the table already contains a column with a specific name.
     * 
     * @param columnName
     *            Column name.
     * @return True if the table already contains a column with this name, false
     *         otherwise.
     */
    protected boolean hasColumn(String columnName) {
        return columnNames.contains(columnName);
    }

    /**
     * Add a new column to the table.
     * 
     * @param columnName
     *            Column name.
     * @return The newly created column.
     */
    protected TableColumn addColumn(final String columnName) {
        // Add column name to our internal list.
        columnNames.add(columnName);

        // Instantiate column.
        final TableColumn column = new TableColumn(table, SWT.LEFT);
        column.setData("columnName", columnName);
        column.setText(columnName + "     ");
        column.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                // Clicking on the current sort field toggles the direction.
                // Clicking on a new field changes the sort field.
                if (StringUtils.equals(sortColumnName, columnName)) {
                    sortAsc = !sortAsc;
                } else {
                    sortColumnName = columnName;
                }
                Comparator<Map<String, String>> comparator = new Comparator<Map<String, String>>() {
                    @Override
                    public int compare(Map<String, String> rowValues1, Map<String, String> rowValues2) {
                        String value1 = rowValues1.get(columnName);
                        String value2 = rowValues2.get(columnName);
                        if (sortAsc) {
                            return (value1 == null) ? -1 : value1.compareTo(value2);
                        } else {
                            return (value2 == null) ? -1 : value2.compareTo(value1);
                        }
                    }
                };
                Collections.sort(rowValues, comparator);
                table.removeAll();
                for (Map<String, String> values : rowValues) {
                    createRow(values);
                }
                setSortSignifier();
            }
        });

        // Pack.
        column.pack();
        return column;
    }

    /**
     * Set sort signifier on the sorted column. Clear sort signifier on the
     * other columns.
     */
    private void setSortSignifier() {
        for (TableColumn column : table.getColumns()) {
            String name = (String) column.getData("columnName");
            char signifier = sortAsc ? Sophie.SIGNIFIER_SORTED_ASC : Sophie.SIGNIFIER_SORTED_DESC;
            column.setText(name + (StringUtils.equals(sortColumnName, name) ? " " + signifier : StringUtils.EMPTY));
        }
    }

    /**
     * Add a new row to the table.
     * 
     * @param values
     *            Row values keyed by column name.
     * @return The newly created row.
     */
    protected TableItem addRow(Map<String, String> values) {
        // Add row to our internal list.
        rowValues.add(values);

        // Instantiate row.
        return createRow(values);
    }

    /**
     * Instantiate a new row.
     * 
     * @param values
     *            Row values keyed by column name.
     * @return The newly created row.
     */
    private TableItem createRow(Map<String, String> values) {
        TableItem item = new TableItem(table, SWT.NULL);
        for (Map.Entry<String, String> value : values.entrySet()) {
            item.setText(columnNames.indexOf(value.getKey()), value.getValue());
        }
        return item;
    }

    /**
     * Clear the table and re-populate it.
     * 
     * @throws SophieException
     *             If the table could not be populated.
     */
    public void refresh() throws SophieException {
        rowValues = new ArrayList<Map<String, String>>();
        sortAsc = true;
        sortColumnName = null;
        setSortSignifier();
        table.removeAll();
        populate();
        // Let selection listeners know that no row is now selected.
        // This allows toolbar buttons that require a row to be selected to
        // become disabled.
        Event event = new Event();
        event.widget = table;
        event.display = table.getDisplay();
        event.type = SWT.DefaultSelection;
        table.notifyListeners(SWT.DefaultSelection, event);
    }

    /**
     * Populate the table with columns/rows.
     * 
     * @throws SophieException
     *             If the table could not be populated.
     */
    protected abstract void populate() throws SophieException;

    /**
     * Get the currently selected row.
     * 
     * @return Currently selected row.
     */
    protected TableItem[] getTableSelection() {
        return table.getSelection();
    }

}