package fr.lteconsulting.hexa.client.ui.htreetable; import java.util.ArrayList; import java.util.HashMap; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.uibinder.client.UiConstructor; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import fr.lteconsulting.hexa.client.css.HexaCss; import fr.lteconsulting.hexa.client.tools.HexaTools; public class HTreeTable extends ComplexPanel implements ClickHandler { interface Css extends HexaCss { static final Css CSS = GWT.create( Css.class ); String main(); } public interface Callback { void onHTableClick( Object item ); } HTItem m_root = new HTItem( HTItemType.Item, null ); Element m_table; Callback m_callback = null; Widget headerWidget = null; HashMap<Element, HTItem> cells = new HashMap<Element, HTItem>(); @UiConstructor public HTreeTable() { m_table = DOM.createTable(); m_table.setAttribute( "border", "1" ); m_table.addClassName( Css.CSS.main() ); setElement( m_table ); addDomHandler( this, ClickEvent.getType() ); } public void setHeaderWidget( Widget w ) { if( headerWidget != null ) remove( headerWidget ); headerWidget = w; add( headerWidget, m_table ); } public void setCallback( Callback callback ) { m_callback = callback; } @Override public void onClick( ClickEvent event ) { if( m_callback == null ) return; HTItem item = getHTItemForEvent( event ); if( item == null ) { HexaTools.alert( "getHTItemForEvent return null in HTreeTable.java" ); return; } m_callback.onHTableClick( item ); } private HTItem getHTItemForEvent( ClickEvent event ) { Element td = getEventTargetCell( Event.as( event.getNativeEvent() ) ); if( td == null ) return null; return cells.get( td ); } protected Element getEventTargetCell( Event event ) { Element td = DOM.eventGetTarget( event ); for( ; td != null; td = DOM.getParent( td ) ) { // If it's a TD, it might be the one we're looking for. if( td.getTagName().equalsIgnoreCase( "td" ) ) { // Make sure it's directly a part of this table before returning // it. Element tr = DOM.getParent( td ); Element table = DOM.getParent( tr ); if( table == m_table ) return td; } // If we run into this table's body, we're out of options. if( td == m_table ) return null; } return null; } @Override public void clear() { clear( null ); } public void clear( String innerHTML ) { // removeItem( m_root ); while( m_root.m_children.size() > 0 ) removeItem( m_root.m_children.get( m_root.m_children.size() - 1 ) ); if( innerHTML != null ) m_table.setInnerHTML( innerHTML ); } public void endBulk() { m_root.updateRowSpan(); } public Object addSpliter() { Element row = DOM.createTR(); Element cell = DOM.createTD(); cell.setAttribute( "colspan", "10" ); // because only ff supports // colspan=0, this is hardcoded // here row.appendChild( cell ); row.addClassName( "Spliter" ); cell.addClassName( "Spliter" ); m_table.insertAfter( row, m_root.m_row ); HTItem item = new HTItem( HTItemType.Splitter, m_root ); cells.put( cell, item ); item.m_row = row; item.m_cell = cell; return item; } public boolean getExpanded( Object item ) { if( item == null ) return true; HTItem spliter = (HTItem) item; if( spliter.m_type != HTItemType.Splitter ) return true; return spliter.m_fExpanded; } public void setExpandedSpliter( Object item ) { if( item == null ) return; HTItem spliter = (HTItem) item; if( spliter.m_type != HTItemType.Splitter ) return; // balayer tous les spliter, // si == spliter => expand // sinon collapse for( HTItem s : m_root.m_children ) { if( s.m_type != HTItemType.Splitter ) continue; s.setExpanded( s == spliter ); } } public Object addItem( Object parentItem ) { return addItem( parentItem, true ); } public Object addItemBulk( Object parentItem ) { return addItem( parentItem, false ); } public Object addItem( Object parentItem, boolean fUpdateRowSpan ) { HTItem parent = (HTItem) parentItem; if( parent == null ) parent = m_root; // ajouter une ligne, quelle position ? Element row = null; if( parent.m_type == HTItemType.Splitter ) { row = DOM.createTR(); m_table.insertAfter( row, parent.m_row ); } else if( parent.m_children.size() == 0 ) { // pas de creation de TR row = parent.m_row; } else { // row of the last grand grand son HTItem parentLastChild = parent.getLastGrandChild(); row = DOM.createTR(); m_table.insertAfter( row, parentLastChild.m_row ); } // seul cas de nullit� : c'est le premier TR if( row == null ) { row = DOM.createTR(); m_table.appendChild( row ); } Element cell = DOM.createTD(); row.appendChild( cell ); HTItem item = new HTItem( HTItemType.Item, parent ); cells.put( cell, item ); item.m_row = row; item.m_cell = cell; if( fUpdateRowSpan ) m_root.updateRowSpan(); return item; } public void removeItem( Object item ) { HTItem htItem = (HTItem) item; if( htItem == null ) return; removeItemRec( htItem ); m_root.updateRowSpan(); } public void removeItemRec( HTItem item ) { while( item.m_children.size() > 0 ) removeItemRec( item.m_children.remove( item.m_children.size() - 1 ) ); removeWidget( item ); item.m_row.removeChild( item.m_cell ); cells.remove( item.m_cell ); // tous les freres d'apres doivent prendre le row les pr�c�dant Element curRow = item.m_row; int nextBrotherPos = item.m_parent.m_children.indexOf( item ) + 1; if( nextBrotherPos < item.m_parent.m_children.size() ) item.m_parent.m_children.get( nextBrotherPos ).assignRow( curRow ); if( item.m_row.getChildCount() == 0 ) m_table.removeChild( item.m_row ); item.m_parent.m_children.remove( item ); } public Object getParentItem( Object item ) { HTItem htItem = (HTItem) item; if( htItem == null ) return null; htItem = htItem.m_parent; if( htItem == m_root ) return null; return htItem; } public void setText( Object item, String text ) { HTItem htItem = (HTItem) item; removeWidget( htItem ); htItem.m_cell.setInnerText( text ); } public void setWidget( Object item, Widget widget ) { HTItem htItem = (HTItem) item; htItem.m_cell.setInnerText( "" ); if( htItem.m_widget != null ) remove( htItem.m_widget ); add( widget, htItem.m_cell ); htItem.m_widget = widget; } public boolean removeWidget( HTItem item ) { if( item.m_widget == null ) return false; boolean res = remove( item.m_widget ); item.m_widget = null; return res; } public enum HTItemType { Splitter, Item; } class HTItem { HTItemType m_type; HTItem m_parent; ArrayList<HTItem> m_children = new ArrayList<HTItem>(); boolean m_fExpanded = true; Element m_row = null; Element m_cell = null; Widget m_widget = null; public HTItem( HTItemType type, HTItem parent ) { m_type = type; m_parent = parent; if( m_parent != null ) m_parent.m_children.add( this ); } public HTItem getLastGrandChild() { int nbChild = m_children.size(); if( nbChild == 0 ) return null; HTItem last = m_children.get( nbChild - 1 ).getLastGrandChild(); if( last == null ) last = m_children.get( nbChild - 1 ); return last; } public int getNbRows() { int count = 0; for( HTItem c : m_children ) count += c.getNbRows(); if( count == 0 ) return 1; return count; } public void setExpanded( boolean fExpanded ) { if( m_type != HTItemType.Splitter ) return; m_fExpanded = fExpanded; for( HTItem child : m_children ) child.setVisible( fExpanded ); } public void setVisible( boolean fVisible ) { if( fVisible ) m_row.getStyle().clearDisplay(); else m_row.getStyle().setDisplay( Display.NONE ); for( HTItem child : m_children ) child.setVisible( fVisible ); } public void updateRowSpan() { if( m_type != HTItemType.Splitter ) { try { int nbRows = getNbRows(); m_cell.setAttribute( "rowspan", String.valueOf( nbRows ) ); } catch( Exception e ) { } } for( HTItem c : m_children ) c.updateRowSpan(); } public void assignRow( Element row ) { int pos = m_parent.m_children.indexOf( this ); int nextPos = pos + 1; m_cell.removeFromParent(); // si il y a un frere suivant, on lui donne notre TR int parentSize = m_parent.m_children.size(); if( parentSize > nextPos ) m_parent.m_children.get( nextPos ).assignRow( m_row ); if( m_row.getChildCount() == 0 ) m_row.removeFromParent(); m_row = row; m_row.appendChild( m_cell ); if( m_children.size() > 0 ) m_children.get( 0 ).assignRow( m_row ); } } }