Package org.drools.guvnor.client.widgets.decoratedgrid

Source Code of org.drools.guvnor.client.widgets.decoratedgrid.VerticalMergableGridWidget

/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.drools.guvnor.client.widgets.decoratedgrid;

import java.util.List;
import java.util.Set;

import org.drools.guvnor.client.widgets.decoratedgrid.DecoratedGridWidget.MOVE_DIRECTION;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.Event;

/**
* A Vertical implementation of MergableGridWidget, that renders columns as erm,
* columns and rows as rows. Supports merging of cells between rows.
*
* @author manstis
*
*/
public class VerticalMergableGridWidget<T> extends MergableGridWidget<T> {

    protected DecoratedGridWidget<T> grid;

    public VerticalMergableGridWidget(final DecoratedGridWidget<T> grid,
                                      final DynamicData data,
                                      final List<DynamicColumn<T>> columns) {
        super( data,
               columns );
        this.grid = grid;
    }

    @Override
    public void deleteRow(int index) {
        if ( index < 0 ) {
            throw new IllegalArgumentException(
                                                "Index cannot be less than zero." );
        }
        if ( index > grid.getData().size() ) {
            throw new IllegalArgumentException(
                                                "Index cannot be greater than the number of rows." );
        }

        grid.getSidebarWidget().deleteSelector( index );
        tbody.deleteRow( index );
        fixRowStyles( index );
    }

    @Override
    public void deselectCell(CellValue< ? extends Comparable< ? >> cell) {
        if ( cell == null ) {
            throw new IllegalArgumentException( "cell cannot be null" );
        }

        Coordinate hc = cell.getHtmlCoordinate();
        TableRowElement tre = tbody.getRows().getItem( hc.getRow() )
                .<TableRowElement> cast();
        TableCellElement tce = tre.getCells().getItem( hc.getCol() )
                .<TableCellElement> cast();

        String cellSelectedStyle = style.cellTableCellSelected();
        tce.removeClassName( cellSelectedStyle );
    }

    @Override
    public void hideColumn(int index) {
        if ( index < 0 ) {
            throw new IllegalArgumentException( "index cannot be less than zero" );
        }
        if ( index > columns.size() ) {
            throw new IllegalArgumentException( "index cannot be greater than the number of rows" );
        }

        for ( int iRow = 0; iRow < grid.getData().size(); iRow++ ) {
            DynamicDataRow rowData = grid.getData().get( iRow );
            CellValue< ? extends Comparable< ? >> cell = rowData.get( index );

            if ( cell.getRowSpan() > 0 ) {
                Coordinate hc = cell.getHtmlCoordinate();
                TableRowElement tre = tbody.getRows().getItem( hc.getRow() );
                TableCellElement tce = tre.getCells().getItem( hc.getCol() );
                tre.removeChild( tce );
            }
        }
    }

    @Override
    public void insertRowBefore(int index,
                                DynamicDataRow rowData) {
        if ( index < 0 ) {
            throw new IllegalArgumentException(
                                                "Index cannot be less than zero." );
        }
        if ( index > grid.getData().size() ) {
            throw new IllegalArgumentException(
                                                "Index cannot be greater than the number of rows." );
        }
        if ( rowData == null ) {
            throw new IllegalArgumentException( "Row data cannot be null" );
        }
        if ( rowData.size() != columns.size() ) {
            throw new IllegalArgumentException( "rowData contains a different number of columns to the grid" );
        }

        grid.getSidebarWidget().insertSelectorBefore( rowData,
                                                        index );
        TableRowElement newRow = tbody.insertRow( index );
        populateTableRowElement( newRow,
                                 rowData );
        fixRowStyles( index );
    }

