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 org.apache.log4j.chainsaw.helper.SwingHelper;
21  
22  import javax.swing.JTable;
23  import javax.swing.table.JTableHeader;
24  import javax.swing.table.TableColumnModel;
25  import java.awt.Color;
26  import java.awt.event.InputEvent;
27  import java.awt.event.MouseEvent;
28  import java.awt.event.MouseListener;
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  public class JSortTable extends JTable implements MouseListener {
39      protected int sortedColumnIndex = -1;
40      protected boolean sortedColumnAscending = true;
41      private String sortedColumn;
42      private int lastSelectedColumn = -1;
43  
44      public JSortTable(SortTableModel model) {
45          super(model);
46          initSortHeader();
47      }
48  
49      public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
50          //selection of the msg field causes rendering to flash...skip over it
51          int colToSelect = columnIndex;
52          //CHAINSAW columns are 1-based indexes
53          if (columnIndex + 1 == ChainsawColumns.INDEX_MESSAGE_COL_NAME) {
54              colToSelect = lastSelectedColumn < columnIndex ? columnIndex + 1 : columnIndex - 1;
55              super.changeSelection(rowIndex, colToSelect, toggle, extend);
56          } else {
57              super.changeSelection(rowIndex, columnIndex, toggle, extend);
58          }
59          lastSelectedColumn = colToSelect;
60      }
61  
62      protected void initSortHeader() {
63          JTableHeader header = getTableHeader();
64          header.setBackground(Color.WHITE);
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(() -> {
96              final int currentRow = getSelectedRow();
97              if ((row > -1) && (row < getRowCount())) {
98                  try {
99                      //get the requested row off of the bottom and top of the screen by making the 5 rows around the requested row visible
100                     //if new past current row, scroll to display the 20th row past new selected row
101                     scrollRectToVisible(getCellRect(row, col, true));
102                     if (row > currentRow) {
103                         scrollRectToVisible(getCellRect(row + 5, col, true));
104                     }
105                     if (row < currentRow) {
106                         scrollRectToVisible(getCellRect(row - 5, col, true));
107                     }
108                     scrollRectToVisible(getCellRect(row, col, true));
109                     setRowSelectionInterval(row, row);
110                 } catch (IllegalArgumentException iae) {
111                     //ignore..out of bounds
112                 }
113             }
114         });
115     }
116 
117     public void scrollToRow(int row) {
118         scrollTo(row, columnAtPoint(getVisibleRect().getLocation()));
119     }
120 
121     public boolean isSortedColumnAscending() {
122         return sortedColumnAscending;
123     }
124 
125     public void mouseClicked(MouseEvent event) {
126 
127         if (event.getClickCount() < 2 || event.isPopupTrigger()) {
128             return;
129         } else if (event.getClickCount() > 1 && ((event.getModifiers() & InputEvent.BUTTON2_MASK) > 0)) {
130             return;
131         }
132 
133         TableColumnModel colModel = getColumnModel();
134         int index = colModel.getColumnIndexAtX(event.getX());
135         int modelIndex = colModel.getColumn(index).getModelIndex();
136         SortTableModel model = (SortTableModel) getModel();
137 
138         if (model.isSortable(modelIndex)) {
139             // toggle ascension, if already sorted
140             if (sortedColumnIndex == index) {
141                 sortedColumnAscending = !sortedColumnAscending;
142             }
143 
144             sortedColumnIndex = index;
145             sortedColumn = colModel.getColumn(index).getHeaderValue().toString();
146             model.sortColumn(modelIndex, sortedColumnAscending);
147             getTableHeader().resizeAndRepaint();
148         }
149     }
150 
151     public void mousePressed(MouseEvent event) {
152     }
153 
154     public void mouseReleased(MouseEvent event) {
155     }
156 
157     public void mouseEntered(MouseEvent event) {
158     }
159 
160     public void mouseExited(MouseEvent event) {
161     }
162 }