View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  package org.xmlhammer.gui.output;
23  
24  import java.awt.Color;
25  import java.awt.LayoutManager;
26  import java.util.regex.Matcher;
27  import java.util.regex.Pattern;
28  
29  import javax.swing.JPanel;
30  import javax.swing.text.BadLocationException;
31  import javax.swing.text.DefaultHighlighter;
32  import javax.swing.text.JTextComponent;
33  import javax.swing.text.Highlighter.Highlight;
34  
35  import org.apache.log4j.Logger;
36  
37  /***
38   * A search-able Panel.
39   * 
40   * @version $Revision$, $Date$
41   * @author Edwin Dankert <edankert@gmail.com>
42   */
43  
44  public abstract class SearchablePanel extends JPanel {
45  	public SearchablePanel() {
46          super();
47      }
48  
49      public SearchablePanel(boolean arg0) {
50          super(arg0);
51      }
52  
53      public SearchablePanel(LayoutManager arg0, boolean arg1) {
54          super(arg0, arg1);
55      }
56  
57      public SearchablePanel(LayoutManager arg0) {
58          super(arg0);
59      }
60  
61      public abstract boolean search(String search, boolean matchCase, boolean forward);
62  
63      protected static boolean search(JTextComponent text, String search, boolean matchCase, boolean forward) {
64          Pattern pattern = null;
65          String regularSearch = "//Q"+prepareNonRegularExpression(search)+"//E";
66  
67          int start = -1;
68          int end = -1;
69           
70          if (!matchCase) {
71              pattern = Pattern.compile( regularSearch, Pattern.CASE_INSENSITIVE);
72          } else {
73              pattern = Pattern.compile( regularSearch);
74          }
75  
76          try {
77              int caret = text.getCaretPosition();
78  
79              if (getHiglight(text) != null) {
80                  caret = Math.max(caret, Math.max(getHighlightStart(text), getHighlightEnd(text)));
81              }
82              
83              Matcher matcher = pattern.matcher(text.getText(0, text.getDocument().getLength()));
84              
85              if (forward) {
86                  boolean match = matcher.find(caret);
87                  
88                  // could not find a match, start from the start...
89                  if (!match) {
90                      match = matcher.find(0);
91                  }
92                  
93                  if (match) {
94                      start = matcher.start();
95                      end = matcher.end();
96                  }
97              } else {
98                  caret = text.getCaretPosition();
99  
100                 if (getHiglight(text) != null) {
101                     caret = Math.min(caret, Math.min(getHighlightStart(text), getHighlightEnd(text)));
102                 }
103 
104                 while (matcher.find()) {
105                     if (matcher.start() < caret) {
106                         start = matcher.start();
107                         end = matcher.end();
108                     } else {
109                         break;
110                     }
111                 }
112 
113                 if (start == -1) {
114                     boolean match = matcher.find(caret);
115                     // get last matching element.
116                     while (match) {
117                         start = matcher.start();
118                         end = matcher.end();
119 
120                         match = matcher.find();
121                     }
122                 }
123             }
124 
125             if (end != -1) {
126                 matcher.find(start);
127                 select(text, start, end);
128             }
129 
130             text.repaint();
131         } catch(Exception e) {
132             e.printStackTrace();
133         }
134         
135         return end != -1;
136     }
137     
138     private static String prepareNonRegularExpression(String regexp) {
139         StringBuffer result = new StringBuffer(regexp);
140         
141         if (result.length() > 0) {
142             int index = result.indexOf("//E");
143             
144             while (index != -1) {
145                 result.replace(index, index+2, "//E////E//Q");
146                 index = result.indexOf("//E", index+7);
147             }
148             
149             // Last character is a '\', make sure to escape otherwise it will escape 
150             // the \E and we don't see the end of the non-regular expression.
151             if (result.charAt(result.length()-1) == '//') {
152                 result.append("E//////Q");
153             }
154         }
155     
156         return result.toString();
157     }
158     
159     private static void select(JTextComponent text, int start, int end) {
160         try {
161             if (start > 0) {
162                 text.getHighlighter().removeAllHighlights();
163                 text.getHighlighter().addHighlight(start, end, new DefaultHighlighter.DefaultHighlightPainter(brighter(text.getSelectionColor())));
164             }
165         } catch (BadLocationException e) {
166             Logger.getLogger(SearchablePanel.class).debug(e);
167         }
168         text.setCaretPosition(Math.max(0, end));
169     }
170     
171     private static int getHighlightStart(JTextComponent text) {
172         Highlight highlight = getHiglight(text);
173         
174         if (highlight != null) {
175             return highlight.getStartOffset();
176         }
177         
178         return -1;
179     }
180 
181     private static int getHighlightEnd(JTextComponent text) {
182         Highlight highlight = getHiglight(text);
183         
184         if (highlight != null) {
185             return highlight.getEndOffset();
186         }
187         
188         return -1;
189     }
190 
191     private static Highlight getHiglight(JTextComponent text) {
192         Highlight[] highlights = text.getHighlighter().getHighlights();
193 
194         if (highlights.length > 0) {
195             return highlights[0];
196         }
197         
198         return null;
199     }
200     
201     private static Color brighter(Color color) {
202         return new Color(brighten(color.getRed()), brighten(color.getGreen()), brighten(color.getBlue()));
203     }
204     
205     private static int brighten(int color) {
206         int newColor = color * (100 + 10) / 100;
207         
208         // A color cannot become brighter than white.
209         if ( newColor >= 0xFF) {
210             newColor = 0xFF;
211 
212         // The color has to be brighter than the previous color.
213         } else if ( newColor == color) {
214             newColor++;
215         }
216         
217         return newColor;
218     }
219 }