    @Override
    public void onBrowserEvent(Event event) {

        String eventType = event.getType();

        // Get the event target.
        EventTarget eventTarget = event.getEventTarget();
        if ( !Element.is( eventTarget ) ) {
            return;
        }
        Element target = event.getEventTarget().cast();

        // Find the cell where the event occurred.
        TableCellElement tableCell = findNearestParentCell( target );
        if ( tableCell == null ) {
            return;
        }
        int htmlCol = tableCell.getCellIndex();

        Element trElem = tableCell.getParentElement();
        if ( trElem == null ) {
            return;
        }
        TableRowElement tr = TableRowElement.as( trElem );
        int htmlRow = tr.getSectionRowIndex();

        // Convert HTML coordinates to physical coordinates
        DynamicDataRow htmlRowData = data.get( htmlRow );
        CellValue< ? extends Comparable< ? >> htmlCell = htmlRowData.get( htmlCol );
        Coordinate c = htmlCell.getPhysicalCoordinate();
        CellValue< ? extends Comparable< ? >> physicalCell = data.get( c.getRow() ).get( c.getCol() );

        // Select range
        if ( eventType.equals( "click" ) ) {
            grid.startSelecting( c );
        }

        // Keyboard navigation
        if ( eventType.equals( "keypress" ) ) {
            if ( event.getKeyCode() == KeyCodes.KEY_DELETE ) {
                grid.update( null );
            } else if ( event.getKeyCode() == KeyCodes.KEY_RIGHT
                        || (event.getKeyCode() == KeyCodes.KEY_TAB && !event
                                .getShiftKey()) ) {
                grid.moveSelection( MOVE_DIRECTION.RIGHT );
                event.preventDefault();
            } else if ( event.getKeyCode() == KeyCodes.KEY_LEFT
                        || (event.getKeyCode() == KeyCodes.KEY_TAB && event
                                .getShiftKey()) ) {
                grid.moveSelection( MOVE_DIRECTION.LEFT );
                event.preventDefault();
            } else if ( event.getKeyCode() == KeyCodes.KEY_UP ) {
                grid.moveSelection( MOVE_DIRECTION.UP );
                event.preventDefault();
            } else if ( event.getKeyCode() == KeyCodes.KEY_DOWN ) {
                grid.moveSelection( MOVE_DIRECTION.DOWN );
                event.preventDefault();
            }
        }
        // Enter key is a special case; as the selected cell needs to be
        // sent events and not the cell that GWT deemed the target for
        // events.
        if ( eventType.equals( "keydown" ) ) {
            if ( event.getKeyCode() == KeyCodes.KEY_ENTER ) {

                physicalCell = grid.getSelections().first();
                c = physicalCell.getCoordinate();
                tableCell = tbody.getRows()
                        .getItem( physicalCell.getHtmlCoordinate().getRow() )
                        .getCells()
                        .getItem( physicalCell.getHtmlCoordinate().getCol() );
            }
        }

        // Pass event and physical cell to Cell Widget for handling
        Cell<CellValue< ? extends Comparable< ? >>> cellWidget = grid
                .getColumns().get( c.getCol() ).getCell();

        // Implementations of AbstractCell aren't forced to initialise
        // consumed events
        Set<String> consumedEvents = cellWidget.getConsumedEvents();
        if ( consumedEvents != null
             && consumedEvents.contains( eventType ) ) {
            Context context = new Context( c.getRow(),
                                           c.getCol(),
                                           c );
            cellWidget.onBrowserEvent( context,
                                       tableCell.getFirstChildElement(),
                                       physicalCell,
                                       event,
                                       null );
        }
    }

    @Override
    public void redraw() {

        // Prepare sidebar
        grid.getSidebarWidget().initialise();

        TableSectionElement nbody = Document.get().createTBodyElement();

        for ( int iRow = 0; iRow < grid.getData().size(); iRow++ ) {

            // Add a selector for each row
            DynamicDataRow rowData = grid.getData().get( iRow );
            grid.getSidebarWidget().appendSelector( rowData );

            TableRowElement tre = Document.get().createTRElement();
            tre.setClassName( getRowStyle( iRow ) );

            populateTableRowElement( tre,
                                     rowData );
            nbody.appendChild( tre );

        }

        // Update table to DOM
        table.replaceChild( nbody,
                            tbody );
        tbody = nbody;

    }

    @Override
    public void redrawColumn(int index) {
        if ( index < 0 ) {
            throw new IllegalArgumentException(
                                                "index cannot be less than zero." );
        }
        if ( index > grid.getColumns().size() ) {
            throw new IllegalArgumentException(
                                                "index cannot be greater than the number of defined columns." );
        }

        for ( int iRow = 0; iRow < grid.getData().size(); iRow++ ) {
            TableRowElement tre = tbody.getRows().getItem( iRow );
            DynamicDataRow rowData = grid.getData().get( iRow );
            redrawTableRowElement( rowData,
                                   tre,
                                   index,
                                   index );
        }

    }

    @Override
    public void redrawColumns(int startRedrawIndex,
                              int endRedrawIndex) {
        if ( startRedrawIndex < 0 ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be less than zero." );
        }
        if ( startRedrawIndex > grid.getColumns().size() ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be greater than the number of defined columns." );
        }
        if ( endRedrawIndex < 0 ) {
            throw new IllegalArgumentException(
                                                "endRedrawIndex cannot be less than zero." );
        }
        if ( endRedrawIndex > grid.getColumns().size() ) {
            throw new IllegalArgumentException(
                                                "endRedrawIndex cannot be greater than the number of defined columns." );
        }
        if ( startRedrawIndex > endRedrawIndex ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be greater than endRedrawIndex." );
        }

        for ( int iRow = 0; iRow < grid.getData().size(); iRow++ ) {
            TableRowElement tre = tbody.getRows().getItem( iRow );
            DynamicDataRow rowData = grid.getData().get( iRow );
            redrawTableRowElement( rowData,
                                   tre,
                                   startRedrawIndex,
                                   endRedrawIndex );
        }
    }

