package com.opendoorlogistics.studio.tables.custom; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; import java.util.concurrent.Callable; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import com.opendoorlogistics.api.ExecutionReport; import com.opendoorlogistics.api.Tables; import com.opendoorlogistics.api.app.ui.BeanEditorFactory; import com.opendoorlogistics.api.app.ui.BeanEditorPanel; import com.opendoorlogistics.api.app.ui.UIAction; import com.opendoorlogistics.api.tables.ODLListener; import com.opendoorlogistics.api.tables.ODLTable; import com.opendoorlogistics.api.tables.ODLTableDefinition; import com.opendoorlogistics.api.tables.beans.BeanMappedRow; import com.opendoorlogistics.codefromweb.PackTableColumn; import com.opendoorlogistics.core.scripts.execution.ExecutionReportImpl; import com.opendoorlogistics.core.tables.utils.TableUtils; import com.opendoorlogistics.core.utils.ui.ExecutionReportDialog; import com.opendoorlogistics.core.utils.ui.OkCancelDialog; import com.opendoorlogistics.core.utils.ui.PopupMenuMouseAdapter; import com.opendoorlogistics.studio.tables.custom.StandardEditActionHandlers.ActionType; /** * The panel to show when the table is ok * @author Phil * */ public class TableActivePanel<T extends BeanMappedRow> extends JPanel implements ODLListener{ private BeanMappingInfo<T> bmi; private final JTable jTable; private final List<UIAction> actions; private final StandardEditActionHandlers editHandlers; private final BeanEditorFactory<T> editorFactory; private ODLTable adaptedTable; private ExecutionReport lastReport; public TableActivePanel(BeanMappingInfo<T> bmi, BeanEditorFactory<T> editorFactory) { setLayout(new BorderLayout()); this.bmi = bmi; this.editorFactory = editorFactory; // update the adapter first of all so we have a full table for the column packer to work on.. updateAdapter(); Component header = editorFactory.createTableHeader(); if(header!=null){ add(header, BorderLayout.NORTH); } // init the table jTable = new JTable(createTableModel()); jTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jTable.setFillsViewportHeight(true); jTable.getTableHeader().setReorderingAllowed(false); jTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { updateEnabledActions(); } }); jTable.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() >= 2) { editHandlers.actionPerformed(null, null, ActionType.EDIT); } } }); PackTableColumn.packAll(jTable, 6); // place the table in a scrollpane JScrollPane scrollPane = new JScrollPane(jTable); add(scrollPane, BorderLayout.CENTER); // add a toolbar JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); add(toolBar, BorderLayout.SOUTH); // create right-click popup menu on the list final JPopupMenu popup = new JPopupMenu(); jTable.addMouseListener(new PopupMenuMouseAdapter() { @Override protected void launchMenu(MouseEvent me) { // ensure the correct row is selected int row = jTable.rowAtPoint(me.getPoint()); if (row != -1) { jTable.getSelectionModel().setSelectionInterval(row, row); } popup.show(me.getComponent(), me.getX(), me.getY()); } }); // create the actions editHandlers = createActionHandlers(); actions = StandardEditActionHandlers.createActions("linked file", editHandlers); for (Action action : actions) { toolBar.add(action); popup.add(action); } updateEnabledActions(); } @Override public void tableChanged(int tableId, int firstRow, int lastRow) { fireTableDataChanged(); updateEnabledActions(); } @Override public void datastoreStructureChanged() { updateAdapter(); fireTableDataChanged(); updateEnabledActions(); } public void fireTableDataChanged() { // save table selection int selRow=jTable.getSelectedRow(); AbstractTableModel model = (AbstractTableModel) jTable.getModel(); model.fireTableDataChanged(); if(selRow!=-1){ jTable.getSelectionModel().setSelectionInterval(selRow, selRow); } } @Override public ODLListenerType getType() { // TODO Auto-generated method stub return null; } private Window getWindowAncestor() { return SwingUtilities.getWindowAncestor(this); } private StandardEditActionHandlers createActionHandlers() { return new StandardEditActionHandlers() { private void doEdit(Callable<Boolean> callable, ActionType type) { if (bmi.getDs()==null || !TableUtils.runTransaction(bmi.getDs(), callable)) { JOptionPane.showMessageDialog(TableActivePanel.this, "Could not complete edit action:" + type); } ; } @Override public void actionPerformed(ActionEvent e, UIAction action, ActionType type) { int selRow = jTable.getSelectedRow(); int nbRow = jTable.getRowCount(); ODLTable rawTable = bmi.getRawTable(); if (adaptedTable == null || rawTable == null) { return; } Tables tables = bmi.getApi().tables(); switch (type) { case ADD: try { T item = (T) bmi.getMapping().getBeanClass().newInstance(); runEditor(item, new Callable<Boolean>() { @Override public Boolean call() throws Exception { bmi.getMapping().writeObjectToTable(item, adaptedTable); return true; } }, type); } catch (Exception e2) { // TODO: handle exception } break; case EDIT: ExecutionReportImpl report = new ExecutionReportImpl(); T item = bmi.getMapping().readObjectFromTableByRow(adaptedTable, selRow, report); if (report.isFailed()) { ExecutionReportDialog dlg = new ExecutionReportDialog((JFrame) getWindowAncestor(), "Error reading object", report, true); dlg.setVisible(true); } runEditor(item, new Callable<Boolean>() { @Override public Boolean call() throws Exception { bmi.getMapping().updateTableRow(item, adaptedTable, item.getGlobalRowId()); return true; } }, type); break; case DELETE_ITEM: if (selRow != -1) { doEdit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { rawTable.deleteRow(selRow); return true; } }, type); } break; case MOVE_ITEM_UP: if (selRow != -1 && selRow > 0) { doEdit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { tables.copyRow(rawTable, selRow, rawTable, selRow - 1); rawTable.deleteRow(selRow + 1); jTable.getSelectionModel().setSelectionInterval(selRow - 1, selRow - 1); return true; } }, type); } break; case MOVE_ITEM_DOWN: if (selRow != -1 && selRow < (nbRow - 1)) { doEdit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { tables.copyRow(rawTable, selRow, rawTable, selRow + 2); rawTable.deleteRow(selRow); jTable.getSelectionModel().setSelectionInterval(selRow + 1, selRow + 1); return true; } }, type); } break; default: break; } } private void runEditor(T item, Callable<Boolean> callable, ActionType type) { BeanEditorPanel<T> panel = editorFactory.createEditorPanel(item); try { OkCancelDialog dlg = new OkCancelDialog(getWindowAncestor(), true, true) { protected Component createMainComponent(boolean inWindowsBuilder) { return panel; } }; dlg.setResizable(panel.isResizable()); switch(type){ case ADD: dlg.setTitle("Add new record"); break; case EDIT: dlg.setTitle("Edit record"); break; default: break; } if (dlg.showModal() == OkCancelDialog.OK_OPTION) { doEdit(callable, type); } } catch (Exception e) { if (panel != null) { panel.dispose(); } } } @Override public void updateEnabledState(UIAction action, ActionType type) { int selRow = jTable.getSelectedRow(); int nbRow = jTable.getRowCount(); boolean enabled = adaptedTable != null; if (enabled) { switch (type) { case EDIT: case DELETE_ITEM: enabled = selRow != -1; break; case MOVE_ITEM_UP: enabled = selRow >= 1; break; case MOVE_ITEM_DOWN: enabled = selRow != -1 && selRow < (nbRow - 1); break; case ADD: enabled = true; break; default: enabled = false; break; } } action.setEnabled(enabled); } }; } protected TableModel createTableModel() { ODLTableDefinition definition = bmi.getMapping().getTableDefinition(); return new AbstractTableModel() { @Override public int getColumnCount() { return definition.getColumnCount(); } @Override public int getRowCount() { if (hasAdapter()) { return adaptedTable.getRowCount(); } return 0; } @Override public String getColumnName(int column) { return definition.getColumnName(column); } @Override public Object getValueAt(int rowIndex, int columnIndex) { if (hasAdapter()) { return adaptedTable.getValueAt(rowIndex, columnIndex); } return null; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { // if (hasAdapter() && rowIndex < adaptedTable.getRowCount() && columnIndex < adaptedTable.getColumnCount()) { // adaptedTable.setValueAt(aValue, rowIndex, columnIndex); // } } }; } private boolean hasAdapter() { return lastReport != null && lastReport.isFailed() == false && adaptedTable != null; } private void updateAdapter() { lastReport = new ExecutionReportImpl(); adaptedTable = bmi.createTableAdapter(lastReport); } private void updateEnabledActions() { for (UIAction action : actions) { action.updateEnabledState(); } } }