/** * 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.reader; import com.google.common.annotations.VisibleForTesting; import org.waveprotocol.wave.client.wave.DocumentRegistry; import org.waveprotocol.wave.client.wave.InteractiveDocument; import org.waveprotocol.wave.client.wave.LocalSupplementedWave; import org.waveprotocol.wave.client.wavepanel.impl.focus.FocusFramePresenter; import org.waveprotocol.wave.client.wavepanel.impl.focus.FocusFramePresenter.FocusOrder; import org.waveprotocol.wave.client.wavepanel.impl.focus.ViewTraverser; import org.waveprotocol.wave.client.wavepanel.view.BlipView; import org.waveprotocol.wave.client.wavepanel.view.dom.ModelAsViewProvider; import org.waveprotocol.wave.model.conversation.ConversationBlip; /** * Inteprets focus-frame movement as reading actions, and also provides an * ordering for focus frame movement, based on unread content. * */ public final class Reader implements FocusFramePresenter.Listener, FocusOrder { private final LocalSupplementedWave supplement; private final ModelAsViewProvider models; private final ViewTraverser traverser; private final DocumentRegistry<? extends InteractiveDocument> documents; @VisibleForTesting Reader(LocalSupplementedWave supplement, ModelAsViewProvider models, DocumentRegistry<? extends InteractiveDocument> documents, ViewTraverser traverser) { this.supplement = supplement; this.models = models; this.documents = documents; this.traverser = traverser; } /** * Builds and installs the reading feature. * * @return the feature. */ public static Reader install(LocalSupplementedWave supplement, FocusFramePresenter focus, ModelAsViewProvider models, DocumentRegistry<? extends InteractiveDocument> documents) { ViewTraverser traverser = new ViewTraverser(); final Reader reader = new Reader(supplement, models, documents, traverser); focus.setOrder(reader); focus.addListener(reader); return reader; } @Override public void onFocusMoved(BlipView oldUi, BlipView newUi) { if (oldUi != null) { ConversationBlip oldBlip = models.getBlip(oldUi); InteractiveDocument document = documents.get(oldBlip); if (oldBlip != null) { supplement.stopReading(oldBlip); document.stopDiffRetention(); document.clearDiffs(); } } if (newUi != null) { // UI hack: normally, becoming read triggers diff clearing, except when // the cause of becoming read is focus-frame placement. ConversationBlip newBlip = models.getBlip(newUi); InteractiveDocument document = documents.get(newBlip); if (newBlip != null) { document.startDiffRetention(); supplement.startReading(newBlip); } } } private boolean isRead(BlipView blipUi) { return !supplement.isUnread(models.getBlip(blipUi)); } // // Next/Previous blips based on read/unread state. // @Override public BlipView getNext(BlipView start) { BlipView blipUi = traverser.getNext(start); while (blipUi != null && isRead(blipUi)) { blipUi = traverser.getNext(blipUi); } return blipUi; } @Override public BlipView getPrevious(BlipView start) { BlipView blipUi = traverser.getPrevious(start); while (blipUi != null && isRead(blipUi)) { blipUi = traverser.getPrevious(blipUi); } return blipUi; } }