Package org.jasig.portal.channels.UserPreferences

Source Code of org.jasig.portal.channels.UserPreferences.TabColumnPrefsState

/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you 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 org.jasig.portal.channels.UserPreferences;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portal.ChannelManager;
import org.jasig.portal.ChannelRegistryManager;
import org.jasig.portal.ChannelRuntimeData;
import org.jasig.portal.ChannelSAXStreamFilter;
import org.jasig.portal.ChannelStaticData;
import org.jasig.portal.GeneralRenderingException;
import org.jasig.portal.IUserPreferencesManager;
import org.jasig.portal.PortalControlStructures;
import org.jasig.portal.PortalException;
import org.jasig.portal.PortalSessionManager;
import org.jasig.portal.StructureAttributesIncorporationFilter;
import org.jasig.portal.StructureStylesheetUserPreferences;
import org.jasig.portal.StylesheetSet;
import org.jasig.portal.UserPreferences;
import org.jasig.portal.UserProfile;
import org.jasig.portal.i18n.LocaleAwareXSLT;
import org.jasig.portal.layout.IUserLayoutManager;
import org.jasig.portal.layout.IUserLayoutStore;
import org.jasig.portal.layout.UserLayoutManagerFactory;
import org.jasig.portal.layout.UserLayoutStoreFactory;
import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
import org.jasig.portal.layout.node.IUserLayoutFolderDescription;
import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
import org.jasig.portal.layout.node.UserLayoutChannelDescription;
import org.jasig.portal.layout.node.UserLayoutFolderDescription;
import org.jasig.portal.serialize.OutputFormat;
import org.jasig.portal.serialize.XMLSerializer;
import org.jasig.portal.utils.DocumentFactory;
import org.jasig.portal.utils.ResourceLoader;
import org.jasig.portal.utils.SAX2DuplicatingFilterImpl;
import org.jasig.portal.utils.XSLT;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ContentHandler;


