true if the user clicked on this submit button to
* submit the form in which the button is contained.
*
- * @param state the state of the current request
+ * @param ps the state of the current request
* @return true if the user clicked this button to submit
* the enclosing form.
*/
diff --git a/ccm-core/src/main/java/org/libreccm/core/User.java b/ccm-core/src/main/java/org/libreccm/core/User.java
index 3ad9a031b..cfba04126 100644
--- a/ccm-core/src/main/java/org/libreccm/core/User.java
+++ b/ccm-core/src/main/java/org/libreccm/core/User.java
@@ -18,37 +18,36 @@
*/
package org.libreccm.core;
-import static org.libreccm.core.CoreConstants.*;
-
-import java.io.Serializable;
-import java.util.Objects;
+import org.hibernate.validator.constraints.NotBlank;
+import org.libreccm.docrepo.Repository;
+import org.libreccm.docrepo.Resource;
import javax.persistence.AssociationOverride;
+import javax.persistence.CollectionTable;
import javax.persistence.Column;
+import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
-
import javax.persistence.Entity;
+import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
-import javax.persistence.Table;
-
-import org.hibernate.validator.constraints.NotBlank;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.persistence.CollectionTable;
-import javax.persistence.ElementCollection;
-import javax.persistence.FetchType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
+import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import static org.libreccm.core.CoreConstants.CORE_XML_NS;
+import static org.libreccm.core.CoreConstants.DB_SCHEMA;
/**
* The {@code User} entity stores the name and the password of a user along with
@@ -183,6 +182,25 @@ public class User extends Subject implements Serializable {
@XmlElement(name = "group-membership", namespace = CORE_XML_NS)
private ListBasePage class
+ * + * @author Jim Parsons + * @author Tobias Osmers + */ +public class BasePage extends Page { + + private final Container globalContainer; + private final Container headerContainer; + private final Container bodyContainer; + private final Container footerContainer; + + private IntegerParameter selected = new IntegerParameter("m"); + + // Todo: add strings to package properties + public static final String DOC_GLOBAL_ELEMENT = "docs:global"; + public static final String DOC_HEADER_ELEMENT = "docs:header"; + public static final String DOC_BODY_ELEMENT = "docs:body"; + public static final String DOC_FOOTER_ELEMENT = "docs:footer"; + public static final String DOC_XML_NS = "http://www.redhat.com/docs/1.0"; + + // There are 2 views: user and admin. view determines which context + // bar and view link to show. + private String view; + private Link viewLink; + + + /** + * Default constructor. + */ + public BasePage() { + this(null); + } + + /** + * Overloaded constructor. + * + * @param view A String that specifies which application view to + * show. Valid values: "user", "admin" and "null". If view is + * "null", there will be no right-hand navigation link. Note - + * We've decided not to have the right-hand navigation link at + * all. Instead, you should create tabs. So, once the + * applications are migrated, view will always be null and we can + * remove view altogether. + */ + public BasePage(String view) { + super(new Label(), new SimpleContainer()); + + setClassAttr("DOCS"); + + m_panel = new Panel(); + + addGlobalStateParam(selected); + + globalContainer = new SimpleContainer(DOC_GLOBAL_ELEMENT, DOC_XML_NS); + headerContainer = new SimpleContainer(DOC_HEADER_ELEMENT, DOC_XML_NS); + bodyContainer = new SimpleContainer(DOC_BODY_ELEMENT, DOC_XML_NS); + footerContainer = new SimpleContainer(DOC_FOOTER_ELEMENT, DOC_XML_NS); + + super.add(globalContainer); + super.add(headerContainer); + super.add(bodyContainer); + super.add(footerContainer); + + this.view = view; + } + + /** + * Getter for the global container. + * + * @return The global container. + */ + public Container getGlobal() { + return globalContainer; + } + + /** + * Getter for the header container. + * + * @return The header container. + */ + public Container getHeader() { + return headerContainer; + } + + /** + * Getter for the body container. + * + * @return The body container. + */ + public Container getBody() { + return bodyContainer; + } + + /** + * Getter for the footer container. + * + * @return The footer container. + */ + public Container getFooter() { + return footerContainer; + } + + /** + * Locks the page and all its components against further modifications. + * + *Locking a page helps in finding mistakes that result from modifying a + * page's structure.
+ */ + @Override + public void lock() { + buildPage(); + + super.lock(); + } + + /** + * Builds the page. + * + * Only the PortalPage.lock() should invoke this method, though users + * of this class may sometimes want to override this method. + * + * Todo: resolvable or deletable? + * Context Bar temporarily deactivated until the functionality to create + * multiple repositories (table docs_mounted) is restored. Because + * currently there is only one repository mounted there is no relevant + * context + */ + protected final void buildPage() { + buildTitle(); + //buildContextBar(); + buildGlobal(getGlobal()); + buildHeader(getHeader()); + buildBody(getBody()); + buildFooter(getFooter()); + } + + /** + * Builds the title. + */ + protected void buildTitle() { + /** + * Internal class. + */ + class ApplicationAdminLabelPrinter implements PrintListener { + public void prepare(PrintEvent e) { + Label targetLabel = (Label)e.getTarget(); + + CcmApplication application = Web.getWebContext().getApplication(); + + Assert.exists(application, CcmApplication.class); + + targetLabel.setLabel(application.getTitle() + " Administration"); + } + } + + if (view != null && view.equals("admin")) { + setTitle(new Label(new ApplicationAdminLabelPrinter())); + } else { + setTitle(new Label(new CurrentApplicationLabelPrinter())); + } + } + + /** + * Builds the context bar. + * + * Todo: unused method.. delete? + */ + protected void buildContextBar() { + DimensionalNavbar navbar = new DimensionalNavbar(); + + navbar.setClassAttr("portalNavbar"); + navbar.add(new Link(new ParentApplicationLinkPrinter())); + navbar.add(new Link(new CurrentApplicationLinkPrinter())); + + getHeader().add(navbar); + } + + /** + * Builds by default the global container in the base page. + * + * @param global The global container. + */ + protected void buildGlobal(Container global) { + Link link = new Link(new Label(GlobalizationUtil.globalize("ui.workspace.sign_out")), "/register/logout"); + + link.setClassAttr("signoutLink"); + getGlobal().add(link); + } + + /** + * Builds by default the header container in the base page. + * + * @param header The header container. + */ + protected void buildHeader(Container header) { + if (view != null) { + if (view.equals("user")) { + viewLink = new Link(new Label(GlobalizationUtil.globalize("ui.view.admin")), "./admin/index.jsp") { + public boolean isVisible(PageState ps) { + return userIsAdmin(ps); + }}; + } else if (view.equals("admin")) { + viewLink = new Link( new Label(GlobalizationUtil.globalize("ui.view.user")), "../index.jsp"); + } + } + + if (viewLink != null) { + viewLink.setClassAttr("portalControl"); + + header.add(viewLink); + } + } + + /** + * Builds the body container in the base page. By default + * nothing. + * + * @param body The body container. + */ + protected void buildBody(Container body) {} + + /** + * Builds the footer container in the base page. By default + * nothing. + * + * @param footer The body container. + */ + protected void buildFooter(Container footer) {} + + + /** + * Represents a panel as a simple container. + */ + private class Panel extends SimpleContainer { + @Override + public void generateXML(PageState ps, Element p) { + Component selected = getSelected(ps); + if (selected == null) { + super.generateXML(ps, p); + } else { + SimpleContainer fakeBody = new SimpleContainer(DOC_BODY_ELEMENT, DOC_XML_NS); + fakeBody.add(selected); + + Element parent = generateParent(p); + + headerContainer.generateXML(ps, parent); + footerContainer.generateXML(ps, parent); + fakeBody.generateXML(ps, parent); + } + } + } + + /** + * Gets the selected component by the given page state. + * + * @param ps The given page state. + * @return The slected component. + */ + private Component getSelected(PageState ps) { + Integer stateIndex = (Integer) ps.getValue(selected); + Component c = null; + if (stateIndex != null) { + c = getComponent(stateIndex); + } + + return c; + } + + /** + * Sets the selected component by a given page state and component. + * + * @param ps The page state. + * @param c The component being selected. + */ + private void setSelected(PageState ps, Component c) { + if (c == null) { + ps.setValue(selected, null); + } else { + ps.setValue(selected, stateIndex(c)); + } + } + + /** + * Makes the given component the only visible component between + * the header and footer of this page. + * + * @param ps The page state. + * @param c The given component. + */ + public void goModal(PageState ps, Component c) { + Component oldc = getSelected(ps); + if (oldc != null) { + oldc.setVisible(ps, false); + } + c.setVisible(ps, true); + setSelected(ps, c); + } + + /** + * Clears the currently selected modal component if it has been set. + * + * @param ps The page state to be cleared. + */ + public void goUnmodal(PageState ps) { + Component oldc = getSelected(ps); + if (oldc != null) { + oldc.setVisible(ps, false); + } + setSelected(ps, null); + } + + /** + * Checks on the permission level, weather the user is admin by the + * given page state. + * + * @param ps The given page state + * @return true if the user is admin, false otherwise. + * + * Todo: does not need param, can be changed + * Todo: Usage of Permission classes don't work + + */ + private boolean userIsAdmin(PageState ps) { +// PermissionDescriptor permDescriptor = +// new PermissionDescriptor(PrivilegeDescriptor.ADMIN, +// Web.getWebContext().getApplication(), +// Kernel.getContext().getParty()); +// return PermissionService.checkPermission(permDescriptor); + return false; + } + + /** + * Adds a component to the body. + * + * @param pc the component to be added + */ + @Override + public void add(Component pc) { + Assert.isUnlocked(this); + bodyContainer.add(pc); + } + + /** + * Class. + */ + protected class CurrentApplicationLinkPrinter implements PrintListener { + public CurrentApplicationLinkPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Link link = (Link) e.getTarget(); + //PageState pageState = e.getPageState(); + + CcmApplication app = Web.getWebContext().getApplication(); + + Assert.exists(app, CcmApplication.class); + + link.setChild(new Label(app.getTitle().toString())); + link.setTarget(app.getPrimaryUrl()); + } + } + + /** + * Class. + */ + protected class ParentApplicationLinkPrinter implements PrintListener { + public ParentApplicationLinkPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Link link = (Link) e.getTarget(); + //PageState pageState = e.getPageState(); + + CcmApplication app = Web.getWebContext().getApplication(); + + Assert.exists(app, CcmApplication.class); + + CcmApplication parent = (CcmApplication) app.getParent(); + if (parent != null ) { + link.setChild(new Label(parent.getTitle().toString())); + link.setTarget(parent.getPrimaryUrl()); + } else { + link.setChild(new Label("/")); + link.setTarget(com.arsdigita.web.URL.root().toString()); + } + } + } + + /** + * Class. + */ + protected class CurrentApplicationLabelPrinter implements PrintListener { + + public CurrentApplicationLabelPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Label label = (Label) e.getTarget(); + //PageState pageState = e.getPageState(); + + CcmApplication app = Web.getWebContext().getApplication(); + + Assert.exists(app, CcmApplication.class); + + label.setLabel(app.getTitle().toString()); + } + } +} diff --git a/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/BrowsePane.java b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/BrowsePane.java new file mode 100644 index 000000000..f8f3307aa --- /dev/null +++ b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/BrowsePane.java @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Container; +import com.arsdigita.bebop.GridPanel; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.List; +import com.arsdigita.bebop.ModalContainer; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SegmentedPanel; +import com.arsdigita.bebop.SimpleComponent; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import com.arsdigita.bebop.event.ChangeEvent; +import com.arsdigita.bebop.event.ChangeListener; +import com.arsdigita.bebop.event.RequestEvent; +import com.arsdigita.bebop.event.RequestListener; +import com.arsdigita.bebop.list.ListCellRenderer; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.xml.Element; +import org.libreccm.cdi.utils.CdiLookupException; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.docrepo.File; +import org.libreccm.docrepo.Resource; +import org.libreccm.docrepo.ResourceRepository; + +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + * User Interface component of the Document Repository application which + * which serves as entry-point and navigation tool of the repositories + * that a user has subscribed too. + * The tree of all subscribed repositories is on the left side, the full + * listing of the currently selected directory is on the right side. + * + * @author Stefan Deusch + * @author Tobias Osmers + */ +public class BrowsePane extends ModalContainer implements Constants, ChangeListener, RequestListener { + + //private static final Logger logger = Logger.getLogger(BrowsePane.class); + + private Component m_folderContent; + private Component m_destinationFolderPanel; + private Component m_newFileForm; + private Component m_newFolderForm; + private Component m_errorMsgPanel; + private DestinationFolderForm m_destinationFolderForm; + private ErrorMessageLabel m_errorMsgLabel; + private Container m_segmentPanelBrowseContainer; + + private Tree m_tree; + + private BigDecimalParameter m_rootFolderIdParam = new BigDecimalParameter(ROOTFOLDER_ID_PARAM_NAME); + private BigDecimalParameter m_selFolderIdParam = new BigDecimalParameter(SEL_FOLDER_ID_PARAM_NAME); + private BigDecimalParameter m_fileIdParam = new BigDecimalParameter(FILE_ID_PARAM_NAME); + private StringParameter m_rootAddDocParam= new StringParameter(ROOT_ADD_DOC_PARAM_NAME); + + /** + * Default constructor. + */ + public BrowsePane() { + m_segmentPanelBrowseContainer = new BoxPanel(); + m_segmentPanelBrowseContainer.setClassAttr("sidebarNavPanel"); + + BoxPanel leftSide = new BoxPanel(); + leftSide.setClassAttr("navbar"); + m_tree = new SuperTree(new RepositoriesSuperTreeModel()); + m_tree.addChangeListener(this); + leftSide.add(m_tree); + + m_segmentPanelBrowseContainer.add(leftSide); + + // Create all panels on the right side. + SegmentedPanel rightSide = new SegmentedPanel(); + rightSide.setClassAttr("segmentPanel"); + m_folderContent = makeContentPanel(rightSide); + m_segmentPanelBrowseContainer.add(rightSide); + + // Add all forms and panels to the container + m_newFileForm = makeFileUploadForm(); + m_segmentPanelBrowseContainer.add(m_newFileForm); + + m_newFolderForm = makeFolderCreateForm(); + m_segmentPanelBrowseContainer.add(m_newFolderForm); + + m_destinationFolderPanel = makeExpandFolderPanel(); + m_segmentPanelBrowseContainer.add(m_destinationFolderPanel); + + m_errorMsgPanel = makeErrorMsgPanel(); + m_segmentPanelBrowseContainer.add(m_errorMsgPanel); + } + + /** + * Register the page the fist time. + * + * @param page The page to be registered. + */ + @Override + public void register(Page page) { + page.addGlobalStateParam(m_rootFolderIdParam); + page.addGlobalStateParam(m_selFolderIdParam); + page.addGlobalStateParam(m_rootAddDocParam); + page.addGlobalStateParam(m_fileIdParam); + + page.addRequestListener(this); + + super.register(page); + } + + /** + * Checks if a folder is selected in the page state and consequently + * hides or shows the Folder Contents or the Folder Action panels. + * + * @param event The request event. + */ + public void pageRequested(RequestEvent event) { + PageState state = event.getPageState(); + + Long fileId = ((BigDecimal) state.getValue(m_fileIdParam)).longValue(); + + boolean display = false; + String key = (String) m_tree.getSelectedKey(state); + + // start out with root folder selected and open + if (key == null) { + key = Utils.getRootFolder(state).getID().toString(); + m_tree.setSelectedKey(state, key); + display = true; + } + + // need this only when coming from 1-file page + if (fileId != null) { + final CdiUtil cdiUtil = new CdiUtil(); + final ResourceRepository resourceRepository; + try { + resourceRepository = cdiUtil.findBean(ResourceRepository.class); + File file = (File) resourceRepository.findById(fileId); + Resource parent = file.getParent(); + key = Long.toString(parent.getObjectId()); + + while (!parent.isRoot()) { + parent = parent.getParent(); + String nextKey = Long.toString(parent.getObjectId()); + m_tree.expand(nextKey, state); + } + + // to display this file's folder in the table + m_tree.setSelectedKey(state, key); + + // now wipe out file param to avoid trouble elsewhere + state.setValue(m_fileIdParam, null); + } catch (CdiLookupException e) { + throw new IllegalStateException(String.format( + "Failed to retrieve file %d from the database.", fileId)); + } + } + + // finally expand selected folder + m_tree.expand(key, state); + + if (display) { + if( "t".equalsIgnoreCase(((String)state.getValue(m_rootAddDocParam)))) { + // Entry hook to display FileUpload Form for Root folder + displayFileUpload(state); + } else { + displayFolderContentPanel(state); + } + } + } + + /** + * Helper method to communicate selected folder ID to sub components. + * Return only non-null after tree has been displayed at least once. + * + * @param state The page state. + * + * @return The folder id. + */ + public BigDecimal getFolderID(PageState state) { + return new BigDecimal((String) m_tree.getSelectedKey(state)); + } + + /** + * Implementation of the change listener, clicking on the folder + * loads the directory on the right side. + * + * @param event The change event. e.g. clicking. + */ + public void stateChanged(ChangeEvent event) { + PageState state = event.getPageState(); + + // Display folder on the right side corresponding to the key + displayFolderContentPanel(state); + } + + /** + * Build a panel to display the Folder content of the selected Folder + * and add it as a segment to the passed Segmented Panel + * + * @param segmentPanel The segment panel. + * + * @return The segment panel with the added segment as a component. + */ + private Component makeContentPanel(SegmentedPanel segmentPanel) { + + Label folder_info_header = new Label + (new GlobalizedMessage("ui.folder.content.header", BUNDLE_NAME)); + folder_info_header.addPrintListener( + new FolderNamePrintListener(m_tree)); + + ActionLink newFileLink = new ActionLink(new Label(FOLDER_NEW_FILE_LINK)); + newFileLink.setClassAttr("actionLink"); + + ActionLink newFolderLink = + new ActionLink(new Label(FOLDER_NEW_FOLDER_LINK)); + newFolderLink.setClassAttr("actionLink"); + + newFileLink.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFileUpload(e.getPageState()); + } + }); + + newFolderLink.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFolderCreate(e.getPageState()); + } + }); + + GridPanel folderGrid = new GridPanel(1); + SimpleContainer pane = new SimpleContainer(); + pane.add(newFileLink); + pane.add(new Label(" ")); + pane.add(newFolderLink); + folderGrid.add(pane, GridPanel.RIGHT | GridPanel.BOTTOM); + folderGrid.add(new FolderContentsTableForm(this, m_tree), + GridPanel.LEFT | GridPanel.BOTTOM); + + return segmentPanel.addSegment(folder_info_header, + folderGrid); + } + + /** + * Builds the file upload form. + * + * @return A component with the build file upload form. + */ + private Component makeFileUploadForm() { + GridPanel gridPanel = new GridPanel(1); + + Label fileUploadFormHeaderLabel = new Label(new GlobalizedMessage("ui.file.upload.header", BUNDLE_NAME)); + fileUploadFormHeaderLabel.addPrintListener(new FolderNamePrintListener(m_tree)); + + gridPanel.add(fileUploadFormHeaderLabel); + gridPanel.add(new FileUploadForm(this, m_tree)); + + return gridPanel; + } + + /** + * Builds the folder create form. + * + * @return A component with the build folder create form. + */ + private Component makeFolderCreateForm() { + GridPanel gridPanel = new GridPanel(1); + Label folderCreateFormHeaderLabel = new Label(new GlobalizedMessage("ui.folder.create.header", BUNDLE_NAME)); + folderCreateFormHeaderLabel.addPrintListener(new FolderNamePrintListener(m_tree)); + + gridPanel.add(folderCreateFormHeaderLabel); + gridPanel.add(new FolderCreateForm(this, m_tree)); + + return gridPanel; + } + + /** + * Builds the destination folders tree. + * + * @return A component with the destination folder tree. + */ + private Component makeExpandFolderPanel() { + GridPanel gridPanel = new GridPanel(1); + m_destinationFolderForm = new DestinationFolderForm(this); + + gridPanel.add(DESTINATION_FOLDER_PANEL_HEADER); + gridPanel.add(m_destinationFolderForm); + + return gridPanel; + } + + /** + * Builds the panel to display error messages when copy/move failed. + * + * @return A component with the panel to display error messages. + */ + private Component makeErrorMsgPanel() { + ColumnPanel columnPanel = new ColumnPanel(1); + m_errorMsgLabel = new ErrorMessageLabel(); + columnPanel.add(m_errorMsgLabel); + + ActionLink link = new ActionLink(ACTION_ERROR_CONTINUE); + link.setClassAttr("actionLink"); + link.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFolderContentPanel(e.getPageState()); + } + }); + + columnPanel.add(link); + return columnPanel; + } + + /** + * Display the file upload form. + * + * @param state The page state + */ + public void displayFileUpload(PageState state) { + m_newFileForm.setVisible(state, true); + } + + /** + * Display the folder create form. + * + * @param state The page state + */ + public void displayFolderCreate(PageState state) { + m_newFolderForm.setVisible(state, true); + } + + /** + * Display the folder content panel. + * + * @param state The page state + */ + public void displayFolderContentPanel(PageState state) { + m_segmentPanelBrowseContainer.setVisible(state, true); + } + + /** + * Display the folder destination panel. + * + * @param state The page state + * @param resourceList A list of resources + * @param isMove Weather its moved or copied + */ + public void displayDestinationFolderPanel(PageState state, + Object[] resourceList, + boolean isMove) { + + m_destinationFolderPanel.setVisible(state, true); + m_destinationFolderForm.setResourceList(state, resourceList); + if (isMove) { + m_destinationFolderForm.setMove(state); + } else { + m_destinationFolderForm.setCopy(state); + } + } + + /** + * Display the error message panel. + * + * @param state The page state + * @param action The file operation + * @param list The list of messages + */ + public void displayErrorMsgPanel(PageState state, + String action, + ArrayList list) { + + m_errorMsgLabel.setMessages(state, action, list); + + m_errorMsgPanel.setVisible(state, true); + } + + + /** + * Error message panel that allows to set customized error + * messages without showing a tomcat stacktrace. + */ + private static class ErrorMessageLabel extends SimpleComponent implements Constants { + + private RequestLocal m_msgs; + private RequestLocal m_action; + + /** + * Constructor. + */ + public ErrorMessageLabel() { + m_msgs = new RequestLocal(); + m_action = new RequestLocal(); + + } + + /** + * Set list of file/folder that could not be delete/move/copy. + * + * @param state The page state + * @param action The file operation (action, move, copy) + * @param msgs The list of messages + */ + public void setMessages(PageState state, + String action, + ArrayList msgs) { + m_action.set(state, action); + m_msgs.set(state, msgs); + } + + @Override + public void generateXML(PageState state, Element parent) { + Element element = parent.newChildElement("docs:error-label", + DOCS_XML_NS); + element.addAttribute("action", (String) m_action.get(state)); + + ArrayList list = (ArrayList) m_msgs.get(state); + + if (list != null) { + for (Object aList : list) { + Element item = element.newChildElement("docs:item", DOCS_XML_NS); + item.addAttribute("name", ((String) aList)); + } + } + } + } + + /** + * Table Cell Renderer that provides clickable Links to follow + * directory links . + * + * Todo: inner private class never used.. + */ + private static class DirLinkRenderer implements ListCellRenderer { + + public Component getComponent(List list, PageState state, + Object value, String key, + int index, boolean isSelected) { + + Link link = new Link((String)value, + "?" + SEL_FOLDER_ID_PARAM.getName() + + "=" + key); + return link; + } + } +} diff --git a/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/CancelButton.java b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/CancelButton.java new file mode 100644 index 000000000..bcde4efc5 --- /dev/null +++ b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/CancelButton.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.globalization.GlobalizedMessage; + +/** + * Customized Cancel button that takes you 1 level back in + * the browser history. + * + * @author Tobias Osmers + */ +public class CancelButton extends Submit { + public CancelButton(GlobalizedMessage label) { + super(label); + setOnClick("history.go(-1); return false;"); + } +} diff --git a/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/Constants.java b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/Constants.java new file mode 100644 index 000000000..bf6dda1b6 --- /dev/null +++ b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/Constants.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.globalization.GlobalizedMessage; + +/** + * Variously used constant objects used in Document Repository UI + * + * Todo: refactor this whole fucking class. Totally idiotic. + * + * @author Stefan Deusch + * @author Tobias Osmers + */ + +public interface Constants { + + // PDL vars + String FOLDER_ID = "folderID"; + String IS_LOCKED = "isLocked"; + String IS_MOUNTED = "isMounted"; + String LAST_MODIFIED = "lastModified"; + String MODIFYING_USER = "modifyingUser"; + String MIME_TYPE_LABEL = "mimeTypeDescription"; + String NAME = "name"; + String ABS_PATH = "absPath"; + String NUM_FILES = "numFiles"; + String REPOSITORY_ID = "repositoryID"; + String RESOURCE_ID = "resourceID"; + String SIZE = "size"; + String TYPE = "mimeType"; + String IS_FOLDER = "isFolder"; + + // PDL queries + String GET_ALL_TREES = "com.arsdigita.docrepo.getAllTreesView"; + String GET_REPOSITORIES = "com.arsdigita.docrepo.getRepositoriesView"; + String GET_REPOSITORIES_ROOTS = "com.arsdigita.docrepo.getRepositoryRoots"; + String GET_CHILDREN = "com.arsdigita.docrepo.getChildren"; + + // PDL associations + String FILES = "files"; + String FOLDERS = "folders"; + + /** + * The XML namespace. + */ + String DOCS_XML_NS = "http://www.arsdigita.com/docs-ui/1.0"; + + /** + * Globalization resource + */ + String BUNDLE_NAME = "com.arsdigita.docrepo.DRResources"; + + /** + * Global state parameters. + */ + String ROOTFOLDER_ID_PARAM_NAME = "r_id"; + BigDecimalParameter ROOTFOLDER_ID_PARAM = new BigDecimalParameter(ROOTFOLDER_ID_PARAM_NAME); + + String SEL_FOLDER_ID_PARAM_NAME = "f_id"; + BigDecimalParameter SEL_FOLDER_ID_PARAM = new BigDecimalParameter(SEL_FOLDER_ID_PARAM_NAME); + + String FILE_ID_PARAM_NAME = "d_id"; + BigDecimalParameter FILE_ID_PARAM = new BigDecimalParameter(FILE_ID_PARAM_NAME); + + /** + * DM Index page title + */ + Label PAGE_TITLE_LABEL = new Label + (new GlobalizedMessage("ui.page.title", BUNDLE_NAME)); + + /** + * DM File Info Page + */ + Label FILE_INFO_LABEL = new Label + (new GlobalizedMessage("ui.fileinfo.title", BUNDLE_NAME)); + + // File Info Navigational Tabs + Label FILE_INFO_PROPERTIES_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.properties.title", BUNDLE_NAME)); + + Label FILE_INFO_HISTORY_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.history.title", BUNDLE_NAME)); + + Label FILE_INFO_COMMENTS_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.comments.title", BUNDLE_NAME)); + + Label FILE_INFO_LINKS_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.links.title", BUNDLE_NAME)); + + Label GO_BACK_LABEL = new Label + (new GlobalizedMessage("ui.fileinfo.goback.label", BUNDLE_NAME)); + + /** + * Navigational dimensional bar + */ + Label MY_WORKSPACE_LABEL = new Label + (new GlobalizedMessage("ui.workspace.title", BUNDLE_NAME)); + + Label SIGN_OUT_LABEL = new Label + (new GlobalizedMessage("ui.nav.signout", BUNDLE_NAME)); + + Label HELP_LABEL = new Label + (new GlobalizedMessage("ui.nav.help", BUNDLE_NAME)); + + + /** + * Page navigational tabs + */ + Label WS_BROWSE_TITLE = new Label + (new GlobalizedMessage("ui.workspace.browse.title", BUNDLE_NAME)); + + Label WS_SEARCH_TITLE = new Label + (new GlobalizedMessage("ui.workspace.search.title", BUNDLE_NAME)); + + Label WS_REPOSITORIES_TITLE = new Label + (new GlobalizedMessage("ui.workspace.repositories.title", BUNDLE_NAME)); + + /** + * One Folder content + */ + Label FOLDER_INFORMATION_HEADER = new Label + (new GlobalizedMessage("ui.folder.content.header", BUNDLE_NAME)); + + /** + * Repositories + */ + Label REPOSITORIES_INFORMATION_HEADER = new Label + (new GlobalizedMessage("ui.repositories.content.header", BUNDLE_NAME)); + + GlobalizedMessage REPOSITORY_RECENTDOCS_EMPTY + = new GlobalizedMessage("ui.repositories.recentDocs.empty", BUNDLE_NAME); + + /** + * File Uplaod Form + */ + Label FILE_UPLOAD_FORM_HEADER = new Label + (new GlobalizedMessage("ui.file.upload.header", BUNDLE_NAME)); + + /** + * Folder Create Form + */ + Label FOLDER_CREATE_FORM_HEADER = new Label + (new GlobalizedMessage("ui.folder.create.header", BUNDLE_NAME)); + + /** + * File Properties + */ + Label FILE_PROPERTIES_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.properties.header", BUNDLE_NAME)); + + /** + * File Edit Panel + */ + Label FILE_EDIT_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.edit.header", BUNDLE_NAME)); + + GlobalizedMessage FILE_EDIT_ACTION_DESCRIPTION = + new GlobalizedMessage("ui.fileinfo.edit.action.description", BUNDLE_NAME); + + /** + * File Upload Panel + */ + Label FILE_UPLOAD_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.upload.header", BUNDLE_NAME)); + + GlobalizedMessage FILE_UPLOAD_INITIAL_TRANSACTION_DESCRIPTION = + new GlobalizedMessage("ui.fileinfo.upload.initialversion.description", BUNDLE_NAME); + + /** + * File Download Panel + */ + Label FILE_DOWNLOAD_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.download.header", BUNDLE_NAME)); + + /** + * File-Send-to-Colleague Form + */ + Label FILE_SEND_COLLEAGUE_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.sendcolleague.header", BUNDLE_NAME)); + + /** + * File-Delete Form + */ + Label FILE_DELETE_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.delete.header", BUNDLE_NAME)); + + /** + * File Action Panel + */ + Label FILE_ACTION_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.actions.header", BUNDLE_NAME)); + + /** + * File Revision History Panel + */ + + Label FILE_REVISION_HISTORY_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.history.header", BUNDLE_NAME)); + + + /** + * File Feedback Panel + */ + + Label FILE_FEEDBACK_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.feedback.header", BUNDLE_NAME)); + + + /** + * Action Panel Constants + */ + Label DESTINATION_FOLDER_PANEL_HEADER = new Label( + new GlobalizedMessage("ui.folder.destination.list.header", BUNDLE_NAME)); + + Label FOLDER_EMPTY_LABEL = new Label( + new GlobalizedMessage("ui.folder.empty", BUNDLE_NAME)); + + GlobalizedMessage FOLDER_NEW_FOLDER_LINK = + new GlobalizedMessage("ui.action.newfolder", BUNDLE_NAME); + + GlobalizedMessage FOLDER_NEW_FILE_LINK = + new GlobalizedMessage("ui.action.newfile", BUNDLE_NAME); + + Label ACTION_CUT_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.cut", BUNDLE_NAME)); + + Label ACTION_COPY_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.copy", BUNDLE_NAME)); + + Label ACTION_DELETE_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.delete", BUNDLE_NAME)); + + GlobalizedMessage ACTION_DELETE_CONFIRM = + new GlobalizedMessage("ui.action.confirm.delete", BUNDLE_NAME); + + Label ACTION_ERROR_LABEL = new Label( + new GlobalizedMessage("ui.action.error", BUNDLE_NAME)); + + Label ACTION_ERROR_CONTINUE = new Label( + new GlobalizedMessage("ui.action.error.continue", BUNDLE_NAME)); + + String ACTION_CUT_VALUE = "resource-cut"; + String ACTION_COPY_VALUE = "resource-copy"; + String ACTION_DELETE_VALUE = "resource-delete"; + + GlobalizedMessage ACTION_DELETE_SUBMIT = + new GlobalizedMessage("ui.action.submit.delete", BUNDLE_NAME); + + GlobalizedMessage ACTION_COPY_SUBMIT = + new GlobalizedMessage("ui.action.submit.copy", BUNDLE_NAME); + + GlobalizedMessage ACTION_MOVE_SUBMIT = + new GlobalizedMessage("ui.action.submit.move", BUNDLE_NAME); + + + /** + * Portlet Panel Constants + */ + GlobalizedMessage ROOT_ADD_RESOURCE_LINK = + new GlobalizedMessage("ui.action.portlet.newresource", BUNDLE_NAME); + + String ROOT_ADD_DOC_PARAM_NAME = "root_add_doc"; + StringParameter ROOT_ADD_DOC_PARAM = + new StringParameter(ROOT_ADD_DOC_PARAM_NAME); + + + /** + * File Action Panel Constants + */ + GlobalizedMessage FILE_EDIT_LINK = + new GlobalizedMessage("ui.fileinfo.edit.link", BUNDLE_NAME); + + GlobalizedMessage FILE_NEW_VERSION_LINK = + new GlobalizedMessage("ui.fileinfo.newversion.link", BUNDLE_NAME); + + GlobalizedMessage FILE_DOWNLOAD_LINK = + new GlobalizedMessage("ui.fileinfo.download.link", BUNDLE_NAME); + + GlobalizedMessage FILE_SEND_COLLEAGUE_LINK = + new GlobalizedMessage("ui.fileinfo.sendcolleague.link", BUNDLE_NAME); + + GlobalizedMessage FILE_DELETE_LINK = + new GlobalizedMessage("ui.fileinfo.delete.link", BUNDLE_NAME); + + + /** + * Error messages + */ + GlobalizedMessage FOLDER_PARENTNOTFOUND_ERROR = + new GlobalizedMessage("ui.error.parentnotfound", BUNDLE_NAME); + + GlobalizedMessage RESOURCE_EXISTS_ERROR = + new GlobalizedMessage("ui.error.resourceexists", BUNDLE_NAME); + + GlobalizedMessage EMAIL_INVALID_ERROR = + new GlobalizedMessage("ui.email.formatinvalid", BUNDLE_NAME); + + GlobalizedMessage DIFFERENT_MIMETYPE_ERROR = + new GlobalizedMessage("ui.error.mimetype", BUNDLE_NAME); + + + /** + * FILE DELETE link + */ + GlobalizedMessage FILE_DELETE_CONFIRM = + new GlobalizedMessage("ui.file.confirm.delete", BUNDLE_NAME); + + // Labels for Files + GlobalizedMessage FILE_NAME = + new GlobalizedMessage("ui.file.name", BUNDLE_NAME); + + GlobalizedMessage FILE_NAME_REQUIRED = + new GlobalizedMessage("ui.file.name.required", BUNDLE_NAME); + + GlobalizedMessage FILE_UPLOAD_ADD_FILE = + new GlobalizedMessage("ui.file.upload", BUNDLE_NAME); + + GlobalizedMessage FILE_SOURCE = + new GlobalizedMessage("ui.file.source", BUNDLE_NAME); + + GlobalizedMessage FILE_DESCRIPTION = + new GlobalizedMessage("ui.file.description", BUNDLE_NAME); + + GlobalizedMessage FILE_VERSION_DESCRIPTION = + new GlobalizedMessage("ui.file.version.description", BUNDLE_NAME); + + GlobalizedMessage FILE_KEYWORDS = + new GlobalizedMessage("ui.file.keywords", BUNDLE_NAME); + + GlobalizedMessage FILE_SAVE = + new GlobalizedMessage("ui.file.save", BUNDLE_NAME); + + GlobalizedMessage FILE_SUBMIT = + new GlobalizedMessage("ui.file.submit", BUNDLE_NAME); + + GlobalizedMessage CANCEL = + new GlobalizedMessage("ui.action.cancel", BUNDLE_NAME); + + /** + * Folder parameters + */ + String FOLDER_NAME = "folder-name"; + String FOLDER_DESCRIPTION = "folder-description"; + + Label FOLDER_NAME_LABEL = new Label( + new GlobalizedMessage("ui.folder.name", BUNDLE_NAME)); + + Label FOLDER_DESCRIPTION_LABEL = new Label( + new GlobalizedMessage("ui.folder.description", BUNDLE_NAME)); + + GlobalizedMessage FOLDER_SAVE = + new GlobalizedMessage("ui.folder.save", BUNDLE_NAME); + + /** + * Repsitories Selection Form + */ + GlobalizedMessage REPOSITORIES_MOUNTED_SAVE = + new GlobalizedMessage("ui.repositories.mounted.save", BUNDLE_NAME); + + /** + * Send to colleague form variables. + */ + Label SEND_FRIEND_FORM_EMAIL_SUBJECT = new Label( + new GlobalizedMessage("ui.send.friend.email.subject", BUNDLE_NAME)); + + Label SEND_FRIEND_FORM_EMAIL_LIST = new Label( + new GlobalizedMessage("ui.send.friend.email.list", BUNDLE_NAME)); + + Label SEND_FRIEND_FORM_DESCRIPTION = new Label( + new GlobalizedMessage("ui.send.friend.description", BUNDLE_NAME)); + + GlobalizedMessage SEND_FRIEND_FORM_SUBMIT = + new GlobalizedMessage("ui.send.friend.submit", BUNDLE_NAME); +} diff --git a/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/DestinationFolderForm.java b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/DestinationFolderForm.java new file mode 100644 index 000000000..5ff78c5b4 --- /dev/null +++ b/ccm-docrepo/src/main/java/com/arsdigita/docrepo/ui/DestinationFolderForm.java @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Hidden; +import com.arsdigita.bebop.form.RadioGroup; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.parameters.ArrayParameter; +import com.arsdigita.docrepo.util.GlobalizationUtil; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.web.Web; +import com.arsdigita.xml.Element; +import org.apache.log4j.Logger; +import org.libreccm.cdi.utils.CdiLookupException; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.docrepo.Folder; +import org.libreccm.docrepo.Repository; +import org.libreccm.docrepo.Resource; +import org.libreccm.docrepo.ResourceManager; +import org.libreccm.docrepo.ResourceRepository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Intermediate form of the "Move-to" and "Copy-to" process. + * It shows the folder tree of the repositories expanded + * with checkboxes next to it. + * + * @author David Dao + * @author Stefan Deusch + * @author Tobias Osmers + */ +public class DestinationFolderForm extends Form implements FormInitListener, + FormProcessListener, Constants { + + private static final Logger log = Logger.getLogger(DestinationFolderForm.class); + + private Hidden m_resourceList; + private ExpandedFolderTree m_radioGroup; + + private Submit m_copySubmit; + private Submit m_moveSubmit; + private BrowsePane m_parent; + + /** + * Constructor. Creates a destination folder form. + * + * @param parent The parent of the destination folder form + */ + public DestinationFolderForm(BrowsePane parent) { + super("Destination-Folder", new ColumnPanel(1)); + m_parent = parent; + m_resourceList = new Hidden(new ArrayParameter("resourceList")); + add(m_resourceList); + + m_radioGroup = new ExpandedFolderTree(); + add(m_radioGroup); + + m_copySubmit = new Submit(GlobalizationUtil.globalize( + "ui.action.submit.copy")); + add(m_copySubmit); + m_moveSubmit = new Submit(GlobalizationUtil.globalize( + "ui.action.submit.copy")); + add(m_moveSubmit); + + addInitListener(this); + addProcessListener(this); + } + + /** + *Adds a DOM subtree representing this component under the given
+ * parent node. Uses the request values stored in state.
Contains methods to simplify globalizing keys
+ * + * @author sarnold@redhat.com + * @author Tobias Osmers + */ + +public class GlobalizationUtil implements Globalized { + + private static final String BUNDLE_NAME = "com.arsdigita.docrepo.Resources"; + + public static GlobalizedMessage globalize(String key) { + return new GlobalizedMessage(key, BUNDLE_NAME); + } + + public static GlobalizedMessage globalize(String key, Object[] args) { + return new GlobalizedMessage(key, BUNDLE_NAME, args); + + } +} diff --git a/ccm-docrepo/src/main/java/org/libreccm/docrepo/BlobObject.java b/ccm-docrepo/src/main/java/org/libreccm/docrepo/BlobObject.java index a39e47944..a5cc3fc1a 100644 --- a/ccm-docrepo/src/main/java/org/libreccm/docrepo/BlobObject.java +++ b/ccm-docrepo/src/main/java/org/libreccm/docrepo/BlobObject.java @@ -64,7 +64,7 @@ public class BlobObject implements Serializable { private byte[] content; /** - * The {@link Resource} assigned to the {@code BlobObject}. + * The {@link Resource} the {@code BlobObject} was assigned to. */ @OneToOne(mappedBy = "content") @NotEmpty diff --git a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Folder.java b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Folder.java index 4988ac23f..b0d3a8006 100644 --- a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Folder.java +++ b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Folder.java @@ -19,6 +19,7 @@ package org.libreccm.docrepo; import javax.persistence.Entity; +import javax.persistence.OneToOne; import javax.persistence.Table; /** @@ -34,10 +35,28 @@ public class Folder extends Resource { private static final long serialVersionUID = 1561466556458872622L; + /** + * The {@link Repository} this {@code Folder} is assigned to as root. + */ + @OneToOne(mappedBy = "rootFolder") + private Repository repository; + /** * Constructor calls the super-class-constructor of {@link Resource}. */ public Folder() { super(); } + + //> Begin GETTER & SETTER + + public Repository getRepository() { + return repository; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + //< End GETTER & SETTER } diff --git a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Repository.java b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Repository.java index e4d8c2868..0f62f5bf3 100644 --- a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Repository.java +++ b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Repository.java @@ -18,15 +18,19 @@ */ package org.libreccm.docrepo; +import org.libreccm.core.User; import org.libreccm.web.CcmApplication; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; import javax.persistence.Table; /** - * Entity class of a repository for documents. Instances will be persisted into the - * database. Instance variables are inherited from {@link CcmApplication}. + * Entity class of a repository for documents. Instances will be persisted into + * the database. Instance variables are inherited from {@link CcmApplication}. * * @author Tobias Osmers * @version 01/10/2015 @@ -38,16 +42,24 @@ public class Repository extends CcmApplication { private static final long serialVersionUID = 6673243021462798036L; /** - * The root of the repository. + * Name des {@code Repository}s. */ - @Column(name = "ROOT_ID") - private long rootId; + @Column(name = "NAME") + private String name; /** - * The owner of the repository. + * The root of the {@code Repository}. */ - @Column(name = "OWNER_ID") - private long ownerId; + @OneToOne + @JoinColumn(name = "ROOT_FOLDER") + private Folder rootFolder; + + /** + * The owner of the {@code Repository}. + */ + @ManyToOne + @JoinColumn(name = "OWNER") + private User owner; /** * Constructor calls the super-class-constructor of {@link CcmApplication}. @@ -58,20 +70,28 @@ public class Repository extends CcmApplication { //> Begin GETTER & SETTER - public long getRootId() { - return rootId; + public String getName() { + return name; } - public void setRootId(long rootId) { - this.rootId = rootId; + public void setName(String name) { + this.name = name; } - public long getOwnerId() { - return ownerId; + public Folder getRootFolder() { + return rootFolder; } - public void setOwnerId(long ownerId) { - this.ownerId = ownerId; + public void setRootFolder(Folder root_folder) { + this.rootFolder = root_folder; + } + + public User getOwner() { + return owner; + } + + public void setOwner(User owner) { + this.owner = owner; } //< End GETTER & SETTER diff --git a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Resource.java b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Resource.java index bb50525cb..2b1272954 100644 --- a/ccm-docrepo/src/main/java/org/libreccm/docrepo/Resource.java +++ b/ccm-docrepo/src/main/java/org/libreccm/docrepo/Resource.java @@ -291,4 +291,8 @@ public abstract class Resource extends CcmObject { } //< End GETTER & SETTER + + public boolean isRoot() { + return isFolder() && getParent() == null; + } } diff --git a/ccm-docrepo/src/main/java/org/libreccm/docrepo/ResourceManager.java b/ccm-docrepo/src/main/java/org/libreccm/docrepo/ResourceManager.java index 776f93100..6c29c65af 100644 --- a/ccm-docrepo/src/main/java/org/libreccm/docrepo/ResourceManager.java +++ b/ccm-docrepo/src/main/java/org/libreccm/docrepo/ResourceManager.java @@ -18,6 +18,8 @@ */ package org.libreccm.docrepo; +import org.apache.log4j.Logger; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; @@ -29,11 +31,26 @@ import javax.inject.Inject; */ @RequestScoped public class ResourceManager { + private static final Logger log = Logger.getLogger(ResourceManager.class); @Inject private transient ResourceRepository resourceRepository; + public void copyToFolder(Resource original, Folder folder) { + Resource copy = original.isFolder() ? new Folder() : new File(); + copy.setName(original.getName()); + copy.setDescription(original.getDescription()); + copy.setIsFolder(original.isFolder()); + copy.setPath(String.format("%s/%s", folder.getPath(), copy.getName())); + copy.setMimeType(original.getMimeType()); + copy.setSize(original.getSize()); + copy.setContent(original.getContent()); + copy.setParent(folder); + copy.setImmediateChildren(original.getImmediateChildren()); + + resourceRepository.save(copy); + } diff --git a/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources.properties b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources.properties new file mode 100644 index 000000000..69bdc1cc5 --- /dev/null +++ b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources.properties @@ -0,0 +1,76 @@ +ui.action.edit.copy=Copy +ui.action.edit.cut=Cut +ui.action.edit.delete=Delete +ui.action.error=The following error(s) occured: +ui.action.error.continue=Continue +ui.action.submit.delete=Delete +ui.action.confirm.delete='Do you really want to delete the selected files and folders?' +ui.action.submit.copy=Copy to ... +ui.action.submit.move=Move to ... +ui.action.newfile=New Document +ui.action.newfolder=New Folder +ui.action.cancel=Cancel +ui.email.formatinvalid=Did not send document to following e-mail addresses because of invalid format +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Description: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Upload File: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Save +ui.file.submit=Upload +ui.file.source=Source: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.file.confirm.delete=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.page.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.action.portlet.newresource=New Document +ui.folder.name_not_unique=A folder with this name already exists +ui.workspace.sign_out=Sign out +ui.view.admin=View of the Admin +ui.view.user=The view of the User +ui.folder.choose_destination=Please choose a destination diff --git a/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_de.properties b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_de.properties new file mode 100644 index 000000000..b907c122e --- /dev/null +++ b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_de.properties @@ -0,0 +1,76 @@ +ui.action.edit.copy=Kopieren +ui.action.edit.cut=Ausschneiden +ui.action.edit.delete=Löschen +ui.action.error=Folgende(r) Fehler trat(en) auf: +ui.action.error.continue=Fortfahren +ui.action.submit.delete=L\u00f6schen +ui.action.confirm.delete='Sollen die ausgew\u00e4hlten Dateien und Ordner tats\u00e4chlich gel\u00f6scht werden?' +ui.action.submit.copy=Kopieren nach ... +ui.action.submit.move=Verschieben nach ... +ui.action.newfile=Neues Dokument +ui.action.newfolder=Neuer Ordner +ui.action.cancel=Abbrechen +ui.email.formatinvalid=Das Dokument konte aufgrund eines ung\u00fcltigen Formates nicht an die folgende E-Mail Adresse versandt werden +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Beschreibung: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Datgei hochladen: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Sichern +ui.file.submit=Upload +ui.file.source=Quelle: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.file.confirm.delete=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.page.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.action.portlet.newresource=New Document +ui.folder.name_not_unique=Ein Ordner mit diesem Namen existiert bereits +ui.workspace.sign_out=Abmelden +ui.view.admin=Ansicht des Admin +ui.view.user=Die Ansicht des Benutzers +ui.folder.choose_destination=Bitte w\u00e4hle ein Ziel diff --git a/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_en.properties b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_en.properties new file mode 100644 index 000000000..69bdc1cc5 --- /dev/null +++ b/ccm-docrepo/src/main/resources/com.arsdigita.docrepo/Resources_en.properties @@ -0,0 +1,76 @@ +ui.action.edit.copy=Copy +ui.action.edit.cut=Cut +ui.action.edit.delete=Delete +ui.action.error=The following error(s) occured: +ui.action.error.continue=Continue +ui.action.submit.delete=Delete +ui.action.confirm.delete='Do you really want to delete the selected files and folders?' +ui.action.submit.copy=Copy to ... +ui.action.submit.move=Move to ... +ui.action.newfile=New Document +ui.action.newfolder=New Folder +ui.action.cancel=Cancel +ui.email.formatinvalid=Did not send document to following e-mail addresses because of invalid format +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Description: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Upload File: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Save +ui.file.submit=Upload +ui.file.source=Source: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.file.confirm.delete=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.page.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.action.portlet.newresource=New Document +ui.folder.name_not_unique=A folder with this name already exists +ui.workspace.sign_out=Sign out +ui.view.admin=View of the Admin +ui.view.user=The view of the User +ui.folder.choose_destination=Please choose a destination