JTextPane - HTMLDocument: when adding/removing a new style, other attributes also changes - java

I have a JTextPane (or JEditorPane) in which I want to add some buttons to format text (as shown in the picture).
When I change the selected text to Bold (making a new Style), the font family (and others attributes) also changes. Why? I want to set (or remove) the bold attribute in the selected text and other stays unchanged, as they were.
This is what I'm trying:
private void setBold(boolean flag){
HTMLDocument doc = (HTMLDocument) editorPane.getDocument();
int start = editorPane.getSelectionStart();
int end = editorPane.getSelectedText().length();
StyleContext ss = doc.getStyleSheet();
//check if BoldStyle exists and then add / remove it
Style style = ss.getStyle("BoldStyle");
if(style == null){
style = ss.addStyle("BoldStyle", null);
style.addAttribute(StyleConstants.Bold, true);
} else {
style.addAttribute(StyleConstants.Bold, false);
ss.removeStyle("BoldStyle");
}
doc.setCharacterAttributes(start, end, style, true);
}
But as I explained above, other attributes also change:
Any help will be appreciated. Thanks in advance!
http://oi40.tinypic.com/riuec9.jpg

What you are trying to do can be accomplished with one of the following two lines of code:
new StyledEditorKit.BoldAction().actionPerformed(null);
or
editorPane.getActionMap().get("font-bold").actionPerformed(null);
... where editorPane is an instance of JEditorPane of course.
Both will seamlessly take care of any attributes already defined and supports text selection.
Regarding your code, it does not work with previously styled text because you are overwriting the corresponding attributes with nothing. I mean, you never gather the values for the attributes already set for the current selected text using, say, the getAttributes() method. So, you are effectively resetting them to whatever default the global stylesheet specifies.
The good news is you don't need to worry about all this if you use one of the snippets above. Hope that helps.

I made some minor modifications to your code and it worked here:
private void setBold(boolean flag){
HTMLDocument doc = (HTMLDocument) editorPane.getDocument();
int start = editorPane.getSelectionStart();
int end = editorPane.getSelectionEnd();
if (start == end) {
return;
}
if (start > end) {
int life = start;
start = end;
end = life;
}
StyleContext ss = doc.getStyleSheet();
//check if BoldStyle exists and then add / remove it
Style style = ss.getStyle(editorPane.getSelectedText());
if(style == null){
style = ss.addStyle(editorPane.getSelectedText(), null);
style.addAttribute(StyleConstants.Bold, true);
} else {
style.addAttribute(StyleConstants.Bold, false);
ss.removeStyle(editorPane.getSelectedText());
}
doc.setCharacterAttributes(start, end - start, style, true);
}

Related

Text Highlighting with PDFClown without using PDF Annotations

