/*
* mongobrowser - a webstart gui application for viewing,
* editing and administering a Mongo Database
* Copyright 2009-2011 MeBigFatGuy.com
* Copyright 2009-2011 Dave Brosius
*
* Licensed 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 com.mebigfatguy.mongobrowser.dialogs;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Set;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreePath;
import com.mebigfatguy.mongobrowser.MongoConstants;
import com.mebigfatguy.mongobrowser.MongoContext;
import com.mebigfatguy.mongobrowser.TreeUtils;
import com.mebigfatguy.mongobrowser.actions.DeleteAction;
import com.mebigfatguy.mongobrowser.actions.EditKeyValueAction;
import com.mebigfatguy.mongobrowser.actions.ManageIndicesAction;
import com.mebigfatguy.mongobrowser.actions.NewCollectionAction;
import com.mebigfatguy.mongobrowser.actions.NewKeyValueAction;
import com.mebigfatguy.mongobrowser.actions.NewObjectAction;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
/**
* the panel that holds the tree of mongo database objects
*/
public class MongoDataPanel extends JPanel implements MongoPanel {
private static final long serialVersionUID = 1579613544693305078L;
private final MongoContext context;
private JTree tree;
private JMenuItem manageIndicesItem;
private JMenuItem newCollectionItem;
private JMenuItem newObjectItem;
private JMenuItem newKeyValueItem;
private JMenuItem editKeyValueItem;
private JMenuItem deleteItem;
/**
* constructs the panel
*
* @param ctxt
* the mediator object
*/
public MongoDataPanel(MongoContext ctxt) {
context = ctxt;
initComponents();
initListeners();
}
/**
* sets up the panel when a database is connected to
*/
@Override
public void init() {
DB db = context.getDatabase();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
MongoTreeNode root = (MongoTreeNode) model.getRoot();
if (db != null) {
Set<String> collectionNames = db.getCollectionNames();
for (String collectionName : collectionNames) {
DBCollection collection = db.getCollection(collectionName);
boolean readOnly = collectionName.startsWith(MongoConstants.SYSTEM_PREFIX);
MongoTreeNode col = new MongoTreeNode(collection, readOnly);
root.add(col);
MongoTreeNode slug = new MongoTreeNode();
col.add(slug);
}
} else {
root.removeAllChildren();
}
model.nodeStructureChanged(root);
context.setSelectedNodes();
}
/**
* cleans up a panel when a database is disconnected from
*/
@Override
public void term() {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
MongoTreeNode root = (MongoTreeNode) model.getRoot();
root.removeAllChildren();
model.nodeStructureChanged(root);
context.setSelectedNodes();
}
/**
* creates and lays out the components in this panel
*/
private void initComponents() {
setLayout(new BorderLayout(4, 4));
MongoTreeNode root = new MongoTreeNode(new MongoTreeNode.Root());
tree = new JTree(root);
tree.setRootVisible(false);
tree.setShowsRootHandles(true);
tree.setCellRenderer(new MongoTreeCellRenderer());
add(new JScrollPane(tree), BorderLayout.CENTER);
context.setTree(tree);
newCollectionItem = new JMenuItem(new NewCollectionAction(context));
manageIndicesItem = new JMenuItem(new ManageIndicesAction(context));
newObjectItem = new JMenuItem(new NewObjectAction(context));
newKeyValueItem = new JMenuItem(new NewKeyValueAction(context));
editKeyValueItem = new JMenuItem(new EditKeyValueAction(context));
deleteItem = new JMenuItem(new DeleteAction(context));
}
/**
* installs the event listeners for the components on this panel
*/
private void initListeners() {
final JPopupMenu menu = new JPopupMenu();
tree.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
showPopup(e);
}
@Override
public void mousePressed(MouseEvent e) {
showPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
showPopup(e);
}
private void showPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
int x = e.getX();
int y = e.getY();
menu.removeAll();
TreePath path = tree.getPathForLocation(x, y);
if (path == null) {
menu.add(newCollectionItem);
menu.show(tree, x, y);
} else {
MongoTreeNode node = (MongoTreeNode) path.getLastPathComponent();
context.setSelectedNodes(node);
if (node.getType() == MongoTreeNode.Type.Collection) {
if (!node.isReadOnly()) {
menu.add(manageIndicesItem);
menu.add(newObjectItem);
menu.show(tree, x, y);
}
} else if (node.getType() == MongoTreeNode.Type.Object) {
if (!node.isReadOnly()) {
menu.add(newKeyValueItem);
menu.addSeparator();
menu.add(deleteItem);
menu.show(tree, x, y);
}
} else if (node.getType() == MongoTreeNode.Type.KeyValue) {
if (!node.isReadOnly()) {
MongoTreeNode.KV kv = (MongoTreeNode.KV) node.getUserObject();
Object value = kv.getValue();
boolean needsSeparator = false;
if (value instanceof DBObject) {
menu.add(newKeyValueItem);
needsSeparator = true;
} else {
menu.add(editKeyValueItem);
needsSeparator = true;
}
if (!kv.getKey().startsWith("_")) {
if (needsSeparator) {
menu.addSeparator();
}
menu.add(deleteItem);
menu.show(tree, x, y);
}
}
}
}
}
}
});
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
@Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
MongoTreeNode node = (MongoTreeNode) event.getPath().getLastPathComponent();
MongoTreeNode slug = (MongoTreeNode) node.getFirstChild();
if (slug.getType() == MongoTreeNode.Type.ExpansionSlug) {
node.removeAllChildren();
switch (node.getType()) {
case Collection: {
DBCollection collection = (DBCollection) node.getUserObject();
DBCursor cursor = collection.find();
while (cursor.hasNext()) {
DBObject obj = cursor.next();
MongoTreeNode objNode = new MongoTreeNode(obj, node.isReadOnly());
node.add(objNode);
slug = new MongoTreeNode();
objNode.add(slug);
}
}
break;
case Object: {
DBObject object = (DBObject) node.getUserObject();
for (String key : object.keySet()) {
Object value = object.get(key);
MongoTreeNode kv = new MongoTreeNode(new MongoTreeNode.KV(key, value), node
.isReadOnly());
node.add(kv);
if (value instanceof DBObject) {
slug = new MongoTreeNode();
kv.add(slug);
}
}
}
break;
case KeyValue: {
MongoTreeNode.KV topKV = (MongoTreeNode.KV) node.getUserObject();
DBObject object = (DBObject) topKV.getValue();
for (String key : object.keySet()) {
Object value = object.get(key);
MongoTreeNode kv = new MongoTreeNode(new MongoTreeNode.KV(key, value), node
.isReadOnly());
node.add(kv);
if (value instanceof DBObject) {
slug = new MongoTreeNode();
kv.add(slug);
}
}
}
break;
}
}
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.nodeStructureChanged(node);
}
@Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
MongoTreeNode node = (MongoTreeNode) event.getPath().getLastPathComponent();
node.removeAllChildren();
MongoTreeNode slug = new MongoTreeNode();
node.add(slug);
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.nodeStructureChanged(node);
}
});
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent tse) {
MongoTreeNode[] nodes = TreeUtils.getSelectedNodes((JTree) tse.getSource());
if (nodes.length > 0) {
context.setSelectedNodes(nodes);
} else {
context.setSelectedNodes();
}
}
});
}
}