package com.bagri.tools.vvm.ui;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import java.util.logging.Logger;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultEditorKit;
import javax.xml.transform.OutputKeys;
import com.bagri.tools.vvm.event.ApplicationEvent;
import com.bagri.tools.vvm.event.EventBus;
import com.bagri.tools.vvm.model.Schema;
import com.bagri.tools.vvm.model.TypedValue;
import com.bagri.tools.vvm.service.SchemaManagementService;
import com.bagri.tools.vvm.service.ServiceException;
import com.bagri.tools.vvm.util.FileUtil;
public class SchemaQueryPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(SchemaQueryPanel.class.getName());
private final SchemaManagementService schemaService;
private final EventBus<ApplicationEvent> eventBus;
private final Schema schema;
//private JToolBar toolBar;
private JTextArea queryText;
private JTextArea queryResult;
private JRadioButton bXDM;
private JButton runQuery;
private JButton cancelQuery;
private JButton queryProps;
private JButton clearResults;
private JLabel lbTime;
private Properties properties;
private Map<String, TypedValue> bindings = new HashMap<>();
private long parseTime;
private Thread qRunner;
public SchemaQueryPanel(Schema schema, SchemaManagementService schemaService, EventBus<ApplicationEvent> eventBus) {
super(new BorderLayout());
this.schema = schema;
this.schemaService = schemaService;
this.eventBus = eventBus;
JToolBar queryToolbar = new JToolBar();
// "Query type" switch
ButtonGroup queryGroup = new ButtonGroup();
bXDM = new JRadioButton("XDM");
bXDM.setSelected(true);
JRadioButton bXQJ = new JRadioButton("XQJ");
queryGroup.add(bXDM);
queryGroup.add(bXQJ);
queryToolbar.add(bXDM);
queryToolbar.add(bXQJ);
queryToolbar.addSeparator();
// "Run Query" button
runQuery = new JButton("Run Query");
runQuery.setToolTipText("Bind params, execute query...");
runQuery.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onRunQuery();
}
});
queryToolbar.add(runQuery);
queryToolbar.addSeparator();
// "Query Properties" button
queryProps = new JButton("Query Properties");
queryProps.setToolTipText("Set query processing properties");
queryProps.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onQueryProperties();
}
});
queryToolbar.add(queryProps);
queryToolbar.addSeparator();
// "Clear Results" button
clearResults = new JButton("Clear Results");
clearResults.setToolTipText("Clear results panel");
clearResults.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
queryResult.setText(null);
}
});
queryToolbar.add(clearResults);
queryToolbar.addSeparator();
// "Cancel Query" button
cancelQuery = new JButton("Cancel Query");
cancelQuery.setToolTipText("Cancel currently running query");
cancelQuery.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onCancelQuery();
}
});
cancelQuery.setEnabled(false);
queryToolbar.add(cancelQuery);
queryToolbar.addSeparator();
lbTime = new JLabel();
lbTime.setVisible(false);
queryToolbar.add(lbTime);
//queryToolbar.addSeparator();
queryToolbar.setFloatable(false);
add(queryToolbar, BorderLayout.PAGE_START);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setDividerLocation(200);
splitPane.setTopComponent(createQueryEditorPanel());
splitPane.setBottomComponent(createQueryResultsPanel());
add(splitPane, BorderLayout.CENTER);
try {
properties = schemaService.getQueryProperties(schema.getSchemaName());
} catch (ServiceException ex) {
properties = new Properties();
properties.setProperty("bdb.client.fetchSize", "1000");
properties.setProperty("xqj.schema.queryTimeout", "0");
}
String prop = properties.getProperty(OutputKeys.INDENT);
if (prop == null) {
properties.setProperty(OutputKeys.INDENT, "yes");
}
prop = properties.getProperty(OutputKeys.METHOD);
if (prop == null) {
properties.setProperty(OutputKeys.METHOD, "xml");
}
prop = properties.getProperty(OutputKeys.OMIT_XML_DECLARATION);
if (prop == null) {
properties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
}
}
private JScrollPane createQueryEditorPanel() {
//Create a text area.
queryText = new JTextArea();
queryText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
queryText.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if ( SwingUtilities.isRightMouseButton ( e ) ) {
// TODO: add Icons
// TODO: display "Cut" and "Copy" as grayed text, if text is not selected
JPopupMenu menu = new JPopupMenu ();
JMenuItem menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
menuItem.setText("Cut");
menuItem.setMnemonic(KeyEvent.VK_T);
menu.add(menuItem);
menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
menuItem.setText("Copy");
menuItem.setMnemonic(KeyEvent.VK_C);
menu.add(menuItem);
// TODO: display "paste" as grayed text if clipboard is empty.
menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
menuItem.setText("Paste");
menuItem.setMnemonic(KeyEvent.VK_P);
menu.add(menuItem);
menu.show(queryText, e.getX(), e.getY());
}
}
});
JScrollPane areaScrollPane = new JScrollPane(queryText);
areaScrollPane.setPreferredSize(new Dimension(500, 150));
areaScrollPane.setMinimumSize(new Dimension(500, 150));
queryText.setCaretPosition(0);
return areaScrollPane;
}
private JScrollPane createQueryResultsPanel() {
//Create a text area.
queryResult = new JTextArea();
queryResult.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane areaScrollPane = new JScrollPane(queryResult);
areaScrollPane.setPreferredSize(new Dimension(500, 150));
areaScrollPane.setMinimumSize(new Dimension(500, 150));
queryResult.setEditable(false);
queryResult.setCaretPosition(0);
return areaScrollPane;
}
// --- Event Handlers --- //
private void onRunQuery() {
final String qry = queryText.getText();
if (qry != null && qry.trim().length() > 0) {
lbTime.setVisible(false);
long stamp = System.currentTimeMillis();
try {
java.util.List<String> vars = schemaService.parseQuery(schema.getSchemaName(), qry, properties);
parseTime = System.currentTimeMillis() - stamp;
if (vars.size() > 0) {
final BindQueryVarsDialog dlg = new BindQueryVarsDialog(vars, bindings, SchemaQueryPanel.this);
dlg.setSuccessListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Map<String, TypedValue> typedValues = dlg.getBindings();
runQuery(typedValues);
storeBindings(typedValues);
}
});
}
});
dlg.setVisible(true);
} else {
runQuery(null);
}
} catch (ServiceException ex) {
handleServiceException(ex);
}
}
}
private void runQuery(Map<String, TypedValue> values) {
String query = queryText.getText();
queryResult.setText(null);
runQuery.setEnabled(false);
queryProps.setEnabled(false);
clearResults.setEnabled(false);
cancelQuery.setEnabled(true);
//setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
Map<String, Object> params = null;
if (values != null) {
params = convertBindings(values);
}
qRunner = new QueryRunner(query, bXDM.isSelected(), params, properties);
//SwingUtilities.invokeLater(qRunner);
qRunner.start();
} catch (Exception ex) {
onDoneQuery(ex, 0);
}
}
private void handleServiceException(Exception ex) {
StringWriter sw = new StringWriter();
PrintWriter printWriter = new PrintWriter(sw);
ex.printStackTrace(printWriter);
queryResult.setText(sw.toString());
}
private Map<String, Object> convertBindings(Map<String, TypedValue> typedValues) throws IOException {
Map<String, Object> result = new HashMap<>(typedValues.size());
for (Map.Entry<String, TypedValue> e: typedValues.entrySet()) {
if ("file".equals(e.getValue().getType())) {
String text = FileUtil.readTextFile(e.getValue().getValue().toString());
result.put(e.getKey(), text);
} else {
result.put(e.getKey(), e.getValue().getValue());
}
}
return result;
}
private void storeBindings(Map<String, TypedValue> typedValues) {
bindings.putAll(typedValues);
}
private void onQueryProperties() {
//
final EditPropertiesDialog dlg = new EditPropertiesDialog(properties, SchemaQueryPanel.this);
dlg.setSuccessListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
properties.clear();
properties.putAll(dlg.getProperties());
}
});
}
});
dlg.setVisible(true);
}
private void onCancelQuery() {
// implement it...
LOGGER.info("cancelling query...");
try {
schemaService.cancelQuery(schema.getSchemaName());
//qRunner.interrupt();
//cancelQuery.setEnabled(false);
} catch (Exception ex) {
handleServiceException(ex);
}
}
private void onDoneQuery(Object result, long runTime) {
runQuery.setEnabled(true);
queryProps.setEnabled(true);
clearResults.setEnabled(true);
cancelQuery.setEnabled(false);
//setCursor(Cursor.getDefaultCursor());
if (result instanceof Exception) {
handleServiceException((Exception) result);
} else {
queryResult.setText((result == null) ? "Null" : result.toString());
lbTime.setText("Parse time: " + parseTime + " ms; Query time: " + runTime + " ms");
lbTime.setVisible(true);
}
}
private /*static*/ class QueryRunner extends Thread {
private String query;
private boolean useXDM = false;
private Map<String, Object> params;
private Properties props;
QueryRunner(String query, boolean useXDM, Map<String, Object> params, Properties props) {
this.query = query;
this.useXDM = useXDM;
this.params = params;
this.props = props;
}
public void run() {
Object result;
long runTime = System.currentTimeMillis();
try {
result = schemaService.runQuery(schema.getSchemaName(), useXDM, query, params, props);
onDoneQuery(result, System.currentTimeMillis() - runTime);
} catch (Exception ex) {
onDoneQuery(ex, 0);
}
}
}
}