001: package org.drools.brms.client.table;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.Iterator;
022: import java.util.List;
023:
024: import org.drools.brms.client.ruleeditor.EditorLauncher;
025:
026: import com.google.gwt.user.client.ui.Grid;
027: import com.google.gwt.user.client.ui.Image;
028: import com.google.gwt.user.client.ui.SourcesTableEvents;
029: import com.google.gwt.user.client.ui.TableListener;
030: import com.google.gwt.user.client.ui.Widget;
031:
032: /**
033: * A sortable table widget. Extends the GWT Grid widget.
034: * (more performant then FlexTable).
035: */
036: public class SortableTable extends Grid implements TableListener {
037:
038: /** The stylez */
039: public static String styleListHeader = "rule-ListHeader";
040: public static String styleSelectedRow = "rule-SelectedRow";
041: public static String styleEvenRow = "rule-ListEvenRow";
042:
043: public static String styleList = "rule-List";
044:
045: private static int SORT_ASCENDING = 0;
046: private static int SORT_DESCENDING = 1;
047:
048: /** vars for current storting state */
049: private int sortColIndex = -1;
050: private int sortDirection = -1;
051:
052: /** Icons for sorting status */
053: private String ascendingIcon = "images/shuffle_up.gif";
054: private String descendingIcon = "images/shuffle_down.gif";
055: private String blankImage = "images/up_down.gif";
056:
057: // Holds the data rows of the table
058: // This is a list of RowData Object
059: private List tableRows = new ArrayList();
060:
061: // Holds the data for the column headers
062: private List tableHeader = new ArrayList();
063: private int hideColumnIndex;
064: private int selectedRow;
065: private int RowNumbers;
066: private boolean hasIcons = true;
067:
068: /**
069: * Create a sortable table widget, of the specified proportions.
070: * The number of rows does NOT include the header.
071: */
072: public SortableTable(int rows, int cols) {
073: super (rows + 1, cols);
074:
075: this .addTableListener(this );
076: setStyleName(styleList);
077:
078: }
079:
080: /**
081: * This will return a sortable table ready to go.
082: * @param rows The data.
083: * @param header Headers.
084: * @param fillRows The number of rows to pad out, if needed
085: * @param hasIcons
086: * @return A SortableTable ready to go !
087: */
088: public static SortableTable createTableWidget(DataModel data,
089: String[] header, int fillRows, boolean hasIcons) {
090: SortableTable tableWidget = null;
091:
092: if (fillRows > data.getNumberOfRows()) {
093: tableWidget = new SortableTable(fillRows, header.length + 1);
094: tableWidget.setValue(1, 1, "", null);
095: } else {
096: tableWidget = new SortableTable(data.getNumberOfRows() + 1,
097: header.length + 1);
098: }
099:
100: tableWidget.setColumnHeader("", 0);
101:
102: for (int i = 0; i < header.length; i++) {
103: tableWidget.setColumnHeader(header[i], i + 1);
104: }
105:
106: tableWidget.setHiddenColumn(0);
107: for (int i = 0; i < data.getNumberOfRows(); i++) {
108: tableWidget.setValue(i + 1, 0, data.getRowId(i), null);
109: for (int j = 0; j < header.length; j++) {
110: //tableWidget.setValue( i + 1, j + 1, cols[j], null );
111: tableWidget.setValue(i + 1, j + 1, data.getValue(i, j),
112: data.getWidget(i, j));
113: }
114: }
115:
116: tableWidget.setHasIcons(hasIcons);
117:
118: return tableWidget;
119: }
120:
121: private void setHasIcons(boolean hasIcons) {
122: this .hasIcons = hasIcons;
123: }
124:
125: /**
126: * Adds a header, which will be at the zero index in the table.
127: */
128: public void setColumnHeader(String name, int index) {
129: tableHeader.add(index, name);
130: this .renderTableHeader(name, index);
131: }
132:
133: /**
134: * This can be used to ensure that a column is invisible.
135: * This will also include the header (first row)
136: * You would use this to allow a "key" column to be stored with the data.
137: * For example, a UUID for a rule.
138: */
139: public void setHiddenColumn(int colIndex) {
140: this .hideColumnIndex = colIndex;
141: this .getCellFormatter().setVisible(0, colIndex, false);
142: }
143:
144: /**
145: * This will store the value in the x,y position.
146: * Values must be comparable for sorting to work of course.
147: * Start with a row index of 1 otherwise as zero means header.
148: */
149: public void setValue(int row, int col, Comparable val, Widget w) {
150:
151: if (row == 0)
152: return;
153:
154: //for alternate for highlighting.
155: resetStyle(row, col);
156:
157: if ((row - 1) >= this .tableRows.size()
158: || null == tableRows.get(row - 1)) {
159: tableRows.add(row - 1, new RowData());
160: }
161:
162: RowData rowData = (RowData) this .tableRows.get(row - 1);
163: rowData.addColumnValue(col, val);
164: if (w == null) {
165: this .setText(row, col, "" + val.toString() + "");
166: } else {
167: this .setWidget(row, col, w);
168: }
169:
170: //and hiding the required column
171: if (col == hideColumnIndex) {
172: getCellFormatter().setVisible(row, col, false);
173: }
174: }
175:
176: private void resetStyle(int rowIndex, int colIndex) {
177: if (rowIndex % 2 == 0) {
178: getCellFormatter().setStyleName(rowIndex, colIndex,
179: styleEvenRow);
180: }
181: }
182:
183: /** This performs the sorting */
184: public void sort(int columnIndex) {
185: Collections.sort(this .tableRows);
186: if (this .sortColIndex != columnIndex) {
187: // New Pattern Header clicked
188: // Reset the sortDirection to ASC
189: this .sortDirection = SORT_ASCENDING;
190: } else {
191: // Reverse the sortDirection
192: this .sortDirection = (this .sortDirection == SORT_ASCENDING) ? SORT_DESCENDING
193: : SORT_ASCENDING;
194: }
195: this .sortColIndex = columnIndex;
196: }
197:
198: /**
199: * When a cell is clicked, the selected row is styled, and
200: * the currently selected row is remembered.
201: *
202: * If it was in-fact a header that was clicked, then it will sort the
203: * data and redisplay the grid.
204: */
205: public void onCellClicked(SourcesTableEvents sender, int row,
206: int col) {
207:
208: if (row <= tableRows.size()) {
209: styleSelectedRow(row);
210: clickSort(row, col);
211: }
212:
213: }
214:
215: /**
216: * This will apply the "highlight" for the selected row, and remove it from the previous
217: * one, and set the selectedRow.
218: */
219: private void styleSelectedRow(int row) {
220: if (row != 0) {
221: CellFormatter formatter = getCellFormatter();
222: for (int i = 1; i < this .getColumnCount(); i++) {
223: formatter.setStyleName(row, i, styleSelectedRow);
224:
225: if (selectedRow % 2 == 0 && selectedRow != 0) {
226: formatter
227: .setStyleName(selectedRow, i, styleEvenRow);
228: } else {
229: formatter.removeStyleName(selectedRow, i,
230: styleSelectedRow);
231: }
232: }
233:
234: selectedRow = row;
235: }
236: }
237:
238: /**
239: * @return The selected row index.
240: */
241: public int getSelectedRow() {
242: return this .selectedRow;
243: }
244:
245: /**
246: * This will return the key of the selected row.
247: */
248: public String getSelectedKey() {
249: return this .getText(selectedRow, this .hideColumnIndex);
250: }
251:
252: /**
253: * This actually kicks off the sorting.
254: */
255: private void clickSort(int row, int col) {
256: if (row != 0) {
257: return;
258: }
259: this .setSortColIndex(col);
260: this .sort(col);
261: this .drawTable();
262: }
263:
264: /*
265: * getSortAscImage
266: *
267: * Getter for Sort Ascending Image
268: *
269: * @return String
270: */
271: public String getSortAscImage() {
272: return ascendingIcon;
273: }
274:
275: /*
276: * setSortAscImage
277: *
278: * Setter for Sort Ascending Image
279: *
280: * @param relative path + image name (String)
281: * e.g. images/asc.gif
282: */
283: public void setSortAscImage(String sortAscImage) {
284: this .ascendingIcon = sortAscImage;
285: }
286:
287: /*
288: * getSortDescImage
289: *
290: * Getter for Sort Descending Image
291: *
292: * @return String
293: */
294: public String getSortDescImage() {
295: return descendingIcon;
296: }
297:
298: /*
299: * setSortDescImgage
300: *
301: * Setter for Sort Descending Image
302: *
303: * @param relative path + image name (String)
304: * e.g. images/desc.gif
305: */
306: public void setSortDescImgage(String sortDescImgage) {
307: this .descendingIcon = sortDescImgage;
308: }
309:
310: /*
311: * getBlankImage
312: *
313: * Getter for blank Image
314: *
315: * @return String
316: */
317: public String getBlankImage() {
318: return blankImage;
319: }
320:
321: /*
322: * setBlankImage
323: *
324: * Setter for the blank Image
325: *
326: * @param relative path + image name (String)
327: * e.g. images/blank.gif
328: */
329: public void setBlankImage(String blankImage) {
330: this .blankImage = blankImage;
331: }
332:
333: /*
334: * drawTable
335: *
336: * Renders the header as well as the body
337: * of the table
338: */
339: protected void drawTable() {
340: this .displayTableHeader();
341: this .displayTableBody();
342: }
343:
344: /*
345: * displayTableHeader
346: *
347: * Renders only the table header
348: */
349: private void displayTableHeader() {
350: int colIndex = 0;
351: for (Iterator colHeaderIter = this .tableHeader.iterator(); colHeaderIter
352: .hasNext();) {
353: String colHeader = (String) colHeaderIter.next();
354: this .renderTableHeader(colHeader, colIndex++);
355: }
356:
357: }
358:
359: /*
360: * displayTableBody
361: *
362: * Renders the body or the remaining rows of the table
363: * except the header.
364: * It checks the sort direction and displays the rows
365: * accordingly
366: */
367: private void displayTableBody() {
368: if (this .sortDirection == SORT_ASCENDING
369: || this .sortDirection == -1) {
370: // Ascending order and Default Display
371: for (int rowIndex = 0; rowIndex < tableRows.size(); rowIndex++) {
372: RowData columns = (RowData) tableRows.get(rowIndex);
373: for (int colIndex = 0; colIndex < columns
374: .getColumnValues().size(); colIndex++) {
375: Object value = columns.getColumnValue(colIndex);
376: setCell(rowIndex + 1, colIndex, value.toString());
377: }
378: }
379: } else {
380: // Descending Order Display
381: for (int rowIndex = tableRows.size() - 1, rowNum = 1; rowIndex >= 0; rowIndex--, rowNum++) {
382: RowData columns = (RowData) tableRows.get(rowIndex);
383: for (int colIndex = 0; colIndex < columns
384: .getColumnValues().size(); colIndex++) {
385: Object value = columns.getColumnValue(colIndex);
386: setCell(rowNum, colIndex, value.toString());
387: }
388: }
389: }
390: }
391:
392: private void setCell(int rowNum, int colIndex, String value) {
393: if (null != value) {
394: if (colIndex == 1 && hasIcons)
395: this .setWidget(rowNum, colIndex, new Image("images/"
396: + EditorLauncher.getAssetFormatIcon(value
397: .toString())));
398: else
399: this .setText(rowNum, colIndex, value.toString());
400: }
401: }
402:
403: /*
404: * setSortColIndex
405: *
406: * Sets the current column index being sorted
407: *
408: * @param column index being sorted (int)
409: */
410: private void setSortColIndex(int sortIndex) {
411: for (int rowIndex = 0; rowIndex < tableRows.size(); rowIndex++) {
412: RowData row = (RowData) tableRows.get(rowIndex);
413: row.setSortColIndex(sortIndex);
414: }
415: }
416:
417: /*
418: * renderTableHeader
419: * Renders a particular column in the Table Header
420: *
421: * @param Pattern Name (String)
422: * @param Pattern Index (int)
423: */
424: private void renderTableHeader(String name, int index) {
425: StringBuffer headerText = new StringBuffer();
426: headerText.append(name);
427: headerText.append(" <img border='0' src=");
428: if (this .sortColIndex == index) {
429: if (this .sortDirection == SORT_ASCENDING) {
430: headerText.append("'" + this .ascendingIcon
431: + "' alt='Ascending' ");
432: } else {
433: headerText.append("'" + this .descendingIcon
434: + "' alt='Descending' ");
435: }
436: } else {
437: headerText.append("'" + this .blankImage + "'");
438: }
439: headerText.append("/>");
440:
441: this .setHTML(0, index, headerText.toString());
442: getRowFormatter().setStyleName(0, styleListHeader);
443:
444: }
445:
446: public int getRowNumbers() {
447: return RowNumbers;
448: }
449:
450: public void setRowNumbers(int rowNumbers) {
451: RowNumbers = rowNumbers;
452: }
453:
454: }
|