package com.delcyon.capo.webapp.widgets; import java.util.List; import java.util.SortedSet; import java.util.logging.Level; import com.delcyon.capo.CapoApplication; import com.delcyon.capo.resourcemanager.ResourceDescriptor; import com.delcyon.capo.resourcemanager.ResourceType; import com.delcyon.capo.resourcemanager.ResourceURI; import com.delcyon.capo.resourcemanager.types.JcrResourceType; import com.delcyon.capo.webapp.models.DomItemModel.DomUse; import com.delcyon.capo.webapp.models.ResourceDescriptorItemModel; import com.delcyon.capo.webapp.servlets.CapoWebApplication; import eu.webtoolkit.jwt.AlignmentFlag; import eu.webtoolkit.jwt.MatchOptions; import eu.webtoolkit.jwt.WApplication; import eu.webtoolkit.jwt.WCompositeWidget; import eu.webtoolkit.jwt.WContainerWidget; import eu.webtoolkit.jwt.WGridLayout; import eu.webtoolkit.jwt.WLink; import eu.webtoolkit.jwt.WLink.Type; import eu.webtoolkit.jwt.WModelIndex; import eu.webtoolkit.jwt.WMouseEvent; import eu.webtoolkit.jwt.WPushButton; /** * This Widget combines a resource tree and a resource editor. * It automatically * @author jeremiah * */ public class WCapoResourceExplorer extends WCompositeWidget { private ResourceType resourceType = new JcrResourceType(); private WContainerWidget container = new WContainerWidget(); private WGridLayout contentPaneLayout; private WCapoResourceTreeView capoResourceTreeView; private WCapoResourceEditor capoResourceEditor; private WPushButton resetButton; private WPushButton saveButton; public WCapoResourceExplorer() { setImplementation(container); setMargin(0); container.setLayout(getResourceExplorerLayout()); //container.setAttributeValue("style", "background-image: url('/wr/images/background.png'); background-repeat: no-repeat; background-position: bottom right; background-size: contain;"); getResourceExplorerLayout().addWidget(getCapoResourceTreeView(), 0, 0,1,0); getResourceExplorerLayout().addWidget(getResourceEditor(), 0, 1); getResourceExplorerLayout().addWidget(getSaveButton(), 2, 0, 1, 1, AlignmentFlag.AlignTop); getResourceExplorerLayout().addWidget(getResetButton(), 3, 0, 1, 1, AlignmentFlag.AlignTop); WApplication.getInstance().internalPathChanged().addListener(this,this::processInternalPathChange); } private WGridLayout getResourceExplorerLayout() { if (contentPaneLayout == null) { contentPaneLayout = new WGridLayout(); contentPaneLayout.setColumnStretch(1, 1); contentPaneLayout.setContentsMargins(0, 0, 0, 0); contentPaneLayout.setColumnResizable(0); contentPaneLayout.setRowStretch(1, 1); contentPaneLayout.setRowStretch(0, 1); } return contentPaneLayout; } private WCapoResourceTreeView getCapoResourceTreeView() { if(capoResourceTreeView == null) { capoResourceTreeView = new WCapoResourceTreeView(); //watch for selection change events capoResourceTreeView.selectionChanged().addListener(this, this::selectedItemChanged); //watch for internal patch change requests from tree capoResourceTreeView.doubleClicked().addListener(this, this::processTreeDoubleClick); } return capoResourceTreeView; } private WCapoResourceEditor getResourceEditor() { if (capoResourceEditor == null) { capoResourceEditor = new WCapoResourceEditor(); } return capoResourceEditor; } /** * Set the kind of resource that we're dealing with, this is mostly used to figure out what kind od scheme to use when making paths. * The default is JcrResourceType * @param resourceType */ public void setResourceType(ResourceType resourceType) { this.resourceType = resourceType; } public ResourceType getResourceType() { return resourceType; } /** * * @return Resource scheme plus a ':' */ private String getResourceTypeScheme() { return getResourceType().getName()+":"; } /** * Process request for tree root/internal path changes from tree * @param modelIndex * @param mouseEvent */ private void processTreeDoubleClick(WModelIndex modelIndex, WMouseEvent mouseEvent) { //update the internal path with the our resource URI. by allowing this to emit processInternalPathChange() also get called WApplication.getInstance().setInternalPath(((ResourceDescriptor)modelIndex.getInternalPointer()).getResourceURI().getPath(), true); } /** * sends selection changes in the tree to the resource editor */ private void selectedItemChanged() { SortedSet<WModelIndex> selectedIndexes = getCapoResourceTreeView().getSelectedIndexes(); if(selectedIndexes.size() == 0) { return; } else if (selectedIndexes.size() == 1) { WModelIndex modelIndex = selectedIndexes.first(); final Object selectedItem = modelIndex.getInternalPointer(); getResourceEditor().setModel((ResourceDescriptor) selectedItem); //TODO add some sort of event/Signal listener to process this so that we don't have to know so much about models and events } refresh(); } private WPushButton getSaveButton() { if(saveButton == null) { saveButton = new WPushButton("Save"); saveButton.clicked().addListener(this, this::saveSession); } return saveButton; } /** * saves current jcrSession, TODO this should really work with the current users workspace or something. */ private void saveSession() { try { ((CapoWebApplication) CapoWebApplication.getInstance()).getJcrSession().save(); } catch (Exception e) { CapoWebApplication.exception(Level.SEVERE, "Error saving JCR session", e); } } private WPushButton getResetButton() { if(resetButton == null) { resetButton = new WPushButton("Reset"); resetButton.setLink(new WLink(Type.InternalPath, "/")); resetButton.clicked().addListener(this, this::reset); } return resetButton; } /** * Resets session and tree view to root */ private void reset() { try { //refresh the jcr session, wiping all unsaved changes ((CapoWebApplication) CapoWebApplication.getInstance()).getJcrSession().refresh(false); //reload the tree view ((ResourceDescriptorItemModel) capoResourceTreeView.getModel()).reload(); capoResourceTreeView.setModel(new ResourceDescriptorItemModel(CapoApplication.getDataManager().getResourceDescriptor(null, getResourceTypeScheme()+"/"),DomUse.NAVIGATION)); } catch (Exception e) { CapoWebApplication.exception(Level.SEVERE, "Error resetting", e); } } public void setRootResourceDescriptor(ResourceDescriptor resourceDescriptor) { setResourceType(resourceDescriptor.getResourceType()); getCapoResourceTreeView().setRootResourceDescriptor(resourceDescriptor); } /** * Deal with any internal path changes in the system. Make sure that the proper components and resources are loaded and views are show etc */ private void processInternalPathChange() { System.out.println(WApplication.getInstance().getInternalPath()); //skip and changes that happen when we're not visible if(isVisible() == false) { return; } try { //TODO make this deal with resource that are not only of type repo: ResourceDescriptor resourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(null, getResourceTypeScheme()+WApplication.getInstance().getInternalPath()); ResourceURI originalURI = resourceDescriptor.getResourceURI(); //we don't ever want to set the root to anything that isn't a container. So if it isn't use its parent who should be if(resourceDescriptor.getResourceMetaData(null).isContainer() == false) { if(resourceDescriptor.getParentResourceDescriptor() != null) { resourceDescriptor = resourceDescriptor.getParentResourceDescriptor(); } else { String parentURI = resourceDescriptor.getResourceURI().getResourceURIString().replaceAll("/"+resourceDescriptor.getLocalName(), ""); if(parentURI.equals(getResourceTypeScheme())) //make sure we have a root for the repo { parentURI = getResourceTypeScheme()+"/"; } resourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(null,parentURI); WApplication.getInstance().setInternalPath(resourceDescriptor.getResourceURI().getPath()); } } setRootResourceDescriptor(resourceDescriptor); if(originalURI != null) { WModelIndex currentIndex = getCapoResourceTreeView().getModel().getIndex(0, 0); if(currentIndex != null) //not sure why this can be null, it isn't very often { List<WModelIndex> indexes = getCapoResourceTreeView().getModel().match(currentIndex, ResourceDescriptorItemModel.ResourceURI_ROLE, originalURI.toString(), 1, MatchOptions.defaultMatchOptions); if(indexes.size() > 0) { getCapoResourceTreeView().select(indexes.get(0)); } } } getCapoResourceTreeView().selectionChanged(); refresh(); } catch (Exception e) { CapoWebApplication.exception(Level.SEVERE, "Error processing internal path change", e); } } }