package com.revolsys.swing.map.layer.record.component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DecimalFormat;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ProgressMonitor;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
import org.jdesktop.swingx.VerticalLayout;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.swing.SwingUtil;
import com.revolsys.swing.action.RunnableAction;
import com.revolsys.swing.action.enablecheck.EnableCheck;
import com.revolsys.swing.map.layer.record.AbstractRecordLayer;
import com.revolsys.swing.map.layer.record.LayerRecord;
import com.revolsys.swing.map.layer.record.table.RecordLayerTable;
import com.revolsys.swing.map.layer.record.table.model.RecordLayerErrors;
import com.revolsys.swing.map.layer.record.table.model.RecordLayerTableModel;
import com.revolsys.swing.menu.Menus;
import com.revolsys.swing.table.TablePanel;
import com.revolsys.util.WrappedException;
public abstract class AbstractUpdateField extends JDialog {
private static final long serialVersionUID = 1L;
protected static EnableCheck newEnableCheck() {
final EnableCheck enableCheck = Menus.enableCheck((final RecordLayerTable table) -> {
final int columnIndex = TablePanel.getEventColumn();
final RecordLayerTableModel tableModel = table.getModel();
if (tableModel.isFieldEditable(columnIndex)) {
if (tableModel.isIdField(columnIndex)) {
return false;
} else {
return true;
}
} else {
return false;
}
});
return enableCheck;
}
private final FieldDefinition fieldDefinition;
private final DecimalFormat format = new DecimalFormat("#,###");
private final AbstractRecordLayer layer;
private JButton okButton;
private final int recordCount;
private final RecordLayerTable table;
private final RecordLayerTableModel tableModel;
private final String recordCountString;
protected AbstractUpdateField(final String title) {
super(SwingUtil.getActiveWindow(), title, ModalityType.APPLICATION_MODAL);
this.table = TablePanel.getEventTable();
this.tableModel = this.table.getModel();
this.layer = this.table.getLayer();
final int eventColumn = TablePanel.getEventColumn();
this.fieldDefinition = this.table.getColumnFieldDefinition(eventColumn);
this.recordCount = this.tableModel.getRowCount();
this.recordCountString = this.format.format(this.recordCount);
initDialog();
}
protected void cancel() {
if (isVisible()) {
SwingUtil.dispose(this);
}
}
private void finish() {
if (this.recordCount > 100) {
final int confirm = JOptionPane.showConfirmDialog(this,
"<html>Update <b style='color:#32CD32'>" + this.recordCountString
+ "</b> records? This may take a long time or fail if there are many records.</html>",
"Update Records?", JOptionPane.OK_CANCEL_OPTION);
if (confirm != JOptionPane.OK_OPTION) {
setVisible(false);
return;
}
}
final ProgressMonitor progressMonitor = new ProgressMonitor(this, getProgressMonitorTitle(),
"Updated 0 of " + this.recordCountString, 0, 100);
progressMonitor.setProgress(0);
setVisible(false);
final AtomicInteger progress = new AtomicInteger();
final SwingWorker<?, ?> task = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
final Set<String> fieldNames = new LinkedHashSet<>();
fieldNames.add(AbstractUpdateField.this.fieldDefinition.getName());
fieldNames.addAll(AbstractUpdateField.this.layer.getFieldNames());
final RecordLayerErrors errors = new RecordLayerErrors("Setting Field Values",
AbstractUpdateField.this.layer, fieldNames);
AbstractUpdateField.this.tableModel.forEachRecord((record) -> {
if (progressMonitor.isCanceled()) {
throw new CancellationException();
} else {
try {
updateRecord(record);
} catch (final WrappedException e) {
errors.addRecord(record, e.getCause());
} catch (final Throwable e) {
errors.addRecord(record, e);
}
final int updateCount = progress.incrementAndGet();
if (updateCount < AbstractUpdateField.this.recordCount) {
final int updatePercent = (int)Math
.floor(updateCount * 100 / (double)AbstractUpdateField.this.recordCount);
if (updatePercent < 100) {
setProgress(updatePercent);
}
}
}
});
setProgress(100);
if (!isCancelled()) {
errors.showErrorDialog();
}
return null;
}
@Override
protected void done() {
}
};
task.addPropertyChangeListener((event) -> {
if ("progress" == event.getPropertyName()) {
final int percent = (Integer)event.getNewValue();
progressMonitor.setProgress(percent);
progressMonitor.setNote("Updated " + progress + " of " + this.recordCountString);
}
});
task.execute();
}
protected FieldDefinition getFieldDefinition() {
return this.fieldDefinition;
}
public AbstractRecordLayer getLayer() {
return this.layer;
}
protected String getProgressMonitorTitle() {
return "Set " + this.fieldDefinition.getName();
}
public String getRecordCountString() {
return this.recordCountString;
}
protected void initDialog() {
setLayout(new VerticalLayout());
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
setMinimumSize(new Dimension(300, 100));
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent e) {
cancel();
}
});
final JPanel fieldPanel = initFieldPanel();
final String fieldTitle = this.fieldDefinition.getTitle();
fieldPanel.setBorder(BorderFactory.createTitledBorder("Set " + fieldTitle + " = "));
add(fieldPanel);
final JLabel recordCountLabel = new JLabel("<html><b style='color:#32CD32'>"
+ getRecordCountString() + "</b> records will be updated.</html>");
recordCountLabel.setBorder(BorderFactory.createEmptyBorder(1, 5, 1, 5));
add(recordCountLabel);
final JComponent errorsPanel = initErrorsPanel();
if (errorsPanel != null) {
add(errorsPanel);
}
final JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
add(buttonsPanel);
final JButton cancelButton = RunnableAction.newButton("Cancel", this::cancel);
buttonsPanel.add(cancelButton);
this.okButton = RunnableAction.newButton("OK", this::finish);
if (this.fieldDefinition.isRequired()) {
this.okButton.setEnabled(false);
}
buttonsPanel.add(this.okButton);
pack();
SwingUtil.autoAdjustPosition(this);
}
protected JComponent initErrorsPanel() {
return null;
}
protected abstract JPanel initFieldPanel();
protected void setFormValid(final boolean valid) {
this.okButton.setEnabled(valid);
}
protected abstract void updateRecord(final LayerRecord record);
}