Author: sdeboy
Date: Wed Jun 16 07:43:55 2010
New Revision: 955150

URL: http://svn.apache.org/viewvc?rev=955150&view=rev
Log:
Added 'copy value under pointer to clipboard' log panel context menu item.
Fixed a number of table rendering issues, including bolding and line wrapping 
(line wrap mode correctly displays the entire event).

Table rendering now uses styleddocuments instead of htmldocuments to facilitate 
multi-line rendering + bolding..multi-line mode previously cut off long lines 
of text without spaces, multi-line mode now works as expected..

Modified:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
    
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
    
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html

Modified: 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java?rev=955150&r1=955149&r2=955150&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java 
(original)
+++ 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java 
Wed Jun 16 07:43:55 2010
@@ -30,6 +30,8 @@ import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Toolkit;
 import java.awt.Window;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
@@ -96,7 +98,6 @@ import javax.swing.JScrollPane;
 import javax.swing.JSeparator;
 import javax.swing.JSplitPane;
 import javax.swing.JTable;
-import javax.swing.JTextArea;
 import javax.swing.JTextField;
 import javax.swing.JToolBar;
 import javax.swing.KeyStroke;
@@ -1423,7 +1424,7 @@ public class LogPanel extends DockablePa
                 value = ((JLabel) comp).getText();
               }
             } else {
-              Object o = table.getValueAt(row, column).toString();
+              Object o = table.getValueAt(row, column);
 
               if (o instanceof String[] && ((String[])o).length > 0) {
                 value = ((String[]) o)[0];
@@ -1463,7 +1464,7 @@ public class LogPanel extends DockablePa
                 value = ((JLabel) comp).getText();
               }
             } else {
-              Object o = table.getValueAt(row, column).toString();
+              Object o = table.getValueAt(row, column);
 
               if (o instanceof String[] && ((String[])o).length > 0) {
                 value = ((String[]) o)[0];
@@ -1494,6 +1495,47 @@ public class LogPanel extends DockablePa
         }
       };
 
+    final Action copyAction =
+      new AbstractAction("Copy value under pointer to clipboard") {
+        public void actionPerformed(ActionEvent e) {
+                      if (currentPoint != null) {
+            int column = table.columnAtPoint(currentPoint);
+            int row = table.rowAtPoint(currentPoint);
+            String colName = table.getColumnName(column).toUpperCase();
+            String value = "";
+
+            if 
(colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
+              JComponent comp =
+                (JComponent) table.getCellRenderer(row, column);
+
+              if (comp instanceof JLabel) {
+                value = ((JLabel) comp).getText();
+              }
+            } else {
+              Object o = table.getValueAt(row, column);
+              //exception - build message + throwable
+              if (o != null) {
+                  if (o instanceof String[]) {
+                      String[] ti = (String[])o;
+                      if (ti.length > 0 && (!(ti.length == 1 && 
ti[0].equals("")))) {
+                        ExtendedLoggingEvent event = tableModel.getRow(row);
+                        value = event.getMessage().toString();
+                        for (int i=0;i<((String[])o).length;i++) {
+                            value = value + "\n" + ((String[]) o)[i];
+                        }
+                      }
+                  } else {
+                    value = o.toString();
+                  }
+              }
+            }
+            StringSelection selection = new StringSelection(value);
+            Clipboard clipboard = 
Toolkit.getDefaultToolkit().getSystemClipboard();
+            clipboard.setContents(selection, null);
+        }
+      }
+      };
+
     final JMenuItem menuItemToggleDock = new JMenuItem("Undock/dock");
 
     dockingAction =
@@ -1609,6 +1651,7 @@ public class LogPanel extends DockablePa
     p.add(new JSeparator());
 
     p.add(menuBuildColorRule);
+    p.add(copyAction);
     p.add(new JSeparator());
         
     p.add(menuItemToggleDetails);

