// @formatter:off // @formatter:off /** * Copyright 2010 Google Inc. * * 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 cc.kune.wave.client; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.waveprotocol.wave.client.account.Profile; import org.waveprotocol.wave.client.account.ProfileManager; import org.waveprotocol.wave.client.common.safehtml.EscapeUtils; import org.waveprotocol.wave.client.common.safehtml.SafeHtmlBuilder; import org.waveprotocol.wave.client.render.RenderingRules; import org.waveprotocol.wave.client.state.ThreadReadStateMonitor; import org.waveprotocol.wave.client.uibuilder.HtmlClosure; import org.waveprotocol.wave.client.uibuilder.HtmlClosureCollection; import org.waveprotocol.wave.client.uibuilder.UiBuilder; import org.waveprotocol.wave.client.wavepanel.render.ShallowBlipRenderer; import org.waveprotocol.wave.client.wavepanel.view.ViewIdMapper; import org.waveprotocol.wave.client.wavepanel.view.dom.full.AnchorViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.BlipMetaViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.BlipViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ContinuationIndicatorViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.InlineThreadViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ParticipantAvatarViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ParticipantNameViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ParticipantsViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ReplyBoxViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.RootThreadViewBuilder; import org.waveprotocol.wave.client.wavepanel.view.dom.full.ViewFactory; import org.waveprotocol.wave.model.conversation.Conversation; import org.waveprotocol.wave.model.conversation.ConversationBlip; import org.waveprotocol.wave.model.conversation.ConversationThread; import org.waveprotocol.wave.model.conversation.ConversationView; import org.waveprotocol.wave.model.util.CollectionUtils; import org.waveprotocol.wave.model.util.IdentityMap; import org.waveprotocol.wave.model.util.IdentityMap.ProcV; import org.waveprotocol.wave.model.util.IdentityMap.Reduce; import org.waveprotocol.wave.model.util.StringMap; import org.waveprotocol.wave.model.wave.ParticipantId; import cc.kune.common.client.utils.WindowUtils; import cc.kune.core.client.state.SiteParameters; // TODO: Auto-generated Javadoc /** * Renders conversational objects with UiBuilders. * * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado) */ public final class CustomFullDomRenderer implements RenderingRules<UiBuilder> { /** * The Interface DocRefRenderer. * * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado) */ public interface DocRefRenderer { /** * Render. * * @param blip the blip * @param replies the replies * @return the ui builder */ UiBuilder render(ConversationBlip blip, IdentityMap<ConversationThread, UiBuilder> replies); /** The empty. */ DocRefRenderer EMPTY = new DocRefRenderer() { @Override public UiBuilder render(ConversationBlip blip, IdentityMap<ConversationThread, UiBuilder> replies) { return UiBuilder.Constant.of(EscapeUtils.fromSafeConstant("<div></div>")); } }; } /** * The Interface ParticipantsRenderer. * * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado) */ public interface ParticipantsRenderer { /** * Render. * * @param c the c * @return the ui builder */ UiBuilder render(Conversation c); /** The empty. */ ParticipantsRenderer EMPTY = new ParticipantsRenderer() { @Override public UiBuilder render(Conversation c) { return UiBuilder.Constant.of(EscapeUtils.fromSafeConstant("<div></div>")); } }; } /** The blip populator. */ private final ShallowBlipRenderer blipPopulator; /** The doc renderer. */ private final DocRefRenderer docRenderer; /** The view id mapper. */ private final ViewIdMapper viewIdMapper; /** The view factory. */ private final ViewFactory viewFactory; /** The profile manager. */ private final ProfileManager profileManager; /** The read monitor. */ private final ThreadReadStateMonitor readMonitor; /** The show participants panel. */ private final boolean showParticipantsPanel; /** * Instantiates a new custom full dom renderer. * * @param blipPopulator the blip populator * @param docRenderer the doc renderer * @param profileManager the profile manager * @param viewIdMapper the view id mapper * @param viewFactory the view factory * @param readMonitor the read monitor * @param showParticipantsPanel the show participants panel */ public CustomFullDomRenderer(ShallowBlipRenderer blipPopulator, DocRefRenderer docRenderer, ProfileManager profileManager, ViewIdMapper viewIdMapper, ViewFactory viewFactory, ThreadReadStateMonitor readMonitor, boolean showParticipantsPanel) { this.blipPopulator = blipPopulator; this.docRenderer = docRenderer; this.profileManager = profileManager; this.viewIdMapper = viewIdMapper; this.viewFactory = viewFactory; this.readMonitor = readMonitor; this.showParticipantsPanel = showParticipantsPanel; } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.ConversationView, org.waveprotocol.wave.model.util.IdentityMap) */ @Override public UiBuilder render(ConversationView wave, IdentityMap<Conversation, UiBuilder> conversations) { // return the first conversation in the view. // TODO(hearnden): select the 'best' conversation. return conversations.isEmpty() ? null : getFirstConversation(conversations); } /** * Gets the first conversation. * * @param conversations the conversations * @return the first conversation */ public UiBuilder getFirstConversation(IdentityMap<Conversation, UiBuilder> conversations) { return conversations.reduce(null, new Reduce<Conversation, UiBuilder, UiBuilder>() { @Override public UiBuilder apply(UiBuilder soFar, Conversation key, UiBuilder item) { // Pick the first rendering (any will do). return soFar == null ? item : soFar; } }); } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.Conversation, java.lang.Object, java.lang.Object) */ @Override public UiBuilder render(Conversation conversation, UiBuilder participantsUi, UiBuilder threadUi) { String id = viewIdMapper.conversationOf(conversation); boolean isTop = !conversation.hasAnchor(); return isTop ? viewFactory.createTopConversationView(id, threadUi, participantsUi) : viewFactory.createInlineConversationView(id, threadUi, participantsUi); } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.Conversation, org.waveprotocol.wave.model.util.StringMap) */ @Override public UiBuilder render(Conversation conversation, StringMap<UiBuilder> participantUis) { HtmlClosureCollection participantsUi = new HtmlClosureCollection(); for (ParticipantId participant : conversation.getParticipantIds()) { participantsUi.add(participantUis.get(participant.getAddress())); } String id = viewIdMapper.participantsOf(conversation); // Kune patch (but not used) return showParticipantsPanel? ParticipantsViewBuilder.create(id, participantsUi): new UiBuilder() { @Override public void outputHtml(SafeHtmlBuilder arg0) { // Don't show nothing }}; } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.Conversation, org.waveprotocol.wave.model.wave.ParticipantId) */ @Override public UiBuilder render(Conversation conversation, ParticipantId participant) { Profile profile = profileManager.getProfile(participant); String id = viewIdMapper.participantOf(conversation, participant); // Use ParticipantAvatarViewBuilder for avatars. if (WindowUtils.getParameter(SiteParameters.WAVE_AVATARS_DISABLED) != null) { ParticipantNameViewBuilder participantUi = ParticipantNameViewBuilder.create(id); participantUi.setAvatar(profile.getImageUrl()); participantUi.setName(profile.getFullName()); return participantUi; } else { ParticipantAvatarViewBuilder participantUi = ParticipantAvatarViewBuilder.create(id); participantUi.setAvatar(profile.getImageUrl()); participantUi.setName(profile.getFullName()); return participantUi; } } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.ConversationThread, org.waveprotocol.wave.model.util.IdentityMap) */ @Override public UiBuilder render(final ConversationThread thread, final IdentityMap<ConversationBlip, UiBuilder> blipUis) { HtmlClosure blipsUi = new HtmlClosure() { @Override public void outputHtml(SafeHtmlBuilder out) { for (ConversationBlip blip : thread.getBlips()) { UiBuilder blipUi = blipUis.get(blip); // Not all blips are rendered. if (blipUi != null) { blipUi.outputHtml(out); } } } }; String threadId = viewIdMapper.threadOf(thread); String replyIndicatorId = viewIdMapper.replyIndicatorOf(thread); UiBuilder builder = null; if (thread.getConversation().getRootThread() == thread) { ReplyBoxViewBuilder replyBoxBuilder = ReplyBoxViewBuilder.create(replyIndicatorId); builder = RootThreadViewBuilder.create(threadId, blipsUi, replyBoxBuilder); } else { ContinuationIndicatorViewBuilder indicatorBuilder = ContinuationIndicatorViewBuilder.create( replyIndicatorId); InlineThreadViewBuilder inlineBuilder = InlineThreadViewBuilder.create(threadId, blipsUi, indicatorBuilder); int read = readMonitor.getReadCount(thread); int unread = readMonitor.getUnreadCount(thread); inlineBuilder.setTotalBlipCount(read + unread); inlineBuilder.setUnreadBlipCount(unread); builder = inlineBuilder; } return builder; } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.ConversationBlip, java.lang.Object, org.waveprotocol.wave.model.util.IdentityMap, org.waveprotocol.wave.model.util.IdentityMap) */ @Override public UiBuilder render(final ConversationBlip blip, UiBuilder document, final IdentityMap<ConversationThread, UiBuilder> anchorUis, final IdentityMap<Conversation, UiBuilder> nestedConversations) { UiBuilder threadsUi = new UiBuilder() { @Override public void outputHtml(SafeHtmlBuilder out) { for (ConversationThread thread : blip.getReplyThreads()) { anchorUis.get(thread).outputHtml(out); } } }; UiBuilder convsUi = new UiBuilder() { @Override public void outputHtml(SafeHtmlBuilder out) { // Order by conversation id. Ideally, the sort key would be creation // time, but that is not exposed in the conversation API. final List<Conversation> ordered = CollectionUtils.newArrayList(); nestedConversations.each(new ProcV<Conversation, UiBuilder>() { @Override public void apply(Conversation conv, UiBuilder ui) { ordered.add(conv); } }); Collections.sort(ordered, new Comparator<Conversation>() { @Override public int compare(Conversation o1, Conversation o2) { return o1.getId().compareTo(o2.getId()); } }); // List<UiBuilder> orderedUis = CollectionUtils.newArrayList(); for (Conversation conv : ordered) { nestedConversations.get(conv).outputHtml(out); } } }; BlipMetaViewBuilder metaUi = BlipMetaViewBuilder.create(viewIdMapper.metaOf(blip), document); if (blip.isRoot()) metaUi.disable(BlipMetaViewBuilder.DELETE_MENU_OPTIONS_SET); blipPopulator.render(blip, metaUi); return BlipViewBuilder.create(viewIdMapper.blipOf(blip), metaUi, threadsUi, convsUi, blip.isRoot()); } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.ConversationBlip, org.waveprotocol.wave.model.util.IdentityMap) */ @Override public UiBuilder render( ConversationBlip blip, IdentityMap<ConversationThread, UiBuilder> replies) { return docRenderer.render(blip, replies); } /* (non-Javadoc) * @see org.waveprotocol.wave.client.render.RenderingRules#render(org.waveprotocol.wave.model.conversation.ConversationThread, java.lang.Object) */ @Override public UiBuilder render(ConversationThread thread, UiBuilder threadR) { String id = EscapeUtils.htmlEscape(viewIdMapper.defaultAnchorOf(thread)); return AnchorViewBuilder.create(id, threadR); } }