package com.bagri.tools.vvm.ui;
import static com.bagri.tools.vvm.util.Icons.COLLECTION_ICON;
import static com.bagri.tools.vvm.util.Icons.DOCUMENT_ICON;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.border.TitledBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import com.bagri.tools.vvm.event.ApplicationEvent;
import com.bagri.tools.vvm.event.EventBus;
import com.bagri.tools.vvm.model.Collection;
import com.bagri.tools.vvm.model.Document;
import com.bagri.tools.vvm.model.Schema;
import com.bagri.tools.vvm.service.DocumentManagementService;
import com.bagri.tools.vvm.service.SchemaManagementService;
import com.bagri.tools.vvm.service.ServiceException;
import com.bagri.tools.vvm.util.ErrorUtil;
public class SchemaDocumentPanel extends JPanel {
private static final Logger LOGGER = Logger.getLogger(SchemaDocumentPanel.class.getName());
private static final String all_docs = "All Documents";
private final DocumentManagementService docMgr;
private final EventBus<ApplicationEvent> eventBus;
private final Schema schema;
private JTree docTree;
private JPanel clnPanel = null;
private JPanel docPanel = null;
private JPanel clnInfoPanel;
private JPanel clnStatsPanel;
private JPanel docInfoPanel;
private JTextArea contentArea;
private JSplitPane mgrSplitter;
private String currentPath = null;
private List<Collection> collections = null;
public SchemaDocumentPanel(Schema schema, SchemaManagementService schemaService, EventBus<ApplicationEvent> eventBus) {
super(new BorderLayout());
this.schema = schema;
this.eventBus = eventBus;
this.docMgr = schemaService.getDocumentManagement(schema.getSchemaName());
JToolBar docToolbar = new JToolBar();
// "Add Document" button
JButton addDoc = new JButton("Add Document");
addDoc.setToolTipText("Register new document from disk...");
addDoc.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onAddDocument();
}
});
docToolbar.add(addDoc);
docToolbar.addSeparator();
// "Add Documents" button
JButton addDocs = new JButton("Add Documents");
addDocs.setToolTipText("Register bunch of documents from directory...");
addDocs.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onAddDocuments();
}
});
docToolbar.add(addDocs);
docToolbar.addSeparator();
// "Delete Document" button
JButton delDoc = new JButton("Delete Document");
delDoc.setToolTipText("Delete selected document");
delDoc.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onDeleteDocument();
}
});
docToolbar.add(delDoc);
docToolbar.addSeparator();
// "Add Collection" button
JButton addCol = new JButton("Add Collection");
addCol.setToolTipText("Register new documents Collection...");
addCol.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onAddCollection();
}
});
docToolbar.add(addCol);
docToolbar.addSeparator();
// "Delete Collection" button
JButton delCol = new JButton("Delete Collection");
delCol.setToolTipText("Delete selected Collection...");
delCol.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onDeleteCollection();
}
});
docToolbar.add(delCol);
docToolbar.addSeparator();
// "Delete Documents" button
JButton delDocs = new JButton("Delete Documents");
delDocs.setToolTipText("Delete documents for selected Collection...");
delDocs.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onDeleteDocuments();
}
});
docToolbar.add(delDocs);
docToolbar.addSeparator();
// "Add Document to Collections" button
JButton addDocClns = new JButton("Add Document to Collections");
addDocClns.setToolTipText("Add selected document to collections...");
addDocClns.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onAddDocumentToCollection();
}
});
docToolbar.add(addDocClns);
docToolbar.addSeparator();
// "Remove Document from Collections" button
JButton remDocClns = new JButton("Remove Document from Collections");
remDocClns.setToolTipText("Remove selected document from collections...");
remDocClns.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onRemoveDocumentFromCollection();
}
});
docToolbar.add(remDocClns);
docToolbar.addSeparator();
docToolbar.setFloatable(false);
add(docToolbar, BorderLayout.PAGE_START);
mgrSplitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
mgrSplitter.setDividerLocation(0.9);
mgrSplitter.setLeftComponent(getCollectionManagementPanel());
mgrSplitter.setRightComponent(createDocumentTreePanel());
add(mgrSplitter, BorderLayout.CENTER);
}
private JPanel createDocumentTreePanel() {
JPanel treePanel = new JPanel(new BorderLayout());
docTree = new JTree();
docTree.setCellRenderer(new DocTreeCellRenderer());
DefaultMutableTreeNode root = new DefaultMutableTreeNode(schema.getSchemaName());
try {
Collection allCln = docMgr.getCollection(all_docs);
DefaultMutableTreeNode all = new DefaultMutableTreeNode(allCln);
root.add(all);
// fill all docs tree...
fillCollectionDocuments(all, all_docs);
collections = docMgr.getCollections();
} catch (ServiceException ex) {
LOGGER.throwing(this.getClass().getName(), "createDocumentTreePanel", ex);
}
if (collections != null) {
Collections.sort(collections);
for (Collection collection: collections) {
DefaultMutableTreeNode cln = new DefaultMutableTreeNode(collection);
root.add(cln);
fillCollectionDocuments(cln, collection.getName());
}
}
docTree.setModel(new DefaultTreeModel(root, false));
docTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
docTree.setExpandsSelectedPaths(true);
docTree.setShowsRootHandles(true);
docTree.setRootVisible(false);
if (collections == null) {
docTree.expandRow(0);
}
docTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath().getLastPathComponent();
if (node == null) return;
int dividerLocation = mgrSplitter.getDividerLocation();
Object nodeInfo = node.getUserObject();
if (nodeInfo instanceof Document) {
String uri = ((Document) nodeInfo).getUri();
selectDocument(uri);
// splitPane.setRightComponent(getUserManagementView());
} else if (nodeInfo instanceof Collection) {
selectCollection((Collection) nodeInfo);
// splitPane.setRightComponent(getClusterManagementPanel());
}
mgrSplitter.setDividerLocation(dividerLocation);
}
});
treePanel.add(new JScrollPane(docTree));
treePanel.setPreferredSize(new Dimension(200, 500));
return treePanel;
}
private void handleServiceException(Exception ex) {
StringWriter sw = new StringWriter();
PrintWriter printWriter = new PrintWriter(sw);
ex.printStackTrace(printWriter);
contentArea.setText(sw.toString());
}
private JPanel getCollectionManagementPanel() {
if (clnPanel == null) {
clnPanel = new JPanel(new BorderLayout());
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
clnInfoPanel = new JPanel(new GridLayout(3, 3));
clnInfoPanel.add(new JLabel("name:"));
clnInfoPanel.add(new JLabel("id:"));
clnInfoPanel.add(new JLabel("version:"));
clnInfoPanel.add(new JLabel("description:"));
clnInfoPanel.add(new JLabel("document type:"));
clnInfoPanel.add(new JLabel("enabled:"));
clnInfoPanel.add(new JLabel("created at:"));
clnInfoPanel.add(new JLabel("created by:"));
clnInfoPanel.add(new JLabel(""));
clnInfoPanel.setPreferredSize(new Dimension(1000, 90));
clnInfoPanel.setMinimumSize(new Dimension(1000, 90));
clnInfoPanel.setBorder(BorderFactory.createTitledBorder("collection: "));
splitPane.setTopComponent(clnInfoPanel);
JPanel panel = new JPanel(new BorderLayout());
clnStatsPanel = new JPanel(new GridLayout(2, 3));
clnStatsPanel.add(new JLabel("documents:"));
clnStatsPanel.add(new JLabel("fragments:"));
clnStatsPanel.add(new JLabel("elements:"));
clnStatsPanel.add(new JLabel("full size in bytes:"));
clnStatsPanel.add(new JLabel("avg doc size in bytes:"));
clnStatsPanel.add(new JLabel("avg doc size in elements:"));
clnStatsPanel.setPreferredSize(new Dimension(1000, 70));
clnStatsPanel.setBorder(BorderFactory.createTitledBorder("statistics: "));
panel.add(clnStatsPanel, BorderLayout.NORTH);
splitPane.setBottomComponent(panel);
clnPanel.add(splitPane, BorderLayout.CENTER);
splitPane.setDividerLocation(0.2);
}
return clnPanel;
}
private void selectCollection(Collection cln) {
getCollectionManagementPanel();
//try {
((TitledBorder) clnInfoPanel.getBorder()).setTitle("collection: " + cln.getName());
Component[] labels = clnInfoPanel.getComponents();
((JLabel) labels[0]).setText("name: " + cln.getName());
((JLabel) labels[1]).setText("id: " + cln.getId());
((JLabel) labels[2]).setText("version: " + cln.getVersion());
((JLabel) labels[3]).setText("description: " + cln.getDescription());
((JLabel) labels[4]).setText("document type: " + cln.getDocType());
((JLabel) labels[5]).setText("enabled: " + cln.isEnabled());
((JLabel) labels[6]).setText("created at: " + cln.getCreatedAt());
((JLabel) labels[7]).setText("created by: " + cln.getCreatedBy());
clnInfoPanel.repaint();
((TitledBorder) clnStatsPanel.getBorder()).setTitle("statistics: " + cln.getName());
labels = clnStatsPanel.getComponents();
((JLabel) labels[0]).setText("documents: " + cln.getDocCount());
((JLabel) labels[1]).setText("fragments: " + cln.getFraCount());
((JLabel) labels[2]).setText("elements: " + cln.getEltCount());
((JLabel) labels[3]).setText("full size in bytes: " + cln.getByteSize());
((JLabel) labels[4]).setText("avg doc size in bytes: " + cln.getAvgByteSize());
((JLabel) labels[5]).setText("avg doc size in elements: " + cln.getAvgEltSize());
//} catch (ServiceException ex) {
// handleServiceException(ex);
//}
mgrSplitter.setLeftComponent(clnPanel);
}
private JPanel getDocumentManagementPanel() {
if (docPanel == null) {
docPanel = new JPanel(new BorderLayout());
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
docInfoPanel = new JPanel(new GridLayout(5, 3));
docInfoPanel.add(new JLabel("key:"));
//docInfoPanel.add(new JLabel("id:"));
docInfoPanel.add(new JLabel("version:"));
docInfoPanel.add(new JLabel("uri:"));
docInfoPanel.add(new JLabel("size:"));
docInfoPanel.add(new JLabel("encoding:"));
docInfoPanel.add(new JLabel("created at:"));
docInfoPanel.add(new JLabel("created by:"));
docInfoPanel.add(new JLabel("start tx:"));
docInfoPanel.add(new JLabel("elements:"));
docInfoPanel.add(new JLabel("fragments:"));
docInfoPanel.add(new JLabel("collections:"));
docInfoPanel.add(new JLabel("partition:"));
docInfoPanel.add(new JLabel("owner:"));
docInfoPanel.setPreferredSize(new Dimension(1000, 120));
docInfoPanel.setMinimumSize(new Dimension(1000, 120));
docInfoPanel.setBorder(BorderFactory.createTitledBorder("document: "));
splitPane.setTopComponent(docInfoPanel);
contentArea = new JTextArea();
contentArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane areaScrollPane = new JScrollPane(contentArea);
areaScrollPane.setPreferredSize(new Dimension(1000, 500));
areaScrollPane.setMinimumSize(new Dimension(1000, 500));
contentArea.setEditable(false);
contentArea.setCaretPosition(0);
splitPane.setBottomComponent(areaScrollPane);
docPanel.add(splitPane, BorderLayout.CENTER);
splitPane.setDividerLocation(0.2);
}
return docPanel;
}
private int fillCollectionDocuments(DefaultMutableTreeNode clNode, String clName) {
try {
List<Document> documents = docMgr.getDocuments(clName);
Collections.sort(documents);
int cnt = clNode.getChildCount();
for (Document document: documents) {
DefaultMutableTreeNode doc = new DefaultMutableTreeNode(document);
clNode.add(doc);
}
cnt = clNode.getChildCount() - cnt;
//LOGGER.info("fillCollectionDocuments; added: " + cnt + "; returning: " + documents.size());
return documents.size();
} catch (Exception ex) {
LOGGER.throwing(this.getClass().getName(), "fillCollectionDocuments", ex);
}
return 0;
}
private void selectDocument(String uri) {
getDocumentManagementPanel();
try {
Map<String, Object> doc = docMgr.getDocumentInfo(uri);
((TitledBorder) docInfoPanel.getBorder()).setTitle("document: " + doc.get("uri"));
Component[] labels = docInfoPanel.getComponents();
((JLabel) labels[0]).setText("key: " + doc.get("key"));
//((JLabel) labels[1]).setText("id: " + doc.get("id"));
((JLabel) labels[1]).setText("version: " + doc.get("version"));
((JLabel) labels[2]).setText("uri: " + doc.get("uri"));
((JLabel) labels[3]).setText("size: " + doc.get("bytes"));
((JLabel) labels[4]).setText("encoding: " + doc.get("encoding"));
((JLabel) labels[5]).setText("created at: " + doc.get("created at"));
((JLabel) labels[6]).setText("created by: " + doc.get("created by"));
((JLabel) labels[7]).setText("start tx: " + doc.get("txStart"));
((JLabel) labels[8]).setText("elements: " + doc.get("elements"));
((JLabel) labels[9]).setText("fragments: " + doc.get("fragments"));
((JLabel) labels[10]).setText("collections: " + doc.get("collections"));
((JLabel) labels[11]).setText("partition: " + doc.get("partition"));
((JLabel) labels[12]).setText("owner: " + doc.get("owner"));
docInfoPanel.repaint();
String content = docMgr.getDocumentContent(uri);
contentArea.setText(content);
contentArea.setCaretPosition(0);
} catch (ServiceException ex) {
handleServiceException(ex);
}
mgrSplitter.setLeftComponent(docPanel);
}
private DefaultMutableTreeNode getCollectionNode(String collection) {
Object root = docTree.getModel().getRoot();
int cnt = docTree.getModel().getChildCount(root);
for (int i=0; i < cnt; i++) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) docTree.getModel().getChild(root, i);
if (collection.equals(((Collection) node.getUserObject()).getName())) {
return node;
}
}
return null;
}
private void refreshCollection(DefaultMutableTreeNode clnNode, String collection) {
try {
Collection cln = docMgr.getCollection(collection);
if (cln != null) {
clnNode.setUserObject(cln);
((DefaultTreeModel) docTree.getModel()).reload(clnNode);
}
} catch (ServiceException ex) {
ErrorUtil.showError(this.getParent(), ex);
}
}
private void insertDocument(Document doc, String collection) {
DefaultMutableTreeNode parent = getCollectionNode(collection);
if (parent != null) {
int idx = 0;
DefaultMutableTreeNode node = null;
Enumeration en = parent.children();
while (en.hasMoreElements()) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) en.nextElement();
Document exDoc = (Document) child.getUserObject();
int cmp = doc.compareTo(exDoc);
if (cmp < 0) {
break;
} else if (cmp == 0) {
node = child;
break;
}
idx++;
}
if (node == null) {
node = new DefaultMutableTreeNode(doc);
((DefaultTreeModel) docTree.getModel()).insertNodeInto(node, parent, idx);
refreshCollection(parent, collection);
} else {
node.setUserObject(doc);
}
docTree.setSelectionPaths(new TreePath[] {new TreePath(node.getPath())});
} else {
LOGGER.info("insertDocument; no node found for collection: " + collection);
}
}
private void insertDocument(Document doc, java.util.Collection<String> collections) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
if (collections != null) {
for (String collection: collections) {
insertDocument(doc, collection);
}
}
insertDocument(doc, all_docs);
} finally {
setCursor(Cursor.getDefaultCursor());
}
}
private void refreshDocuments(String collection) {
DefaultMutableTreeNode parent = getCollectionNode(collection);
if (parent != null) {
parent.removeAllChildren();
fillCollectionDocuments(parent, collection);
refreshCollection(parent, collection);
} else {
LOGGER.info("refreshDocuments; no node found for collection: " + collection);
}
}
private void refreshDocuments(java.util.Collection<String> collections) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
if (collections != null) {
for (String collection: collections) {
refreshDocuments(collection);
}
}
refreshDocuments(all_docs);
} finally {
setCursor(Cursor.getDefaultCursor());
}
}
private void removeSelectedDocument() {
DefaultMutableTreeNode nextNode;
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) docTree.getLastSelectedPathComponent();
if (selectedNode.getNextSibling() != null) {
nextNode = selectedNode.getNextSibling();
} else if (selectedNode.getPreviousSibling() != null) {
nextNode = selectedNode.getPreviousSibling();
} else {
nextNode = (DefaultMutableTreeNode) selectedNode.getParent();
}
((DefaultTreeModel) docTree.getModel()).removeNodeFromParent(selectedNode);
docTree.setSelectionPaths(new TreePath[] {new TreePath(nextNode.getPath())});
}
private List<String> getCollectionNames() {
List<String> names = new ArrayList<>(collections.size());
for (Collection cln: collections) {
names.add(cln.getName());
}
return names;
}
// --- Event Handlers --- //
private void onAddDocument() {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Select File");
String docType = schema.getDataFormat();
FileNameExtensionFilter filter = new FileNameExtensionFilter(docType + " Documents", docType.toLowerCase());
chooser.setFileFilter(filter);
if (currentPath != null) {
chooser.setCurrentDirectory(new File(currentPath));
}
CollectionPanel cp = null;
if (collections != null) {
cp = new CollectionPanel(getCollectionNames());
chooser.setAccessory(cp);
}
int returnVal = chooser.showOpenDialog(this.getParent());
if (returnVal == JFileChooser.APPROVE_OPTION) {
currentPath = chooser.getCurrentDirectory().getAbsolutePath();
java.util.Collection<String> clns = null;
if (cp != null) {
clns = cp.getSelectedCollections();
}
try {
Document doc = docMgr.storeDocument(chooser.getSelectedFile().getAbsolutePath(), clns);
insertDocument(doc, clns);
} catch (ServiceException ex) {
ErrorUtil.showError(this.getParent(), ex);
}
}
}
private void onAddDocuments() {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Select Directory");
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (currentPath != null) {
chooser.setCurrentDirectory(new File(currentPath));
}
CollectionPanel cp = null;
if (collections != null) {
cp = new CollectionPanel(getCollectionNames());
chooser.setAccessory(cp);
}
int returnVal = chooser.showOpenDialog(this.getParent());
if (returnVal == JFileChooser.APPROVE_OPTION) {
currentPath = chooser.getCurrentDirectory().getAbsolutePath();
java.util.Collection<String> clns = null;
if (cp != null) {
clns = cp.getSelectedCollections();
}
try {
if (docMgr.storeDocuments(chooser.getSelectedFile().getAbsolutePath(), clns)) {
refreshDocuments(clns);
}
} catch (Exception ex) {
ErrorUtil.showError(this.getParent(), ex);
}
}
}
private void onDeleteDocument() {
if (docTree.getSelectionPath() != null) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) docTree.getSelectionPath().getLastPathComponent();
Document doc = (Document) node.getUserObject();
try {
docMgr.deleteDocument(doc.getUri());
// TODO: delete it from all collections!
removeSelectedDocument();
} catch (ServiceException ex) {
ErrorUtil.showError(this.getParent(), ex);
}
}
}
private void onAddCollection() {
//
}
private void onDeleteCollection() {
//
}
private void onDeleteDocuments() {
//
}
private void onAddDocumentToCollection() {
//
}
private void onRemoveDocumentFromCollection() {
//
}
private class DocTreeCellRenderer extends DefaultTreeCellRenderer {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
ImageIcon icon = getTreeIcon(value);
if (null != icon) {
setIcon(icon);
}
return this;
}
private ImageIcon getTreeIcon(Object value) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
Object valueObject = treeNode.getUserObject();
if (valueObject instanceof Collection) {
return COLLECTION_ICON;
}
if (valueObject instanceof Document) {
return DOCUMENT_ICON;
}
return null;
}
}
}