/*
* Copyright 2000-2001,2004 The Apache Software Foundation.
*
* Licensed 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.apache.jetspeed.modules.actions.controllers;
//Jetspeed Stuff
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
// Java stuff
import java.util.Vector;
import org.apache.jetspeed.om.profile.Entry;
import org.apache.jetspeed.om.profile.Layout;
import org.apache.jetspeed.om.profile.Portlets;
import org.apache.jetspeed.om.profile.Profile;
import org.apache.jetspeed.om.profile.psml.PsmlLayout;
import org.apache.jetspeed.om.registry.RegistryEntry;
import org.apache.jetspeed.portal.PortletController;
import org.apache.jetspeed.portal.PortletSet;
import org.apache.jetspeed.services.Registry;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.util.AutoProfile;
import org.apache.turbine.modules.ActionLoader;
// Turbine stuff
//import org.apache.turbine.util.DynamicURI;
import org.apache.turbine.util.RunData;
// Velocity Stuff
import org.apache.velocity.context.Context;
/**
* This action builds a context suitable for controllers handlings simple sorted
* lists of portlets
*
* @author <a href="mailto:raphael@apache.org">Rapha�l Luta</a>
* @author <a href="mailto:paulsp@apache.org">Paul Spencer</a>
*/
public class RowColumnControllerAction extends VelocityControllerAction {
/**
* Static initialization of the logger for this class
*/
private static final JetspeedLogger logger = JetspeedLogFactoryService
.getLogger(RowColumnControllerAction.class.getName());
/**
* Subclasses must override this method to provide default behavior for the
* portlet action
*/
@Override
protected void buildNormalContext(PortletController controller,
Context context, RunData rundata) {
// retrieve the size for each of the element
String sizes = controller.getConfig().getInitParameter("sizes");
context.put("sizes", getCellSizes(sizes));
}
/**
* Parses the size config info and returns a list of size values for the
* current set
*
* @param sizeList
* java.lang.String a comma separated string a values
* @return a List of values
*/
public static List getCellSizes(String sizelist) {
List list = new Vector();
if (sizelist != null) {
StringTokenizer st = new StringTokenizer(sizelist, ",");
while (st.hasMoreTokens()) {
list.add(st.nextToken());
}
}
return list;
}
/**
* Adds a "pane" portlet object in the context which represents the currently
* selected pane
*/
@Override
protected void buildCustomizeContext(PortletController controller,
Context context, RunData rundata) {
super.buildCustomizeContext(controller, context, rundata);
JetspeedRunData jdata = (JetspeedRunData) rundata;
PortletSet set = (PortletSet) jdata.getCustomized();
Portlets portlets =
jdata.getCustomizedProfile().getDocument().getPortletsById(set.getID());
List plist = new ArrayList();
List work = new ArrayList();
List filler =
Collections.nCopies(portlets.getPortletsCount()
+ portlets.getEntryCount(), null);
plist.addAll(filler);
for (int i = 0; i < portlets.getPortletsCount(); i++) {
Portlets p = portlets.getPortlets(i);
if (logger.isDebugEnabled()) {
logger.debug("RowColumnControllerAction: processing portlet: "
+ p.getTitle());
}
Layout layout = p.getLayout();
if (layout == null) {
// Pane should always have a layout with correct position
if (logger.isDebugEnabled()) {
logger
.debug("RowColumnControllerAction: no layout, creating a new one");
}
layout = new PsmlLayout();
layout.setPosition(i);
p.setLayout(layout);
}
if (layout != null) {
try {
int pos = (int) layout.getPosition();
if (logger.isDebugEnabled()) {
logger.debug("RowColumnControllerAction: layout has position: "
+ pos);
}
if (pos >= 0 && pos < plist.size()) {
plist.set(pos, p);
} else {
work.add(p);
}
} catch (Exception e) {
logger.error("Layout error", e);
layout.setPosition(-1);
work.add(p);
}
} else {
work.add(p);
}
}
for (int i = 0; i < portlets.getEntryCount(); i++) {
Entry p = portlets.getEntry(i);
Layout layout = p.getLayout();
if (layout != null) {
try {
int pos = (int) layout.getPosition();
if (pos >= 0) {
plist.set(pos, p);
} else {
work.add(p);
}
} catch (Exception e) {
layout.setPosition(-1);
work.add(p);
}
} else {
work.add(p);
}
}
Iterator i = work.iterator();
for (int idx = 0; idx < plist.size(); idx++) {
if (plist.get(idx) == null) {
if (i.hasNext()) {
plist.set(idx, i.next());
} else {
plist.remove(idx);
}
}
}
Map titles = new HashMap();
i = plist.iterator();
while (i.hasNext()) {
Object obj = i.next();
if (obj instanceof Portlets) {
Portlets entry = (Portlets) obj;
if ((entry.getMetaInfo() != null)
&& (entry.getMetaInfo().getTitle() != null)) {
titles.put(entry.getId(), entry.getMetaInfo().getTitle());
}
} else {
Entry entry = (Entry) obj;
if ((entry.getMetaInfo() != null)
&& (entry.getMetaInfo().getTitle() != null)) {
titles.put(entry.getId(), entry.getMetaInfo().getTitle());
} else {
RegistryEntry pentry =
Registry.getEntry(Registry.PORTLET, entry.getParent());
if (pentry != null) {
titles.put(entry.getId(), pentry.getTitle());
}
}
}
}
context.put("portlets", plist);
context.put("titles", titles);
/**
* Make a list of all used portlets available thru the 'runs' reference
* ------
* -------------------------------------------------------------------- last
* modified: 10/31/01 Andreas Kempf, Siemens ICM S CP PE, Munich mailto:
* A.Kempf@web.de
*/
context.put("runs", AutoProfile.getPortletList(rundata));
// --------------------------------------------------------------------------
}
/**
* Cancel the current customizations. If this was the last customization on
* the stack, then return the user to the home page.
*/
@Override
public void doCancel(RunData data, Context context) {
((JetspeedRunData) data).setCustomized(null);
if (((JetspeedRunData) data).getCustomized() == null) {
try {
ActionLoader.getInstance().exec(data, "controls.EndCustomize");
} catch (Exception e) {
logger.error("Unable to load action controls.EndCustomize ", e);
}
}
}
public void doSave(RunData data, Context context) {
doApply(data, context);
}
public void doApply(RunData data, Context context) {
// move one level back in customization
((JetspeedRunData) data).setCustomized(null);
// if we are all done customization
if (((JetspeedRunData) data).getCustomized() == null) {
// save the edit profile and make it current
try {
((JetspeedRunData) data).getCustomizedProfile().store();
} catch (Exception e) {
logger.error("Unable to save profile ", e);
}
try {
ActionLoader.getInstance().exec(data, "controls.EndCustomize");
} catch (Exception e) {
logger.error("Unable to load action controls.EndCustomize ", e);
}
}
}
/**
* Remove a pane from the current set This method expects the following
* parameters - paneid: the id a the pane to modify within the current profile
* - position: the position of the component to delete
*/
public void doDelete(RunData data, Context context) throws Exception {
JetspeedRunData jdata = (JetspeedRunData) data;
PortletSet customizedSet = (PortletSet) jdata.getCustomized();
int position = data.getParameters().getInt("position", -1);
Profile profile = jdata.getCustomizedProfile();
// ADDED for WML
// boolean isWML = (profile.getMediaType().equalsIgnoreCase("wml"));
if (customizedSet == null) {
return;
}
if (position > -1) {
Portlets set =
profile.getDocument().getPortletsById(customizedSet.getID());
if (set != null) {
// first try explicit portlets position
for (int i = 0; i < set.getPortletsCount(); i++) {
Portlets p = set.getPortlets(i);
Layout layout = p.getLayout();
//
// if (layout == null)
// {
// Layout nl = new Layout ();
// nl.setPosition (String.valueOf(i));
//
// }
if ((layout != null) && (layout.getPosition() != -1)) {
int lpos = (int) layout.getPosition();
if (lpos == position) {
set.removePortlets(i);
updateLayoutPositions(set);
// MODIFIED: Save changes for wml profiles
// if (isWML)
// doSave(data, null);
return;
}
}
}
// try explicit entry position
for (int i = 0; i < set.getEntryCount(); i++) {
Entry p = set.getEntry(i);
Layout layout = p.getLayout();
if ((layout != null) && (layout.getPosition() != -1)) {
int lpos = (int) layout.getPosition();
if (lpos == position) {
set.removeEntry(i);
// MODIFIED: Save changes for wml profiles
// if (isWML)
// doSave(data, null);
return;
}
}
}
// else use implicit position
if (position < set.getPortletsCount()) {
set.removePortlets(position);
// MODIFIED: Save changes for wml profiles
// if (isWML)
// doSave(data, null);
return;
}
if (position < set.getEntryCount()) {
set.removeEntry(position);
// MODIFIED: Save changes for wml profiles
// if (isWML)
// doSave(data, null);
return;
}
}
}
}
/**
* Updates the layout position based on physical order within the resorted
* portlet list. Assures that layout position is always consecutive and within
* bounds.
*
* @param set
*/
private void updateLayoutPositions(Portlets set) {
// Load the panes into a list
List list = new ArrayList();
for (int i = 0; i < set.getPortletsCount(); i++) {
Portlets pane = set.getPortlets(i);
list.add(pane);
}
// Sort list using the current layout position
Collections.sort(list, new Comparator() {
@Override
public int compare(Object pane1, Object pane2) {
Long pos1 = new Long(((Portlets) pane1).getLayout().getPosition());
Long pos2 = new Long(((Portlets) pane2).getLayout().getPosition());
return pos1.compareTo(pos2);
}
});
// Update the layout position based on the physical order within the sorted
// list
int position = 0;
for (Iterator iter = list.iterator(); iter.hasNext();) {
Portlets pane = (Portlets) iter.next();
Layout layout = pane.getLayout();
layout.setPosition(position++);
}
}
/**
* Move a component up within the pane This method expects the following
* parameters - paneid: the id a the pane to modify within the current profile
* - position: move the component which occupies this position
*/
public void doUp(RunData data, Context context) throws Exception {
doMove(data, context, true);
}
/**
* Move a component down within the pane This method expects the following
* parameters - paneid: the id a the pane to modify within the current profile
* - position: move the component which occupies this position
*/
public void doDown(RunData data, Context context) throws Exception {
doMove(data, context, false);
}
/**
* Move a component within the pane This method expects the following
* parameters - paneid: the id a the pane to modify within the current profile
* - position: move the component which occupies this position The moveUp
* boolean determines the direction of the move
*/
public void doMove(RunData data, Context context, boolean moveUp)
throws Exception {
JetspeedRunData jdata = (JetspeedRunData) data;
PortletSet customizedSet = (PortletSet) jdata.getCustomized();
int position = data.getParameters().getInt("position", -1);
Profile profile = jdata.getCustomizedProfile();
// ADDED for WML
// boolean isWML = (profile.getMediaType().equalsIgnoreCase("wml"));
if (customizedSet == null) {
return;
}
if (position > -1) {
int target = -1;
Portlets set =
profile.getDocument().getPortletsById(customizedSet.getID());
Layout targetLayout = null;
Layout baseLayout = null;
if (set != null) {
// check if we can possibly move as requested and calculate
// target position
if (moveUp) {
if ((position >= set.getPortletsCount())
&& (position >= set.getEntryCount())) {
return;
}
target = position + 1;
} else {
if (position == 0) {
return;
}
target = position - 1;
}
// first find objects at explicit portlets position
for (int i = 0; i < set.getPortletsCount(); i++) {
if ((targetLayout != null) && (baseLayout != null)) {
break;
}
Portlets p = set.getPortlets(i);
Layout layout = p.getLayout();
if ((layout != null) && (layout.getPosition() != -1)) {
int lpos = (int) layout.getPosition();
if ((baseLayout == null) && (lpos == position)) {
baseLayout = layout;
}
if ((targetLayout == null) && (lpos == target)) {
targetLayout = layout;
}
}
}
// try explicit entry position
for (int i = 0; i < set.getEntryCount(); i++) {
if ((targetLayout != null) && (baseLayout != null)) {
break;
}
Entry p = set.getEntry(i);
Layout layout = p.getLayout();
if ((layout != null) && (layout.getPosition() != -1)) {
int lpos = (int) layout.getPosition();
if ((baseLayout == null) && (lpos == position)) {
baseLayout = layout;
}
if ((targetLayout == null) && (lpos == target)) {
targetLayout = layout;
}
}
}
// else use implicit position
if (baseLayout == null) {
if (position < set.getPortletsCount()) {
Portlets p = set.getPortlets(position);
if (p.getLayout() == null) {
p.setLayout(new PsmlLayout());
}
baseLayout = p.getLayout();
}
if (position < set.getEntryCount()) {
Entry p = set.getEntry(position);
if (p.getLayout() == null) {
p.setLayout(new PsmlLayout());
}
baseLayout = p.getLayout();
}
}
if (targetLayout == null) {
if (target < set.getPortletsCount()) {
Portlets p = set.getPortlets(target);
if (p.getLayout() == null) {
p.setLayout(new PsmlLayout());
}
targetLayout = p.getLayout();
}
if (target < set.getEntryCount()) {
Entry p = set.getEntry(target);
if (p.getLayout() == null) {
p.setLayout(new PsmlLayout());
}
targetLayout = p.getLayout();
}
}
// we should now have found both baseLayout and targetLayout, swap
// their positions using explicit positioning
if ((baseLayout == null) || (targetLayout == null)) {
return;
}
baseLayout.setPosition(target);
targetLayout.setPosition(position);
}
}
// MODIFIED: Save changes for wml profiles
// if (isWML)
// doSave(data, null);
}
}