Exception when using POI FontFormatting setFontColor - java

Trying to use POI conditional formatting. I have the following method:
private final static Color PEAK_ORANGE = new Color(255, 239, 221);
public ConditionalFormattingRule getConditionalFormatting(ConditionalFormattingRule formattingContainer, FormatSpecs format){
FontFormatting fontFmt = formattingContainer.createFontFormatting();
fontFmt.setFontStyle(true, false);
// fontFmt.setFontColorIndex((short)11);
fontFmt.setFontColor(new XSSFColor(PEAK_ORANGE));
PatternFormatting patternFmt = formattingContainer.createPatternFormatting();
patternFmt.setFillBackgroundColor(new XSSFColor(PEAK_ORANGE));
return formattingContainer;
}
When I use the setFontColor() method I get index out of bounds exception.
When I use the setFontColorIndex() method using some arbitrary index value, I do not get the exception. Notice however that I use the exact same color reference in the call to set the background color
patternFmt.setFillBackgroundColor(new XSSFColor(PEAK_ORANGE));
and this works fine, no exceptions.
Has anyone else run into this? Am I missing something in the call to set the font color? I prefer to use my colors rather than those from the IndexedColors class.

This looks like a small bug in Apache POI, a simple workaround is to first set an index-color and then set the actual intended full color, i.e.
fontFmt.setFontColorIndex((short)1);
fontFmt.setFontColor(new XSSFColor(PEAK_ORANGE));
The setFontColorIndex() will initialize the internal structures so that setFontColor() will work.
FYI, the bug should be fixed in time for release 4.0 of Apache POI.

Related

How do I iterate over an entire document in OpenOffice/LibreOffice with UNO

I am writing java code to access a document open in Libre Office.
I now need to write some code which iterate over the entire document, hopefully in the same order it is shown in the editor.
I can use this code to iterate over all the normal text:
XComponent writerComponent=xComponentLoader.loadComponentFromURL(loadUrl, "_blank", 0, loadProps);
XTextDocument mxDoc=UnoRuntime.queryInterface(XTextDocument.class, writerComponent);
XText mxDocText=mxDoc.getText();
XEnumerationAccess xParaAccess = (XEnumerationAccess) UnoRuntime.queryInterface(XEnumerationAccess.class, mxDocText);
XEnumeration xParaEnum = xParaAccess.createEnumeration();
Object element = xParaEnum.nextElement();
while (xParaEnum.hasMoreElements()) {
XEnumerationAccess inlineAccess = (XEnumerationAccess) UnoRuntime.queryInterface(XEnumerationAccess.class, element);
XEnumeration inline = inlineAccess.createEnumeration();
// And I can then iterate over this inline element and get all the text and formatting.
}
But the problem is that this does not include any chart objects.
I can then use
XDrawPagesSupplier drawSupplier=UnoRuntime.queryInterface(XDrawPagesSupplier.class, writerComponent);
XDrawPages pages=drawSupplier.getDrawPages();
XDrawPage drawPage=UnoRuntime.queryInterface(XDrawPage.class,page);
for(int j=0;j!=drawPage.getCount();j++) {
Object sub=drawPage.getByIndex(j);
XShape subShape=UnoRuntime.queryInterface(XShape.class,sub);
// Now I got my subShape, but how do I know its position, relative to the text.
}
And this gives me all charts (And other figures I guess), but the problem is: How do I find out where these charts are positioned in relation to the text in the model. And how do I get a cursor which represent each chart?
Update:
I am now looking for an anchor for my XShape, but XShape don't have a getAnchor() method.
But If I use
XPropertySet prop=UnoRuntime.queryInterface(XPropertySet.class,shape);
I get the prop class.
And I call prop.getPropertyValue("AnchorType") which gives me an ancher type of TextContentAnchorType.AS_CHARACTER
but I just can't get the anchor itself. There are no anchor or textrange property.
btw: I tried looking into installing "MRI" for libre office, but the only version I could find hav libreoffice 3.3 as supported version, and it would not install on version 7.1
----- Update 2 -----
I managed to make it work. It turns out that my XShape also implements XTextContent (Thank you MRI), so all I had to do was:
XTextContent subContent=UnoRuntime.queryInterface(XTextContent.class,subShape);
XTextRange anchor=subContent.getAnchor();
XTextCursor cursor = anchor.getText().createTextCursorByRange(anchor.getStart());
cursor.goRight((short)50,true);
System.out.println("String=" + cursor.getString());
This gives me a cursor which point to the paragraph, which I can then move forward/backward to find out where the shape is. So this println call will print the 50 chars following the XShape.
How do I find out where these charts are positioned in relation to the text in the model. And how do I get a cursor which represent each chart?
Abridged comments
Anchors pin objects to a specific location. Does the shape have a method getAnchor() or property AnchorType? I would use an introspection tool such as MRI to determine this. Download MRI 1.3.4 from https://github.com/hanya/MRI/releases.
As far as a cursor, maybe it is similar to tables:
oText = oTable.getAnchor().getText()
oCurs = oText.createTextCursor()
Code solution given by OP
XTextContent subContent=UnoRuntime.queryInterface(XTextContent.class,subShape);
XTextRange anchor=subContent.getAnchor();
XTextCursor cursor = anchor.getText().createTextCursorByRange(anchor.getStart());
cursor.goRight((short)50,true);
System.out.println("String=" + cursor.getString());

