/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.chemistry.opencmis.workbench;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.AbstractTableModel;
import javax.swing.text.NumberFormatter;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.workbench.model.ClientModel;
public class QueryFrame extends JFrame {
private static final long serialVersionUID = 1L;
private static final String WINDOW_TITLE = "CMIS Query";
private static final String DEFAULT_QUERY = "SELECT * FROM cmis:document";
private ClientModel model;
private JTextArea queryText;
private JFormattedTextField maxHitsField;
private JCheckBox searchAllVersionsCheckBox;
private JTable resultsTable;
private JLabel queryTimeLabel;
public QueryFrame(ClientModel model) {
super();
this.model = model;
createGUI();
}
private void createGUI() {
setTitle(WINDOW_TITLE + " - " + model.getRepositoryName());
setPreferredSize(new Dimension(800, 700));
setMinimumSize(new Dimension(200, 60));
setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
// input
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.LINE_AXIS));
queryText = new JTextArea(DEFAULT_QUERY, 5, 60);
inputPanel.add(queryText);
JPanel inputPanel2 = new JPanel();
inputPanel2.setPreferredSize(new Dimension(160, 100));
inputPanel2.setMaximumSize(inputPanel.getPreferredSize());
inputPanel2.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
JButton queryButton = new JButton("Query");
queryButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doQuery();
}
});
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 2;
inputPanel2.add(queryButton, c);
maxHitsField = new JFormattedTextField(new NumberFormatter());
maxHitsField.setValue(Integer.valueOf(100));
maxHitsField.setColumns(5);
JLabel maxHitsLabel = new JLabel("Max hits:");
maxHitsLabel.setLabelFor(maxHitsField);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
inputPanel2.add(maxHitsLabel, c);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
inputPanel2.add(maxHitsField, c);
searchAllVersionsCheckBox = new JCheckBox("search all versions", false);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 2;
inputPanel2.add(searchAllVersionsCheckBox, c);
queryTimeLabel = new JLabel("(-- hits in -- seconds)");
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 2;
inputPanel2.add(queryTimeLabel, c);
inputPanel.add(inputPanel2);
// table
resultsTable = new JTable();
resultsTable.setFillsViewportHeight(true);
resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final JPopupMenu popup = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Copy to clipboard");
popup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
int rows = resultsTable.getModel().getColumnCount();
for (int row = 0; row < rows; row++) {
int cols = resultsTable.getModel().getColumnCount();
for (int col = 0; col < cols; col++) {
sb.append(resultsTable.getModel().getValueAt(row, col));
sb.append("|");
}
sb.append("\n");
}
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable transferable = new StringSelection(sb.toString());
clipboard.setContents(transferable, null);
}
});
resultsTable.addMouseListener(new MouseListener() {
public void mouseExited(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
});
add(new JSplitPane(JSplitPane.VERTICAL_SPLIT, inputPanel, new JScrollPane(resultsTable)));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private synchronized void doQuery() {
String text = queryText.getText();
text = text.replace('\n', ' ');
ItemIterable<QueryResult> results = null;
try {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
int maxHits = 1000;
try {
maxHitsField.commitEdit();
maxHits = ((Number) maxHitsField.getValue()).intValue();
} catch (Exception e) {
}
results = model.query(text, searchAllVersionsCheckBox.isSelected(), maxHits);
ResultTableModel rtm = new ResultTableModel();
long startTime = System.currentTimeMillis();
int row = 0;
for (QueryResult qr : results.getPage(maxHits)) {
rtm.setColumnCount(Math.max(rtm.getColumnCount(), qr.getProperties().size()));
for (PropertyData<?> prop : qr.getProperties()) {
rtm.setValue(row, prop.getQueryName(), prop.getFirstValue());
}
row++;
}
rtm.setRowCount(row);
long stopTime = System.currentTimeMillis();
float time = ((float) (stopTime - startTime)) / 1000f;
queryTimeLabel.setText("(" + row + " hits in " + time + " seconds)");
resultsTable.setModel(rtm);
} catch (Exception ex) {
ClientHelper.showError(null, ex);
return;
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
static class ResultTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private int columnCount = 0;
private int rowCount = 0;
private Map<String, Integer> columnMapping = new HashMap<String, Integer>();
private Map<Integer, Map<Integer, Object>> data = new HashMap<Integer, Map<Integer, Object>>();
private Map<Integer, Class<?>> columnClass = new HashMap<Integer, Class<?>>();
public ResultTableModel() {
}
public void setColumnCount(int columnCount) {
this.columnCount = columnCount;
}
public int getColumnCount() {
return columnCount;
}
public void setRowCount(int rowCount) {
this.rowCount = rowCount;
}
public int getRowCount() {
return rowCount;
}
public void setValue(int rowIndex, String queryName, Object value) {
Integer col = columnMapping.get(queryName);
if (col == null) {
col = columnMapping.size();
columnMapping.put(queryName, columnMapping.size());
}
if (value == null) {
return;
}
if (value instanceof GregorianCalendar) {
value = ClientHelper.getDateString((GregorianCalendar) value);
}
columnClass.put(col, value.getClass());
Map<Integer, Object> row = data.get(rowIndex);
if (row == null) {
row = new HashMap<Integer, Object>();
data.put(rowIndex, row);
}
row.put(col, value);
}
public Object getValueAt(int rowIndex, int columnIndex) {
Map<Integer, Object> row = data.get(rowIndex);
if (row == null) {
return null;
}
return row.get(columnIndex);
}
@Override
public String getColumnName(int column) {
for (Map.Entry<String, Integer> e : columnMapping.entrySet()) {
if (e.getValue().equals(column)) {
return e.getKey();
}
}
return "?";
}
@Override
public Class<?> getColumnClass(int columnIndex) {
Class<?> clazz = columnClass.get(columnIndex);
if (clazz != null) {
return clazz;
}
return String.class;
}
}
}