/** * 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 org.waveprotocol.wave.client.wavepanel.impl.focus; import org.waveprotocol.wave.client.wavepanel.view.AnchorView; import org.waveprotocol.wave.client.wavepanel.view.BlipMetaView; import org.waveprotocol.wave.client.wavepanel.view.BlipView; import org.waveprotocol.wave.client.wavepanel.view.ConversationView; import org.waveprotocol.wave.client.wavepanel.view.InlineConversationView; import org.waveprotocol.wave.client.wavepanel.view.InlineThreadView; import org.waveprotocol.wave.client.wavepanel.view.RootThreadView; import org.waveprotocol.wave.client.wavepanel.view.ThreadView; import org.waveprotocol.wave.client.wavepanel.view.TopConversationView; import org.waveprotocol.wave.client.wavepanel.view.View; /** * Traverses the wave panel's view structure, defining the blip ordering for * focus movement. * */ public final class ViewTraverser { private boolean skipCollapsedContent; public void skipCollapsedContent() { this.skipCollapsedContent = true; } public void includeCollapsedContent() { this.skipCollapsedContent = false; } /** @return the input view, but after maybe filtering collapsed content. */ private boolean skip(InlineConversationView view) { return skipCollapsedContent && view.isCollapsed(); } /** @return the input view, but after maybe filtering collapsed content. */ private boolean skip(InlineThreadView view) { return skipCollapsedContent && view.isCollapsed(); } public BlipView getFirst(ConversationView v) { return getNextPre(v, v.getRootThread()); } public BlipView getNext(BlipView blip) { BlipMetaView meta = blip.getMeta(); return meta != null ? getNextPre(blip, meta) : getNextPost(blip, meta); } public BlipView getLast(ConversationView v) { return getPrevPre(v, v.getRootThread()); } public BlipView getPrevious(BlipView b) { return getPrevPost(b.getParent(), b); } // // Next Pre. // private BlipView getNextPre(ConversationView parent, RootThreadView thread) { BlipView first = thread.getBlipAfter(null); return first != null ? getNextPre(thread, first) : getNextPost(parent, thread); } private BlipView getNextPre(ThreadView parent, BlipView blip) { return blip; } private BlipView getNextPre(BlipView parent, BlipMetaView meta) { AnchorView first = meta.getInlineAnchorAfter(null); return first != null ? getNextPre(meta, first) : getNextPost(parent, meta); } private BlipView getNextPre(BlipMetaView parent, AnchorView anchor) { InlineThreadView contents = anchor.getThread(); return contents != null ? getNextPre(anchor, contents) : getNextPost(parent, anchor); } private BlipView getNextPre(AnchorView parent, InlineThreadView thread) { BlipView first = skip(thread) ? null : thread.getBlipAfter(null); return first != null ? getNextPre(thread, first) : getNextPost(parent, thread); } private BlipView getNextPre(BlipView parent, AnchorView anchor) { InlineThreadView contents = anchor.getThread(); return contents != null ? getNextPre(anchor, contents) : getNextPost(parent, anchor); } private BlipView getNextPre(BlipView parent, InlineConversationView conversation) { RootThreadView root = skip(conversation) ? null : conversation.getRootThread(); return root != null ? getNextPre(conversation, root) : getNextPost(parent, conversation); } // // Next Post. // private BlipView getNextPost(View parent, View child) { if (parent == null) { return null; } switch (parent.getType()) { case ANCHOR: return getNextPost((AnchorView) parent, (InlineThreadView) child); case META: return getNextPost((BlipMetaView) parent, (AnchorView) child); case BLIP: switch (child.getType()) { case META: return getNextPost((BlipView) parent, (BlipMetaView) child); case ANCHOR: return getNextPost((BlipView) parent, (AnchorView) child); case INLINE_CONVERSATION: return getNextPost((BlipView) parent, (InlineConversationView) child); default: throw new RuntimeException("unknown blip child type: " + child.getType()); } case INLINE_THREAD: return getNextPost((InlineThreadView) parent, (BlipView) child); case ROOT_THREAD: return getNextPost((RootThreadView) parent, (BlipView) child); case ROOT_CONVERSATION: return getNextPost((TopConversationView) parent, (RootThreadView) child); case INLINE_CONVERSATION: return getNextPost((InlineConversationView) parent, (RootThreadView) child); default: throw new RuntimeException("unknown container type: " + parent.getType()); } } private BlipView getNextPost(InlineConversationView parent, RootThreadView child) { return getNextPost(parent.getParent(), parent); } private BlipView getNextPost(TopConversationView parent, RootThreadView child) { return null; } private BlipView getNextPost(ThreadView parent, BlipView child) { BlipView next = parent.getBlipAfter(child); return next != null ? getNextPre(parent, next) : getNextPost(parent.getParent(), parent); } private BlipView getNextPost(BlipView parent, BlipMetaView meta) { return getNextPost(parent, (AnchorView) null); } private BlipView getNextPost(BlipView parent, AnchorView anchor) { AnchorView next = parent.getDefaultAnchorAfter(anchor); return (next != null) ? getNextPre(parent, next) : getNextPost(parent, (InlineConversationView) null); } private BlipView getNextPost(BlipView parent, InlineConversationView conversation) { InlineConversationView next = parent.getConversationAfter(conversation); return (next != null) ? getNextPre(parent, next) : getNextPost(parent.getParent(), parent); } private BlipView getNextPost(BlipMetaView parent, AnchorView anchor) { AnchorView next = parent.getInlineAnchorAfter(anchor); return next != null ? getNextPre(parent, next) : getNextPost(parent.getParent(), parent); } private BlipView getNextPost(AnchorView parent, InlineThreadView thread) { return getNextPost(parent.getParent(), parent); } // // Prev Pre. // private BlipView getPrevPre(ConversationView parent, RootThreadView thread) { BlipView last = thread.getBlipBefore(null); return last != null ? getPrevPre(thread, last) : getPrevPost(parent, thread); } private BlipView getPrevPre(ThreadView parent, BlipView blip) { InlineConversationView last = blip.getConversationBefore(null); return last != null ? getPrevPre(blip, last) : getPrevPost(blip, (InlineConversationView) null); } private BlipView getPrevPre(AnchorView parent, InlineThreadView thread) { BlipView last = skip(thread) ? null : thread.getBlipBefore(null); return last != null ? getPrevPre(thread, last) : getPrevPost(parent, thread); } private BlipView getPrevPre(BlipView parent, BlipMetaView meta) { AnchorView last = meta.getInlineAnchorBefore(null); return last != null ? getPrevPre(meta, last) : getPrevPost(parent, meta); } private BlipView getPrevPre(BlipView parent, AnchorView anchor) { InlineThreadView contents = anchor.getThread(); return contents != null ? getPrevPre(anchor, contents) : getPrevPost(anchor.getParent(), anchor); } private BlipView getPrevPre(BlipView parent, InlineConversationView conversation) { RootThreadView root = skip(conversation) ? null : conversation.getRootThread(); return root != null ? getPrevPre(conversation, root) : getPrevPost(conversation, root); } private BlipView getPrevPre(BlipMetaView parent, AnchorView anchor) { InlineThreadView contents = anchor.getThread(); return contents != null ? getPrevPre(anchor, contents) : getPrevPost(anchor.getParent(), anchor); } // // Prev Post. // private BlipView getPrevPost(View parent, View child) { if (parent == null) { return null; } switch (parent.getType()) { case ANCHOR: return getPrevPost((AnchorView) parent, (InlineThreadView) child); case META: return getPrevPost((BlipMetaView) parent, (AnchorView) child); case BLIP: switch (child.getType()) { case META: return getPrevPost((BlipView) parent, (BlipMetaView) child); case ANCHOR: return getPrevPost((BlipView) parent, (AnchorView) child); case INLINE_CONVERSATION: return getPrevPost((BlipView) parent, (InlineConversationView) child); default: throw new RuntimeException("unknown blip child type: " + child.getType()); } case INLINE_THREAD: return getPrevPost((ThreadView) parent, (BlipView) child); case ROOT_THREAD: return getPrevPost((ThreadView) parent, (BlipView) child); case INLINE_CONVERSATION: return getPrevPost((InlineConversationView) parent, (RootThreadView) child); case ROOT_CONVERSATION: return getPrevPost((TopConversationView) parent, (RootThreadView) child); default: throw new RuntimeException("unknown parent type: " + parent.getType()); } } private BlipView getPrevPost(InlineConversationView parent, RootThreadView child) { return getPrevPost(parent.getParent(), parent); } private BlipView getPrevPost(TopConversationView parent, RootThreadView child) { return null; } private BlipView getPrevPost(BlipView parent, AnchorView child) { AnchorView prev = parent.getDefaultAnchorBefore(child); BlipMetaView meta; return prev != null ? getPrevPre(parent, prev) // \u2620 : ((meta = parent.getMeta()) != null) // \u2620 ? getPrevPre(parent, meta) // \u2620 : getPrevPost(parent, meta); } private BlipView getPrevPost(BlipView parent, BlipMetaView child) { return parent; } private BlipView getPrevPost(BlipView parent, InlineConversationView child) { InlineConversationView prev = parent.getConversationBefore(child); return prev != null ? getPrevPre(parent, prev) : getPrevPost(parent, (AnchorView) null); } private BlipView getPrevPost(BlipMetaView parent, AnchorView child) { AnchorView prev = parent.getInlineAnchorBefore(child); return prev != null ? getPrevPre(parent, prev) : getPrevPost(parent.getParent(), parent); } private BlipView getPrevPost(ThreadView parent, BlipView child) { BlipView prev = parent.getBlipBefore(child); return prev != null ? getPrevPre(parent, prev) : getPrevPost(parent.getParent(), parent); } private BlipView getPrevPost(AnchorView parent, InlineThreadView child) { return getPrevPost(parent.getParent(), parent); } }