ValidObservationTableModel.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2009 AAVSO (http://www.aavso.org/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.ui.model.list;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import javax.swing.table.AbstractTableModel;
import org.aavso.tools.vstar.data.IOrderedObservationSource;
import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.data.ValidObservation;
import org.aavso.tools.vstar.exception.AuthenticationError;
import org.aavso.tools.vstar.exception.CancellationException;
import org.aavso.tools.vstar.exception.ConnectionException;
import org.aavso.tools.vstar.ui.VStar;
import org.aavso.tools.vstar.ui.dialog.MessageBox;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.mediator.message.DiscrepantObservationMessage;
import org.aavso.tools.vstar.ui.mediator.message.SeriesCreationMessage;
import org.aavso.tools.vstar.util.ObservationInserter;
import org.aavso.tools.vstar.util.notification.Listener;
/**
* A table model for valid observations.
*/
@SuppressWarnings("serial")
public class ValidObservationTableModel extends AbstractTableModel implements IOrderedObservationSource {
/**
* A mapping from series to valid observations.
*/
private Map<SeriesType, List<ValidObservation>> obsSourceListMap;
/**
* The list of valid observations retrieved.
*/
private List<ValidObservation> validObservations;
/**
* A weak reference hash map from observations to row indices. We only want this
* map's entries to exist if they (ValidObservation instances in particular) are
* in use elsewhere.
*/
private WeakHashMap<ValidObservation, Integer> validObservationToRowIndexMap;
private ObservationInserter obsInserter;
/**
* The source of column information.
*/
private final ITableColumnInfoSource columnInfoSource;
/**
* The total number of columns in the table.
*/
private final int columnCount;
/**
* Constructor
*
* @param obsSourceListMap A mapping from source series to lists of observation
* sources.
* @param observations The initial set of observations for the table model.
* @param columnInfoSource A source of table column information.
*/
public ValidObservationTableModel(Map<SeriesType, List<ValidObservation>> obsSourceListMap,
List<ValidObservation> observations, ITableColumnInfoSource columnInfoSource) {
this.obsSourceListMap = obsSourceListMap;
this.columnInfoSource = columnInfoSource;
this.columnCount = columnInfoSource.getColumnCount();
this.obsInserter = new ObservationInserter();
updateObservationsList(observations);
Mediator.getInstance().getDiscrepantObservationNotifier().addListener(createDiscrepantChangeListener());
Mediator.getInstance().getSeriesCreationNotifier().addListener(createSeriesCreationListener());
}
public Map<SeriesType, List<ValidObservation>> getObsSourceListMap() {
return obsSourceListMap;
}
/**
* @return the columnInfoSource
*/
public ITableColumnInfoSource getColumnInfoSource() {
return columnInfoSource;
}
/**
* @return the validObservations
*/
public List<ValidObservation> getObservations() {
return validObservations;
}
/**
* @return the observation inserter
*/
public ObservationInserter getObsInserter() {
return obsInserter;
}
/**
* Returns the row index (0..n-1) given an observation.
*
* @param ob a valid observation whose row index we want.
* @return The observation's row index.
*/
public Integer getRowIndexFromObservation(ValidObservation ob) {
return validObservationToRowIndexMap.get(ob);
}
/**
* @see javax.swing.table.TableModel#getColumnCount()
*/
public int getColumnCount() {
return columnCount;
}
/**
* @see javax.swing.table.TableModel#getRowCount()
*/
public int getRowCount() {
return this.validObservations.size();
}
/**
* @see javax.swing.table.AbstractTableModel#getColumnName(int)
*/
public String getColumnName(int column) {
assert column < columnCount;
return this.columnInfoSource.getTableColumnTitle(column);
}
/**
* @see javax.swing.table.TableModel#getValueAt(int, int)
*/
public Object getValueAt(int rowIndex, int columnIndex) {
Object result = null;
try {
assert columnIndex < columnCount;
ValidObservation validOb = this.validObservations.get(rowIndex);
result = this.columnInfoSource.getTableColumnValue(columnIndex, validOb);
} catch (IndexOutOfBoundsException e) {
// Sometimes the series-index, item-index pair will have
// changed or have become non-existent. Ignore but log.
VStar.LOGGER.log(Level.WARNING, "Observation value retrieval error", e);
}
return result;
}
/**
* @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int,
* int)
*/
public void setValueAt(Object value, int rowIndex, int columnIndex) {
if (columnIndex == columnInfoSource.getDiscrepantColumnIndex()) {
// if (Mediator.getInstance().getAnalysisType() ==
// AnalysisType.RAW_DATA) {
ValidObservation ob = this.validObservations.get(rowIndex);
try {
toggleDiscrepantStatus(ob);
// If the loaded dataset comes from AID, open
// report-to-HQ dialog.
Mediator.getInstance().reportDiscrepantObservation(ob, null);
// Tell anyone who's listening about the change.
DiscrepantObservationMessage message = new DiscrepantObservationMessage(ob, this);
Mediator.getInstance().getDiscrepantObservationNotifier().notifyListeners(message);
} catch (CancellationException ex) {
toggleDiscrepantStatus(ob);
} catch (ConnectionException ex) {
toggleDiscrepantStatus(ob);
MessageBox.showErrorDialog("Authentication Source Error", ex);
} catch (AuthenticationError ex) {
toggleDiscrepantStatus(ob);
MessageBox.showErrorDialog("Authentication Error", "Login failed.");
} catch (Exception ex) {
toggleDiscrepantStatus(ob);
MessageBox.showErrorDialog("Discrepant Reporting Error", ex.getLocalizedMessage());
}
// }
}
}
private void toggleDiscrepantStatus(ValidObservation ob) {
ob.setDiscrepant(!ob.isDiscrepant());
}
/**
* @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
// "is-discrepant" check box?
boolean is_discrepant_checkbox_editable = columnIndex == columnInfoSource.getDiscrepantColumnIndex()
/* && Mediator.getInstance().getAnalysisType() == AnalysisType.RAW_DATA */;
return is_discrepant_checkbox_editable;
}
/**
* @see javax.swing.table.AbstractTableModel#getColumnClass(int)
*/
public Class<?> getColumnClass(int columnIndex) {
return columnInfoSource.getTableColumnClass(columnIndex);
}
// TODO: needed? exists in row filter; and if needed, why not also one for
// excluded?
/**
* Listen for discrepant observation change notification.
*/
protected Listener<DiscrepantObservationMessage> createDiscrepantChangeListener() {
return new Listener<DiscrepantObservationMessage>() {
@Override
public void update(DiscrepantObservationMessage info) {
fireTableDataChanged();
}
@Override
public boolean canBeRemoved() {
return true;
}
};
}
protected Listener<SeriesCreationMessage> createSeriesCreationListener() {
return new Listener<SeriesCreationMessage>() {
@Override
public void update(SeriesCreationMessage info) {
updateObservationsList(info.getObs());
fireTableDataChanged();
}
@Override
public boolean canBeRemoved() {
return true;
}
};
}
// Helpers
/**
* Accept observations into this table model.
*
* @param observations The observations to accept; may be null
*/
private void updateObservationsList(List<ValidObservation> observations) {
// maintain ordering, keep track of min/max
validObservations = obsInserter.addValidObservations(observations);
// observations.stream().forEach(ob -> obsInserter.addValidObservation(ob));
// validObservations = obsInserter.getValidObservations();
// re-map *all* observations to row indices
validObservationToRowIndexMap = new WeakHashMap<ValidObservation, Integer>();
for (int i = 0; i < validObservations.size(); i++) {
validObservationToRowIndexMap.put(validObservations.get(i), i);
}
}
}