/**
* This user preferences component is for use with layouts based
* on the tab-column structure.
* @author Ken Weiner, kweiner@unicon.net
* @version $Revision: 19776 $
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
public class TabColumnPrefsState extends BaseState
{
    private static final Log log = LogFactory.getLog(TabColumnPrefsState.class);
  protected ChannelStaticData staticData;
  protected ChannelRuntimeData runtimeData;
  private static final String sslLocation = "/org/jasig/portal/channels/CUserPreferences/tab-column/tab-column.ssl";

  private IUserLayoutManager ulm;
  private PortalControlStructures pcs;
  private UserPreferences userPrefs;
  private UserProfile editedUserProfile;
  private static IUserLayoutStore ulStore = UserLayoutStoreFactory.getUserLayoutStoreImpl();
  private StylesheetSet set;

  private String action = "none";
  private String activeTab = "none";
  private String elementID = "none";
  private String newColumnId = null;

  // These can be overridden in a sub-class.
  protected static String BLANK_TAB_NAME = "My Tab"; // The tab will take on this name if left blank by the user
  protected static String SKINS_PATH = "media/org/jasig/portal/layout/tab-column/nested-tables";

  // Here are all the possible error messages for this channel. Maybe these should be moved to
  // a properties file or static parameters.  Actually, the error handling written so far isn't
  // very good and should be improved.  For example, there needs to be a way to let a user know that
  // he/she couldn't remove a tab because it was set as unremovable.
  private String errorMessage = "Nothing is wrong!";
  private static final String errorMessageSetActiveTab = "Problem trying to set the active tab";
  private static final String errorMessageRenameTab = "Problem trying to rename tab";
  private static final String errorMessageMoveTab = "Problem trying to move the tab";
  private static final String errorMessageAddTab = "Problem trying to add a new tab";
  private static final String errorMessageDeleteTab = "Problem trying to delete tab";
  private static final String errorMessageLockTab = "Problem trying to lock tab";
  private static final String errorMessageUnlockTab = "Problem trying to unlock tab";
  private static final String errorMessageChangeColumnWidths = "Problem changing column widths";
  private static final String errorMessageMoveColumn = "Problem trying to move column";
  private static final String errorMessageNewColumn = "Problem trying to add a new column";
  private static final String errorMessageDeleteColumn = "Problem trying to delete column";
  private static final String errorMessageNewChannel = "Problem trying to add a new channel";
  private static final String errorMessageModChannelParams = "Problem trying to modify channel parameters";
  private static final String errorMessageMoveChannel = "Problem trying to move channel";
  private static final String errorMessageDeleteChannel = "Problem trying to delete channel";

  public TabColumnPrefsState() throws PortalException
  {
    super();
    this.internalState = new DefaultState(this);

    // initialize stylesheet set
    set = new StylesheetSet(ResourceLoader.getResourceAsURLString(this.getClass(), sslLocation));
  }

  public TabColumnPrefsState(CUserPreferences context) throws PortalException
  {
    super(context);
    this.internalState = new DefaultState(this);
    // initialize stylesheet set
    set = new StylesheetSet(ResourceLoader.getResourceAsURLString(this.getClass(), sslLocation));
  }

  public void setStaticData (ChannelStaticData sd) throws PortalException
  {
    this.staticData = sd;
    this.internalState.setStaticData(sd);
  }

  public void setRuntimeData (ChannelRuntimeData rd) throws PortalException
  {
    this.runtimeData = rd;

    // See if a top-level action has been given
    String action=rd.getParameter("action");
    if (action != null) {
      if (action.equals("newChannel")) {
        if (!(internalState instanceof NewChannelState)) {
          internalState = new NewChannelState(this);
          internalState.setStaticData(staticData);
        }
      } else if (action.equals("manageSkins")) {
        if (!(internalState instanceof SelectSkinsState)) {
          internalState = new SelectSkinsState(this);
          internalState.setStaticData(staticData);
        }
      } else if (action.equals("resetLayout")) {
        if (!(internalState instanceof ResetLayoutState)) {
          internalState = new ResetLayoutState(this);
          internalState.setStaticData(staticData);
        }
      } else if (action.equals("managePreferences")) {
        internalState = new DefaultState(this);
        internalState.setStaticData(staticData);
      }
    }
    internalState.setRuntimeData(rd);

    try
    {

      // Need this check so that we don't override the column width's we just set
      if (internalState instanceof DefaultState){
        if (((DefaultState)internalState).columnHasBeenAdded)
          return;
      }

      // The profile the user is currently viewing or modifying...
      editedUserProfile = context.getEditedUserProfile();
      ulm = getUserLayoutManager();
      userPrefs = context.getUserPreferencesFromStore(editedUserProfile);
    }
    catch (Exception e)
    {
      throw new GeneralRenderingException(e);
    }
  }

  public void setPortalControlStructures(PortalControlStructures pcs) throws PortalException  {
    this.pcs = pcs;
  }

  public void renderXML(ContentHandler out) throws PortalException
  {
    if (this.internalState != null)
      this.internalState.renderXML(out);
    else
      log.error( "TabColumnPrefsState::renderXML() : No internal state!");
  }

  // Helper methods...

  private final IUserLayoutManager getUserLayoutManager() throws Exception
  {
    IUserPreferencesManager upm = context.getUserPreferencesManager();
    IUserLayoutManager lm=null;
    // If the we are editing the current user layout, get a copy of the current user layout,
    // otherwise get it from the database or other persistant storage
    if (modifyingCurrentUserLayout()) {
        // get it from the preferences manager
        lm=upm.getUserLayoutManager();
    else {
        // construct a new one
        lm=UserLayoutManagerFactory.getUserLayoutManager(upm.getPerson(),context.getCurrentUserPreferences().getProfile());
    }
    return lm;
  }

  private final String getActiveTab()
  {
    String activeTab = "none";

    try
    {
      // Get the profile associated with the layout currently being modified
      UserPreferences userPrefsFromStore = context.getUserPreferencesFromStore(context.getCurrentUserPreferences().getProfile());
      activeTab = userPrefsFromStore.getStructureStylesheetUserPreferences().getParameterValue("activeTab");
    }
    catch (Exception e)
    {
      log.error( "TabColumnPrefsState::getAcctiveTab : Unable to retrieve active tab.");
    }

    return activeTab;
  }

  private final void setActiveTab(String activeTab) throws Exception
  {
    StructureStylesheetUserPreferences ssup = userPrefs.getStructureStylesheetUserPreferences();
    ssup.putParameterValue("activeTab", activeTab);

    // Persist structure stylesheet user preferences
    int profileId = editedUserProfile.getProfileId();
    ulStore.setStructureStylesheetUserPreferences(staticData.getPerson(), profileId, ssup);
  }

  private final void renameTab(String tabId, String tabName) throws PortalException
  {
      IUserLayoutFolderDescription tab=(IUserLayoutFolderDescription)ulm.getNode(tabId);
      if(ulm.canUpdateNode(ulm.getNode(tabId))) {
          if (tabName == null || tabName.trim().length() == 0) {
              tab.setName(BLANK_TAB_NAME);
          } else {
              tab.setName(tabName);
          }
          ulm.updateNode(tab);
      } else {
          throw new PortalException("Attempt to rename immutable tab " + tabId + "has failed");
      }
  }

  private final void moveTab(String sourceTabId, String method, String destinationTabId) throws PortalException {
      // determine root folder id
      String rootNodeId=ulm.getParentId(sourceTabId);

      if(ulm.canMoveNode(sourceTabId,rootNodeId,destinationTabId)) {
          if(method.equals("insertBefore")) {
              ulm.moveNode(sourceTabId,rootNodeId,destinationTabId);
          } else {
              ulm.moveNode(sourceTabId,rootNodeId,null);
          }
      }
  }

  /**
   * Adds a new tab to the layout.
   * @param tabName the name of the tab
   * @param method either <code>insertBefore</code> or <code>appendAfter</code>
   * @param destinationTabId the column to insert the new column before or append after (may actually be a tab)
   * @throws PortalException
   */
  private final void addTab(String tabName, String method, String destinationTabId) throws PortalException
  {

    IUserLayoutFolderDescription newTab = createFolder(tabName);
    if (tabName == null || tabName.trim().length() == 0) {
        newTab.setName(BLANK_TAB_NAME);
    }
    String siblingId=null;
    if(method.equals("insertBefore"))
      siblingId=destinationTabId;
    ulm.addNode(newTab,ulm.getRootFolderId(),siblingId);

    // Add a new column to this tab
    IUserLayoutFolderDescription newColumn = createFolder("Column");
    ulm.addNode(newColumn, newTab.getId(), null);
  }

  /**
   * This method will remove a column from the user's layout.  The column will be added into the layout
   * via the "add new column" link within the preferences channel.  Clicking on cancel after choosing to add
   * a new column will not remove the column hence the introduction of this method.
   */
  private final void removeNewColumn() {
      try {
          Document doc = this.ulm.getUserLayoutDOM();
          Node nNewColumnNode = doc.getElementById(this.newColumnId);
          if (nNewColumnNode != null){
            Node parent = nNewColumnNode.getParentNode();
            parent.removeChild(nNewColumnNode);
            this.newColumnId = null;
          }
      } catch (Exception e){
          if (log.isDebugEnabled())
              log.debug("removeNewColumn failed to find new column with id "
                      + this.newColumnId);
      }
  }


  /**
   * Adds a new column into the layout.  Before the column is added,
   * a check is done to see whether the destination element is a tab.  If it is,
   * a new column is inserted first.
   * @param method either <code>insertBefore</code> or <code>appendAfter</code>
   * @param destinationElementId the column to insert the new column before or append after (may actually be a tab)
   * @throws Exception
   */
  private final void addColumn(String method, String destinationElementId) throws Exception
  {
      IUserLayoutFolderDescription newColumn = createFolder("Column");
      // Insert a column if the destination element is a tab
      if(isTab(destinationElementId)) {
          ulm.addNode(newColumn,destinationElementId,null);
      } else if(isColumn(destinationElementId)) {
          String siblingId=null;
          if(method.equals("insertBefore")) {
              siblingId=destinationElementId;
          }
          // Returns the node that was just added containing the default width of 100%
          IUserLayoutNodeDescription ulnd = ulm.addNode(newColumn,ulm.getParentId(destinationElementId),siblingId);
          // Get the current users layout
          Document doc = this.ulm.getUserLayoutDOM();
          // Keep track of the new column id incase the user clicks on cancel button
          this.newColumnId = ulnd.getId();
          Element nE = (Element)doc.getElementById(ulnd.getId());
          // Find out how many siblings this node contains
          NodeList list = nE.getParentNode().getChildNodes();
          if (list != null && list.getLength() > 0)
              this.setEvenlyAssignedColumnWidths(list);
      }
  }

  private final void changeColumnWidths(HashMap columnWidths) throws Exception
  {
    StructureStylesheetUserPreferences ssup = userPrefs.getStructureStylesheetUserPreferences();
    java.util.Set sColWidths = columnWidths.keySet();
    java.util.Iterator iterator = sColWidths.iterator();
    while(iterator.hasNext())
    {
      String folderId = (String)iterator.next();
      String newWidth = (String)columnWidths.get(folderId);

      // Only accept widths that are either percentages or integers (fixed widths)
      boolean widthIsValid = true;
      try
      {
        Integer.parseInt(newWidth.endsWith("%") ? newWidth.substring(0, newWidth.indexOf("%")) : newWidth);
      }
      catch (java.lang.NumberFormatException nfe)
      {
        widthIsValid = false;
      }

      if (widthIsValid)
        ssup.setFolderAttributeValue(folderId, "width", newWidth);
      else
        if (log.isDebugEnabled())
            log.debug("User id " + staticData.getPerson().getID() + " entered invalid column width: " + newWidth);

    }

    // Persist structure stylesheet user preferences
    saveUserPreferences();
  }

  /**
   * Moves a column from one position in the layout to another.  Before the move is performed,
   * a check is done to see whether the source and/or destination elements are tabs.  If either
   * is a tab, a new column is inserted between it and the channels that it contains before the
   * move is carried out.
   * @param sourceId the column to move (may actually be a tab)
   * @param method either <code>insertBefore</code> or <code>appendAfter</code>
   * @param destinationId the column to insert the new column before or append after (may actually be a tab)
   * @throws PortalException
   */
  private final void moveColumn(String sourceId, String method, String destinationId) throws PortalException
  {
      String siblingId=null;
      if(method.equals("insertBefore")) {
          siblingId=destinationId;
      }
      ulm.moveNode(sourceId,ulm.getParentId(destinationId),siblingId);
  }

  /**
   * Moves a channel from one position in the layout to another.
   * @param sourceChannelSubscribeId the channel to move
   * @param method either <code>insertBefore</code> or <code>appendAfter</code>
   * @param destinationElementId the ID of the channel to insert the new channel before or append after
   * @throws PortalException
   */
  private final void moveChannel(String sourceChannelSubscribeId, String method, String destinationElementId) throws PortalException
  {
      if(isTab(destinationElementId)) {
          // create a new column and move channel there
          IUserLayoutNodeDescription newColumn=ulm.addNode(createFolder("Column"),destinationElementId,null);
          ulm.moveNode(sourceChannelSubscribeId,newColumn.getId(),null);
      } else if(isColumn(destinationElementId)) {
          // move the channel into the column
          ulm.moveNode(sourceChannelSubscribeId,destinationElementId,null);
      } else {
          // assume that destinationElementId is that of a sibling channel
          String siblingId=null;
          if(method.equals("insertBefore")) {
              siblingId=destinationElementId;
          }
          ulm.moveNode(sourceChannelSubscribeId,ulm.getParentId(destinationElementId),siblingId);
      }
  }

  /**
   * Adds a channel to the layout.
   * @param newChannel the channel to add
   * @param position either <code>before</code> or <code>after</code>
   * @param destinationElementId the ID of the channel to insert the new channel before or append after
   * @throws PortalException
   */
  private final void addChannel(Element newChannel, String position, String destinationElementId) throws PortalException
  {
      IUserLayoutChannelDescription channel=new UserLayoutChannelDescription(newChannel);
      if(isTab(destinationElementId)) {
          // create a new column and move channel there
          IUserLayoutNodeDescription newColumn=ulm.addNode(createFolder("Column"),destinationElementId,null);
          ulm.addNode(channel,newColumn.getId(),null);
      } else if(isColumn(destinationElementId)) {
          // move the channel into the column
          ulm.addNode(channel,destinationElementId,null);
      } else {
          // assume that destinationElementId is that of a sibling channel
          String siblingId=null;
          if(position.equals("before")) {
              siblingId=destinationElementId;
          }
          ulm.addNode(channel,ulm.getParentId(destinationElementId),siblingId);
      }

      // Make sure ChannelManager knows about the new channel
      final ChannelManager channelManager = pcs.getChannelManager();
      channelManager.instantiateChannel(pcs.getHttpServletRequest(), pcs.getHttpServletResponse(), channel.getId());
     
      ulm.saveUserLayout();
  }

  /**
   * Adds a channel to the layout.
   * @param selectedChannelSubscribeId the channel to add
   * @param position either <code>before</code> or <code>after</code>
   * @param destinationElementId the ID of the channel to insert the new channel before or append after
   * @throws Exception
   */
  private final void addChannel(String selectedChannelSubscribeId, String position, String destinationElementId) throws Exception
  {
    Document channelRegistry = ChannelRegistryManager.getChannelRegistry(staticData.getPerson());
    Element newChannel = channelRegistry.getElementById(selectedChannelSubscribeId);
    addChannel(newChannel, position, destinationElementId);
  }