    @Override
    public void redrawRows(int startRedrawIndex,
                           int endRedrawIndex) {
        if ( startRedrawIndex < 0 ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be less than zero." );
        }
        if ( startRedrawIndex > grid.getData().size() ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be greater than the number of rows in the table." );
        }
        if ( endRedrawIndex < 0 ) {
            throw new IllegalArgumentException(
                                                "endRedrawIndex cannot be less than zero." );
        }
        if ( endRedrawIndex > grid.getData().size() ) {
            throw new IllegalArgumentException(
                                                "endRedrawIndex cannot be greater than the number of rows in the table." );
        }
        if ( startRedrawIndex > endRedrawIndex ) {
            throw new IllegalArgumentException(
                                                "startRedrawIndex cannot be greater than endRedrawIndex." );
        }

        for ( int iRow = startRedrawIndex; iRow <= endRedrawIndex; iRow++ ) {
            TableRowElement newRow = Document.get().createTRElement();
            DynamicDataRow rowData = grid.getData().get( iRow );
            populateTableRowElement( newRow,
                                     rowData );
            tbody.replaceChild( newRow,
                                tbody.getChild( iRow ) );
        }
        fixRowStyles( startRedrawIndex );
    }

    @Override
    public void resizeColumn(DynamicColumn< ? > col,
                             int width) {
        if ( col == null ) {
            throw new IllegalArgumentException( "col cannot be null" );
        }
        if ( width < 0 ) {
            throw new IllegalArgumentException( "width cannot be less than zero" );
        }

        col.setWidth( width );
        int iCol = col.getColumnIndex();
        for ( DynamicDataRow row : grid.getData() ) {
            CellValue< ? extends Comparable< ? >> cell = row
                    .get( iCol );
            Coordinate c = cell.getHtmlCoordinate();
            TableRowElement tre = tbody.getRows().getItem(
                                                           c.getRow() );
            TableCellElement tce = tre.getCells().getItem(
                                                           c.getCol() );
            tce.getFirstChild().<DivElement> cast().getStyle()
                    .setWidth( width,
                               Unit.PX );
        }

        // Resizing columns can cause the scrollbar to appear
        grid.assertDimensions();

    }

    @Override
    public void selectCell(CellValue< ? extends Comparable< ? >> cell) {
        if ( cell == null ) {
            throw new IllegalArgumentException( "cell cannot be null" );
        }

        Coordinate hc = cell.getHtmlCoordinate();
        TableRowElement tre = tbody.getRows().getItem( hc.getRow() )
                .<TableRowElement> cast();
        TableCellElement tce = tre.getCells().getItem( hc.getCol() )
                .<TableCellElement> cast();

        String cellSelectedStyle = style.cellTableCellSelected();
        tce.addClassName( cellSelectedStyle );
        tce.focus();
    }

    @Override
    public void showColumn(int index) {
        if ( index < 0 ) {
            throw new IllegalArgumentException( "index cannot be less than zero" );
        }
        if ( index > columns.size() ) {
            throw new IllegalArgumentException( "index cannot be greater than the number of rows" );
        }

        for ( int iRow = 0; iRow < grid.getData().size(); iRow++ ) {
            DynamicDataRow rowData = grid.getData().get( iRow );
            TableCellElement tce = makeTableCellElement( index,
                                                         rowData );
            if ( tce != null ) {

                CellValue< ? extends Comparable< ? >> cell = rowData.get( index );
                Coordinate hc = cell.getHtmlCoordinate();

                TableRowElement tre = tbody.getRows().getItem( hc.getRow() );
                TableCellElement ntce = tre.insertCell( hc.getCol() );
                tre.replaceChild( tce,
                                  ntce );
            }
        }
    }

    // Find the cell that contains the element. Note that the TD element is not
    // the parent. The parent is the div inside the TD cell.
    private TableCellElement findNearestParentCell(Element elem) {
        while ( (elem != null)
                && (elem != table) ) {
            String tagName = elem.getTagName();
            if ( "td".equalsIgnoreCase( tagName )
                    || "th".equalsIgnoreCase( tagName ) ) {
                return elem.cast();
            }
            elem = elem.getParentElement();
        }
        return null;
    }

