package com.opendoorlogistics.studio.tables.custom;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Callable;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import com.opendoorlogistics.api.ExecutionReport;
import com.opendoorlogistics.api.ODLApi;
import com.opendoorlogistics.api.Tables;
import com.opendoorlogistics.api.app.ui.BeanEditorFactory;
import com.opendoorlogistics.api.tables.ODLListener;
import com.opendoorlogistics.api.tables.ODLTableDefinition;
import com.opendoorlogistics.api.tables.beans.BeanMappedRow;
import com.opendoorlogistics.api.ui.Disposable;
import com.opendoorlogistics.core.scripts.execution.ExecutionReportImpl;
import com.opendoorlogistics.core.tables.utils.TableUtils;
import com.opendoorlogistics.core.utils.ui.ExecutionReportDialog;
import com.opendoorlogistics.studio.LoadedState.HasLoadedDatastore;
/**
* Shows a table which has a plugin popup box for editing items... Want simple controls to move items up and down, delete them and create new items. Want
* pluggable popup controls for editing a row. The base table could have missing or misordered fields however. Could we build an adapter on-the-fly and create
* missing fields???
*
* @author Phil
*
* @param <T>
*/
public abstract class CustomTableEditor<T extends BeanMappedRow> extends JPanel implements Disposable {
private final BeanMappingInfo<T> bmi;
private final BeanEditorFactory<T> editorFactory;
private final Component parent;
private final ODLListener structureListener = new ODLListener() {
@Override
public void datastoreStructureChanged() {
if(tableActivePanel!=null){
tableActivePanel.datastoreStructureChanged();
}
updateMode();
}
@Override
public ODLListenerType getType() {
return ODLListenerType.DATASTORE_STRUCTURE_CHANGED;
}
@Override
public void tableChanged(int tableId, int firstRow, int lastRow) {
if(tableActivePanel!=null){
tableActivePanel.tableChanged(tableId, firstRow, lastRow);;
}
}
};
private final ODLListener dataListener = new ODLListener() {
@Override
public void tableChanged(int tableId, int firstRow, int lastRow) {
if(tableActivePanel!=null){
tableActivePanel.tableChanged(tableId, firstRow, lastRow);;
}
}
@Override
public void datastoreStructureChanged() {
// TODO Auto-generated method stub
}
@Override
public ODLListenerType getType() {
return ODLListenerType.TABLE_CHANGED;
}
};
private TableActivePanel<T> tableActivePanel;
private enum Mode{
TABLE_IS_PRESENT_IN_DATASTORE,
TABLE_OR_FIELDS_MISSING
}
private Mode mode;
private void fixDatastoreNoPrompt(){
ExecutionReport report = new ExecutionReportImpl();
if(bmi.getDs()==null){
report.setFailed("No datastore is open.");
}
else{
TableUtils.runTransaction(bmi.getDs(), new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
bmi.getApi().tables().addTableDefinition(bmi.getMapping().getTableDefinition(), bmi.getDs(), true);
return true;
}
});
}
if (report.isFailed()) {
ExecutionReportDialog dlg = new ExecutionReportDialog((JFrame) SwingUtilities.getWindowAncestor(parent), "Error", report, true);
dlg.setVisible(true);
}
updateMode();
}
public CustomTableEditor(Component parent,ODLApi api, Class<T> cls, BeanEditorFactory<T> editorFactory,HasLoadedDatastore hasDs) {
this.parent = parent;
this.bmi = new BeanMappingInfo<>(api, cls, hasDs);
this.editorFactory = editorFactory;
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
bmi.getDs().addListener(structureListener);
bmi.getDs().addListener(dataListener, -1);
updateMode();
}
@Override
public void dispose() {
bmi.getDs().removeListener(structureListener);
bmi.getDs().removeListener(dataListener);
}
private void updateMode(){
Tables tables = bmi.getApi().tables();
ExecutionReportImpl report = new ExecutionReportImpl();
ODLTableDefinition dfn = bmi.getMapping().getTableDefinition();
Mode newMode = Mode.TABLE_IS_PRESENT_IN_DATASTORE;
if(bmi.getDs() == null || !tables.getTableDefinitionExists(dfn, bmi.getDs(), true, report)){
newMode = Mode.TABLE_OR_FIELDS_MISSING;
}
if(newMode!=mode){
// remove all existing components
removeAll();
tableActivePanel = null;
if(newMode == Mode.TABLE_IS_PRESENT_IN_DATASTORE){
tableActivePanel = new TableActivePanel<>(bmi, editorFactory);
add(tableActivePanel,BorderLayout.CENTER);
setPreferredSize(new Dimension(800, 600));
}else{
initInactiveMode(report);
setPreferredSize(null);
}
mode = newMode;
onModeChange();
validate();
repaint();
}
}
private void initInactiveMode(ExecutionReportImpl report){
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
StringBuilder builder = new StringBuilder();
builder.append("<html>The table " + bmi.getMapping().getTableDefinition().getName() + " and its fields must be present in your datastore.");
builder.append("<br>Do you want to correct the issue(s) found below?<br>");
for(String line : report.getLines(false)){
builder.append("<br>-<i>");
builder.append(line);
builder.append("</i>");
}
builder.append("</html>");
JLabel label = new JLabel(builder.toString());
//JScrollPane pane = new JScrollPane(textArea);
//textArea.setMinimumSize(new Dimension(600, 200));
panel.add(label);
panel.add(Box.createRigidArea(new Dimension(1, 10)));
JButton button = new JButton("Click to fix datastore issues");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fixDatastoreNoPrompt();
}
});
panel.add(button);
add(new JScrollPane(panel),BorderLayout.CENTER);
}
protected abstract void onModeChange();
}