package com.delcyon.capo.webapp.widgets; import com.delcyon.capo.resourcemanager.ResourceDescriptor; import com.delcyon.capo.resourcemanager.ResourceDescriptor.Action; import com.delcyon.capo.resourcemanager.ResourceDescriptor.State; import com.delcyon.capo.resourcemanager.types.ContentMetaData; import com.delcyon.capo.resourcemanager.types.JcrResourceDescriptor; import com.delcyon.capo.webapp.models.DomItemModel.DomUse; import com.delcyon.capo.webapp.models.ResourceDescriptorItemModel; import eu.webtoolkit.jwt.SelectionBehavior; import eu.webtoolkit.jwt.SelectionMode; import eu.webtoolkit.jwt.Signal; import eu.webtoolkit.jwt.Signal1; import eu.webtoolkit.jwt.Signal2; import eu.webtoolkit.jwt.WDialog; import eu.webtoolkit.jwt.WLabel; import eu.webtoolkit.jwt.WLength; import eu.webtoolkit.jwt.WLineEdit; import eu.webtoolkit.jwt.WModelIndex; import eu.webtoolkit.jwt.WMouseEvent; import eu.webtoolkit.jwt.WPopupMenu; import eu.webtoolkit.jwt.WPushButton; import eu.webtoolkit.jwt.WRegExpValidator; import eu.webtoolkit.jwt.WValidator; /** * This class lets a user navigate a tree of resource descriptors, as well as provide a few node editing methods * @author jeremiah * */ public class WCapoResourceTreeView extends CapoWTreeView { private ResourceDescriptor rootResourceDescriptor = null; private WPopupMenu treeViewRightClickMenu; private WDialog createNodeDialog; public WCapoResourceTreeView() { //basic setup setLayoutSizeAware(true); setColumnResizeEnabled(false); setWidth(new WLength(250)); setSelectionMode(SelectionMode.SingleSelection); setSelectionBehavior(SelectionBehavior.SelectItems); setSelectable(true); setAlternatingRowColors(true); //setup Right click Menu setRightClickAware(true); rightClicked().addListener(this, new Signal2.Listener<WModelIndex, WMouseEvent>() { @Override public void trigger(WModelIndex arg1, WMouseEvent arg2) { getTreeViewRightClickMenu().popup(arg2);; } }); } /** * * Convenience method to set the model appropriately */ public void setRootResourceDescriptor(ResourceDescriptor rootResourceDescriptor) { this.rootResourceDescriptor = rootResourceDescriptor; setModel(new ResourceDescriptorItemModel(rootResourceDescriptor,DomUse.NAVIGATION)); } /** * * @return the ResourceDescriptor set with setRootResourceDescriptor */ public ResourceDescriptor getRootResourceDescriptor() { return rootResourceDescriptor; } /** * Generate the views right click menu * @return */ private WPopupMenu getTreeViewRightClickMenu() { if(treeViewRightClickMenu == null) { treeViewRightClickMenu = new WPopupMenu(); //setup create node method treeViewRightClickMenu.addItem("Create Node...").clicked().addListener(this, new Signal.Listener() { public void trigger() { getCreateNodeDialog().show(); }; }); //setup delete method treeViewRightClickMenu.addItem("Delete").clicked().addListener(this, new Signal.Listener() { @Override public void trigger() { deleteNode(); } }); //TODO we still need a rename, and a move method there } return this.treeViewRightClickMenu; } /** * Creates or returns the node creation dialog * @return */ private WDialog getCreateNodeDialog() { if(createNodeDialog == null) { createNodeDialog = new WDialog("Create Node"); createNodeDialog.setClosable(true); createNodeDialog.rejectWhenEscapePressed(true); createNodeDialog.rejectWhenEscapePressed(); WLabel label = new WLabel("Enter a node name", createNodeDialog.getContents()); final WLineEdit nodeNameLineEdit = new WLineEdit(createNodeDialog.getContents()); label.setBuddy(nodeNameLineEdit); WRegExpValidator nodeNameValidator = new WRegExpValidator("[A-Za-z1-9 \\.]+"); nodeNameValidator.setMandatory(true); final WPushButton okPushButton = new WPushButton("OK", createNodeDialog.getFooter()); okPushButton.setDefault(true); okPushButton.disable(); //watch the nodeNameLineEdit and only enable the ok button when the entered text is valid nodeNameLineEdit.keyWentUp().addListener(this, new Signal.Listener() { public void trigger() { okPushButton.setDisabled(nodeNameLineEdit.validate() != WValidator.State.Valid); } }); okPushButton.clicked().addListener(this, new Signal.Listener() { public void trigger() { //make sure we got validated if (nodeNameLineEdit.validate() != null) { //fire the acceptance signal createNodeDialog.accept(); //send off to have the node created createNode(nodeNameLineEdit.getText()); //clear out text out for the next use nodeNameLineEdit.setText(""); } } }); WPushButton cancelPushButton = new WPushButton("Cancel", createNodeDialog.getFooter()); cancelPushButton.clicked().addListener(createNodeDialog,new Signal1.Listener<WMouseEvent>() { public void trigger(WMouseEvent e1) { //fire of rejection signal createNodeDialog.reject(); } }); } return createNodeDialog; } /** * This will delete the currently selected node if possible. */ private void deleteNode() { WModelIndex index = getSelectedIndexes().first(); if(index != null) { ResourceDescriptor selectedResourceDescriptor = (ResourceDescriptor) index.getInternalPointer(); try { ResourceDescriptor parentResourceDescriptor = selectedResourceDescriptor.getParentResourceDescriptor(); //get our parent index, since it's our parent's children that are going to change WModelIndex parentIndex = ((ResourceDescriptorItemModel) getModel()).getParent(index); //let the mode know that we're about to do some updating. ((ResourceDescriptorItemModel) getModel()).beginRemoveRows(parentIndex, index.getRow(), index.getRow()); //do the deletion selectedResourceDescriptor.performAction(null, Action.DELETE); //if we have a parent, have it refresh it's data if (parentResourceDescriptor != null) { parentResourceDescriptor.reset(State.INITIALIZED); } //let the view know that we're done editing so that it refreshes if (parentIndex != null) { ((ResourceDescriptorItemModel) getModel()).fireDataChanged(parentIndex,false); } else { //if we don't have a parent, then reload the whole model, fairly heavy weight ((ResourceDescriptorItemModel) getModel()).reload(); } } catch (Exception e) { e.printStackTrace(); } } } /** * Creates a child node of the currently selected node with the given name * @param name */ private void createNode(String name) { WModelIndex index = null; ResourceDescriptor selectedResourceDescriptor = null; //figure out where our selected node is, could be the root if(getSelectedIndexes().isEmpty()) {//yep, it's the root, because nothing else is selected index = null; selectedResourceDescriptor = ((ResourceDescriptorItemModel)getModel()).getTopLevelResourceDescriptor(); } else { index = getSelectedIndexes().first(); selectedResourceDescriptor = (ResourceDescriptor) index.getInternalPointer(); } try { //if the current node is about to become a first time parent, set the container attribute to true if(selectedResourceDescriptor instanceof JcrResourceDescriptor && selectedResourceDescriptor.getResourceMetaData(null).isContainer() == false) { selectedResourceDescriptor.getResourceMetaData(null).setValue(ContentMetaData.Attributes.container.toString(), true+""); } //get a pointer to the child resource ResourceDescriptor childResourceDescriptor = selectedResourceDescriptor.getChildResourceDescriptor(null, name); //initialize it, this seems like it shouldn't be needed... //childResourceDescriptor.init(null, null, null, false); // going to leave this here for now //tell the pointer to actually create itself. childResourceDescriptor.performAction(null, Action.CREATE); //refresh it selectedResourceDescriptor.reset(State.OPEN); //cause the view to update if(index != null) { ((ResourceDescriptorItemModel)getModel()).fireDataChanged(index,true); } else { ((ResourceDescriptorItemModel)getModel()).reload();//TODO this is really heavy weight, when in reality, model needs to fire data changed event } } catch (Exception e) { e.printStackTrace(); } } }