0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/chat/tags/sakai_2-4-1/chat-tool/tool/src/java/org/sakaiproject/chat/tool/ChatAction.java $
0003: * $Id: ChatAction.java 9983 2006-05-25 20:07:58Z ggolden@umich.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.chat.tool;
0021:
0022: import java.util.Iterator;
0023: import java.util.List;
0024: import java.util.Vector;
0025:
0026: import org.apache.commons.logging.Log;
0027: import org.apache.commons.logging.LogFactory;
0028: import org.sakaiproject.authz.api.PermissionsHelper;
0029: import org.sakaiproject.chat.api.ChatChannel;
0030: import org.sakaiproject.chat.api.ChatChannelEdit;
0031: import org.sakaiproject.chat.api.ChatMessage;
0032: import org.sakaiproject.chat.api.ChatMessageEdit;
0033: import org.sakaiproject.chat.cover.ChatService;
0034: import org.sakaiproject.cheftool.Context;
0035: import org.sakaiproject.cheftool.JetspeedRunData;
0036: import org.sakaiproject.cheftool.PortletConfig;
0037: import org.sakaiproject.cheftool.RunData;
0038: import org.sakaiproject.cheftool.VelocityPortlet;
0039: import org.sakaiproject.cheftool.VelocityPortletPaneledAction;
0040: import org.sakaiproject.cheftool.api.Menu;
0041: import org.sakaiproject.cheftool.api.MenuItem;
0042: import org.sakaiproject.cheftool.menu.MenuEntry;
0043: import org.sakaiproject.cheftool.menu.MenuImpl;
0044: import org.sakaiproject.component.cover.ServerConfigurationService;
0045: import org.sakaiproject.entity.api.Reference;
0046: import org.sakaiproject.entity.cover.EntityManager;
0047: import org.sakaiproject.event.api.SessionState;
0048: import org.sakaiproject.exception.IdInvalidException;
0049: import org.sakaiproject.exception.IdUnusedException;
0050: import org.sakaiproject.exception.IdUsedException;
0051: import org.sakaiproject.exception.PermissionException;
0052: import org.sakaiproject.presence.cover.PresenceService;
0053: import org.sakaiproject.site.cover.SiteService;
0054: import org.sakaiproject.time.api.Time;
0055: import org.sakaiproject.time.api.TimeBreakdown;
0056: import org.sakaiproject.time.cover.TimeService;
0057: import org.sakaiproject.tool.api.Placement;
0058: import org.sakaiproject.tool.cover.SessionManager;
0059: import org.sakaiproject.tool.cover.ToolManager;
0060: import org.sakaiproject.util.FormattedText;
0061: import org.sakaiproject.util.PresenceObservingCourier;
0062: import org.sakaiproject.util.ResourceLoader;
0063: import org.sakaiproject.util.StringUtil;
0064: import org.sakaiproject.util.Validator;
0065:
0066: /**
0067: * <p>
0068: * ChatAction is the Sakai chat tool.
0069: * </p>
0070: */
0071: public class ChatAction extends VelocityPortletPaneledAction {
0072: /** Our logger. */
0073: private static Log M_log = LogFactory.getLog(ChatAction.class);
0074:
0075: /** Resource bundle using current language locale */
0076: private static ResourceLoader rb = new ResourceLoader("chat");
0077:
0078: private static final String MODE_CONFIRM_DELETE_MESSAGE = "confirmmdeletemessage";
0079:
0080: /** portlet configuration parameter names. */
0081: private static final String PARAM_CHANNEL = "channel";
0082:
0083: private static final String PARAM_DISPLAY_DATE = "display-date";
0084:
0085: private static final String PARAM_DISPLAY_TIME = "display-time";
0086:
0087: private static final String PARAM_DISPLAY_USER = "display-user";
0088:
0089: private static final String PARAM_SOUND_ALERT = "sound-alert";
0090:
0091: private static final String PARAM_MEMBER_FILTER = "member-filter";
0092:
0093: private static final String PARAM_FILTER_TYPE = "filter-type";
0094:
0095: private static final String PARAM_FILTER_PARAM = "filter-param";
0096:
0097: /** Configure form field names. */
0098: private static final String FORM_CHANNEL = "channel";
0099:
0100: private static final String FORM_NEW_CHANNEL = "new-channel";
0101:
0102: private static final String FORM_FILTER_TYPE = "filter-type";
0103:
0104: private static final String FORM_FILTER_PARAM_DAYS = "filter-param-days";
0105:
0106: private static final String FORM_FILTER_PARAM_NUMBER = "filter-param-number";
0107:
0108: /** Message filter names */
0109: private static final String FILTER_BY_NUMBER = "SelectMessagesByNumber";
0110:
0111: private static final String FILTER_BY_TIME = "SelectMessagesByTime";
0112:
0113: private static final String FILTER_TODAY = "SelectTodaysMessages";
0114:
0115: private static final String FILTER_ALL = "SelectAllMessages";
0116:
0117: private static final String[] ALL_FILTERS = { FILTER_BY_NUMBER,
0118: FILTER_BY_TIME, FILTER_TODAY, FILTER_ALL };
0119:
0120: /** Default values to use in case of input errors */
0121: private static final int DEFAULT_PARAM = 0;
0122:
0123: private static final int DEFAULT_DAYS = 3;
0124:
0125: private static final int DEFAULT_MSGS = 12;
0126:
0127: /** Control form field names. */
0128: private static final String FORM_MESSAGE = "message";
0129:
0130: /** names and values of request parameters to select sub-panels */
0131: private static final String MONITOR_PANEL = "List";
0132:
0133: private static final String CONTROL_PANEL = "Control";
0134:
0135: private static final String PRESENCE_PANEL = "Presence";
0136:
0137: private static final String TOOLBAR_PANEL = "Toolbar";
0138:
0139: /** state attribute names. */
0140: private static final String STATE_CHANNEL_REF = "channelId";
0141:
0142: private static final String STATE_SITE = "siteId";
0143:
0144: private static final String STATE_DISPLAY_DATE = "display-date";
0145:
0146: private static final String STATE_DISPLAY_TIME = "display-time";
0147:
0148: private static final String STATE_DISPLAY_USER = "display-user";
0149:
0150: private static final String STATE_SOUND_ALERT = "sound-alert";
0151:
0152: private static final String STATE_UPDATE = "update";
0153:
0154: private static final String STATE_CHANNEL_PROBLEM = "channel-problem";
0155:
0156: private static final String STATE_FILTER_TYPE = "filter-type";
0157:
0158: private static final String STATE_FILTER_PARAM = "filter-param";
0159:
0160: private static final String STATE_MESSAGE_FILTER = "message-filter";
0161:
0162: private static final String STATE_MORE_SELECTED = "more-selected";
0163:
0164: private static final String STATE_MORE_MESSAGES_LABEL = "more-messages-label";
0165:
0166: private static final String STATE_MORE_MESSAGES_FILTER = "more-messages-filter";
0167:
0168: private static final String STATE_FEWER_MESSAGES_LABEL = "fewer-messages-label";
0169:
0170: private static final String STATE_FEWER_MESSAGES_FILTER = "fewer-messages-filter";
0171:
0172: private static final String STATE_BROWSER = "browser";
0173:
0174: private static final String STATE_CHAT_PRESENCE_OBSERVER = STATE_OBSERVER2;
0175:
0176: private static final String STATE_COLOR_MAPPER = "color-mapper";
0177:
0178: private static final String STATE_MAIN_MESSAGE = "message-for-chat-layout";
0179:
0180: private static final String NEW_CHAT_CHANNEL = "new-chat-channel";
0181:
0182: /** Resource property on the message indicating that the message had been deleted */
0183: private static final String PROPERTY_MESSAGE_DELETED = "deleted";
0184:
0185: private static final String TIME_DATE_SELECT = "selected-time-date-display";
0186:
0187: /** State attribute set when we need to go into permissions mode. */
0188: private static final String STATE_PERMISSIONS = "sakai:chat:permissions";
0189:
0190: /**
0191: * Populate the state object, if needed.
0192: */
0193: protected void initState(SessionState state,
0194: VelocityPortlet portlet, JetspeedRunData rundata) {
0195: super .initState(state, portlet, rundata);
0196:
0197: // detect that we have not done this, yet
0198: if (state.getAttribute(STATE_CHANNEL_REF) == null) {
0199: PortletConfig config = portlet.getPortletConfig();
0200:
0201: // read the channel from configuration, or, if not specified, use the default for the page
0202: String channel = StringUtil.trimToNull(config
0203: .getInitParameter(PARAM_CHANNEL));
0204: if (channel == null) {
0205: channel = ChatService.channelReference(ToolManager
0206: .getCurrentPlacement().getContext(),
0207: SiteService.MAIN_CONTAINER);
0208: }
0209:
0210: state.setAttribute(STATE_CHANNEL_REF, channel);
0211:
0212: if (state.getAttribute(STATE_DISPLAY_DATE) == null) {
0213: state.setAttribute(STATE_DISPLAY_DATE, new Boolean(
0214: config.getInitParameter(PARAM_DISPLAY_DATE)));
0215: }
0216:
0217: if (state.getAttribute(STATE_DISPLAY_TIME) == null) {
0218: state.setAttribute(STATE_DISPLAY_TIME, new Boolean(
0219: config.getInitParameter(PARAM_DISPLAY_TIME)));
0220: }
0221:
0222: if (state.getAttribute(STATE_DISPLAY_USER) == null) {
0223: state.setAttribute(STATE_DISPLAY_USER, new Boolean(
0224: config.getInitParameter(PARAM_DISPLAY_USER)));
0225: }
0226:
0227: if (state.getAttribute(STATE_SOUND_ALERT) == null) {
0228: state.setAttribute(STATE_SOUND_ALERT, new Boolean(
0229: config.getInitParameter(PARAM_SOUND_ALERT)));
0230: }
0231:
0232: if (state.getAttribute(STATE_COLOR_MAPPER) == null) {
0233: ColorMapper mapper = new ColorMapper();
0234:
0235: // always set this user's color to first color (red)
0236: mapper.getColor(StringUtil.trimToZero(SessionManager
0237: .getCurrentSessionUserId()));
0238:
0239: state.setAttribute(STATE_COLOR_MAPPER, mapper);
0240: }
0241:
0242: if (state.getAttribute(STATE_FILTER_TYPE) == null) {
0243: String filter_type = config.getInitParameter(
0244: PARAM_FILTER_TYPE, FILTER_BY_TIME);
0245: String filter_param = config.getInitParameter(
0246: PARAM_FILTER_PARAM, String
0247: .valueOf(DEFAULT_DAYS));
0248:
0249: updateMessageFilters(state, filter_type, filter_param);
0250: }
0251:
0252: // the event resource reference pattern to watch for
0253: // setup the observer to notify our MONITOR_PANEL panel (inside the Main panel)
0254: if (state.getAttribute(STATE_OBSERVER) == null) {
0255: // get the current tool placement
0256: Placement placement = ToolManager.getCurrentPlacement();
0257:
0258: // location is just placement
0259: String location = placement.getId();
0260:
0261: // the html element to update on delivery
0262: String elementId = MONITOR_PANEL;
0263: Reference r = EntityManager.newReference(channel);
0264: String pattern = ChatService.messageReference(r
0265: .getContext(), r.getId(), "");
0266: boolean wantsBeeps = ((Boolean) state
0267: .getAttribute(STATE_SOUND_ALERT))
0268: .booleanValue();
0269:
0270: state.setAttribute(STATE_OBSERVER,
0271: new ChatObservingCourier(location, elementId,
0272: pattern, wantsBeeps));
0273: }
0274:
0275: // the event resource reference pattern to watch for
0276: // setup the observer to notify our PRESENCE_PANEL panel (inside the Main panel)
0277: if (state.getAttribute(STATE_CHAT_PRESENCE_OBSERVER) == null) {
0278: // get the current tool placement
0279: Placement placement = ToolManager.getCurrentPlacement();
0280:
0281: // location is just placement
0282: String location = placement.getId();
0283:
0284: // the html element to update on delivery
0285: String elementId = PRESENCE_PANEL;
0286:
0287: // setup an observer to notify us when presence at this location changes
0288: PresenceObservingCourier observer = new PresenceObservingCourier(
0289: location, elementId);
0290:
0291: state.setAttribute(STATE_CHAT_PRESENCE_OBSERVER,
0292: observer);
0293: }
0294: }
0295: // repopulate state object and title bar when default chat room changes
0296: else {
0297: PortletConfig config = portlet.getPortletConfig();
0298: // read the channel from configuration, or, if not specified, use the default for the page
0299: String channel = StringUtil.trimToNull(config
0300: .getInitParameter(PARAM_CHANNEL));
0301: if (channel == null) {
0302: channel = ChatService.channelReference(ToolManager
0303: .getCurrentPlacement().getContext(),
0304: SiteService.MAIN_CONTAINER);
0305: }
0306: state.setAttribute(STATE_CHANNEL_REF, channel);
0307: String channelName = rundata.getParameters().getString(
0308: FORM_CHANNEL);
0309: // update the tool config
0310: Placement placement = ToolManager.getCurrentPlacement();
0311: placement.setTitle(rb.getString("chatroom") + "\""
0312: + channelName + "\"");
0313: }
0314: // make sure the observer is in sync with state
0315: updateObservationOfChannel(state, portlet.getID());
0316:
0317: } // initState
0318:
0319: /**
0320: * Setup our observer to be watching for change events for our channel.
0321: *
0322: * @param peid
0323: * The portlet id.
0324: */
0325: private void updateObservationOfChannel(SessionState state,
0326: String peid) {
0327: // make sure the pattern matches the channel we are looking at
0328: String channel = (String) state.getAttribute(STATE_CHANNEL_REF);
0329: Reference r = EntityManager.newReference(channel);
0330: String pattern = ChatService.messageReference(r.getContext(), r
0331: .getId(), "");
0332:
0333: // update the observer looking for new messages
0334: ChatObservingCourier observer1 = (ChatObservingCourier) state
0335: .getAttribute(STATE_OBSERVER);
0336: observer1.setResourcePattern(pattern);
0337:
0338: } // updateObservationOfChannel
0339:
0340: /**
0341: * Get the channel from ChatService or create it.
0342: */
0343: private ChatChannel getChannel(SessionState state, String name) {
0344: // deal with the channel not yet existing
0345: ChatChannel channel = null;
0346: try {
0347: channel = ChatService.getChatChannel(name);
0348: } catch (IdUnusedException ignore) {
0349: } catch (PermissionException ignore) {
0350: }
0351:
0352: if ((channel == null)
0353: && (state.getAttribute(STATE_CHANNEL_PROBLEM) == null)) {
0354: // create the channel
0355: try {
0356: ChatChannelEdit edit = ChatService.addChatChannel(name);
0357: ChatService.commitChannel(edit);
0358: channel = edit;
0359: } catch (IdUsedException e) {
0360: // strange, the channel already exists!
0361: try {
0362: channel = ChatService.getChatChannel(name);
0363: } catch (IdUnusedException ignore) {
0364: } catch (PermissionException ignore) {
0365: }
0366: } catch (IdInvalidException e) {
0367: // stranger, we cannot use this id!
0368: state.setAttribute(STATE_CHANNEL_PROBLEM, rb
0369: .getString("thischat"));
0370: M_log.warn("doSend(): creating channel: ", e);
0371: } catch (PermissionException e) {
0372: // rats, this user cannot create the channel
0373: state.setAttribute(STATE_CHANNEL_PROBLEM, rb
0374: .getString("youdonot2"));
0375: }
0376: }
0377: return channel;
0378:
0379: } // getChannel
0380:
0381: /**
0382: * Update the state message-filtering attributes to use the filtering criteria specified by the filter_type and filter_param parameters.
0383: *
0384: * @param state
0385: * The session state.
0386: * @param filter_type
0387: * A string specifying the filter type.
0388: * @param filter_param
0389: * A string specifying the filter param.
0390: */
0391: private void updateMessageFilters(SessionState state,
0392: String filter_type, String filter_param) {
0393: state.setAttribute(STATE_MORE_MESSAGES_LABEL, rb
0394: .getString("showall"));
0395: state.setAttribute(STATE_MORE_MESSAGES_FILTER,
0396: new SelectAllMessages());
0397: state.setAttribute(STATE_FILTER_PARAM, String
0398: .valueOf(DEFAULT_PARAM));
0399:
0400: state.setAttribute(STATE_MORE_SELECTED, new Boolean(false));
0401: state.setAttribute(STATE_FILTER_TYPE, filter_type);
0402: if (filter_type.equals(FILTER_ALL)) {
0403: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0404: new SelectMessagesByTime(DEFAULT_DAYS));
0405: state.setAttribute(STATE_FEWER_MESSAGES_LABEL, rb
0406: .getString("showpast")
0407: + " " + DEFAULT_DAYS + " " + rb.getString("days"));
0408: state.setAttribute(STATE_MESSAGE_FILTER, state
0409: .getAttribute(STATE_MORE_MESSAGES_FILTER));
0410: state.setAttribute(STATE_MORE_SELECTED, new Boolean(true));
0411: } else if (filter_type.equals(FILTER_TODAY)) {
0412: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0413: new SelectTodaysMessages());
0414: state.setAttribute(STATE_FEWER_MESSAGES_LABEL, rb
0415: .getString("showtoday"));
0416: state.setAttribute(STATE_MESSAGE_FILTER, state
0417: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0418: } else if (filter_type.equals(FILTER_BY_NUMBER)) {
0419: int number = DEFAULT_MSGS;
0420: try {
0421: number = Integer.parseInt(filter_param);
0422: if (number <= 0) {
0423: throw new Exception();
0424: }
0425: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0426: new SelectMessagesByNumber(number));
0427: state.setAttribute(STATE_FILTER_PARAM, filter_param);
0428: } catch (Exception e) {
0429: // M_log.warn("updateMessageFilters() invalid param: " );
0430: }
0431: state.setAttribute(STATE_FILTER_PARAM, String
0432: .valueOf(number));
0433: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0434: new SelectMessagesByNumber(number));
0435: state.setAttribute(STATE_FEWER_MESSAGES_LABEL, rb
0436: .getString("showlast")
0437: + " " + number + " " + rb.getString("messages"));
0438: state.setAttribute(STATE_MESSAGE_FILTER, state
0439: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0440: } else if (filter_type.equals(FILTER_BY_TIME)) {
0441: int number = DEFAULT_DAYS;
0442: try {
0443: number = Integer.parseInt(filter_param);
0444: if (number <= 0) {
0445: throw new Exception();
0446: }
0447: } catch (Exception e) {
0448: // M_log.warn("updateMessageFilters() invalid param: " );
0449: }
0450: state.setAttribute(STATE_FILTER_PARAM, String
0451: .valueOf(number));
0452: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0453: new SelectMessagesByTime(number));
0454: state.setAttribute(STATE_FEWER_MESSAGES_LABEL, rb
0455: .getString("showpast")
0456: + " " + number + " " + rb.getString("days"));
0457: state.setAttribute(STATE_MESSAGE_FILTER, state
0458: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0459: } else {
0460: state.setAttribute(STATE_FILTER_PARAM, String
0461: .valueOf(DEFAULT_DAYS));
0462: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0463: new SelectMessagesByTime(DEFAULT_DAYS));
0464: state.setAttribute(STATE_FEWER_MESSAGES_LABEL, rb
0465: .getString("showpast")
0466: + " " + DEFAULT_DAYS + " " + rb.getString("days"));
0467: state.setAttribute(STATE_MESSAGE_FILTER, state
0468: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0469: }
0470:
0471: } // updateMessageFilters
0472:
0473: /**
0474: * build the context for the Main (Layout) panel
0475: *
0476: * @return (optional) template name for this panel
0477: */
0478: public String buildMainPanelContext(VelocityPortlet portlet,
0479: Context context, RunData rundata, SessionState state) {
0480: context.put("tlang", rb);
0481: // if there's an alert message specifically targetted for main fraim, display it
0482: String msg = (String) state.getAttribute(STATE_MAIN_MESSAGE);
0483: context.put("alertMessage", msg);
0484: state.removeAttribute(STATE_MAIN_MESSAGE);
0485:
0486: String mode = (String) state.getAttribute(STATE_MODE);
0487: if (MODE_OPTIONS.equals(mode)) {
0488: return buildOptionsPanelContext(portlet, context, rundata,
0489: state);
0490: } else if (MODE_CONFIRM_DELETE_MESSAGE.equals(mode)) {
0491: return buildConfirmDeleteMessagePanelContext(portlet,
0492: context, rundata, state);
0493: }
0494:
0495: List focus_elements = new Vector();
0496: focus_elements.add(CONTROL_PANEL);
0497: focus_elements.add(FORM_MESSAGE);
0498:
0499: context.put("focus_path", focus_elements);
0500:
0501: context.put("panel-control", CONTROL_PANEL);
0502: context.put("panel-monitor", MONITOR_PANEL);
0503: context.put("panel-presence", PRESENCE_PANEL);
0504: context.put("panel-toolbar", TOOLBAR_PANEL);
0505:
0506: // the url for the chat courier, using a quick 10 second refresh
0507: setVmCourier(rundata.getRequest(), 10);
0508:
0509: return (String) getContext(rundata).get("template") + "-Layout";
0510:
0511: } // buildLayoutPanelContext
0512:
0513: /**
0514: * Handle a user clicking on the view-date menu.
0515: */
0516: public void doToggle_date_display(RunData runData, Context context) {
0517: toggleState(runData, STATE_DISPLAY_DATE);
0518:
0519: // schedule a refresh of the monitor panel
0520: String peid = ((JetspeedRunData) runData).getJs_peid();
0521: schedulePeerFrameRefresh(mainPanelUpdateId(peid) + "."
0522: + MONITOR_PANEL);
0523:
0524: // schedule a return of focus to Control panel (from the parent's perspective)
0525: String[] focusPath = { CONTROL_PANEL, FORM_MESSAGE };
0526: scheduleFocusRefresh(focusPath);
0527:
0528: } // doToggle_date_display
0529:
0530: /**
0531: * Handle a user clicking on the view-time menu.
0532: */
0533: public void doToggle_time_display(RunData runData, Context context) {
0534: toggleState(runData, STATE_DISPLAY_TIME);
0535:
0536: // schedule a refresh of the monitor panel
0537: String peid = ((JetspeedRunData) runData).getJs_peid();
0538: schedulePeerFrameRefresh(mainPanelUpdateId(peid) + "."
0539: + MONITOR_PANEL);
0540:
0541: // schedule a return of focus to Control panel (from the parent's perspective)
0542: String[] focusPath = { CONTROL_PANEL, FORM_MESSAGE };
0543: scheduleFocusRefresh(focusPath);
0544:
0545: } // doToggle_time_display
0546:
0547: /**
0548: * Handle a user clicking on the time-date dropdown.
0549: */
0550: public void doChange_time_date_display(RunData runData,
0551: Context context) {
0552: String peid = ((JetspeedRunData) runData).getJs_peid();
0553: SessionState state = ((JetspeedRunData) runData)
0554: .getPortletSessionState(peid);
0555:
0556: String time_date = runData.getParameters().getString(
0557: "changeView");
0558:
0559: boolean oldTime = ((Boolean) state
0560: .getAttribute(STATE_DISPLAY_TIME)).booleanValue();
0561: boolean oldDate = ((Boolean) state
0562: .getAttribute(STATE_DISPLAY_DATE)).booleanValue();
0563:
0564: if (time_date.equals(rb.getString("bar.onlytime"))) {
0565: // if the time is not shown, toggle to show it
0566: if (!oldTime) {
0567: toggleState(runData, STATE_DISPLAY_TIME);
0568: }
0569: // if the date is being shown, toggle to hide it
0570: if (oldDate) {
0571: toggleState(runData, STATE_DISPLAY_DATE);
0572: }
0573: } else if (time_date.equals(rb.getString("bar.datetime"))) {
0574: // if the time is not shown, toggle to show it
0575: if (!oldTime) {
0576: toggleState(runData, STATE_DISPLAY_TIME);
0577: }
0578: // if the date is not shown, toggle to show it
0579: if (!oldDate) {
0580: toggleState(runData, STATE_DISPLAY_DATE);
0581: }
0582: } else if (time_date.equals(rb.getString("bar.onlydate"))) {
0583: // if the time is being shown, toggle to hide it
0584: if (oldTime) {
0585: toggleState(runData, STATE_DISPLAY_TIME);
0586: }
0587: // if the date is not shown, toggle to show it
0588: if (!oldDate) {
0589: toggleState(runData, STATE_DISPLAY_DATE);
0590: }
0591: } else if (time_date.equals(rb.getString("bar.nodatetime"))) {
0592: // if the time is being shown, toggle to hide it
0593: if (oldTime) {
0594: toggleState(runData, STATE_DISPLAY_TIME);
0595: }
0596: // if the date is being shown, toggle to hide it
0597: if (oldDate) {
0598: toggleState(runData, STATE_DISPLAY_DATE);
0599: }
0600: }
0601:
0602: state.setAttribute(TIME_DATE_SELECT, time_date);
0603:
0604: schedulePeerFrameRefresh(mainPanelUpdateId(peid) + "."
0605: + MONITOR_PANEL);
0606:
0607: // schedule a return of focus to Control panel (from the parent's perspective)
0608: String[] focusPath = { CONTROL_PANEL, FORM_MESSAGE };
0609: scheduleFocusRefresh(focusPath);
0610:
0611: } // doChange_time_date_display
0612:
0613: /**
0614: * Handle a user clicking on the sound-alert button.
0615: */
0616: public void doToggle_sound_alert(RunData runData, Context context) {
0617: String peid = ((JetspeedRunData) runData).getJs_peid();
0618: SessionState state = ((JetspeedRunData) runData)
0619: .getPortletSessionState(peid);
0620:
0621: // toggle the state setting
0622: boolean newValue = !((Boolean) state
0623: .getAttribute(STATE_SOUND_ALERT)).booleanValue();
0624: state.setAttribute(STATE_SOUND_ALERT, new Boolean(newValue));
0625: ChatObservingCourier observer = (ChatObservingCourier) state
0626: .getAttribute(STATE_OBSERVER);
0627: observer.alertEnabled(newValue);
0628:
0629: // schedule a return of focus to Control panel (from the parent's perspective)
0630: String[] focusPath = { CONTROL_PANEL, FORM_MESSAGE };
0631: scheduleFocusRefresh(focusPath);
0632:
0633: } // doToggle_sound_alert
0634:
0635: /**
0636: * Toggle the state attribute
0637: *
0638: * @param stateName
0639: * The name of the state attribute to toggle
0640: */
0641: private void toggleState(RunData runData, String stateName) {
0642: // access the portlet element id to find our state
0643: // %%% use CHEF api instead of Jetspeed to get state
0644: String peid = ((JetspeedRunData) runData).getJs_peid();
0645: SessionState state = ((JetspeedRunData) runData)
0646: .getPortletSessionState(peid);
0647:
0648: // toggle the state setting
0649: boolean newValue = !((Boolean) state.getAttribute(stateName))
0650: .booleanValue();
0651: state.setAttribute(stateName, new Boolean(newValue));
0652:
0653: } // toggleState
0654:
0655: /**
0656: * Handle a user clicking on the show-all/show-some button.
0657: */
0658: public void doToggle_filter(RunData runData, Context context) {
0659: // access the portlet element id to find our state
0660: // %%% use CHEF api instead of Jetspeed to get state
0661: String peid = ((JetspeedRunData) runData).getJs_peid();
0662: SessionState state = ((JetspeedRunData) runData)
0663: .getPortletSessionState(peid);
0664:
0665: // toggle the filter setting between show-more and show-fewer
0666: if (((Boolean) state.getAttribute(STATE_MORE_SELECTED))
0667: .booleanValue()) {
0668: state.setAttribute(STATE_MESSAGE_FILTER, state
0669: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0670: } else {
0671: state.setAttribute(STATE_MESSAGE_FILTER, state
0672: .getAttribute(STATE_MORE_MESSAGES_FILTER));
0673: }
0674: toggleState(runData, STATE_MORE_SELECTED);
0675:
0676: if (((String) state.getAttribute(STATE_FILTER_TYPE))
0677: .equals(FILTER_BY_NUMBER)) {
0678: if (!((Boolean) state.getAttribute(STATE_MORE_SELECTED))
0679: .booleanValue()) {
0680: try {
0681: int number = Integer.parseInt((String) state
0682: .getAttribute(STATE_FILTER_PARAM));
0683: state.setAttribute(STATE_FEWER_MESSAGES_FILTER,
0684: new SelectMessagesByNumber(number));
0685: state.setAttribute(STATE_MESSAGE_FILTER, state
0686: .getAttribute(STATE_FEWER_MESSAGES_FILTER));
0687: } catch (NumberFormatException e) {
0688: }
0689: }
0690: }
0691:
0692: // schedule a refresh of the monitor panel
0693: schedulePeerFrameRefresh(mainPanelUpdateId(peid) + "."
0694: + MONITOR_PANEL);
0695:
0696: // schedule a return of focus to Control panel (from the parent's perspective)
0697: String[] focusPath = { CONTROL_PANEL, FORM_MESSAGE };
0698: scheduleFocusRefresh(focusPath);
0699:
0700: } // doToggle_filter
0701:
0702: /**
0703: * build the context for the Toolbar panel
0704: *
0705: * @return (optional) template name for this panel
0706: */
0707: public String buildToolbarPanelContext(VelocityPortlet portlet,
0708: Context context, RunData rundata, SessionState state) {
0709: // we might be on the way to a permissions...
0710: if (state.getAttribute(STATE_PERMISSIONS) != null) {
0711: state.removeAttribute(STATE_PERMISSIONS);
0712: doPermissionsNow(rundata, context);
0713: }
0714:
0715: context.put("tlang", rb);
0716: // build the menu
0717: Menu bar = new MenuImpl(portlet, rundata, (String) state
0718: .getAttribute(STATE_ACTION));
0719: /*
0720: * boolean displayDate = ((Boolean)state.getAttribute(STATE_DISPLAY_DATE)).booleanValue(); bar.add( new MenuEntry((displayDate ? rb.getString("hided") + " " : " " + rb.getString("showd")), null, true, (displayDate ? MenuItem.CHECKED_TRUE :
0721: * MenuItem.CHECKED_FALSE), "doToggle_date_display") ); boolean displayTime = ((Boolean)state.getAttribute(STATE_DISPLAY_TIME)).booleanValue(); bar.add( new MenuEntry((displayTime ? rb.getString("hidet") + " " : " " + rb.getString("showt")), null,
0722: * true, (displayTime ? MenuItem.CHECKED_TRUE : MenuItem.CHECKED_FALSE), "doToggle_time_display") );
0723: */
0724: context.put("selectedView", state
0725: .getAttribute(TIME_DATE_SELECT));
0726:
0727: // if the java beep is disabled, don't offer the alert
0728: if (ServerConfigurationService.getBoolean("java.beep", false)) {
0729: boolean soundAlert = ((Boolean) state
0730: .getAttribute(STATE_SOUND_ALERT)).booleanValue();
0731: bar.add(new MenuEntry((soundAlert ? rb.getString("turnoff")
0732: + " " : " " + rb.getString("turnon")), null, true,
0733: (soundAlert ? MenuItem.CHECKED_TRUE
0734: : MenuItem.CHECKED_FALSE),
0735: "doToggle_sound_alert"));
0736: }
0737:
0738: boolean moreSelected = ((Boolean) state
0739: .getAttribute(STATE_MORE_SELECTED)).booleanValue();
0740: /*
0741: * bar.add( new MenuEntry((moreSelected ? (String)state.getAttribute(STATE_FEWER_MESSAGES_LABEL) : (String)state.getAttribute(STATE_MORE_MESSAGES_LABEL)), null, true, (moreSelected ? MenuItem.CHECKED_TRUE : MenuItem.CHECKED_FALSE),
0742: * "doToggle_filter") );
0743: */
0744: String pastLabel = "";
0745: String fewerLabel = (String) state
0746: .getAttribute(STATE_FEWER_MESSAGES_LABEL);
0747: String moreLabel = (String) state
0748: .getAttribute(STATE_MORE_MESSAGES_LABEL);
0749: context.put("pastLabel",
0750: (moreSelected ? moreLabel : fewerLabel));
0751: context.put("fewerLabel", fewerLabel);
0752: context.put("moreLabel", moreLabel);
0753:
0754: // add options if allowed
0755: addOptionsMenu(bar, (JetspeedRunData) rundata);
0756:
0757: // add permissions, if allowed
0758: if (SiteService.allowUpdateSite(ToolManager
0759: .getCurrentPlacement().getContext())) {
0760: bar.add(new MenuEntry(rb.getString("permis"),
0761: "doPermissions"));
0762: }
0763:
0764: context.put(Menu.CONTEXT_MENU, bar);
0765: context.put(Menu.CONTEXT_ACTION, state
0766: .getAttribute(STATE_ACTION));
0767:
0768: return null; // (String)getContext(rundata).get("template") + "-Toolbar";
0769:
0770: } // buildToolbarPanelContext
0771:
0772: /**
0773: * build the context for the List panel
0774: *
0775: * @return (optional) template name for this panel
0776: */
0777: public String buildListPanelContext(VelocityPortlet portlet,
0778: Context context, RunData rundata, SessionState state) {
0779: // display info
0780: context.put("tlang", rb);
0781: context.put("display_date", state
0782: .getAttribute(STATE_DISPLAY_DATE));
0783: context.put("display_time", state
0784: .getAttribute(STATE_DISPLAY_TIME));
0785: context.put("display_user", state
0786: .getAttribute(STATE_DISPLAY_USER));
0787: context.put("sound_alert", state
0788: .getAttribute(STATE_SOUND_ALERT));
0789:
0790: // provide a color mapper to keep track of user color coding for the session
0791: context.put("color_mapper", (ColorMapper) state
0792: .getAttribute(STATE_COLOR_MAPPER));
0793:
0794: // find the channel and get the messages
0795: try {
0796: ChatFilter filter = (ChatFilter) state
0797: .getAttribute(STATE_MESSAGE_FILTER);
0798:
0799: // // TODO: TIMING
0800: // if (CurrentService.getInThread("DEBUG") == null)
0801: // CurrentService.setInThread("DEBUG", new StringBuffer());
0802: // long startTime = System.currentTimeMillis();
0803:
0804: List msgs = ChatService.getMessages((String) state
0805: .getAttribute(STATE_CHANNEL_REF), filter
0806: .getAfterDate(), filter.getLimitedToLatest(), true, // asc
0807: true, // TODO: inc drafts
0808: false // not pubview onyl
0809: );
0810:
0811: // // TODO: TIMING
0812: // long endTime = System.currentTimeMillis();
0813: // if (endTime-startTime > /*5*/000)
0814: // {
0815: // StringBuffer buf = (StringBuffer) CurrentService.getInThread("DEBUG");
0816: // if (buf != null)
0817: // {
0818: // buf.insert(0,"ChatAction.list: "
0819: // + state.getAttribute(STATE_CHANNEL_REF)
0820: // + " time: " + (endTime - startTime));
0821: // }
0822: // }
0823:
0824: context.put("chat_messages", msgs);
0825:
0826: // boolean allowed = ChatService.allowRemoveChannel((String)state.getAttribute(STATE_CHANNEL_REF));
0827: // context.put("allowRemoveMessage", new Boolean(allowed));
0828:
0829: ChatChannel channel = getChannel(state, (String) state
0830: .getAttribute(STATE_CHANNEL_REF));
0831: context.put("channel", channel);
0832:
0833: } catch (PermissionException e) {
0834: context.put("alertMessage", rb.getString("youdonot1"));
0835: } catch (Exception e) {
0836: M_log.warn("buildListPanelContext()", e);
0837: }
0838:
0839: // inform the observing courier that we just updated the page...
0840: // if there are pending requests to do so they can be cleared
0841: justDelivered(state);
0842:
0843: return null;
0844:
0845: } // buildListPanelContext
0846:
0847: /**
0848: * build the context for the Control panel (has a send field)
0849: *
0850: * @return (optional) template name for this panel
0851: */
0852: public String buildControlPanelContext(VelocityPortlet portlet,
0853: Context context, RunData rundata, SessionState state) {
0854: context.put("tlang", rb);
0855: // put this pannel's name for the return url
0856: context.put("panel-control", CONTROL_PANEL);
0857:
0858: // set the action for form processing
0859: context.put(Menu.CONTEXT_ACTION, state
0860: .getAttribute(STATE_ACTION));
0861:
0862: // set the form field name for the send button
0863: context.put("form-submit", BUTTON + "doSend");
0864:
0865: // set the form field name for the send button
0866: context.put("form-message", FORM_MESSAGE);
0867:
0868: // is this user going to be able to post (add permission on the channel)
0869: boolean allowed = ChatService.allowAddChannel((String) state
0870: .getAttribute(STATE_CHANNEL_REF));
0871: if (!allowed) {
0872: context.put("alertMessage", rb.getString("youdonot3")); // %%% or no message?
0873: }
0874: context.put("allow-send", new Boolean(allowed));
0875:
0876: return null;
0877:
0878: } // buildControlPanelContext
0879:
0880: /**
0881: * build the context for the Presence panel (has a send field)
0882: *
0883: * @return (optional) template name for this panel
0884: */
0885: public String buildPresencePanelContext(VelocityPortlet portlet,
0886: Context context, RunData rundata, SessionState state) {
0887: context.put("tlang", rb);
0888: String template = null;
0889:
0890: // get the observer
0891: PresenceObservingCourier observer = (PresenceObservingCourier) state
0892: .getAttribute(STATE_CHAT_PRESENCE_OBSERVER);
0893:
0894: // put into context a list of sessions with chat presence
0895: String location = observer.getLocation();
0896:
0897: // refresh our presence at the location
0898: PresenceService.setPresence(location);
0899:
0900: // get the current presence list (User objects) for this page
0901: List users = PresenceService.getPresentUsers(location);
0902: context.put("users", users);
0903:
0904: // inform the observing courier that we just updated the page...
0905: // if there are pending requests to do so they can be cleared
0906: observer.justDelivered();
0907:
0908: return null;
0909:
0910: } // buildPresencePanelContext
0911:
0912: /**
0913: * Handle a user posting a new chat message.
0914: */
0915: public void doSend(RunData runData, Context context) {
0916: // access the portlet element id to find our state
0917: // %%% use CHEF api instead of Jetspeed to get state
0918: String peid = ((JetspeedRunData) runData).getJs_peid();
0919: SessionState state = ((JetspeedRunData) runData)
0920: .getPortletSessionState(peid);
0921:
0922: // read in the message input
0923: // %%% JANDERSE - The user enters plaintext, but messages are now stored as formatted text;
0924: // therefore, the plaintext must be converted to formatted text when it is returned from the browser.
0925: String message = runData.getParameters().getCleanString(
0926: FORM_MESSAGE);
0927: message = FormattedText
0928: .convertPlaintextToFormattedText(message);
0929:
0930: // ignore empty messages
0931: if ((message == null) || (message.length() == 0))
0932: return;
0933:
0934: // deal with the channel not yet existing
0935: // TODO: we don't really need to read the channel to post... -ggolden
0936:
0937: // // TODO: TIMING
0938: // if (CurrentService.getInThread("DEBUG") == null)
0939: // CurrentService.setInThread("DEBUG", new StringBuffer());
0940: // long startTime = System.currentTimeMillis();
0941:
0942: ChatChannel channel = getChannel(state, (String) state
0943: .getAttribute(STATE_CHANNEL_REF));
0944:
0945: // // TODO: TIMING
0946: // long endTime = System.currentTimeMillis();
0947: // if (endTime-startTime > /*5*/000)
0948: // {
0949: // StringBuffer buf = (StringBuffer) CurrentService.getInThread("DEBUG");
0950: // if (buf != null)
0951: // {
0952: // buf.insert(0,"ChatAction.doSend: "
0953: // + state.getAttribute(STATE_CHANNEL_REF)
0954: // + " time: " + (endTime - startTime));
0955: // }
0956: // }
0957:
0958: // post the message
0959: if (channel != null) {
0960: try {
0961: ChatMessageEdit edit = channel.addChatMessage();
0962: edit.setBody(message);
0963: channel.commitMessage(edit);
0964: } catch (PermissionException e) {
0965: addAlert(state, rb.getString("youdonot3"));
0966: } catch (Exception e) // %%% why?
0967: {
0968: addAlert(state, rb.getString("therewaspro"));
0969: M_log.warn("doSend()", e);
0970: }
0971: } else {
0972: addAlert(state, (String) state
0973: .getAttribute(STATE_CHANNEL_PROBLEM));
0974: }
0975:
0976: } // doSend
0977:
0978: /**
0979: * Setup for the options panel.
0980: */
0981: public String buildOptionsPanelContext(VelocityPortlet portlet,
0982: Context context, RunData rundata, SessionState state) {
0983: context.put("tlang", rb);
0984: // provide "filter_type" with the current default value for filtering messages
0985: context.put("filter_type", (String) state
0986: .getAttribute(STATE_FILTER_TYPE));
0987:
0988: // provide "filter_type_form" with form field name for selecting a message filter
0989: context.put("filter_type_form", FORM_FILTER_TYPE);
0990:
0991: // provide "filter_days_param" as current value or default value for number of days
0992: context.put("filter_days_param", (String) state
0993: .getAttribute(STATE_FILTER_PARAM));
0994:
0995: // provide "filter_days_param_form" with form field name for filter parameter (number of days/messages)
0996: context.put("filter_days_param_form", FORM_FILTER_PARAM_DAYS);
0997:
0998: // provide "filter_param" as current value or default value for number of days/messages
0999: context.put("filter_number_param", (String) state
1000: .getAttribute(STATE_FILTER_PARAM));
1001:
1002: // provide "filter_param_form" with form field name for filter parameter (number of days/messages)
1003: context.put("filter_number_param_form",
1004: FORM_FILTER_PARAM_NUMBER);
1005:
1006: // provide "default_chat_channel" with the dafault channel-id for the user/group
1007: context.put("default_chat_channel", SiteService.MAIN_CONTAINER);
1008:
1009: // provide "chat_channel" with the current channel's id
1010: String placementContext = ToolManager.getCurrentPlacement()
1011: .getContext();
1012: String defaultChannel = ChatService.channelReference(
1013: placementContext, SiteService.MAIN_CONTAINER);
1014: String sitePrefix = defaultChannel.substring(0, defaultChannel
1015: .lastIndexOf(SiteService.MAIN_CONTAINER));
1016: String currentChannel = ((String) state
1017: .getAttribute(STATE_CHANNEL_REF)).substring(sitePrefix
1018: .length());
1019: context.put("chat_channel", currentChannel);
1020:
1021: // provide "chat_channels" as a list of channels belonging to this site
1022:
1023: // // TODO: TIMING
1024: // if (CurrentService.getInThread("DEBUG") == null)
1025: // CurrentService.setInThread("DEBUG", new StringBuffer());
1026: // long startTime = System.currentTimeMillis();
1027:
1028: Iterator aChannel = ChatService.getChannelIds(placementContext)
1029: .iterator();
1030:
1031: // // TODO: TIMING
1032: // long endTime = System.currentTimeMillis();
1033: // if (endTime-startTime > /*5*/000)
1034: // {
1035: // StringBuffer buf = (StringBuffer) CurrentService.getInThread("DEBUG");
1036: // if (buf != null)
1037: // {
1038: // buf.insert(0,"ChatAction.options: "
1039: // + state.getAttribute(STATE_CHANNEL_REF)
1040: // + " time: " + (endTime - startTime));
1041: // }
1042: // }
1043:
1044: List channel_list = new Vector();
1045: while (aChannel.hasNext()) {
1046: String theChannel = (String) aChannel.next();
1047: if (!theChannel.equals(SiteService.MAIN_CONTAINER)
1048: && !theChannel.equals(currentChannel)) {
1049: channel_list.add(theChannel);
1050: }
1051: }
1052: context.put("chat_channels", channel_list);
1053:
1054: // provide "new_chat_channel" as flag to create a new channel
1055: context.put("new_chat_channel", NEW_CHAT_CHANNEL);
1056:
1057: // provide "form_new_channel" with form field name for specifying a new channel name
1058: context.put("form_new_channel", FORM_NEW_CHANNEL);
1059:
1060: // provide "chat_channel_form" with the form name for the new channel selection field
1061: context.put("chat_channel_form", FORM_CHANNEL);
1062:
1063: // set the action for form processing
1064: context.put(Menu.CONTEXT_ACTION, state
1065: .getAttribute(STATE_ACTION));
1066: context.put("form-submit", BUTTON + "doUpdate");
1067: context.put("form-cancel", BUTTON + "doCancel");
1068:
1069: // pick the "-customize" template based on the standard template name
1070: String template = (String) getContext(rundata).get("template");
1071: return template + "-customize";
1072:
1073: } // buildOptionsPanelContext
1074:
1075: public String buildConfirmDeleteMessagePanelContext(
1076: VelocityPortlet portlet, Context context, RunData rundata,
1077: SessionState state) {
1078: context.put("tlang", rb);
1079: // Put the message object into the context (the message that is about to be deleted)
1080: try {
1081: // String messageRef = ChatService.messageReference(
1082: // (String) state.getAttribute(STATE_CHANNEL_REF),
1083: // (String) state.getAttribute("messageid"));
1084: // Reference msgRef = new Reference(messageRef);
1085:
1086: // // TODO: TIMING
1087: // if (CurrentService.getInThread("DEBUG") == null)
1088: // CurrentService.setInThread("DEBUG", new StringBuffer());
1089: // long startTime = System.currentTimeMillis();
1090:
1091: // Message msg = ChatService.getMessage(msgRef);
1092: String messageid = (String) state.getAttribute("messageid");
1093: ChatChannel channel = ChatService
1094: .getChatChannel((String) state
1095: .getAttribute(STATE_CHANNEL_REF));
1096: ChatMessage msg = channel.getChatMessage(messageid);
1097:
1098: // // TODO: TIMING
1099: // long endTime = System.currentTimeMillis();
1100: // if (endTime-startTime > /*5*/000)
1101: // {
1102: // StringBuffer buf = (StringBuffer) CurrentService.getInThread("DEBUG");
1103: // if (buf != null)
1104: // {
1105: // buf.insert(0,"ChatAction.confirmDelete: "
1106: // + state.getAttribute(STATE_CHANNEL_REF)
1107: // + " time: " + (endTime - startTime));
1108: // }
1109: // }
1110:
1111: context.put("message", msg);
1112: } catch (PermissionException e) {
1113: context.put("alertMessage", rb.getString("youdonot4"));
1114: } catch (IdUnusedException e) {
1115: } catch (Exception e) {
1116: M_log.warn("buildConfirmDeleteMessagePanelContext()", e);
1117: }
1118:
1119: String template = (String) getContext(rundata).get("template");
1120: return template + "-delete";
1121: }
1122:
1123: /**
1124: * Handle a user clicking the "Done" button in the Options panel
1125: */
1126: public void doUpdate(RunData data, Context context) {
1127: // access the portlet element id to find our state
1128: // %%% use CHEF api instead of Jetspeed to get state
1129: String peid = ((JetspeedRunData) data).getJs_peid();
1130: SessionState state = ((JetspeedRunData) data)
1131: .getPortletSessionState(peid);
1132:
1133: String placementContext = ToolManager.getCurrentPlacement()
1134: .getContext();
1135: String newChannel = data.getParameters()
1136: .getString(FORM_CHANNEL);
1137: String currentChannel = ((String) state
1138: .getAttribute(STATE_CHANNEL_REF))
1139: .substring(placementContext.length() + 1);
1140:
1141: if (newChannel != null && newChannel.equals(NEW_CHAT_CHANNEL)) {
1142: newChannel = data.getParameters().getString(
1143: FORM_NEW_CHANNEL);
1144: // make sure channel name is valid Resource ID (for items entered by user)
1145: if (!Validator.checkResourceId(newChannel)) {
1146: // if name is not valid, save error message and return to Options panel
1147: addAlert(state, rb.getString("youent") + " \" "
1148: + newChannel + " \" " + rb.getString("forchat"));
1149: return;
1150: }
1151: }
1152: if (newChannel != null && !newChannel.equals(currentChannel)) {
1153: state.setAttribute(STATE_CHANNEL_REF, ChatService
1154: .channelReference(placementContext, newChannel));
1155: if (M_log.isDebugEnabled())
1156: M_log.debug("doUpdate(): newChannel: " + newChannel);
1157: // ChatChannel chan = getChannel(state, newChannel);
1158: updateObservationOfChannel(state, peid);
1159:
1160: // update the tool config
1161: Placement placement = ToolManager.getCurrentPlacement();
1162: placement.getPlacementConfig().setProperty(PARAM_CHANNEL,
1163: (String) state.getAttribute(STATE_CHANNEL_REF));
1164: placement.setTitle(rb.getString("chatroom") + " \" "
1165: + newChannel + " \" ");
1166:
1167: // deliver an update to the title panel (to show the new title)
1168: String titleId = titlePanelUpdateId(peid);
1169: schedulePeerFrameRefresh(titleId);
1170: }
1171:
1172: // filter
1173: String filter_type = data.getParameters().getString(
1174: FORM_FILTER_TYPE);
1175: if (filter_type != null) {
1176: if (filter_type.equals(FILTER_ALL)) {
1177: if (!filter_type.equals((String) state
1178: .getAttribute(STATE_FILTER_TYPE))) {
1179: updateMessageFilters(state, filter_type, null);
1180:
1181: // update the tool config
1182: Placement placement = ToolManager
1183: .getCurrentPlacement();
1184: placement.getPlacementConfig().setProperty(
1185: PARAM_FILTER_TYPE,
1186: (String) state
1187: .getAttribute(STATE_FILTER_TYPE));
1188: placement.getPlacementConfig().setProperty(
1189: PARAM_FILTER_PARAM,
1190: (String) state
1191: .getAttribute(STATE_FILTER_PARAM));
1192: }
1193: } else if (filter_type.equals(FILTER_BY_TIME)) {
1194: String filter_days_param = data.getParameters()
1195: .getString(FORM_FILTER_PARAM_DAYS);
1196: if (filter_days_param != null) {
1197: if (!filter_type.equals((String) state
1198: .getAttribute(STATE_FILTER_TYPE))
1199: || !filter_days_param.equals((String) state
1200: .getAttribute(STATE_FILTER_PARAM))) {
1201: updateMessageFilters(state, filter_type,
1202: filter_days_param);
1203:
1204: // update the tool config
1205: Placement placement = ToolManager
1206: .getCurrentPlacement();
1207: placement
1208: .getPlacementConfig()
1209: .setProperty(
1210: PARAM_FILTER_TYPE,
1211: (String) state
1212: .getAttribute(STATE_FILTER_TYPE));
1213: placement
1214: .getPlacementConfig()
1215: .setProperty(
1216: PARAM_FILTER_PARAM,
1217: (String) state
1218: .getAttribute(STATE_FILTER_PARAM));
1219: }
1220: }
1221: } else if (filter_type.equals(FILTER_BY_NUMBER)) {
1222: String filter_number_param = data.getParameters()
1223: .getString(FORM_FILTER_PARAM_NUMBER);
1224: if (filter_number_param != null) {
1225: if (!filter_type.equals((String) state
1226: .getAttribute(STATE_FILTER_TYPE))
1227: || !filter_number_param
1228: .equals((String) state
1229: .getAttribute(STATE_FILTER_PARAM))) {
1230: updateMessageFilters(state, filter_type,
1231: filter_number_param);
1232:
1233: // update the tool config
1234: Placement placement = ToolManager
1235: .getCurrentPlacement();
1236: placement
1237: .getPlacementConfig()
1238: .setProperty(
1239: PARAM_FILTER_TYPE,
1240: (String) state
1241: .getAttribute(STATE_FILTER_TYPE));
1242: placement
1243: .getPlacementConfig()
1244: .setProperty(
1245: PARAM_FILTER_PARAM,
1246: (String) state
1247: .getAttribute(STATE_FILTER_PARAM));
1248: }
1249: }
1250: }
1251: }
1252:
1253: // we are done with customization... back to the main mode
1254: state.removeAttribute(STATE_MODE);
1255:
1256: // re-enable auto-updates when leaving options
1257: enableObservers(state);
1258:
1259: // commit the change
1260: saveOptions();
1261:
1262: } // doUpdate
1263:
1264: /**
1265: * Handle a user clicking the "Done" button in the Options panel
1266: */
1267: public void doCancel(RunData data, Context context) {
1268: // access the portlet element id to find our state
1269: // %%% use CHEF api instead of Jetspeed to get state
1270: String peid = ((JetspeedRunData) data).getJs_peid();
1271: SessionState state = ((JetspeedRunData) data)
1272: .getPortletSessionState(peid);
1273:
1274: // we are done with customization... back to the main mode
1275: state.removeAttribute(STATE_MODE);
1276:
1277: // re-enable auto-updates when leaving options
1278: enableObservers(state);
1279:
1280: // cancel the options
1281: cancelOptions();
1282:
1283: } // doCancel
1284:
1285: /**
1286: * Handle a user deleting a message - put up a confirmation page
1287: */
1288: public void doConfirmDeleteMessage(RunData data, Context context) {
1289: // access the portlet element id to find our state
1290: // %%% use CHEF api instead of Jetspeed to get state
1291: String peid = ((JetspeedRunData) data).getJs_peid();
1292: SessionState state = ((JetspeedRunData) data)
1293: .getPortletSessionState(peid);
1294:
1295: String messageid = data.getParameters().getString("messageid");
1296:
1297: state.setAttribute("messageid", messageid);
1298: state.setAttribute(STATE_MODE, MODE_CONFIRM_DELETE_MESSAGE);
1299:
1300: // schedule a main refresh
1301: schedulePeerFrameRefresh(mainPanelUpdateId(peid));
1302: }
1303:
1304: /**
1305: * Handle a user deleting a message - they've already confirmed the deletion, just delete it now
1306: */
1307: public void doDeleteMessage(RunData data, Context context) {
1308: // access the portlet element id to find our state
1309: // %%% use CHEF api instead of Jetspeed to get state
1310: String peid = ((JetspeedRunData) data).getJs_peid();
1311: SessionState state = ((JetspeedRunData) data)
1312: .getPortletSessionState(peid);
1313:
1314: // find the message and delete it now!
1315: try {
1316: String messageid = (String) state.getAttribute("messageid");
1317: ChatChannel channel = ChatService
1318: .getChatChannel((String) state
1319: .getAttribute(STATE_CHANNEL_REF));
1320: channel.removeMessage(messageid);
1321: } catch (PermissionException e) {
1322: context.put("alertMessage", rb.getString("youdonot4"));
1323: } catch (IdUnusedException e) {
1324: } catch (Exception e) {
1325: M_log.warn("doDeleteMessage()", e);
1326: }
1327:
1328: state.removeAttribute("messageid");
1329: state.removeAttribute(STATE_MODE);
1330: }
1331:
1332: interface ChatFilter {
1333: Time getAfterDate();
1334:
1335: int getLimitedToLatest();
1336: }
1337:
1338: /** A filter */
1339: class SelectMessagesByTime implements ChatFilter {
1340: /** The number of days back to accept messages. */
1341: private int m_days = 0;
1342:
1343: /** The cutoff time - messages before this are rejected. */
1344: private Time m_cutoff = null;
1345:
1346: /**
1347: * Constructor
1348: *
1349: * @param days
1350: * The number of days back to accept messages.
1351: */
1352: public SelectMessagesByTime(int days) {
1353: // Log.info("chef", this + ".SelectMessagesByTime(" + days + ")");
1354: m_days = days;
1355:
1356: // compute the cutoff - Note: use the filter fast - the clock is ticking.
1357: m_cutoff = TimeService.newTime(System.currentTimeMillis()
1358: - ((long) days * 24l * 60l * 60l * 1000l));
1359:
1360: } // SelectMessagesByTime
1361:
1362: public Time getAfterDate() {
1363: return m_cutoff;
1364: }
1365:
1366: public int getLimitedToLatest() {
1367: return 0;
1368: }
1369:
1370: public String toString() {
1371: return this .getClass().getName() + " "
1372: + Integer.toString(m_days);
1373: }
1374: }
1375:
1376: /** A filter */
1377: class SelectMessagesByNumber implements ChatFilter {
1378: /** The cutoff value - messages before this date/time are rejected. */
1379: private Time m_first;
1380:
1381: /** the number of messages to select */
1382: private int m_number;
1383:
1384: /**
1385: * Constructor
1386: *
1387: * @param number
1388: * The number of the messages to be returned
1389: */
1390: public SelectMessagesByNumber(int number) {
1391: // Log.info("chef", this + ".SelectMessagesByNumber(" + number + ")");
1392: m_number = number;
1393: }
1394:
1395: public Time getAfterDate() {
1396: return null;
1397: }
1398:
1399: public int getLimitedToLatest() {
1400: return m_number;
1401: }
1402:
1403: public String toString() {
1404: return this .getClass().getName() + " " + m_number;
1405:
1406: } // toString
1407:
1408: } // SelectMessagesByNumber
1409:
1410: /** A filter */
1411: class SelectAllMessages implements ChatFilter {
1412: /** Constructor for the SelectAllMessages object */
1413: public SelectAllMessages() {
1414: // Log.info("chef", this + ".SelectAllMessages()");
1415: } // SelectAllMessages
1416:
1417: public Time getAfterDate() {
1418: return null;
1419: }
1420:
1421: public int getLimitedToLatest() {
1422: return 0;
1423: }
1424:
1425: public String toString() {
1426: return this .getClass().getName();
1427:
1428: } // toString
1429:
1430: } // SelectAllMessages
1431:
1432: /** A filter that gets all messages since midnight today, local time */
1433: class SelectTodaysMessages implements ChatFilter {
1434: /** The cutoff time - messages before this are rejected. */
1435: private Time m_cutoff = null;
1436:
1437: /** Constructor for the SelectTodaysMessages object */
1438: public SelectTodaysMessages() {
1439: super ();
1440: // Log.info("chef", this + ".SelectTodaysMessages()");
1441:
1442: TimeBreakdown now = (TimeService.newTime(System
1443: .currentTimeMillis())).breakdownLocal();
1444: // compute the cutoff for midnight today.
1445: m_cutoff = TimeService.newTimeLocal(now.getYear(), now
1446: .getMonth(), now.getDay(), 0, 0, 0, 0);
1447:
1448: } // SelectTodaysMessages
1449:
1450: public Time getAfterDate() {
1451: return m_cutoff;
1452: }
1453:
1454: public int getLimitedToLatest() {
1455: return 0;
1456: }
1457:
1458: public String toString() {
1459: return this .getClass().getName();
1460:
1461: } // toString
1462:
1463: } // SelectTodaysMessages
1464:
1465: /**
1466: * Handle a request to set options.
1467: */
1468: public void doOptions(RunData runData, Context context) {
1469: super .doOptions(runData, context);
1470:
1471: // access the portlet element id to find our state
1472: String peid = ((JetspeedRunData) runData).getJs_peid();
1473: SessionState state = ((JetspeedRunData) runData)
1474: .getPortletSessionState(peid);
1475:
1476: // if there's an alert message, divert it to the main frame
1477: String msg = (String) state.getAttribute(STATE_MESSAGE);
1478: state.setAttribute(STATE_MAIN_MESSAGE, msg);
1479: state
1480: .removeAttribute(VelocityPortletPaneledAction.STATE_MESSAGE);
1481:
1482: } // doOptions
1483:
1484: /**
1485: * Fire up the permissions editor, next request cycle
1486: */
1487: public void doPermissions(RunData data, Context context) {
1488: String peid = ((JetspeedRunData) data).getJs_peid();
1489: SessionState state = ((JetspeedRunData) data)
1490: .getPortletSessionState(peid);
1491:
1492: // trigger the switch on the next request (which is going to happen after this action is processed with its redirect response to the build)
1493: state.setAttribute(STATE_PERMISSIONS, STATE_PERMISSIONS);
1494:
1495: // schedule a main refresh to excape from the toolbar panel
1496: schedulePeerFrameRefresh(mainPanelUpdateId(peid));
1497: }
1498:
1499: /**
1500: * Fire up the permissions editor
1501: */
1502: protected void doPermissionsNow(RunData data, Context context) {
1503: // get into helper mode with this helper tool
1504: startHelper(data.getRequest(), "sakai.permissions.helper");
1505:
1506: String peid = ((JetspeedRunData) data).getJs_peid();
1507: SessionState state = ((JetspeedRunData) data)
1508: .getPortletSessionState(peid);
1509:
1510: String channelRefStr = (String) state
1511: .getAttribute(STATE_CHANNEL_REF);
1512: Reference channelRef = EntityManager
1513: .newReference(channelRefStr);
1514: String siteRef = SiteService.siteReference(channelRef
1515: .getContext());
1516:
1517: // setup for editing the permissions of the site for this tool, using the roles of this site, too
1518: state.setAttribute(PermissionsHelper.TARGET_REF, siteRef);
1519:
1520: // ... with this description
1521: state.setAttribute(PermissionsHelper.DESCRIPTION, rb
1522: .getString("setpermis")
1523: + " "
1524: + SiteService.getSiteDisplay(channelRef.getContext()));
1525:
1526: // ... showing only locks that are prpefixed with this
1527: state.setAttribute(PermissionsHelper.PREFIX, "chat.");
1528: }
1529: }
|