Skip to content
Snippets Groups Projects
Commit cc8ea713 authored by srosse's avatar srosse
Browse files

OO-758: fix the table search, hold the value by row and dataColumn instead of...

OO-758: fix the table search, hold the value by row and dataColumn instead of index, search all columns...
parent a5d8a364
No related branches found
No related tags found
No related merge requests found
Showing
with 153 additions and 107 deletions
......@@ -19,14 +19,11 @@
*/
package de.bps.olat.modules.cl;
import java.util.List;
import org.olat.core.gui.components.table.ColumnDescriptor;
import org.olat.core.gui.components.table.HrefGenerator;
import org.olat.core.gui.components.table.Table;
import org.olat.core.gui.render.Renderer;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.id.Identity;
import org.olat.core.logging.AssertException;
/**
......@@ -48,6 +45,11 @@ public class ChecklistMultiSelectColumnDescriptor implements ColumnDescriptor {
this.column = column;
}
@Override
public int getDataColumn() {
return column;
}
public void renderValue(StringOutput sb, int row, Renderer renderer) {
// add checkbox
int currentPosInModel = table.getSortedRow(row);
......
......@@ -64,6 +64,12 @@ public interface ColumnDescriptor {
* renderer, otherwise <code>false</code>
*/
boolean translateHeaderKey();
/**
* Return the index used to retrieve the value in the table model
* @return
*/
public int getDataColumn();
/**
* @return
......
......@@ -282,7 +282,8 @@ public class DefaultColumnDescriptor implements ColumnDescriptor {
/**
* @return int
*/
protected int getDataColumn() {
@Override
public int getDataColumn() {
return dataColumn;
}
......
......@@ -37,7 +37,7 @@ import java.util.List;
*
* @author gnaegi
*/
public class GenericObjectArrayTableDataModel extends DefaultTableDataModel {
public class GenericObjectArrayTableDataModel extends DefaultTableDataModel<Object[]> {
private int columnCount;
......@@ -45,7 +45,7 @@ public class GenericObjectArrayTableDataModel extends DefaultTableDataModel {
* @param objectArrays List of Object[] containing whatever data displayable by the table
* @param columnCount Number of elements withing the Object[]
*/
public GenericObjectArrayTableDataModel(final List objectArrays, final int columnCount) {
public GenericObjectArrayTableDataModel(final List<Object[]> objectArrays, final int columnCount) {
super(objectArrays);
this.columnCount = columnCount;
}
......@@ -64,7 +64,7 @@ public class GenericObjectArrayTableDataModel extends DefaultTableDataModel {
* third lastModifiedDate
*/
public final Object getValueAt(final int row, final int col) {
Object[] objectArray = (Object[]) getObject(row);
Object[] objectArray = getObject(row);
return objectArray[col];
}
......@@ -76,7 +76,7 @@ public class GenericObjectArrayTableDataModel extends DefaultTableDataModel {
* @param col
*/
public final void setValueAt(final Object o, final int row, final int col){
Object[] objectArray = (Object[]) getObject(row);
Object[] objectArray = getObject(row);
objectArray[col] = o;
}
}
......@@ -40,7 +40,12 @@ class MultiSelectColumnDescriptor implements ColumnDescriptor {
MultiSelectColumnDescriptor(){
//package visibility for constructor
}
@Override
public int getDataColumn() {
return -1;
}
@Override
public void renderValue(final StringOutput sb, final int row, final Renderer renderer) {
// add checkbox
......
......@@ -86,6 +86,11 @@ public class StaticColumnDescriptor implements ColumnDescriptor {
this.translateHeaderKey = translateHeaderKey;
}
@Override
public int getDataColumn() {
return -1;
}
/**
* @see org.olat.core.gui.components.table.ColumnDescriptor#getAlignment()
*/
......
......@@ -37,6 +37,7 @@ import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.ComponentRenderer;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.gui.render.StringOutputPool;
import org.olat.core.gui.translator.Translator;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
......@@ -176,6 +177,10 @@ public class Table extends Component {
protected ColumnDescriptor getColumnDescriptorFromAllCDs(final int column) {
return allCDs.get(column);
}
protected int getColumnCountFromAllCDs() {
return allCDs.size();
}
/**
* @return Column descriptor of currently sorted column
......@@ -885,14 +890,14 @@ public class Table extends Component {
}
}
private void buildFilteredTableDataModel(final String tableSearchString2) {
private void buildFilteredTableDataModel(final String searchString) {
List<Object> filteredElementList = new ArrayList<Object>();
log.debug("buildFilteredTableDataModel: tableDataModel.getRowCount()=" + tableDataModel.getRowCount());
if (tableDataModel.getRowCount() > 0) {
log.debug("buildFilteredTableDataModel: tableDataModel.getObject(0)=" + tableDataModel.getObject(0));
}
for (int row = 0; row < tableDataModel.getRowCount(); row++) {
if (matchRowWithSearchString(row, tableSearchString2)) {
if (matchRowWithSearchString(row, searchString)) {
filteredElementList.add(tableDataModel.getObject(row));
}
}
......@@ -912,14 +917,18 @@ public class Table extends Component {
return true;
}
// loop over all columns
TableDataModel unfilteredModel = getUnfilteredTableDataModel();
Filter htmlFilter = FilterFactory.getHtmlTagsFilter();
for (int colIndex = 0; colIndex < getUnfilteredTableDataModel().getColumnCount(); colIndex++) {
Object value = getUnfilteredTableDataModel().getValueAt(row, colIndex);
// When a CustomCellRenderer exist, use this to render cell-value to String
ColumnDescriptor cd = this.getColumnDescriptorFromAllCDs(colIndex);
if (isColumnDescriptorVisible(cd)) {
for (int colIndex = getColumnCountFromAllCDs(); colIndex-->0; ) {
ColumnDescriptor cd = getColumnDescriptorFromAllCDs(colIndex);
int dataColumn = cd.getDataColumn();
if (dataColumn >= 0 && isColumnDescriptorVisible(cd)) {
Object value = unfilteredModel.getValueAt(row, dataColumn);
// When a CustomCellRenderer exist, use this to render cell-value to String
if (cd instanceof CustomRenderColumnDescriptor) {
CustomCellRenderer customCellRenderer = ((CustomRenderColumnDescriptor)cd).getCustomCellRenderer();
CustomRenderColumnDescriptor cdrd = (CustomRenderColumnDescriptor)cd;
CustomCellRenderer customCellRenderer = cdrd.getCustomCellRenderer();
if (customCellRenderer instanceof CustomCssCellRenderer) {
// For css renderers only use the hover
// text, not the CSS class name and other
......@@ -930,9 +939,9 @@ public class Table extends Component {
continue;
}
} else {
StringOutput sb = new StringOutput(100);
customCellRenderer.render(sb, null, value, ((CustomRenderColumnDescriptor) cd).getLocale(), cd.getAlignment(), null);
value = sb.toString();
StringOutput sb = StringOutputPool.allocStringBuilder(250);
customCellRenderer.render(sb, null, value, cdrd.getLocale(), cd.getAlignment(), null);
value = StringOutputPool.freePop(sb);
}
}
......@@ -940,10 +949,8 @@ public class Table extends Component {
String valueAsString = (String)value;
// Remove any HTML markup from the value
valueAsString = htmlFilter.filter(valueAsString);
log.debug("matchRowWithFilter: check " + valueAsString);
// Finally compare with search value based on a simple lowercase match
if (valueAsString.toLowerCase().indexOf(tableSearchString2.toLowerCase()) != -1 ) {
log.debug("matchRowWithFilter: found match for row=" + row + " value=" + valueAsString + " with filter=" + tableSearchString2);
return true;
}
}
......
......@@ -31,8 +31,6 @@ import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.olat.core.gui.ShortName;
import org.olat.core.gui.UserRequest;
......@@ -48,19 +46,14 @@ import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.ajax.autocompletion.AutoCompleterController;
import org.olat.core.gui.control.generic.ajax.autocompletion.EntriesChosenEvent;
import org.olat.core.gui.control.generic.ajax.autocompletion.ListProvider;
import org.olat.core.gui.control.generic.ajax.autocompletion.ListReceiver;
import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.gui.translator.PackageTranslator;
import org.olat.core.gui.translator.Translator;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.filter.Filter;
import org.olat.core.util.filter.FilterFactory;
/**
* <!--**************-->
......@@ -121,8 +114,6 @@ public class TableController extends BasicController {
private static final String VC_VAR_HAS_TABLE_SEARCH = "hasTableSearch";
private static final String LOG_DEBUG_DURATION = " duration=";
private OLog log = Tracing.createLoggerFor(this.getClass());
private static final String CMD_FILTER = "cmd.filter.";
......@@ -136,10 +127,6 @@ public class TableController extends BasicController {
*/
public static final Event EVENT_FILTER_SELECTED = new Event("filter.selected");
/**
* Limit the number of search-suggestions in table-search-popup
*/
private static final int MAX_TABLE_SEARCH_RESULT_ENTRIES = 20;
private VelocityContainer contentVc;
......@@ -303,69 +290,7 @@ public class TableController extends BasicController {
}
private Controller createTableSearchController(final UserRequest ureq, final WindowControl wControl) {
ListProvider genericProvider = new ListProvider() {
public void getResult(final String searchValue, final ListReceiver receiver) {
Filter htmlFilter = FilterFactory.getHtmlTagsFilter();
log.debug("getResult start");
long startTime = System.currentTimeMillis();
Set<String> searchEntries = new TreeSet<String>();
int entryCounter = 1;
// loop over whole data-model
for (int rowIndex=0; rowIndex < table.getUnfilteredTableDataModel().getRowCount(); rowIndex++) {
for (int colIndex=0; colIndex < table.getUnfilteredTableDataModel().getColumnCount(); colIndex++) {
Object obj = table.getUnfilteredTableDataModel().getValueAt(rowIndex, colIndex);
// When a CustomCellRenderer exist, use this to render cell-value to String
ColumnDescriptor cd = table.getColumnDescriptorFromAllCDs(colIndex);
if (table.isColumnDescriptorVisible(cd)) {
if (cd instanceof CustomRenderColumnDescriptor) {
CustomCellRenderer customCellRenderer = ((CustomRenderColumnDescriptor)cd).getCustomCellRenderer();
if (customCellRenderer instanceof CustomCssCellRenderer) {
// For css renderers only use the hover
// text, not the CSS class name and other
// markup
CustomCssCellRenderer cssRenderer = (CustomCssCellRenderer) customCellRenderer;
obj = cssRenderer.getHoverText(obj);
if (!StringHelper.containsNonWhitespace((String) obj)) {
continue;
}
} else {
StringOutput sb = new StringOutput();
customCellRenderer.render(sb, null, obj, ((CustomRenderColumnDescriptor) cd).getLocale(), cd.getAlignment(), null);
obj = sb.toString();
}
}
if (obj instanceof String) {
String valueString = (String)obj;
// Remove any HTML markup from the value
valueString = htmlFilter.filter(valueString);
// Finally compare with search value based on a simple lowercase match
if (valueString.toLowerCase().indexOf(searchValue.toLowerCase()) != -1) {
if (searchEntries.add(valueString) ) {
// Add to receiver list same entries only once
if (searchEntries.size() == 1) {
// before first entry, add searchValue. But add only when one search match
receiver.addEntry( searchValue, searchValue );
}
// limit the number of entries
if (entryCounter++ > MAX_TABLE_SEARCH_RESULT_ENTRIES) {
receiver.addEntry("...", "...");
long duration = System.currentTimeMillis() - startTime;
log.debug("getResult reach MAX_TABLE_SEARCH_RESULT_ENTRIES, entryCounter=" + entryCounter + LOG_DEBUG_DURATION + duration);
return;
}
receiver.addEntry(valueString, valueString);
}
}
}
}
}
}
long duration = System.currentTimeMillis() - startTime;
log.debug("getResult finished entryCounter=" + entryCounter + LOG_DEBUG_DURATION + duration);
}
};
ListProvider genericProvider = new TableListProvider(table);
removeAsListenerAndDispose(tableSearchController);
tableSearchController = new AutoCompleterController(ureq, wControl, genericProvider, null, false, 60, 3, translate("table.filter.label"));
listenTo(tableSearchController); // TODO:CG 02.09.2010 Test Tablesearch Performance, remove
......@@ -431,7 +356,7 @@ public class TableController extends BasicController {
}
private void applyAndcheckChangedColumnsChoice(final UserRequest ureq) {
List selRows = colsChoice.getSelectedRows();
List<Integer> selRows = colsChoice.getSelectedRows();
if (selRows.size() == 0) {
showError("error.selectatleastonecolumn");
} else {
......@@ -463,17 +388,18 @@ public class TableController extends BasicController {
return choice;
}
@Override
public void event(final UserRequest ureq, final Controller source, final Event event) {
log.debug("dispatchEvent event=" + event + " source=" + source);
if (event instanceof EntriesChosenEvent) {
EntriesChosenEvent ece = (EntriesChosenEvent)event;
List filterList = ece.getEntries();
List<String> filterList = ece.getEntries();
if (!filterList.isEmpty()) {
this.table.setSearchString((String)filterList.get(0));
this.modelChanged(false);
table.setSearchString(filterList.get(0));
modelChanged(false);
} else {
// reset filter search filter in modelChanged
this.modelChanged();
modelChanged();
}
}
}
......@@ -493,9 +419,7 @@ public class TableController extends BasicController {
*/
public Object getSortedObjectAt(int sortedRow) {
int row = table.getSortedRow(sortedRow);
TableDataModel model = getTableDataModel();
Object obj = model.getObject(row);
return obj;
return getTableDataModel().getObject(row);
}
/**
......@@ -780,5 +704,4 @@ public class TableController extends BasicController {
protected void doDispose() {
//
}
}
package org.olat.core.gui.components.table;
import java.util.Set;
import java.util.TreeSet;
import org.olat.core.gui.control.generic.ajax.autocompletion.ListProvider;
import org.olat.core.gui.control.generic.ajax.autocompletion.ListReceiver;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.gui.render.StringOutputPool;
import org.olat.core.util.StringHelper;
import org.olat.core.util.filter.Filter;
import org.olat.core.util.filter.FilterFactory;
/**
*
* Initial date: 05.09.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class TableListProvider implements ListProvider {
/**
* Limit the number of search-suggestions in table-search-popup
*/
private static final int MAX_TABLE_SEARCH_RESULT_ENTRIES = 20;
private final Table table;
public TableListProvider(Table table) {
this.table = table;
}
@Override
public void getResult(String searchValue, ListReceiver receiver) {
Filter htmlFilter = FilterFactory.getHtmlTagsFilter();
Set<String> searchEntries = new TreeSet<String>();
int entryCounter = 1;
// loop over whole data-model
TableDataModel<?> unfilteredModel = table.getUnfilteredTableDataModel();
int rowCount = unfilteredModel.getRowCount();
int colCount = table.getColumnCountFromAllCDs();
a_a:
for (int colIndex=0; colIndex < colCount; colIndex++) {
ColumnDescriptor cd = table.getColumnDescriptorFromAllCDs(colIndex);
int dataColumn = cd.getDataColumn();
if (dataColumn >= 0 && table.isColumnDescriptorVisible(cd)) {
for (int rowIndex=0; rowIndex < rowCount; rowIndex++) {
Object obj = unfilteredModel.getValueAt(rowIndex, dataColumn);
// When a CustomCellRenderer exist, use this to render cell-value to String
if (cd instanceof CustomRenderColumnDescriptor) {
CustomRenderColumnDescriptor crcd = (CustomRenderColumnDescriptor)cd;
CustomCellRenderer customCellRenderer = crcd.getCustomCellRenderer();
if (customCellRenderer instanceof CustomCssCellRenderer) {
// For css renderers only use the hover
// text, not the CSS class name and other
// markup
CustomCssCellRenderer cssRenderer = (CustomCssCellRenderer) customCellRenderer;
obj = cssRenderer.getHoverText(obj);
if (!StringHelper.containsNonWhitespace((String) obj)) {
continue;
}
} else {
StringOutput sb = StringOutputPool.allocStringBuilder(250);
customCellRenderer.render(sb, null, obj, crcd.getLocale(), cd.getAlignment(), null);
obj = StringOutputPool.freePop(sb);
}
}
if (obj instanceof String) {
String valueString = (String)obj;
// Remove any HTML markup from the value
valueString = htmlFilter.filter(valueString);
// Finally compare with search value based on a simple lowercase match
if (valueString.toLowerCase().indexOf(searchValue.toLowerCase()) != -1) {
if (searchEntries.add(valueString) ) {
// Add to receiver list same entries only once
if (searchEntries.size() == 1) {
// before first entry, add searchValue. But add only when one search match
receiver.addEntry( searchValue, searchValue );
}
// limit the number of entries
if (entryCounter++ > MAX_TABLE_SEARCH_RESULT_ENTRIES) {
receiver.addEntry("...", "...");
break a_a;
}
receiver.addEntry(valueString, valueString);
}
}
}
}
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment