Link to home
Start Free TrialLog in
Avatar of qasinformatik
qasinformatik

asked on

ui-functionality for chat textbox (JTextPane?) - problems with coordinates, background for enire lines...

Hello Experts!

I'm upgrading a java chat tool to a newer version and have a problem with my User Interface.
The messages shall appear in a multi-functional text-window (actual version is text with font-styles
in a JTextPane).

The requirements:
- every message is visually separated from the others and must be  
- copy out of Text-window must be possible (Ctrl + c)
  --> also Header information like "From Walter" and time should be extracted
- pop-up menu at rightclick --> delete/add user to personal contacts if not already in it
- buttons for delete/add user to personal contacts
- hyperlinks and mail-addresses shall be clickable


How it shall look like:
_______________________________________________________
< From Walter        01.06.2006 - 17:01:54      [P] [X]
   This is the message, that was sent from Walter to Me.
_______________________________________________________
< To Walter          01.06.2006 - 17:01:54      [P] [X]
   This is the response


-> [p] is the button for adding user to personal contacts
-> [x] for deleting the message
-> i will call the following 2 lines the header:
_______________________________________________________
< From Walter        01.06.2006 - 17:01:54      [P] [X]



1) Which java component shall i use?
- JTextarea doesn't support Buttons and other included components - so not interesting
- JTextPane is nice but i missed much functionality (see next points)
- are there any more? i just tried JTextPane



2) The Buttons:
in a JTextPane i can add the buttons as components. But i cannot position them where i want to, they are simply
appended to the end of the text - thats ok but i would prefer to be able to position them if possible - is there
a way?

3) The Background for the Header-Line

I want that the entire header-line has a background color that goes from the right border to the
left border even when resizing the window --> i found out how to set background color to the font-Style
but only the text has a background -> i want the entire line to have a background
- it shall look like when u select a message from the inbox message list in Microsoft Outlook or when hovering
divs in dynamic html.

I tried that but it was impossible for me to find out the pixel coordinates from any text-line.

I tried to temporary set the caret into the line and get the x/y-coordinates by using the following
code (this code shall switch the background color per line from red to blue - for testing):
But somehow it didnt work - the variable "coordinates" was null most times.


public void paintComponent (Graphics g)      {
                              
                        
      // Get section element
      Element section = getDocument().getDefaultRootElement();

      // Get number of paragraphs.
      // In a text pane, a span of characters terminated by single
      // newline is typically called a paragraph.
      int paraCount = section.getElementCount();
                  
      // save the caret position            
      int tempPos = getCaretPosition();

      // Get index ranges for each paragraph
      for (int i=0; i<paraCount; i++) {
                                    
            Element e = section.getElement(i);
            int rangeStart = e.getStartOffset();
                  
            this.setCaretPosition(rangeStart);
            Point coordinates = getCaret().getMagicCaretPosition();
                                    
            if(coordinates!= null){
                                          
                  if(g.getColor()==Color.RED)
                        g.setColor(Color.BLUE);
                  else
                        g.setColor(Color.RED);
                  System.out.println(coordinates.x + " - " + coordinates.y);
                                          
                  g.fillRect(0 , coordinates.y, getWidth(), coordinates.y + 20);
            }
                                    
      }
      // set the caret position back
      this.setCaretPosition(tempPos);
}

The problem is that if i cannot find out which message-element is at a certain position, how shall i know
which message to delete if right-click was performed.
--> how can i find out the x,y-coordinates of a line and even better of any text-part or Button?



4) Selecting an entire message block on rightclick
--> is there a way to select an entire message block? (which is Header + the lines until the next header) for example on right click -
so that the user knows which message he's referencing for deletion.
I get the x/y positions of the click-event but how can i find out which message was clicked?


Thanks in advance.
Avatar of hoomanv
hoomanv
Flag of Canada image

3) The Background for the Header-Line
somthing like this ? I guess

  JTextPane tp = new JTextPane();
  tp.setContentType("text/html");
  tp.setText("<p><div style=\"background-color: #FF0000\"><b><font face=\"Tahoma\" size=\"7\">Hello</font></b></div></p>");
