/* * Copyright 2016 Igor Maznitsa. * * 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 com.igormaznitsa.sciareto.ui.misc; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.swing.ListModel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import com.igormaznitsa.sciareto.ui.Focuser; import com.igormaznitsa.sciareto.ui.tree.ExplorerTree; import com.igormaznitsa.sciareto.ui.tree.NodeFileOrFolder; public class GoToFilePanel extends javax.swing.JPanel implements Comparator<NodeFileOrFolder> { private static final long serialVersionUID = 6372355072139143322L; private final ExplorerTree tree; private final transient List<NodeFileOrFolder> foundNodeList = new ArrayList<>(); private final transient List<ListDataListener> listeners = new ArrayList<>(); @Override public int compare(@Nonnull final NodeFileOrFolder o1, @Nonnull final NodeFileOrFolder o2) { return o1.toString().compareTo(o2.toString()); } public GoToFilePanel(@Nonnull final ExplorerTree tree) { this.tree = tree; initComponents(); this.listFoundFiles.setCellRenderer(new NodeListRenderer()); final Dimension dim = new Dimension(512, 400); setPreferredSize(dim); setMinimumSize(dim); setMaximumSize(dim); new Focuser(this.textFieldMask); this.textFieldMask.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(@Nonnull final DocumentEvent e) { processEnteredPattern(); } @Override public void removeUpdate(@Nonnull final DocumentEvent e) { processEnteredPattern(); } @Override public void changedUpdate(@Nonnull final DocumentEvent e) { processEnteredPattern(); } }); this.listFoundFiles.setModel(new ListModel<NodeFileOrFolder>() { @Override public int getSize() { return foundNodeList.size(); } @Override @Nonnull public NodeFileOrFolder getElementAt(final int index) { return foundNodeList.get(index); } @Override public void addListDataListener(@Nonnull final ListDataListener l) { listeners.add(l); } @Override public void removeListDataListener(@Nonnull final ListDataListener l) { listeners.remove(l); } }); } @Nullable public NodeFileOrFolder getSelected() { return this.listFoundFiles.getSelectedValue(); } private void processEnteredPattern() { this.foundNodeList.clear(); this.foundNodeList.addAll(this.tree.findForNamePattern(makePattern(this.textFieldMask.getText()))); for (final ListDataListener l : this.listeners) { l.contentsChanged(new ListDataEvent(this.listFoundFiles.getModel(), ListDataEvent.CONTENTS_CHANGED, 0, this.foundNodeList.size())); } Collections.sort(this.foundNodeList, this); if (!this.foundNodeList.isEmpty()) { this.listFoundFiles.setSelectedIndex(0); this.listFoundFiles.ensureIndexIsVisible(0); } } @Nullable private Pattern makePattern(@Nonnull final String text) { if (text.isEmpty()) { return null; } final StringBuilder buffer = new StringBuilder(); for (final char c : text.toCharArray()) { switch (c) { case '?': buffer.append('.'); break; case '*': buffer.append(".*"); //NOI18N break; default: { if (Character.isWhitespace(c) || Character.isISOControl(c)) { buffer.append("\\s"); //NOI18N } else { final String code = Integer.toHexString(c).toUpperCase(Locale.ENGLISH); buffer.append("\\u").append("0000", 0, 4 - code.length()).append(code); //NOI18N } } break; } } buffer.append(".*"); //NOI18N return Pattern.compile(buffer.toString(), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); } /** * 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() { java.awt.GridBagConstraints gridBagConstraints; labelFilenameMask = new javax.swing.JLabel(); textFieldMask = new javax.swing.JTextField(); jScrollPane1 = new javax.swing.JScrollPane(); listFoundFiles = new javax.swing.JList<>(); setLayout(new java.awt.GridBagLayout()); labelFilenameMask.setText("File Name prefix (wildcards: ? and *)"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 8, 0); add(labelFilenameMask, gridBagConstraints); textFieldMask.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { textFieldMaskKeyPressed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1000.0; gridBagConstraints.insets = new java.awt.Insets(0, 0, 8, 0); add(textFieldMask, gridBagConstraints); listFoundFiles.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); listFoundFiles.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { public void mouseMoved(java.awt.event.MouseEvent evt) { listFoundFilesMouseMoved(evt); } }); jScrollPane1.setViewportView(listFoundFiles); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1000.0; gridBagConstraints.weighty = 1000.0; add(jScrollPane1, gridBagConstraints); }// </editor-fold>//GEN-END:initComponents private void listFoundFilesMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_listFoundFilesMouseMoved final ListModel model = this.listFoundFiles.getModel(); final int index = this.listFoundFiles.locationToIndex(evt.getPoint()); if (index < 0) { this.listFoundFiles.setToolTipText(null); } else { final File file = ((NodeFileOrFolder) model.getElementAt(index)).makeFileForNode(); this.listFoundFiles.setToolTipText(file == null ? null : file.getAbsolutePath()); } }//GEN-LAST:event_listFoundFilesMouseMoved private void textFieldMaskKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_textFieldMaskKeyPressed int selectedIndex = this.listFoundFiles.getSelectedIndex(); boolean processed = false; if (!evt.isConsumed() && evt.getModifiers() == 0) { switch (evt.getKeyCode()) { case KeyEvent.VK_UP: { processed = true; evt.consume(); if (selectedIndex >= 0) { selectedIndex--; } } break; case KeyEvent.VK_DOWN: { processed = true; evt.consume(); if (selectedIndex >= 0) { selectedIndex++; } } break; } if (processed && !this.foundNodeList.isEmpty()) { if (selectedIndex < 0) { selectedIndex = this.foundNodeList.size() - 1; } else if (selectedIndex >= this.foundNodeList.size()) { selectedIndex = 0; } this.listFoundFiles.setSelectedIndex(selectedIndex); this.listFoundFiles.ensureIndexIsVisible(selectedIndex); } } }//GEN-LAST:event_textFieldMaskKeyPressed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel labelFilenameMask; private javax.swing.JList<NodeFileOrFolder> listFoundFiles; private javax.swing.JTextField textFieldMask; // End of variables declaration//GEN-END:variables }