// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tabmodel;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implement methods shared across the different model implementations.
*/
public abstract class TabModelSelectorBase implements TabModelSelector {
public static final int NORMAL_TAB_MODEL_INDEX = 0;
public static final int INCOGNITO_TAB_MODEL_INDEX = 1;
private List<TabModel> mTabModels = Collections.emptyList();
private int mActiveModelIndex = NORMAL_TAB_MODEL_INDEX;
private final ObserverList<TabModelSelectorObserver> mObservers =
new ObserverList<TabModelSelectorObserver>();
private boolean mTabStateInitialized;
protected final void initialize(boolean startIncognito, TabModel... models) {
// Only normal and incognito supported for now.
assert mTabModels.isEmpty();
assert models.length > 0;
if (startIncognito) {
assert models.length > INCOGNITO_TAB_MODEL_INDEX;
}
List<TabModel> tabModels = new ArrayList<TabModel>();
for (int i = 0; i < models.length; i++) {
tabModels.add(models[i]);
}
mActiveModelIndex = startIncognito ? INCOGNITO_TAB_MODEL_INDEX : NORMAL_TAB_MODEL_INDEX;
mTabModels = Collections.unmodifiableList(tabModels);
TabModelObserver tabModelObserver = new EmptyTabModelObserver() {
@Override
public void didAddTab(Tab tab, TabLaunchType type) {
notifyChanged();
notifyNewTabCreated(tab);
}
@Override
public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
notifyChanged();
}
@Override
public void didMoveTab(Tab tab, int newIndex, int curIndex) {
notifyChanged();
}
};
for (TabModel model : models) {
model.addObserver(tabModelObserver);
}
notifyChanged();
}
@Override
public void selectModel(boolean incognito) {
TabModel previousModel = getCurrentModel();
mActiveModelIndex = incognito ? INCOGNITO_TAB_MODEL_INDEX : NORMAL_TAB_MODEL_INDEX;
TabModel newModel = getCurrentModel();
if (previousModel != newModel) {
for (TabModelSelectorObserver listener : mObservers) {
listener.onTabModelSelected(newModel, previousModel);
}
}
}
@Override
public TabModel getModelAt(int index) {
assert (index < mTabModels.size() && index >= 0) :
"requested index " + index + " size " + mTabModels.size();
return mTabModels.get(index);
}
@Override
public Tab getCurrentTab() {
return getCurrentModel() == null ? null : TabModelUtils.getCurrentTab(getCurrentModel());
}
@Override
public int getCurrentTabId() {
Tab tab = getCurrentTab();
return tab != null ? tab.getId() : Tab.INVALID_TAB_ID;
}
@Override
public TabModel getModelForTabId(int id) {
for (int i = 0; i < mTabModels.size(); i++) {
TabModel model = mTabModels.get(i);
if (TabModelUtils.getTabById(model, id) != null || model.isClosurePending(id)) {
return model;
}
}
return null;
}
@Override
public TabModel getCurrentModel() {
return getModelAt(mActiveModelIndex);
}
@Override
public int getCurrentModelIndex() {
return mActiveModelIndex;
}
@Override
public TabModel getModel(boolean incognito) {
int index = incognito ? INCOGNITO_TAB_MODEL_INDEX : NORMAL_TAB_MODEL_INDEX;
return getModelAt(index);
}
@Override
public boolean isIncognitoSelected() {
return mActiveModelIndex == INCOGNITO_TAB_MODEL_INDEX;
}
@Override
public List<TabModel> getModels() {
return mTabModels;
}
@Override
public boolean closeTab(Tab tab) {
for (int i = 0; i < getModels().size(); i++) {
TabModel model = getModelAt(i);
if (model.indexOf(tab) >= 0) {
return model.closeTab(tab);
}
}
assert false : "Tried to close a tab that is not in any model!";
return false;
}
@Override
public void commitAllTabClosures() {
for (int i = 0; i < mTabModels.size(); i++) {
mTabModels.get(i).commitAllTabClosures();
}
}
@Override
public Tab getTabById(int id) {
for (int i = 0; i < getModels().size(); i++) {
Tab tab = TabModelUtils.getTabById(getModelAt(i), id);
if (tab != null) return tab;
}
return null;
}
@Override
public void closeAllTabs() {
closeAllTabs(false);
}
@Override
public void closeAllTabs(boolean uponExit) {
for (int i = 0; i < getModels().size(); i++) {
getModelAt(i).closeAllTabs(!uponExit, uponExit);
}
}
@Override
public int getTotalTabCount() {
int count = 0;
for (int i = 0; i < getModels().size(); i++) {
count += getModelAt(i).getCount();
}
return count;
}
@Override
public void addObserver(TabModelSelectorObserver observer) {
if (!mObservers.hasObserver(observer)) mObservers.addObserver(observer);
}
@Override
public void removeObserver(TabModelSelectorObserver observer) {
mObservers.removeObserver(observer);
}
@Override
public void setCloseAllTabsDelegate(CloseAllTabsDelegate delegate) { }
/**
* Marks the task state being initialized and notifies observers.
*/
public void markTabStateInitialized() {
mTabStateInitialized = true;
for (TabModelSelectorObserver listener : mObservers) listener.onTabStateInitialized();
}
@Override
public boolean isTabStateInitialized() {
return mTabStateInitialized;
}
@Override
public void destroy() {
for (int i = 0; i < getModels().size(); i++) getModelAt(i).destroy();
}
/**
* Notifies all the listeners that the {@link TabModelSelector} or its {@link TabModel} has
* changed.
*/
protected void notifyChanged() {
for (TabModelSelectorObserver listener : mObservers) {
listener.onChange();
}
}
/**
* Notifies all the listeners that a new tab has been created.
* @param tab The tab that has been created.
*/
private void notifyNewTabCreated(Tab tab) {
for (TabModelSelectorObserver listener : mObservers) {
listener.onNewTabCreated(tab);
}
}
}