I've started using PDFClown some weeks ago. My purpose is multi-word highlighting, mainly on newspapers. Starting from the org.pdfclown.samples.cli.TextHighlightSample example, I succeeded in extracting multi-word positions and highlighting them. I even solved some problems due to text ordering and matching in most cases.
Unfortunately my framework includes FPDI and it does not consider PDFAnnotations. So, all the content outside of a page content stream, like text annotations and other so called markup annotations, get lost.
So any suggestion on creating "Text Highlighting" with PdfClown and without using PDF annotations?
To not have the highlight in an annotation but instead in the actual page content stream, one has to put the graphic commandos into the page content stream which in case of the org.pdfclown.samples.cli.TextHighlightSample example are implicitly put into the normal annotation appearance stream.
This can be implemented like this:
org.pdfclown.files.File file = new org.pdfclown.files.File(resource);
Pattern pattern = Pattern.compile("S", Pattern.CASE_INSENSITIVE);
TextExtractor textExtractor = new TextExtractor(true, true);
for (final Page page : file.getDocument().getPages())
{
final List<Quad> highlightQuads = new ArrayList<Quad>();
Map<Rectangle2D, List<ITextString>> textStrings = textExtractor.extract(page);
final Matcher matcher = pattern.matcher(TextExtractor.toString(textStrings));
textExtractor.filter(textStrings, new TextExtractor.IIntervalFilter()
{
#Override
public boolean hasNext()
{
return matcher.find();
}
#Override
public Interval<Integer> next()
{
return new Interval<Integer>(matcher.start(), matcher.end());
}
#Override
public void process(Interval<Integer> interval, ITextString match)
{
{
Rectangle2D textBox = null;
for (TextChar textChar : match.getTextChars())
{
Rectangle2D textCharBox = textChar.getBox();
if (textBox == null)
{
textBox = (Rectangle2D) textCharBox.clone();
}
else
{
if (textCharBox.getY() > textBox.getMaxY())
{
highlightQuads.add(Quad.get(textBox));
textBox = (Rectangle2D) textCharBox.clone();
}
else
{
textBox.add(textCharBox);
}
}
}
highlightQuads.add(Quad.get(textBox));
}
}
#Override
public void remove()
{
throw new UnsupportedOperationException();
}
});
// Highlight the text pattern match!
ExtGState defaultExtGState = new ExtGState(file.getDocument());
defaultExtGState.setAlphaShape(false);
defaultExtGState.setBlendMode(Arrays.asList(BlendModeEnum.Multiply));
PrimitiveComposer composer = new PrimitiveComposer(page);
composer.getScanner().moveEnd();
// TODO: reset graphics state here.
composer.applyState(defaultExtGState);
composer.setFillColor(new DeviceRGBColor(1, 1, 0));
{
for (Quad markupBox : highlightQuads)
{
Point2D[] points = markupBox.getPoints();
double markupBoxHeight = points[3].getY() - points[0].getY();
double markupBoxMargin = markupBoxHeight * .25;
composer.drawCurve(new Point2D.Double(points[3].getX(), points[3].getY()),
new Point2D.Double(points[0].getX(), points[0].getY()),
new Point2D.Double(points[3].getX() - markupBoxMargin, points[3].getY() - markupBoxMargin),
new Point2D.Double(points[0].getX() - markupBoxMargin, points[0].getY() + markupBoxMargin));
composer.drawLine(new Point2D.Double(points[1].getX(), points[1].getY()));
composer.drawCurve(new Point2D.Double(points[2].getX(), points[2].getY()),
new Point2D.Double(points[1].getX() + markupBoxMargin, points[1].getY() + markupBoxMargin),
new Point2D.Double(points[2].getX() + markupBoxMargin, points[2].getY() - markupBoxMargin));
composer.fill();
}
}
composer.flush();
}
file.save(new File(RESULT_FOLDER, "multiPage-highlight-content.pdf"), SerializationModeEnum.Incremental);
(HighlightInContent.java method testHighlightInContent)
You will recognize the text extraction frame from the original example. Merely now the quads from a whole page are collected before they are processed, and the processing code (which mostly has been borrowed from TextMarkup.refreshAppearance()) draws forms representing the quads into the page content.
Beware, to make this work generically, the graphics state has to be reset before inserting the new instructions (the position is marked with a TODO comment). This can be done either by applying save/restore state or by actually counteracting unwanted changed state entries. Unfortunately I did not see how to do the former in PDF Clown and have not yet had the time to do the latter.

How to make the text in an SWT Link widget selectable

