/* * Copyright 2005 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.rulelist; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.MissingResourceException; import java.util.Stack; import org.drools.guvnor.client.common.GenericCallback; import org.drools.guvnor.client.common.LoadingPopup; import org.drools.guvnor.client.messages.Constants; import org.drools.guvnor.client.resources.Images; import org.drools.guvnor.client.rpc.RepositoryServiceFactory; import org.drools.guvnor.client.rpc.TableConfig; import org.drools.guvnor.client.rpc.TableDataResult; import org.drools.guvnor.client.rpc.TableDataRow; import org.drools.guvnor.client.ruleeditor.EditorLauncher; import org.drools.guvnor.client.ruleeditor.MultiViewRow; import org.drools.guvnor.client.util.Format; import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.SimplePanel; import com.gwtext.client.core.EventObject; import com.gwtext.client.data.ArrayReader; import com.gwtext.client.data.DateFieldDef; import com.gwtext.client.data.FieldDef; import com.gwtext.client.data.MemoryProxy; import com.gwtext.client.data.Record; import com.gwtext.client.data.RecordDef; import com.gwtext.client.data.Store; import com.gwtext.client.data.StringFieldDef; import com.gwtext.client.widgets.Button; import com.gwtext.client.widgets.Toolbar; import com.gwtext.client.widgets.ToolbarButton; import com.gwtext.client.widgets.ToolbarItem; import com.gwtext.client.widgets.ToolbarTextItem; import com.gwtext.client.widgets.event.ButtonListenerAdapter; import com.gwtext.client.widgets.grid.CellMetadata; import com.gwtext.client.widgets.grid.ColumnConfig; import com.gwtext.client.widgets.grid.ColumnModel; import com.gwtext.client.widgets.grid.GridPanel; import com.gwtext.client.widgets.grid.Renderer; import com.gwtext.client.widgets.grid.event.GridRowListenerAdapter; /** * Uses an awesome grid and does paging for asset lists. * It works well, but here be dragons. * @author Michael Neale * @deprecated in favor of {@link AssetTable} */ public class AssetItemGrid extends Composite { private static Images images = GWT.create( Images.class ); public static final String RULE_LIST_TABLE_ID = "rulelist"; public static final String PACKAGEVIEW_LIST_TABLE_ID = "packageviewlist"; public static final String ARCHIVED_RULE_LIST_TABLE_ID = "archivedrulelist"; private static final Map<String, ColumnModel> columnConfigs = new HashMap<String, ColumnModel>(); private static final Map<String, RecordDef> recordDefs = new HashMap<String, RecordDef>(); private static final Map<String, Integer> rowsPerPage = new HashMap<String, Integer>(); private final EditItemEvent editEvent; private SimplePanel layout; private Command refresh; /** * Used for tracking paging. */ private Stack<Integer> cursorPositions = createPositionStack(); private int currentCursorPosition = 0; protected Store store; private GridPanel currentGrid; private static Constants constants = GWT.create( Constants.class ); private String feedURL; private Command unloadHook; /** * Call this to set up a table config instead of loading it from the server. You then pass in the config name for later use. * Can save a round trip. */ public static void registerTableConfig(TableConfig tableConfig, String tableConfigKey) { if ( columnConfigs.containsKey( tableConfigKey ) ) { return; } ColumnModel cm = createColumnModel( tableConfig ); columnConfigs.put( tableConfigKey, cm ); RecordDef rd = createRecordDef( tableConfig ); recordDefs.put( tableConfigKey, rd ); rowsPerPage.put( tableConfigKey, new Integer( tableConfig.rowsPerPage ) ); } /** * Create a grid using the given config - config will be loaded from the server if it is not already cached. * You can use registerTableConfig to register it to avoid a server hit. */ public AssetItemGrid(final EditItemEvent event, final String tableConfigKey, final AssetItemGridDataLoader source) { this.editEvent = event; this.layout = new SimplePanel(); if ( !columnConfigs.containsKey( tableConfigKey ) ) { RepositoryServiceFactory.getService().loadTableConfig( tableConfigKey, new GenericCallback<TableConfig>() { public void onSuccess(TableConfig tableConfig) { registerTableConfig( tableConfig, tableConfigKey ); doGrid( source, columnConfigs.get( tableConfigKey ), recordDefs.get( tableConfigKey ), tableConfig.rowsPerPage ); } } ); } else { doGrid( source, columnConfigs.get( tableConfigKey ), recordDefs.get( tableConfigKey ), (rowsPerPage.get( tableConfigKey )).intValue() ); } initWidget( layout ); } /** * Similar to the other constructor, but takes an optional feedURL to show with an atom icon in the top right. */ public AssetItemGrid(final EditItemEvent event, final String tableConfig, final AssetItemGridDataLoader source, String feedURL) { this( event, tableConfig, source ); this.feedURL = feedURL; } private Stack<Integer> createPositionStack() { Stack<Integer> cursorPositions = new Stack<Integer>(); cursorPositions.push( 0 ); return cursorPositions; } /** * Actually build the grid. */ private void doGrid(final AssetItemGridDataLoader source, final ColumnModel cm, final RecordDef rd, final int pageSize) { final int numFlds = rd.getFields().length; final boolean[] loaded = {false}; Timer t = new Timer() { public void run() { if ( !loaded[0] ) LoadingPopup.showMessage( constants.PleaseWait() ); } }; t.schedule( 90 ); source.loadData( cursorPositions.peek(), pageSize, new GenericCallback<TableDataResult>() { public void onSuccess(TableDataResult result) { Object[][] gridData = new Object[result.data.length][]; for ( int i = 0; i < result.data.length; i++ ) { TableDataRow row = result.data[i]; Object[] rowData = new Object[numFlds]; rowData[0] = row.id; rowData[1] = row.format; for ( int j = 2; j < numFlds; j++ ) { if ( rd.getFields()[j] instanceof DateFieldDef ) { Date dt = new Date( Long.parseLong( row.values[j - 2] ) ); //NOTE, GWTEXT only understands certain date formats, for example "yyyy/MM/dd" //works but other formats such as "yyyy/MM/dd" or localized formats is not recognizable //by GWTEXT. See http://code.google.com/p/gwt-ext/issues/detail?id=459&start=100. DateTimeFormat format = DateTimeFormat.getFormat( "yyyy/MM/dd HH:mm" ); //DateTimeFormat format = DateTimeFormat.getFullDateFormat(); rowData[j] = format.format( dt ); } else { rowData[j] = row.values[j - 2]; } } gridData[i] = rowData; } MemoryProxy proxy = new MemoryProxy( gridData ); ArrayReader reader = new ArrayReader( rd ); store = new Store( proxy, reader ); //currentGrid = new Grid(Ext.generateId(), "600px", "600px", store, cm); currentGrid = new GridPanel( store, cm ); currentGrid.setWidth( 600 ); currentGrid.setHeight( 600 ); Toolbar tb = new Toolbar(); currentGrid.setTopToolbar( tb ); if ( result.total > -1 ) { tb.addItem( new ToolbarTextItem( Format.format( constants.ShowingNofXItems().replace( "X", "{0}" ).replace( "Y", "{1}" ), //NON-NLS new String[]{"" + result.data.length, "" + result.total} ) ) ); } else { tb.addItem( new ToolbarTextItem( Format.format( constants.NItems().replace( "X", "{0}" ), new String[]{"" + result.data.length} ) ) ); } if ( cursorPositions.peek() > 0 ) { navButton( source, cm, rd, pageSize, currentGrid, false, tb ); } if ( result.hasNext ) { navButton( source, cm, rd, pageSize, currentGrid, true, tb ); } refresh = new Command() { public void execute() { layout.clear(); currentGrid.destroy(); doGrid( source, cm, rd, pageSize ); } }; ToolbarButton refreshB = new ToolbarButton(); refreshB.setText( constants.refreshList() ); refreshB.addListener( new ButtonListenerAdapter() { public void onClick(Button button, EventObject e) { refresh.execute(); } } ); tb.addButton( refreshB ); ToolbarButton openSelected = new ToolbarButton(); openSelected.setText( constants.openSelected() ); openSelected.addListener( new ButtonListenerAdapter() { public void onClick(Button button, EventObject e) { Record[] selections = currentGrid.getSelectionModel().getSelections(); for ( Record record : selections ) { String uuid = record.getAsString( "uuid" ); editEvent.open( uuid ); } } } ); tb.addButton( openSelected ); ToolbarButton openSelectedToSingleTab = new ToolbarButton(); openSelectedToSingleTab.setText( constants.openSelectedToSingleTab() ); openSelectedToSingleTab.addListener( new ButtonListenerAdapter() { public void onClick(Button button, EventObject e) { Record[] selections = currentGrid.getSelectionModel().getSelections(); MultiViewRow[] rows = new MultiViewRow[selections.length]; for ( int i = 0; i < selections.length; i++ ) { MultiViewRow row = new MultiViewRow(); row.uuid = selections[i].getAsString( "uuid" ); row.name = selections[i].getAsString( "Name" ); row.format = selections[i].getAsString( "format" ); rows[i] = row; } editEvent.open( rows ); } } ); tb.addButton( openSelectedToSingleTab ); if ( feedURL != null ) { tb.addFill(); //System.err.println("Base: " + GWT.getModuleBaseURL()); //System.err.println("URL: " + com.google.gwt.user.client.Window.Location.getHref()); ToolbarItem item = new ToolbarItem( new HTML( Format.format( "<a href='{0}' target='_blank'><img src='{1}'/></a>", feedURL, new Image( images.feed() ).getUrl() ) ).getElement() ); tb.addItem( item ); } currentGrid.addGridRowListener( new GridRowListenerAdapter() { public void onRowDblClick(GridPanel grid, int rowIndex, EventObject e) { String uuid = grid.getSelectionModel().getSelected().getAsString( "uuid" ); editEvent.open( uuid ); } } ); store.load(); layout.add( currentGrid ); //store the end position currentCursorPosition = (int) result.currentPosition; loaded[0] = true; LoadingPopup.close(); } } ); } public String getSelectedRowUUID() { Record r = currentGrid.getSelectionModel().getSelected(); if ( r != null ) { return r.getAsString( "uuid" ); } else { return null; } } public String[] getSelectedRowUUIDs() { Record[] records = currentGrid.getSelectionModel().getSelections(); if ( records != null && records.length != 0 ) { String[] rtn = new String[records.length]; for ( int i = 0; i < records.length; i++ ) { rtn[i] = records[i].getAsString( "uuid" ); } return rtn; } else { return null; } } private void navButton(final AssetItemGridDataLoader source, final ColumnModel cm, final RecordDef rd, final int pageSize, final GridPanel g, final boolean forward, Toolbar tb) { ToolbarButton b = new ToolbarButton(); b.setText( (forward) ? constants.Next() : constants.Previous() ); tb.addButton( b ); b.addListener( new ButtonListenerAdapter() { public void onClick(Button button, EventObject e) { if ( forward ) { //int newPos = currentCursorPosition - 2; int newPos = currentCursorPosition; if ( newPos > 0 ) { cursorPositions.push( newPos ); } } else { cursorPositions.pop(); } layout.clear(); g.destroy(); doGrid( source, cm, rd, pageSize ); } } ); if ( !forward ) { ToolbarButton first = new ToolbarButton( constants.goToFirst() ); tb.addButton( first ); first.addListener( new ButtonListenerAdapter() { @Override public void onClick(Button button, EventObject e) { cursorPositions.clear(); cursorPositions.push( 0 ); layout.clear(); g.destroy(); doGrid( source, cm, rd, pageSize ); } } ); } } private static RecordDef createRecordDef(TableConfig conf) { FieldDef[] fd = new FieldDef[conf.headers.length + 2]; //2 as we have format and UUID to tack on. fd[0] = new StringFieldDef( "uuid" ); //NON-NLS fd[1] = new StringFieldDef( "format" ); //NON-NLS for ( int i = 0; i < conf.headers.length; i++ ) { if ( conf.headerTypes[i].equals( "class java.util.Calendar" ) ) { //NON-NLS fd[i + 2] = new DateFieldDef( conf.headers[i] ); } else { fd[i + 2] = new StringFieldDef( conf.headers[i] ); } } return new RecordDef( fd ); } private static ColumnModel createColumnModel(TableConfig conf) { ColumnConfig[] cfgs = new ColumnConfig[conf.headers.length + 1]; //first the UUID cfgs[0] = new ColumnConfig() { { setHidden( true ); setHeader( "uuid" ); setDataIndex( "uuid" ); //NON-NLS } }; //now the visible headers for ( int i = 0; i < conf.headers.length; i++ ) { final String header = conf.headers[i]; final String headerType = conf.headerTypes[i]; cfgs[i + 1] = new ColumnConfig() { { setupHeader(); setSortable( true ); setDataIndex( header ); if ( header.equals( "Name" ) ) { //name is special ! setWidth( 220 ); setRenderer( new Renderer() { public String render(Object value, CellMetadata cellMetadata, Record record, int rowIndex, int colNum, Store store) { String fmtIcon = new Image( EditorLauncher.getAssetFormatIcon( record.getAsString( "format" ) ) ).getUrl(); String desc = record.getAsString( "Description" ); if ( desc == null ) { desc = ""; } return Format.format( "<img src='{0}'/> <b>{1}</b><br/><small>{2}</small>", new String[]{fmtIcon, (String) value, desc} ); } } ); } else if ( headerType.equals( "class java.util.Calendar" ) ) { setWidth( 120 ); setRenderer( new Renderer() { public String render(Object value, CellMetadata cellMetadata, Record record, int rowIndex, int colNum, Store store) { //DateTimeFormat format = DateTimeFormat.getMediumDateFormat(); DateTimeFormat format = DateTimeFormat.getFormat( "yyyy/MM/dd HH:mm" ); //System.out.println("----format.format( (Date) value )" + format.format( (Date) value )); return format.format( (Date) value ); } } ); } else if ( header.equals( "Description" ) ) { setHidden( true ); //don't want to show a separate description } } /** * This dirty hack is needed to cope with keys that may not be localised. * ie not built in ones (eg a user adds a custom column). */ private void setupHeader() { try { String headerDisplay = constants.getString( header ); setHeader( headerDisplay ); } catch ( MissingResourceException me ) { setHeader( header ); } } }; } return new ColumnModel( cfgs ); } public void refreshGrid() { this.refresh.execute(); } /** * To be used when unloading. * @param command */ public void addUnloadListener(Command command) { this.unloadHook = command; } @Override protected void onUnload() { super.onUnload(); if ( unloadHook != null ) unloadHook.execute(); } }