Tutorial : SwingX Filter Table dengan lebih dari 1 Kondisi (Part 1)

 Setelah sekian lama disibukan dengan pekerjaan, akhirnya saya dapat menulis di blog ini. Kali ini saya akan berbagi source code yang saya peroleh dari pengalaman saya membuat software SIMARSIP. Tutorial akan saya berikan kali ini adalah bagaimana membuat filter table dengan kondisi lebih dari satu. Sebelumnya saya pernah memberikan Tutorial : Membuat Filter Table dengan SwingX , tutotial kali ini merupakan pengembangan dari source code tutorial tersebut. Sekeder mengingatkan pada tutorial sebelumnya saya hanya menyediakan filter dengan satu textfield. Namun kali ini saya akan membuat filter ini menggunakan 2 ComboBox dan 2 TextField. Untuk lebih jelasnya kalian dapat melihat pada tampilan berikut ini.



Cara kerja contoh diatas dapat saya jelaskan sebagai berikut, misalkan pada ComboBox pertama kita akan filter data table tersebut dengan "First Name" sedangkan pada ComboBox dibawahnya kita akan menyaringnya denga "Last Name", kemudian tuliskan kata yang akan kita cari pada masing-masing textfield maka hasil dari penyaringan data dapat kalian lihat di gambar kanan.
Pada contoh diatas hanya terdapat dua kolom pada table dan 2 kondisi penyaringan data. Namun kalian dapat melakukan nya dengan banyak kolom dan banyak pilihan filtering pada ComboBox, maksud saya lebih dari 2 tergantung dari kebutuhan. Kemudian, untuk contoh kali saya gunakan data filtering pada ComboBox yang saya definisikan secara manual, pada kesempatan lainnya akan saya berikan contoh data filtering yang otomatis diambil dari nama kolom pada table. Untuk dapat lebih jelasnya silahkan kalian pelajari source code dibawah ini.

package org.motekar.latihan.swingX;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXComboBox;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTextField;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.jdesktop.swingx.combobox.ListComboBoxModel;

/**
 *
 * @author Muhamad Wibawa
 */

public class FilterTableExtendedExample extends JFrame {

    private JXTable table = new JXTable();
    private static String[] peopleName = new String[]{"Adam Barclay",
        "Aleksandras Novikovas", "Bill Snyder", "Bryan Young",
        "Dan Leuck", "Daniel Lewis", "Daniel Olivera",
        "David Bolsover", "David Hall", "Diego Gil",
        "Dirk Hillbrecht", "Doug Berkland",
        "Erik Vickroy", "Fred Lavigne",
        "Gilles Philippart", "Haris Peco",
        "Jan Bosenberg", "James Morgan",
        "Jeanette Winzenburg", "Mario Cesar",
        "Mark Davidson", "Mark Fortner", "Mark Thornton",
        "Matt Nathan", "Michael Bush", "Michael Swindle",
        "Neil Weber", "Nicola Ken Barozzi", "Noel Grandin",
        "Oleg Minukhin", "Patrick Gotthardt", "Patrick Wright",
        "Pierre Le Lannic", "Ray Turnbull", "Ricardo Lopes",
        "Richard Bair", "Richard Osbaldeston", "Robert Eden", "Robert Stone",
        "Ronald Tetsuo Miura", "Salvan Haas", "Scott Delap",
        "Sean McNamara", "Simon Morris", "Shai Almog",
        "Thomas Bierhance", "Wade Chandler", "Waldemar Klaczynski",
        "Walter Wang", "Xavier Hanin", "Yannick Menager"};

    private JXTextField fieldSearch = new JXTextField();
    private JXTextField fieldSearch2 = new JXTextField();
    private JXComboBox comboCondition = new JXComboBox();
    private JXComboBox comboCondition2 = new JXComboBox();
    //
    private static final String[] CONDITIONS = {" ", "First Name", "Last Name"};
    
    private static final String NULL = " ";
    private static final String FIRST_NAME = "First Name";
    private static final String LAST_NAME = "Last Name";
    
    private RowFilter<Object, Object> searchFilter;
    private RowFilter<Object, Object> searchFilter2;

    public FilterTableExtendedExample() {
        construct();
    }