Better use JEditorPane and set the text as HTML content with your formatting!
whats the benefit of JEditorPane to JTextPane since JTextPane is derived from JEditorPane and has all its parents functionality plus more
for the sake of html customization
Avatar of qasinformatik
qasinformatik

ASKER

If i change to text/html - how can i append the text? The setText replaces the text. If I use HTML Code - can I still use my StyledDocument or do i have to change everything to html?

With the StyledDocuments i can insert a JButton. How is that handled with HTML Code? I guess i will have to use HTML Buttons --> but how can I handle the onClick Event?
> how can i append the text?
insertText()

> can I still use my StyledDocument
yes
need not be a html button but an image with hipherlink!

--> the JTextPanel-Definitions
      private javax.swing.JTextPane getMessagesJTP() {
            if(messagesJTP == null) {
                  messagesJTP = new javax.swing.JTextPane();
                  messagesJTP.setEditable(false);
                  //messagesJTP.setContentType("text/html");
                  messagesDoc = (StyledDocument)messagesJTP.getDocument();
                      
                  // Create a style object and then set the style attributes
                  sendTextStyle = messagesDoc.addStyle("sendTextStyle", null);
              
                  StyleConstants.setFontFamily(sendTextStyle, "Verdana");
                  StyleConstants.setFontSize(sendTextStyle, 10);
                  //StyleConstants.setBold(textStyle, true);
                  //StyleConstants.setBackground(textStyle, Color.blue);
                  StyleConstants.setForeground(sendTextStyle, new Color(100,108,123));
                  
                  receiveTextStyle = messagesDoc.addStyle("receiveTextStyle", null);
              
                  StyleConstants.setFontFamily(receiveTextStyle, "Verdana");
                  StyleConstants.setFontSize(receiveTextStyle, 10);
                  //StyleConstants.setBold(textStyle, true);
                  //StyleConstants.setBackground(textStyle, Color.blue);
                  StyleConstants.setForeground(receiveTextStyle, new Color(0,0,0));


                
                  sendUserStyle = messagesDoc.addStyle("sendUserStyle", null);
                  StyleConstants.setFontFamily(sendUserStyle, "Verdana");
                  StyleConstants.setBold(sendUserStyle, true);
                  StyleConstants.setFontSize(sendUserStyle, 10);
                  //StyleConstants.setBackground(userStyle, Color.blue);
                  StyleConstants.setForeground(sendUserStyle, new Color(100,108,123));          
                  
                  
                  receiveUserStyle = messagesDoc.addStyle("receiveUserStyle", null);
                  StyleConstants.setFontFamily(receiveUserStyle, "Verdana");
                  StyleConstants.setBold(receiveUserStyle, true);
                  StyleConstants.setFontSize(receiveUserStyle, 10);
                  //StyleConstants.setBackground(userStyle, Color.blue);
                  StyleConstants.setForeground(receiveUserStyle, new Color(0,0,0));        
   
                  lineStyle = messagesDoc.addStyle("lineStyle", null);
                  StyleConstants.setFontFamily(lineStyle, "Verdana");
                  StyleConstants.setBold(lineStyle, true);
                  StyleConstants.setFontSize(lineStyle, 10);
                  //StyleConstants.setBackground(userStyle, Color.blue);
                  StyleConstants.setForeground(lineStyle, Color.DARK_GRAY);                
                  
                  errorStyle = messagesDoc.addStyle("errorStyle", null);
                  StyleConstants.setFontFamily(errorStyle, "Verdana");
                  StyleConstants.setBold(errorStyle, true);
                  StyleConstants.setFontSize(errorStyle, 10);
                  //StyleConstants.setBackground(userStyle, Color.blue);
                  StyleConstants.setForeground(errorStyle, Color.RED);          

            }
            return messagesJTP;
      }



