All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.palexdev.mfxcore.base.bindings.MappingSource Maven / Gradle / Ivy

There is a newer version: 11.26.0
Show newest version
/*
 * Copyright (C) 2022 Parisi Alessandro - [email protected]
 * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX)
 *
 * MaterialFX is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 3 of the License,
 * or (at your option) any later version.
 *
 * MaterialFX is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with MaterialFX. If not, see .
 */

package io.github.palexdev.mfxcore.base.bindings;

import io.github.palexdev.mfxcore.base.bindings.base.Updater;
import io.github.palexdev.mfxcore.enums.BindingType;
import javafx.beans.value.ObservableValue;

/**
 * Concrete implementation of {@link AbstractSource}. This type of {@code Source} is capable of
 * mapping the source's type S to the target's type and vice-versa to perform both {@link #updateTarget(Object, Object)}
 * and {@link #updateSource(Object, Object)}.
 *
 * @param  the source's observable type
 * @param  the target's observable type
 */
public class MappingSource extends AbstractSource {
	//================================================================================
	// Properties
	//================================================================================
	protected MappedUpdater targetUpdater; // From source to target
	protected MappedUpdater sourceUpdater; // From target to source

	//================================================================================
	// Constructors
	//================================================================================
	protected MappingSource() {
	}

	public MappingSource(ObservableValue observable) {
		super(observable);
	}

	public static  MappingSource of(ObservableValue observable) {
		return new MappingSource<>(observable);
	}

	//================================================================================
	// Methods
	//================================================================================

	/**
	 * {@inheritDoc}
	 * 

* Operates differently depending on which binding activated this. *

* For unidirectional bindings the target instance is null so the {@link #getTargetUpdater()} is called * then exits. *

* For bidirectional bindings the target instance is not null. Before calling the {@link #getTargetUpdater()} * we first must check that the update is not has not been invoked because of a "bounce" effect, {@link Target#isFromSource()}. */ @Override public void updateTarget(S oldValue, S newValue) { if (target.bindingType() == BindingType.UNIDIRECTIONAL) { try { target.ignoreBinding = true; targetUpdater.update(oldValue, newValue); } finally { target.ignoreBinding = false; } return; } if (target.isFromSource()) return; targetUpdater.update(oldValue, newValue); } /** * {@inheritDoc} *

* Operates differently depending on which binding activated this. *

* For unidirectional bindings the target instance is null so the {@link #getTargetUpdater()} is called * then exits. *

* For bidirectional bindings the target instance is not null. The call to {@link #getSourceUpdater()} * is surrounded by a try-finally block in which we also set {@link Target#isFromSource()} to true, if anything goes wrong * the finally block ensures to reset {@link Target#isFromSource()} back to false. */ @Override public void updateSource(T oldValue, T newValue) { if (target == null) { sourceUpdater.update(oldValue, newValue); return; } try { target.fromSource = true; sourceUpdater.update(oldValue, newValue); } finally { target.fromSource = false; } } /** * {@inheritDoc} *

* For unidirectional bindings. The listener added to this source's observable is responsible for * triggering {@link #updateTarget(Object, Object)}. */ @Override protected void listen() { if (obvListener == null) obvListener = (ov, o, n) -> updateTarget(o, n); observable.addListener(obvListener); } /** * {@inheritDoc} *

* For bidirectional bindings. The source's target is set to the given one. * Then {@link #listen()} is called. Then a listener to the given target is added and is responsible for * triggering {@link #updateSource(Object, Object)}. */ @Override protected void listen(Target target) { listen(); this.target = target; if (tgtListener == null) tgtListener = (ov, o, n) -> updateSource(o, n); target.getObservable().addListener(tgtListener); } /** * {@inheritDoc} *

* Removes the listeners added to this source's observable and the target's observable (if not null). * Then sets all its properties and listeners to null. */ @Override public void dispose() { observable.removeListener(obvListener); if (target != null && tgtListener != null) target.getObservable().removeListener(tgtListener); observable = null; target = null; targetUpdater = null; sourceUpdater = null; obvListener = null; tgtListener = null; } //================================================================================ // Getters/Setters //================================================================================ /** * @return the {@link MappedUpdater} responsible for mapping the source's values to a compatible type and then * update the target */ public MappedUpdater getTargetUpdater() { return targetUpdater; } /** * Sets the {@link MappedUpdater} for the target. */ public MappingSource setTargetUpdater(MappedUpdater targetUpdater) { this.targetUpdater = targetUpdater; return this; } /** * Sets the {@link MappedUpdater} for the target. */ public MappingSource setTargetUpdater(Mapper mapper, Updater updater) { this.targetUpdater = new MappedUpdater<>(mapper, updater); return this; } /** * @return the {@link MappedUpdater} responsible for mapping the target's values to a compatible type and then * update the source */ public MappedUpdater getSourceUpdater() { return sourceUpdater; } /** * Sets the {@link MappedUpdater} for the source. */ public MappingSource setSourceUpdater(MappedUpdater sourceUpdater) { this.sourceUpdater = sourceUpdater; return this; } /** * Sets the {@link MappedUpdater} for the source. */ public MappingSource setSourceUpdater(Mapper mapper, Updater updater) { this.sourceUpdater = new MappedUpdater<>(mapper, updater); return this; } //================================================================================ // Builder //================================================================================ public static class Builder { private final MappingSource source = new MappingSource<>(); public Builder observable(ObservableValue observable) { source.observable = observable; return this; } public Builder targetUpdater(MappedUpdater targetUpdater) { source.targetUpdater = targetUpdater; return this; } public Builder sourceUpdater(MappedUpdater sourceUpdater) { source.sourceUpdater = sourceUpdater; return this; } public MappingSource get() { if (source.observable == null) throw new NullPointerException("Source is invalid as observable is null"); return source; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy