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

org.bridje.jfx.binding.BiListContentBinding Maven / Gradle / Ivy

/*
 * Copyright 2017 Bridje Framework.
 *
 * 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.bridje.jfx.binding;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.stream.Collectors;
import javafx.beans.WeakListener;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

/**
 * A bidirectional binding for two lists of diferent types.
 * 
 * @param  The type of the first list.
 * @param  The type of the second list.
 */
public class BiListContentBinding implements ListChangeListener, WeakListener
{
    private final WeakReference> propertyRef1;

    private final WeakReference> propertyRef2;

    private boolean updating = false;

    private final BiContentConverter converter;
    
    /**
     * The only constructor for this binding.
     * 
     * @param list1 The first list.
     * @param list2 The second list.
     * @param converter The converter from/to the two types of the lists.
     */
    public BiListContentBinding(ObservableList list1, ObservableList list2, BiContentConverter converter)
    {
        propertyRef1 = new WeakReference<>(list1);
        propertyRef2 = new WeakReference<>(list2);
        this.converter = converter;
    }

    @Override
    public void onChanged(ListChangeListener.Change change)
    {
        if (!updating)
        {
            final ObservableList list1 = propertyRef1.get();
            final ObservableList list2 = propertyRef2.get();
            if ((list1 == null) || (list2 == null))
            {
                if (list1 != null)
                {
                    list1.removeListener(this);
                }
                if (list2 != null)
                {
                    list2.removeListener(this);
                }
            }
            else
            {
                try
                {
                    updating = true;
                    final ObservableList dest = (list1 == change.getList()) ? list2 : list1;
                    while (change.next())
                    {
                        if (change.wasPermutated())
                        {
                            dest.remove(change.getFrom(), change.getTo());
                            if(list1 == change.getList())
                            {
                                list2.addAll(change.getFrom(), convertFrom(list1.subList(change.getFrom(), change.getTo())));
                            }
                            else
                            {
                                list1.addAll(change.getFrom(), convertTo(list2.subList(change.getFrom(), change.getTo())));
                            }
                        }
                        else
                        {
                            if (change.wasRemoved())
                            {
                                dest.remove(change.getFrom(), change.getFrom() + change.getRemovedSize());
                            }
                            if (change.wasAdded())
                            {
                                if(list1 == change.getList())
                                {
                                    list2.addAll(change.getFrom(), convertFrom(change.getAddedSubList()));
                                }
                                else
                                {
                                    list1.addAll(change.getFrom(), convertTo(change.getAddedSubList()));
                                }
                            }
                        }
                    }
                }
                finally
                {
                    updating = false;
                }
            }
        }
    }

    @Override
    public boolean wasGarbageCollected()
    {
        return (propertyRef1.get() == null) || (propertyRef2.get() == null);
    }

    @Override
    public int hashCode()
    {
        final ObservableList list1 = propertyRef1.get();
        final ObservableList list2 = propertyRef2.get();
        final int hc1 = (list1 == null) ? 0 : list1.hashCode();
        final int hc2 = (list2 == null) ? 0 : list2.hashCode();
        return hc1 * hc2;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj) return true;

        final Object propertyA1 = propertyRef1.get();
        final Object propertyA2 = propertyRef2.get();
        if ((propertyA1 == null) || (propertyA2 == null)) return false;

        if (obj instanceof BiListContentBinding)
        {
            final BiListContentBinding otherBinding = (BiListContentBinding) obj;
            final Object propertyB1 = otherBinding.propertyRef1.get();
            final Object propertyB2 = otherBinding.propertyRef2.get();
            if ((propertyB1 == null) || (propertyB2 == null)) return false;

            if ((propertyA1 == propertyB1) && (propertyA2 == propertyB2)) return true;
            if ((propertyA1 == propertyB2) && (propertyA2 == propertyB1)) return true;
        }
        return false;
    }

    private List convertFrom(List subList)
    {
        return subList.stream()
                        .map(e -> converter.convertFrom(e))
                        .collect(Collectors.toList());
    }

    private List convertTo(List subList)
    {
        return subList.stream()
                        .map(e -> converter.convertTo(e))
                        .collect(Collectors.toList());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy