org.monkeys.gui.matcher.MatcherPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.monkeys.gui.matcher.MatcherPanel.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.monkeys.gui.matcher;

import org.monkeys.gui.MessageUtils;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import org.apache.commons.io.IOUtils;
import org.monkeys.category.Category;
import org.monkeys.gui.PopupWindow;
import org.monkeys.regex.RegexEntry;
import org.monkeys.regex.RegexMatch;
import org.monkeys.regex.RegexService;
import org.openide.util.Lookup;
import org.openide.windows.WindowManager;

/**
 * complex text / regex matching panel
 * 
 * @author bowen
 */
public class MatcherPanel extends javax.swing.JPanel {
    public static enum ClipboardAction {
        LINE("line", "\r\n"), TAB("tab", "\t");

        @Override
        public String toString() {
            return this.label;
        }

        public String delim() {
            return this.delim;
        }

        private ClipboardAction(final String lbl, final String d) {
            this.label = lbl;
            this.delim = d;
        }

        private final String label;

        private final String delim;
    };

    private final PopupWindow modifyPopup;

    private final ModifyMatchesPanel modifyPanel = new ModifyMatchesPanel();

    private final Color editableText;

    private final Color disabledText;

    public MatcherPanel() {
        initComponents();
        wireEvents();
        this.clipboardDropdown.setModel(new DefaultComboBoxModel(ClipboardAction.values()));
        this.clipboardDropdown.setSelectedItem(ClipboardAction.LINE);
        this.editableText = this.textArea.getForeground();
        this.disabledText = Color.GRAY;
        this.modifyPopup = new PopupWindow(WindowManager.getDefault().getMainWindow(), this);
        this.modifyPopup.setPanel(this.modifyPanel);
        this.setBorder(BorderFactory.createLineBorder(Color.gray, 1));
    }

    public void setHeader(final String label) {
        this.textHeader.setText(label);
    }

    public void setReadOnly(final boolean readonly) {
        this.clearButton.setVisible(!readonly);
        this.editButton.setVisible(!readonly);
        this.editPanel.setVisible(!readonly);
        this.toggleEdit(!readonly);
    }

    public Set<Category> getCategories() {
        if (this.categoryDropdown.isAll()) {
            final RegexService service = Lookup.getDefault().lookup(RegexService.class);
            if (null == service) {
                return Collections.emptySet();
            }
            return service.getCategories();
        }

        final Category selected = this.categoryDropdown.getCategory();
        if (null == selected) {
            return Collections.emptySet();
        }
        return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(selected)));
    }

    public Set<RegexEntry> getEntries() {
        final RegexService service = Lookup.getDefault().lookup(RegexService.class);
        if (null == service) {
            return Collections.emptySet();
        }
        final Set<RegexEntry> set = new TreeSet<>();
        for (final Category category : this.getCategories()) {
            set.addAll(service.getEntries(category));
        }
        return Collections.unmodifiableSet(set);
    }

    public void setMatchable(final CharSequence text) {
        final String string = text != null ? text.toString() : "";
        this.textArea.setText(string);
    }

    public CharSequence getMatchable() {
        return this.textArea.getText();
    }

    public void setMatches(final List<RegexMatch> matches) {
        final String text = this.textArea.getText();
        final boolean valid = text != null && !text.trim().isEmpty() && matches != null && !matches.isEmpty();
        this.highlightMatches(matches);
        if (valid) {
            this.toggleEdit(false);
            this.matchingList.setMatches(matches);
        } else {
            this.toggleEdit(true);
            this.matchingList.setMatches(Collections.EMPTY_LIST);
        }
        this.updateState();
    }

    private void updateState() {
        final List<RegexMatch> matches = this.matchingList.getMatches();
        final List<RegexMatch> selected = this.matchingList.getSelectedMatches();
        final boolean hasMatches = matches != null && !matches.isEmpty();
        final boolean hasSelected = selected != null && !selected.isEmpty();
        this.selectButton.setEnabled(hasMatches);
        this.removeRowButton.setEnabled(hasSelected);
    }

    private void toggleEdit(final boolean editable) {
        if (editable && this.editButton.isVisible()) {
            this.editButton.setSelected(true);
            this.textArea.setEditable(true);
            this.textArea.setForeground(this.editableText);
        } else {
            this.editButton.setEnabled(true);
            this.editButton.setSelected(false);
            this.textArea.setEditable(false);
            this.textArea.setForeground(this.disabledText);
        }
    }

    private void clearHighlights() {
        final Highlighter h = this.textArea.getHighlighter();
        h.removeAllHighlights();
    }

    private void highlightMatches(final Collection<RegexMatch> matches) {
        this.clearHighlights();
        if (null == matches || matches.isEmpty()) {
            return;
        }

        final Highlighter h = this.textArea.getHighlighter();
        final Highlighter.HighlightPainter style = DefaultHighlighter.DefaultPainter;
        for (final RegexMatch match : matches) {
            final int p0 = match.getStart();
            final int p1 = match.getEnd();
            try {
                h.addHighlight(p0, p1, style);
            } catch (final BadLocationException e) {
                MessageUtils.exceptionDialog("Unanble to highlight match [" + match + "].", e);
            }
        }
    }

    private void searchAndReplaceSelected(final Pattern search, final String replace) {
        int count = 0;
        for (final MatcherContext ctx : this.matchingList.getSelectedValues()) {
            final String original = ctx.getText();
            final String blob = ctx.getText() + IOUtils.LINE_SEPARATOR;
            String updated = original;
            int offset = 0;
            final Matcher matcher = search.matcher(blob);
            while (matcher.find()) {
                final int start = matcher.start();
                final int end = matcher.end();
                if (start <= 0) {
                    updated = replace + updated.substring(end - offset);
                } else {
                    final String prefix = updated.substring(0, start - offset);
                    final String suffix = end < updated.length() ? updated.substring(end - offset) : "";
                    updated = prefix + replace + suffix;
                }
                offset += matcher.group().length() - replace.length();
            }
            if (!updated.equals(original)) {
                ctx.setText(updated);
                count++;
            }
        }

        this.modifyPopup.hidePopup();
        this.matchingList.repaint();
        this.checkForDuplicates();
        final String plural = count == 1 ? "item" : "items";
        MessageUtils.infoNotification(count + " " + plural + " updated.", 5000);
    }

    private void appendSuffixSelected(final String text) {
        if (null == text || text.isEmpty()) {
            return;
        }

        for (final MatcherContext ctx : this.matchingList.getSelectedValues()) {
            final String updated = ctx.getText() + text;
            ctx.setText(updated.trim());
        }
        this.modifyPopup.hidePopup();
        this.matchingList.repaint();
        this.checkForDuplicates();

        final int count = this.matchingList.getSelectedRowCount();
        final String plural = count == 1 ? "item" : "items";
        MessageUtils.infoNotification(count + " " + plural + " updated.", 5000);
    }

    private void preappendPrefixSelected(final String text) {
        if (null == text || text.isEmpty()) {
            return;
        }

        for (final MatcherContext ctx : this.matchingList.getSelectedValues()) {
            final String updated = text + ctx.getText();
            ctx.setText(updated.trim());
        }
        this.modifyPopup.hidePopup();
        this.matchingList.repaint();
        this.checkForDuplicates();

        final int count = this.matchingList.getSelectedRowCount();
        final String plural = count == 1 ? "item" : "items";
        MessageUtils.infoNotification(count + " " + plural + " updated.", 5000);
    }

    private void wireEvents() {
        this.modifyPanel.addModifyMatchesListener(new ModifyMatchesListener() {
            @Override
            public void searchAndReplace(final Pattern search, final String replace) {
                searchAndReplaceSelected(search, replace);
            }

            @Override
            public void appendSuffix(final String text) {
                appendSuffixSelected(text);
            }

            @Override
            public void preappendPrefix(final String text) {
                preappendPrefixSelected(text);
            }
        });
        this.matchingList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(final ListSelectionEvent event) {
                if (!event.getValueIsAdjusting()) {
                    matchingListSelected(event);
                }
            }
        });
        this.matchingList.getModel().addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                matchingListTableChanged(e);
            }
        });
    }

    private void checkForDuplicates() {
        this.removeDuplicateButton.setEnabled(this.matchingList.hasDuplicates());
    }

    private void matchingListTableChanged(final TableModelEvent event) {
        this.checkForDuplicates();
    }

    private void matchingListSelected(final ListSelectionEvent event) {
        final List<RegexMatch> list = this.matchingList.getSelectedMatches();
        final boolean selected = !list.isEmpty();
        if (list.size() == 1) {
            final RegexMatch match = list.get(0);
            this.highlightText(match);
        }
        this.modifyButton.setEnabled(selected);
        this.removeRowButton.setEnabled(selected);
        this.clipboardButton.setEnabled(selected);
        this.clipboardDropdown.setEnabled(selected);
        this.undoButton.setEnabled(selected);
    }

    private void highlightText(final RegexMatch match) {
        if (null == match) {
            return;
        }
        try {
            final int p0 = match.getStart();
            final int p1 = match.getEnd();
            final Rectangle viewRect = this.textArea.modelToView(p0);
            this.textArea.scrollRectToVisible(viewRect);
            this.textArea.setCaretPosition(p0);
            this.textArea.moveCaretPosition(p1);
        } catch (final BadLocationException e) {
            MessageUtils.exceptionDialog("Unable to scroll to text for [" + match + "].", e);
        }
    }

    private void copyToClipboard() {
        String delim = ClipboardAction.LINE.delim();
        final Object selected = this.clipboardDropdown.getSelectedItem();
        if (selected instanceof ClipboardAction) {
            final ClipboardAction action = (ClipboardAction) selected;
            delim = action.delim();
        } else if (selected != null) {
            delim = " " + selected.toString().trim() + " ";
        }

        final StringBuilder buffer = new StringBuilder();
        boolean first = true;
        for (final String match : this.matchingList.getSelectedText()) {
            if (!first) {
                buffer.append(delim);
            }
            buffer.append(match);
            first = false;
        }

        final String blob = buffer.toString().trim();
        final StringSelection selection = new StringSelection(blob);
        final Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
        clpbrd.setContents(selection, selection);
    }

    private void undoSelected() {
        for (final MatcherContext ctx : this.matchingList.getSelectedValues()) {
            ctx.reset();
        }
        this.modifyPopup.hidePopup();
        this.matchingList.repaint();
        this.checkForDuplicates();

        final int count = this.matchingList.getSelectedRowCount();
        final String plural = count == 1 ? "item" : "items";
        MessageUtils.infoNotification(count + " " + plural + " reset.", 5000);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")

    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        javax.swing.JSplitPane splitPane = new javax.swing.JSplitPane();
        textPanel = new javax.swing.JPanel();
        textHeader = new org.monkeys.gui.HeaderLabel();
        javax.swing.JScrollPane textScroll = new javax.swing.JScrollPane();
        textArea = new javax.swing.JTextArea();
        editPanel = new javax.swing.JPanel();
        clearButton = new javax.swing.JButton();
        javax.swing.JSeparator jSeparator2 = new javax.swing.JSeparator();
        editButton = new javax.swing.JToggleButton();
        matchingPanel = new javax.swing.JPanel();
        org.monkeys.gui.HeaderLabel matchingHeader = new org.monkeys.gui.HeaderLabel();
        matchingScroll = new javax.swing.JScrollPane();
        matchingList = new org.monkeys.gui.matcher.MatcherTable();
        org.monkeys.gui.HeaderLabel categoryLabel = new org.monkeys.gui.HeaderLabel();
        categoryDropdown = new org.monkeys.gui.CategoryDropdown();
        clipboardButton = new javax.swing.JToggleButton();
        selectButton = new javax.swing.JToggleButton();
        removeDuplicateButton = new javax.swing.JButton();
        removeRowButton = new javax.swing.JButton();
        javax.swing.JSeparator jSeparator3 = new javax.swing.JSeparator();
        javax.swing.JSeparator jSeparator4 = new javax.swing.JSeparator();
        javax.swing.JSeparator jSeparator5 = new javax.swing.JSeparator();
        modifyButton = new javax.swing.JButton();
        javax.swing.JSeparator jSeparator6 = new javax.swing.JSeparator();
        undoButton = new javax.swing.JButton();
        javax.swing.JSeparator jSeparator7 = new javax.swing.JSeparator();
        clipboardDropdown = new javax.swing.JComboBox();

        splitPane.setBorder(null);
        splitPane.setDividerSize(8);
        splitPane.setResizeWeight(0.6);

        textHeader.setText("Text");

        textScroll.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.gray));
        textScroll.setMinimumSize(new java.awt.Dimension(200, 50));
        textScroll.setPreferredSize(new java.awt.Dimension(300, 150));

        textArea.setTabSize(4);
        textArea.setAutoscrolls(false);
        textScroll.setViewportView(textArea);

        clearButton
                .setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/clear-20.png"))); // NOI18N
        clearButton.setText("Clear");
        clearButton.setToolTipText("Clear All Fields");
        clearButton.setBorderPainted(false);
        clearButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearButtonActionPerformed(evt);
            }
        });

        jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);

        editButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/lock-18.png"))); // NOI18N
        editButton.setSelected(true);
        editButton.setText("Edit");
        editButton.setToolTipText("Edit Text");
        editButton.setBorderPainted(false);
        editButton.setDisabledIcon(
                new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/lock-18.png"))); // NOI18N
        editButton.setIconTextGap(3);
        editButton.setSelectedIcon(
                new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/unlock-18.png"))); // NOI18N
        editButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout editPanelLayout = new javax.swing.GroupLayout(editPanel);
        editPanel.setLayout(editPanelLayout);
        editPanelLayout.setHorizontalGroup(editPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(editPanelLayout.createSequentialGroup().addComponent(editButton).addGap(0, 0, 0)
                        .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(0, 0, 0).addComponent(clearButton).addGap(0, 89, Short.MAX_VALUE)));

        editPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
                new java.awt.Component[] { clearButton, editButton });

        editPanelLayout.setVerticalGroup(editPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(editPanelLayout.createSequentialGroup().addGap(0, 0, 0)
                        .addGroup(editPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(jSeparator2)
                                .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(clearButton, javax.swing.GroupLayout.PREFERRED_SIZE, 24,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(0, 0, 0)));

        editPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL,
                new java.awt.Component[] { clearButton, editButton });

        javax.swing.GroupLayout textPanelLayout = new javax.swing.GroupLayout(textPanel);
        textPanel.setLayout(textPanelLayout);
        textPanelLayout.setHorizontalGroup(textPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(textPanelLayout.createSequentialGroup()
                        .addComponent(editPanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(0, 0, Short.MAX_VALUE))
                .addGroup(textPanelLayout.createSequentialGroup().addContainerGap()
                        .addGroup(textPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(textScroll, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                                .addComponent(textHeader, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap()));
        textPanelLayout.setVerticalGroup(textPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(textPanelLayout.createSequentialGroup().addContainerGap()
                        .addComponent(textHeader, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(0, 0, 0)
                        .addComponent(editPanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(textScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 341, Short.MAX_VALUE)
                        .addContainerGap()));

        splitPane.setLeftComponent(textPanel);

        matchingHeader.setText("Matches");

        matchingScroll.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.gray));
        matchingScroll.setMinimumSize(new java.awt.Dimension(200, 120));
        matchingScroll.setPreferredSize(new java.awt.Dimension(480, 300));
        matchingScroll.setViewportView(matchingList);

        categoryLabel.setText("Category");

        clipboardButton.setIcon(
                new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/clipboard-16.png"))); // NOI18N
        clipboardButton.setToolTipText("Copy Selected To Clipboard");
        clipboardButton.setBorderPainted(false);
        clipboardButton.setEnabled(false);
        clipboardButton.setIconTextGap(2);
        clipboardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clipboardButtonActionPerformed(evt);
            }
        });

        selectButton
                .setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/list-16.png"))); // NOI18N
        selectButton.setToolTipText("Select / Unselect All");
        selectButton.setBorderPainted(false);
        selectButton.setEnabled(false);
        selectButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectButtonActionPerformed(evt);
            }
        });

        removeDuplicateButton.setIcon(new javax.swing.ImageIcon(
                getClass().getResource("/org/monkeys/gui/icons/remove-duplicates-16.png"))); // NOI18N
        removeDuplicateButton.setToolTipText("Remove Duplicates");
        removeDuplicateButton.setBorderPainted(false);
        removeDuplicateButton.setEnabled(false);
        removeDuplicateButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeDuplicateButtonActionPerformed(evt);
            }
        });

        removeRowButton
                .setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/remove-16.png"))); // NOI18N
        removeRowButton.setToolTipText("Remove Selected");
        removeRowButton.setBorderPainted(false);
        removeRowButton.setEnabled(false);
        removeRowButton.setIconTextGap(2);
        removeRowButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeRowButtonActionPerformed(evt);
            }
        });

        jSeparator3.setOrientation(javax.swing.SwingConstants.VERTICAL);

        jSeparator4.setOrientation(javax.swing.SwingConstants.VERTICAL);

        jSeparator5.setOrientation(javax.swing.SwingConstants.VERTICAL);

        modifyButton
                .setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/edit-16.png"))); // NOI18N
        modifyButton.setToolTipText("Edit Selected");
        modifyButton.setBorderPainted(false);
        modifyButton.setEnabled(false);
        modifyButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                modifyButtonActionPerformed(evt);
            }
        });

        jSeparator6.setOrientation(javax.swing.SwingConstants.VERTICAL);

        undoButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/monkeys/gui/icons/undo-16.png"))); // NOI18N
        undoButton.setBorderPainted(false);
        undoButton.setEnabled(false);
        undoButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                undoButtonActionPerformed(evt);
            }
        });

        jSeparator7.setOrientation(javax.swing.SwingConstants.VERTICAL);

        clipboardDropdown.setEditable(true);
        clipboardDropdown.setModel(
                new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        clipboardDropdown.setEnabled(false);

        javax.swing.GroupLayout matchingPanelLayout = new javax.swing.GroupLayout(matchingPanel);
        matchingPanel.setLayout(matchingPanelLayout);
        matchingPanelLayout.setHorizontalGroup(matchingPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(matchingPanelLayout.createSequentialGroup().addContainerGap()
                        .addGroup(matchingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(matchingPanelLayout.createSequentialGroup().addComponent(selectButton)
                                        .addGap(0, 0, 0)
                                        .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0).addComponent(removeDuplicateButton).addGap(0, 0, 0)
                                        .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0).addComponent(removeRowButton).addGap(0, 0, 0)
                                        .addComponent(jSeparator4, javax.swing.GroupLayout.PREFERRED_SIZE, 12,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0).addComponent(modifyButton).addGap(0, 0, 0)
                                        .addComponent(jSeparator6, javax.swing.GroupLayout.PREFERRED_SIZE, 12,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0).addComponent(undoButton).addGap(0, 0, 0)
                                        .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 12,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0)
                                        .addComponent(clipboardDropdown, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(0, 0, 0).addComponent(clipboardButton)
                                        .addGap(0, 0, Short.MAX_VALUE))
                                .addComponent(matchingScroll, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                                .addComponent(categoryLabel, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        Short.MAX_VALUE)
                                .addComponent(categoryDropdown, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        Short.MAX_VALUE)
                                .addComponent(matchingHeader, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap()));

        matchingPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
                new java.awt.Component[] { clipboardButton, modifyButton, removeRowButton });

        matchingPanelLayout.setVerticalGroup(matchingPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(matchingPanelLayout.createSequentialGroup().addContainerGap()
                        .addComponent(categoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(0, 0, 0)
                        .addComponent(categoryDropdown, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(matchingHeader, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGroup(matchingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(matchingPanelLayout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, matchingPanelLayout
                                                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                .addComponent(removeDuplicateButton).addComponent(jSeparator4,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addGroup(matchingPanelLayout
                                                .createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                                        false)
                                                .addComponent(selectButton,
                                                        javax.swing.GroupLayout.Alignment.LEADING,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                                                .addComponent(jSeparator3,
                                                        javax.swing.GroupLayout.Alignment.LEADING)
                                                .addComponent(removeRowButton,
                                                        javax.swing.GroupLayout.Alignment.LEADING,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        28, javax.swing.GroupLayout.PREFERRED_SIZE)))
                                .addComponent(modifyButton)
                                .addGroup(matchingPanelLayout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(clipboardButton, javax.swing.GroupLayout.Alignment.TRAILING,
                                                javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGroup(matchingPanelLayout
                                                .createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                                .addComponent(undoButton).addComponent(jSeparator6,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE)))
                                .addComponent(jSeparator7, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(clipboardDropdown, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(matchingScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 275, Short.MAX_VALUE)
                        .addContainerGap()));

        matchingPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL,
                new java.awt.Component[] { clipboardButton, clipboardDropdown });

        splitPane.setRightComponent(matchingPanel);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 664, Short.MAX_VALUE)
                        .addGap(0, 0, 0)));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(splitPane));
    }// </editor-fold>//GEN-END:initComponents

    private void editButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_editButtonActionPerformed
    {//GEN-HEADEREND:event_editButtonActionPerformed
        this.clearHighlights();
        this.toggleEdit(this.editButton.isSelected());
    }//GEN-LAST:event_editButtonActionPerformed

    private void clearButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_clearButtonActionPerformed
    {//GEN-HEADEREND:event_clearButtonActionPerformed
        this.textArea.setText("");
        this.setMatches(Collections.EMPTY_LIST);
    }//GEN-LAST:event_clearButtonActionPerformed

    private void clipboardButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_clipboardButtonActionPerformed
    {//GEN-HEADEREND:event_clipboardButtonActionPerformed
        this.copyToClipboard();
    }//GEN-LAST:event_clipboardButtonActionPerformed

    private void selectButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_selectButtonActionPerformed
    {//GEN-HEADEREND:event_selectButtonActionPerformed
        final boolean isAll;
        final int[] selected = this.matchingList.getSelectedRows();
        if (null == selected || selected.length <= 0) {
            isAll = false;
        } else {
            isAll = selected.length == this.matchingList.getMatches().size();
        }

        if (!isAll) {
            this.matchingList.getSelectionModel().addSelectionInterval(0, this.matchingList.getRowCount() - 1);
        } else {
            this.matchingList.getSelectionModel().clearSelection();
        }
    }//GEN-LAST:event_selectButtonActionPerformed

    private void removeRowButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_removeRowButtonActionPerformed
    {//GEN-HEADEREND:event_removeRowButtonActionPerformed
        final Collection<RegexMatch> matches = this.matchingList.getSelectedMatches();
        if (matches != null && !matches.isEmpty()) {
            this.matchingList.removeMatches(matches);
            this.matchingList.clearSelection();
            this.removeRowButton.setEnabled(false);
        }
    }//GEN-LAST:event_removeRowButtonActionPerformed

    private void removeDuplicateButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_removeDuplicateButtonActionPerformed
    {//GEN-HEADEREND:event_removeDuplicateButtonActionPerformed
        this.matchingList.removeDuplicates();
    }//GEN-LAST:event_removeDuplicateButtonActionPerformed

    private void modifyButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_modifyButtonActionPerformed
    {//GEN-HEADEREND:event_modifyButtonActionPerformed
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                modifyPopup.showPupup(matchingScroll, 0, 0);
            }
        });
    }//GEN-LAST:event_modifyButtonActionPerformed

    private void undoButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_undoButtonActionPerformed
    {//GEN-HEADEREND:event_undoButtonActionPerformed
        this.undoSelected();
    }//GEN-LAST:event_undoButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private org.monkeys.gui.CategoryDropdown categoryDropdown;
    private javax.swing.JButton clearButton;
    private javax.swing.JToggleButton clipboardButton;
    private javax.swing.JComboBox clipboardDropdown;
    private javax.swing.JToggleButton editButton;
    private javax.swing.JPanel editPanel;
    private org.monkeys.gui.matcher.MatcherTable matchingList;
    private javax.swing.JPanel matchingPanel;
    private javax.swing.JScrollPane matchingScroll;
    private javax.swing.JButton modifyButton;
    private javax.swing.JButton removeDuplicateButton;
    private javax.swing.JButton removeRowButton;
    private javax.swing.JToggleButton selectButton;
    private javax.swing.JTextArea textArea;
    private org.monkeys.gui.HeaderLabel textHeader;
    private javax.swing.JPanel textPanel;
    private javax.swing.JButton undoButton;
    // End of variables declaration//GEN-END:variables
}