    private void construct() {
        
        loadComboCondition();
        
        fieldSearch.getDocument().addDocumentListener(new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                updateSearchFilter();
            }

            public void removeUpdate(DocumentEvent e) {
                updateSearchFilter();
            }

            public void changedUpdate(DocumentEvent e) {
                updateSearchFilter();
            }
        });
        
        fieldSearch2.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void insertUpdate(DocumentEvent e) {
                updateSearchFilter();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateSearchFilter();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                updateSearchFilter();
            }
        });

        fillTableData();

        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        this.setTitle("Filter Table Extended Examples");
        this.setPreferredSize(new Dimension(500, 500));
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(createMainPanel(), BorderLayout.CENTER);

    }
    
    protected JPanel createMainPanel() {
        FormLayout lm = new FormLayout(
                "pref,10px,pref,5px,fill:default:grow,10px",
                "pref,5px,pref,5px,fill:default:grow,5px,pref,5px");
        DefaultFormBuilder builder = new DefaultFormBuilder(lm);
        builder.setDefaultDialogBorder();

        JScrollPane scPane = new JScrollPane();
        scPane.setViewportView(table);

        CellConstraints cc = new CellConstraints();

        builder.addLabel("Cari", cc.xy(1, 1));
        builder.add(comboCondition, cc.xy(3, 1));
        builder.add(fieldSearch, cc.xy(5, 1));
        
        builder.add(comboCondition2, cc.xy(3, 3));
        builder.add(fieldSearch2, cc.xy(5, 3));

        builder.add(scPane, cc.xywh(1, 5, 5, 2));

        return builder.getPanel();
    }
    
    private void loadComboCondition() {
        comboCondition.setModel(new ListComboBoxModel<String>(Arrays.asList(CONDITIONS)));
        AutoCompleteDecorator.decorate(comboCondition);
        
        comboCondition2.setModel(new ListComboBoxModel<String>(Arrays.asList(CONDITIONS)));
        AutoCompleteDecorator.decorate(comboCondition2);
        
    }

    private void updateSearchFilter() {
        
        String conditionText = (String) comboCondition.getSelectedItem();
        String conditionText2 = (String) comboCondition2.getSelectedItem();
        
        if (conditionText != null && !conditionText.equals(NULL)) {
            searchFilter = createSearchFilter(fieldSearch.getText(), conditionText);
        }
        
        if (conditionText2 != null && !conditionText2.equals(NULL)) {
            searchFilter2 = createSearchFilter(fieldSearch2.getText(), conditionText2);
        }
        
        updateFilters();
    }
    
    
    private void updateFilters() {
        if ((searchFilter != null) && (searchFilter2 != null)) {
            List<RowFilter<Object, Object>> filters =
                new ArrayList<RowFilter<Object, Object>>(2);
            filters.add(searchFilter);
            filters.add(searchFilter2);
            RowFilter<Object, Object> comboFilter = RowFilter.andFilter(filters);
            table.setRowFilter(comboFilter);
        } else if (searchFilter != null) {
            table.setRowFilter(searchFilter);
        } else {
            table.setRowFilter(searchFilter2);
        }
    }

    private void fillTableData() {
        DefaultTableModel model = new DefaultTableModel();

        model.addColumn("First Name");
        model.addColumn("Last Name");
        
        
        for (String p : peopleName) {

            StringTokenizer token = new StringTokenizer(p, " ");

            String first = token.nextToken();
            String last = token.nextToken();

            model.addRow(new Object[]{first, last});
        }
        
        
        table.setModel(model);
    }
    
    private RowFilter<Object, Object> createSearchFilter(final String filterString,final String conditionText) {
        return new RowFilter<Object, Object>() {
            @Override
            public boolean include(Entry<? extends Object, ? extends Object> entry) {
                DefaultTableModel model = (DefaultTableModel) entry.getModel();
                String firstName = (String)model.getValueAt(((Integer) entry.getIdentifier()).intValue(),0);
                String lastName = (String)model.getValueAt(((Integer) entry.getIdentifier()).intValue(),1);
                boolean matches = false;
                Pattern p = Pattern.compile("(?i).*" + filterString + ".*",
                    Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
                
                String condition = null;
                
                if (conditionText.equals(FIRST_NAME)) {
                    condition = firstName;
                } else if (conditionText.equals(LAST_NAME)) {
                    condition = lastName;
                } 
                
                if (condition != null) {
                    matches = p.matcher(condition).matches();
                }
                
                return matches;
            }
        };
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                JFrame test = new FilterTableExtendedExample();
                test.pack();
                test.setLocationRelativeTo(null);
                test.setVisible(true);
            }
        });
    }
}


Sekian penjelasan mengenai cara membuat filter table dengan lebih dari 2 kondisi, semoga apa yang saya tulis diatas bermanfaat untuk kalian semua. Jika ada pertanyaan atau ada yang ingin dibantu mengenai pemogramman silahkan tulis komentar maupun kirim email.

Wassalam,
Muhamad Wibawa