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