blob: 623bc1a125b1be82e29745c0a91758bac80830f3 [file] [log] [blame]
// Copyright 2018 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.ui.modelutil;
import org.chromium.ui.modelutil.PropertyObservable.PropertyObserver;
/**
* A model change processor for use with a {@link PropertyObservable} model. The
* {@link PropertyModelChangeProcessor} should be registered as a property observer of the model.
* Internally uses a view binder to bind model properties to the toolbar view.
* @param <M> The {@link PropertyObservable} model.
* @param <V> The view object that is changing.
* @param <P> The property of the view that changed.
*/
public class PropertyModelChangeProcessor<M extends PropertyObservable<P>, V, P> {
/**
* A generic view binder that associates a view with a model.
* @param <M> The {@link PropertyObservable} model.
* @param <V> The view object that is changing.
* @param <P> The property of the view that changed.
*/
public interface ViewBinder<M, V, P> { void bind(M model, V view, P propertyKey); }
private final V mView;
private final M mModel;
private final ViewBinder<M, V, P> mViewBinder;
private final PropertyObserver<P> mPropertyObserver = this::onPropertyChanged;
/**
* Construct a new PropertyModelChangeProcessor.
* @param model The model containing the data to be bound.
* @param view The view to which data will be bound.
* @param viewBinder A class that binds the model to the view.
* @param performInitialBind Whether all set model properties should be immediately bound.
*/
private PropertyModelChangeProcessor(
M model, V view, ViewBinder<M, V, P> viewBinder, boolean performInitialBind) {
mModel = model;
mView = view;
mViewBinder = viewBinder;
if (performInitialBind) {
for (P property : model.getAllSetProperties()) {
onPropertyChanged(model, property);
}
}
model.addObserver(mPropertyObserver);
}
/**
* Creates a new PropertyModelChangeProcessor observing the given {@code model}. All set model
* properties will be bound.
* @param model The model containing the data to be bound.
* @param view The view to which data will be bound.
* @param viewBinder A class that binds the model to the view.
*/
public static <M extends PropertyObservable<P>, V, P> PropertyModelChangeProcessor<M, V, P>
create(M model, V view, ViewBinder<M, V, P> viewBinder) {
return create(model, view, viewBinder, true);
}
/**
* Creates a new PropertyModelChangeProcessor observing the given {@code model}.
* @param model The model containing the data to be bound.
* @param view The view to which data will be bound.
* @param viewBinder A class that binds the model to the view.
* @param performInitialBind Whether all set model properties should be immediately bound.
*/
public static <M extends PropertyObservable<P>, V, P> PropertyModelChangeProcessor<M, V, P>
create(M model, V view, ViewBinder<M, V, P> viewBinder, boolean performInitialBind) {
return new PropertyModelChangeProcessor<>(model, view, viewBinder, performInitialBind);
}
/**
* To be called when the model should no longer be observed.
*/
public void destroy() {
mModel.removeObserver(mPropertyObserver);
}
private void onPropertyChanged(PropertyObservable<P> source, P propertyKey) {
assert source == mModel;
// TODO(bauerb): Add support for batching updates.
mViewBinder.bind(mModel, mView, propertyKey);
}
}