<commit_before>/*
 * $Id$
 *
 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx.plaf.basic.core;

import javax.swing.DefaultListSelectionModel;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;

import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.util.Contract;

import sun.swing.SwingUtilities2;

/**
 * ListSortUI provides support for managing the synchronization between
 * RowSorter, SelectionModel and ListModel if a JXList is sortable.<p>
 * 
 * This implementation is an adaption of JTable.SortManager fit to the
 * needs of a ListUI. In contrast to JTable tradition, the ui delegate has 
 * full control about listening to model/selection changes and updating
 * the list accordingly. So it's role is that of a helper to the ui-delgate
 * (vs. as a helper of the JTable). It's still up to the ListUI itself to
 * listen to model/selection and propagate the notification to this class, if
 * a sorter is installed, but still do the usual updates (layout, repaint) itself.
 * On the other hand, listening to the sorter and updating list state accordingly 
 * is completely done by this.
 * 
 */
public final class ListSortUI { 
    private RowSorter<? extends ListModel> sorter;
    private JXList list;

    // Selection, in terms of the model. This is lazily created
    // as needed.
    private ListSelectionModel modelSelection;
    private int modelLeadIndex;
    // Set to true while in the process of changing the selection.
    // If this is true the selection change is ignored.
    private boolean syncingSelection;
    // Temporary cache of selection, in terms of model. This is only used
    // if we don't need the full weight of modelSelection.
    private int[] lastModelSelection;
    private boolean sorterChanged;
    private boolean ignoreSortChange;
    private RowSorterListener sorterListener;

    /**
     * Intanstiates a SortUI on the list which has the given RowSorter.
     * 
     * @param list the list to control, must not be null
     * @param sorter the rowSorter of the list, must not be null
     * @throws NullPointerException if either the list or the sorter is null
     * @throws IllegalStateException if the sorter is not the sorter installed
     *   on the list
     */
    public ListSortUI(JXList list, RowSorter<? extends ListModel> sorter) {
        this.sorter = Contract.asNotNull(sorter, "RowSorter must not be null");
        this.list = Contract.asNotNull(list, "list must not be null");
        if (sorter != list.getRowSorter()) throw
            new IllegalStateException("sorter must be same as the one on list");
        sorterListener = createRowSorterListener();
        sorter.addRowSorterListener(sorterListener);
    }

    /**
     * Disposes any resources used by this SortManager. 
     * Note: this instance must not be used after dispose!
     */
    public void dispose() {
        if (sorter != null) {
            sorter.removeRowSorterListener(sorterListener);
        }
        sorter = null;
        list = null;
    }

//----------------------methods called by listeners
    
    /**
     * Called after notification from ListModel.
     * @param e the change event from the listModel.
     */
    public void modelChanged(ListDataEvent e) {
        ModelChange change = new ModelChange(e);
        prepareForChange(change);
        notifySorter(change);
        if (change.type != ListDataEvent.CONTENTS_CHANGED) {
            // If the Sorter is unsorted we will not have received
            // notification, force treating insert/delete as a change.
            sorterChanged = true;
        }
        processChange(change);
    }

    /**
     * Called after notification from selectionModel.
     * 
     * Invoked when the selection, on the view, has changed.
     */
    public void viewSelectionChanged(ListSelectionEvent e) {
        if (!syncingSelection && modelSelection != null) {
            modelSelection = null;
        }
    }

