package com.applang.components; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.AbstractCellEditor; import javax.swing.BoxLayout; import javax.swing.DefaultCellEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.MatteBorder; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import org.gjt.sp.jedit.View; import android.app.AlertDialog; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.util.Log; import android.widget.Toast; import com.applang.berichtsheft.BerichtsheftActivity; import com.applang.berichtsheft.BerichtsheftApp; import com.applang.berichtsheft.plugin.BerichtsheftPlugin; import static com.applang.Util.*; import static com.applang.Util1.*; import static com.applang.Util2.*; import static com.applang.SwingUtil.*; @SuppressWarnings("rawtypes") public class DataView extends JPanel implements IComponent { public static final String TAG = DataView.class.getSimpleName(); private Context context = BerichtsheftActivity.getInstance(); public Context getContext() { return context; } ContentResolver contentResolver = context.getContentResolver(); public DataView() { resetDataConfiguration(); createUI(); } private JComboBox sqlBox; private DataTable table; public JTable getTable() { return table; } public void createUI() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); sqlBox = new JComboBox(); Memory.update(sqlBox, true, "DataView"); final JTextField textField = comboEdit(sqlBox); sqlBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dc.setProjectionModel(null); reload(textField.getText()); } }); textField.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { super.keyTyped(e); dc.setProjectionModel(null); } }); textField.setText(""); table = new DataTable(new DataModel()); switchSelectionMode(false); add(sqlBox, BorderLayout.NORTH); setMaximumDimension(sqlBox, 100); add(scrollableViewport(table), BorderLayout.CENTER); southStatusBar(this); } @SuppressWarnings("unused") private void toastCellContentsOnDoubleClick() { table.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent ev) { if (ev.getClickCount() == 2) { JTable table = (JTable) ev.getSource(); int row = table.getSelectedRow(); int col = table.getSelectedColumn(); try { Object value = table.getModel().getValueAt(row, col); Point pt = new Point(ev.getX(), ev.getY()); SwingUtilities.convertPointToScreen(pt, table); Toast.makeText( BerichtsheftActivity.getInstance().setLocation(pt), String.valueOf(value), Toast.LENGTH_LONG).show(); } catch (Exception e) { Log.e(TAG, "table cell", e); } } } }); } @SuppressWarnings("unused") private void selectRowOnRightMouseButtonClick() { table.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent ev) { if (SwingUtilities.isRightMouseButton(ev)) { int row = table.rowAtPoint(ev.getPoint()); table.getSelectionModel().setSelectionInterval(row, row); } } }); } private void switchSelectionMode(boolean managed) { table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); if (managed) { table.setCellSelectionEnabled(false); table.setRowSelectionAllowed(true); } else { table.setCellSelectionEnabled(true); } } @Override public Component getUIComponent() { return this; } DataConfiguration dc; public DataConfiguration getDataConfiguration() { return dc; } public void resetDataConfiguration() { dc = new DataConfiguration(context, null, null); } public boolean configureData(View view, boolean full) { boolean retval = dc.display(view, full); if (retval) dc.save(); return retval; } public void setUri(Uri uri) { dc.setUri(uri); } public Uri getUri() { return dc.getUri(); } public void setUriString(String uriString) { setUri(notNullOrEmpty(uriString) ? Uri.parse(uriString) : null); } public String getUriString() { return stringValueOf(getUri()); } public void setFlavor(String flavor) { dc.getProjectionModel().setFlavor(flavor); } public String getFlavor() { return dc.getProjectionModel().getFlavor(); } public void synchronizeSelection(int[] rows, Object...params) { if (sqlBox.isVisible()) { showSqlBox(false); switchSelectionMode(true); JPopupMenu popupMenu = param(null, 0, params); popupAdapter = new PopupAdapter(popupMenu); table.addMouseListener(popupAdapter); tableSelectionListener = param(null, 1, params); table.getSelectionModel().addListSelectionListener(tableSelectionListener); } selectRowAndScrollToVisible(table, rows); } public void showSqlBox(boolean show) { sqlBox.setVisible(show); } private PopupAdapter popupAdapter = null; private ListSelectionListener tableSelectionListener = null; public void nosync() { if (!sqlBox.isVisible()) { showSqlBox(true); switchSelectionMode(false); if (popupAdapter != null) { table.removeMouseListener(popupAdapter); popupAdapter = null; } if (tableSelectionListener != null) { table.getSelectionModel().removeListSelectionListener(tableSelectionListener); tableSelectionListener = null; } } load(); } public void load() { clear(); reload(); } public boolean load(Uri uri) { setUri(uri); return reload(); } public boolean reload(Object...params) { dataAdapter = null; final String sql = param(null, 0, params); return populate(new Job<Void>() { public void perform(Void t, Object[] params) throws Exception { wireObserver(contentResolver, true); Uri uri = getUri(); DataModel model = new DataModel(); String s = sql; ProjectionModel projectionModel = dc.getProjectionModel(); if (projectionModel != null) { BidiMultiMap projection = projectionModel.getProjection(); model.setProjection(projection); String tableName = dbTableName(uri); s = "select " + join(",", projection.getKeys().toArray()) + " from " + tableName; } JTextField textField = comboEdit(sqlBox); if (nullOrEmpty(s) && sqlBox.isEnabled()) s = textField.getText(); Cursor cursor = contentResolver.rawQuery(uri, s); if (cursor != null) { model.traverse(cursor); } table.setModel(model); if (sqlBox.isVisible()) textField.setText(getSql()); else textField.setText(""); wireObserver(contentResolver, false); } }); } public String getSql() { return contentResolver.contentProvider.sql; } private ContentObserver contentObserver = new ContentObserver(null) { public void onChange(Object arg) { table.borderedRowid = null; if (sqlBox.isVisible()) reload(); else { Uri uri = (Uri) arg; Long id = parseId(null, uri); if (id != null) { DataModel model = (DataModel) table.getModel(); Object pk = dataAdapter.info.get("PRIMARY_KEY"); table.rowidColumn = model.columns.indexOf(pk); int row = model.findRowAt(table.rowidColumn, id); ProjectionModel projectionModel = dc.getProjectionModel(); Object[] columns = projectionModel.getExpandedProjection().getKeys().toArray(); Object[][] result = dataAdapter.query(getUriString(), toStrings(columns), pk + "=?", strings("" + id)); if (isAvailable(0, result)) { if (row > -1) model.setValues(false, row, result[0]); else model.addValues(false, result[0]); } else if (row > -1) { model.setValues(false, row, null); } table.borderedRowid = id; model.fireTableDataChanged(); } } } }; public void wireObserver(ContentResolver contentResolver, boolean unwire) { table.setAutoCreateRowSorter(!unwire); if (unwire) contentResolver.unregisterContentObserver(contentObserver); else contentResolver.registerContentObserver(getUri(), false, contentObserver); } public void clear() { resetDataConfiguration(); table.setModel(new DataModel()); } private DataAdapter dataAdapter = null; private boolean populate(Job<Void> populate) { boolean retval = true; String msg = ""; try { populate.perform(null, null); } catch (Exception e) { msg = e.getMessage(); retval = false; } if (notNullOrEmpty(dc.getTableName())) msg = String.format("%s record(s)", table.getModel().getRowCount()); else setColumnWidthsAsPercentages(table, new double[]{0.10, 0.20, 0.15, 0.05, 0.50}); message(msg); return retval; } public boolean populate(DataAdapter dataAdapter, final Object...params) { this.dataAdapter = dataAdapter; wireObserver(contentResolver, true); return populate(new Job<Void>() { public void perform(Void t, Object[] parms) throws Exception { DataAdapter dataAdapter = DataView.this.dataAdapter; wireObserver(dataAdapter.getContext().getContentResolver(), true); ProjectionModel projectionModel = dc.getProjectionModel(); BidiMultiMap projection = projectionModel.getExpandedProjection(); DataModel model = dataAdapter.query(getUriString(), projection, params); table.setModel(valueOrElse(new DataModel(), model)); wireObserver(dataAdapter.getContext().getContentResolver(), false); } }); } public Object[] getSelectedItems() { ListSelectionModel sm = table.getSelectionModel(); if (sm.isSelectionEmpty()) return null; ValList list = vlist(); int[] rows = table.getSelectedRows(); int[] cols = table.getSelectedColumns(); for (int i = 0; i < rows.length; i++) { ValList items = vlist(); for (int j = 0; j < cols.length; j++) { items.add(table.getModel().getValueAt(rows[i], cols[j])); } list.add(items); } return list.toArray(); } public static ValList getSelectedColumnNames(JTable table) { ValList columns = vlist(); int[] cols = table.getSelectedColumns(); for (int i = 0; i < cols.length; i++) { TableColumn col = table.getTableHeader().getColumnModel().getColumn(cols[i]); columns.add(col.getHeaderValue()); } return columns; } public static DefaultTableModel dbTablesModel(Context context, Uri uri) { ValList rows = vlist(); ValList tables = tables(context, uri); for (Object table : tables) { rows.add(objects( table, recordCount(context, dbTable(uri, table.toString())) )); } return new DefaultTableModel( rows.toArray(new Object[0][]), objects("table", "records")) { @Override public boolean isCellEditable(int row, int column) { return false; } }; } public static JComponent dbTablesComponent(Context context, Uri uri, final Job<JTable> onDoubleClick, final Object...params) { DefaultTableModel model = dbTablesModel(context, uri); JTable table = new JTable(model); table.setName("table"); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); if (onDoubleClick != null) { table.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent ev) { if (ev.getClickCount() == 2) { JTable table = (JTable) ev.getSource(); try { onDoubleClick.perform(table, params); } catch (Exception e) { Log.e(TAG, "dbTablesComponent", e); } } } }); } return scrollableViewport(table); } public static File chooseDb(Function<File> chooser, final boolean providerIncluded, Object...params) { final String key = "Database.memory"; File file = getFileFromStore(0, "SQLite database", new FileNameExtensionFilter("db files", "db"), chooser, new Function<String[]>() { public String[] apply(Object... params) { if (param_Boolean(false, 1, params)) return null; ValList list = (ValList) getListSetting(key, vlist()); if (providerIncluded) { for (Object pkg : providerPackages) { list.add(String.valueOf(pkg)); } } return list.toArray(strings()); } }, new Job<String[]>() { public void perform(String[] fileNames, Object[] params) throws Exception { List<String> list = asList(fileNames); putListSetting(key, filter(list, true, isProvider)); } }, params); if (file != null) { String path = file.getPath(); if (isSQLite(file) || isProvider.apply(path) || !fileExists(file)) return file; } return null; } @SuppressWarnings("unchecked") public static void fillFlavorCombo(JComboBox comboBox) { DefaultComboBoxModel model = (DefaultComboBoxModel) comboBox.getModel(); model.removeAllElements(); model.addElement(null); ValList flavors = contentAuthorities(providerPackages); for (Object flavor : sortedSet(flavors)) { model.addElement(flavor); } comboBox.setModel(model); } public static JComponent dbFlavorsComponent(String packageName, final Job<JTable> onDoubleClick, final Object...params) { ValList rows = vlist(); if (notNullOrEmpty(packageName)) { ValList flavors = contentAuthorities(strings(packageName)); for (Object flavor : flavors) { rows.add(objects(split(flavor.toString(), DOT_REGEX).get(-1))); } } else { ValList flavors = contentAuthorities(providerPackages); for (Object flavor : flavors) { rows.add(objects(flavor)); } } if (rows.size() < 1) return null; JTable table = new JTable( new DefaultTableModel( rows.toArray(new Object[0][]), objects("authority")) { @Override public boolean isCellEditable(int row, int column) { return false; } }); table.setName("table"); table.setTableHeader(null); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); if (onDoubleClick != null) { table.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent ev) { if (ev.getClickCount() == 2) { JTable table = (JTable) ev.getSource(); try { onDoubleClick.perform(table, params); } catch (Exception e) { Log.e(TAG, "dbFlavorsComponent", e); } } } }); } return scrollableViewport(table); } private AlertDialog dialog = null; public String askFlavor(String packageName) { final Object[] params = objects(""); final Job<JTable> onDoubleClick = new Job<JTable>() { public void perform(JTable table, Object[] params) throws Exception { int sel = table.getSelectedRow(); if (sel > -1) { params[0] = table.getModel().getValueAt(sel, 0).toString(); } dialog.dismiss(); } }; JComponent flavorsComponent = dbFlavorsComponent(packageName, onDoubleClick, params); if (flavorsComponent == null) return packageName; dialog = new AlertDialog.Builder(context) .setTitle("Database flavor") .setView(flavorsComponent) .setNeutralButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { AlertDialog dlg = (AlertDialog) dialog; JTable table = dlg.findComponentById(1, "table"); try { onDoubleClick.perform(table, params); } catch (Exception e) { Log.e(TAG, "askFlavor", e); } } }) .create(); dialog.open(0.5, 0.5); return params[0].toString(); } public Uri askUri(View view, String path) { Uri uri = null; File dbFile = chooseDb(BerichtsheftPlugin.fileChooser(view), true, path, true); if (dbFile != null) { String flavor = null; String dbPath = dbFile.getPath(); if (isProvider.apply(dbPath)) { String f = askFlavor(dbPath); if (nullOrEmpty(f)) return null; if (f.equals(dbPath)) flavor = f; else flavor = join(".", dbPath, f); if (!makeSureExists(flavor, null)) return null; uri = contentUri(flavor, null); } else { uri = Uri.fromFile(dbFile); if (fileExists(dbFile)) flavor = null; else { flavor = askFlavor(null); if (nullOrEmpty(flavor)) return null; if (!makeSureExists(flavor, dbFile)) return null; } } try { final Job<JTable> onDoubleClick = new Job<JTable>() { public Uri uri = null; public void perform(JTable table, Object[] params) throws Exception { int sel = table.getSelectedRow(); if (sel > -1) { String tableName = table.getModel().getValueAt(sel, 0).toString(); uri = dbTable(uri, tableName); } dialog.dismiss(); } }; onDoubleClick.getClass().getField("uri").set(onDoubleClick, uri); dialog = new AlertDialog.Builder(context) .setTitle(dbPath) .setView(dbTablesComponent(context, uri, onDoubleClick)) .setNeutralButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { AlertDialog dlg = (AlertDialog) dialog; JTable table = dlg.findComponentById(1, "table"); try { onDoubleClick.perform(table, null); } catch (Exception e) { Log.e(TAG, "askUri", e); } } }) .create(); dialog.open(0.5, 0.5); uri = (Uri) onDoubleClick.getClass().getField("uri").get(onDoubleClick); } catch (Exception e) { Log.e(TAG, "askUri", e); } } return uri; } public static class ProjectionModel extends AbstractTableModel implements ListModel { public ProjectionModel(Context context, Uri uri, String flavor, Object...params) { setFlavor(flavor); tableName = dbTableName(uri); initialize(table_info2(context, uri, tableName, flavor), params); } private void initialize(ValMap info, Object...params) { this.info = info; names = info.getList("name").toArray(); types = info.getList("type").toArray(); checks = vlist(); conversions = vlist(); styles = vlist(); sortExpressions = vlist(); int length = names.length; for (int i = 0; i < length; i++) { checks.add(true); conversions.add(""); styles.add(""); sortExpressions.add(""); } BidiMultiMap projection = param(null, 0, params); if (projection != null && isAvailable(0, projection.getKeys())) { for (int i = 0; i < length; i++) { Object name = names[i]; checks.set(i, projection.getValue(name, 3)); conversions.set(i, stringValueOf(projection.getValue(name))); styles.set(i, projection.getValue(name, 4)); sortExpressions.set(i, projection.getValue(name, 5)); } } } public ProjectionModel(DataAdapter dataAdapter) { setFlavor(dataAdapter.getFlavor()); tableName = dataAdapter.getTableName(); initialize(dataAdapter.info); int pkColumn = info.getList("name").indexOf(info.get("PRIMARY_KEY")); if (pkColumn > -1) checks.set(pkColumn, false); } private String tableName; private ValMap info; private Object[] names, types; private ValList checks, conversions, styles, sortExpressions; @Override public int getRowCount() { return names.length; } @Override public int getColumnCount() { return 5; } @Override public String getColumnName(int column) { switch (column) { case 1: return "Column"; case 2: return "Type"; case 3: return "Conversion"; case 4: return "Style"; case 5: return "Sort Order"; default: return ""; } } @Override public Object getValueAt(int row, int col) { switch (col) { case 1: return names[row]; case 2: return types[row]; case 3: return conversions.get(row); case 4: Object style = styles.get(row); return stringValueOf(style); case 5: return sortExpressions.get(row); default: return checks.get(row); } } @Override public void setValueAt(Object value, int row, int col) { switch (col) { case 1: names[row] = value; break; case 2: types[row] = value; break; case 3: conversions.set(row, value); break; case 4: styles.set(row, value); break; case 5: sortExpressions.set(row, value); break; default: checks.set(row, value); } changed = true; memorizeFlavor(); } @Override public Class<?> getColumnClass(int col) { if (col == 0) return Boolean.class; else return String.class; } @Override public boolean isCellEditable(int row, int col) { if (col == 1 || col == 2) return false; else return true; } private String flavor; public void setFlavor(String flavor) { this.flavor = flavor; } public String getFlavor() { return flavor; } public boolean hasFlavor() { return notNullOrEmpty(flavor); } public void injectFlavor() { if (hasFlavor()) { ValMap map = ScriptManager.getProjectionDefault(flavor, tableName); if (map.get("version") == info.get("VERSION")) { BidiMultiMap projection = (BidiMultiMap) map.get("projection"); if (projection != null) { for (int i = 0; i < names.length; i++) { Integer[] index = projection.get(names[i]); if (index.length > 0) { conversions.set(i, projection.getValue(names[index[0]], 1)); checks.set(i, projection.getValue(names[index[0]], 3)); styles.set(i, projection.getValue(names[index[0]], 4)); sortExpressions.set(i, projection.getValue(names[index[0]], 5)); } } fireTableDataChanged(); } } } } private void memorizeFlavor() { if (hasFlavor()) { ValMap map = vmap(); map.put("version", info.get("VERSION")); map.put("projection", getExpandedProjection()); ScriptManager.setProjectionDefault(flavor, tableName, map); } } public BidiMultiMap getExpandedProjection() { return new BidiMultiMap(vlist(names), new ValList(conversions), vlist(types), new ValList(checks), new ValList(styles), new ValList(sortExpressions)); } public BidiMultiMap getProjection() { BidiMultiMap projection = getExpandedProjection(); ValList lists = vlist(projection.getLists()); lists.remove(5); projection.setLists(lists.toArray(new ValList[0])); for (int i = names.length - 1; i >= 0; i--) if (!(Boolean) checks.get(i)) { projection.remove(i); } return projection; } @Override public String toString() { return write_assoc(null, "flavor", getFlavor(), -1) + getExpandedProjection().toString(); } public boolean changed = false; @Override public int getSize() { return getRowCount(); } @Override public Object getElementAt(int index) { return getValueAt(index, 1); } @Override public void addListDataListener(ListDataListener l) { // TODO Auto-generated method stub } @Override public void removeListDataListener(ListDataListener l) { // TODO Auto-generated method stub } public Object[] getStyles(Context context) { return context.getResources().getXMLResourceItem("@style/*"); } public Object[] getAllSortExpressions() { ValList expressions = vlist(_null()); for (Object name : names) { expressions.add(name + " ASC"); expressions.add(name + " DESC"); } return expressions.toArray(); } public String getSortOrder() { ArrayList<String> sortOrder = alist(); for (Object expr : sortExpressions) if (notNullOrEmpty(expr) && sortOrder.indexOf(expr) < 0) sortOrder.add(expr.toString()); return join(",", sortOrder.toArray()); } } public static class ConversionCellEditor extends AbstractCellEditor implements TableCellEditor, ActionListener { JTextField textField = new JTextField(); JPanel panel = null; Component relative; public ConversionCellEditor(Component relative) { this.relative = relative; } @Override public Object getCellEditorValue() { return textField.getText(); } @Override public void actionPerformed(ActionEvent e) { String func = new ScriptManager( BerichtsheftApp.getJEditView(), relative, null, null, null, textField.getText()) .getFunction(); if (notNullOrEmpty(func)) { textField.setText(func); } stopCellEditing(); } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { textField.setText(stringValueOf(value)); if (panel == null) { panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); panel.add(textField); JButton btn = new JButton(iconFrom("/images/ellipsis_16x16.png")); btn.addActionListener(this); panel.add(btn); panel.doLayout(); scaleSize(btn, 0.333); } textField.requestFocus(); return panel; } } public static JComponent projectionComponent(final Context context, final Component relative, final ProjectionModel model) { JTable table = new JTable() { @SuppressWarnings("unchecked") @Override public TableCellEditor getCellEditor(final int row, final int column) { switch (column) { case 3: final ConversionCellEditor cellEditor = new ConversionCellEditor(relative); cellEditor.addCellEditorListener(new CellEditorListener() { public void editingStopped(ChangeEvent e) { Object value = cellEditor.getCellEditorValue(); getModel().setValueAt(value, row, column); } public void editingCanceled(ChangeEvent e) { } }); return cellEditor; case 4: return new DefaultCellEditor(new JComboBox(model.getStyles(context))); case 5: return new DefaultCellEditor(new JComboBox(model.getAllSortExpressions())); default: return super.getCellEditor(row, column); } } }; table.setModel(model == null ? new DefaultTableModel() : model); table.setName("table"); table.setRowSelectionAllowed(false); table.setColumnSelectionAllowed(false); setColumnWidthsAsPercentages(table, 0.10); return scrollableViewport(table); } public static ProjectionModel askProjection(Context context, String title, ProjectionModel model, Object...params) { JComponent projectionComponent = projectionComponent(context, null, model); AlertDialog dialog = new AlertDialog.Builder(context, param_Integer(AlertDialog.behavior, 0, params), param_Integer(3, 1, params)) .setTitle(valueOrElse("Projection", title)) .setView(projectionComponent) .create(); dialog.open(1.0, 0.5); JTable table = findFirstComponent(projectionComponent, "table"); if (table != null) { AbstractCellEditor ce = (AbstractCellEditor) table.getCellEditor(); if (ce != null) ce.stopCellEditing(); } int result = (Integer) dialog.result; if (result > 0) return null; else return model; } public static class DataModel extends AbstractTableModel { @Override public String toString() { return String.valueOf(columns) + "\n\n" + String.valueOf(data).replaceAll("(\\],) (\\[)", "$1\n\n$2"); } public Vector<Vector<Object>> data = new Vector<Vector<Object>>(); public DataModel traverse(Cursor cursor) { if (cursor != null) { if (columns.size() < 1) { for (int i = 0; i < cursor.getColumnCount(); i++) columns.add(cursor.getColumnName(i)); } data.clear(); com.applang.Util1.traverse(cursor, new Job<Cursor>() { public void perform(Cursor cursor, Object[] params) throws Exception { for (int j = 0; j < cursor.getCount(); j++) { Vector<Object> rec = new Vector<Object>(); for (int i = 0; i < cursor.getColumnCount(); i++) { Object value = getCellValue(cursor, j, i); rec.add(value); } data.add(rec); } } }); } return this; } public ValList columns = vlist(); public String[] conversions = strings(); private boolean hasConversion(int col) { return isAvailable(col, conversions) && conversions[col].length() > 0; } private int[] index = null; private int index(int index) { return this.index == null || index >= this.index.length ? index : this.index[index]; } public BidiMultiMap getProjection() { ValList keys = vlist(); ValList values = vlist(); for (int i = 0; i < getColumnCount(); i++) { keys.add(columns.get(index(i))); values.add(conversions[index(i)]); } return new BidiMultiMap(keys, values); } public DataModel setProjection(BidiMultiMap projection) { if (projection != null) { columns = projection.getKeys(); conversions = projection.getValues().toArray(strings()); List<Integer> list = alist(); Object[] checks = valueOrElse(vlist(), projection.getValues(3)).toArray(); for (int i = 0; i < columns.size(); i++) if (param_Boolean(true, i, checks)) list.add(i); index = toIntArray(list); } return this; } public void addValues(boolean convert, Object[] values) { Vector<Object> rec = new Vector<Object>(); for (int i = 0; i < values.length; i++) { Object value = values[i]; if (convert && hasConversion(i)) value = ScriptManager.doConversion(value, conversions[i], "pull"); rec.add(value); } data.add(rec); } public Object[] getValues(boolean convert, int rowIndex) { Object[] values = data.get(rowIndex).toArray(); for (int i = 0; i < values.length; i++) { if (convert && hasConversion(i)) values[i] = ScriptManager.doConversion(values[i], conversions[i], "push"); } return values; } public int findRowAt(int columnIndex, Object value) { if (columnIndex > -1) for (int i = 0; i < getRowCount(); i++) if (data.get(i).get(columnIndex).equals(value)) return i; return -1; } public void setValues(boolean convert, int rowIndex, Object[] values) { if (values != null) { Vector<Object> rec = data.get(rowIndex); for (int i = 0; i < values.length; i++) { Object value = values[i]; if (convert && hasConversion(i)) value = ScriptManager.doConversion(value, conversions[i], "pull"); rec.set(i, value); } } else data.remove(rowIndex); } @Override public Object getValueAt(int rowIndex, int columnIndex) { return data.get(rowIndex).get(index(columnIndex)); } @Override public int getRowCount() { return data.size(); } @Override public int getColumnCount() { return index != null ? index.length : columns.size(); } @Override public String getColumnName(int index) { return String.valueOf(columns.get(index(index))); } @Override public Class<?> getColumnClass(int index) { Object value = getRowCount() > 0 ? getValueAt(0, index) : null; if (value != null) return value.getClass(); else return super.getColumnClass(index(index)); } public String renderCellValue(Object value, int modelColumn) { int col = index(modelColumn); if (hasConversion(col)) value = ScriptManager.doConversion(value, conversions[col], "push"); return stringValueOf(value); } public JTable makeTable() { JTable table = new DataTable(this); table.setAutoCreateRowSorter(true); return table; } } public static class DataTable extends JTable { public DataTable(DataModel cm) { super(cm); } public int rowidColumn = -1; public Long borderedRowid = null; @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component c; try { c = super.prepareRenderer(renderer, row, column); } catch (Exception e) { c = new DefaultTableCellRenderer(); } DataModel model = (DataModel) getModel(); if (c instanceof JLabel) { String string = model.renderCellValue( getValueAt(row, column), convertColumnIndexToModel(column)); JLabel lbl = (JLabel) c; lbl.setText(string); lbl.setToolTipText(string); } if (borderedRowid != null) { Object value = model.getValues(false, row)[rowidColumn]; if (borderedRowid.equals(value)) { JComponent jc = (JComponent)c; jc.setBorder(new MatteBorder(1, column < 1 ? 1 : 0, 1, column > model.getColumnCount() - 2 ? 1 : 0, Color.RED)); } } return c; } } public static void main(String...args) { BerichtsheftApp.loadSettings(); final DataView dv = new DataView(); dv.load(); if (dv.configureData(null, true)) { dv.reload(); } showFrame(null, dv.getUriString(), new UIFunction() { public Component[] apply(final Component comp, Object[] parms) { dv.getTable().setPreferredScrollableViewportSize(new Dimension(800,400)); return components(dv); } }, null, null, Behavior.EXIT_ON_CLOSE); } }