/*
* Copyright (c) 2009-2011 Lockheed Martin Corporation
*
* 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.eurekastreams.web.client.ui.common.stream.renderers;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eurekastreams.commons.formatting.DateFormatter;
import org.eurekastreams.server.domain.stream.ActivityDTO;
import org.eurekastreams.server.domain.stream.ActivityVerb;
import org.eurekastreams.server.domain.stream.BaseObjectType;
import org.eurekastreams.server.domain.stream.StreamEntityDTO;
import org.eurekastreams.web.client.model.GroupStickyActivityModel;
import org.eurekastreams.web.client.ui.common.dialog.Dialog;
import org.eurekastreams.web.client.ui.common.pagedlist.ItemRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.StreamMessageItemRenderer.State;
import org.eurekastreams.web.client.ui.common.stream.renderers.object.BookmarkRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.object.FileRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.object.NoteRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.object.ObjectRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.object.VideoRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.verb.PostRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.verb.ShareRenderer;
import org.eurekastreams.web.client.ui.common.stream.renderers.verb.VerbRenderer;
import org.eurekastreams.web.client.ui.common.stream.share.ShareMessageDialogContent;
import org.eurekastreams.web.client.ui.pages.master.StaticResourceBundle;
import org.eurekastreams.web.client.utility.BaseActivityLinkBuilder;
import org.eurekastreams.web.client.utility.InContextActivityLinkBuilder;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
/**
* Renders an activity for the sticky display at the top of the list.
*/
public class StickyActivityRenderer implements ItemRenderer<ActivityDTO>
{
/** Verb dictionary. */
private final Map<ActivityVerb, VerbRenderer> verbDictionary = new HashMap<ActivityVerb, VerbRenderer>();
/** Object dictionary. */
private final Map<BaseObjectType, ObjectRenderer> objectDictionary = new HashMap<BaseObjectType, ObjectRenderer>();
/** For building links to activities. */
private final BaseActivityLinkBuilder activityLinkBuilder = new InContextActivityLinkBuilder();
/**
* Constructor.
*/
public StickyActivityRenderer()
{
verbDictionary.put(ActivityVerb.POST, new PostRenderer());
verbDictionary.put(ActivityVerb.SHARE, new ShareRenderer());
objectDictionary.put(BaseObjectType.BOOKMARK, new BookmarkRenderer());
objectDictionary.put(BaseObjectType.NOTE, new NoteRenderer());
objectDictionary.put(BaseObjectType.VIDEO, new VideoRenderer());
objectDictionary.put(BaseObjectType.FILE, new FileRenderer());
}
/**
* Render a message item.
*
* @param msg
* the message item.
*
* @return the rendered item as a FlowPanel.
*/
public Panel render(final ActivityDTO msg)
{
Panel mainPanel = new FlowPanel();
mainPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().streamMessageItem());
mainPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().listItem());
mainPanel.addStyleName(State.READONLY.toString());
VerbRenderer verbRenderer = verbDictionary.get(msg.getVerb());
verbRenderer.setup(objectDictionary, msg, State.DEFAULT, false);
// left column items
Panel leftColumn = null;
// avatar
Widget avatar = verbRenderer.getAvatar();
if (avatar != null)
{
Panel parent = leftColumn == null ? mainPanel : leftColumn;
parent.add(avatar);
}
FlowPanel msgContent = new FlowPanel();
msgContent.addStyleName(StaticResourceBundle.INSTANCE.coreCss().description());
mainPanel.add(msgContent);
// row for who posted
Panel sourceMetaData = new FlowPanel();
sourceMetaData.addStyleName(StaticResourceBundle.INSTANCE.coreCss().messageMetadataSource());
for (StatefulRenderer itemRenderer : verbRenderer.getSourceMetaDataItemRenderers())
{
Widget metaDataItem = itemRenderer.render();
if (metaDataItem != null)
{
sourceMetaData.add(metaDataItem);
}
}
msgContent.add(sourceMetaData);
// content
FlowPanel nonMetaData = new FlowPanel();
nonMetaData.addStyleName(State.READONLY.toString());
Widget content = verbRenderer.getContent();
if (content != null)
{
nonMetaData.add(content);
msgContent.add(nonMetaData);
}
// additional metadata
FlowPanel metaData = new FlowPanel();
metaData.addStyleName(StaticResourceBundle.INSTANCE.coreCss().messageMetadataAdditional());
for (StatefulRenderer itemRenderer : verbRenderer.getMetaDataItemRenderers())
{
Widget metaDataItem = itemRenderer.render();
if (metaDataItem != null)
{
metaData.add(metaDataItem);
}
}
if (metaData.getWidgetCount() > 0)
{
msgContent.add(metaData);
}
msgContent.add(buildActionsLine(msg, verbRenderer));
return mainPanel;
}
/**
* Builds the action links line.
*
* @param msg
* The message.
* @param verbRenderer
* Renderer for the message's verb.
* @return The actions panel.
*/
private Widget buildActionsLine(final ActivityDTO msg, final VerbRenderer verbRenderer)
{
StreamEntityDTO destinationStream = msg.getDestinationStream();
// timestamp and actions
Panel timestampActions = new FlowPanel();
timestampActions.addStyleName(StaticResourceBundle.INSTANCE.coreCss().messageTimestampActionsArea());
// Hijack this property and use to show lock icon for private activity.
if (!msg.isShareable())
{
Label lockIcon = new Label("");
lockIcon.addStyleName(StaticResourceBundle.INSTANCE.coreCss().privateIcon());
timestampActions.add(lockIcon);
}
// create timestamp as permalink
String date = new DateFormatter(new Date()).timeAgo(msg.getPostedTime());
Widget dateLink;
String permalinkUrl = activityLinkBuilder.buildActivityPermalink(msg.getId(), destinationStream.getType(),
destinationStream.getUniqueIdentifier());
dateLink = new InlineHyperlink(date, permalinkUrl);
dateLink.addStyleName(StaticResourceBundle.INSTANCE.coreCss().messageTimestampLink());
timestampActions.add(dateLink);
if (msg.getAppName() != null)
{
String appSource = msg.getAppSource();
if (appSource != null)
{
FlowPanel viaPanel = new FlowPanel();
viaPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().viaMetadata());
viaPanel.add(new InlineLabel("via "));
viaPanel.add(new Anchor(msg.getAppName(), appSource));
timestampActions.add(viaPanel);
}
else
{
InlineLabel viaLine = new InlineLabel("via " + msg.getAppName());
viaLine.addStyleName(StaticResourceBundle.INSTANCE.coreCss().viaMetadata());
timestampActions.add(viaLine);
}
// TODO: If appSource is not supplied, the link should go to the respective galleries for apps and plugins.
// However, the app galery requires knowing the start page tab id, and the worthwhile plugin gallery is only
// available to coordinators.
}
ComplexPanel actionsPanel = new FlowPanel();
actionsPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().messageActionsArea());
// Show comments
InlineHyperlink showCommentsLink = new InlineHyperlink("Show Comments", permalinkUrl);
actionsPanel.add(showCommentsLink);
// Share
if (verbRenderer.getAllowShare() && msg.isShareable())
{
insertActionSeparator(actionsPanel, null);
Label shareLink = new InlineLabel("Share");
shareLink.addStyleName(StaticResourceBundle.INSTANCE.coreCss().linkedLabel());
actionsPanel.add(shareLink);
shareLink.addClickHandler(new ClickHandler()
{
public void onClick(final ClickEvent event)
{
Dialog.showCentered(new ShareMessageDialogContent(msg));
}
});
}
// Unstick
// Note: using the cheating way: always create the link, let CSS hide it unless the user is actually a
// coordinator
insertActionSeparator(actionsPanel, StaticResourceBundle.INSTANCE.coreCss().ownerOnlyInline());
Label link = new InlineLabel("Unstick");
link.addStyleName(StaticResourceBundle.INSTANCE.coreCss().linkedLabel());
link.addStyleName(StaticResourceBundle.INSTANCE.coreCss().ownerOnlyInline());
actionsPanel.add(link);
link.addClickHandler(new ClickHandler()
{
public void onClick(final ClickEvent event)
{
GroupStickyActivityModel.getInstance().delete(msg.getDestinationStream().getDestinationEntityId());
}
});
timestampActions.add(actionsPanel);
return timestampActions;
}
/**
* Adds a separator (dot).
*
* @param panel
* Panel to put the separator in.
* @param extraStyle
* Extra style to add.
*/
private void insertActionSeparator(final ComplexPanel panel, final String extraStyle)
{
Label sep = new InlineLabel("\u2219");
sep.addStyleName(StaticResourceBundle.INSTANCE.coreCss().actionLinkSeparator());
if (extraStyle != null)
{
sep.addStyleName(extraStyle);
}
panel.add(sep);
}
}