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