--> This is where i append the message to the JTextPane


            if(messageNo != 0){
                  try{
                        messagesDoc.insertString(messagesDoc.getLength(), "\n"+"_____________________________________________\n", lineStyle);
                  }catch(Exception e){
                  }
            }
            // Append to document
            try{
                                    
                  
                  messagesDoc.insertString(messagesDoc.getLength(), "> " + fromUser, receiveUserStyle);
                  messagesDoc.insertString(messagesDoc.getLength(), "           " + Datum.getToday().toString() + " - " + Zeit.getActualTime().toString(), receiveTextStyle);
                  
                  // delete Button
                  JButton deleteItemJB = new JButton(getIconClose());
                  deleteItemJB.setSize(12,12);
                  deleteItemJB.setPreferredSize(new Dimension(12,12));
                  deleteItemJB.setLocation(78,1);
                  
                    deleteItemJB.addActionListener( new ActionListener() {
                    public void actionPerformed(ActionEvent e) {  
                          MessageMask.this.setVisible(false);
                    }
                    });
                    
                    
//                  The component must first be wrapped in a style
                  JButton addToFavoritesJB = new JButton(getIconMinimize());
                  addToFavoritesJB.setSize(12,12);
                  addToFavoritesJB.setPreferredSize(new Dimension(12,12));
                  addToFavoritesJB.setLocation(64,1);
                        
                        
                  JPanel containerJP = new JPanel();
                  containerJP.setPreferredSize(new Dimension(100,20));
                  containerJP.setLayout(null);
                  containerJP.add(deleteItemJB);
                  containerJP.add(addToFavoritesJB);
                  
                  // The component must first be wrapped in a style
                  Style style = messagesDoc.addStyle("buttonsStyle", null);
                  StyleConstants.setAlignment(style, StyleConstants.ALIGN_RIGHT);
                  StyleConstants.setComponent(style, containerJP);
                  
                  // Insert the component at the end of the text
                  messagesDoc.insertString(messagesDoc.getLength(), "ignored text", style);
                  
                                    
                  messagesDoc.insertString(messagesDoc.getLength(), "\n   " + message , receiveTextStyle);
                  

      
            }catch(Exception e){
            }

------------------------------------------------------------------------
Thats the code which I use to append the text to the JTextPane

Since I didn't get the code to work I tried to do it with the StyledDocument - but I dont get the background for the entire Line then.



@ hoomany
can u give me a codeexample
--> i tried to but finally the only way i saw was the setText()
--> i tried to combine StyledDocument and HTML - but it looked like i had to decide wheter i wanted to use HTML or StyledDocument with the possibility to insert other Components like JPanels, JButtons and whatever.


@ Ksivananth
 What i dont understand is how can I catch the event out of the HTML-Document?
If i write the HTML-Code what do i have to put in the href so that a Java-function is called.
--> please give me a code example

And there is one more limitation with the HTML Code
("<p><div style=\"background-color: #FF0000\"><b><font face=\"Tahoma\" size=\"7\">Hello</font></b></div></p>")
the background isn't painted up to the border of the JTextPane - there are always about 1 or 2 pixel on each side which are not painted.



And 2 more questions:
5) is there a way to draw a break line?
i used: messagesDoc.insertString(messagesDoc.getLength(), "\n"+"_____________________________________________\n", lineStyle);
--> if i resize the window the line won't to up to the borders

6) is there a way to use two alignments in the same line?
_______________________________________________________
< From Walter        01.06.2006 - 17:01:54                         [P] [X]

Thats my header line --> i want the buttons [P] and [X] to be aligned on the right. The text before (but in the same line) shall be aligned on the left
> I tried to do it with the StyledDocument - but I dont get the background for the entire Line then
I was also unable to get it to work using StyledDocument, but still insertText(html content) should work
ok i solved the point with the background-color by using HTML and StyleSheets
thats the new code:
private javax.swing.JTextPane getMessagesJTP() {
      if(messagesJTP == null) {
            messagesJTP = new javax.swing.JTextPane();
            messagesJTP.setEditable(false);
            messagesJTP.setContentType("text/html");
            
            HTMLEditorKit kit = new HTMLEditorKit();
            //HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument();
            
            StyleSheet sheet = kit.getStyleSheet();
            
            sheet.addRule( "p {font-size: small}" );
            sheet.addRule( "body {font-size: 12pt;color: #444444}" );
            sheet.addRule( "div.sendMessage {font-size: 12pt;background-color: #b4b6d3;height:15;}" );
            sheet.addRule( "div.receiveMessage {font-size: 12pt;background-color: #AAAAFF;height:15;}" );
      }
      return messagesJTP;
}

