package com.applang.components; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.util.Properties; import javax.swing.AbstractCellEditor; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; 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.content.SharedPreferences; import android.net.Uri; import com.applang.PluginUtils; import com.applang.SwingUtil.MapEditorComponent; import com.applang.berichtsheft.BerichtsheftActivity; import com.applang.berichtsheft.BerichtsheftApp; import com.applang.berichtsheft.R; import com.applang.berichtsheft.plugin.BerichtsheftPlugin; import com.applang.components.DataView.ProjectionModel; import static com.applang.SwingUtil.*; import static com.applang.Util.*; import static com.applang.Util1.*; import static com.applang.Util2.*; import static com.applang.PluginUtils.*; @SuppressWarnings("rawtypes") public class DataConfiguration { public static final String TAG = DataConfiguration.class.getSimpleName(); private Context mContext; public void setContext(Context context) { mContext = context; prefs = mContext.getSharedPreferences(); } public Context getContext() { return mContext; } private Uri uri = null; public Uri getUri() { return uri; } public void setUri(Uri uri) { this.uri = uri; tableName = dbTableName(uri); path = mContext.getDatabasePath(uri); if (nullOrEmpty(uri)) setProjectionModel(null); if (mProjectionModel != null && mProjectionModel.hasFlavor()) { mContext.registerFlavor(mProjectionModel.getFlavor(), path); } } private String path, tableName; public String getPath() { return dbPath(path); } public String getTableName() { return tableName; } private PropertyChangeSupport mPcs = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener listener) { mPcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { mPcs.removePropertyChangeListener(listener); } private ProjectionModel mProjectionModel = null; public void setProjectionModel(ProjectionModel projectionModel) { if (mProjectionModel != null && mProjectionModel.hasFlavor()) { mContext.unregisterFlavor(mProjectionModel.getFlavor()); } ProjectionModel oldProjectionModel = mProjectionModel; mProjectionModel = projectionModel; mPcs.firePropertyChange("projectionModel", oldProjectionModel, mProjectionModel); } public ProjectionModel getProjectionModel() { return mProjectionModel; } public String getFlavor() { return mProjectionModel != null ? mProjectionModel.getFlavor() : null; } public BidiMultiMap getProjection() { return mProjectionModel != null ? mProjectionModel.getProjection() : null; } public String getSortOrder() { return mProjectionModel != null ? mProjectionModel.getSortOrder() : null; } private ValMap options = vmap(); public DataConfiguration(Context context, Uri uri, ProjectionModel model) { setContext(context); if (nullOrEmpty(uri)) load(); else setUri(uri); if (model != null) setProjectionModel(model); options.put("Layout", "standard"); } public DataConfiguration(DataAdapter dataAdapter) { setContext(dataAdapter.getContext()); String uriString = stringValueOf(uri); setUri(dataAdapter.makeUri(uriString)); setProjectionModel(new ProjectionModel(dataAdapter)); } private AlertDialog dialog; private JTextField entry; private JComboBox comboBox; private JTable[] tables = new JTable[2]; public Boolean display(final View view, Object...params) { final boolean more = param_Boolean(prefs.getBoolean("dataConfig_more", Boolean.TRUE), 0, params); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); panel.add(display_Flavor()); panel.add(Box.createVerticalStrut(10)); panel.add(display_DbFile(view)); panel.add( Box.createVerticalStrut(10) ); Dimension size = new Dimension(400, 110); JComponent component = DataView.dbTablesComponent(mContext, uri, onDoubleClick); tables[0] = findFirstComponent(component, "table"); tables[0].setPreferredScrollableViewportSize(scaledDimension(size, 1.0, 0.8)); panel.add(component); if (more) { component = DataView.projectionComponent(getContext(), dialog, mProjectionModel); tables[1] = findFirstComponent(component, "table"); tables[1].setPreferredScrollableViewportSize(scaledDimension(size, 1.0, 1.2)); panel.add(component); component = new MapEditorComponent(options, _null()); panel.add(component); } tables[0].getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) return; stopCellEditing(); int sel = tables[0].getSelectedRow(); if (sel > -1) { tableName = stringValueOf(tables[0].getModel().getValueAt(sel, 0)); uri = dbTable(uri, tableName); setProjectionModel(new ProjectionModel(mContext, uri, mProjectionModel.getFlavor())); mProjectionModel.injectFlavor(); if (more) { tables[1].setModel(mProjectionModel); } } else { tableName = null; if (tables[1] != null) tables[1].setModel(new DefaultTableModel()); } } } ); result = null; dialog = new AlertDialog.Builder(mContext) .setTitle("Data configuration") .setView(panel) .setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); result = true; } }) .setNeutralButton(more ? R.string.button_less : R.string.button_more, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { prefs.edit().putBoolean("dataConfig_more", !more); finish(); } }) .setNegativeButton(android.R.string.cancel, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); result = false; } }) .setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { finish(); result = false; } }) .create(); setLongText(entry, path); if (mProjectionModel == null) setProjectionModel(new ProjectionModel(mContext, getUri(), mContext.getFlavor())); comboBox.getModel().setSelectedItem(mProjectionModel.getFlavor()); dialog.open(); if (result == null) return display(view, !more); else return result; } private Box display_Flavor() { Box box = new Box(BoxLayout.X_AXIS); box.add(new JLabel("Flavor")); box.add(Box.createHorizontalStrut(10)); comboBox = new JComboBox(); DataView.fillFlavorCombo(comboBox); comboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (mProjectionModel.hasFlavor()) getContext().unregisterFlavor(mProjectionModel.getFlavor()); String flavor = stringValueOf(comboBox.getSelectedItem()); mProjectionModel.setFlavor(flavor); mProjectionModel.injectFlavor(); path = entry.getText(); if (mProjectionModel.hasFlavor()) { if (nullOrEmpty(path)) path = mContext.getDatabasePath(databaseName(flavor)).getPath(); getContext().registerFlavor(flavor, path); } setDbFile(new File(path), tableName); } }); box.add(comboBox); setMaximumDimension(box, 100); return box; } private Box display_DbFile(final View view) { Box box = new Box(BoxLayout.X_AXIS); box.add(new JLabel("Database")); box.add(Box.createHorizontalStrut(10)); entry = new JTextField(40); entry.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { setDbFile(new File(entry.getText()), tableName); } }); entry.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { setLongText(entry, entry.getText()); } }); box.add(entry); box.add(makeCustomButton("datadock.choose-db", new ActionListener() { public void actionPerformed(ActionEvent evt) { File dbFile = DataView.chooseDb(BerichtsheftPlugin.fileChooser(view), true, path, true); if (dbFile != null) { setLongText(entry, dbFile.getPath()); String flavor = stringValueOf(comboBox.getSelectedItem()); if (notNullOrEmpty(flavor)) makeSureExists(flavor, dbFile); setDbFile(dbFile, null); } else alert(getProperty("dataview.sqlite-required.message")); } }, false)); setMaximumDimension(box, 100); return box; } private void setDbFile(File dbFile, String tableName) { if (fileExists(dbFile) && isSQLite(dbFile)) { setUri(fileUri(dbFile.getPath(), tableName)); setLongText(entry, path); tables[0].setModel(DataView.dbTablesModel(mContext, uri)); } else if (flavoredUri()) { String flavor = mProjectionModel.getFlavor(); setUri(contentUri(flavor, tableName)); entry.setText(""); tables[0].setModel(DataView.dbTablesModel(mContext, uri)); } else { setUri(null); tables[0].setModel(new DefaultTableModel()); } TableModel model = tables[0].getModel(); for (int i = 0; i < model.getRowCount(); i++) if (model.getValueAt(i, 0).equals(tableName)) { tables[0].getSelectionModel().setSelectionInterval(i, i); return; } tables[0].getSelectionModel().setSelectionInterval(-1, -1); } private boolean flavoredUri() { return mProjectionModel.hasFlavor() && nullOrEmpty(entry.getText()); } private Job<JTable> onDoubleClick = new Job<JTable>() { public void perform(JTable table, Object[] params) throws Exception { int sel = table.getSelectedRow(); if (sel > -1) { tableName = stringValueOf(tables[0].getModel().getValueAt(sel, 0)); } result = true; finish(); } }; private void finish() { stopCellEditing(); dialog.dismiss(); if (flavoredUri()) uri = contentUri(mProjectionModel.getFlavor(), tableName); else uri = fileUri(path, tableName); } private void stopCellEditing() { if (tables[1] != null) { AbstractCellEditor ce = (AbstractCellEditor) tables[1].getCellEditor(); if (ce != null) ce.stopCellEditing(); } } private Boolean result = null; private SharedPreferences prefs; public void load() { String uriString = stringValueOf(prefs.getString("uri", "")); String database = stringValueOf(prefs.getString("database", "")); diag_println(DIAG_OFF, "loaded uri, database", uriString, database); if (isFileUri(uriString)) database = Uri.parse(uriString).getPath(); if (!fileExists(database)) { database = null; } projectionFromUri(Uri.parse(uriString), database); } public void projectionFromUri(Uri uri, String database) { String flavor = null; if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { flavor = uri.getAuthority(); } String query = uri.getQuery(); if (query != null) { ValList names = vlist(); ValList types = vlist(); ValList conversions = vlist(); ValList checks = vlist(); ValList list = split(query, "&"); for (int i = 0; i < list.size(); i++) { String[] parts = list.get(i).toString().split("=", 2); names.add(parts[0]); parts = parts[1].split("\\|", 3); types.add(parts[0]); conversions.add(parts[1]); checks.add(parts.length > 2 ? Boolean.parseBoolean(parts[2]) : true); } BidiMultiMap projection = new BidiMultiMap(names, conversions, types, checks); setProjectionModel(new ProjectionModel(mContext, uri, flavor, projection)); } String tableName = dbTableName(uri); uri = uri.buildUpon().query(null).fragment(null).build(); dbTable(uri, tableName); getContext().registerFlavor(flavor, database); setUri(uri); } public void save() { Uri uri = getUri(); String database = mContext.getDatabasePath(uri); if (notNullOrEmpty(tableName)) { uri = dbTable(uri, tableName); if (mProjectionModel != null) uri = projectionToUri(uri); } String uriString = uri != null ? Uri.decode(uri.toString()) : null; prefs.edit().putString("uri", uriString).putString("database", database).commit(); diag_println(DIAG_OFF, "saved uri, database", uriString, database); } public Uri projectionToUri(Uri uri) { Uri.Builder builder = uri.buildUpon().query(""); if (mProjectionModel.hasFlavor()) { builder .scheme(ContentResolver.SCHEME_CONTENT) .authority(mProjectionModel.getFlavor()) .path(dbTableName(uri)); } BidiMultiMap projection = mProjectionModel.getExpandedProjection(); ValList names = projection.getKeys(); ValList conversions = projection.getValues(1); ValList types = projection.getValues(2); ValList checks = projection.getValues(3); for (int i = 0; i < names.size(); i++) { builder.appendQueryParameter( stringValueOf(names.get(i)), join("|", objects( types.get(i), stringValueOf(conversions.get(i)), stringValueOf(checks.get(i)) ))); } uri = builder.build(); return uri; } // NOTE used in scripts public static String inquireUri(String uriString, boolean full) { DataConfiguration dc = new DataConfiguration(BerichtsheftActivity.getInstance(), Uri.parse(stringValueOf(uriString)), null); if (dc.display(null, full)) return stringValueOf(dc.getUri()); else return null; } public static boolean dataProperties(View view, Properties props) { Uri uri = Uri.parse(props.getProperty("uri", "")); DataConfiguration dc = new DataConfiguration(BerichtsheftActivity.getInstance(view), uri, null); if (dc.display(view, true)) { props.setProperty("uri", stringValueOf(dc.getUri())); return true; } return false; } /** * @param args */ public static void main(String...args) { BerichtsheftApp.loadSettings(); DataConfiguration dc = new DataConfiguration(BerichtsheftActivity.getInstance(), null, null); do { if (dc.display(null)) dc.save(); else break; ProjectionModel model = dc.getProjectionModel(); println("%s\n%s\n%s\n%s\n%s\n", dc.getUri(), dc.getPath(), dc.getTableName(), model, model.getFlavor()); } while (true); System.exit(0); } }