001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010 Sun Microsystems, Inc.
015 * Portions Copyright 2015-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.event;
018
019import java.awt.Component;
020import java.awt.Container;
021import java.awt.event.KeyEvent;
022
023import javax.swing.ComboBoxModel;
024import javax.swing.JComboBox;
025import javax.swing.JLabel;
026import javax.swing.JList;
027import javax.swing.JComboBox.KeySelectionManager;
028import javax.swing.text.JTextComponent;
029
030/**
031 * A class used to allow the user to type a sequence of characters that will
032 * select automatically an item in the combo box.
033 * Note that there must be one instance of this class per combo box.  Two
034 * combo boxes must not share the same ComboKeySelectionManager object and
035 * two ComboKeySelectionManager must not be used by the same combo box.
036 */
037public class ComboKeySelectionManager implements KeySelectionManager
038{
039  private JComboBox combo;
040  private JList list;
041
042  /** The String that we are searching. */
043  private String lastSearchedString;
044
045  private long lastSearchedTime;
046
047  /**
048   * The number of milliseconds we wait between types before considering that
049   * the search starts again.
050   */
051  private long RESET_BETWEEN_TYPES = 700;
052
053  /**
054   * Default constructor.
055   * @param combo the combo box that is attached to this selection key manager.
056   */
057  public ComboKeySelectionManager(JComboBox combo)
058  {
059    this.combo = combo;
060    list = new JList();
061  }
062
063  @Override
064  public int selectionForKey(char key, ComboBoxModel model)
065  {
066    int selectedIndex = -1;
067    long currentTime = System.currentTimeMillis();
068    if (key == KeyEvent.VK_BACK_SPACE)
069    {
070      if (lastSearchedString == null)
071      {
072        lastSearchedString = "";
073      }
074      else if (lastSearchedString.length() > 0)
075      {
076        lastSearchedString = lastSearchedString.substring(0,
077            lastSearchedString.length() -1);
078      }
079      else
080      {
081        // Nothing to do.
082      }
083    }
084    else
085    {
086      if (lastSearchedTime + RESET_BETWEEN_TYPES < currentTime)
087      {
088        // Reset the search.
089        lastSearchedString = String.valueOf(key);
090      }
091      else
092      {
093        if (lastSearchedString == null)
094        {
095          lastSearchedString = String.valueOf(key);
096        }
097        else
098        {
099          lastSearchedString += key;
100        }
101      }
102    }
103    lastSearchedTime = currentTime;
104    if (lastSearchedString.length() > 0)
105    {
106      for (int i = 0; i < model.getSize() && selectedIndex == -1; i++)
107      {
108        Object value = model.getElementAt(i);
109        Component comp = combo.getRenderer().getListCellRendererComponent(list,
110            value, i, true, true);
111        String sValue;
112        if (comp instanceof Container)
113        {
114          sValue = getDisplayedStringValue((Container)comp);
115          if (sValue == null)
116          {
117            sValue = "";
118          }
119          else
120          {
121            sValue = sValue.trim();
122          }
123        }
124        else
125        {
126          sValue = String.valueOf(value);
127        }
128        if (sValue.toLowerCase().startsWith(lastSearchedString.toLowerCase()))
129        {
130          selectedIndex = i;
131        }
132      }
133    }
134    return selectedIndex;
135  }
136
137  private String getDisplayedStringValue(Container c)
138  {
139    String sValue = null;
140    if (c instanceof JLabel)
141    {
142      sValue = ((JLabel)c).getText();
143    }
144    else if (c instanceof JTextComponent)
145    {
146      sValue = ((JTextComponent)c).getText();
147    }
148    else
149    {
150      int nCount = c.getComponentCount();
151      for (int i=0 ; i<nCount && sValue == null; i++)
152      {
153        Component child = c.getComponent(i);
154        if (child instanceof Container)
155        {
156          sValue = getDisplayedStringValue((Container)child);
157        }
158      }
159    }
160    return sValue;
161  }
162}