Modified: 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java?rev=955150&r1=955149&r2=955150&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
 (original)
+++ 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
 Wed Jun 16 07:43:55 2010
@@ -20,7 +20,7 @@ package org.apache.log4j.chainsaw;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.Font;
+import java.awt.Insets;
 import java.awt.font.FontRenderContext;
 import java.awt.font.LineBreakMeasurer;
 import java.awt.font.TextAttribute;
@@ -44,21 +44,32 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTable;
 import javax.swing.JTextPane;
-import javax.swing.SwingConstants;
 import javax.swing.UIManager;
 import javax.swing.border.Border;
 import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableColumn;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.BoxView;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+import javax.swing.text.IconView;
+import javax.swing.text.LabelView;
 import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.ParagraphView;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.Style;
 import javax.swing.text.StyleConstants;
 import javax.swing.text.StyledDocument;
-import javax.swing.text.html.HTMLDocument;
-import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.TabSet;
+import javax.swing.text.TabStop;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
 
 import org.apache.log4j.chainsaw.color.RuleColorizer;
 import org.apache.log4j.chainsaw.icons.LevelIconFactory;
 import org.apache.log4j.helpers.Constants;
-import org.apache.log4j.helpers.Transform;
 import org.apache.log4j.rule.Rule;
 import org.apache.log4j.spi.LoggingEventFieldResolver;
 
@@ -97,14 +108,16 @@ public class TableColorizingRenderer ext
   private static final Border MIDDLE_EMPTY_BORDER = 
BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, 0);
   private static final Border RIGHT_EMPTY_BORDER = 
BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, borderWidth);
 
-  private final JLabel levelLabel = new JLabel();
-  private JLabel generalLabel = new JLabel();
+  private final JTextPane levelTextPane = new JTextPane();
+  private JTextPane singleLineTextPane = new JTextPane();
 
   private final JPanel multiLinePanel = new JPanel();
   private final JPanel generalPanel = new JPanel();
   private final JPanel levelPanel = new JPanel();
   private ApplicationPreferenceModel applicationPreferenceModel;
   private JTextPane multiLineTextPane;
