I have an objectlistview with 4 columns and a dynamic number of rows, I'm struggling with programmable editing a cell text value, and optionally change the forecolor
I've read everything and anything that I could put my hands on, but couldn't find any valid and right to the point example on how to do it.
the ObjectListView is created this why
List<VideoItem> list = new List<VideoItem>();
foreach (dynamic item in VideoItems)
{
list.Add(new VideoItem { Index = (int)item.index, OldName = (string)item.oldname, NewName = (string)item.newname });
}
olv1.AddObjects(list);
VideoItem class look like this
private class VideoItem
{
public int Index;
public string OldName;
public string NewName;
}
but i need to programmably edit a cell text on event. I'm doing some logical operations on other cell at the end im storing the result to to cell next to it.
You should be storing the result (making the change) to the underlying model object and then call RefreshObject(myModelObject);
About the forcolor, i need to change only the cell I've changed
"To change the formatting of an individual cell, you need to set UseCellFormatEvents to true and then listen for FormatCell events."
Take a look at this.
Just to add to Rev1.0 Answer, i needed to update the object that contains the items (in my case a List) then, use olv1.RefreshObject(list); flow by olv1.BuildList(true);
the olv1.BuildList(true); refresh the GUI immediately.
here a small code snippet to make thing bit more clear
it's changing the data in column 3 when a checkbox is checked.
using System.Collections.Generic;
using System.Windows.Forms;
namespace Test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Initializeolv();
}
private class VideoItem
{
public int Index;
public string OldName;
public string NewName;
}
private List<VideoItem> list = new List<VideoItem>();
private void Initializeolv()
{
for (var i = 1; i <= 10; i++)
{
list.Add(new VideoItem { Index = i, OldName = $"old{i}", NewName = $"new{i}" });
}
olv1.AddObjects(list);
}
private void olv1_ItemChecked(object sender, ItemCheckedEventArgs e)
{
list[e.Item.Index].NewName = "new200";
olv1.RefreshObject(list);
olv1.BuildList(true);
}
}
}
Related
I'm trying to make Solr search phone numbers which are stored like this +79876543210 using a query like these:
+79876543210
79876543210
89876543210 <-- '+7' is replaced with region specific code '8'
9876543210 <-- '+7' entirely removed
This is just an example. Another one is wired line phone numbers:
+78662123456 <-- '+78662' is a specific region code
78662123456
88662123456
8662123456
123456 <-- region code entirely removed
One way I could manage this is using a separate field which is filled with these variants and used solely during search.
But this has issues with highlighting (it returns <em>123456</em> to be highlighted whereas the real value shown to user is +78662123456).
I thought that maybe it's best to make these indices using just Solr, but how?
First thought was to use managed synonyms filter and pass them along with each added record. But the docs explicitly states:
Changes made to managed resources via this REST API are not applied to the active Solr components until the Solr collection (or Solr core in single server mode) is reloaded.
So reloading a core every time after adding a record is not the way to go.
Other issues involve keeping these synonyms up to date with records.
Could there be another way to solve this?
Thanks to this comment (by MatsLindh) I've managed to assemble a simple filter based on bult-in EdgeNGramTokenFilter:
package com.step4;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReverseCustomFilter extends TokenFilter {
private static final PatternReplacementPair[] phonePatterns = {
new PatternReplacementPair("\\+7", "7"),
new PatternReplacementPair("\\+7", "8"),
new PatternReplacementPair("\\+7", ""),
new PatternReplacementPair("\\+78662", ""),
new PatternReplacementPair("\\+78663", ""),
};
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private final PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class);
private int curPatternIndex;
private int curPosIncr;
private State curState;
public ReverseCustomFilter(TokenStream input) {
super(input);
}
#Override
public final boolean incrementToken() throws IOException {
while (true) {
if (curPatternIndex == 0) {
if (!input.incrementToken()) {
return false;
}
curState = captureState();
curPosIncr += posIncrAtt.getPositionIncrement();
curPatternIndex = 1;
}
if (curPatternIndex <= phonePatterns.length) {
PatternReplacementPair replacementPair = phonePatterns[curPatternIndex - 1];
curPatternIndex++;
restoreState(curState);
Matcher matcher = replacementPair.getPattern().matcher(termAtt);
if (matcher.find()) {
posIncrAtt.setPositionIncrement(curPosIncr);
curPosIncr = 0;
String replaced = matcher.replaceFirst(replacementPair.getReplacement());
termAtt.setEmpty().append(replaced);
return true;
}
}
else {
restoreState(curState);
posIncrAtt.setPositionIncrement(0);
curPatternIndex = 0;
return true;
}
}
}
#Override
public void reset() throws IOException {
super.reset();
curPatternIndex = 0;
curPosIncr = 0;
}
#Override
public void end() throws IOException {
super.end();
posIncrAtt.setPositionIncrement(curPosIncr);
}
private static class PatternReplacementPair {
private final Pattern pattern;
private final String replacement;
public PatternReplacementPair(String pattern, String replacement) {
this.pattern = Pattern.compile(pattern);
this.replacement = replacement;
}
public Pattern getPattern() {
return pattern;
}
public String getReplacement() {
return replacement;
}
}
}
In itext 5, it can be used cell events to compute a subtotal of a table column. How can this be done in itext 7?
The itext 5 example can be found in this URL: http://developers.itextpdf.com/examples/tables/using-cell-events-add-special-content#2887-subtotal.java
There is currently no direct alternative of cell event functionality in iText7.
Howerver, the desired output can be achieved using rich rendering mechanism which allows a lot more than just events.
I will provide just one of the possible ways to implement a subtotal of table on the page. Total is easy and thus I'm leaving it out of the scope of the answer.
For the starters, we will need a class responsible for calculations:
private static class SubtotalHandler {
private int subtotalSum;
public void reset() {
subtotalSum = 0;
}
public void add(int val) {
subtotalSum += val;
}
public int get() {
return subtotalSum;
}
}
The code for generating the table itself will look like this:
Table table = new Table(UnitValue.createPercentArray(new float[] {1, 1})).setWidth(400);
table.setHorizontalAlignment(HorizontalAlignment.CENTER);
// Create our calculating class instance
SubtotalHandler handler = new SubtotalHandler();
for (int i = 0; i < 200; i++) {
table.addCell(new Cell().add(String.valueOf(i + 1)));
int price = 10;
Cell priceCell = new Cell().add(String.valueOf(price));
// Note that we set a custom renderer that will interact with our handler
priceCell.setNextRenderer(new SubtotalHandlerAwareCellRenderer(priceCell, handler, price));
table.addCell(priceCell);
}
table.addFooterCell(new Cell().add("Subtotal"));
Cell subtotalCell = new Cell();
// We create a custom renderer for the subtotal value itself as well because the text of the cell will depend on the state of the subtotal handler
subtotalCell.setNextRenderer(new SubtotalCellRenderer(subtotalCell, handler));
table.addFooterCell(subtotalCell);
Renderers of cells with price just tell the subtotal handler that some amount has been added:
private static class SubtotalHandlerAwareCellRenderer extends CellRenderer {
private SubtotalHandler subtotalHandler;
private int price;
public SubtotalHandlerAwareCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler, int price) {
super(modelElement);
this.subtotalHandler = subtotalHandler;
this.price = price;
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
subtotalHandler.add(price);
}
#Override
public IRenderer getNextRenderer() {
return new SubtotalHandlerAwareCellRenderer((Cell) modelElement, subtotalHandler, price);
}
}
When it comes to the rendering of the footer cell, the corresponding cell asks the subtotal handler about the amount and prints it, and resets the subtotal handler afterwards:
private static class SubtotalCellRenderer extends CellRenderer {
private SubtotalHandler subtotalHandler;
public SubtotalCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler) {
super(modelElement);
this.subtotalHandler = subtotalHandler;
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
new Canvas(drawContext.getCanvas(), drawContext.getDocument(), occupiedArea.getBBox()).
showTextAligned(String.valueOf(subtotalHandler.get()), occupiedArea.getBBox().getX() + 3,
occupiedArea.getBBox().getY() + 3, TextAlignment.LEFT);
subtotalHandler.reset();
}
#Override
public IRenderer getNextRenderer() {
return new SubtotalCellRenderer((Cell) modelElement, subtotalHandler);
}
}
The output looks like this:
For testing purposes (using JemmyFX), I want to check that the content of a TableView is appropriately formatted. For example: one column is of type Double and a cell factory has been applied to show the number as a percent: 20%.
How can I verify that when the value is 0.2d, the cell is showing as 20%?
Ideally I am looking for something along those lines:
TableColumn<VatInvoice, Double> percentVat = ...
assertEquals(percentVat.getTextualRepresentation(), "20%");
Note: I have tried to use the TableCell directly like below but getText() returns null:
TableCell<VatInvoice, Double> tc = percentVat.getCellFactory().call(percentVat);
tc.itemProperty().set(0.2);
assertEquals(tc.getText(), "20%"); //tc.getText() is null
The best I have found so far, using JemmyFX, is the following:
public String getCellDataAsText(TableViewDock table, int row, int column) {
final TableCellItemDock dock = new TableCellItemDock(table.asTable(), row, column);
return dock.wrap().waitState(new State<String>() {
#Override public String reached() {
return dock.wrap().cellWrap().getControl().getText();
}
});
}
You can try editing the cell factory.
tc.setCellFactory(new Callback<TableColumn, TableCell>(){
#Override
public TableCell call(TableColumn param){
return new TableCell(){
#Override
public void updateItem(Object item, boolean isEmpty){
//...logic to format the text
assertEquals(getText(), "20%");
}
};
}
});
Is there anyway to define the editor type on a cell by cell basis in GXT 3.0?
I need to create a transposed table; the column become the row and the row is the column. That being the case, a column (from a normal table point of view) will have various editor type, whereby a row will have identical editor type.
I am trying to use following approach - It seems to be working fine, and allow to open up editors based on data type but when i click out; it doesn't close/hide editor.
I would really appreciate if someone can please point me in right direction.
final GridInlineEditing<MyModel> editing = new GridInlineEditing<MyModel>(mygrid){
#SuppressWarnings("unchecked")
#Override public <O> Field<O> getEditor(ColumnConfig<MyModel, ?> columnConfig) {
if(valueColumnName.equals(columnConfig.getHeader().asString())) {
MyModel myModel = tree.getSelectionModel().getSelectedItem();
if(MyModelType.STRING.equals(myModel.getMyModelType())) {
TextField textField = new TextField();
textField.setAllowBlank(Boolean.FALSE);
return (Field<O>) textField;
}
else {
TextArea textField = new TextArea();
textField.setAllowBlank(Boolean.FALSE);
return (Field<O>) textField;
}
}
return super.getEditor(columnConfig);
}
};
editing.setClicksToEdit(ClicksToEdit.TWO);
PS:
This is similar to question below; but answer is specific to post GXT 3.0. I am new to stackoverflow and it seems recommendation was to create new question instead of adding new post to old thread.
GXT EditorGrid: choose cell editor type on a cell by cell basis
After playing around all day; my colleague(Praveen) and I figured it out. So instead of trying to override GridInlineEditing's getEditor() method override startEditing() method. Also, you will need converters if you have data like Date, List etc. Below is sample code; hope this help others.
final GridInlineEditing<MyModel> editing = new GridInlineEditing<MyModel>(tree){
#Override public void startEditing(GridCell cell) {
MyModel myModel= tree.getSelectionModel().getSelectedItem();
if(MyModelType.TEXT.equals(myModel.getContextVariableType())) {
TextArea textField = new TextArea();
textField.setAllowBlank(Boolean.FALSE);
super.addEditor(valueColumn, textField);
}
else if(MyModelType.BOOLEAN.equals(myModel.getContextVariableType())) {
SimpleComboBox<String> simpleComboBox = new SimpleComboBox<String>(new StringLabelProvider<String>());
simpleComboBox.setTriggerAction(TriggerAction.ALL);
simpleComboBox.add("YES");
simpleComboBox.add("NO");
super.addEditor(valueColumn, simpleComboBox);
}
else if(MyModel.INTEGER.equals(myModel.getContextVariableType())) {
SpinnerField<Integer> spinnerField = new SpinnerField<Integer>(new IntegerPropertyEditor());
spinnerField.setIncrement(1);
Converter<String, Integer> converter = new Converter<String, Integer>(){
#Override public String convertFieldValue(Integer object) {
String value = "";
if(object != null) {
value = object.toString();
}
return value;
}
#Override public Integer convertModelValue(String object) {
Integer value = 0;
if(object != null && object.trim().length() > 0) {
value = Integer.parseInt(object);
}
return value;
}
};
super.addEditor(valueColumn, converter, (Field)spinnerField);
}
else {
TextField textField = new TextField();
textField.setAllowBlank(Boolean.FALSE);
super.addEditor(valueColumn, textField);
}
super.startEditing(cell);
}
};
editing.setClicksToEdit(ClicksToEdit.TWO);
I think the reason you are not seeing the fields not closing is because you are not actually adding them to the GridInlineEditing class.
In the parts where you have the following return statements;
return (Field<O>) textField;
Those textfields are never added to the grid.
I would try substituting the following code for your first two return statement;
super.addEditor(columnConfig, (Field<O>) textField;
This adds the editor to some maps used by AbstractGridEditing. Specifically, the AbstractGridEditing.removeEditor(GridCell, Field<?>) method, which is used in GridInlineEditing.doCompleteEditing() and GridInlineEditing.cancelEditing() needs the field to be in the map so it can be detached from its parent.
I am dynamically creating a RadGrid and adding GridTemplateColumns to it. Those columns have textbox in them.
After binding datatable to the grid, after user makes changes to the textboxes and on clicking save button, I would like to access the textbox values. But I am stuck at getting hold of the textbox instance. I couldn't even get hold of GridItems!
To add more complexity, my RadGrid is in a UserControl, which is in a (multi)view.
Heres the code.
protected void Page_Init(object sender, EventArgs e)
{
DefineGridStructure();
}
protected void Page_Load(object sender, EventArgs e)
{
if (RadGrid1 != null && RadGrid1.Items.Count > 0)
{
string strtxt = ((TextBox)RadGrid1.Items[1]["ProductGroup1"].Controls[0]).Text;//For starters, load one control and check it's state
}
}
private void DefineGridStructure()
{
RadGrid1 = new RadGrid();
RadGrid1.AutoGenerateColumns = false;
RadGrid1.ShowHeader = true;
RadGrid1.NeedDataSource += RadGrid1_NeedDataSource;
foreach(GridColumn qtyColumn in BuildGridQtyColumns(PaxColumnCount))
{
RadGrid1.MasterTableView.Columns.Add(qtyColumn);
}
//Add grid to page
phRadGrid.Controls.Add(RadGrid1);
}
private List<GridColumn> BuildGridQtyColumns(int count)
{
List<GridColumn> qtyColumns = new List<GridColumn>();
for (int i = 1; i <= count; i++)
{
string qtyColumnName = string.Format("ProductGroup{0}", i);
GridTemplateColumn qtyColumn = new GridTemplateColumn();
qtyColumn.ItemTemplate = new GridNumberTemplate(qtyColumnName);//Creates a textbox control
qtyColumn.UniqueName = qtyColumnName;
qtyColumn.HeaderText = "Qty";
qtyColumn.HeaderStyle.Width = Unit.Pixel(60);
qtyColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Center;
qtyColumns.Add(qtyColumn);
}
return qtyColumns;
}
Since my control is in view, it's Page_Init is called more than once for each action that involves this view.
For a dynamically generated radgrid, it should be created in page_init method and viewstate for this grid will be restored for us automatically which we can get hold of in page_load method.