/* * File : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.documentcenter/src/com/alkacon/opencms/documentcenter/CmsDocumentList.java,v $ * Date : $Date: 2010/03/19 15:31:13 $ * Version: $Revision: 1.3 $ * * This file is part of the Alkacon OpenCms Add-On Module Package * * Copyright (c) 2010 Alkacon Software GmbH (http://www.alkacon.com) * * The Alkacon OpenCms Add-On Module Package is free software: * you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Alkacon OpenCms Add-On Module Package 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Alkacon OpenCms Add-On Module Package. * If not, see http://www.gnu.org/licenses/. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com. * * For further information about OpenCms, please see the * project website: http://www.opencms.org. */ package com.alkacon.opencms.documentcenter; import org.opencms.main.CmsLog; import java.util.AbstractList; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; /** * Provides methods to create a special list of CmsDocument objects regarding language and attachment functionality.<p> * * After adding all documents to the list, the {@link #closeList()} method has to be called once * before working with the list contents, e.g. before sorting the list or iterating it.<p> * * @author Andreas Zahner * * @version $Revision: 1.3 $ * * @since 6.2.0 */ public class CmsDocumentList extends AbstractList { /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsDocumentList.class); private List m_attachments; private CmsDocument[] m_documents; private boolean m_onlyVersions; private int m_size; private boolean m_useAttachments; private boolean m_useLanguages; private boolean m_useTypes; private String m_defaultType; /** * Creates an empty document list with an initial capacity of 16 items.<p> */ public CmsDocumentList() { this(16); } /** * Creates an empty document list with the flags to use language versions and attachments, to show only versions and * the given initial capacity.<p> * * @param useTypes the flag if different types of a document should be considered * @param defaultType if list uses types, the default type is specified here * @param useAttachments the flag if attachments of a document should be conbsidered * @param useLanguages the flag if language versions of a document should be considered * @param onlyVersions the flag if only versions of a specific document should be added to the list * @param initialCapacity the initial capacity of the document list */ public CmsDocumentList( boolean useTypes, String defaultType, boolean useAttachments, boolean useLanguages, boolean onlyVersions, int initialCapacity) { m_documents = new CmsDocument[initialCapacity]; m_size = 0; m_attachments = new ArrayList(); m_useLanguages = useLanguages; m_onlyVersions = onlyVersions; m_useAttachments = useAttachments; m_useTypes = useTypes; m_defaultType = defaultType; } /** * Creates an empty document list with the flags to use language versions and attachments, to show only versions and * the given initial capacity.<p> * * @param useAttachments the flag is attachments of a document should be conbsidered * @param useLanguages the flag if language versions of a document should be considered * @param onlyVersions the flag if only versions of a specific document should be added to the list * @param initialCapacity the initial capacity of the document list */ public CmsDocumentList(boolean useAttachments, boolean useLanguages, boolean onlyVersions, int initialCapacity) { this(false, null, useAttachments, useLanguages, onlyVersions, initialCapacity); } /** * Creates an empty document list with the flags to use language versions, to show only versions and the given initial capacity.<p> * * @param useLanguages the flag if language versions of a document should be considered * @param onlyVersions the flag if only versions of a specific document should be added to the list * @param initialCapacity the initial capacity of the document list */ public CmsDocumentList(boolean useLanguages, boolean onlyVersions, int initialCapacity) { this(true, useLanguages, onlyVersions, initialCapacity); } /** * Creates an empty document list with the given initial capacity.<p> * * @param initialCapacity the initial capacity of the document list */ public CmsDocumentList(int initialCapacity) { this(false, false, initialCapacity); } /** * @see java.util.AbstractList#add(int, java.lang.Object) */ public void add(int index, Object element) { rangeCheck(index); CmsDocument doc = convertDocument(element); if (doc.isNullDocument() || checkContainer(doc)) { return; } ensureCapacity(m_size + 1); // Increments modCount!! System.arraycopy(m_documents, index, m_documents, index + 1, m_size - index); m_documents[index] = doc; m_size++; } /** * @see java.util.AbstractList#add(java.lang.Object) */ public boolean add(Object element) { CmsDocument doc = convertDocument(element); if (doc.isNullDocument() || checkContainer(doc)) { return true; } ensureCapacity(m_size + 1); m_documents[m_size++] = doc; return true; } /** * @see java.util.Collection#clear() */ public void clear() { modCount++; for (int i = 0; i < m_size; i++) { m_documents[i] = null; } m_size = 0; } /** * Closes the list after adding all documents to it, this is needed to assign the found attachments to the documents.<p> */ public void closeList() { for (int i = 0; i < m_attachments.size(); i++) { // loop through all attachments CmsDocument att = (CmsDocument)m_attachments.get(i); boolean added = false; for (int k = 0; k < m_size; k++) { // check if the attachment belongs to a document if (m_documents[k].isVersionOf(att)) { // found a document for the attachment if (m_documents[k].addAttachment(att)) { added = true; break; } } } if (!added) { // found no document for the attachment, add it as separate attachment to the list ensureCapacity(m_size + 1); m_documents[m_size++] = att; } } // empty the attachment list m_attachments = new ArrayList(); } /** * @see java.util.Collection#contains(java.lang.Object) */ public boolean contains(Object elem) { return indexOf(elem) >= 0; } /** * Increases the capacity of this <tt>CmsDocumentList</tt> instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity. */ public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = m_documents.length; if (minCapacity > oldCapacity) { CmsDocument[] oldData = m_documents; int newCapacity = (oldCapacity * 3) / 2 + 1; if (newCapacity < minCapacity) { newCapacity = minCapacity; } m_documents = new CmsDocument[newCapacity]; System.arraycopy(oldData, 0, m_documents, 0, m_size); } } /** * @see java.util.AbstractList#get(int) */ public Object get(int index) { rangeCheck(index); return m_documents[index]; } /** * @see java.util.List#indexOf(java.lang.Object) */ public int indexOf(Object elem) { if (elem == null) { for (int i = 0; i < m_size; i++) { if (m_documents[i] == null) { return i; } } } else { for (int i = 0; i < m_size; i++) { if (elem.equals(m_documents[i])) { return i; } } } return -1; } /** * @see java.util.AbstractList#remove(int) */ public Object remove(int index) { rangeCheck(index); modCount++; CmsDocument oldValue = m_documents[index]; int numMoved = m_size - index - 1; if (numMoved > 0) { System.arraycopy(m_documents, index + 1, m_documents, index, numMoved); } m_documents[--m_size] = null; return oldValue; } /** * @see java.util.AbstractList#set(int, java.lang.Object) */ public Object set(int index, Object element) { rangeCheck(index); CmsDocument newValue = (CmsDocument)element; CmsDocument oldValue = m_documents[index]; m_documents[index] = newValue; return oldValue; } /** * @see java.util.AbstractCollection#size() */ public int size() { return m_size; } /** * Checks if the document is added as a subdocument or attachment.<p> * * If the document was not merged, it is a new document that has to be added to the list depending on the only versions flag.<p> * * @param doc the document to check * @return true if the document was added as subdocument, attachment or if the document should not be added, otherwise false */ private boolean checkContainer(CmsDocument doc) { boolean docnameWithoutPostfixEquality; for (int i = 0; i < m_size; i++) { docnameWithoutPostfixEquality = doc.getDocumentNameFullWithoutPostfix().equals( m_documents[i].getDocumentNameFullWithoutPostfix()); if (m_documents[i].isVersionOf(doc) || (m_useTypes && docnameWithoutPostfixEquality)) { if (m_useTypes) { if ((m_defaultType != null) && (m_defaultType.equals(doc.getPostfix()))) { if (m_documents[i].getTypes().size() > 0) { doc.setTypes(m_documents[i].getTypes()); } doc.addType(m_documents[i]); m_documents[i] = doc; } else { m_documents[i].addType(doc); } return true; } else if ((m_useAttachments) && (doc.isAttachment()) && (!m_documents[i].isAttachment())) { // store attachment in temporary list to assign later m_attachments.add(doc); return true; } else if ((m_useAttachments) && (m_documents[i].isAttachment()) && (!doc.isAttachment())) { if (isOnlyVersions()) { return true; } else { m_attachments.add(m_documents[i]); m_documents[i] = doc; return true; } } else if (m_useLanguages) { // merge the document if languages are used m_documents[i] = m_documents[i].mergeDocuments(doc); return true; } } else if (isOnlyVersions()) { // this is no version of a present document, do not add it at all return true; } } return false; } /** * Converts an object to a document.<p> * * @param element the object to convert * @return the document object representation */ private CmsDocument convertDocument(Object element) { try { return (CmsDocument)element; } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Tried adding wrong object to document list " + e); } } return CmsDocument.getNullDocument(); } /** * Returns the flag if only versions of a specific document should be added to the list.<p> * * @return the flag if only versions of a specific document should be added to the list */ private boolean isOnlyVersions() { return m_onlyVersions; } /** * Check if the given index is in range. If not, throw an appropriate * runtime exception. This method does *not* check if the index is * negative: It is always used immediately prior to an array access, * which throws an ArrayIndexOutOfBoundsException if index is negative. * * @param index the index to check */ private void rangeCheck(int index) { if ((index > m_size) || (index < 0)) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + m_size); } } }