Document.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:7k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: Document.java,v 1.4 2005/10/10 18:01:34 rbair Exp $
  3.  *
  4.  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.swingx.autocomplete;
  22. import javax.swing.UIManager;
  23. import javax.swing.text.AttributeSet;
  24. import javax.swing.text.BadLocationException;
  25. import javax.swing.text.PlainDocument;
  26. /**
  27.  * A Document that can be plugged into any JTextComponent to enable automatic completion.
  28.  * It finds and selects matching items using any implementation of the AbstractComponentAdaptor.
  29.  */
  30. public class Document extends PlainDocument {
  31.     
  32.     /** Flag to indicate if adaptor.setSelectedItem has been called.
  33.      * Subsequent calls to remove/insertString should be ignored
  34.      * as they are likely have been caused by the adapted Component that
  35.      * is trying to set the text for the selected component.*/
  36.     boolean selecting=false;
  37.     
  38.     /**
  39.      * true, if only items from the adaptors's list can be entered
  40.      * false, otherwise (selected item might not be in the adaptors's list)
  41.      */
  42.     boolean strictMatching;
  43.     
  44.     /**
  45.      * The adaptor that is used to find and select items.
  46.      */
  47.     AbstractComponentAdaptor adaptor;
  48.     
  49.     /**
  50.      * Creates a new Document for the given AbstractComponentAdaptor.
  51.      * @param strictMatching true, if only items from the adaptor's list should
  52.      * be allowed to be entered
  53.      * @param adaptor The adaptor that will be used to find and select matching
  54.      * items.
  55.      */
  56.     public Document(AbstractComponentAdaptor adaptor, boolean strictMatching) {
  57.         this.adaptor = adaptor;
  58.         this.strictMatching = strictMatching;
  59.         
  60.         // Handle initially selected object
  61.         Object selected = adaptor.getSelectedItem();
  62.         if (selected!=null) setText(selected.toString());
  63.         adaptor.markEntireText();
  64.     }
  65.     
  66.     /**
  67.      * Returns if only items from the adaptor's list should be allowed to be entered.
  68.      * @return if only items from the adaptor's list should be allowed to be entered
  69.      */
  70.     public boolean isStrictMatching() {
  71.         return strictMatching;
  72.     }
  73.     
  74.     public void remove(int offs, int len) throws BadLocationException {
  75.         // return immediately when selecting an item
  76.         if (selecting) return;
  77.         super.remove(offs, len);
  78.         if (!strictMatching) {
  79.             setSelectedItem(getText(0, getLength()));
  80.             adaptor.getTextComponent().setCaretPosition(offs);
  81.         }
  82.     }
  83.     
  84.     public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
  85.         // return immediately when selecting an item
  86.         if (selecting) return;
  87.         // insert the string into the document
  88.         super.insertString(offs, str, a);
  89.         // lookup and select a matching item
  90.         Object item = lookupItem(getText(0, getLength()));
  91.         if (item != null) {
  92.             setSelectedItem(item);
  93.         } else {
  94.             if (strictMatching) {
  95.                 // keep old item selected if there is no match
  96.                 item = adaptor.getSelectedItem();
  97.                 // imitate no insert (later on offs will be incremented by
  98.                 // str.length(): selection won't move forward)
  99.                 offs = offs-str.length();
  100.                 // provide feedback to the user that his input has been received but can not be accepted
  101.                 UIManager.getLookAndFeel().provideErrorFeedback(adaptor.getTextComponent());
  102.             } else {
  103.                 // no item matches => use the current input as selected item
  104.                 item=getText(0, getLength());
  105.                 setSelectedItem(item);
  106.             }
  107.         }
  108.         setText(item==null?"":item.toString());
  109.         // select the completed part
  110.         adaptor.markText(offs+str.length());
  111.     }
  112.     
  113.     /**
  114.      * Sets the text of this Document to the given text.
  115.      * @param text the text that will be set for this document
  116.      */
  117.     private void setText(String text) {
  118.         try {
  119.             // remove all text and insert the completed string
  120.             super.remove(0, getLength());
  121.             super.insertString(0, text, null);
  122.         } catch (BadLocationException e) {
  123.             throw new RuntimeException(e.toString());
  124.         }
  125.     }
  126.     
  127.     /**
  128.      * Selects the given item using the AbstractComponentAdaptor.
  129.      * @param item the item that is to be selected
  130.      */
  131.     private void setSelectedItem(Object item) {
  132.         selecting = true;
  133.         adaptor.setSelectedItem(item);
  134.         selecting = false;
  135.     }
  136.     
  137.     /**
  138.      * Searches for an item that matches the given pattern. The AbstractComponentAdaptor
  139.      * is used to access the candidate items. The match is not case-sensitive
  140.      * and will only match at the beginning of each item's string representation.
  141.      * @param pattern the pattern that should be matched
  142.      * @return the first item that matches the pattern or <code>null</code> if no item matches
  143.      */
  144.     private Object lookupItem(String pattern) {
  145.         Object selectedItem = adaptor.getSelectedItem();
  146.         // only search for a different item if the currently selected does not match
  147.         if (selectedItem != null && startsWithIgnoreCase(selectedItem.toString(), pattern)) {
  148.             return selectedItem;
  149.         } else {
  150.             // iterate over all items
  151.             for (int i=0, n=adaptor.getItemCount(); i < n; i++) {
  152.                 Object currentItem = adaptor.getItem(i);
  153.                 // current item starts with the pattern?
  154.                 if (currentItem != null && startsWithIgnoreCase(currentItem.toString(), pattern)) {
  155.                     return currentItem;
  156.                 }
  157.             }
  158.         }
  159.         // no item starts with the pattern => return null
  160.         return null;
  161.     }
  162.     
  163.     /**
  164.      * Returns true if <code>string1</code> starts with <code>string2</code> (ignoring case).
  165.      * @param string1 the first string
  166.      * @param string2 the second string
  167.      * @return true if <code>string1</code> starts with <code>string2</code>; false otherwise
  168.      */
  169.     private boolean startsWithIgnoreCase(String string1, String string2) {
  170.         // this could be optimized, but anyway it doesn't seem to be a performance killer
  171.         return string1.toUpperCase().startsWith(string2.toUpperCase());
  172.     }
  173. }