    /**
     * Called after notification from RowSorter.
     * 
     * @param e RowSorter event of type SORTED.
     */
    protected void sortedChanged(RowSorterEvent e) {
        sorterChanged = true;
        if (!ignoreSortChange) {
            prepareForChange(e);
            processChange(null);
            // PENDING Jw: this is fix of 1161-swingx - not updated after setting 
            // rowFilter
            // potentially costly? but how to distinguish a mere sort from a 
            // filterchanged? (only the latter requires a revalidate)
            list.revalidate();
//            list.repaint();
        }
    }


//--------------------- prepare change, that is cache selection if needed
    /**
     * Invoked when the RowSorter has changed. 
     * Updates the internal cache of the selection based on the change.
     * 
     * @param sortEvent the notification
     * @throws NullPointerException if the given event is null.
     */
    private void prepareForChange(RowSorterEvent sortEvent) {
        Contract.asNotNull(sortEvent, "sorter event not null");
        // sort order changed. If modelSelection is null and filtering
        // is enabled we need to cache the selection in terms of the
        // underlying model, this will allow us to correctly restore
        // the selection even if rows are filtered out.
        if (modelSelection == null &&
                sorter.getViewRowCount() != sorter.getModelRowCount()) {
            modelSelection = new DefaultListSelectionModel();
            ListSelectionModel viewSelection = getViewSelectionModel();
            int min = viewSelection.getMinSelectionIndex();
            int max = viewSelection.getMaxSelectionIndex();
            int modelIndex;
            for (int viewIndex = min; viewIndex <= max; viewIndex++) {<commit_msg>Issue 1161-swingx: JXList not completely updated on setRowFilter - changed ListSortUI again: need to revalidate _and_ repaint<commit_after>/*
 * $Id$
 *
 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx.plaf.basic.core;

import javax.swing.DefaultListSelectionModel;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;

import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.util.Contract;

import sun.swing.SwingUtilities2;

/**
 * ListSortUI provides support for managing the synchronization between
 * RowSorter, SelectionModel and ListModel if a JXList is sortable.<p>
 * 
 * This implementation is an adaption of JTable.SortManager fit to the
 * needs of a ListUI. In contrast to JTable tradition, the ui delegate has 
 * full control about listening to model/selection changes and updating
 * the list accordingly. So it's role is that of a helper to the ui-delgate
 * (vs. as a helper of the JTable). It's still up to the ListUI itself to
 * listen to model/selection and propagate the notification to this class, if
 * a sorter is installed, but still do the usual updates (layout, repaint) itself.
 * On the other hand, listening to the sorter and updating list state accordingly 
 * is completely done by this.
 * 
 */
public final class ListSortUI { 
    private RowSorter<? extends ListModel> sorter;
    private JXList list;

    // Selection, in terms of the model. This is lazily created
    // as needed.
    private ListSelectionModel modelSelection;
    private int modelLeadIndex;
    // Set to true while in the process of changing the selection.
    // If this is true the selection change is ignored.
    private boolean syncingSelection;
    // Temporary cache of selection, in terms of model. This is only used
    // if we don't need the full weight of modelSelection.
    private int[] lastModelSelection;
    private boolean sorterChanged;
    private boolean ignoreSortChange;
    private RowSorterListener sorterListener;

    /**
     * Intanstiates a SortUI on the list which has the given RowSorter.
     * 
     * @param list the list to control, must not be null
     * @param sorter the rowSorter of the list, must not be null
     * @throws NullPointerException if either the list or the sorter is null
     * @throws IllegalStateException if the sorter is not the sorter installed
     *   on the list
     */
    public ListSortUI(JXList list, RowSorter<? extends ListModel> sorter) {
        this.sorter = Contract.asNotNull(sorter, "RowSorter must not be null");
        this.list = Contract.asNotNull(list, "list must not be null");
        if (sorter != list.getRowSorter()) throw
            new IllegalStateException("sorter must be same as the one on list");
        sorterListener = createRowSorterListener();
        sorter.addRowSorterListener(sorterListener);
    }

    /**
     * Disposes any resources used by this SortManager. 
     * Note: this instance must not be used after dispose!
     */
    public void dispose() {
        if (sorter != null) {
            sorter.removeRowSorterListener(sorterListener);
        }
        sorter = null;
        list = null;
    }

//----------------------methods called by listeners
    
    /**
     * Called after notification from ListModel.
     * @param e the change event from the listModel.
     */
    public void modelChanged(ListDataEvent e) {
        ModelChange change = new ModelChange(e);
        prepareForChange(change);
        notifySorter(change);
        if (change.type != ListDataEvent.CONTENTS_CHANGED) {
            // If the Sorter is unsorted we will not have received
            // notification, force treating insert/delete as a change.
            sorterChanged = true;
        }
        processChange(change);
    }

    /**
     * Called after notification from selectionModel.
     * 
     * Invoked when the selection, on the view, has changed.
     */
    public void viewSelectionChanged(ListSelectionEvent e) {
        if (!syncingSelection && modelSelection != null) {
            modelSelection = null;
        }
    }

    /**
     * Called after notification from RowSorter.
     * 
     * @param e RowSorter event of type SORTED.
     */
    protected void sortedChanged(RowSorterEvent e) {
        sorterChanged = true;
        if (!ignoreSortChange) {
            prepareForChange(e);
            processChange(null);
            // PENDING Jw: this is fix of 1161-swingx - not updated after setting 
            // rowFilter
            // potentially costly? but how to distinguish a mere sort from a 
            // filterchanged? (only the latter requires a revalidate)
            list.revalidate();
            list.repaint();
        }
    }


//--------------------- prepare change, that is cache selection if needed
    /**
     * Invoked when the RowSorter has changed. 
     * Updates the internal cache of the selection based on the change.
     * 
     * @param sortEvent the notification
     * @throws NullPointerException if the given event is null.
     */
    private void prepareForChange(RowSorterEvent sortEvent) {
        Contract.asNotNull(sortEvent, "sorter event not null");
        // sort order changed. If modelSelection is null and filtering
        // is enabled we need to cache the selection in terms of the
        // underlying model, this will allow us to correctly restore
        // the selection even if rows are filtered out.
        if (modelSelection == null &&
                sorter.getViewRowCount() != sorter.getModelRowCount()) {
            modelSelection = new DefaultListSelectionModel();
            ListSelectionModel viewSelection = getViewSelectionModel();
            int min = viewSelection.getMinSelectionIndex();
            int max = viewSelection.getMaxSelectionIndex();
            int modelIndex;
            for (int viewIndex = min; viewIndex <= max; viewIndex++) {
{'fraction_non_alphanumeric': 0.0769342429960807, 'fraction_numerical': 0.004790245318623893, 'mean_word_length': 2.7070217917675543, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6887453', 'n_tokens_mistral': 3610, 'n_tokens_neox': 3481, 'n_words': 1461}