0001: /* Copyright 2002 The JA-SIG Collaborative. All rights reserved.
0002: * See license distributed with this file and
0003: * available online at http://www.uportal.org/license.html
0004: */
0005:
0006: package org.jasig.portal.channels.DLMUserPreferences;
0007:
0008: import java.io.IOException;
0009: import java.io.InputStream;
0010: import java.io.StringWriter;
0011: import java.util.ArrayList;
0012: import java.util.Enumeration;
0013: import java.util.HashMap;
0014: import java.util.Iterator;
0015: import java.util.List;
0016: import java.util.Map;
0017: import java.util.ResourceBundle;
0018: import java.util.Map.Entry;
0019:
0020: import javax.xml.transform.Templates;
0021: import javax.xml.transform.Transformer;
0022: import javax.xml.transform.TransformerFactory;
0023: import javax.xml.transform.dom.DOMSource;
0024: import javax.xml.transform.sax.SAXResult;
0025: import javax.xml.transform.sax.SAXTransformerFactory;
0026: import javax.xml.transform.sax.TransformerHandler;
0027:
0028: import org.jasig.portal.ChannelDefinition;
0029: import org.jasig.portal.ChannelParameter;
0030: import org.jasig.portal.ChannelRegistryManager;
0031: import org.jasig.portal.ChannelRegistryStoreFactory;
0032: import org.jasig.portal.ChannelRuntimeData;
0033: import org.jasig.portal.ChannelSAXStreamFilter;
0034: import org.jasig.portal.ChannelStaticData;
0035: import org.jasig.portal.GeneralRenderingException;
0036: import org.jasig.portal.IChannelRegistryStore;
0037: import org.jasig.portal.IUserPreferencesManager;
0038: import org.jasig.portal.PortalControlStructures;
0039: import org.jasig.portal.PortalException;
0040: import org.jasig.portal.PortalSessionManager;
0041: import org.jasig.portal.StructureAttributesIncorporationFilter;
0042: import org.jasig.portal.StructureStylesheetUserPreferences;
0043: import org.jasig.portal.StylesheetSet;
0044: import org.jasig.portal.UserPreferences;
0045: import org.jasig.portal.UserProfile;
0046: import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
0047: import org.jasig.portal.layout.node.IUserLayoutFolderDescription;
0048: import org.jasig.portal.layout.IUserLayoutManager;
0049: import org.jasig.portal.layout.IUserLayoutStore;
0050: import org.jasig.portal.layout.UserLayoutStoreFactory;
0051: import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
0052: import org.jasig.portal.layout.node.UserLayoutChannelDescription;
0053: import org.jasig.portal.layout.node.UserLayoutFolderDescription;
0054: import org.jasig.portal.layout.UserLayoutManagerFactory;
0055: import org.jasig.portal.layout.dlm.ChannelDescription;
0056: import org.jasig.portal.layout.dlm.Constants;
0057: import org.jasig.portal.layout.dlm.UserPrefsHandler;
0058: import org.jasig.portal.security.IPerson;
0059: import org.jasig.portal.serialize.OutputFormat;
0060: import org.jasig.portal.serialize.XMLSerializer;
0061: import org.apache.commons.logging.Log;
0062: import org.apache.commons.logging.LogFactory;
0063: import org.jasig.portal.utils.DocumentFactory;
0064: import org.jasig.portal.utils.ResourceLoader;
0065: import org.jasig.portal.utils.SAX2DuplicatingFilterImpl;
0066: import org.jasig.portal.utils.XSLT;
0067: import org.w3c.dom.Document;
0068: import org.w3c.dom.Element;
0069: import org.w3c.dom.Node;
0070: import org.xml.sax.ContentHandler;
0071:
0072: /**
0073: * This user preferences component is for use with layouts based
0074: * on the tab-column structure.
0075: * @author Ken Weiner, kweiner@interactivebusiness.com
0076: * @version $Revision: 36535 $
0077: */
0078: public class TabColumnPrefsState extends BaseState {
0079: private static final Log log = LogFactory
0080: .getLog(TabColumnPrefsState.class);
0081: protected ChannelStaticData staticData;
0082: protected ChannelRuntimeData runtimeData;
0083: private static final String sslLocation = "/org/jasig/portal/channels/DLMUserPreferences/tab-column/tab-column.ssl";
0084: private static final String bundleBaseLocation = "/org/jasig/portal/channels/DLMUserPreferences/tab-column/";
0085:
0086: private IUserLayoutManager ulm;
0087: private PortalControlStructures pcs;
0088: private UserPreferences userPrefs;
0089: private UserProfile editedUserProfile;
0090: private static IUserLayoutStore ulStore = UserLayoutStoreFactory
0091: .getUserLayoutStoreImpl();
0092: private StylesheetSet set;
0093:
0094: private String action = "none";
0095: private String activeTab = "none";
0096: private String elementID = "none";
0097:
0098: // These can be overridden in a sub-class.
0099: protected static String BLANK_TAB_NAME = "My Tab"; // The tab will take on this name if left blank by the user
0100: protected static String SKIN_LIST_FILE = "media/org/jasig/portal/layout/tab-column/xhtml-theme/skinList.xml";
0101: /**
0102: * Configuration Object to read resource bundle property values for I18N
0103: */
0104:
0105: // Here are all the possible error messages for this channel. Maybe these should be moved to
0106: // a properties file or static parameters. Actually, the error handling written so far isn't
0107: // very good and should be improved. For example, there needs to be a way to let a user know that
0108: // he/she couldn't remove a tab because it was set as unremovable.
0109: private String errorMessage = "Nothing is wrong!";
0110: private static final String errorMessageSetActiveTab = "Problem trying to set the active tab";
0111: private static final String errorMessageRenameTab = "Problem trying to rename tab";
0112: private static final String errorMessageMoveTab = "Problem trying to move the tab";
0113: private static final String errorMessageAddTab = "Problem trying to add a new tab";
0114: private static final String errorMessageDeleteTab = "Problem trying to delete tab";
0115: private static final String errorMessageLockTab = "Problem trying to lock tab";
0116: private static final String errorMessageUnlockTab = "Problem trying to unlock tab";
0117: private static final String errorMessageChangeColumnWidths = "Problem changing column widths";
0118: private static final String errorMessageMoveColumn = "Problem trying to move column";
0119: private static final String errorMessageNewColumn = "Problem trying to add a new column";
0120: private static final String errorMessageDeleteColumn = "Problem trying to delete column";
0121: private static final String errorMessageNewChannel = "Problem trying to add a new channel";
0122: private static final String errorMessageModChannelParams = "Problem trying to modify channel parameters";
0123: private static final String errorMessageMoveChannel = "Problem trying to move channel";
0124: private static final String errorMessageDeleteChannel = "Problem trying to delete channel";
0125:
0126: public TabColumnPrefsState() throws PortalException {
0127: super ();
0128: this .internalState = new DefaultState(this );
0129:
0130: // initialize stylesheet set
0131: set = new StylesheetSet(ResourceLoader.getResourceAsURLString(
0132: this .getClass(), sslLocation));
0133: }
0134:
0135: public TabColumnPrefsState(CUserPreferences context)
0136: throws PortalException {
0137: super (context);
0138: this .internalState = new DefaultState(this );
0139: // initialize stylesheet set
0140: set = new StylesheetSet(ResourceLoader.getResourceAsURLString(
0141: this .getClass(), sslLocation));
0142: }
0143:
0144: public void setStaticData(ChannelStaticData sd)
0145: throws PortalException {
0146: this .staticData = sd;
0147: this .internalState.setStaticData(sd);
0148: }
0149:
0150: public void setRuntimeData(ChannelRuntimeData rd)
0151: throws PortalException {
0152: this .runtimeData = rd;
0153:
0154: // See if a top-level action has been given
0155: String action = rd.getParameter("action");
0156: if (action != null) {
0157: if (action.equals("newChannel")) {
0158: if (!(internalState instanceof NewChannelState)) {
0159: internalState = new NewChannelState(this );
0160: internalState.setStaticData(staticData);
0161: }
0162: } else if (action.equals("manageSkins")) {
0163: if (!(internalState instanceof SelectSkinsState)) {
0164: internalState = new SelectSkinsState(this );
0165: internalState.setStaticData(staticData);
0166: }
0167: } else if (action.equals("resetLayout")) {
0168: if (!(internalState instanceof ResetLayoutState)) {
0169: internalState = new ResetLayoutState(this );
0170: internalState.setStaticData(staticData);
0171: }
0172: } else if (action.equals("managePreferences")) {
0173: internalState = new DefaultState(this );
0174: internalState.setStaticData(staticData);
0175: }
0176: }
0177: internalState.setRuntimeData(rd);
0178:
0179: try {
0180: // The profile the user is currently viewing or modifying...
0181: editedUserProfile = context.getEditedUserProfile();
0182: ulm = getUserLayoutManager();
0183: userPrefs = context
0184: .getUserPreferencesFromStore(editedUserProfile);
0185: } catch (Exception e) {
0186: throw new GeneralRenderingException(e);
0187: }
0188: }
0189:
0190: public void setPortalControlStructures(PortalControlStructures pcs)
0191: throws PortalException {
0192: this .pcs = pcs;
0193: }
0194:
0195: public void renderXML(ContentHandler out) throws PortalException {
0196: if (this .internalState != null)
0197: this .internalState.renderXML(out);
0198: else
0199: log.error("No internal state!");
0200: }
0201:
0202: // Helper methods...
0203:
0204: private final IUserLayoutManager getUserLayoutManager()
0205: throws Exception {
0206: IUserPreferencesManager upm = context
0207: .getUserPreferencesManager();
0208: IUserLayoutManager lm = null;
0209: // If the we are editing the current user layout, get a copy of the current user layout,
0210: // otherwise get it from the database or other persistant storage
0211: if (modifyingCurrentUserLayout()) {
0212: // get it from the preferences manager
0213: lm = upm.getUserLayoutManager();
0214: } else {
0215: // construct a new one
0216: lm = UserLayoutManagerFactory.getUserLayoutManager(upm
0217: .getPerson(), context.getCurrentUserPreferences()
0218: .getProfile());
0219: }
0220: return lm;
0221: }
0222:
0223: private final String getActiveTab() {
0224: String activeTab = "none";
0225:
0226: try {
0227: // Get the profile associated with the layout currently being modified
0228: UserPreferences userPrefsFromStore = context
0229: .getUserPreferencesFromStore(context
0230: .getCurrentUserPreferences().getProfile());
0231: activeTab = userPrefsFromStore
0232: .getStructureStylesheetUserPreferences()
0233: .getParameterValue("activeTab");
0234: } catch (Exception e) {
0235: log.error("Unable to retrieve active tab.");
0236: }
0237:
0238: return activeTab;
0239: }
0240:
0241: private final void setActiveTab(String activeTab) throws Exception {
0242: StructureStylesheetUserPreferences ssup = userPrefs
0243: .getStructureStylesheetUserPreferences();
0244: ssup.putParameterValue("activeTab", activeTab);
0245:
0246: // Persist structure stylesheet user preferences
0247: int profileId = editedUserProfile.getProfileId();
0248: ulStore.setStructureStylesheetUserPreferences(staticData
0249: .getPerson(), profileId, ssup);
0250: }
0251:
0252: private final void renameTab(String tabId, String tabName)
0253: throws PortalException {
0254: IUserLayoutFolderDescription tab = (IUserLayoutFolderDescription) ulm
0255: .getNode(tabId);
0256: if (ulm.canUpdateNode(ulm.getNode(tabId))) {
0257: if (tabName == null || tabName.trim().length() == 0) {
0258: tab.setName(BLANK_TAB_NAME);
0259: } else {
0260: tab.setName(tabName);
0261: }
0262: ulm.updateNode(tab);
0263: } else {
0264:
0265: throw new PortalException("attempt.to.rename.immutable.tab"
0266: + tabId);
0267: }
0268: saveLayout(false);
0269: }
0270:
0271: private boolean getRestriction(String val) {
0272: // This seems kind of backwards but is correct. The checkboxes are
0273: // labeled "X Allowed" and if checked the values here are "true". If
0274: // not checked then no value is submitted for that checkbox resulting
0275: // in a null value here.
0276:
0277: if (val == null || !val.equals("true"))
0278: return false;
0279: return true;
0280: }
0281:
0282: private final void changeRestrictions(String id,
0283: String moveAllowed, String editAllowed,
0284: String addChildAllowed, String deleteAllowed)
0285: throws Exception {
0286: IUserLayoutNodeDescription node = ulm.getNode(id);
0287:
0288: node.setDeleteAllowed(getRestriction(deleteAllowed));
0289: node.setMoveAllowed(getRestriction(moveAllowed));
0290:
0291: if (node instanceof UserLayoutFolderDescription) {
0292: UserLayoutFolderDescription fldr = null;
0293: fldr = (UserLayoutFolderDescription) node;
0294: fldr.setEditAllowed(getRestriction(editAllowed));
0295: fldr.setAddChildAllowed(getRestriction(addChildAllowed));
0296: }
0297: ulm.updateNode(node);
0298: saveLayout(false);
0299: }
0300:
0301: private final void moveTab(String sourceTabId, String method,
0302: String destinationTabId) throws PortalException {
0303: // determine root folder id
0304: String rootNodeId = ulm.getParentId(sourceTabId);
0305:
0306: if (ulm.canMoveNode(sourceTabId, rootNodeId, destinationTabId)) {
0307: if (method.equals("insertBefore")) {
0308: ulm.moveNode(sourceTabId, rootNodeId, destinationTabId);
0309: } else {
0310: ulm.moveNode(sourceTabId, rootNodeId, null);
0311: }
0312: saveLayout(false);
0313: }
0314: }
0315:
0316: /**
0317: * Adds a new tab to the layout.
0318: * @param tabName the name of the tab
0319: * @param method either <code>insertBefore</code> or <code>appendAfter</code>
0320: * @param destinationTabId the column to insert the new column before or append after (may actually be a tab)
0321: * @throws PortalException
0322: */
0323: private final void addTab(String tabName, String method,
0324: String destinationTabId) throws PortalException {
0325: IUserLayoutFolderDescription newTab = createFolder(tabName);
0326:
0327: if (tabName == null || tabName.trim().length() == 0) {
0328: newTab.setName(BLANK_TAB_NAME);
0329: }
0330: String siblingId = null;
0331: if (method.equals("insertBefore"))
0332: siblingId = destinationTabId;
0333: ulm.addNode(newTab, ulm.getRootFolderId(), siblingId);
0334:
0335: saveLayout(false);
0336: }
0337:
0338: /**
0339: * Adds a new column into the layout. Before the column is added,
0340: * a check is done to see whether the destination element is a tab. If it is,
0341: * a new column is inserted first.
0342: * @param method either <code>insertBefore</code> or <code>appendAfter</code>
0343: * @param destinationElementId the column to insert the new column before or append after (may actually be a tab)
0344: * @throws Exception
0345: */
0346: private final void addColumn(String method,
0347: String destinationElementId) throws Exception {
0348: IUserLayoutFolderDescription newColumn = createFolder("Column");
0349: // Insert a column if the destination element is a tab
0350: if (isTab(destinationElementId)) {
0351: ulm.addNode(newColumn, destinationElementId, null);
0352: } else if (isColumn(destinationElementId)) {
0353: String siblingId = null;
0354: if (method.equals("insertBefore")) {
0355: siblingId = destinationElementId;
0356: }
0357: ulm.addNode(newColumn, ulm
0358: .getParentId(destinationElementId), siblingId);
0359: }
0360: saveLayout(false);
0361: }
0362:
0363: private final void changeColumnWidths(HashMap columnWidths)
0364: throws Exception {
0365: // Must get from store because the one in memory is comtaminated with stylesheet params
0366: // that shouldn't get persisted
0367: //UserPreferences userPrefsFromStore = context.getUserPreferencesFromStore(context.getCurrentUserPreferences().getProfile());
0368: //StructureStylesheetUserPreferences ssup = userPrefsFromStore.getStructureStylesheetUserPreferences();
0369: StructureStylesheetUserPreferences ssup = userPrefs
0370: .getStructureStylesheetUserPreferences();
0371:
0372: /*
0373: userPrefs is loaded directly from the database not copied from the
0374: UserPreferencesManager's value. As such it does not contain current
0375: session values like the structure stylesheet parameter userLayoutRoot
0376: which tells the rendering engine the node id that should be displayed
0377: in focused mode. While in preferences this node id is the node id of the
0378: preferences channel. That is a session value and should not be preserved.
0379: But the UserPreferencesManager's structure stylesheet user preferences
0380: object is being replaced by the version that we have here so that column
0381: width changes take immediate affect. Therefore, after persisting them we
0382: need to push the value of the userLayoutRoot node back into the
0383: preferences now held by the UserPreferencesManager so that the
0384: preferences channel remains in focus after changing the column widths.
0385: */
0386: String focusedNode = context.getUserPreferencesManager()
0387: .getUserPreferences()
0388: .getStructureStylesheetUserPreferences()
0389: .getParameterValue("userLayoutRoot");
0390: String activeTab = context.getUserPreferencesManager()
0391: .getUserPreferences()
0392: .getStructureStylesheetUserPreferences()
0393: .getParameterValue("activeTab");
0394:
0395: java.util.Set sColWidths = columnWidths.keySet();
0396: java.util.Iterator iterator = sColWidths.iterator();
0397: while (iterator.hasNext()) {
0398: String folderId = (String) iterator.next();
0399: String newWidth = (String) columnWidths.get(folderId);
0400:
0401: // Only accept widths that are either percentages or integers (fixed widths)
0402: boolean widthIsValid = true;
0403: try {
0404: Integer
0405: .parseInt(newWidth.endsWith("%") ? newWidth
0406: .substring(0, newWidth.indexOf("%"))
0407: : newWidth);
0408: } catch (java.lang.NumberFormatException nfe) {
0409: widthIsValid = false;
0410: }
0411:
0412: if (widthIsValid) {
0413: ssup.setFolderAttributeValue(folderId, "width",
0414: newWidth);
0415: Element folder = ulm.getUserLayoutDOM().getElementById(
0416: folderId);
0417: UserPrefsHandler.setUserPreference(folder, "width",
0418: staticData.getPerson());
0419: } else if (log.isDebugEnabled())
0420: log.debug("User id " + staticData.getPerson().getID()
0421: + " entered invalid column width: " + newWidth);
0422:
0423: }
0424:
0425: // Persist structure stylesheet user preferences
0426: saveUserPreferences();
0427: saveLayout(false);
0428:
0429: // now push the focused node value back into new rendering prefs object.
0430: ssup.putParameterValue("userLayoutRoot", focusedNode);
0431:
0432: if (activeTab != null)
0433: ssup.putParameterValue("activeTab", activeTab);
0434: }
0435:
0436: /**
0437: * Moves a column from one position in the layout to another. Before the move is performed,
0438: * a check is done to see whether the source and/or destination elements are tabs. If either
0439: * is a tab, a new column is inserted between it and the channels that it contains before the
0440: * move is carried out.
0441: * @param sourceId the column to move (may actually be a tab)
0442: * @param method either <code>insertBefore</code> or <code>appendAfter</code>
0443: * @param destinationId the column to insert the new column before or append after (may actually be a tab)
0444: * @throws PortalException
0445: */
0446: private final void moveColumn(String sourceId, String method,
0447: String destinationId) throws PortalException {
0448: String siblingId = null;
0449: if (method.equals("insertBefore")) {
0450: siblingId = destinationId;
0451: }
0452: ulm.moveNode(sourceId, ulm.getParentId(destinationId),
0453: siblingId);
0454: saveLayout(false);
0455: }
0456:
0457: /**
0458: * Moves a channel from one position in the layout to another.
0459: * @param sourceChannelSubscribeId the channel to move
0460: * @param method either <code>insertBefore</code> or <code>appendAfter</code>
0461: * @param destinationElementId the ID of the channel to insert the new channel before or append after
0462: * @throws PortalException
0463: */
0464: private final void moveChannel(String sourceChannelSubscribeId,
0465: String method, String destinationElementId)
0466: throws PortalException {
0467: if (isTab(destinationElementId)) {
0468: // create a new column and move channel there
0469: IUserLayoutNodeDescription newColumn = ulm.addNode(
0470: createFolder("Column"), destinationElementId, null);
0471: ulm.moveNode(sourceChannelSubscribeId, newColumn.getId(),
0472: null);
0473: } else if (isColumn(destinationElementId)) {
0474: // move the channel into the column
0475: ulm.moveNode(sourceChannelSubscribeId,
0476: destinationElementId, null);
0477: } else {
0478: // assume that destinationElementId is that of a sibling channel
0479: String siblingId = null;
0480: if (method.equals("insertBefore")) {
0481: siblingId = destinationElementId;
0482: }
0483: ulm.moveNode(sourceChannelSubscribeId, ulm
0484: .getParentId(destinationElementId), siblingId);
0485: }
0486: saveLayout(false);
0487: }
0488:
0489: /**
0490: * Adds a channel to the layout.
0491: * @param channel the channel to add
0492: * @param position either <code>before</code> or <code>after</code>
0493: * @param destinationElementId the ID of the channel to insert the new channel before or append after
0494: * @throws PortalException
0495: */
0496: private final void addChannel(
0497: IUserLayoutChannelDescription channel, String position,
0498: String destinationElementId) throws PortalException {
0499: if (isTab(destinationElementId)) {
0500: // create a new column and move channel there
0501: IUserLayoutNodeDescription newColumn = ulm.addNode(
0502: createFolder("Column"), destinationElementId, null);
0503: ulm.addNode(channel, newColumn.getId(), null);
0504: } else if (isColumn(destinationElementId)) {
0505: // move the channel into the column
0506: ulm.addNode(channel, destinationElementId, null);
0507: } else {
0508: // assume that destinationElementId is that of a sibling channel
0509: String siblingId = null;
0510: if (position.equals("before")) {
0511: siblingId = destinationElementId;
0512: }
0513: ulm.addNode(channel, ulm.getParentId(destinationElementId),
0514: siblingId);
0515: }
0516:
0517: // Make sure ChannelManager knows about the new channel
0518: pcs.getChannelManager().instantiateChannel(channel.getId());
0519: saveLayout(true);
0520: }
0521:
0522: /**
0523: * Adds a channel to the layout.
0524: * @param newChannel the channel to add
0525: * @param position either <code>before</code> or <code>after</code>
0526: * @param destinationElementId the ID of the channel to insert the new channel before or append after
0527: * @throws PortalException
0528: */
0529: private final void addChannel(Element newChannel, String position,
0530: String destinationElementId) throws PortalException {
0531: IUserLayoutChannelDescription channel = new UserLayoutChannelDescription(
0532: newChannel);
0533: addChannel(channel, position, destinationElementId);
0534: }
0535:
0536: /**
0537: * Adds a channel to the layout.
0538: * @param selectedChannelSubscribeId the channel to add
0539: * @param position either <code>before</code> or <code>after</code>
0540: * @param destinationElementId the ID of the channel to insert the new channel before or append after
0541: * @throws Exception
0542: */
0543: private final void addChannel(String selectedChannelSubscribeId,
0544: String position, String destinationElementId)
0545: throws Exception {
0546: Document channelRegistry = ChannelRegistryManager
0547: .getChannelRegistry(staticData.getPerson());
0548: Element newChannel = channelRegistry
0549: .getElementById(selectedChannelSubscribeId);
0550: addChannel(newChannel, position, destinationElementId);
0551: }
0552:
0553: /**
0554: * Removes a channel element from the layout
0555: * @param channelSubscribeId the ID attribute of the channel to remove
0556: */
0557: private final void deleteChannel(String channelSubscribeId)
0558: throws Exception {
0559: deleteElement(channelSubscribeId);
0560: }
0561:
0562: /**
0563: * Removes a tab or column element from the layout. To remove
0564: * a channel element, call deleteChannel().
0565: * @param elementId the ID attribute of the element to remove
0566: */
0567: private final void deleteElement(String elementId) throws Exception {
0568: ulm.deleteNode(elementId);
0569: saveLayout(false);
0570: }
0571:
0572: private final void updateTabLock(String elementId, boolean locked)
0573: throws Exception {
0574: // NOTE: this method is to be removed soon.
0575: /*
0576: Element element = userLayout.getElementById(elementId);
0577: if(locked)
0578: {
0579: element.setAttribute("unremovable", "true");
0580: element.setAttribute("immutable", "true");
0581: }
0582: else
0583: {
0584: element.setAttribute("unremovable", "false");
0585: element.setAttribute("immutable", "false");
0586: }
0587: saveLayout(false);
0588: */
0589: }
0590:
0591: /**
0592: * A folder is a tab if its parent element is the layout element
0593: * @param folder the folder in question
0594: * @return <code>true</code> if the folder is a tab, otherwise <code>false</code>
0595: */
0596: private final boolean isTab(String folderId) throws PortalException {
0597: // we could be a bit more careful here and actually check the type
0598: return ulm.getRootFolderId().equals(ulm.getParentId(folderId));
0599: }
0600:
0601: /**
0602: * A folder is a column if its parent is a tab element
0603: * @param folder the folder in question
0604: * @return <code>true</code> if the folder is a column, otherwise <code>false</code>
0605: */
0606: private final boolean isColumn(String folderId)
0607: throws PortalException {
0608: return isTab(ulm.getParentId(folderId));
0609: }
0610:
0611: /**
0612: * Creates a folder element with default attributes. This method can be used
0613: * to create a tab or a column. For tabs, pass the tab name. For column,
0614: * pass an empty String since column names aren't meaningful
0615: * @param name the tab name for tabs and an empty string for columns
0616: * @return the newly created tab or column
0617: */
0618: private final IUserLayoutFolderDescription createFolder(String name) {
0619: String id = "tbd";
0620: IUserLayoutFolderDescription folder = new UserLayoutFolderDescription();
0621: folder.setName(name);
0622: folder.setId(id);
0623: folder.setFolderType(IUserLayoutFolderDescription.REGULAR_TYPE);
0624: folder.setHidden(false);
0625: folder.setUnremovable(false);
0626: folder.setImmutable(false);
0627: return folder;
0628: }
0629:
0630: /**
0631: * Finds any parameters in a channel that are determined to be overridable
0632: * by a user.
0633: * @param channelPublishId an identifier to find the selected channel within the channel registry
0634: * @return a list of <parameter> elements whose override attribute is set to true
0635: * @throws org.jasig.portal.PortalException
0636: */
0637: private final List getOverridableChannelParams(
0638: String channelPublishId) throws PortalException {
0639: List overridableParams = null;
0640: ChannelParameter parms[] = getChannelDefParams(channelPublishId);
0641:
0642: if (parms != null && parms.length > 0) {
0643: overridableParams = new ArrayList();
0644: for (int p = 0; p < parms.length; p++) {
0645: if (parms[p].getOverride())
0646: overridableParams.add(parms[p]);
0647: }
0648: }
0649: return overridableParams;
0650: }
0651:
0652: /**
0653: * For a channel already located in the user's layout this method finds any
0654: * parameters that are overridable by the user.
0655: *
0656: * @param channelDesc
0657: * the IUserLayoutChannelDescription representing the channel
0658: * in the user's layout.
0659: * @return a list of Channel<parameter>elements whose override attribute is set to
0660: * true
0661: * @throws org.jasig.portal.PortalException
0662: */
0663: private final List getOverridableChannelParams(
0664: IUserLayoutChannelDescription channelDesc)
0665: throws PortalException {
0666: // get params in channel description in the layout which can be a super
0667: // set of those defined in the publish-time definition due to the
0668: // addition of fragment or user added adhoc values. Then pass through
0669: // the definition adding overrideable parms to the list and removing
0670: // the corresponding value from the description map. Any remaining in
0671: // the description map represent adhoc ones and should be added to the
0672: // list.
0673:
0674: List overridableParams = null;
0675: Map descParms = new HashMap(channelDesc.getParameterMap());
0676: ChannelParameter parms[] = getChannelDefParams(channelDesc
0677: .getChannelPublishId());
0678:
0679: if (parms != null && parms.length > 0) {
0680: overridableParams = new ArrayList();
0681: for (int p = 0; p < parms.length; p++) {
0682: if (parms[p].getOverride())
0683: overridableParams.add(parms[p]);
0684: descParms.remove(parms[p].getName());
0685: }
0686: }
0687: if (descParms.size() > 0) {
0688: if (overridableParams == null)
0689: overridableParams = new ArrayList();
0690:
0691: // description map is a map of name value pairs. need to convert to
0692: // ChannelParameter instances.
0693: for (Iterator i = descParms.entrySet().iterator(); i
0694: .hasNext();) {
0695: Map.Entry e = (Entry) i.next();
0696: String name = (String) e.getKey();
0697: String value = (String) e.getValue();
0698: ChannelParameter parm = new ChannelParameter(name,
0699: value, true);
0700: overridableParams.add(parm);
0701: }
0702: }
0703: return overridableParams;
0704: }
0705:
0706: /**
0707: * Return the list of publish-time-specified channel parameters.
0708: *
0709: * @param id
0710: * @return
0711: * @throws PortalException
0712: */
0713: private ChannelParameter[] getChannelDefParams(String id)
0714: throws PortalException {
0715: IChannelRegistryStore crs = ChannelRegistryStoreFactory
0716: .getChannelRegistryStoreImpl();
0717: id = id.startsWith("chan") ? id.substring(4) : id;
0718: int pubId = Integer.parseInt(id);
0719: ChannelDefinition def = null;
0720: try {
0721: def = crs.getChannelDefinition(pubId);
0722: } catch (Exception e) {
0723: throw new PortalException(
0724: "unable.to.load.channel.definition " + id, e);
0725: }
0726: return def.getParameters();
0727: }
0728:
0729: private void saveLayout(boolean channelsAdded)
0730: throws PortalException {
0731: ulm.saveUserLayout();
0732: }
0733:
0734: private void saveUserPreferences() throws PortalException {
0735: IUserPreferencesManager upm = context
0736: .getUserPreferencesManager();
0737: if (modifyingCurrentUserLayout()) {
0738: upm.setNewUserLayoutAndUserPreferences(null, userPrefs);
0739: } else {
0740: try {
0741: ulStore.putUserPreferences(staticData.getPerson(),
0742: userPrefs);
0743: } catch (Exception e) {
0744: throw new PortalException(e);
0745: }
0746: }
0747: }
0748:
0749: private boolean modifyingCurrentUserLayout() throws PortalException {
0750: // check if we're editing the same layout (note: this relies on the layout Ids to be meaningful, which
0751: // is not entirely true with the current "template user layout" feature. Hopefully this will go away soon.
0752: return (context.getUserPreferencesManager().getCurrentProfile()
0753: .getProfileId() == editedUserProfile.getProfileId() && context
0754: .getUserPreferencesManager().getCurrentProfile()
0755: .isSystemProfile() == editedUserProfile
0756: .isSystemProfile());
0757: }
0758:
0759: /**
0760: * A sub-state of TabColumnPrefsState for visualizing the user layout
0761: * in tab-column form.
0762: */
0763: protected class DefaultState extends BaseState {
0764: private static final boolean printXMLToLog = false;
0765:
0766: protected TabColumnPrefsState context;
0767:
0768: public DefaultState(TabColumnPrefsState context) {
0769: this .context = context;
0770: }
0771:
0772: public void setRuntimeData(ChannelRuntimeData rd)
0773: throws PortalException {
0774: runtimeData = rd;
0775:
0776: // If the user hasn't clicked on a tab, get persisted active tab
0777: if (activeTab.equals("none"))
0778: activeTab = getActiveTab();
0779:
0780: action = runtimeData.getParameter("action");
0781:
0782: if (action != null) {
0783: // Select tab
0784: if (action.equals("selectTab"))
0785: activeTab = runtimeData.getParameter("activeTab");
0786: // Set active tab
0787: else if (action.equals("setActiveTab")) {
0788: try {
0789: setActiveTab(activeTab);
0790: } catch (Exception e) {
0791: log.error(e, e);
0792: action = "error";
0793: errorMessage = errorMessageSetActiveTab;
0794: }
0795: }
0796: // Change tab restrictions
0797: else if (action.equals("changePermissions")) {
0798: try {
0799: String elementId = runtimeData
0800: .getParameter("elementID");
0801: String moveAllowed = runtimeData
0802: .getParameter("moveAllowed");
0803: String editAllowed = runtimeData
0804: .getParameter("editAllowed");
0805: String addChildAllowed = runtimeData
0806: .getParameter("addChildAllowed");
0807: String deleteAllowed = runtimeData
0808: .getParameter("deleteAllowed");
0809: changeRestrictions(elementId, moveAllowed,
0810: editAllowed, addChildAllowed,
0811: deleteAllowed);
0812: } catch (Exception e) {
0813: log.error(e, e);
0814: action = "error";
0815: errorMessage = errorMessageRenameTab;
0816: }
0817: }
0818: // Rename tab
0819: else if (action.equals("renameTab")) {
0820: try {
0821: String tabId = runtimeData
0822: .getParameter("elementID");
0823: String tabName = runtimeData
0824: .getParameter("tabName");
0825:
0826: renameTab(tabId, tabName);
0827: } catch (Exception e) {
0828: log.error(e, e);
0829: action = "error";
0830: errorMessage = errorMessageRenameTab;
0831: }
0832: }
0833: // Move tab
0834: else if (action.equals("moveTab")) {
0835: try {
0836: String methodAndID = runtimeData
0837: .getParameter("method_ID");
0838:
0839: if (methodAndID != null) {
0840: String sourceTabId = runtimeData
0841: .getParameter("elementID");
0842: int indexOf_ = methodAndID.indexOf("_");
0843: String method = methodAndID.substring(0,
0844: indexOf_); // insertBefore or appendAfter
0845: String destinationTabId = methodAndID
0846: .substring(indexOf_ + 1);
0847:
0848: moveTab(sourceTabId, method,
0849: destinationTabId);
0850: } else
0851: action = "selectTab";
0852: } catch (Exception e) {
0853: log.error(e, e);
0854: action = "error";
0855: errorMessage = errorMessageMoveTab;
0856: }
0857: }
0858: // Add tab
0859: else if (action.equals("addTab")) {
0860: try {
0861: String tabName = runtimeData
0862: .getParameter("tabName");
0863: String methodAndID = runtimeData
0864: .getParameter("method_ID");
0865:
0866: if (methodAndID != null) {
0867: int indexOf_ = methodAndID.indexOf("_");
0868: String method = methodAndID.substring(0,
0869: indexOf_); // insertBefore or appendAfter
0870: String destinationTabId = methodAndID
0871: .substring(indexOf_ + 1);
0872:
0873: addTab(tabName, method, destinationTabId);
0874: } else
0875: action = "newTab";
0876: } catch (Exception e) {
0877: log.error(e, e);
0878: action = "error";
0879: errorMessage = errorMessageAddTab;
0880: }
0881: }
0882: // Delete tab
0883: else if (action.equals("deleteTab")) {
0884: try {
0885: String tabId = runtimeData
0886: .getParameter("elementID");
0887:
0888: deleteElement(tabId);
0889: } catch (Exception e) {
0890: log.error(e, e);
0891: action = "error";
0892: errorMessage = errorMessageDeleteTab;
0893: }
0894: }
0895: // Lock tab
0896: else if (action.equals("lockTab")) {
0897: try {
0898: String tabId = runtimeData
0899: .getParameter("elementID");
0900:
0901: updateTabLock(tabId, true);
0902: } catch (Exception e) {
0903: log.error(e, e);
0904: action = "error";
0905: errorMessage = errorMessageLockTab;
0906: }
0907: }
0908: // Unlock tab
0909: else if (action.equals("unlockTab")) {
0910: try {
0911: String tabId = runtimeData
0912: .getParameter("elementID");
0913:
0914: updateTabLock(tabId, false);
0915: } catch (Exception e) {
0916: log.error(e, e);
0917: action = "error";
0918: errorMessage = errorMessageUnlockTab;
0919: }
0920: }
0921: // Select column
0922: else if (action.equals("selectColumn"))
0923: elementID = runtimeData.getParameter("elementID");
0924: // Change column width(s)
0925: else if (action.equals("columnWidth")) {
0926: try {
0927: HashMap columnWidths = new HashMap();
0928: Enumeration eParams = runtimeData
0929: .getParameterNames();
0930: while (eParams.hasMoreElements()) {
0931: String param = (String) eParams
0932: .nextElement();
0933: String prefix = "columnWidth_";
0934:
0935: if (param.startsWith(prefix)) {
0936: String folderId = param
0937: .substring(prefix.length());
0938: String newWidth = runtimeData
0939: .getParameter(prefix + folderId);
0940: columnWidths.put(folderId, newWidth);
0941: }
0942: }
0943:
0944: changeColumnWidths(columnWidths);
0945: } catch (Exception e) {
0946: log.error(e, e);
0947: action = "error";
0948: errorMessage = errorMessageChangeColumnWidths;
0949: }
0950: }
0951: // Move column
0952: else if (action.equals("moveColumn")) {
0953: String activeTabParam = runtimeData
0954: .getParameter("activeTab");
0955: if (activeTabParam != null)
0956: activeTab = activeTabParam;
0957: }
0958: // Move column here
0959: else if (action.equals("moveColumnHere")) {
0960: try {
0961: // Get the source column if this is a one-step move, otherwise we already
0962: // have it stored as elementID
0963: String sourceId = runtimeData
0964: .getParameter("sourceID");
0965: if (sourceId != null)
0966: elementID = sourceId;
0967:
0968: String method = runtimeData
0969: .getParameter("method");
0970: String destinationId = runtimeData
0971: .getParameter("elementID");
0972:
0973: moveColumn(elementID, method, destinationId);
0974: } catch (Exception e) {
0975: log.error(e, e);
0976: action = "error";
0977: errorMessage = errorMessageMoveColumn;
0978: }
0979: }
0980: // New column
0981: else if (action.equals("newColumn")) {
0982: try {
0983: String method = runtimeData
0984: .getParameter("method");
0985: elementID = runtimeData
0986: .getParameter("elementID");
0987: String destinationColumnId = elementID;
0988:
0989: addColumn(method, destinationColumnId);
0990: } catch (Exception e) {
0991: log.error(e, e);
0992: action = "error";
0993: errorMessage = errorMessageNewColumn;
0994: }
0995: }
0996: // Add column
0997: else if (action.equals("addColumn")) {
0998: // Currently not implemented...
0999: // We need to assign widths to columns.
1000: // The action addColumn isn't in the stylesheet yet.
1001: }
1002: // Delete column
1003: else if (action.equals("deleteColumn")) {
1004: try {
1005: String columnId = runtimeData
1006: .getParameter("elementID");
1007:
1008: deleteElement(columnId);
1009: } catch (Exception e) {
1010: log.error(e, e);
1011: action = "error";
1012: errorMessage = errorMessageDeleteColumn;
1013: }
1014: }
1015: // Select channel
1016: else if (action.equals("selectChannel")) {
1017: elementID = runtimeData.getParameter("elementID");
1018:
1019: // Modify channel parameters
1020: String subAction = runtimeData
1021: .getParameter("subAction");
1022: if (subAction != null
1023: && subAction.equals("modifyChannelParams")) {
1024: IUserLayoutChannelDescription layoutChannel = (IUserLayoutChannelDescription) ulm
1025: .getNode(elementID);
1026: List overridableChanParams = getOverridableChannelParams(layoutChannel);
1027: context.internalState = new ParametersState(
1028: context, this , overridableChanParams,
1029: layoutChannel);
1030: context.internalState.setStaticData(staticData);
1031: }
1032: }
1033: // Move channel
1034: else if (action.equals("moveChannel")) {
1035: String activeTabParam = runtimeData
1036: .getParameter("activeTab");
1037: if (activeTabParam != null)
1038: activeTab = activeTabParam;
1039: }
1040: // Move channel here
1041: else if (action.equals("moveChannelHere")) {
1042: try {
1043: // Get the source channel if this is a one-step move, otherwise we already
1044: // have it stored as elementID
1045: String sourceId = runtimeData
1046: .getParameter("sourceID");
1047: if (sourceId != null)
1048: elementID = sourceId;
1049:
1050: String method = runtimeData
1051: .getParameter("method");
1052: String destinationId = runtimeData
1053: .getParameter("elementID");
1054:
1055: moveChannel(elementID, method, destinationId);
1056:
1057: // Clear out elementId so the channel doesn't stay highlighted
1058: elementID = null;
1059: } catch (Exception e) {
1060: log.error(e, e);
1061: action = "error";
1062: errorMessage = errorMessageMoveChannel;
1063: }
1064: }
1065: // Delete channel
1066: else if (action.equals("deleteChannel")) {
1067: try {
1068: String channelSubscribeId = runtimeData
1069: .getParameter("elementID");
1070:
1071: deleteChannel(channelSubscribeId);
1072: } catch (Exception e) {
1073: log.error(e, e);
1074: action = "error";
1075: errorMessage = errorMessageDeleteChannel;
1076: }
1077: }
1078: // Cancel
1079: else if (action.equals("cancel")) {
1080: elementID = "none";
1081: }
1082: } else
1083: action = "none";
1084: }
1085:
1086: public void renderXML(ContentHandler out)
1087: throws PortalException {
1088: try {
1089: // Set up chain: userLayout --> Structure Attributes Incorp. Filter --> out
1090: TransformerFactory tFactory = TransformerFactory
1091: .newInstance();
1092: if (tFactory instanceof SAXTransformerFactory) {
1093: SAXTransformerFactory saxTFactory = (SAXTransformerFactory) tFactory;
1094:
1095: // Empty transformer to do the initial dom2sax transition
1096: Transformer emptytr = tFactory.newTransformer();
1097:
1098: // Stylesheet transformer
1099: String xslURI = set.getStylesheetURI("default",
1100: runtimeData.getBrowserInfo());
1101:
1102: // removed for DLM version of prefs channel.
1103: // use the ResourceBundle approach that the community is going to
1104: //xslURI= LocaleAwareXSLT.getLocaleAwareXslUri(xslURI, runtimeData.getLocales(), this);
1105: String urlString = ResourceLoader
1106: .getResourceAsURLString(this .getClass(),
1107: xslURI);
1108: ResourceBundle bundle = ResourceBundle.getBundle(
1109: bundleBaseLocation + "default", runtimeData
1110: .getLocales()[0]);
1111:
1112: Templates templates = XSLT.getTemplates(urlString,
1113: bundle);
1114: TransformerHandler th = saxTFactory
1115: .newTransformerHandler(templates);
1116: th.setResult(new SAXResult(out));
1117: Transformer sstr = th.getTransformer();
1118:
1119: // Set the parameters
1120: sstr.setParameter("baseActionURL", runtimeData
1121: .getBaseActionURL());
1122: sstr.setParameter("activeTab", activeTab);
1123: sstr.setParameter("action", action);
1124: sstr.setParameter("elementID",
1125: elementID != null ? elementID : "none");
1126: sstr.setParameter("errorMessage", errorMessage);
1127:
1128: StructureStylesheetUserPreferences ssup = userPrefs
1129: .getStructureStylesheetUserPreferences();
1130: StructureAttributesIncorporationFilter saif = new StructureAttributesIncorporationFilter(
1131: th, ssup);
1132:
1133: // Put a duplicating filter before th
1134: StringWriter sw = null;
1135: OutputFormat outputFormat = null;
1136: if (printXMLToLog) {
1137: sw = new StringWriter();
1138: outputFormat = new OutputFormat();
1139: outputFormat.setIndenting(true);
1140: XMLSerializer debugSerializer = new XMLSerializer(
1141: sw, outputFormat);
1142: SAX2DuplicatingFilterImpl dupFilter = new SAX2DuplicatingFilterImpl(
1143: th, debugSerializer);
1144: dupFilter.setParent(saif);
1145: }
1146:
1147: // Incorporate channel registry document into userLayout if user is in the subscribe process
1148: if (action.equals("newChannel")) {
1149: Node channelRegistry = ChannelRegistryManager
1150: .getChannelRegistry(
1151: staticData.getPerson())
1152: .getDocumentElement();
1153: // start document manually
1154: saif.startDocument();
1155: // output layout
1156: ulm.getUserLayout(new ChannelSAXStreamFilter(
1157: (ContentHandler) saif));
1158: emptytr
1159: .transform(
1160: new DOMSource(channelRegistry),
1161: new SAXResult(
1162: new ChannelSAXStreamFilter(
1163: (ContentHandler) saif)));
1164: // end document manually
1165: saif.endDocument();
1166: } else {
1167: //if (action.equals("moveChannelHere"))
1168: //System.out.println(org.jasig.portal.utils.XML.serializeNode(userLayout));
1169:
1170: // Begin SAX chain
1171: // emptytr.transform(new DOMSource(), new SAXResult(saif));
1172: ulm.getUserLayout((ContentHandler) saif);
1173: }
1174:
1175: // Debug piece to print out the recorded pre-structure transformation XML
1176: if (printXMLToLog) {
1177:
1178: log.debug("incoming.xml.for.transformation "
1179: + sw.toString());
1180: }
1181:
1182: } else {
1183: log.error("unable.to.obtain.SAX.Transformer");
1184: }
1185: } catch (Exception e) {
1186: log.error(e, e);
1187: throw new GeneralRenderingException(e);
1188: }
1189: }
1190: }
1191:
1192: /**
1193: * A sub-state of TabColumnPrefsState for resetting layout
1194: */
1195: protected class ResetLayoutState extends BaseState {
1196: protected TabColumnPrefsState context;
1197:
1198: public ResetLayoutState(TabColumnPrefsState context) {
1199: this .context = context;
1200: }
1201:
1202: public void setRuntimeData(ChannelRuntimeData rd)
1203: throws PortalException {
1204: try {
1205: IPerson user = staticData.getPerson();
1206: editedUserProfile.setLayoutId(0);
1207: ulStore.updateUserProfile(user, editedUserProfile);
1208: user.setAttribute(Constants.PLF, null);
1209: ulm.loadUserLayout();
1210: } catch (Exception e) {
1211: throw new PortalException(e);
1212: }
1213: // return to the default state
1214: BaseState df = new DefaultState(context);
1215: df.setStaticData(staticData);
1216: context.setState(df);
1217: }
1218: }
1219:
1220: /**
1221: * A sub-state of TabColumnPrefsState for selecting skins
1222: */
1223: protected class SelectSkinsState extends BaseState {
1224: protected TabColumnPrefsState context;
1225:
1226: public SelectSkinsState(TabColumnPrefsState context) {
1227: this .context = context;
1228: }
1229:
1230: public void setRuntimeData(ChannelRuntimeData rd)
1231: throws PortalException {
1232: runtimeData = rd;
1233: String action = runtimeData.getParameter("action");
1234: if (action != null) {
1235: if (runtimeData.getParameter("submitSave") != null) {
1236: // save
1237: String skinName = runtimeData
1238: .getParameter("skinName");
1239: userPrefs.getThemeStylesheetUserPreferences()
1240: .putParameterValue("skin", skinName);
1241: // save user preferences ?
1242: saveUserPreferences();
1243: // reset state
1244: BaseState df = new DefaultState(context);
1245: df.setStaticData(staticData);
1246: context.setState(df);
1247: } else if (runtimeData.getParameter("submitCancel") != null) {
1248: // return to the default state
1249: BaseState df = new DefaultState(context);
1250: df.setStaticData(staticData);
1251: context.setState(df);
1252: }
1253: }
1254: }
1255:
1256: public void renderXML(ContentHandler out)
1257: throws PortalException {
1258: InputStream xmlStream = null;
1259: try {
1260: xmlStream = PortalSessionManager
1261: .getResourceAsStream(SKIN_LIST_FILE);
1262: String currentSkin = userPrefs
1263: .getThemeStylesheetUserPreferences()
1264: .getParameterValue("skin");
1265:
1266: XSLT xslt = XSLT.getTransformer(this , runtimeData
1267: .getLocales());
1268: ResourceBundle bundle = ResourceBundle.getBundle(
1269: bundleBaseLocation + "skinlist", runtimeData
1270: .getLocales()[0]);
1271: xslt.setResourceBundle(bundle);
1272: xslt.setXML(xmlStream);
1273: xslt.setXSL(sslLocation, "skinList", runtimeData
1274: .getBrowserInfo());
1275: xslt.setTarget(out);
1276: xslt.setStylesheetParameter("baseActionURL",
1277: runtimeData.getBaseActionURL());
1278: if (currentSkin != null)
1279: xslt.setStylesheetParameter("currentSkin",
1280: currentSkin);
1281: xslt.transform();
1282: } finally {
1283: try {
1284: if (xmlStream != null)
1285: xmlStream.close();
1286: } catch (IOException exception) {
1287: log
1288: .error(
1289: "TabColumnPrefsState:renderXML()::unalbe to close InputStream ",
1290: exception);
1291: }
1292: }
1293: }
1294: }
1295:
1296: /**
1297: * A sub-state of TabColumnPrefsState for choosing a new channel (formerly subscribe)
1298: */
1299: protected class NewChannelState extends BaseState {
1300: protected TabColumnPrefsState context;
1301: private String position = "none";
1302: private String catID = "top";
1303:
1304: public NewChannelState(TabColumnPrefsState context) {
1305: this .context = context;
1306: }
1307:
1308: public void setRuntimeData(ChannelRuntimeData rd)
1309: throws PortalException {
1310: runtimeData = rd;
1311: String action = runtimeData.getParameter("action");
1312: if (action != null) {
1313: if (action.equals("cancel")) {
1314: returnToDefaultState();
1315: } else {
1316: // User clicked "?"
1317: if (runtimeData.getParameter("channelMoreInfo") != null) {
1318: // Implement channel preview here!
1319: String selectedChannel = runtimeData
1320: .getParameter("selectedChannel");
1321: // Do more...
1322: } else if (runtimeData.getParameter("addChannel") != null) {
1323: // User clicked "Add"
1324: String selectedChannel = runtimeData
1325: .getParameter("selectedChannel");
1326: if (selectedChannel != null) {
1327: try {
1328: // Determine whether channel has overridable parameters
1329: List overridableChanParams = getOverridableChannelParams(selectedChannel);
1330: if (overridableChanParams == null
1331: || overridableChanParams
1332: .isEmpty()) {
1333: addChannel(selectedChannel,
1334: position, elementID);
1335: returnToDefaultState();
1336: } else { // present user with screen to specify subscribe-time params
1337: Document channelRegistry = ChannelRegistryManager
1338: .getChannelRegistry(staticData
1339: .getPerson());
1340: Element channel = channelRegistry
1341: .getElementById(selectedChannel);
1342: /*
1343: * The next line is tightly coupled to DLM which is ok since
1344: * this is the DLM version of the prefs channel. But if we
1345: * rework the ILayoutManager interface to create an
1346: * implementation independant approach to instantiating
1347: * channel descriptions we wouldn't have to tighly couple.
1348: */
1349: ChannelDescription newChannel = new ChannelDescription(
1350: channel);
1351: context.internalState = new ParametersState(
1352: context, this ,
1353: overridableChanParams,
1354: newChannel, position,
1355: elementID);
1356: context.internalState
1357: .setStaticData(staticData);
1358: }
1359: } catch (Exception e) {
1360: log
1361: .error(
1362: "Problem occurred adding Channel.",
1363: e);
1364: errorMessage = errorMessageNewChannel;
1365: }
1366: }
1367: } else {
1368: // Collect the position and element ID the first time
1369: String passedPosition = runtimeData
1370: .getParameter("position");
1371: String passedElementID = runtimeData
1372: .getParameter("elementID");
1373: if (passedPosition != null)
1374: position = passedPosition;
1375: if (passedElementID != null)
1376: elementID = passedElementID;
1377:
1378: // User clicked "Go"
1379: String selectedCategory = runtimeData
1380: .getParameter("selectedCategory");
1381: if (selectedCategory != null
1382: && selectedCategory.trim().length() > 0)
1383: catID = selectedCategory;
1384: }
1385: }
1386: }
1387: }
1388:
1389: public void renderXML(ContentHandler out)
1390: throws PortalException {
1391: Document doc = ChannelRegistryManager
1392: .getChannelRegistry(staticData.getPerson());
1393:
1394: XSLT xslt = XSLT.getTransformer(this , runtimeData
1395: .getLocales());
1396: ResourceBundle bundle = ResourceBundle.getBundle(
1397: bundleBaseLocation + "newChannel", runtimeData
1398: .getLocales()[0]);
1399: xslt.setResourceBundle(bundle);
1400: xslt.setXML(doc);
1401: xslt.setXSL(sslLocation, "newChannel", runtimeData
1402: .getBrowserInfo());
1403: xslt.setTarget(out);
1404: xslt.setStylesheetParameter("baseActionURL", runtimeData
1405: .getBaseActionURL());
1406: xslt.setStylesheetParameter("elementID", elementID);
1407: xslt.setStylesheetParameter("position", position);
1408: xslt.setStylesheetParameter("catID", catID);
1409: xslt.setStylesheetParameter("errorMessage", errorMessage);
1410: xslt.transform();
1411:
1412: }
1413:
1414: private void returnToDefaultState() throws PortalException {
1415: // Reset global variables
1416: elementID = "none";
1417: position = "none";
1418: action = "none";
1419:
1420: BaseState defaultState = new DefaultState(context);
1421: defaultState.setStaticData(staticData);
1422: context.setState(defaultState);
1423: }
1424: }
1425:
1426: /**
1427: * A sub-state of TabColumnPrefsState for setting channel parameters
1428: */
1429: protected class ParametersState extends BaseState {
1430: protected TabColumnPrefsState context;
1431: protected BaseState previousState;
1432: private List overridableChanParams;
1433: private IUserLayoutChannelDescription channelDesc;
1434: private String position;
1435: private String destinationElementId;
1436:
1437: private boolean error = false;
1438:
1439: public ParametersState(TabColumnPrefsState context,
1440: BaseState previousState, List overridableChanParams,
1441: IUserLayoutChannelDescription channelDesc) {
1442: this .context = context;
1443: this .previousState = previousState;
1444: this .overridableChanParams = overridableChanParams;
1445: this .channelDesc = channelDesc;
1446: }
1447:
1448: public ParametersState(TabColumnPrefsState context,
1449: BaseState previousState, List overridableChanParams,
1450: IUserLayoutChannelDescription channelDesc,
1451: String position, String destinationElementId) {
1452: this (context, previousState, overridableChanParams,
1453: channelDesc);
1454: this .position = position;
1455: this .destinationElementId = destinationElementId;
1456: }
1457:
1458: public void setRuntimeData(ChannelRuntimeData rd)
1459: throws PortalException {
1460: runtimeData = rd;
1461: String action = runtimeData.getParameter("uPTCUP_action");
1462: if (action != null) {
1463: if (action.equals("back")) {
1464: context.setState(previousState);
1465: } else if (action.equals("finished")) {
1466: applyChanges(); // Add or modify the channel
1467: returnToDefaultState();
1468: } else if (action.equals("cancel")) {
1469: returnToDefaultState();
1470: }
1471: }
1472: }
1473:
1474: public void renderXML(ContentHandler out)
1475: throws PortalException {
1476: try {
1477: XSLT xslt = XSLT.getTransformer(this , runtimeData
1478: .getLocales());
1479: ResourceBundle bundle = ResourceBundle.getBundle(
1480: bundleBaseLocation + "parameters", runtimeData
1481: .getLocales()[0]);
1482: xslt.setResourceBundle(bundle);
1483: xslt.setXML(getParametersDoc());
1484: xslt.setXSL(sslLocation, "parameters", runtimeData
1485: .getBrowserInfo());
1486: xslt.setTarget(out);
1487: xslt.setStylesheetParameter("baseActionURL",
1488: runtimeData.getBaseActionURL());
1489: if (error)
1490: xslt.setStylesheetParameter("errorMessage",
1491: errorMessage);
1492: xslt.transform();
1493: } catch (Exception e) {
1494: log.error(e, e);
1495: }
1496: }
1497:
1498: private void returnToDefaultState() throws PortalException {
1499: // Reset global variables
1500: elementID = "none";
1501: position = "none";
1502: action = "none";
1503:
1504: BaseState defaultState = new DefaultState(context);
1505: defaultState.setStaticData(staticData);
1506: context.setState(defaultState);
1507: }
1508:
1509: private void applyChanges() {
1510: // Finally, add the channel to the layout or modify it if it is already there
1511: try {
1512: if (previousState instanceof NewChannelState) {
1513: processParams();
1514: context.addChannel(channelDesc, position,
1515: destinationElementId);
1516: } else if (previousState instanceof DefaultState) {
1517: updateParams((IUserLayoutChannelDescription) ulm
1518: .getNode(elementID));
1519: }
1520:
1521: } catch (Exception e) {
1522: error = true;
1523: errorMessage = errorMessageModChannelParams;
1524: }
1525: }
1526:
1527: private void updateParams(IUserLayoutChannelDescription cd)
1528: throws PortalException {
1529: // Process params
1530: Iterator iter = overridableChanParams.iterator();
1531: while (iter.hasNext()) {
1532: ChannelParameter parm = (ChannelParameter) iter.next();
1533: String paramValue = runtimeData.getParameter(parm
1534: .getName());
1535: cd.setParameterValue(parm.getName(), paramValue);
1536: }
1537: ulm.updateNode(cd);
1538: context.saveLayout(false);
1539: }
1540:
1541: private void processParams() {
1542: // Process params by passing through the overrideable parms list and
1543: // pushing the submitted value for that param into the description
1544: Iterator iter = overridableChanParams.iterator();
1545: while (iter.hasNext()) {
1546: ChannelParameter parm = (ChannelParameter) iter.next();
1547: String paramValue = runtimeData.getParameter(parm
1548: .getName());
1549: channelDesc.setParameterValue(parm.getName(),
1550: paramValue);
1551: }
1552: }
1553:
1554: private Document getParametersDoc() throws PortalException {
1555: Document doc = DocumentFactory.getNewDocument();
1556:
1557: // Top-level element
1558: Element userPrefParamsE = doc
1559: .createElement("userPrefParams");
1560:
1561: if (previousState instanceof NewChannelState)
1562: userPrefParamsE.appendChild(channelDesc.getXML(doc));
1563: else if (previousState instanceof DefaultState) {
1564: IUserLayoutNodeDescription node = ulm
1565: .getNode(elementID);
1566: userPrefParamsE.appendChild(node.getXML(doc));
1567: }
1568:
1569: // CPD
1570: Document cpd = ChannelRegistryManager.getCPD(channelDesc
1571: .getChannelTypeId());
1572: if (cpd != null)
1573: userPrefParamsE.appendChild(doc.importNode(cpd
1574: .getDocumentElement(), true));
1575:
1576: doc.appendChild(userPrefParamsE);
1577: return doc;
1578: }
1579: }
1580:
1581: }
|