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 org.apache.log4j.chainsaw.prefs.SettingsManager;
23  import org.apache.log4j.helpers.Constants;
24  
25  import javax.swing.table.TableColumn;
26  import java.beans.PropertyChangeListener;
27  import java.beans.PropertyChangeSupport;
28  import java.io.Serializable;
29  import java.util.*;
30  
31  
32  /**
33   * Used to encapsulate all the preferences for a given LogPanel
34   *
35   * @author Paul Smith
36   */
37  public class LogPanelPreferenceModel implements Serializable {
38      public static final String ISO8601 = "ISO8601";
39      public static final Collection DATE_FORMATS;
40  
41      private static final long serialVersionUID = 7526472295622776147L;
42  
43      static {
44          Collection list = new ArrayList();
45  
46          Properties properties = SettingsManager.getInstance().getDefaultSettings();
47  
48          for (Map.Entry<Object, Object> objectObjectEntry : properties.entrySet()) {
49              Map.Entry<Object, Object> entry = objectObjectEntry;
50  
51              if (entry.getKey().toString().startsWith("DateFormat")) {
52                  list.add(entry.getValue());
53              }
54          }
55  
56          DATE_FORMATS = Collections.unmodifiableCollection(list);
57      }
58  
59      private transient final PropertyChangeSupport propertySupport =
60          new PropertyChangeSupport(this);
61      private String dateFormatPattern = Constants.SIMPLE_TIME_PATTERN;
62      private boolean levelIcons;
63      private List allColumns = new ArrayList();
64      private List visibleColumns = new ArrayList();
65      private List visibleColumnOrder = new ArrayList();
66      //set to true to match default 'detailPaneVisible' setting
67      private boolean detailPaneVisible = true;
68      private boolean toolTips;
69      //default thumbnail bar tooltips to true
70      private boolean thumbnailBarToolTips = true;
71      private boolean scrollToBottom;
72      private boolean logTreePanelVisible;
73      private String loggerPrecision = "";
74  
75      private Collection hiddenLoggers = new HashSet();
76      private String timeZone;
77      //default wrapMsg to true
78      private boolean wrapMsg = true;
79      private boolean highlightSearchMatchText;
80      private String hiddenExpression;
81      private String alwaysDisplayExpression;
82      private String clearTableExpression;
83      //default to cyclic mode off
84      private boolean cyclic = false;
85      private boolean showMillisDeltaAsGap;
86      //default search results to visible
87      private boolean searchResultsVisible = true;
88  
89      /**
90       * Returns an <b>unmodifiable</b> list of the columns.
91       * <p>
92       * The reason it is unmodifiable is to enforce the requirement that
93       * the List is actually unique columns.  IT _could_ be a set,
94       * but we need to maintain the order of insertion.
95       *
96       * @return
97       */
98      public List getColumns() {
99          return Collections.unmodifiableList(allColumns);
100     }
101 
102     public void setCyclic(boolean cyclic) {
103         this.cyclic = cyclic;
104     }
105 
106     public boolean isCyclic() {
107         return cyclic;
108     }
109 
110     /**
111      * Returns an <b>unmodifiable</b> list of the visible columns.
112      * <p>
113      * The reason it is unmodifiable is to enforce the requirement that
114      * the List is actually unique columns.  IT _could_ be a set,
115      * but we need to maintain the order of insertion.
116      *
117      * @return
118      */
119     public List getVisibleColumns() {
120         return Collections.unmodifiableList(visibleColumns);
121     }
122 
123     public void clearColumns() {
124         Object oldValue = this.allColumns;
125         allColumns = new ArrayList();
126         propertySupport.firePropertyChange("columns", oldValue, allColumns);
127     }
128 
129     private TableColumn findColumnByHeader(List list, String header) {
130         for (Object aList : list) {
131             TableColumn c = (TableColumn) aList;
132             //columns may have changed - header may not exist
133             if (c != null && c.getHeaderValue() != null && c.getHeaderValue().equals(header)) {
134                 return c;
135             }
136         }
137         return null;
138     }
139 
140     public void setVisibleColumnOrder(List visibleColumnOrder) {
141         this.visibleColumnOrder = visibleColumnOrder;
142     }
143 
144     public List getVisibleColumnOrder() {
145         return visibleColumnOrder;
146     }
147 
148     public boolean addColumn(TableColumn column) {
149         if (findColumnByHeader(allColumns, column.getHeaderValue().toString()) != null) {
150             return false;
151         }
152 
153         Object oldValue = allColumns;
154         allColumns = new ArrayList(allColumns);
155         allColumns.add(column);
156 
157         propertySupport.firePropertyChange("columns", oldValue, allColumns);
158         return true;
159     }
160 
161     private void setColumns(List columns) {
162         Object oldValue = allColumns;
163         allColumns = new ArrayList(columns);
164         propertySupport.firePropertyChange("columns", oldValue, columns);
165     }
166 
167     /**
168      * Returns the Date Pattern string for the alternate date formatter.
169      *
170      * @return date pattern
171      */
172     public final String getDateFormatPattern() {
173         return dateFormatPattern;
174     }
175 
176     public final void setDefaultDatePatternFormat() {
177         String oldVal = this.dateFormatPattern;
178         this.dateFormatPattern = Constants.SIMPLE_TIME_PATTERN;
179         propertySupport.firePropertyChange(
180             "dateFormatPattern", oldVal, this.dateFormatPattern);
181     }
182 
183     /**
184      * @param dateFormatPattern
185      */
186     public final void setDateFormatPattern(String dateFormatPattern) {
187         String oldVal = this.dateFormatPattern;
188         this.dateFormatPattern = dateFormatPattern;
189         propertySupport.firePropertyChange(
190             "dateFormatPattern", oldVal, this.dateFormatPattern);
191     }
192 
193     /**
194      * @param listener
195      */
196     public synchronized void addPropertyChangeListener(
197         PropertyChangeListener listener) {
198         propertySupport.addPropertyChangeListener(listener);
199     }
200 
201     /**
202      * @param propertyName
203      * @param listener
204      */
205     public synchronized void addPropertyChangeListener(
206         String propertyName, PropertyChangeListener listener) {
207         propertySupport.addPropertyChangeListener(propertyName, listener);
208     }
209 
210     /**
211      * @param listener
212      */
213     public synchronized void removePropertyChangeListener(
214         PropertyChangeListener listener) {
215         propertySupport.removePropertyChangeListener(listener);
216     }
217 
218     /**
219      * @param propertyName
220      * @param listener
221      */
222     public synchronized void removePropertyChangeListener(
223         String propertyName, PropertyChangeListener listener) {
224         propertySupport.removePropertyChangeListener(propertyName, listener);
225     }
226 
227     /**
228      * Applies all the properties of another model to this model
229      *
230      * @param model the model to copy
231      *              all the properties from
232      */
233     public void apply(LogPanelPreferenceModel model) {
234         setCyclic(model.isCyclic());
235         setLoggerPrecision(model.getLoggerPrecision());
236         setDateFormatPattern(model.getDateFormatPattern());
237         setLevelIcons(model.isLevelIcons());
238         setWrapMessage(model.isWrapMessage());
239         setHighlightSearchMatchText(model.isHighlightSearchMatchText());
240         setTimeZone(model.getTimeZone());
241         setToolTips(model.isToolTips());
242         setThumbnailBarToolTips((model.isThumbnailBarToolTips()));
243         setScrollToBottom(model.isScrollToBottom());
244         setDetailPaneVisible(model.isDetailPaneVisible());
245         setLogTreePanelVisible(model.isLogTreePanelVisible());
246         setVisibleColumnOrder(model.getVisibleColumnOrder());
247         setSearchResultsVisible(model.isSearchResultsVisible());
248         // we have to copy the list, because getColumns() is unmodifiable
249         setColumns(model.getColumns());
250 
251         setVisibleColumns(model.getVisibleColumns());
252         setHiddenLoggers(model.getHiddenLoggers());
253         setHiddenExpression(model.getHiddenExpression());
254         setAlwaysDisplayExpression(model.getAlwaysDisplayExpression());
255         setShowMillisDeltaAsGap(model.isShowMillisDeltaAsGap());
256         setClearTableExpression(model.getClearTableExpression());
257     }
258 
259     /**
260      * Returns true if this the fast ISO8601DateFormat object
261      * should be used instead of SimpleDateFormat
262      *
263      * @return use ISO8601 format flag
264      */
265     public boolean isUseISO8601Format() {
266         return getDateFormatPattern().equals(ISO8601);
267     }
268 
269     /**
270      * @return level icons flag
271      */
272     public boolean isLevelIcons() {
273         return levelIcons;
274     }
275 
276     public boolean isWrapMessage() {
277         return wrapMsg;
278     }
279 
280     public boolean isHighlightSearchMatchText() {
281         return highlightSearchMatchText;
282     }
283 
284     /**
285      * @param levelIcons
286      */
287     public void setLevelIcons(boolean levelIcons) {
288         this.levelIcons = levelIcons;
289         propertySupport.firePropertyChange("levelIcons", !levelIcons, levelIcons);
290     }
291 
292     public void setSearchResultsVisible(boolean searchResultsVisible) {
293         boolean oldValue = this.searchResultsVisible;
294         this.searchResultsVisible = searchResultsVisible;
295         propertySupport.firePropertyChange("searchResultsVisible", oldValue, searchResultsVisible);
296     }
297 
298     public boolean isSearchResultsVisible() {
299         return searchResultsVisible;
300     }
301 
302     /**
303      * @param wrapMsg
304      */
305     public void setWrapMessage(boolean wrapMsg) {
306         this.wrapMsg = wrapMsg;
307         propertySupport.firePropertyChange("wrapMessage", !wrapMsg, wrapMsg);
308     }
309 
310     /**
311      * @param highlightSearchMatchText
312      */
313     public void setHighlightSearchMatchText(boolean highlightSearchMatchText) {
314         this.highlightSearchMatchText = highlightSearchMatchText;
315         propertySupport.firePropertyChange("highlightSearchMatchText", !highlightSearchMatchText, highlightSearchMatchText);
316     }
317 
318     /**
319      * @param loggerPrecision - an integer representing the number of packages to display,
320      *                        or an empty string representing 'display all packages'
321      */
322     public void setLoggerPrecision(String loggerPrecision) {
323         String oldVal = this.loggerPrecision;
324         this.loggerPrecision = loggerPrecision;
325         propertySupport.firePropertyChange("loggerPrecision", oldVal, this.loggerPrecision);
326     }
327 
328     /**
329      * Returns the Logger precision.
330      *
331      * @return logger precision
332      */
333     public final String getLoggerPrecision() {
334         return loggerPrecision;
335     }
336 
337     /**
338      * Returns true if the named column should be made visible otherwise
339      * false.
340      *
341      * @param column
342      * @return column visible flag
343      */
344     public boolean isColumnVisible(TableColumn column) {
345         return (findColumnByHeader(visibleColumns, column.getHeaderValue().toString()) != null);
346     }
347 
348     private void setVisibleColumns(List visibleColumns) {
349         Object oldValue = new ArrayList();
350         this.visibleColumns = new ArrayList(visibleColumns);
351 
352         propertySupport.firePropertyChange("visibleColumns", oldValue, this.visibleColumns);
353     }
354 
355     public void setColumnVisible(String columnName, boolean isVisible) {
356         boolean wasVisible = findColumnByHeader(visibleColumns, columnName) != null;
357 
358         //because we're a list and not a set, ensure we keep at most
359         //one entry for a tablecolumn
360         Object col = findColumnByHeader(allColumns, columnName);
361         if (isVisible && !wasVisible) {
362             visibleColumns.add(col);
363             visibleColumnOrder.add(col);
364             propertySupport.firePropertyChange("visibleColumns", Boolean.valueOf(isVisible), Boolean.valueOf(wasVisible));
365         }
366         if (!isVisible && wasVisible) {
367             visibleColumns.remove(col);
368             visibleColumnOrder.remove(col);
369             propertySupport.firePropertyChange("visibleColumns", Boolean.valueOf(isVisible), Boolean.valueOf(wasVisible));
370         }
371     }
372 
373     /**
374      * Toggles the state between visible, non-visible for a particular Column name
375      *
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     /**
412      * @param scrollToBottom
413      */
414     public final void setScrollToBottom(boolean scrollToBottom) {
415         boolean oldValue = this.scrollToBottom;
416         this.scrollToBottom = scrollToBottom;
417         propertySupport.firePropertyChange(
418             "scrollToBottom", oldValue, this.scrollToBottom);
419     }
420 
421     /**
422      * @param showMillisDeltaAsGap
423      */
424     public final void setShowMillisDeltaAsGap(boolean showMillisDeltaAsGap) {
425         boolean oldValue = this.showMillisDeltaAsGap;
426         this.showMillisDeltaAsGap = showMillisDeltaAsGap;
427         propertySupport.firePropertyChange(
428             "showMillisDeltaAsGap", oldValue, this.showMillisDeltaAsGap);
429     }
430 
431     public final void setThumbnailBarToolTips(boolean thumbnailBarToolTips) {
432         boolean oldValue = this.thumbnailBarToolTips;
433         this.thumbnailBarToolTips = thumbnailBarToolTips;
434         propertySupport.firePropertyChange("thumbnailBarToolTips", oldValue, this.thumbnailBarToolTips);
435     }
436 
437     public final boolean isThumbnailBarToolTips() {
438         return thumbnailBarToolTips;
439     }
440 
441     /**
442      * @return tool tips enabled flag
443      */
444     public final boolean isToolTips() {
445         return toolTips;
446     }
447 
448     /**
449      * @param toolTips
450      */
451     public final void setToolTips(boolean toolTips) {
452         boolean oldValue = this.toolTips;
453         this.toolTips = toolTips;
454         propertySupport.firePropertyChange("toolTips", oldValue, this.toolTips);
455     }
456 
457     /**
458      * @return log tree panel visible flag
459      */
460     public final boolean isLogTreePanelVisible() {
461         return logTreePanelVisible;
462     }
463 
464     /**
465      * @param logTreePanelVisible
466      */
467     public final void setLogTreePanelVisible(boolean logTreePanelVisible) {
468         boolean oldValue = this.logTreePanelVisible;
469         this.logTreePanelVisible = logTreePanelVisible;
470         propertySupport.firePropertyChange(
471             "logTreePanelVisible", oldValue, this.logTreePanelVisible);
472     }
473 
474     /**
475      * @return custom date format flag
476      */
477     public boolean isCustomDateFormat() {
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 }