JAL-2047 resolved structure chooser's displayed column configuration updating, added...
[jalview.git] / src / jalview / fts / core / FTSDataColumnPreferences.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.fts.core;
22
23 import jalview.fts.api.FTSDataColumnI;
24 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
25 import jalview.fts.api.FTSRestClientI;
26 import jalview.fts.service.pdb.PDBFTSRestClient;
27
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Comparator;
31 import java.util.HashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34
35 import javax.swing.JScrollPane;
36 import javax.swing.JTable;
37 import javax.swing.RowSorter;
38 import javax.swing.SortOrder;
39 import javax.swing.table.AbstractTableModel;
40 import javax.swing.table.TableModel;
41 import javax.swing.table.TableRowSorter;
42
43
44 @SuppressWarnings("serial")
45 public class FTSDataColumnPreferences extends JScrollPane
46 {
47   protected JTable tbl_FTSDataColumnPrefs = new JTable();
48
49   protected JScrollPane scrl_pdbDocFieldConfig = new JScrollPane(
50           tbl_FTSDataColumnPrefs);
51
52   private HashMap<String, FTSDataColumnI> map = new HashMap<String, FTSDataColumnI>();
53
54   private Collection<FTSDataColumnI> structSummaryColumns = new LinkedHashSet<FTSDataColumnI>();
55
56   private Collection<FTSDataColumnI> allFTSDataColumns = new LinkedHashSet<FTSDataColumnI>();
57
58   public enum PreferenceSource
59   {
60     SEARCH_SUMMARY, STRUCTURE_CHOOSER, PREFERENCES;
61   }
62
63   private PreferenceSource currentSource;
64
65   private FTSRestClientI ftsRestClient;
66
67   public FTSDataColumnPreferences(PreferenceSource source,
68           FTSRestClientI ftsRestClient)
69   {
70     this.ftsRestClient = ftsRestClient;
71     structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
72             .getAllDefaultDisplayedStructureDataColumns();
73     allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
74
75     tbl_FTSDataColumnPrefs.setAutoCreateRowSorter(true);
76     this.getViewport().add(tbl_FTSDataColumnPrefs);
77     this.currentSource = source;
78
79     String[] columnNames = null;
80     switch (source)
81     {
82     case SEARCH_SUMMARY:
83       columnNames = new String[] { "", "Display", "Group" };
84       break;
85     case STRUCTURE_CHOOSER:
86       columnNames = new String[] { "", "Display", "Group" };
87       break;
88     case PREFERENCES:
89       columnNames = new String[] { "PDB Field", "Show in search summary",
90           "Show in structure summary" };
91       break;
92     default:
93       break;
94     }
95
96     Object[][] data = new Object[allFTSDataColumns.size() - 1][3];
97
98     int x = 0;
99     for (FTSDataColumnI field : allFTSDataColumns)
100     {
101       if (field.getName().equalsIgnoreCase("all"))
102       {
103         continue;
104       }
105
106       switch (source)
107       {
108       case SEARCH_SUMMARY:
109         data[x++] = new Object[] {
110             ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
111                     .contains(field),
112             field.getName(), field.getGroup() };
113         break;
114       case STRUCTURE_CHOOSER:
115         data[x++] = new Object[] { structSummaryColumns.contains(field),
116             field.getName(), field.getGroup() };
117         break;
118       case PREFERENCES:
119         data[x++] = new Object[] { field.getName(),
120             ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
121                     .contains(field),
122             structSummaryColumns.contains(field) };
123         break;
124       default:
125         break;
126       }
127       map.put(field.getName(), field);
128     }
129
130     FTSDataColumnPrefsTableModel model = new FTSDataColumnPrefsTableModel(columnNames, data);
131     tbl_FTSDataColumnPrefs.setModel(model);
132
133     switch (source)
134     {
135     case SEARCH_SUMMARY:
136     case STRUCTURE_CHOOSER:
137       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0)
138               .setPreferredWidth(30);
139       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0).setMinWidth(20);
140       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0).setMaxWidth(40);
141       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(1)
142               .setPreferredWidth(150);
143       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(1).setMinWidth(150);
144       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2)
145               .setPreferredWidth(150);
146       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2)
147 .setMinWidth(150);
148
149       TableRowSorter<TableModel> sorter = new TableRowSorter<>(
150               tbl_FTSDataColumnPrefs.getModel());
151       tbl_FTSDataColumnPrefs.setRowSorter(sorter);
152       List<RowSorter.SortKey> sortKeys = new ArrayList<>();
153       int columnIndexToSort = 2;
154       sortKeys.add(new RowSorter.SortKey(columnIndexToSort,
155               SortOrder.ASCENDING));
156       sorter.setSortKeys(sortKeys);
157       sorter.setComparator(
158               columnIndexToSort,
159               new Comparator<FTSDataColumnGroupI>()
160               {
161                 @Override
162                 public int compare(FTSDataColumnGroupI o1,
163                         FTSDataColumnGroupI o2)
164                 {
165                   return o1.getSortOrder() - o2.getSortOrder();
166                 }
167               });
168       sorter.sort();
169
170       tbl_FTSDataColumnPrefs
171               .setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
172       break;
173     case PREFERENCES:
174     default:
175       break;
176     }
177
178   }
179
180   public Collection<FTSDataColumnI> getStructureSummaryFields()
181   {
182     return structSummaryColumns;
183   }
184
185   class FTSDataColumnPrefsTableModel extends AbstractTableModel
186   {
187
188     public FTSDataColumnPrefsTableModel(String[] columnNames, Object[][] data)
189     {
190       this.data = data;
191       this.columnNames = columnNames;
192     }
193
194     private Object[][] data;
195
196     private String[] columnNames;
197
198     @Override
199     public int getColumnCount()
200     {
201       return columnNames.length;
202     }
203
204     @Override
205     public int getRowCount()
206     {
207       return data.length;
208     }
209
210     @Override
211     public String getColumnName(int col)
212     {
213       return columnNames[col];
214     }
215
216     @Override
217     public Object getValueAt(int row, int col)
218     {
219       return data[row][col];
220     }
221
222     /*
223      * JTable uses this method to determine the default renderer/ editor for
224      * each cell. If we didn't implement this method, then the last column would
225      * contain text ("true"/"false"), rather than a check box.
226      */
227     @Override
228     public Class getColumnClass(int c)
229     {
230       return getValueAt(0, c).getClass();
231     }
232
233     /*
234      * Don't need to implement this method unless your table's editable.
235      */
236     @Override
237     public boolean isCellEditable(int row, int col)
238     {
239       // Note that the data/cell address is constant,
240       // no matter where the cell appears onscreen.
241       // !isPDBID(row, col) ensures the PDB_Id cell is never editable as it
242       // serves as a unique id for each row.
243       // return (col == 1 || col == 2) && !isPDBID(row, col);
244       switch (currentSource)
245       {
246       case SEARCH_SUMMARY:
247       case STRUCTURE_CHOOSER:
248         return (col == 0) && !isPrimaryKeyCell(row, 1);
249       case PREFERENCES:
250         return (col == 1 || col == 2) && !isPrimaryKeyCell(row, 0);
251       default:
252         return false;
253       }
254
255     }
256
257     /**
258      * Determines whether the data in a given cell is a PDB ID.
259      * 
260      * @param row
261      * @param col
262      * @return
263      */
264
265     public boolean isPrimaryKeyCell(int row, int col)
266     {
267       String name = getValueAt(row, col).toString();
268       FTSDataColumnI pdbField = map.get(name);
269       return pdbField.isPrimaryKeyColumn();
270     }
271
272     /*
273      * Don't need to implement this method unless your table's data can change.
274      */
275     @Override
276     public void setValueAt(Object value, int row, int col)
277     {
278       data[row][col] = value;
279       fireTableCellUpdated(row, col);
280
281       String name = null;
282       switch (currentSource)
283       {
284       case SEARCH_SUMMARY:
285       case STRUCTURE_CHOOSER:
286         name = getValueAt(row, 1).toString();
287         break;
288       case PREFERENCES:
289         name = getValueAt(row, 0).toString();
290         break;
291       default:
292         break;
293       }
294       boolean selected = ((Boolean) value).booleanValue();
295
296       FTSDataColumnI ftsDataColumn = map.get(name);
297
298       if (currentSource == PreferenceSource.SEARCH_SUMMARY)
299       {
300         updatePrefs(ftsRestClient
301                 .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
302                 selected);
303       }
304       else if (currentSource == PreferenceSource.STRUCTURE_CHOOSER)
305       {
306         updatePrefs(structSummaryColumns, ftsDataColumn, selected);
307       }
308       else if (currentSource == PreferenceSource.PREFERENCES)
309       {
310         if (col == 1)
311         {
312           updatePrefs(ftsRestClient
313                   .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
314                   selected);
315         }
316         else if (col == 2)
317         {
318           updatePrefs(structSummaryColumns, ftsDataColumn, selected);
319         }
320       }
321     }
322
323     private void updatePrefs(
324             Collection<FTSDataColumnI> prefConfig,
325             FTSDataColumnI dataColumn, boolean selected)
326     {
327       if (prefConfig.contains(dataColumn) && !selected)
328       {
329         prefConfig.remove(dataColumn);
330       }
331
332       if (!prefConfig.contains(dataColumn) && selected)
333       {
334         prefConfig.add(dataColumn);
335       }
336     }
337
338   }
339 }