Change the Color of a Cell through Google Sheet API: Invalid requests

I want to set the background color of a cell (or group of cell) through Google Sheet API.
I wrote this request, it perfectly works when I write .setFields("*"), but I can't do that because this overrides all the previous requests I performed on that cell.
So I specify .setFields("backgroundColor") according to the field name as seen in this document.
But I get an error:
"message" : "Invalid requests[1].repeatCell: Invalid field: background_color",
Please note that backgroundColor has become background_color.
I tried other strings such as color, backgroundcolor... but none works. I don't know how to do.
Color XgoogleColor = new Color().setRed(1f).setGreen(0f).setBlue(0f); // Color.RED
return new Request()
.setRepeatCell(new RepeatCellRequest()
.setCell(new CellData()
.setUserEnteredFormat(new CellFormat()
.setBackgroundColor(XgoogleColor)
)
)
.setRange(new GridRange()
.setSheetId(sheetId)
.setStartRowIndex(startRow)
.setEndRowIndex(endRow)
.setStartColumnIndex(startColumn)
.setEndColumnIndex(endColumn)
)
.setFields("backgroundColor")
);
I believe your situation and goal as follows.
In your script, when .setFields("*") is used, the script works.
You want to update only backgroundColor.
In this case, please modify as follows.
From:
.setFields("backgroundColor")
To:
.setFields("userEnteredFormat.backgroundColor")
By this, backgroundColor is updated.
Reference:
RepeatCellRequest

Add Renderer to Vaadin Grid

I migrating a Vaadin 8 project to Vaadin 14 and i try to show HTML in a grid column.
I figured out, that i have to use a TemplateRenderer, but how can i use it?
Here is the code from Vaadin 8:
grid.addColumn(e -> {
return ((Data) e).getValues()[index];
}).setCaption(myCaption).setRenderer(new HtmlRenderer());
In Vaadin 14 i did this:
gird.addColumn(e -> {
return TemplateRenderer.<Data>of((String) e.getValues()[index])
}).setHeader(myCaption);
e.getValues()[index] includes HTML, for example: <FONT SIZE = 4 COLOR = BLACK> ⚫</FONT>
In Vaadin 14 it always returns com.vaadin.flow.data.renderer.
Before we get to how to use a TemplateRenderer with Grid, I first need to point out that what you're trying to do is potentially dangerous because of the way it can lead to XSS vulnerabilities if the HTML strings that you want to show may be supplied by application users.
Using the Html component is indeed one potential solution to this problem, but it causes some overhead because there will be one component instance in memory for each row in the grid. There's also the same problem with potentially causing XSS vulnerabilities.
The first thing to notice with TemplateRenderer is that the renderer needs to be supplied directly as a parameter to addColumn. Wrapping it in a lambda will instead use that lambda as a value provider, which means that the toString() value of the renderer instance will be used with the default plain text renderer.
All rows should use the same renderer instance, configured with the same template string. The trick is that you can pass the data to show as a per-row property that the template will render for you. The last piece of the puzzle is that the template syntax tries to protect you against accidental XSS vulnerabilities, so you need to use a slightly contrived syntax to actually make it render the data as HTML.
Putting everything together, and also using JSoup to remove any dangerous stuff from your HTML strings, the working solution looks like this:
grid.addColumn(TemplateRenderer
.<Data> of("<div inner-h-t-m-l='[[item.html]]'></div>")
.withProperty("html", e -> {
String unsafeHtml = e.getValues()[index];
String safeHtml = Jsoup.clean(unsafeHtml, Whitelist.basic());
return safeHtml;
})).setHeader(myCaption);
I found a solution.
Instead of using the TemplateRenderer I used a ComponentRenderer.
The migration documentation recomented to use a TempleteRenderer or an ComponentRenderer instead of the htmlRenderer.
https://vaadin.com/docs/v14/flow/migration/8-migration-example.html#step-4-product-grid
Here is the code that worked for me:
grid.addColumn(new ComponentRenderer<>(e -> {
String value = (String) e.getValues()[index];
return new Html(value);
})).setHeader(String.valueOf(col + 1));
Comparing your attempts with TemplateRenderer and the documentation, I would assume it will have to look like this:
grid.addColumn(e ->
TemplateRenderer.<Data>of("[[item.customValue]]")
.withProperty("customValue", (String) e.getValues()[index])
).setHeader(myCaption);

