View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   */
20  package org.apache.log4j.chainsaw;
21  
22  import java.beans.PropertyChangeListener;
23  import java.beans.PropertyChangeSupport;
24  import java.io.Serializable;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Properties;
33  
34  import javax.swing.table.TableColumn;
35  
36  import org.apache.log4j.chainsaw.prefs.SettingsManager;
37  import org.apache.log4j.helpers.Constants;
38  
39  
40  /**
41   *  Used to encapsulate all the preferences for a given LogPanel
42   * @author Paul Smith
43   */
44  public class LogPanelPreferenceModel implements Serializable{
45    public static final String ISO8601 = "ISO8601";
46    public static final Collection DATE_FORMATS;
47  
48   private static final long serialVersionUID = 7526472295622776147L;
49    static {
50      Collection list = new ArrayList();
51  
52      Properties properties = SettingsManager.getInstance().getDefaultSettings();
53  
54      for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
55        Map.Entry entry = (Map.Entry) iter.next();
56  
57        if (entry.getKey().toString().startsWith("DateFormat")) {
58          list.add(entry.getValue());
59        }
60      }
61  
62      DATE_FORMATS = Collections.unmodifiableCollection(list);
63    }
64  
65    private transient final PropertyChangeSupport propertySupport =
66      new PropertyChangeSupport(this);
67    private String dateFormatPattern = Constants.SIMPLE_TIME_PATTERN;
68    private boolean levelIcons;
69    private List allColumns = new ArrayList();
70    private List visibleColumns = new ArrayList();
71    private List visibleColumnOrder = new ArrayList();
72    //set to true to match default 'detailPaneVisible' setting
73    private boolean detailPaneVisible = true;
74    private boolean toolTips;
75    //default thumbnail bar tooltips to true
76    private boolean thumbnailBarToolTips = true;
77    private boolean scrollToBottom;
78    private boolean logTreePanelVisible;
79    private String loggerPrecision = "";
80  
81    private Collection hiddenLoggers = new HashSet();
82    private String timeZone;
83    //default wrapMsg to true
84    private boolean wrapMsg = true;
85    private boolean highlightSearchMatchText;
86    private String hiddenExpression;
87    private String alwaysDisplayExpression;
88    private String clearTableExpression;
89    //default to cyclic mode off
90    private boolean cyclic = false;
91    private boolean showMillisDeltaAsGap;
92    //default search results to visible
93    private boolean searchResultsVisible = true;
94  
95      /**
96     * Returns an <b>unmodifiable</b> list of the columns.
97     * 
98     * The reason it is unmodifiable is to enforce the requirement that
99     * the List is actually unique columns.  IT _could_ be a set,
100    * but we need to maintain the order of insertion.
101    * 
102    * @return
103    */
104   public List getColumns() {
105       return Collections.unmodifiableList(allColumns);
106   }
107 
108   public void setCyclic(boolean cyclic) {
109     this.cyclic = cyclic;
110   }
111 
112   public boolean isCyclic() {
113       return cyclic;
114   }
115   
116   /**
117    * Returns an <b>unmodifiable</b> list of the visible columns.
118    * 
119    * The reason it is unmodifiable is to enforce the requirement that
120    * the List is actually unique columns.  IT _could_ be a set,
121    * but we need to maintain the order of insertion.
122    * 
123    * @return
124    */
125   public List getVisibleColumns() {
126       return Collections.unmodifiableList(visibleColumns);
127   }
128   
129   public void clearColumns(){
130       Object oldValue = this.allColumns;
131       allColumns = new ArrayList();
132       propertySupport.firePropertyChange("columns", oldValue, allColumns);
133   }
134   
135   private TableColumn findColumnByHeader(List list, String header) {
136 	  for (Iterator iter = list.iterator();iter.hasNext();) {
137 		  TableColumn c = (TableColumn)iter.next();
138           //columns may have changed - header may not exist
139 		  if (c != null && c.getHeaderValue() != null && c.getHeaderValue().equals(header)) {
140 			  return c;
141 		  }
142 	  }
143 	  return null;
144   }
145   
146   public void setVisibleColumnOrder(List visibleColumnOrder) {
147 	  this.visibleColumnOrder = visibleColumnOrder;
148   }
149   
150   public List getVisibleColumnOrder() {
151 	  return visibleColumnOrder;
152   }
153   
154   public boolean addColumn(TableColumn column){
155 	  if (findColumnByHeader(allColumns, column.getHeaderValue().toString()) != null) {
156 		  return false;
157 	  }
158 
159       Object oldValue = allColumns;
160       allColumns = new ArrayList(allColumns);
161       allColumns.add(column);
162       
163       propertySupport.firePropertyChange("columns", oldValue, allColumns);
164       return true;
165   }
166   
167   private void setColumns(List columns) {
168       Object oldValue = allColumns;
169       allColumns = new ArrayList(columns);
170       propertySupport.firePropertyChange("columns", oldValue, columns);
171   }
172 
173 /**
174    * Returns the Date Pattern string for the alternate date formatter.
175    * @return date pattern
176    */
177   public final String getDateFormatPattern() {
178     return dateFormatPattern;
179   }
180 
181   public final void setDefaultDatePatternFormat() {
182 	    String oldVal = this.dateFormatPattern;
183 	    this.dateFormatPattern = Constants.SIMPLE_TIME_PATTERN;
184 	    propertySupport.firePropertyChange(
185 	    	      "dateFormatPattern", oldVal, this.dateFormatPattern);
186   }
187   /**
188    * @param dateFormatPattern
189    */
190   public final void setDateFormatPattern(String dateFormatPattern) {
191     String oldVal = this.dateFormatPattern;
192     this.dateFormatPattern = dateFormatPattern;
193     propertySupport.firePropertyChange(
194       "dateFormatPattern", oldVal, this.dateFormatPattern);
195   }
196 
197   /**
198    * @param listener
199    */
200   public synchronized void addPropertyChangeListener(
201     PropertyChangeListener listener) {
202     propertySupport.addPropertyChangeListener(listener);
203   }
204 
205   /**
206    * @param propertyName
207    * @param listener
208    */
209   public synchronized void addPropertyChangeListener(
210     String propertyName, PropertyChangeListener listener) {
211     propertySupport.addPropertyChangeListener(propertyName, listener);
212   }
213 
214   /**
215    * @param listener
216    */
217   public synchronized void removePropertyChangeListener(
218     PropertyChangeListener listener) {
219     propertySupport.removePropertyChangeListener(listener);
220   }
221 
222   /**
223    * @param propertyName
224    * @param listener
225    */
226   public synchronized void removePropertyChangeListener(
227     String propertyName, PropertyChangeListener listener) {
228     propertySupport.removePropertyChangeListener(propertyName, listener);
229   }
230 
231   /**
232    * Applies all the properties of another model to this model
233    *
234    * @param model the model to copy
235    * all the properties from
236    */
237   public void apply(LogPanelPreferenceModel model) {
238     setCyclic(model.isCyclic());
239     setLoggerPrecision(model.getLoggerPrecision());
240     setDateFormatPattern(model.getDateFormatPattern());
241     setLevelIcons(model.isLevelIcons());
242     setWrapMessage(model.isWrapMessage());
243     setHighlightSearchMatchText(model.isHighlightSearchMatchText());
244     setTimeZone(model.getTimeZone());
245     setToolTips(model.isToolTips());
246     setThumbnailBarToolTips((model.isThumbnailBarToolTips()));
247     setScrollToBottom(model.isScrollToBottom());
248     setDetailPaneVisible(model.isDetailPaneVisible());
249     setLogTreePanelVisible(model.isLogTreePanelVisible());
250     setVisibleColumnOrder(model.getVisibleColumnOrder());
251     setSearchResultsVisible(model.isSearchResultsVisible());
252     // we have to copy the list, because getColumns() is unmodifiable
253     setColumns(model.getColumns());
254     
255     setVisibleColumns(model.getVisibleColumns());
256     setHiddenLoggers(model.getHiddenLoggers());
257     setHiddenExpression(model.getHiddenExpression());
258     setAlwaysDisplayExpression(model.getAlwaysDisplayExpression());
259     setShowMillisDeltaAsGap(model.isShowMillisDeltaAsGap());
260     setClearTableExpression(model.getClearTableExpression());
261   }
262 
263   /**
264    * Returns true if this the fast ISO8601DateFormat object
265    * should be used instead of SimpleDateFormat
266    * @return use ISO8601 format flag
267    */
268   public boolean isUseISO8601Format() {
269     return getDateFormatPattern().equals(ISO8601);
270   }
271 
272   /**
273    * @return level icons flag
274    */
275   public boolean isLevelIcons() {
276     return levelIcons;
277   }
278 
279   public boolean isWrapMessage() {
280     return wrapMsg;
281   }
282 
283   public boolean isHighlightSearchMatchText() {
284     return highlightSearchMatchText;
285   }
286 
287   /**
288    * @param levelIcons
289    */
290   public void setLevelIcons(boolean levelIcons) {
291     this.levelIcons = levelIcons;
292     propertySupport.firePropertyChange("levelIcons", !levelIcons, levelIcons);
293   }
294 
295   public void setSearchResultsVisible(boolean searchResultsVisible) {
296     boolean oldValue = this.searchResultsVisible;
297     this.searchResultsVisible = searchResultsVisible;
298     propertySupport.firePropertyChange("searchResultsVisible", oldValue, searchResultsVisible);
299   }
300 
301   public boolean isSearchResultsVisible() {
302     return searchResultsVisible;
303   }
304 
305   /**
306    * @param wrapMsg
307    */
308   public void setWrapMessage(boolean wrapMsg) {
309     this.wrapMsg = wrapMsg;
310     propertySupport.firePropertyChange("wrapMessage", !wrapMsg, wrapMsg);
311   }
312 
313     /**
314      * @param highlightSearchMatchText
315      */
316     public void setHighlightSearchMatchText(boolean highlightSearchMatchText) {
317       this.highlightSearchMatchText = highlightSearchMatchText;
318       propertySupport.firePropertyChange("highlightSearchMatchText", !highlightSearchMatchText, highlightSearchMatchText);
319     }
320 
321   /**
322    * @param loggerPrecision - an integer representing the number of packages to display, 
323    * or an empty string representing 'display all packages' 
324    */
325   public void setLoggerPrecision(String loggerPrecision) {
326     String oldVal = this.loggerPrecision;
327     this.loggerPrecision = loggerPrecision;
328     propertySupport.firePropertyChange("loggerPrecision", oldVal, this.loggerPrecision);      
329   }
330   
331   /**
332    * Returns the Logger precision.
333    * @return logger precision
334    */
335   public final String getLoggerPrecision() {
336     return loggerPrecision;
337   }
338 
339   /**
340    * Returns true if the named column should be made visible otherwise
341    * false.
342    * @param column
343    * @return column visible flag
344    */
345   public boolean isColumnVisible(TableColumn column) {
346 	  return (findColumnByHeader(visibleColumns, column.getHeaderValue().toString()) != null);
347   }
348 
349   private void setVisibleColumns(List visibleColumns) {
350       Object oldValue = new ArrayList();
351       this.visibleColumns = new ArrayList(visibleColumns);
352       
353       propertySupport.firePropertyChange("visibleColumns", oldValue, this.visibleColumns);
354   }
355 
356   public void setColumnVisible(String columnName, boolean isVisible) {
357     boolean wasVisible = findColumnByHeader(visibleColumns, columnName) != null;
358 
359       //because we're a list and not a set, ensure we keep at most
360     //one entry for a tablecolumn
361     Object col = findColumnByHeader(allColumns, columnName);
362     if (isVisible && !wasVisible) {
363 		visibleColumns.add(col);
364 		visibleColumnOrder.add(col);
365 	    propertySupport.firePropertyChange("visibleColumns", new Boolean(isVisible), new Boolean(wasVisible));
366 	}
367     if (!isVisible && wasVisible) {
368 		visibleColumns.remove(col);
369 		visibleColumnOrder.remove(col);
370 	    propertySupport.firePropertyChange("visibleColumns", new Boolean(isVisible), new Boolean(wasVisible));
371 	}
372   }
373   
374   /**
375    * Toggles the state between visible, non-visible for a particular Column name
376    * @param column
377    */
378   public void toggleColumn(TableColumn column) {
379     setColumnVisible(column.getHeaderValue().toString(), !isColumnVisible(column));
380   }
381 
382   /**
383    * @return detail pane visible flag
384    */
385   public final boolean isDetailPaneVisible() {
386     return detailPaneVisible;
387   }
388 
389   /**
390    * @param detailPaneVisible
391    */
392   public final void setDetailPaneVisible(boolean detailPaneVisible) {
393     boolean oldValue = this.detailPaneVisible;
394     this.detailPaneVisible = detailPaneVisible;
395     propertySupport.firePropertyChange(
396       "detailPaneVisible", oldValue, this.detailPaneVisible);
397   }
398 
399   /**
400    * @return scroll to bottom flag
401    */
402   public final boolean isScrollToBottom() {
403     return scrollToBottom;
404   }
405 
406 
407   public final boolean isShowMillisDeltaAsGap() {
408       return showMillisDeltaAsGap;
409   }
410   /**
411    * @param scrollToBottom
412    */
413   public final void setScrollToBottom(boolean scrollToBottom) {
414     boolean oldValue = this.scrollToBottom;
415     this.scrollToBottom = scrollToBottom;
416     propertySupport.firePropertyChange(
417       "scrollToBottom", oldValue, this.scrollToBottom);
418   }
419 
420     /**
421      * @param showMillisDeltaAsGap
422      */
423     public final void setShowMillisDeltaAsGap(boolean showMillisDeltaAsGap) {
424       boolean oldValue = this.showMillisDeltaAsGap;
425       this.showMillisDeltaAsGap = showMillisDeltaAsGap;
426       propertySupport.firePropertyChange(
427         "showMillisDeltaAsGap", oldValue, this.showMillisDeltaAsGap);
428     }
429 
430   public final void setThumbnailBarToolTips(boolean thumbnailBarToolTips) {
431       boolean oldValue = this.thumbnailBarToolTips;
432       this.thumbnailBarToolTips = thumbnailBarToolTips;
433       propertySupport.firePropertyChange("thumbnailBarToolTips", oldValue, this.thumbnailBarToolTips);
434   }
435 
436   public final boolean isThumbnailBarToolTips() {
437       return thumbnailBarToolTips;
438   }
439 
440   /**
441    * @return tool tips enabled flag
442    */
443   public final boolean isToolTips() {
444     return toolTips;
445   }
446 
447   /**
448    * @param toolTips
449    */
450   public final void setToolTips(boolean toolTips) {
451     boolean oldValue = this.toolTips;
452     this.toolTips = toolTips;
453     propertySupport.firePropertyChange("toolTips", oldValue, this.toolTips);
454   }
455 
456   /**
457    * @return log tree panel visible flag
458    */
459   public final boolean isLogTreePanelVisible() {
460     return logTreePanelVisible;
461   }
462 
463   /**
464    * @param logTreePanelVisible
465    */
466   public final void setLogTreePanelVisible(boolean logTreePanelVisible) {
467     boolean oldValue = this.logTreePanelVisible;
468     this.logTreePanelVisible = logTreePanelVisible;
469     propertySupport.firePropertyChange(
470       "logTreePanelVisible", oldValue, this.logTreePanelVisible);
471   }
472 
473   /**
474    * @return custom date format flag
475    */
476   public boolean isCustomDateFormat()
477   {
478     return !DATE_FORMATS.contains(getDateFormatPattern()) && !isUseISO8601Format();
479   }
480 
481   public void setHiddenLoggers(Collection hiddenSet) {
482       Object oldValue = this.hiddenLoggers;
483       this.hiddenLoggers = hiddenSet;
484       propertySupport.firePropertyChange("hiddenLoggers", oldValue, this.hiddenLoggers);
485   }
486 
487   public Collection getHiddenLoggers() {
488     return hiddenLoggers;
489   }
490 
491   public String getTimeZone() {
492     return timeZone;
493   }
494   
495   public void setTimeZone(String timeZone) {
496       Object oldValue = this.timeZone;
497       this.timeZone = timeZone;
498       propertySupport.firePropertyChange("dateFormatTimeZone", oldValue, this.timeZone);
499   }
500 
501   public void setHiddenExpression(String hiddenExpression) {
502     Object oldValue = this.hiddenExpression;
503     this.hiddenExpression = hiddenExpression;
504     propertySupport.firePropertyChange("hiddenExpression", oldValue, this.hiddenExpression);
505   }
506 
507   public String getHiddenExpression() {
508     return hiddenExpression;
509   }
510 
511   public void setAlwaysDisplayExpression(String alwaysDisplayExpression) {
512     Object oldValue = this.hiddenExpression;
513     this.alwaysDisplayExpression = alwaysDisplayExpression;
514     propertySupport.firePropertyChange("alwaysDisplayExpression", oldValue, this.alwaysDisplayExpression);
515   }
516 
517   public String getAlwaysDisplayExpression() {
518     return alwaysDisplayExpression;
519   }
520 
521   public void setClearTableExpression(String clearTableExpression) {
522     Object oldValue = this.clearTableExpression;
523     this.clearTableExpression = clearTableExpression;
524     //no propertychange if both null
525     if (oldValue == null && this.clearTableExpression == null) {
526         return;
527     }
528     propertySupport.firePropertyChange("clearTableExpression", oldValue, this.clearTableExpression);
529   }
530 
531   public String getClearTableExpression() {
532     return clearTableExpression;
533   }
534 }