You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
621 lines
22 KiB
621 lines
22 KiB
package com.fr.design.gui.icombobox; |
|
|
|
import java.awt.BorderLayout; |
|
import java.awt.Color; |
|
import java.awt.Component; |
|
import java.awt.Dimension; |
|
import java.awt.Graphics; |
|
import java.awt.Graphics2D; |
|
import java.awt.IllegalComponentStateException; |
|
import java.awt.RenderingHints; |
|
import java.awt.event.KeyAdapter; |
|
import java.awt.event.KeyEvent; |
|
import java.awt.event.KeyListener; |
|
import java.awt.event.MouseAdapter; |
|
import java.awt.event.MouseEvent; |
|
import java.awt.event.MouseListener; |
|
import java.awt.event.MouseMotionAdapter; |
|
import java.awt.event.MouseMotionListener; |
|
import java.util.Enumeration; |
|
|
|
import javax.swing.BorderFactory; |
|
import javax.swing.DefaultListCellRenderer; |
|
import javax.swing.JComboBox; |
|
import javax.swing.JComponent; |
|
import javax.swing.JList; |
|
import javax.swing.JPopupMenu; |
|
import javax.swing.JScrollPane; |
|
import javax.swing.JTree; |
|
import javax.swing.MenuSelectionManager; |
|
import javax.swing.SwingUtilities; |
|
import javax.swing.event.DocumentEvent; |
|
import javax.swing.event.DocumentListener; |
|
import javax.swing.event.PopupMenuListener; |
|
import javax.swing.plaf.basic.BasicComboBoxUI; |
|
import javax.swing.plaf.basic.ComboPopup; |
|
import javax.swing.tree.DefaultMutableTreeNode; |
|
import javax.swing.tree.DefaultTreeModel; |
|
import javax.swing.tree.TreeCellRenderer; |
|
import javax.swing.tree.TreeNode; |
|
import javax.swing.tree.TreePath; |
|
|
|
import com.fr.design.constants.UIConstants; |
|
import com.fr.design.gui.ibutton.UIButton; |
|
import com.fr.design.gui.ilable.UILabel; |
|
import com.fr.design.gui.itextfield.UITextField; |
|
import com.fr.design.layout.FRGUIPaneFactory; |
|
import com.fr.general.ComparatorUtils; |
|
import com.fr.general.NameObject; |
|
import com.fr.stable.Constants; |
|
import com.fr.stable.StringUtils; |
|
|
|
public class FRTreeComboBox extends UIComboBox { |
|
|
|
private static final int PAGE_DIFF = 5; |
|
private static final int DEFAULT_HEIGHT = 120; |
|
|
|
// richer:下拉展示用的tree |
|
protected JTree tree; |
|
private boolean onlyLeafSelectable = true; |
|
|
|
public FRTreeComboBox() { |
|
this(new JTree()); |
|
} |
|
|
|
public FRTreeComboBox(JTree tree) { |
|
this(tree, null); |
|
} |
|
|
|
public FRTreeComboBox(JTree tree, TreeCellRenderer renderer) { |
|
this(tree, renderer, false); |
|
} |
|
|
|
public FRTreeComboBox(JTree tree, TreeCellRenderer renderer, boolean editable) { |
|
this(tree, renderer, false, editable); |
|
} |
|
|
|
public FRTreeComboBox(JTree tree, TreeCellRenderer renderer, |
|
boolean showRoot, boolean editable) { |
|
this.setTree(tree); |
|
this.tree.setCellRenderer(renderer); |
|
this.setEditor(new FrTreeSearchComboBoxEditor(this)); |
|
if (!showRoot) { |
|
tree.expandPath(new TreePath(tree.getModel().getRoot())); |
|
tree.setRootVisible(false); |
|
} |
|
this.setEditable(editable); |
|
setUI(new FRTreeComboBoxUI()); |
|
} |
|
|
|
public JTree getTree() { |
|
return this.tree; |
|
} |
|
|
|
/** |
|
* 自定义那些那些node可以选中,默认情况下所有node节点都可以选中 |
|
* @param node |
|
* @return |
|
*/ |
|
protected boolean customSelectable(DefaultMutableTreeNode node){ |
|
return true; |
|
} |
|
|
|
public void setTree(JTree tree) { |
|
this.tree = tree; |
|
if (tree != null) { |
|
this.setSelectedItem(tree.getSelectionPath()); |
|
this.setRenderer(new TreeComboBoxRenderer()); |
|
} |
|
} |
|
|
|
public void setOnlyLeafSelectable(boolean onlyLeafSelectable) { |
|
this.onlyLeafSelectable = onlyLeafSelectable; |
|
} |
|
|
|
/** |
|
* 获得FRTreeComboBox的返回值 |
|
* |
|
* @return Object |
|
*/ |
|
public Object getSelectedObject() { |
|
if (!(this.getSelectedItem() instanceof TreePath)) { |
|
return this.getSelectedItem(); |
|
} |
|
TreePath treePath = (TreePath) this.getSelectedItem(); |
|
if (treePath == null) { |
|
return null; |
|
} |
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent(); |
|
return node.getUserObject(); |
|
} |
|
|
|
public String getProcedureSelectName() { |
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode) ((TreePath) this.getSelectedItem()).getLastPathComponent(); |
|
NameObject no = (NameObject) node.getUserObject(); |
|
String ds2 = no.getName(); |
|
node = (DefaultMutableTreeNode) node.getParent(); |
|
no = (NameObject) node.getUserObject(); |
|
String ds1 = no.getName(); |
|
return ds1 + "." + ds2; |
|
} |
|
|
|
protected void dealSamePath(TreePath parent,TreeNode node,UITextField textField){ |
|
boolean isBreak = false; |
|
for (Enumeration e = node.children(); e.hasMoreElements(); ) { |
|
TreeNode n = (TreeNode) e.nextElement(); |
|
TreePath path = parent.pathByAddingChild(n); |
|
TreeNode pathnode = (TreeNode) path.getLastPathComponent(); |
|
for (Enumeration e2 = pathnode.children(); e2.hasMoreElements(); ) { |
|
TreeNode n2 = (TreeNode) e2.nextElement(); |
|
TreePath path2 = path.pathByAddingChild(n2); |
|
if (pathToString(path2).toUpperCase().startsWith(textField.getText().toUpperCase())) { |
|
tree.scrollPathToVisible(path2); |
|
tree.setSelectionPath(path2); |
|
isBreak = true; |
|
break; |
|
} |
|
} |
|
if (isBreak) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
public void setSelectedItem(Object o) { |
|
if (o instanceof String) { |
|
this.setSelectedItemString((String) o); |
|
return; |
|
} |
|
this.tree.setSelectionPath((TreePath) o); |
|
if (this.isEditable && o != null) { |
|
this.setSelectedItemString(pathToString((TreePath) o)); |
|
} else { |
|
this.getModel().setSelectedItem(o); |
|
} |
|
} |
|
|
|
private boolean validTreePath(String treePath){ |
|
return StringUtils.isNotEmpty(treePath) && treePath.charAt(0) == '[' && treePath.endsWith("]"); |
|
} |
|
|
|
protected String pathToString(TreePath path) { |
|
String temp = path.toString(); |
|
if (validTreePath(temp)) { |
|
temp = temp.substring(2, temp.length() - 1); |
|
String[] selectedtable = temp.split(","); |
|
String table = selectedtable[selectedtable.length - 1].trim(); |
|
if (table.contains(".")) { |
|
String[] temp2 = table.split("\\."); |
|
table = temp2[temp2.length - 1].trim(); |
|
} |
|
return table; |
|
} |
|
return ""; |
|
} |
|
|
|
/* |
|
* richer:根据NameObject的名字来选取 |
|
*/ |
|
public void setSelectedItemString(String _name) { |
|
if (StringUtils.isBlank(_name)) { |
|
this.setSelectedIndex(-1); |
|
return; |
|
} |
|
DefaultTreeModel model = (DefaultTreeModel) this.tree.getModel(); |
|
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); |
|
DefaultMutableTreeNode leaf = root.getFirstLeaf(); |
|
do { |
|
Object userObj = leaf.getUserObject(); |
|
if (userObj instanceof NameObject) { |
|
if (ComparatorUtils.equals(_name, ((NameObject) userObj).getName())) { |
|
TreePath path = new TreePath(model.getPathToRoot(leaf)); |
|
this.tree.setSelectionPath(path); |
|
this.setSelectedItem(path); |
|
break; |
|
} |
|
} |
|
} while ((leaf = leaf.getNextLeaf()) != null); |
|
if (leaf == null) { |
|
this.getModel().setSelectedItem(_name); |
|
} |
|
} |
|
|
|
public void setSelectedFirst() { |
|
DefaultTreeModel model = (DefaultTreeModel) this.tree.getModel(); |
|
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); |
|
if (root == null) { |
|
return; |
|
} |
|
DefaultMutableTreeNode leaf = root.getFirstLeaf(); |
|
if (leaf == null) { |
|
return; |
|
} |
|
if (leaf.getUserObject() instanceof NameObject) { |
|
TreePath path = new TreePath(model.getPathToRoot(leaf)); |
|
this.tree.setSelectionPath(path); |
|
this.setSelectedItem(path); |
|
} |
|
} |
|
|
|
public void setPopSize(int width, int height) { |
|
treePopup.setPopSize(width, height); |
|
} |
|
|
|
|
|
private static TreePopup treePopup; |
|
|
|
private static class FRTreeComboBoxUI extends BasicComboBoxUI implements MouseListener{ |
|
private boolean isRollover = false; |
|
|
|
public FRTreeComboBoxUI() { |
|
super(); |
|
} |
|
protected ComboPopup createPopup() { |
|
treePopup = new TreePopup(comboBox); |
|
return treePopup; |
|
} |
|
@Override |
|
protected UIButton createArrowButton() { |
|
arrowButton = new UIButton(UIConstants.ARROW_DOWN_ICON){ |
|
/** |
|
* 组件是否需要响应添加的观察者事件 |
|
* |
|
* @return 如果需要响应观察者事件则返回true,否则返回false |
|
*/ |
|
@Override |
|
public boolean shouldResponseChangeListener() { |
|
return false; |
|
} |
|
}; |
|
((UIButton) arrowButton).setRoundBorder(true, Constants.LEFT); |
|
arrowButton.addMouseListener(this); |
|
comboBox.addMouseListener(this); |
|
return (UIButton) arrowButton; |
|
} |
|
|
|
public void paint(Graphics g, JComponent c) { |
|
super.paint(g, c); |
|
Graphics2D g2d = (Graphics2D)g; |
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
|
Color linecolor = null; |
|
if (comboBox.isPopupVisible()) { |
|
linecolor = UIConstants.LINE_COLOR; |
|
arrowButton.setSelected(true); |
|
} else if (isRollover) { |
|
linecolor = UIConstants.LIGHT_BLUE; |
|
} else { |
|
linecolor = UIConstants.LINE_COLOR; |
|
arrowButton.setSelected(false); |
|
} |
|
g2d.setColor(linecolor); |
|
if (!comboBox.isPopupVisible()) { |
|
g2d.drawRoundRect(0, 0, c.getWidth() - arrowButton.getWidth() + 3, c.getHeight() - 1, UIConstants.LARGEARC, UIConstants.LARGEARC); |
|
} else { |
|
g2d.drawRoundRect(0, 0, c.getWidth() , c.getHeight() + 3, UIConstants.LARGEARC, UIConstants.LARGEARC ); |
|
g2d.drawLine(0, c.getHeight()-1, c.getWidth(), c.getHeight()-1); |
|
} |
|
} |
|
|
|
|
|
|
|
private void setRollover(boolean isRollover) { |
|
if (this.isRollover != isRollover) { |
|
this.isRollover = isRollover; |
|
comboBox.repaint(); |
|
} |
|
} |
|
|
|
@Override |
|
public void mouseEntered(MouseEvent e) { |
|
setRollover(true); |
|
} |
|
|
|
@Override |
|
public void mouseExited(MouseEvent e) { |
|
setRollover(false); |
|
} |
|
|
|
@Override |
|
public void mouseClicked(MouseEvent e) { |
|
} |
|
|
|
@Override |
|
public void mousePressed(MouseEvent e) { |
|
|
|
} |
|
|
|
@Override |
|
public void mouseReleased(MouseEvent e) { |
|
|
|
} |
|
} |
|
|
|
/** |
|
* 添加弹出菜单监听 |
|
* |
|
* @param l 监听事件 |
|
* |
|
* @date 2015-1-22-下午5:04:00 |
|
* |
|
*/ |
|
public void addPopupMenuListener(PopupMenuListener l) { |
|
treePopup.addPopupMenuListener(l); |
|
} |
|
|
|
private class TreeComboBoxRenderer extends DefaultListCellRenderer { |
|
public Component getListCellRendererComponent(JList list, Object value, |
|
int index, boolean isSelected, boolean cellHasFocus) { |
|
if (value != null) { |
|
TreePath path = (TreePath) value; |
|
TreeNode node = (TreeNode) path.getLastPathComponent(); |
|
value = node; |
|
TreeCellRenderer treeCellRenderer = tree.getCellRenderer(); |
|
UILabel lb = (UILabel) treeCellRenderer.getTreeCellRendererComponent(tree, value, isSelected, |
|
false, node.isLeaf(), index, cellHasFocus); |
|
return lb; |
|
} |
|
return super.getListCellRendererComponent(list, value, index, |
|
isSelected, cellHasFocus); |
|
} |
|
} |
|
|
|
/* |
|
* richer:弹出部分 |
|
*/ |
|
private static class TreePopup extends JPopupMenu implements ComboPopup { |
|
/** |
|
* |
|
*/ |
|
private static final long serialVersionUID = 1L; |
|
private int defaultWidth = 0; |
|
private int defaultHeight = 0; |
|
protected FRTreeComboBox comboBox; |
|
protected JScrollPane scrollPane; |
|
protected JTree tree; |
|
|
|
protected MouseMotionListener mouseMotionListener; |
|
protected MouseListener mouseListener; |
|
private MouseListener treeSelectListener = new MouseAdapter() { |
|
public void mousePressed(MouseEvent e) { |
|
JTree tree = (JTree) e.getSource(); |
|
TreePath treePath = tree.getPathForLocation(e.getPoint().x, e |
|
.getPoint().y); |
|
if (treePath == null) { |
|
return; |
|
} |
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath |
|
.getLastPathComponent(); |
|
selectTreeItem(node, treePath); |
|
} |
|
}; |
|
|
|
//samuel:相应首字母导航的键盘确定 |
|
private KeyListener treeKeyListener = new KeyAdapter() { |
|
public void keyReleased(KeyEvent e) { |
|
int key = e.getKeyCode(); |
|
if (key == KeyEvent.VK_ENTER) { |
|
TreePath treePath = tree.getSelectionPath(); |
|
if (treePath == null) { |
|
return; |
|
} |
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath |
|
.getLastPathComponent(); |
|
selectTreeItem(node, treePath); |
|
} |
|
} |
|
}; |
|
|
|
private void selectTreeItem(DefaultMutableTreeNode node, TreePath treePath) { |
|
if (node.isRoot()) { |
|
return; |
|
} |
|
if (comboBox.onlyLeafSelectable && !node.isLeaf()) { |
|
return; |
|
} |
|
|
|
//自定义node是否可选择 |
|
if (!comboBox.customSelectable(node)){ |
|
return; |
|
} |
|
|
|
comboBox.setSelectedItem(treePath); |
|
togglePopup(); |
|
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
} |
|
|
|
public TreePopup(JComboBox comboBox) { |
|
this.comboBox = (FRTreeComboBox) comboBox; |
|
this.setBorder(BorderFactory.createLineBorder(Color.black)); |
|
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
|
this.setLightWeightPopupEnabled(comboBox |
|
.isLightWeightPopupEnabled()); |
|
tree = this.comboBox.getTree(); |
|
if (tree != null) { |
|
this.scrollPane = new JScrollPane(tree); |
|
this.scrollPane.setBorder(null); |
|
this.add(this.scrollPane, BorderLayout.CENTER); |
|
tree.addMouseListener(this.treeSelectListener); |
|
tree.addKeyListener(this.treeKeyListener); |
|
} |
|
} |
|
|
|
public void show() { |
|
this.updatePopup(); |
|
try { |
|
/* |
|
* 这里有个问题,可能是哪里的listenerr有冲突将这个JPopMenu show的X设置为70时 |
|
* 正好可以脱离DBManipulationPane,此时可以正确相应鼠标点击事件,否则由于焦点不在JPopmenu |
|
* 上点击,树时将导致窗口销毁,无法正确相应点击事件 |
|
*/ |
|
this.show(comboBox, 0, comboBox.getHeight()); |
|
} catch (IllegalComponentStateException e) { |
|
// richer:这里有可能会抛出一个异常,可以不用处理 |
|
} |
|
} |
|
|
|
public void hide() { |
|
this.setVisible(false); |
|
} |
|
|
|
public JList getList() { |
|
return new JList(); |
|
} |
|
|
|
public MouseMotionListener getMouseMotionListener() { |
|
if (mouseMotionListener == null) { |
|
mouseMotionListener = new MouseMotionAdapter() { |
|
}; |
|
} |
|
return mouseMotionListener; |
|
} |
|
|
|
public KeyListener getKeyListener() { |
|
return null; |
|
} |
|
|
|
public void uninstallingUI() { |
|
} |
|
|
|
public MouseListener getMouseListener() { |
|
if (mouseListener == null) { |
|
mouseListener = new InvocationMouseHandler(); |
|
} |
|
return mouseListener; |
|
} |
|
|
|
protected void togglePopup() { |
|
if (this.isVisible()) { |
|
this.hide(); |
|
} else { |
|
this.show(); |
|
} |
|
} |
|
|
|
protected void updatePopup() { |
|
int width = defaultWidth == 0 ? this.comboBox.getSize().width : defaultWidth; |
|
int height = defaultHeight == 0 ? DEFAULT_HEIGHT : defaultHeight; |
|
this.setPreferredSize(new Dimension(width, height)); |
|
Object selectedObj = this.comboBox.getSelectedItem(); |
|
if (selectedObj instanceof TreePath) { |
|
TreePath tp = (TreePath) selectedObj; |
|
(this.comboBox).getTree().setSelectionPath(tp); |
|
} |
|
} |
|
|
|
public void setPopSize(int width, int height) { |
|
this.defaultWidth = width; |
|
this.defaultHeight = height; |
|
} |
|
|
|
protected class InvocationMouseHandler extends MouseAdapter { |
|
public void mousePressed(MouseEvent e) { |
|
if (!SwingUtilities.isLeftMouseButton(e) |
|
|| !comboBox.isEnabled()) { |
|
return; |
|
} |
|
if (comboBox.isEditable()) { |
|
Component comp = comboBox.getEditor().getEditorComponent(); |
|
if ((!(comp instanceof JComponent)) |
|
|| ((JComponent) comp).isRequestFocusEnabled()) { |
|
comp.requestFocus(); |
|
} |
|
} else if (comboBox.isRequestFocusEnabled()) { |
|
comboBox.requestFocus(); |
|
} |
|
togglePopup(); |
|
} |
|
} |
|
} |
|
|
|
class FrTreeSearchComboBoxEditor extends UIComboBoxEditor implements DocumentListener { |
|
private volatile boolean setting = false; |
|
private FRTreeComboBox comboBox; |
|
private Object item; |
|
|
|
public FrTreeSearchComboBoxEditor(FRTreeComboBox comboBox) { |
|
super(); |
|
this.comboBox = comboBox; |
|
textField.getDocument().addDocumentListener(this); |
|
textField.addKeyListener(this.treeKeyListener); |
|
} |
|
|
|
private KeyListener treeKeyListener = new KeyAdapter() { |
|
public void keyPressed(KeyEvent e) { |
|
int key = e.getKeyCode(); |
|
if (key == KeyEvent.VK_DOWN) { |
|
int row = tree.getRowForPath(tree.getSelectionPath()) + 1; |
|
tree.setSelectionRow(row); |
|
tree.scrollRowToVisible(row); |
|
} else if (key == KeyEvent.VK_UP) { |
|
int row = tree.getRowForPath(tree.getSelectionPath()) - 1; |
|
tree.setSelectionRow(row); |
|
tree.scrollRowToVisible(row); |
|
} else if (key == KeyEvent.VK_PAGE_DOWN) { |
|
int row = tree.getRowForPath(tree.getSelectionPath()) + PAGE_DIFF; |
|
tree.setSelectionRow(row); |
|
tree.scrollRowToVisible(row); |
|
} else if (key == KeyEvent.VK_PAGE_UP) { |
|
int row = tree.getRowForPath(tree.getSelectionPath()) - PAGE_DIFF; |
|
tree.setSelectionRow(row); |
|
tree.scrollRowToVisible(row); |
|
} |
|
} |
|
|
|
public void keyReleased(KeyEvent e) { |
|
int key = e.getKeyCode(); |
|
if (key == KeyEvent.VK_ENTER) { |
|
TreePath treePath = tree.getSelectionPath(); |
|
if (treePath == null) { |
|
return; |
|
} |
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath |
|
.getLastPathComponent(); |
|
if (node.isLeaf()) { |
|
comboBox.setSelectedItem(treePath); |
|
textField.setText(pathToString(treePath)); |
|
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
} |
|
} |
|
|
|
} |
|
}; |
|
|
|
|
|
public void setItem(Object item) { |
|
this.item = item; |
|
this.setting = true; |
|
textField.setText((item == null) ? "" : item.toString()); |
|
this.setting = false; |
|
} |
|
|
|
public Object getItem() { |
|
return this.item; |
|
} |
|
|
|
public void insertUpdate(DocumentEvent e) { |
|
changeHandler(); |
|
} |
|
|
|
public void removeUpdate(DocumentEvent e) { |
|
changeHandler(); |
|
} |
|
|
|
public void changedUpdate(DocumentEvent e) { |
|
changeHandler(); |
|
} |
|
|
|
protected void changeHandler() { |
|
if (setting) { |
|
return; |
|
} |
|
setPopupVisible(true); |
|
this.item = textField.getText(); |
|
TreeNode root = (TreeNode) tree.getModel().getRoot(); |
|
TreePath parent = new TreePath(root); |
|
TreeNode node = (TreeNode) parent.getLastPathComponent(); |
|
dealSamePath(parent,node,textField); |
|
this.getEditorComponent().requestFocus(); |
|
} |
|
|
|
} |
|
} |