I have a text in the Link SWT widget created as follow:
Link message = new Link(parent, SWT.WRAP);
message.setText(myMessage);
I want the text (in myMessage variable) be selectable, to grant users to copy it.
How can I do this?
I have used Link widget because I need hyperlinks in the text to be clickable.
The SWT Link widget is not selectable. To work around this I can think of either
provide a context menu for the Link with a Copy menu item that copies the text to the clipboard
place a Copy (tool) button next to the Link that copies the text to the clipboard
use a Browser widget which is selectable but harder to layout and requires extra work to trigger the functinality when the link is selected
if you don't mind the extra dependency to org.eclipse.ui.forms, use the FormText. The FormText can show hyperlinks and allows to select and copy text
Why not using a StyledText to allow text selection ?
String string = "This is sample text with a link and some other link here.";
final StyledText styledText = new StyledText (shell, SWT.MULTI | SWT.BORDER);
styledText.setText(string);
String link1 = "link";
String link2 = "here";
StyleRange style = new StyleRange();
style.underline = true;
style.underlineStyle = SWT.UNDERLINE_LINK;
int[] ranges = {string.indexOf(link1), link1.length(), string.indexOf(link2), link2.length()};
StyleRange[] styles = {style, style};
styledText.setStyleRanges(ranges, styles);
styledText.addListener(SWT.MouseDown, new Listener() {
#Override
public void handleEvent(Event event) {
// It is up to the application to determine when and how a link should be activated.
// In this snippet links are activated on mouse down when the control key is held down
if ((event.stateMask & SWT.MOD1) != 0) {
try {
int offset = styledText.getOffsetAtLocation(new Point (event.x, event.y));
StyleRange style = styledText.getStyleRangeAtOffset(offset);
if (style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK) {
System.out.println("Click on a Link");
}
} catch (IllegalArgumentException e) {
// no character under event.x, event.y
}
}
}
});
Full example here

iTextSharp Footer Gets Progressively Bolder with Each Page

Using OnEndPage, I add a footer to my PDF created with iTextSharp. The footer font gets progressively bolder with each page.
How can I create consistent NORMAL fonts in my footer?
Here is my code:
public override void OnEndPage(PdfWriter writer, Document doc)
{
iTextSharp.text.Image gif = null;
if (FooterImage)
{
if (File.Exists(PathImages))
{
gif = iTextSharp.text.Image.GetInstance(PathImages);
gif.ScaleToFit(75f, 75f);
gif.SetAbsolutePosition(0, 0);
}
}
string sFooter = string.Empty;
if (FooterURL != null && FooterURL.Length > 0)
{
sFooter = FooterURL + " ";
}
if (FooterDate != null && FooterDate.Length > 0)
{
sFooter += FooterDate + " ";
}
if (FooterPage)
{
sFooter += "Page " + doc.PageNumber.ToString();
}
PdfPTable footerTbl = new PdfPTable(1);
footerTbl.TotalWidth = 900;
footerTbl.HorizontalAlignment = Element.ALIGN_CENTER;
Phrase ph = new Phrase(sFooter, FontFactory.GetFont(FontFactory.TIMES, 10, iTextSharp.text.Font.NORMAL));
PdfPCell cell = new PdfPCell(ph);
cell.Border = 0;
cell.PaddingLeft = 10;
footerTbl.AddCell(cell);
if (FooterImage)
{
PdfContentByte cbfoot = writer.DirectContent;
PdfTemplate tpl = cbfoot.CreateTemplate(gif.Width / 5, gif.Height / 5);
tpl.AddImage(gif);
cbfoot.AddTemplate(tpl, doc.PageSize.Width - 100, 10);
}
footerTbl.WriteSelectedRows(0, -1, 10, 30, writer.DirectContent);
}
In the old days, when there wasn't as much choice as today regarding fonts, people used workarounds to create bold fonts. One way to make a font bold, was by adding the same text over and over again at the same position. I think that this is happening to you.
When you use page events correctly, the onEndPage() method is triggered automatically each time a page ends. My guess is that you're doing something very wrong that triggers the onEndPage() many times. Maybe you are called the onEndPage() from your code, maybe you're adding the page event to the writer more than once (and page events are cumulative).
If I have to guess, I would guess that you are doing the latter. My guess is based on the fact that you are using variables such as FooterImage in your onEndPage() method. How are you setting that variable. If you are setting it in the constructor of the page event and you're adding the new page event over and over again to the writer, then you're doing it wrong.

How to set font color for selected text in jTextArea?