+  private MutableAttributeSet boldAttributeSet;
+  private TabSet tabs;
 
     /**
    * Creates a new TableColorizingRenderer object.
@@ -115,24 +128,36 @@ public class TableColorizingRenderer ext
     generalPanel.setLayout(new BoxLayout(generalPanel, BoxLayout.Y_AXIS));
     levelPanel.setLayout(new BoxLayout(levelPanel, BoxLayout.Y_AXIS));
 
-    multiLinePanel.setAlignmentX(TOP_ALIGNMENT);
-    generalPanel.setAlignmentX(TOP_ALIGNMENT);
-    levelPanel.setAlignmentX(TOP_ALIGNMENT);
-
-    generalLabel.setVerticalAlignment(SwingConstants.TOP);
-    levelLabel.setVerticalAlignment(SwingConstants.TOP);
-    levelLabel.setOpaque(true);
-    levelLabel.setText("");
+    //define the 'bold' attributeset
+    boldAttributeSet = new SimpleAttributeSet();
+    StyleConstants.setBold(boldAttributeSet, true);
+
+    //throwable col may have a tab..if so, render the tab as col zero
+    int pos = 0;
+    int align = TabStop.ALIGN_LEFT;
+    int leader = TabStop.LEAD_NONE;
+    TabStop tabStop = new TabStop(pos, align, leader);
+    tabs = new TabSet(new TabStop[]{tabStop});
 
-    generalPanel.add(generalLabel);
-    levelPanel.add(levelLabel);
+    levelTextPane.setOpaque(true);
+    levelTextPane.setText("");
+
+    generalPanel.add(singleLineTextPane);
+    levelPanel.add(levelTextPane);
 
     this.colorizer = colorizer;
     multiLineTextPane = new JTextPane();
-    multiLineTextPane.setEditorKit(new HTMLEditorKit());
-    multiLineTextPane.setMargin(null);
+    multiLineTextPane.setEditorKit(new StyledEditorKit());
+
+    singleLineTextPane.setEditorKit(new OneLineEditorKit());
+    levelTextPane.setEditorKit(new OneLineEditorKit());
+
     multiLineTextPane.setEditable(false);
-    multiLineTextPane.setFont(levelLabel.getFont());
+    multiLineTextPane.setFont(levelTextPane.getFont());
+    Insets leftRightInsets = new Insets(0, 5, 0, 5);
+    multiLineTextPane.setMargin(leftRightInsets);
+    singleLineTextPane.setMargin(leftRightInsets);
+    levelTextPane.setMargin(leftRightInsets);
   }
 
   public void setToolTipsVisible(boolean toolTipsVisible) {
@@ -162,15 +187,20 @@ public class TableColorizingRenderer ext
     switch (colIndex) {
     case ChainsawColumns.INDEX_THROWABLE_COL_NAME:
       if (value instanceof String[] && ((String[])value).length > 0){
+          Style tabStyle = singleLineTextPane.getLogicalStyle();
+          StyleConstants.setTabSet(tabStyle, tabs);
+          //set the 1st tab at position 3
+          singleLineTextPane.setLogicalStyle(tabStyle);
           //exception string is split into an array..just highlight the first 
line completely if anything in the exception matches if we have a match for the 
exception field
           Set exceptionMatches = 
(Set)matches.get(LoggingEventFieldResolver.EXCEPTION_FIELD);
           if (exceptionMatches != null && exceptionMatches.size() > 0) {
-              generalLabel.setText(bold(((String[])value)[0]));
+              singleLineTextPane.setText(((String[])value)[0]);
+              boldAll((StyledDocument) singleLineTextPane.getDocument());
           } else {
-              generalLabel.setText(((String[])value)[0]);
+              singleLineTextPane.setText(((String[])value)[0]);
           }
       } else {
-        generalLabel.setText("");
+        singleLineTextPane.setText("");
       }
       component = generalPanel;
       break;
@@ -184,68 +214,72 @@ public class TableColorizingRenderer ext
           break;
         }
       }
-      
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LOGGER_FIELD),
 logger.substring(startPos + 1)));
+      singleLineTextPane.setText(logger.substring(startPos + 1));
+      
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LOGGER_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
       component = generalPanel;
       break;
     case ChainsawColumns.INDEX_ID_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.PROP_FIELD
 + "LOG4JID"), value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.PROP_FIELD 
+ "LOG4JID"), (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.CLASS_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.CLASS_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_FILE_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.FILE_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.FILE_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_LINE_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LINE_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LINE_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_NDC_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.NDC_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.NDC_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_THREAD_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.THREAD_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.THREAD_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_TIMESTAMP_COL_NAME:
         //timestamp matches contain the millis..not the display text..just 
highlight if we have a match for the timestamp field
         Set timestampMatches = 
(Set)matches.get(LoggingEventFieldResolver.TIMESTAMP_FIELD);
         if (timestampMatches != null && timestampMatches.size() > 0) {
-            generalLabel.setText(bold(value.toString()));
+            singleLineTextPane.setText(value.toString());
+            boldAll((StyledDocument) singleLineTextPane.getDocument());
         } else {
-            generalLabel.setText(value.toString());
+            singleLineTextPane.setText(value.toString());
         }
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
-        
generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.METHOD_FIELD),
 value.toString()));
+        singleLineTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.METHOD_FIELD),
 (StyledDocument) singleLineTextPane.getDocument());
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME:
     case ChainsawColumns.INDEX_MESSAGE_COL_NAME:
+        String thisString = value.toString().trim();
+        multiLineTextPane.setText(thisString);
         int width = tableColumn.getWidth();
 
-        String thisString;
         if (colIndex == ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME) {
             //property keys are set as all uppercase
-            thisString = 
buildHighlightString(matches.get(LoggingEventFieldResolver.PROP_FIELD + 
ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE.toUpperCase()), 
value.toString().trim());
+            
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.PROP_FIELD 
+ ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE.toUpperCase()), 
(StyledDocument) multiLineTextPane.getDocument());
         } else {
-            thisString = 
buildHighlightString(matches.get(LoggingEventFieldResolver.MSG_FIELD), 
value.toString().trim());
+            
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.MSG_FIELD),
 (StyledDocument) multiLineTextPane.getDocument());
         }
         int tableRowHeight = table.getRowHeight(row);
-        setText(thisString);
         multiLinePanel.removeAll();
         multiLinePanel.add(multiLineTextPane);
-        HTMLDocument document = new HTMLDocument();
-        multiLineTextPane.setDocument(document);
-        Font font = label.getFont();
-        String bodyRule = "body { font-family: " + font.getFamily() + "; 
font-size: " + (font.getSize()) + "pt; }";
-        
((HTMLDocument)multiLineTextPane.getDocument()).getStyleSheet().addRule(bodyRule);
-        multiLineTextPane.setText(thisString);
+
         if (wrap) {
             Map paramMap = new HashMap();
             paramMap.put(TextAttribute.FONT, multiLineTextPane.getFont());
@@ -263,26 +297,23 @@ public class TableColorizingRenderer ext
         break;
     case ChainsawColumns.INDEX_LEVEL_COL_NAME:
       if (levelUseIcons) {
-        levelLabel.setIcon((Icon) iconMap.get(value.toString()));
-
-        if (levelLabel.getIcon() != null) {
-          levelLabel.setText("");
-        }
+        levelTextPane.insertIcon((Icon) iconMap.get(value.toString()));
+        levelTextPane.setText("");
         if (!toolTipsVisible) {
-          levelLabel.setToolTipText(value.toString());
+          levelTextPane.setToolTipText(value.toString());
         }
       } else {
-        levelLabel.setIcon(null);
-        
levelLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LEVEL_FIELD),
 value.toString()));
+        levelTextPane.setText(value.toString());
+        
setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LEVEL_FIELD),
 (StyledDocument) levelTextPane.getDocument());
         if (!toolTipsVisible) {
-            levelLabel.setToolTipText(null);
+            levelTextPane.setToolTipText(null);
         }
       }
       if (toolTipsVisible) {
-          levelLabel.setToolTipText(label.getToolTipText());
+          levelTextPane.setToolTipText(label.getToolTipText());
       }
-      levelLabel.setForeground(label.getForeground());
-      levelLabel.setBackground(label.getBackground());
+      levelTextPane.setForeground(label.getForeground());
+      levelTextPane.setBackground(label.getBackground());
       component = levelPanel;
       break;
 
@@ -302,9 +333,10 @@ public class TableColorizingRenderer ext
         if (thisProp != null) {
             String propKey = LoggingEventFieldResolver.PROP_FIELD + 
thisProp.toUpperCase();
             Set propKeyMatches = (Set)matches.get(propKey);
-            generalLabel.setText(buildHighlightString(propKeyMatches, 
loggingEvent.getProperty(thisProp)));
+            singleLineTextPane.setText(loggingEvent.getProperty(thisProp));
+            setHighlightAttributesInternal(propKeyMatches, (StyledDocument) 
singleLineTextPane.getDocument());
         } else {
-            generalLabel.setText("");
+            singleLineTextPane.setText("");
         }
         component = generalPanel;
         break;
@@ -344,10 +376,10 @@ public class TableColorizingRenderer ext
         styledDocument.setCharacterAttributes(0, styledDocument.getLength() + 
1, attributes, false);
         multiLineTextPane.setBackground(background);
     }
-    levelLabel.setBackground(background);
-    levelLabel.setForeground(foreground);
-    generalLabel.setBackground(background);
-    generalLabel.setForeground(foreground);
+    levelTextPane.setBackground(background);
+    levelTextPane.setForeground(foreground);
+    singleLineTextPane.setBackground(background);
+    singleLineTextPane.setForeground(foreground);
 
     if (isSelected) {
       if (col == 0) {
@@ -468,89 +500,90 @@ public class TableColorizingRenderer ext
      return Math.max(ChainsawConstants.DEFAULT_ROW_HEIGHT, (int) height);
     }
 
-    private String buildHighlightString(Object matchSet, String input) {
+    private void setHighlightAttributesInternal(Object matchSet, 
StyledDocument styledDocument) {
         if (!highlightSearchMatchText) {
-            return fixLeadingSlash(Transform.escapeTags(input));
+            return;
         }
+        setHighlightAttributes(matchSet, styledDocument);
+    }
+
+    public void setHighlightAttributes(Object matchSet, StyledDocument 
styledDocument) {
         if (matchSet instanceof Set) {
             Set thisSet = (Set)matchSet;
-            //start with result as input and replace each time
-            String result = input;
             for (Iterator iter = thisSet.iterator();iter.hasNext();) {
                 String thisEntry = iter.next().toString();
-                result = bold(result, thisEntry);
+                bold(thisEntry, styledDocument);
             }
-            return "<html>" + fixLeadingSlash(escapeAllButBoldTags(result)) + 
"</html>";
         }
-        return fixLeadingSlash(Transform.escapeTags(input));
     }
 
-    /*
-        Weird Swing HTML/table cell renderer issue - if first character is a 
forward slash,
-        the text isn't displayed at all.  
-        Workaround is to render the leading slash character using the ASCII 
html code for forward slash (&#47;)
-    */
-    private String fixLeadingSlash(String input) {
-        if (input.length() > 0 && input.charAt(0) == '/') {
-            return "&#47;" + input.substring(1);
+    private void boldAll(StyledDocument styledDocument) {
+        if (!highlightSearchMatchText) {
+            return;
         }
-        return input;
+        styledDocument.setCharacterAttributes(0, styledDocument.getLength(), 
boldAttributeSet, false);
     }
-
-    private String escapeAllButBoldTags(String input) {
-            if (!highlightSearchMatchText) {
-                return Transform.escapeTags(input);
-            }
-            String lowerInput = input.toLowerCase();
-            String lowerBoldStart = "<b>";
-            String lowerBoldEnd = "</b>";
-            int boldStartLength = lowerBoldStart.length();
-            int boldEndLength = lowerBoldEnd.length();
+    
+    private void bold(String textToBold, StyledDocument styledDocument) {
+        try {
+            String lowerInput = styledDocument.getText(0, 
styledDocument.getLength()).toLowerCase();
+            String lowerTextToBold = textToBold.toLowerCase();
+            int textToBoldLength = textToBold.length();
             int firstIndex = 0;
-            int currentIndex = 0;
-            StringBuffer newString = new StringBuffer("");
-            while ((currentIndex = lowerInput.indexOf(lowerBoldStart, 
firstIndex)) > -1) {
-                
newString.append(Transform.escapeTags(input.substring(firstIndex, 
currentIndex)));
-                newString.append(lowerBoldStart);
-                firstIndex = currentIndex + boldStartLength;
-                currentIndex = lowerInput.indexOf(lowerBoldEnd, firstIndex);
-                if (currentIndex > -1) {
-                    
newString.append(Transform.escapeTags(input.substring(firstIndex, 
currentIndex)));
-                    newString.append(lowerBoldEnd);
-                    firstIndex = currentIndex + boldEndLength;
-                }
+            int currentIndex;
+            while ((currentIndex = lowerInput.indexOf(lowerTextToBold, 
firstIndex)) > -1) {
+                styledDocument.setCharacterAttributes(currentIndex, 
textToBoldLength, boldAttributeSet, false);
+                firstIndex = currentIndex + textToBoldLength;
             }
-            newString.append(Transform.escapeTags(input.substring(firstIndex, 
input.length())));
-            return newString.toString();
         }
-
-    private String bold(String input) {
-        if (!highlightSearchMatchText) {
-            return Transform.escapeTags(input);
+        catch (BadLocationException e) {
+            //ignore
         }
-        return "<html><b>" + Transform.escapeTags(input) + "</b></html>";
-    }
-    
-    private String bold(String input, String textToBold) {
-        String lowerInput = input.toLowerCase();
-        String lowerTextToBold = textToBold.toLowerCase();
-        int textToBoldLength = textToBold.length();
-        int firstIndex = 0;
-        int currentIndex = 0;
-        StringBuffer newString = new StringBuffer("");
-        while ((currentIndex = lowerInput.indexOf(lowerTextToBold, 
firstIndex)) > -1) {
-            newString.append(input.substring(firstIndex, currentIndex));
-            newString.append("<b>");
-            newString.append(input.substring(currentIndex, currentIndex + 
textToBoldLength));
-            newString.append("</b>");
-            firstIndex = currentIndex + textToBoldLength;
-        }
-        newString.append(input.substring(firstIndex, input.length()));
-        return newString.toString();
     }
 
     public void setHighlightSearchMatchText(boolean highlightSearchMatchText)
     {
         this.highlightSearchMatchText = highlightSearchMatchText;
     }
+
+    private class OneLineEditorKit extends StyledEditorKit {
+        private ViewFactory viewFactoryImpl = new ViewFactoryImpl();
+
+        public ViewFactory getViewFactory() {
+            return viewFactoryImpl;
+        }
+    }
+
+    private class ViewFactoryImpl implements ViewFactory {
+        public View create(Element elem)
+        {
+            String elementName = elem.getName();
+            if (elementName != null)
+            {
+                if (elementName.equals(AbstractDocument.ParagraphElementName)) 
{
+                    return new OneLineParagraphView(elem);
+                } else  if 
(elementName.equals(AbstractDocument.ContentElementName)) {
+                    return new LabelView(elem);
+                } else if 
(elementName.equals(AbstractDocument.SectionElementName)) {
+                    return new BoxView(elem, View.Y_AXIS);
+                } else if 
(elementName.equals(StyleConstants.ComponentElementName)) {
+                    return new ComponentView(elem);
+                } else if (elementName.equals(StyleConstants.IconElementName)) 
{
+                    return new IconView(elem);
+                }
+            }
+            return new LabelView(elem);
+        }
+    }
+
+    private class OneLineParagraphView extends ParagraphView {
+        public OneLineParagraphView(Element elem) {
+            super(elem);
+        }
+
+        //this is the main fix - set the flow span to be max val
+        public int getFlowSpan(int index) {
+            return Integer.MAX_VALUE;
+        }
+    }
 }

Modified: 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html?rev=955150&r1=955149&r2=955150&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
 (original)
+++ 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
 Wed Jun 16 07:43:55 2010
@@ -10,6 +10,11 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is 
subject to change.  If you are experiencing problems displaying events in 
Chainsaw, please delete everything in the $user.dir/.chainsaw directory and 
restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>15 Jun 2010</h2>
+<ul>
+<li>Added 'copy value under pointer to clipboard' log panel context menu 
item.</li>
+<li>Fixed a number of table rendering issues, including bolding and line 
wrapping (line wrap mode correctly displays the entire event).</li>
+</ul>
 <h2>14 Jun 2010</h2>
 <ul>
 <li>Updated initial 'You have no receivers defined' dialog to clarify what 
configuration options are available, including the fact that Chainsaw always 
saves the receiver configuration defined through the Receiver configuration 
panel, and that receiver configuration can be auto-loaded by Chainsaw.</li>


Reply via email to