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  package org.apache.log4j.chainsaw;
19  
20  import java.awt.event.InputEvent;
21  import java.awt.event.MouseEvent;
22  import java.awt.event.MouseListener;
23  
24  import javax.swing.JTable;
25  import javax.swing.table.JTableHeader;
26  import javax.swing.table.TableColumnModel;
27  
28  import org.apache.log4j.chainsaw.helper.SwingHelper;
29  
30  
31  /**
32   * A Sortable JTable implementation that allows a user to click on a
33   * specific Column and have the row information sorted by that column.
34   *
35   * @author Claude Duguay
36   * @author Scott Deboy <sdeboy@apache.org>
37   * 
38   */
39  public class JSortTable extends JTable implements MouseListener {
40    protected int sortedColumnIndex = -1;
41    protected boolean sortedColumnAscending = true;
42    private String sortedColumn;
43    private int lastSelectedColumn = -1;
44  
45    public JSortTable(SortTableModel model) {
46      super(model);
47      initSortHeader();
48    }
49  
50    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
51      //selection of the msg field causes rendering to flash...skip over it
52      int colToSelect = columnIndex;
53      //CHAINSAW columns are 1-based indexes
54      if (columnIndex + 1 == ChainsawColumns.INDEX_MESSAGE_COL_NAME) {
55          colToSelect = lastSelectedColumn < columnIndex ? columnIndex + 1 : columnIndex - 1;
56          super.changeSelection(rowIndex, colToSelect, toggle, extend);
57      } else {
58          super.changeSelection(rowIndex, columnIndex, toggle, extend);
59      }
60      lastSelectedColumn = colToSelect;
61    }
62  
63    protected void initSortHeader() {
64      JTableHeader header = getTableHeader();
65      header.setDefaultRenderer(new SortHeaderRenderer());
66      header.addMouseListener(this);
67    }
68  
69    public int getSortedColumnIndex() {
70      return sortedColumnIndex;
71    }
72  
73    public void updateSortedColumn() {
74    	if (sortedColumn != null) {
75    		try {
76  	  		sortedColumnIndex = columnModel.getColumnIndex(sortedColumn);
77              getTableHeader().resizeAndRepaint();
78    		} catch (IllegalArgumentException ie) {//nothing...column is not in the model
79    			setSortedColumnIndex(-1);
80  	  	}
81  	  }
82    }
83    
84    public void setSortedColumnIndex(int index) {
85      sortedColumnIndex = index;
86      if (sortedColumnIndex > -1) {
87          SortTableModel model = (SortTableModel) getModel();
88          model.sortColumn(sortedColumnIndex, sortedColumnAscending);
89      }
90      getTableHeader().resizeAndRepaint();
91    }
92  
93    //Allow synchronous updates if already on the EDT
94    private void scrollTo(final int row, final int col) {
95      SwingHelper.invokeOnEDT(new Runnable() {
96        public void run() {
97          final int currentRow = getSelectedRow();
98          if ((row > -1) && (row < getRowCount())) {
99            try {
100             //get the requested row off of the bottom and top of the screen by making the 5 rows around the requested row visible
101             //if new past current row, scroll to display the 20th row past new selected row
102             scrollRectToVisible(getCellRect(row, col, true));
103             if (row > currentRow) {
104                 scrollRectToVisible(getCellRect(row + 5, col, true));
105             }
106             if (row < currentRow) {
107                 scrollRectToVisible(getCellRect(row - 5, col, true));
108             }
109             scrollRectToVisible(getCellRect(row, col, true));
110             setRowSelectionInterval(row, row);
111           } catch (IllegalArgumentException iae) {
112             //ignore..out of bounds
113           }
114         }
115       }
116     });
117   }
118 
119   public void scrollToRow(int row) {
120     scrollTo(row, columnAtPoint(getVisibleRect().getLocation()));
121   }
122 
123   public boolean isSortedColumnAscending() {
124     return sortedColumnAscending;
125   }
126 
127   public void mouseClicked(MouseEvent event) {
128   	
129   	if(event.getClickCount()<2 || event.isPopupTrigger()){
130   		return;
131   	}else if(event.getClickCount()>1 && ((event.getModifiers() & InputEvent.BUTTON2_MASK)>0)){
132   		return;
133   	}
134   	
135     TableColumnModel colModel = getColumnModel();
136     int index = colModel.getColumnIndexAtX(event.getX());
137     int modelIndex = colModel.getColumn(index).getModelIndex();
138     SortTableModel model = (SortTableModel) getModel();
139 
140     if (model.isSortable(modelIndex)) {
141       // toggle ascension, if already sorted
142       if (sortedColumnIndex == index) {
143         sortedColumnAscending = !sortedColumnAscending;
144       }
145 
146       sortedColumnIndex = index;
147       sortedColumn = colModel.getColumn(index).getHeaderValue().toString();
148       model.sortColumn(modelIndex, sortedColumnAscending);
149       getTableHeader().resizeAndRepaint();
150     }
151   }
152 
153   public void mousePressed(MouseEvent event) {
154   }
155 
156   public void mouseReleased(MouseEvent event) {
157   }
158 
159   public void mouseEntered(MouseEvent event) {
160   }
161 
162   public void mouseExited(MouseEvent event) {
163   }
164 }