/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.cayenne.modeler.util.combo; import java.lang.reflect.Method; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; import javax.swing.plaf.basic.BasicComboBoxEditor; import org.apache.cayenne.modeler.util.CellRenderers; /** * CustomTypeComboBoxEditor is used as an editor of a combobox, when * custom type (such as Entity) is to be used. BasicComboBoxEditor * cannot be used, because it converts String values to other types * incorrectly (in fact, only classes with valueOf(String) methods * are supported). * */ public class CustomTypeComboBoxEditor extends BasicComboBoxEditor { /** * 'oldValue' property is private somewhy, so we make our local * copy */ protected Object localOldValue; /** * The combobox being edited */ protected final JComboBox combo; /** * Whether non-present items are allowed */ protected final boolean allowsUserValues; /** * Creates new editor * @param combo ComboBox being edited */ public CustomTypeComboBoxEditor(JComboBox combo, boolean allowsUserValues) { editor = new EditorTextField(combo); this.combo = combo; this.allowsUserValues = allowsUserValues; } /** * Sets the item that should be edited. * * @param anObject the displayed value of the editor */ @Override public void setItem(Object anObject) { localOldValue = anObject; super.setItem(anObject == null ? null : CellRenderers.asString(anObject)); } /** * @return edited item */ @Override public Object getItem() { Object newValue = editor.getText(); if (localOldValue != null && !(localOldValue instanceof String)) { // The original value is not a string. Should return the value in it's // original type. if (newValue.equals(localOldValue.toString())) { return localOldValue; } else { // Must take the value from the editor and get the value and cast it to the new type. Class cls = localOldValue.getClass(); try { newValue = convert((String)newValue, cls); } catch (Exception ignored) {} } } if (!allowsUserValues && newValue != null) { boolean contains = false; for (int i = 0; i < combo.getItemCount(); i++) { if (newValue.equals(combo.getItemAt(i))) { contains = true; break; } } if (!contains) { return null; } } return newValue; } /** * Converts String value to specified type * * @param value String value of textfield * @param classTo type of result item * * @return value of classTo type, or null if conversion is impossible */ protected Object convert(String value, Class<?> classTo) { if (classTo == String.class) { return value; } /* * We still try to it in BasicComboBox's way, so that primary object * types (such as numbers) would still be supported */ try { Method method = classTo.getMethod("valueOf", String.class); return method.invoke(null, value); } catch (Exception ignored) {} /* * We could manually convert strings to dbentities, attrs and other, but * in this implementation we use reverse operation instead, and convert * combobox model's items to String. * All string values are assumed unique is one model. */ ComboBoxModel model = combo.getModel(); for (int i = 0; i < model.getSize(); i++) { if (value.equals(CellRenderers.asString(model.getElementAt(i)))) { return model.getElementAt(i); } } //we return null, since String will not be appreciated return null; } }