    // Row styles need to be re-applied after inserting and deleting rows
    private void fixRowStyles(int iRow) {
        while ( iRow < tbody.getChildCount() ) {
            Element e = Element.as( tbody.getChild( iRow ) );
            TableRowElement tre = TableRowElement.as( e );
            tre.setClassName( getRowStyle( iRow ) );
            iRow++;
        }
    }

    // Get style applicable to row
    private String getRowStyle(int iRow) {
        String evenRowStyle = style.cellTableEvenRow();
        String oddRowStyle = style.cellTableOddRow();
        boolean isEven = iRow % 2 == 0;
        String trClasses = isEven ? evenRowStyle : oddRowStyle;
        return trClasses;
    }

    // Build a TableCellElement
    private TableCellElement makeTableCellElement(int iCol,
                                                  DynamicDataRow rowData) {

        String cellStyle = style.cellTableCell();
        String divStyle = style.cellTableCellDiv();
        String cellSelectedStyle = style.cellTableCellSelected();
        TableCellElement tce = null;

        // Column to render the column
        DynamicColumn< ? > column = grid.getColumns().get( iCol );

        CellValue< ? extends Comparable< ? >> cellData = rowData.get( iCol );
        int rowSpan = cellData.getRowSpan();
        if ( rowSpan > 0 ) {

            // Use Elements rather than Templates as it's easier to set
            // attributes that need to be dynamic
            tce = Document.get().createTDElement();
            DivElement div = Document.get().createDivElement();
            if ( cellData.isSelected() ) {
                tce.addClassName( cellSelectedStyle );
            }
            tce.addClassName( cellStyle );
            div.setClassName( divStyle );

            // Dynamic attributes!
            div.getStyle().setWidth( column.getWidth(),
                                     Unit.PX );
            div.getStyle().setHeight( Math.floor( style.rowHeight() * 0.95 ),
                                      Unit.PX );
            tce.getStyle().setHeight( style.rowHeight()
                                              * rowSpan,
                                      Unit.PX );
            tce.setRowSpan( rowSpan );

            // Render the cell and set inner HTML
            Coordinate c = cellData.getCoordinate();
            Context context = new Context( c.getRow(),
                                           c.getCol(),
                                           c );
            SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
            column.render( context,
                           rowData,
                           cellBuilder );
            div.setInnerHTML( cellBuilder.toSafeHtml().asString() );

            // Construct the table
            tce.appendChild( div );
            tce.setTabIndex( 0 );
        }
        return tce;

    }

    // Populate the content of a TableRowElement. This is used to populate
    // new, empty, TableRowElements with complete rows for insertion into an
    // HTML table based upon visible columns
    private TableRowElement populateTableRowElement(TableRowElement tre,
                                                    DynamicDataRow rowData) {

        for ( int iCol = 0; iCol < grid.getColumns().size(); iCol++ ) {
            if ( grid.getColumns().get( iCol ).isVisible() ) {
                TableCellElement tce = makeTableCellElement( iCol,
                                                             rowData );
                if ( tce != null ) {
                    tre.appendChild( tce );
                }
            }
        }

        return tre;

    }

    // Redraw a row adding new cells if necessary. This is used to populate part
    // of a row from the given index onwards, when a new column has been
    // inserted. It is important the indexes on the underlying data have
    // been set correctly before calling as they are used to determine the
    // correct HTML element in which to render a cell.
    private void redrawTableRowElement(DynamicDataRow rowData,
                                       TableRowElement tre,
                                       int startColIndex,
                                       int endColIndex) {

        for ( int iCol = startColIndex; iCol <= endColIndex; iCol++ ) {

            // Only redraw visible columns
            DynamicColumn< ? > column = grid.getColumns().get( iCol );
            if ( column.isVisible() ) {

                int maxColumnIndex = tre.getCells().getLength() - 1;
                int requiredColumnIndex = rowData.get( iCol ).getHtmlCoordinate()
                        .getCol();
                if ( requiredColumnIndex > maxColumnIndex ) {

                    // Make a new TD element
                    TableCellElement newCell = makeTableCellElement( iCol,
                                                                     rowData );
                    if ( newCell != null ) {
                        tre.appendChild( newCell );
                    }

                } else {

                    // Reuse an existing TD element
                    TableCellElement newCell = makeTableCellElement( iCol,
                                                                     rowData );
                    if ( newCell != null ) {
                        TableCellElement oldCell = tre.getCells().getItem(
                                                                           requiredColumnIndex );
                        tre.replaceChild( newCell,
                                          oldCell );
                    }
                }
            }
        }

    }

}
TOP

Related Classes of org.drools.guvnor.client.widgets.decoratedgrid.VerticalMergableGridWidget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.