How to reset back to default css after adding style?

Basically I have changed the css for a text field in javafx by adding a style class like this:
textfield.getStyleClass().add("textfieldstyle");
But then I want to be able to revert it back to its original appearance. But since the original appearance in this case is the default skin for JavaFX, I can't find the original layout for the textfields. I found the textfieldskin properties here, but its a jungle, and I can't find anything about the color of the -fx-control-inner-background, -fx-text-box-border and -fx-focus-color, which is what I want to know.
I've triedtextfield.getStyleClass().remove("textfieldstyle"); and think that does remove the new css, but it doesn't apply the old one again.
Thanks to the comments by #UlukBiy and #varren I solved the issue. System.out.println(textfield.getStyleClass()); was of great use since it allowed me to check which style classes were applied on the text field as default. And as it is pointed out in the comments those where text-input and text-field.
So to restore the text field's css to its default value I just did:
textfield.getStyleClass().clear();
textfield.getStyleClass().addAll("text-field", "text-input");
To reset an element's default styling after setting it using .setStyle("css settings....."); you can simply use -
textfield.setStyle(null);
I'm not sure if this would work on it's own for an element that's had a class applied using .getStyleClass().add("textfieldstyle"); but if not you could do something like -
textfield.getStyleClass().clear();
textfield.setStyle(null);
A short way to effictively remove your style class even in case of duplicates, with a lambda :
textfield.getStyleClass().removeIf(style -> style.equals("textfieldstyle"));
The following test code works for me when adding and removing a class from a control such as Textfield:
import javafx.scene.control.TextInputControl;
public class test
{
protected void setEditable(final TextInputControl toControl, final boolean tlEditable)
{
toControl.setEditable(tlEditable);
if (tlEditable)
{
if (toControl.getStyleClass().contains("non-editable-class"))
{
toControl.getStyleClass().removeAll("non-editable-class");
}
}
else if (!toControl.getStyleClass().contains("non-editable-class"))
{
toControl.getStyleClass().add("non-editable-class");
}
}
}

how to index polygon data in Lucene

How can I add polygon data to Lucene index. Below is the code snippet which I use
private SpatialContext ctx;
ctx.readShapeFromWkt("POLYGON((-10 30,-40 40,-10 -20,40 20,0 0,-10 30))")
But it give the exception with message
Unknown Shape definition [POLYGON((-10 30,-40 40,-10 -20,40 20,0 0,-10 30))]
While same format works fine in solr. What should I use instead of this format or way
SpatialContext does not support "POLYGON" (see WktShapeParser).
JtsSpatialContext adds support for polygons.
You may need to get the JTS topology suite added to your classpath first. Then set your spatialContextFactory to com.spatial4j.core.context.jts.JtsSpatialContextFactory.

Categories

Resources