I have to set defined color(like red) for selected text in jTextArea. It is like highlighting process in text area (jTextArea). When I select particular text and click on any button it should change in predefined color.
I can change jTextArea to jTextPane or JEditorPane if there is any solution.
Styled text (with a color attribute for characters) is available as StyledDocument, and usable in JTextPane and JEditorPane. So use a JTextPane.
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
StyledDocument doc = textPane.getStyledDocument();
int start = textPane.getSelectionStart();
int end = textPane.getSelectionEnd();
if (start == end) { // No selection, cursor position.
return;
}
if (start > end) { // Backwards selection?
int life = start;
start = end;
end = life;
}
Style style = textPane.addStyle("MyHilite", null);
StyleConstants.setForeground(style, Color.GREEN.darker());
//style = textPane.getStyle("MyHilite");
doc.setCharacterAttributes(start, end - start, style, false);
}
Mind: the style can be set at the creation of the JTextPane, and as the outcommented code shows, retrieved out of the JTextPane field.
First of all you can not do this using JTextArea because it is a plain text area.You have to use a styled text area like JEditorPane.see here.You can use a HTMLDocument and do what you want.See here

Discover titles/paragraphs in word docs

I'm trying to discover paragraphs/titles in word documents.
I use Apache POI to do this.
An example that I use is:
fs = new POIFSFileSystem(new FileInputStream(filesname));
HWPFDocument doc = new HWPFDocument(fs);
WordExtractor we = new WordExtractor(doc);
ArrayList titles = new ArrayList();
try {
for (int i = 0; i < we.getText().length() - 1; i++) {
int startIndex = i;
int endIndex = i + 1;
Range range = new Range(startIndex, endIndex, doc);
CharacterRun cr = range.getCharacterRun(0);
if (cr.isBold() || cr.isItalic() || cr.getUnderlineCode() != 0) {
while (cr.isBold() || cr.isItalic() || cr.getUnderlineCode() != 0) {
i++;
endIndex += 1;
range = new Range(endIndex, endIndex + 1, doc);
cr = range.getCharacterRun(0);
}
range = new Range(startIndex, endIndex - 1, doc);
titles.add(range.text());
}
}
}
catch (IndexOutOfBoundsException iobe) {
//sometimes this happens have to find out why.
}`enter code here`
This works for all bold, italic or underlined text.
But what I want is to discover the font that is used most often. And then to discover variations compared to that font style. Anyone an Idea?
Well, some thoughts would be to try some of the following:
cr.getFontSize() could be used at the beginning of a paragraph to see if the range changes font size. That in conjunction with bold, italic or underlined would be a good identifier.
cr.getFontName() could also be used to determine when and where the font changes in a given range.
cr.getColor() would be another possibility to help identify if the user is using different colors for a font.
I guess I would iterate over the range and create multiple CharacterRun items each time the text characteristics change. Then evaluate each item based on position in the paragraph as well as all of the afore-mentioned characteristics (size, color, name, bold, italics, etc.). Perhaps create some sort of weighting scale based on the most common values.
It might also be of value to create a Title object and store the values for each set of characteristics to help optimize searches in later character runs in the same document.
You might want to take a look at the buildParagraphTagAndStyle method in Tika's WordExtractor:
https://svn.apache.org/repos/asf/tika/trunk/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/WordExtractor.java
For HWPF (.doc), to call it you'd do:
StyleDescription style =
document.getStyleSheet().getStyleDescription(p.getStyleIndex());
TagAndStyle tas = buildParagraphTagAndStyle(
style.getName(), (parentTableLevel>0)
);
For XWPF (.docx) you'd do:
XWPFStyle style = styles.getStyle(paragraph.getStyleID());
TagAndStyle tas = WordExtractor.buildParagraphTagAndStyle(
style.getName(), paragraph.getPartType() == BodyType.TABLECELL
);
It will be easier if you process the data by converting it into paragraphs.
WordExtractor we = new WordExtractor(doc);
String[] para = we.getParagraphText();
Then work paragraph wise. If your code already couldn't figure out the titles, then you can check for bold and underlines in each paragraph.
The paragraphs function as follows:
for(int i=0;i<para.length;i++)
{
System.out.println("Length of paragraph "+(i+1)+": "+ para[i].length());
System.out.println(para[i].toString());
}
A working example can be found here:
http://sanjaal.com/java/120/java-file/how-to-read-doc-file-using-java-and-apache-poi/#comments

Categories