View Javadoc
1   package fr.ifremer.tutti.ui.swing.content.operation.catches.species.frequency;
2   
3   /*
4    * #%L
5    * Tutti :: UI
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.EditSpeciesBatchPanelUI;
26  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.edit.SpeciesBatchRowModel;
27  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.edit.SpeciesBatchTableModel;
28  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.edit.SpeciesBatchUI;
29  import fr.ifremer.tutti.ui.swing.util.computable.ComputableData;
30  import jaxx.runtime.SwingUtil;
31  import jaxx.runtime.swing.JTables;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.nuiton.jaxx.application.swing.table.ColumnIdentifier;
35  
36  import javax.swing.AbstractCellEditor;
37  import javax.swing.JTable;
38  import javax.swing.UIManager;
39  import javax.swing.border.LineBorder;
40  import javax.swing.table.DefaultTableCellRenderer;
41  import javax.swing.table.TableCellEditor;
42  import javax.swing.table.TableCellRenderer;
43  import java.awt.Color;
44  import java.awt.Component;
45  import java.awt.Font;
46  import java.awt.event.KeyAdapter;
47  import java.awt.event.KeyEvent;
48  import java.awt.event.MouseAdapter;
49  import java.awt.event.MouseEvent;
50  import java.util.ArrayList;
51  import java.util.List;
52  import java.util.Objects;
53  import java.util.stream.Collectors;
54  
55  /**
56   * Component to render and edit frequency stuff from batch table.
57   *
58   * @author Tony Chemit - chemit@codelutin.com
59   * @since 0.2
60   */
61  public class SpeciesFrequencyCellComponent extends DefaultTableCellRenderer {
62  
63      private static final long serialVersionUID = 1L;
64  
65      protected Color computedDataColor;
66  
67      /** Logger. */
68      private static final Log log = LogFactory.getLog(SpeciesFrequencyCellComponent.class);
69  
70      private Font defaulfFont;
71  
72      private Font selectedFont;
73  
74      public SpeciesFrequencyCellComponent(Color computedDataColor) {
75          setHorizontalAlignment(CENTER);
76          setIcon(SwingUtil.createActionIcon("show-frequency"));
77          this.computedDataColor = computedDataColor;
78      }
79  
80      public void setComputedOrNotText(ComputableData<Integer> data) {
81          String text;
82  
83          if (data != null && data.getData() != null) {
84              text = String.valueOf(data.getData());
85  
86          } else if (data != null && data.getComputedData() != null && data.getComputedData() != 0) {
87  
88              String blue = Integer.toHexString(computedDataColor.getRGB()).substring(2);
89              text = "<html><em style='color: #" + blue + "'>" + data.getComputedData() + "</em></html>";
90  
91          } else {
92              text = " - ";
93          }
94          setText(text);
95          setToolTipText(text);
96      }
97  
98      @Override
99      public Component getTableCellRendererComponent(JTable table,
100                                                    Object value,
101                                                    boolean isSelected,
102                                                    boolean hasFocus,
103                                                    int row,
104                                                    int column) {
105 
106         if (defaulfFont == null) {
107             defaulfFont = UIManager.getFont("Table.font");
108             selectedFont = defaulfFont.deriveFont(Font.BOLD);
109         }
110 
111         Component result = super.getTableCellRendererComponent(table,
112                                                                value,
113                                                                isSelected,
114                                                                hasFocus,
115                                                                row,
116                                                                column);
117         if (isSelected) {
118             result.setFont(selectedFont);
119         } else {
120             result.setFont(defaulfFont);
121         }
122         return result;
123     }
124 
125     public static TableCellRenderer newRender(Color computedDataColor) {
126         return new FrequencyCellRenderer(computedDataColor);
127     }
128 
129     public static TableCellEditor newEditor(SpeciesBatchUI ui, Color computedDataColor) {
130         return new FrequencyCellEditor(ui, computedDataColor);
131     }
132 
133     public static class FrequencyCellEditor extends AbstractCellEditor implements TableCellEditor {
134 
135         private static final long serialVersionUID = 1L;
136 
137         protected final SpeciesFrequencyCellComponent component;
138 
139         protected final SpeciesBatchUI ui;
140 
141         protected JTable table;
142 
143         protected SpeciesBatchTableModel tableModel;
144 
145         protected ColumnIdentifier<SpeciesBatchRowModel> columnIdentifier;
146 
147         protected SpeciesBatchRowModel editRow;
148 
149         protected Integer rowIndex;
150 
151         protected Integer nextEditableRowIndex;
152 
153         protected Integer columnIndex;
154 
155         protected SpeciesBatchRowModel previousSiblingRow;
156 
157         public FrequencyCellEditor(SpeciesBatchUI ui, Color computedDataColor) {
158             this.ui = ui;
159             component = new SpeciesFrequencyCellComponent(computedDataColor);
160             component.setBorder(new LineBorder(Color.BLACK));
161             component.addKeyListener(new KeyAdapter() {
162                 @Override
163                 public void keyReleased(KeyEvent e) {
164                     if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_SPACE) {
165                         e.consume();
166                         startEdit();
167                     }
168                 }
169             });
170 
171             component.addMouseListener(new MouseAdapter() {
172                 @Override
173                 public void mouseClicked(MouseEvent e) {
174                     e.consume();
175                     startEdit();
176                 }
177             });
178         }
179 
180         public SpeciesBatchRowModel getEditRow() {
181             return editRow;
182         }
183 
184         public Integer getNextEditableRowIndex() {
185             return nextEditableRowIndex;
186         }
187 
188         public SpeciesBatchRowModel getPreviousSiblingRow() {
189             return previousSiblingRow;
190         }
191 
192         public void initEditor(JTable table, int row, int column) {
193             tableModel = (SpeciesBatchTableModel) table.getModel();
194             this.table = table;
195             columnIdentifier = SpeciesBatchTableModel.COMPUTED_NUMBER;
196             rowIndex = row;
197             columnIndex = column;
198             editRow = tableModel.getEntry(row);
199         }
200 
201         public void startEdit() {
202 
203             Objects.requireNonNull(tableModel, "No table model assigned.");
204             Objects.requireNonNull(editRow, "No editRow found.");
205 
206             // compute the next editable row
207             nextEditableRowIndex = tableModel.getNextEditableFrequencyRow(rowIndex + 1);
208 
209             // compute the previous sibling row
210             previousSiblingRow = tableModel.getPreviousSibling(editRow);
211 
212             if (log.isDebugEnabled()) {
213                 log.debug("Will edit frequencies for row: " + rowIndex +
214                                   ", nextEditableRow: " + nextEditableRowIndex +
215                                   ", previous siblingRow: " + previousSiblingRow);
216             }
217 
218             EditSpeciesBatchPanelUI parent = ui.getParentContainer(EditSpeciesBatchPanelUI.class);
219             parent.getHandler().editSpeciesFrequencies(this);
220         }
221 
222         public void save(SpeciesFrequencyUIModel frequencyModel) {
223 
224             if (frequencyModel.isValid()) {
225 
226                 // at close, synch back frequencies
227 
228                 // set the weigth
229                 editRow.setWeight(frequencyModel.getTotalWeight());
230 
231                 if (frequencyModel.isSimpleCountingMode()) {
232 
233                     editRow.setNumber(frequencyModel.getSimpleCount());
234                     // DO THIS BEFORE SETTING THE FREQUENCIES AS THE FREQUENCIES MODIFICATIONS TRIGGERS THE SAVE
235                     editRow.setIndividualObservation(new ArrayList<>());
236                     editRow.setFrequency(new ArrayList<>());
237 
238                 } else {
239 
240                     // push back to batch
241                     editRow.setNumber(null);
242 
243                     //
244                     // transfert back individual observations
245                     //
246 
247                     List<IndividualObservationBatchRowModel> individualObservation = new ArrayList<>();
248 //                    CopyIndividualObservationMode copyIndividualObservationMode = frequencyModel.getCopyIndividualObservationMode();
249 //
250 //                    row.setCopyIndividualObservationMode(copyIndividualObservationMode);
251                     individualObservation.addAll(frequencyModel.getIndividualObservationModel().getRows());
252                     if (log.isDebugEnabled()) {
253                         log.debug("Push back " + individualObservation.size() + " observations to batch " + frequencyModel.getBatch());
254                     }
255 
256                     // DO THIS BEFORE SETTING THE FREQUENCIES AS THE FREQUENCIES MODIFICATIONS TRIGGERS THE SAVE
257                     // set individual observations to the incoming batch
258                     editRow.setIndividualObservation(individualObservation);
259 
260                     //
261                     // transfert back frequencies
262                     //
263 
264                     // the row is valid even if there is no data (just for the highlighter)
265                     // but we save it only if there is data
266                     // can keep this row
267                     List<SpeciesFrequencyRowModel> frequency =
268                             frequencyModel.getRows()
269                                           .stream()
270                                           .filter(row -> row.isValid() && (row.withNumber() || row.withWeight()))
271                                           .collect(Collectors.toList());
272 
273                     if (log.isDebugEnabled()) {
274                         log.debug("Push back " + frequency.size() + " frequencies to batch " + frequencyModel.getBatch());
275                     }
276 
277                     // set frequencies to the incoming batch
278                     editRow.setFrequency(frequency);
279 
280                 }
281 
282                 // update frequencies total
283                 ui.getHandler().updateTotalFromFrequencies(editRow);
284             }
285 
286             ui.getHandler().saveRow(editRow);
287 
288         }
289 
290         public void save(SpeciesFrequencyUIModel frequencyModel, boolean quit) {
291 
292             save(frequencyModel);
293 
294             if (quit) {
295                 int r = rowIndex;
296                 int c = columnIndex;
297 
298                 // stop edition
299                 stopCellEditing();
300 
301                 // reselect this cell
302                 JTables.doSelectCell(table, r, c);
303                 table.requestFocus();
304 
305             } else {
306 
307                 // keep next cell to edit
308                 int nextR = nextEditableRowIndex;
309                 int c = columnIndex;
310 
311                 // stop edition of this row
312                 stopCellEditing();
313 
314                 // use now the next row data
315                 rowIndex = nextR;
316 
317                 // load the row
318                 editRow = tableModel.getEntry(rowIndex);
319 
320                 // will save the previous row in the species row
321                 JTables.doSelectCell(table, rowIndex, c);
322 
323                 // start edit
324                 startEdit();
325             }
326         }
327 
328         @Override
329         public Component getTableCellEditorComponent(JTable table,
330                                                      Object value,
331                                                      boolean isSelected,
332                                                      int row,
333                                                      int column) {
334 
335             initEditor(table, row, column);
336 
337             if (log.isDebugEnabled()) {
338                 log.debug("Set columnIdentifier (" + column + ") :: " + columnIdentifier.getPropertyName());
339             }
340             ComputableData<Integer> data = (ComputableData<Integer>) value;
341             component.setComputedOrNotText(data);
342 
343             return component;
344         }
345 
346         @Override
347         public Object getCellEditorValue() {
348 
349             Objects.requireNonNull(editRow, "No editRow found in editor.");
350 
351             Object result = null;
352             if (columnIdentifier == SpeciesBatchTableModel.COMPUTED_NUMBER) {
353                 result = editRow.getComputedOrNotNumber();
354             }
355             if (log.isDebugEnabled()) {
356                 log.debug("editor value (" + columnIdentifier + "): " + result);
357             }
358 
359             return result;
360         }
361 
362         @Override
363         public void cancelCellEditing() {
364             super.cancelCellEditing();
365             rowIndex = null;
366             nextEditableRowIndex = null;
367             columnIndex = null;
368             editRow = null;
369         }
370     }
371 
372     public static class FrequencyCellRenderer implements TableCellRenderer {
373 
374         protected final SpeciesFrequencyCellComponent component;
375 
376         public FrequencyCellRenderer(Color computedDataColor) {
377             component = new SpeciesFrequencyCellComponent(computedDataColor);
378         }
379 
380         @Override
381         public Component getTableCellRendererComponent(JTable table,
382                                                        Object value,
383                                                        boolean isSelected,
384                                                        boolean hasFocus,
385                                                        int row,
386                                                        int column) {
387             component.setForeground(Color.BLACK);
388             ComputableData<Integer> data = (ComputableData<Integer>) value;
389             SpeciesFrequencyCellComponent result =
390                     (SpeciesFrequencyCellComponent) component.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
391 
392             boolean editable = table.isCellEditable(row, column);
393             result.setEnabled(editable);
394             result.setComputedOrNotText(data);
395             return result;
396         }
397     }
398 }