--> and thats the code for writing it out on TextPanel


      Vector selMessages = MessageContainer.getAllMessages();
            
      String code = "<html>\n<title>iCom Message window</title>\n<body>";
//      prepare messages for writing
      for(int i=0; i<selMessages.size(); i++){
            Message msg = (Message)(selMessages.get(i));
            
            code += "<div width=\"100%\" class=\"receiveMessage\" >";
            code += "> " + msg.getFrom()+ "\t" +  msg.getReceiveDate().toString() + " - " + msg.getReceiveTime().toString();
            code += "</div>\n";
            code += msg.getMessage().replaceAll("\n", "<br>\n");                  
            code += "\n";
            
            
      }
      code += "</body></html>";
      
      getMessagesJTP().setText(code);

--> So the points 1, 3, 5 and 6 are solved.

Rest:

7) Now I need the buttons to be placed + made clickable - I have pictures/icons for them but I dont have them on a webserver since the application shall be installed locally.
--> So what i want is a Button with a picture (safed in JAR-File) which I can click
Questions form my side:
- which URL do I use for them (pics are in a Jar-File) --> i get the other pictures/icons as followed:
-----------------
      private ImageIcon getIconClose() throws Exception{
            if(iconClose == null){
                  URL url = getClass().getResource("/qas/layout/x.jpg");
                  iconClose = new ImageIcon(url);
            }
            return iconClose;
      }
-----------------
--> with a JButton component it would be quite easy (if there was a way to allow JButtons in the HTML-Code that would solve this point)
- how do i define the onclick-event - how is the link between html-source code and Event handling realised?


4) Selecting an entire message block on rightclick
--> is there a way to select an entire message block? (which is Header + the message lines until the next header) for example on right click -
so that the user knows which message he's referencing for deletion.

--> can I make a javascript pass the messageNo to the Java-Application? Do i have to realise the event handling in javascript or in the Java-Application?

pane.addHyperlinkListener(new HyperlinkListener() {
    public void hyperlinkUpdate(HyperlinkEvent event) {
        ...
    }
});
hope hoomany's post helps regarding the hyperlink event!
Well,
I solved question 7 by myself.
I found a complete example for the .addHyperlinkListener somewhere else.

I would have wished some code examples - it was quite hard to find something that handled my problem.

The only thing that is still open is point 4 - selecting an entire message block on rightclick.
Would be nice if someone had a way to do that.

I have a html-block encapsulated in a div --> i want to handle the onclick event in Java - not in Javascript. If there is a way to pass the event to javascript thats ok too.
The entire HTML-Text of the page is in a JTextPane
-->
     Vector selMessages = MessageContainer.getAllMessages();
         
     String code = "<html>\n<title>iCom Message window</title>\n<body>";
//     prepare messages for writing
     for(int i=0; i<selMessages.size(); i++){
          Message msg = (Message)(selMessages.get(i));
         
          code += "<div id=\"+msg.getMessageNo()+\" width=\"100%\" class=\"receiveMessage\" >";
          code += "> " + msg.getFrom()+ "\t" +  msg.getReceiveDate().toString() + " - " + msg.getReceiveTime().toString();
          code += "</div>\n";
          code += msg.getMessage().replaceAll("\n", "<br>\n");              
          code += "\n";
         
         
     }
     code += "</body></html>";

--> if I added an onClick='callParentProgram();' to the div in the line (code += "<div width=\"100%\" class=\"receiveMessage\" >";) - would there be a way to get the event up to java?
--> Or can I add an ActionListener to the JTextPane which catches the rightClick-Event? But how would I be able to find out, which div was clicked?

small correction:  *If there is a way to pass the event from javascript to java thats ok too.

--> is there no way to edit a message?
ASKER CERTIFIED SOLUTION
Avatar of CetusMOD
CetusMOD
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial