How can i change the selected word font color?
I want to create a function for this, but my level is so basic with this api...
This is my pseudo cod:
public String setTextColor(String word){
String coloredWord = null;
/**
* setColor method here
*/
return coloredWord;
}
So, this function have to return the colored word.
Please help, if you can :)
You need to set the Run Property. This works similarly to Rich Text Strings in the Excel API, but is a bit different.
// p is your paragraph object
XWPFRun r = p.createRun();
r.setColor("ff0000");
r.setText("This text is red");
r = p.createRun();
r.setText(" but this text is black");
All text in a given run has the same formatting properties. Any time those properties need to change, you need to add a new run to the paragraph.
I need to develop an Eclipse plugin that can "color" the same occurrence of a variable/value/tag in XML as the JAVA editor does.
I'm using the default XML Editor from eclipse, and am currently able to put a grey background on the selected words with the following code :
for (Point p : offsets){
TextPresentation t = new TextPresentation();
t.replaceStyleRange(new StyleRange( (int)p.getX(),
(int)(p.getY() - p.getX()),
null,
Color.win32_new(null, 0xDDDDDD)));
fText.changeTextPresentation(t, true);
}
My problem is that I can't recover the default style if the user tries to select another variable/tag/value. The text will not set its natural coloring after loosing the focus. For the moment, I am using hard-coded RGB values to set the defaults colors, BUT it is only "working" if the user kept the Eclipse default theme (white theme).
Is there a way to ask the document for a complete syntax coloring re-validation ?
Thanks for reading.
I found an answer by myself.
Here it is :
before changing the style of the selection, you should first save the current style. Use a similar structure:
private ArrayList<Point> offsets = new ArrayList<Point>();
private ArrayList<Color> foregroundgColor = new ArrayList<Color>();
Then you put all the styles/offsets of the occurences in this structure, in a loop statement :
offsets.add(new Point(i,j));
fgColor.add(fText.getTextWidget().getStyleRangeAtOffset(i).foreground);
You can now apply the "highlighting" (grey background on the occurences) :
for (Point p : offsets){
TextPresentation t = new TextPresentation();
t.replaceStyleRange(new StyleRange( (int)p.getX(),
(int)(p.getY() - p.getX()),
null,
Color.win32_new(null, 0xDDDDDD)));
fText.changeTextPresentation(t, true);
}
Finally, when the selected occurences loses the focus, you restore the default styles :
for (int i = 0; i < offsets.size(); i++){
Point p = offsets.get(i);
TextPresentation t = new TextPresentation();
t.replaceStyleRange(new StyleRange( (int)p.getX(),
(int)(p.getY() - p.getX()),
fgColor.get(i),
null));
fText.changeTextPresentation(t, true);
}
offsets.clear();
fgColor.clear();
I am trying to implement a text editor in NetBeans with simple functions like: text styling (bold, italic, underlined ...), open file, save file and search. Search function searches for a specified string in the document and highlights the results. The problem occurs when I am trying to remove those highlights or add new ones for different search. Currently I use StyledDocument object together with jTextPane.
private void textHighlight(int startAt, int endAt, Color c) {
Style sCh;
sCh = textEditor.addStyle("TextBackground", null);
StyleConstants.setBackground(sCh, c);
StyledDocument sDoc = textEditor.getStyledDocument();
sDoc.setCharacterAttributes(startAt, endAt - startAt, sCh, false);
}
private void textFind(java.awt.event.ActionEvent evt) {
int searchIndex = 0;
String searchValue = searchField.getText();
if(lastIndex != -1) {
while(searchIndex < lastIndex) {
countOccurencies++;
int i = textEditor.getText().indexOf(searchValue, searchIndex);
textHighlight(i, i+searchValue.length(), Color.MAGENTA);
searchIndex = i+searchValue.length();
}
statusLabel.setText(countOccurencies + " rezultatov.");
} else {
statusLabel.setText("Ni rezultatov!");
}
}
}
private void searchEnd(java.awt.event.ActionEvent evt) {
textEditor.removeStyle("TextBackground");
}
removeStyle() doesn't seem to be working.
Must admit I don't know how Styles work, but maybe the attributes of the Style are copied to the Document at the time you add the Style?
Another option is to use the Highlighter class. See textPane.getHighlighter(). Then you can keep track of the individual highlights you add in an ArrayList and then use the ArrayList to remove the highlights when you want the clear the text pan.
Also, inside your search loop you have a couple of problems:
Don't use the getText() method. This can cause problems with text offsets being off by one for every line of text in the text pane. See Text and New Lines for more information and the solution.
You are getting the text inside the loop which is not very efficient. You should only get the text once outside the loop.
Context
I've been working on dynamic PDF generation for a while now, and I've come across my final requirement. Alas, it's a nightmare. I'm using the iText library, version 2.1.7.
I'm basically trying to get a formatting like the top row (which I just mocked up in paint). The other rows are how it looks at the moment, but I'm having some real trouble with getting them to line up properly!
Code
The code being used to generate each color coded block is here:
String currentPrice = p.getPrice();
String timeStr = p.getTime();
Chunk price = new Chunk(currentPrice);
Chunk time = (Chunk) generatePdfElement("Timestamp", timeStr);
if (priceDbl > lastPrice) {
// set color to blue.
price.setBackground(WebColors.getRGBColor("#7777FF"));
time.setBackground(WebColors.getRGBColor("#7777FF"));
} else if (priceDbl < lastPrice) {
// set to red.
price.setBackground(WebColors.getRGBColor("#FF0000"));
time.setBackground(WebColors.getRGBColor("#FF0000"));
}
Paragraph pricePara = new Paragraph();
pricePara.add(price);
pricePara.add(generateBreakLine());
pricePara.add(time);
pricePara.add(generateBreakLine());
// Add the new price data to the list of all the prices for this cell.
allPrices.add(pricePara);
allPrices is then added to a paragraph and put into the cell:
Paragraph pricesCellValue = new Paragraph();
pricesCellValue.addAll(allPrices);
PdfPCell pricesCell = new PdfPCell(pricesCellValue);
pricesCell.setBackgroundColor(WebColors.getRGBColor(getRowStr()));
selectionsTable.addCell(pricesCell);
// Add each cell to the table to create the row.
The approaches I've tried
I tried the obvious, which was removing the last breakline from each Chunk. This didn't work, and it just looked exactly the same, although each Chunk was closer together.
I also tried changing from Paragraph to Phrase, which means the code looked like this:
Phrase pricePara = new Phrase();
pricePara.add(price);
pricePara.add(generateBreakLine());
pricePara.add(time);
//pricePara.add(generateBreakLine());
// Add the new price data to the list of all the prices for this cell.
allPrices.add(pricePara);
And this was the result:
So now I'm fresh out of ideas! Does anyone else have any suggestions, or some experience with iText in this area?
Edit
Just for clarity, generateBreakLine() generates a new empty Paragraph object.
I used a nested PdfPTable in the last cell, to format the positioning of each Phrase. Works like a dream!
I have:
JTextPane jtextPane = new JTextPane();
jtextPane.setEditorKit(new HTMLEditorKit());
...
Then later I try to add an unordered list button to the toolbar such that the action is:
Action insertBulletAction =
HTMLEditorKit.InsertHTMLTextAction ("Bullets", "<ul><li> </li></ul>",
HTML.Tag.P, HTML.Tag.UL);
JButton insertBulletJButton = new JButton(insertBulletAction);
And this does include the proper code if I take a dump of the html that's generated. However it will be rendered really badly, as in not even close to reasonable as illustrated below:
However if I do:
jtextPane.setText(jtextPane.getText());
jtextPane.repaint();
Then all is well. But if I don't do BOTH lines, then neither will work alone. I can also make it work by setting the text before I make the jtextPane visible.
This is really odd and I don't understand why I'd have to do a setText(getText()) followed by a repaint().
PS: This is very similar to this question: How to implement bullet points in a JTextPane? And it works except that it's not rendering correctly. I don't know if it has to do with HTMLEditorKit vs RTFEditorKit, but something i causing the rendering to fail. The html source code under is perfect...
PS2: This link is also very handy but it also didn't show a solution.
Update: Here is the full code as requested, but there isn't much else...
public static void main(String[] args)
{
JFrame jframe = new JFrame();
jframe.setSize(800, 600);
jframe.setVisible(true);
JTextPane jtextPane = new JTextPane();
jtextPane.setEditorKit(new HTMLEditorKit());
Action insertBulletAction = new HTMLEditorKit.InsertHTMLTextAction ("Bullets",
"<ul><li> </li></ul>", HTML.Tag.P, HTML.Tag.UL);
JButton insertBulletJButton = new JButton(insertBulletAction);
insertBulletJButton.setRequestFocusEnabled(false);
jframe.setLayout(new BorderLayout());
jframe.add(new JScrollPane(jtextPane));
jframe.add(insertBulletJButton, BorderLayout.SOUTH);
}
The answer is actually quite complex. Basically the InsertHtmlAction is just not good enough by itself. You need a lot of work and logic to get to a working list action. It requires a lot of logic! So you definitely have to override the Action class. Basically the parameters of the InsertHtmlAction will change depending on where in the html code you are.
That being said, I studied several open source solutions to get a better understanding for what was all involved. Many long hours later (and many hours spent beforehand as well), and I was finally able to figure it out well enough for what I needed. But it is fairly complex. Too complex to write about here, it would take a chapter of a book just to explain the concepts. And even then I'm still fuzzy on some details (I'm still working through it).
I can now understand why people sell components for this!
I found that most open source solutions don't really deal nicely with lists. They generally somewhat work but most have glaring bugs. That or they just don't really handle anything but the most basic cases of lists.
Here is a list of systems I looked at to understand how they work to get a better understanding of everything. I unfortunately found the documentation lacking or hard to understand, so looking at these projects helped me more than anything else.
The most helpful
Shef - Most helpful of all.
ekit - Decent but many bugs and not the best code organization
MetaphaseEditor - Similar to ekit
Moderately helpful (more complex, buggy, less relevant, etc.)
OOoBean - Tried but too much (and hence too much complexity) for what I needed. Looks really good though, you just need to invest time.
JXHTMLEdit - Seemed interest
Additional links
JWebEngine - Mostly for rendering
Joeffice - Interesting but it's all videos and wasn't enough ready enough yet.
Richtext - No comments. I only briefly looked at it.
JRichTextEditor - No comments either, same thing.
Paid
JWord - Look very interesting but it was beyond the budget for what I was doing.
For those that need a more specific explanation of HTMLEditorKit's peculiar way of handling lists, it all comes down to the markup generated. I'll try it to keep it as simple as I can. Let's rewind a bit and talk about HTML documents in Swing.
Turns out that Swing relies on paragraphs for doing cursor positioning and navigation. For example, every time you write in a new line, a new pagraph is generated. Even the corresponding view of the document depends on the presence of paragraphs in the right places. There must always be a paragraph in the document. Otherwise, odd things start to happen.
So, what happens if the document is completely blank? Surely, there is no need for a paragraph there. Well, unbelievably, even in that case there is a paragraph. This is one of the effects of what the documentation calls a p-implied or implied paragraph. The HTML generated for a blank document is:
<html>
<head></head>
<body>
<p style="margin-top: 0">
</p>
</body>
</html>
Expectedly, when you insert a list, it is placed inside the paragraph:
<html>
<head></head>
<body>
<p style="margin-top: 0">
<ul>
<li>
</li>
</ul>
</p>
</body>
</html>
... which is of course invalid markup (not just because there is no title inside the head).
But wait! It gets more interesting. Once the list is inserted, the "internal pointer" of the document, as it were, stays after the closing </ul> tag. Consequently, if you type "Hello", it will be placed outside the list:
<html>
<head></head>
<body>
<p style="margin-top: 0">
<ul>
<li>
</li>
</ul>
Hello
</p>
</body>
</html>
This is why that “Hello” appears way to the right relative to the inserted bullet. Now, as Stephane mentioned in the question, setText(getText()) magically solves the problem. That's because manually setting the contents of the JTextPane instance triggers the parser, which in turn places the “internal pointer” where it should be; inside the list. Now when you type “Hello”, it will appear much closer to the bullet. I say much closer because there is still something not right about the HTML:
<html>
<head></head>
<body>
<p style="margin-top: 0">
<ul>
<li>
Hello
</li>
</ul>
</p>
</body>
</html>
Notice there is no paragraph enclosing the new text in the list. That's why the text won't appear right next to the bullet.
How do you go about all this? Well, that's the tricky bit Stephane was talking about. You would be up against a combination of bugs (such as this one), undocumented glitches (like this one) and default behaviour as we have seen. The easiest way out is to use one of the solutions in Stephane's list. I agree Shef is the best of all but has not have that much activity since 2009 (!). Personally, I found Stanislav's website incredibly useful for all things EditorKit.
You can also have a look at ADAPRO: a pretty stable open-source assistive editor I was heavily involved in. The assistive features are buggy but the core editing functionality was thoroughly tested. The following code comes from that project. It requires the ElementWriter class from SHEF's net.atlanticbb.tantlinger.ui.text package.
//HTML representation of an empty paragraph
private static final String sEmptyParagraph = "<p style=\"margin-top: 0\"></p>";
/**
* Translates into HTML a given element of the document model.
* #param element Element to serialise to a HTML string
* #param out Serialiser to HTML string
* #return HTML string "equivalent" to given element
*/
static String extractHTML (Element element, StringWriter out) {
ElementWriter writer = new ElementWriter (out, element);
try {
writer.write();
} catch (IOException e) {
System.out.println ("Error encountered when serialising element: " +e);
e.printStackTrace();
} catch (BadLocationException e) {
System.out.println ("Error encountered when extracting HTML at the element's position: " +e);
e.printStackTrace();
}
return out.toString();
}
/**
* Determines if the parent element of the current paragraph element is one of a number provided as a list
* of tag names. If so, it returns the parent element.
* #param document Document model of the text
* #param iCaretPos Caret's current position
* #param sTags Possible parent tags
* #return Parent element
*/
static Element getNearestParent (HTMLDocument document, int iCaretPos, String sTags) {
Element root;
root = document.getParagraphElement (iCaretPos);
do {
root = root.getParentElement();
} while (sTags.indexOf (root.getName()) == -1);
return root;
}
/**
* Inserts all HTML tags required to build an ordered/unordered list at the caret's current position.
* If the aim is instead to turn the numbered/bulleted paragraphs into plain ones, it takes care of
* deleting the necessary tags.
* #param sTypeList Type of list to build: "ul" or "ol".
* #param textArea Editable area containing text.
*/
static void insertList (String sTypeList, JTextPane textArea) {
boolean bOnlyListSelected; //selection includes a list exclusively
int iStartIndex, iEndIndex, //element indexes included in selection
iStartSel, iEndSel, //starting and ending offset of selected text
iItemNo, //total number of list items
i;
String sHTML, //HTML code of text represented by a given element
sHTMLBlock, //HTML code block to be inserted into document model
sRest; //part of the text remaining unselected after the selected block
HTML.Tag tag; //current list tag
HTMLDocument document; //data model underlying the typed text
Element root, //root element of the document model tree
section; //element representing a block of text
SimpleAttributeSet attribIns; //backup of current input attributes
//Fetches the current document
document = (HTMLDocument) textArea.getDocument();
//Finds the topmost parent element of the current paragraph (effectively, is the list inside a table?)
root = getNearestParent (document, textArea.getCaretPosition(), "td body");
//Range of elements included in the selection
iStartSel = textArea.getSelectionStart();
iEndSel = textArea.getSelectionEnd();
iStartIndex = root.getElementIndex (iStartSel);
iEndIndex = root.getElementIndex (iEndSel);
//HTML-related initialisations
sHTML = "";
sHTMLBlock = "";
tag = null;
//Checks if selection is comprised of just list items
i = iStartIndex;
bOnlyListSelected = true;
do {
tag = HTML.getTag (root.getElement(i).getName());
//Is it a list tag?
if ((tag == null) || ((!tag.equals (HTML.Tag.OL)) && (!tag.equals (HTML.Tag.UL))))
bOnlyListSelected = false;
i++;
} while (bOnlyListSelected && (i <= iEndIndex));
//Back up current input attributes
attribIns = new SimpleAttributeSet (textArea.getInputAttributes());
try {
//At some point in the selection there is no previous list...
if (!bOnlyListSelected) {
//Inserts <LI> tags for every text block
for (i = iStartIndex; i <= iEndIndex; i++) {
section = root.getElement(i);
tag = HTML.getTag (section.getName());
//Retrieves current HTML
sHTML = extractHTML (section, new StringWriter());
//If it is non-listed text, reconstitute the paragraph
if (tag == null)
sHTML = "<p style=\"margin-top: 0;\">" +sHTML+ "</p>";
//Text in a list already => no nesting (delete <UL>/<OL> tags)
if (sHTML.indexOf("<li>") != -1) {
sHTML = sHTML.substring (sHTML.indexOf("<li>"), sHTML.length());
sHTML = sHTML.substring (0, sHTML.lastIndexOf("</li>") + 5);
//Non-listed text => add <LI> tags
} else sHTML = "<li>" +sHTML+ "</li>";
sHTMLBlock = sHTMLBlock + sHTML;
}
sHTMLBlock = "<"+sTypeList+">" +sHTMLBlock.trim()+ "</"+sTypeList+">";
//Gets the text coming after caret or end of selection
sRest = textArea.getText (iEndSel, document.getLength() - iEndSel);
//Adds an empty paragraph at the end of the list if the latter coincides with the end of the document
//or if the rest of the document is empty. This is to avoid a glitch in the editor kit's write() method.
//http://java-sl.com/tip_html_kit_last_empty_par.html
if ((root.getElement(iEndIndex).getEndOffset() == root.getEndOffset()) ||
sRest.replaceAll ("[\\p{Z}\\s]", "").trim().isEmpty())
sHTMLBlock = sHTMLBlock + sEmptyParagraph;
//Removes the remaining old non-listed text block and saves resulting HTML string to document model
document.setOuterHTML (root.getElement(iEndIndex), sHTMLBlock);
if (iEndIndex > iStartIndex)
document.remove (root.getElement(iStartIndex).getStartOffset(),
root.getElement(iEndIndex - 1).getEndOffset() -
root.getElement(iStartIndex).getStartOffset());
//Selection just includes list items
} else {
//Works out the list's length in terms of element indexes
root = root.getElement (root.getElementIndex (iStartSel));
iItemNo = root.getElementCount();
iStartIndex = root.getElementIndex (textArea.getSelectionStart());
iEndIndex = root.getElementIndex (textArea.getSelectionEnd());
//For everery <LI> block, remove the <LI> tag
for (i = iStartIndex; i <= iEndIndex; i++) {
sHTML = extractHTML (root.getElement(i), new StringWriter());
sHTML = sHTML.substring(sHTML.indexOf("<li>") + 4, sHTML.length());
sHTML = sHTML.substring(0, sHTML.lastIndexOf("</li>"));
sHTMLBlock = sHTMLBlock + sHTML;
}
//List selected partially? => divide list
if (iItemNo > (iEndIndex - iStartIndex + 1)) {
//Saves HTML string to document model
((HTMLEditorKit) textArea.getEditorKit()).insertHTML (document, root.getElement(iEndIndex).getEndOffset(),
sHTMLBlock, 3, 0, HTML.Tag.P);
//Removes the old block
document.remove (root.getElement(iStartIndex).getStartOffset(),
root.getElement(iEndIndex).getEndOffset() -
root.getElement(iStartIndex).getStartOffset());
//Removes the list tag associated with the block
} else document.setOuterHTML (root, sHTMLBlock.trim());
}
} catch (Exception eTexto) {
System.out.println ("Problemas al eliminar/insertar texto: " +eTexto);
eTexto.printStackTrace();
}
//Recover selection. Previous operations displace the cursor and thus selection highlight is lost
textArea.setSelectionStart (iStartSel);
textArea.setSelectionEnd (iEndSel);
//If only one list item has been created and is the first one, copy all previous style information to the list
if ((!bOnlyListSelected) && (iStartSel == iEndSel)) {
textArea.setCharacterAttributes (attribIns, false);
}
}