/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ package org.lobobrowser.primary.ext; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.net.URL; import java.util.Collection; import java.util.Iterator; import javax.swing.JComboBox; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; /** * The Class AddressField. */ public class AddressField extends JComboBox<String> { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 1L; /** The component source. */ private final ComponentSource componentSource; /** * Instantiates a new address field. * * @param cs * the cs */ public AddressField(ComponentSource cs) { this.componentSource = cs; this.setEditable(true); TextFieldComboBoxEditor editor = new TextFieldComboBoxEditor(); this.setEditor(editor); editor.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { onKeyReleased(e); } @Override public void keyPressed(KeyEvent e) { onKeyPressed(e); } }); this.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { onBeforePopupVisible(); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } @Override public void popupMenuCanceled(PopupMenuEvent e) { } }); this.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); if ("comboBoxEdited".equals(cmd)) { onEdited(event.getModifiers()); } else if ("comboBoxChanged".equals(cmd)) { } } }); // This needed the first time to set a reasonable // popup size. this.onBeforePopupVisible(); } /** * Gets the text. * * @return the text */ public String getText() { if (this.isEditable()) { return (String) this.getEditor().getItem(); } else { return String.valueOf(this.getSelectedItem()); } } /** * Sets the text. * * @param text * the new text */ public void setText(String text) { JComboBox<String> combo = this; boolean editable = this.isEditable(); if (editable) { combo.getEditor().setItem(text); } } /** * Sets the url. * * @param url * the new url */ public void setUrl(URL url) { this.setText(url == null ? "" : url.toExternalForm()); } /** * On before popup visible. */ private void onBeforePopupVisible() { if ((comboInvalid || comboHasHeadMatches) && !populatingMatches) { populateCombo(this.getText()); } } /** The combo invalid. */ private boolean comboInvalid = true; /** The combo has head matches. */ private boolean comboHasHeadMatches = false; /** The populating matches. */ private boolean populatingMatches = false; /** * Populate combo. * * @param comboBoxText * the combo box text */ private void populateCombo(String comboBoxText) { // Expected to be called in GUI thread. this.populatingMatches = true; try { JComboBox<String> urlComboBox = this; urlComboBox.removeAllItems(); Collection<String> recentUrls = this.componentSource.getRecentLocations(30); Iterator<String> i = recentUrls.iterator(); while (i.hasNext()) { String matchUrl = i.next(); urlComboBox.addItem(matchUrl); } this.setText(comboBoxText); this.comboHasHeadMatches = false; this.comboInvalid = false; } finally { this.populatingMatches = false; } } /** * On edited. * * @param modifiers * the modifiers */ private void onEdited(int modifiers) { // if(this.getText().length() != 0) { // this.componentSource.navigateOrSearch(); // } } /** * On key released. * * @param event * the event */ private void onKeyReleased(KeyEvent event) { AddressField urlComboBox = this; char releasedChar = event.getKeyChar(); if (validPopupChar(releasedChar)) { String urlText = urlComboBox.getText(); Collection<String> headMatches = this.componentSource.getPotentialMatches(urlText); if (headMatches.size() == 0) { if (urlComboBox.isPopupVisible()) { urlComboBox.hidePopup(); } } else { populatingMatches = true; try { urlComboBox.removeAllItems(); Iterator<String> i = headMatches.iterator(); while (i.hasNext()) { String matchUrl = (String) i.next(); urlComboBox.addItem(matchUrl); } comboHasHeadMatches = true; if (!urlComboBox.isPopupVisible()) { urlComboBox.showPopup(); } urlComboBox.setSelectedItem(null); urlComboBox.setText(urlText); } finally { populatingMatches = false; } } } } /** * On key pressed. * * @param event * the event */ private void onKeyPressed(KeyEvent event) { AddressField urlComboBox = this; if (event.getKeyCode() == KeyEvent.VK_ENTER) { String urlText = urlComboBox.getText(); if (urlText.length() != 0) { this.componentSource.navigateOrSearch(); } } } /** * Valid popup char. * * @param ch * the ch * @return true, if successful */ private boolean validPopupChar(char ch) { return Character.isLetterOrDigit(ch) || (ch == '.') || (ch == '/'); } }