/**
   * Removes a channel element from the layout
   * @param channelSubscribeId the ID attribute of the channel to remove
   */
  private final void deleteChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) throws Exception
  {
    pcs.getChannelManager().removeChannel(request, response, channelSubscribeId);
    deleteElement(channelSubscribeId);
  }

  /**
   * Removes a tab or column element from the layout.  To remove
   * a channel element, call deleteChannel().
   * @param elementId the ID attribute of the element to remove
   */
  private final void deleteElement(String elementId) throws Exception
  {
      // Need to check if we are about to delete a column, if so, need to reset other columns to appropriate width's
      Document doc = this.ulm.getUserLayoutDOM();
      Element childElement=(Element)doc.getElementById(elementId);
      // determine if this is a column
      String whatIsThis = childElement.getAttribute("name");
      if (whatIsThis != null && whatIsThis.startsWith("Column")){
        userPrefs.getStructureStylesheetUserPreferences().removeFolder(childElement.getAttribute("ID"));
        // get the id of the parent (tab)
        String tabId = ((Element)childElement.getParentNode()).getAttribute("ID");
        // Found a column .. lets remove the column selected first
        ulm.deleteNode(elementId);
        // get the updated xml document
        doc = this.ulm.getUserLayoutDOM();
        // Find out how many siblings this node contains
        NodeList list = ((Element)doc.getElementById(tabId)).getChildNodes();
        if (list != null && list.getLength() > 0)
            this.setEvenlyAssignedColumnWidths(list);
        this.saveUserPreferences();

      } else {
        // this is a tab, go ahead and delete it
        ulm.deleteNode(elementId);
      }
  }

  /**
* @param list as a NodeList that contains all columns in current tab
*/
  private void setEvenlyAssignedColumnWidths(NodeList list) {
    // Simply divide the number of columns by 100 and produce an evenly numbered column widths
    int columns = list.getLength();
    int columnSize = 100 / columns;
    int remainder = 100 % columns;
    // Traverse through the columns and reset with the new caculated value
    StructureStylesheetUserPreferences ssup = userPrefs.getStructureStylesheetUserPreferences();
    for (int i=0; i < list.getLength(); i++){
        Element c = (Element) list.item(i);
        String nId = c.getAttribute("ID");
        ssup.setFolderAttributeValue(nId, "width", (i == (list.getLength() - 1) ? columnSize+remainder+"%" : columnSize+"%"));
    }
  }

  private final void updateTabLock(String elementId, boolean locked) throws Exception
  {
      // NOTE: this method is to be removed soon.
  }

  /**
   * A folder is a tab if its parent element is the layout element
   * @param folderId the id of the folder in question
   * @return <code>true</code> if the folder is a tab, otherwise <code>false</code>
   */
  private final boolean isTab (String folderId) throws PortalException
  {
      // we could be a bit more careful here and actually check the type
      return ulm.getRootFolderId().equals(ulm.getParentId(folderId));
  }

  /**
   * A folder is a column if its parent is a tab element
   * @param folderId the id of the folder in question
   * @return <code>true</code> if the folder is a column, otherwise <code>false</code>
   */
  private final boolean isColumn (String folderId) throws PortalException
  {
      return isTab(ulm.getParentId(folderId));
  }

  /**
   * Creates a folder element with default attributes.  This method can be used
   * to create a tab or a column.  For tabs, pass the tab name.  For column,
   * pass an empty String since column names aren't meaningful
   * @param name the tab name for tabs and an empty string for columns
   * @return the newly created tab or column
   */
  private final IUserLayoutFolderDescription createFolder (String name)
  {
    String id = "tbd";
    IUserLayoutFolderDescription folder=new UserLayoutFolderDescription();
    folder.setName(name);
    folder.setId(id);
    folder.setFolderType(IUserLayoutFolderDescription.REGULAR_TYPE);
    folder.setHidden(false);
    folder.setUnremovable(false);
    folder.setImmutable(false);
    return folder;
  }

  /**
   * Finds any parameters in a channel that are determined to be overridable
   * by a user.
   * @param channelPublishId an identifier to find the selected channel within the channel registry
   * @return a list of <parameter> elements whose override attribute is set to true
   * @throws org.jasig.portal.PortalException
   */
  private final List getOverridableChannelParams(String channelPublishId) throws PortalException {
    Document channelRegistry = ChannelRegistryManager.getChannelRegistry(staticData.getPerson());
    Element channel = (Element)channelRegistry.getElementById(channelPublishId.startsWith("chan") ? channelPublishId : "chan" + channelPublishId);
    List overridableParams = null;

    if (channel != null) {
      overridableParams = new ArrayList();

      NodeList params = channel.getElementsByTagName("parameter");
      for (int i = 0; i < params.getLength(); i++) {
        Element param = (Element)params.item(i);
        String override = param.getAttribute("override");
        if (override != null && override.equals("yes"))
          overridableParams.add(param);
      }
    } else {
      throw new PortalException("Channel " + channelPublishId + " is missing from the channel registry");
    }
    return overridableParams;
  }


  private void saveUserPreferences () throws PortalException
  {
    userPrefs.getStructureStylesheetUserPreferences().putParameterValue("userLayoutRoot", staticData.getChannelSubscribeId());
    IUserPreferencesManager upm = context.getUserPreferencesManager();
    if (modifyingCurrentUserLayout()) {
        upm.setNewUserLayoutAndUserPreferences(null, userPrefs);
    } else {
      try {
          ulStore.putUserPreferences(staticData.getPerson(), userPrefs);
      } catch (Exception e) {
        throw new PortalException(e);
      }
    }
  }

  private boolean modifyingCurrentUserLayout () throws PortalException
  {
      // check if we're editing the same layout (note: this relies on the layout Ids to be meaningful, which
      // is not entirely true with the current "template user layout" feature. Hopefully this will go away soon.
      return (context.getUserPreferencesManager().getCurrentProfile().getProfileFname().equals(editedUserProfile.getProfileFname()) && context.getUserPreferencesManager().getCurrentProfile().isSystemProfile()==editedUserProfile.isSystemProfile());
  }

  /**
   * A sub-state of TabColumnPrefsState for visualizing the user layout
   * in tab-column form.
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
  protected class DefaultState extends BaseState
  {
    private static final boolean printXMLToLog = false;
    private boolean columnHasBeenAdded = false;
    protected TabColumnPrefsState context;

    public DefaultState(TabColumnPrefsState context)
    {
      this.context = context;
    }

    public void setRuntimeData (ChannelRuntimeData rd) throws PortalException
    {
      runtimeData = rd;

      // If the user hasn't clicked on a tab, get persisted active tab
      if (activeTab.equals("none"))
        activeTab = getActiveTab();

      action = runtimeData.getParameter("action");

      if (action != null)
      {
        // Select tab
        if (action.equals("selectTab"))
          activeTab = runtimeData.getParameter("activeTab");
        // Set active tab
        else if (action.equals("setActiveTab"))
        {
          try
          {
            setActiveTab(activeTab);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageSetActiveTab;
          }
        }
        // Rename tab
        else if (action.equals("renameTab"))
        {
          try
          {
            String tabId = runtimeData.getParameter("elementID");
            String tabName = runtimeData.getParameter("tabName");

            renameTab(tabId, tabName);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageRenameTab;
          }
        }
        // Move tab
        else if (action.equals("moveTab"))
        {
          try
          {
            String methodAndID = runtimeData.getParameter("method_ID");

            if (methodAndID != null)
            {
              String sourceTabId = runtimeData.getParameter("elementID");
              int indexOf_ = methodAndID.indexOf("_");
              String method = methodAndID.substring(0, indexOf_); // insertBefore or appendAfter
              String destinationTabId = methodAndID.substring(indexOf_ + 1);

              moveTab(sourceTabId, method, destinationTabId);
            }
            else
              action = "selectTab";
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageMoveTab;
          }
        }
        // Add tab
        else if (action.equals("addTab"))
        {
          try
          {
            String tabName = runtimeData.getParameter("tabName");
            String methodAndID = runtimeData.getParameter("method_ID");

            if (methodAndID != null)
            {
              int indexOf_ = methodAndID.indexOf("_");
              String method = methodAndID.substring(0, indexOf_); // insertBefore or appendAfter
              String destinationTabId = methodAndID.substring(indexOf_ + 1);

              addTab(tabName, method, destinationTabId);
            }
            else
              action = "newTab";
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageAddTab;
          }
        }
        // Delete tab
        else if (action.equals("deleteTab"))
        {
          try
          {
            String tabId = runtimeData.getParameter("elementID");

            deleteElement(tabId);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageDeleteTab;
          }
        }
        // Lock tab
        else if (action.equals("lockTab"))
        {
          try
          {
            String tabId = runtimeData.getParameter("elementID");

            updateTabLock(tabId, true);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageLockTab;
          }
        }
        // Unlock tab
        else if (action.equals("unlockTab"))
        {
          try
          {
            String tabId = runtimeData.getParameter("elementID");

            updateTabLock(tabId, false);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageUnlockTab;
          }
        }
        // Select column
        else if (action.equals("selectColumn"))
          elementID = runtimeData.getParameter("elementID");
        // Change column width(s)
        else if (action.equals("columnWidth"))
        {
          try
          {
            HashMap columnWidths = new HashMap();
            Enumeration eParams = runtimeData.getParameterNames();
            while (eParams.hasMoreElements())
            {
              String param = (String)eParams.nextElement();
              String prefix = "columnWidth_";

              if (param.startsWith(prefix))
              {
                String folderId = param.substring(prefix.length());
                String newWidth = runtimeData.getParameter(prefix + folderId);
                columnWidths.put(folderId, newWidth);
              }
            }

            changeColumnWidths(columnWidths);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageChangeColumnWidths;
          }
        }
        // Move column
        else if (action.equals("moveColumn"))
        {
          String activeTabParam = runtimeData.getParameter("activeTab");
          if (activeTabParam != null)
            activeTab = activeTabParam;
        }
        // Move column here
        else if (action.equals("moveColumnHere"))
        {
          try
          {
            // Get the source column if this is a one-step move, otherwise we already
            // have it stored as elementID
            String sourceId = runtimeData.getParameter("sourceID");
            if (sourceId != null)
              elementID = sourceId;

            String method = runtimeData.getParameter("method");
            String destinationId = runtimeData.getParameter("elementID");

            moveColumn(elementID, method, destinationId);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageMoveColumn;
          }
        }
        // New column
        else if (action.equals("newColumn"))
        {
          try
          {
            String method = runtimeData.getParameter("method");
            elementID = runtimeData.getParameter("elementID");
            String destinationColumnId = elementID;

            addColumn(method, destinationColumnId);
            columnHasBeenAdded = true;
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageNewColumn;
          }
        }
        // Add column
        else if (action.equals("addColumn"))
        {
          // Currently not implemented...
          // We need to assign widths to columns.
          // The action addColumn isn't in the stylesheet yet.
        }
        // Delete column
        else if (action.equals("deleteColumn"))
        {
          try
          {
            String columnId = runtimeData.getParameter("elementID");

            deleteElement(columnId);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageDeleteColumn;
          }
        }
        // Select channel
        else if (action.equals("selectChannel"))
        {
          elementID = runtimeData.getParameter("elementID");

          // Modify channel parameters
          String subAction = runtimeData.getParameter("subAction");
          if (subAction != null && subAction.equals("modifyChannelParams"))
          {
            IUserLayoutChannelDescription layoutChannel=(IUserLayoutChannelDescription)ulm.getNode(elementID);
            String channelPublishId=layoutChannel.getChannelPublishId();

            Document channelRegistry = ChannelRegistryManager.getChannelRegistry(staticData.getPerson());
            Element channel = (Element)channelRegistry.getElementById("chan" + channelPublishId);
            List overridableChanParams = getOverridableChannelParams(channelPublishId);
            context.internalState = new ParametersState(context, this, overridableChanParams, channel);
            context.internalState.setStaticData(staticData);
          }
        }
        // Move channel
        else if (action.equals("moveChannel"))
        {
          String activeTabParam = runtimeData.getParameter("activeTab");
          if (activeTabParam != null)
            activeTab = activeTabParam;
        }
        // Move channel here
        else if (action.equals("moveChannelHere"))
        {
          try
          {
            // Get the source channel if this is a one-step move, otherwise we already
            // have it stored as elementID
            String sourceId = runtimeData.getParameter("sourceID");
            if (sourceId != null)
              elementID = sourceId;

            String method = runtimeData.getParameter("method");
            String destinationId = runtimeData.getParameter("elementID");

            moveChannel(elementID, method, destinationId);

            // Clear out elementId so the channel doesn't stay highlighted
            elementID = null;
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageMoveChannel;
          }
        }
        // Delete channel
        else if (action.equals("deleteChannel"))
        {
          try
          {
            String channelSubscribeId = runtimeData.getParameter("elementID");

            deleteChannel(pcs.getHttpServletRequest(), pcs.getHttpServletResponse(), channelSubscribeId);
          }
          catch (Exception e)
          {
            log.error(e, e);
            action = "error";
            errorMessage = errorMessageDeleteChannel;
          }
        }
        // Cancel
        else if (action.equals("cancel"))
        {
          elementID = "none";
          // check to see if we added a new column
          if (columnHasBeenAdded){
            removeNewColumn();
            columnHasBeenAdded = false;
          }
        }
      }
      else
        action = "none";
    }

    public void renderXML (ContentHandler out) throws PortalException {
      try {
        // Set up chain: userLayout --> Structure Attributes Incorp. Filter --> out
        TransformerFactory tFactory = TransformerFactory.newInstance();
        if (tFactory instanceof SAXTransformerFactory) {
          SAXTransformerFactory saxTFactory = (SAXTransformerFactory)tFactory;

          // Empty transformer to do the initial dom2sax transition
          Transformer emptytr = tFactory.newTransformer();

          // Stylesheet transformer
          String xslURI = set.getStylesheetURI("default", runtimeData.getBrowserInfo());

          // for i18n
          xslURI= LocaleAwareXSLT.getLocaleAwareXslUri(xslURI, runtimeData.getLocales(), this);

          TransformerHandler th = saxTFactory.newTransformerHandler(XSLT.getTemplates(ResourceLoader.getResourceAsURLString(this.getClass(), xslURI)));
          th.setResult(new SAXResult(out));
          Transformer sstr = th.getTransformer();

          // Set the parameters
          sstr.setParameter("baseActionURL", runtimeData.getBaseActionURL());
          sstr.setParameter("activeTab", activeTab);
          sstr.setParameter("action", action);
          sstr.setParameter("elementID", elementID != null ? elementID : "none");
          sstr.setParameter("errorMessage", errorMessage);

          StructureStylesheetUserPreferences ssup = userPrefs.getStructureStylesheetUserPreferences();
          StructureAttributesIncorporationFilter saif = new StructureAttributesIncorporationFilter(th, ssup);

          // Put a duplicating filter before th
          StringWriter sw = null;
          OutputFormat outputFormat = null;
          if (printXMLToLog) {
            sw = new StringWriter();
            outputFormat = new OutputFormat();
            outputFormat.setIndenting(true);
            XMLSerializer debugSerializer = new XMLSerializer(sw, outputFormat);
            SAX2DuplicatingFilterImpl dupFilter = new SAX2DuplicatingFilterImpl(th, debugSerializer);
            dupFilter.setParent(saif);
          }

          // Incorporate channel registry document into userLayout if user is in the subscribe process
          if (action.equals("newChannel")) {
            Node channelRegistry = ChannelRegistryManager.getChannelRegistry(staticData.getPerson()).getDocumentElement();
            // start document manually
            saif.startDocument();
            // output layout
            ulm.getUserLayout(new ChannelSAXStreamFilter((ContentHandler)saif));
            emptytr.transform(new DOMSource(channelRegistry),new SAXResult(new ChannelSAXStreamFilter((ContentHandler)saif)));
            // end document manually
            saif.endDocument();
          } else {
              //if (action.equals("moveChannelHere"))
              //System.out.println(org.jasig.portal.utils.XML.serializeNode(userLayout));

              // Begin SAX chain
              //          emptytr.transform(new DOMSource(), new SAXResult(saif));
              ulm.getUserLayout((ContentHandler)saif);
          }

          // Debug piece to print out the recorded pre-structure transformation XML
          if (printXMLToLog) {
            log.debug("TablColumnPrefsState::renderXML() : XML incoming to the structure transformation :\n\n" + sw.toString() + "\n\n");
          }

        } else {
          log.error( "TablColumnPrefsState::renderXML() : Unable to obtain SAX Transformer Factory ! Check your TRAX configuration.");
        }
      } catch (Exception e) {
        log.error(e, e);
        throw new GeneralRenderingException(e);
      }
    }
  }

  /**
   * A sub-state of TabColumnPrefsState for resetting layout
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
  protected class ResetLayoutState extends BaseState
  {
    protected TabColumnPrefsState context;

    public ResetLayoutState(TabColumnPrefsState context) {
      this.context = context;
    }

    public void setRuntimeData(ChannelRuntimeData rd) throws PortalException {
      try {
        editedUserProfile.setLayoutId(0);
        ulStore.updateUserProfile(staticData.getPerson(), editedUserProfile);
        ulm.loadUserLayout();
      } catch (Exception e) {
        throw new PortalException(e);
      }
      // return to the default state
      BaseState df = new DefaultState(context);
      df.setStaticData(staticData);
      context.setState(df);
    }
  }


  /**
   * A sub-state of TabColumnPrefsState for selecting skins
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
  protected class SelectSkinsState extends BaseState
  {
    protected TabColumnPrefsState context;

    public SelectSkinsState(TabColumnPrefsState context) {
        this.context = context;
    }

    public void setRuntimeData (ChannelRuntimeData rd) throws PortalException {
        runtimeData = rd;
        String action = runtimeData.getParameter("action");
        if (action != null) {
            if (runtimeData.getParameter("submitSave")!=null) {
                // save
                String skinName = runtimeData.getParameter("skinName");
                userPrefs.getThemeStylesheetUserPreferences().putParameterValue("skin",skinName);
                // save user preferences
                saveUserPreferences();
                // reset state
                BaseState df=new DefaultState(context);
                df.setStaticData(staticData);
                context.setState(df);
            } else if (runtimeData.getParameter("submitCancel")!=null) {
                // return to the default state
                BaseState df=new DefaultState(context);
                df.setStaticData(staticData);
                context.setState(df);
            }
        }
    }

    public void renderXML (ContentHandler out) throws PortalException
    {
      InputStream xmlStream = null;
    try {
      xmlStream = PortalSessionManager.getResourceAsStream(SKINS_PATH + "/skinList.xml");
      String currentSkin = userPrefs.getThemeStylesheetUserPreferences().getParameterValue("skin");

      XSLT xslt = XSLT.getTransformer(this, runtimeData.getLocales());
      xslt.setXML(xmlStream);
      xslt.setXSL(sslLocation, "skinList", runtimeData.getBrowserInfo());
      xslt.setTarget(out);
      xslt.setStylesheetParameter("skinsPath", SKINS_PATH);
      xslt.setStylesheetParameter("baseActionURL", runtimeData.getBaseActionURL());
      if(currentSkin!=null)
        xslt.setStylesheetParameter("currentSkin", currentSkin);
      xslt.transform();
      } finally {
        try {
          if (xmlStream != null)
            xmlStream.close();
        } catch (IOException exception) {
          log.error("TabColumnPrefsState:renderXML()::unable to close InputStream ", exception);
        }
      }
    }
  }

  /**
   * A sub-state of TabColumnPrefsState for choosing a new channel (formerly subscribe)
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
  protected class NewChannelState extends BaseState
  {
    protected TabColumnPrefsState context;
    private String position = "none";
    private String catID = "top";

    public NewChannelState(TabColumnPrefsState context) {
      this.context = context;
    }

    public void setRuntimeData (ChannelRuntimeData rd) throws PortalException {
      runtimeData = rd;
      String action = runtimeData.getParameter("action");
      if (action != null) {
        if (action.equals("cancel")) {
          returnToDefaultState();
        } else {
          // User clicked "?"
          if (runtimeData.getParameter("channelMoreInfo") != null) {
            // Implement channel preview here!
            String selectedChannel = runtimeData.getParameter("selectedChannel");
            // Do more...
          } else if (runtimeData.getParameter("addChannel") != null) {
            // User clicked "Add"
            String selectedChannel = runtimeData.getParameter("selectedChannel");
            if (selectedChannel != null) {
              try {
                // Determine whether channel has overridable parameters
                List overridableChanParams = getOverridableChannelParams(selectedChannel);
                if (overridableChanParams.isEmpty()) {
                  addChannel(selectedChannel, position, elementID);
                  returnToDefaultState();
                } else { // present user with screen to specify subscribe-time params
                  Document channelRegistry = ChannelRegistryManager.getChannelRegistry(staticData.getPerson());
                  Element channel = (Element)channelRegistry.getElementById(selectedChannel);
                  context.internalState = new ParametersState(context, this, overridableChanParams, channel, position, elementID);
                  context.internalState.setStaticData(staticData);
                }
              } catch (Exception e) {
                errorMessage = errorMessageNewChannel;
              }
            }
          } else {
            // Collect the position and element ID the first time
            String passedPosition = runtimeData.getParameter("position");
            String passedElementID = runtimeData.getParameter("elementID");
            if (passedPosition != null)
              position = passedPosition;
            if (passedElementID != null)
              elementID = passedElementID;

            // User clicked "Go"
            String selectedCategory = runtimeData.getParameter("selectedCategory");
            if (selectedCategory != null  && selectedCategory.trim().length() > 0)
              catID = selectedCategory;
          }
        }
      }
    }

    public void renderXML (ContentHandler out) throws PortalException
    {
      Document doc = ChannelRegistryManager.getChannelRegistry(staticData.getPerson());

      XSLT xslt = XSLT.getTransformer(this, runtimeData.getLocales());
      xslt.setXML(doc);
      xslt.setXSL(sslLocation, "newChannel", runtimeData.getBrowserInfo());
      xslt.setTarget(out);
      xslt.setStylesheetParameter("baseActionURL", runtimeData.getBaseActionURL());
      xslt.setStylesheetParameter("elementID", elementID);
      xslt.setStylesheetParameter("position", position);
      xslt.setStylesheetParameter("catID", catID);
      xslt.setStylesheetParameter("errorMessage", errorMessage);
      xslt.transform();
    }

    private void returnToDefaultState() throws PortalException {
      // Reset global variables
      elementID = "none";
      position = "none";
      action = "none";

      BaseState defaultState = new DefaultState(context);
      defaultState.setStaticData(staticData);
      context.setState(defaultState);
    }
  }

  /**
   * A sub-state of TabColumnPrefsState for setting channel parameters
* @deprecated All IChannel implementations should be migrated to portlets
*/
@Deprecated
  protected class ParametersState extends BaseState
  {
    protected TabColumnPrefsState context;
    protected BaseState previousState;
    private List overridableChanParams;
    private Element registryChannel;
    private String position;
    private String destinationElementId;

    private boolean error = false;

    public ParametersState(TabColumnPrefsState context, BaseState previousState, List overridableChanParams, Element registryChannel) {
      this.context = context;
      this.previousState = previousState;
      this.overridableChanParams = overridableChanParams;
      this.registryChannel = registryChannel;
    }

    public ParametersState(TabColumnPrefsState context, BaseState previousState, List overridableChanParams, Element registryChannel, String position, String destinationElementId) {
      this(context, previousState, overridableChanParams, registryChannel);
      this.position = position;
      this.destinationElementId = destinationElementId;
    }

    public void setRuntimeData (ChannelRuntimeData rd) throws PortalException {
      runtimeData = rd;
      String action = runtimeData.getParameter("uPTCUP_action");
      if (action != null) {
        if (action.equals("back")) {
          context.setState(previousState);
        } else if (action.equals("finished")) {
          applyChanges(); // Add or modify the channel
          returnToDefaultState();
        } else if (action.equals("cancel")) {
          returnToDefaultState();
        }
      }
    }

    public void renderXML (ContentHandler out) throws PortalException
    {
      XSLT xslt = XSLT.getTransformer(this, runtimeData.getLocales());
      xslt.setXML(getParametersDoc());
      xslt.setXSL(sslLocation, "parameters", runtimeData.getBrowserInfo());
      xslt.setTarget(out);
      xslt.setStylesheetParameter("baseActionURL", runtimeData.getBaseActionURL());
      if (error)
        xslt.setStylesheetParameter("errorMessage", errorMessage);
      xslt.transform();
    }

    private void returnToDefaultState() throws PortalException {
      // Reset global variables
        elementID = "none";
        position = "none";
        action = "none";

      BaseState defaultState = new DefaultState(context);
      defaultState.setStaticData(staticData);
      context.setState(defaultState);
    }

    private void applyChanges() {
      // Finally, add the channel to the layout or modify it if it is already there
      try {
        if (previousState instanceof NewChannelState) {
          processParams(registryChannel);
          context.addChannel(registryChannel, position, destinationElementId);
        }
        else if (previousState instanceof DefaultState) {
          updateParams((IUserLayoutChannelDescription)ulm.getNode(elementID));
        }

      } catch (Exception e) {
        error = true;
        errorMessage = errorMessageModChannelParams;
      }
    }

    private void updateParams(IUserLayoutChannelDescription cd) throws PortalException {
      // Process params
      Iterator iter = overridableChanParams.iterator();
      while (iter.hasNext()) {
        Element parameterE = (Element)iter.next();
        String paramName = parameterE.getAttribute("name");
        String paramValue = runtimeData.getParameter(paramName);
        cd.setParameterValue(paramName, paramValue);
      }
      ulm.updateNode(cd);
    }

    private void processParams(Element channel) {
      // Process params
      Iterator iter = overridableChanParams.iterator();
      while (iter.hasNext()) {
        Element parameterE = (Element)iter.next();
        String paramName = parameterE.getAttribute("name");
        String paramValue = runtimeData.getParameter(paramName);

        // Find param within channel and update it
        NodeList params = channel.getElementsByTagName("parameter");
        for (int i = 0; i < params.getLength(); i++) {
          Element paramE = (Element)params.item(i);
          if (paramE.getAttribute("name").equals(paramName)) {
            paramE.setAttribute("value", paramValue);
            break;
          }
        }
      }
    }

    private Document getParametersDoc() throws PortalException {
      Document doc = DocumentFactory.getNewDocument();

      // Top-level element
      Element userPrefParamsE = doc.createElement("userPrefParams");

      if (previousState instanceof NewChannelState)
        userPrefParamsE.appendChild(doc.importNode(registryChannel, true));
      else if (previousState instanceof DefaultState) {
        IUserLayoutNodeDescription node=ulm.getNode(elementID);
        userPrefParamsE.appendChild(node.getXML(doc));
      }

      // CPD
      Document cpd = ChannelRegistryManager.getCPD(registryChannel.getAttribute("typeID"));
      if (cpd != null)
        userPrefParamsE.appendChild(doc.importNode(cpd.getDocumentElement(), true));

      doc.appendChild(userPrefParamsE);
      return doc;
    }
  }

}
TOP

Related Classes of org.jasig.portal.channels.UserPreferences.TabColumnPrefsState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.