package org.rr.jeborker.gui.cell; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; import java.util.logging.Level; import javax.swing.Icon; import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import org.rr.commons.log.LoggerFactory; import org.rr.commons.mufs.IResourceHandler; import org.rr.commons.mufs.ResourceHandlerFactory; import org.rr.commons.swing.SwingUtils; import org.rr.commons.swing.components.JRCheckBox; import org.rr.commons.swing.components.JRLabel; import org.rr.commons.swing.components.tree.TreeUtil; import org.rr.commons.utils.StringUtil; import org.rr.jeborker.app.BasePathList; import org.rr.jeborker.app.preferences.APreferenceStore; import org.rr.jeborker.app.preferences.PreferenceStoreFactory; import org.rr.jeborker.gui.MainMenuBarController; import org.rr.jeborker.gui.action.ActionUtils; import org.rr.jeborker.gui.model.BasePathTreeModel; import org.rr.jeborker.gui.model.FileSystemNode; import org.rr.jeborker.gui.resources.ImageResourceBundle; public class BasePathTreeCellRenderer extends JPanel implements TreeCellRenderer { private static final Color filteredForegroundColor = Color.DARK_GRAY.brighter().brighter(); private JRLabel label; private JTree tree; private JRCheckBox checkbox; private Object value; private boolean isDropCell; private Icon eyesVisible; private Icon eyesInvisible; private Icon eyesTreeState; private Font labelNormalFont; private Font labelBoldFont; private ItemListener[] allCheckboxItemListeners; public BasePathTreeCellRenderer(JTree tree) { this.tree = tree; setOpaque(false); eyesVisible = ImageResourceBundle.getResourceAsImageIcon("eyes_blue_16.png"); eyesInvisible = ImageResourceBundle.getResourceAsImageIcon("eyes_gray_16.png"); eyesTreeState = ImageResourceBundle.getResourceAsImageIcon("eyes_between_16.png"); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 20, 0}; gridBagLayout.rowHeights = new int[]{0, 0}; gridBagLayout.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; setLayout(gridBagLayout); checkbox = new JRCheckBox(); GridBagConstraints gbc_chckbxCheck = new GridBagConstraints(); gbc_chckbxCheck.insets = new Insets(0, 0, 0, 5); gbc_chckbxCheck.gridx = 0; gbc_chckbxCheck.gridy = 0; add(checkbox, gbc_chckbxCheck); checkbox.addItemListener(createCheckboxItemListener()); checkbox.setRolloverEnabled(false); checkbox.setTriStateIcon(eyesTreeState); checkbox.setIcon(eyesInvisible); //unselected icon checkbox.setSelectedIcon(eyesVisible); //selected icon checkbox.setDisabledIcon(eyesInvisible); checkbox.setDisabledSelectedIcon(eyesInvisible); checkbox.setOpaque(false); label = new JRLabel(); setupLabelFont(); label.setOpaque(false); label.setUnderline(null); label.setUnderlineInset(-3); label.setUnderlineThinkness(2); GridBagConstraints gbc_label = new GridBagConstraints(); gbc_label.fill = GridBagConstraints.BOTH; gbc_label.gridx = 1; gbc_label.gridy = 0; add(label, gbc_label); } private ItemListener createCheckboxItemListener() { return new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { final TreePath selectionPath = tree.getSelectionPath(); if(selectionPath != null) { Object lastPathComponent = selectionPath.getLastPathComponent(); String resourceName = null; if (lastPathComponent instanceof IResourceHandler) { resourceName = ((IResourceHandler) lastPathComponent).toString(); } else if(lastPathComponent instanceof FileSystemNode){ resourceName = ((FileSystemNode)lastPathComponent).getResource().toString(); } if(resourceName != null) { ActionUtils.toggleBasePathVisibility(resourceName); } else { final APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE); final BasePathList basePaths = preferenceStore.getBasePath(); final boolean isVisible = basePaths.isAllPathElementsVisible(); for(String basePath : basePaths) { ActionUtils.setBasePathVisibility(basePath, !isVisible); } } ((DefaultTreeModel)tree.getModel()).reload((TreeNode) selectionPath.getLastPathComponent()); } } }; } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { final int rowCount = tree.getRowCount(); final APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE); final BasePathList basePaths = preferenceStore.getBasePath(); IResourceHandler pathResource; //font change may happens with look and feel change if(!label.getFont().equals(this.labelNormalFont) && !label.getFont().equals(this.labelBoldFont)) { setupLabelFont(); } if (value instanceof IResourceHandler) { pathResource = (IResourceHandler) value; String resourceName = pathResource.getName(); label.setText(resourceName); setCheckboxCheck(pathResource, basePaths); setBasePathColorIndicator(pathResource, basePaths); this.value = value; } else if(value instanceof FileSystemNode){ pathResource = ((FileSystemNode)value).getResource(); label.setText(pathResource.getName()); setCheckboxCheck(pathResource, basePaths); setBasePathColorIndicator(pathResource, basePaths); this.value = pathResource; } else { pathResource = ResourceHandlerFactory.getResourceHandler(StringUtil.toString(value)); label.setText(StringUtil.toString(value)); checkbox.setVisible(true); setCheckboxCheck(pathResource, basePaths); setBasePathColorIndicator(pathResource, basePaths); this.value = null; } setLabelEnabled(preferenceStore, basePaths, pathResource); try { resetLabelFont(); JTree.DropLocation dropLocation = tree.getDropLocation(); if (dropLocation != null && dropLocation.getChildIndex() == -1 && tree.getRowForPath(dropLocation.getPath()) == row) { this.setBackground(SwingUtils.getSelectionBackgroundColor()); this.setForeground(SwingUtils.getSelectionForegroundColor()); label.setForeground(SwingUtils.getSelectionForegroundColor()); isDropCell = true; } else if (selected) { this.setBackground(SwingUtils.getSelectionBackgroundColor()); this.setForeground(SwingUtils.getSelectionForegroundColor()); label.setForeground(SwingUtils.getSelectionForegroundColor()); isDropCell = false; } else { TreePath filterTreePath = ((BasePathTreeModel)tree.getModel()).getFilterTreePath(); if(filterTreePath == null) { //no filter set label.setForeground(SwingUtils.getForegroundColor()); } else { TreePath rowPath = tree.getPathForRow(row); if(filterTreePath.equals(rowPath)) { label.setForeground(SwingUtils.getForegroundColor()); } else if(TreeUtil.isChild(filterTreePath, rowPath)) { label.setForeground(SwingUtils.getForegroundColor()); } else { label.setForeground(filteredForegroundColor); if(rowCount == row + 1) { //set the last tree entry bold if there is a click filter. label.setFont(labelBoldFont); } } } this.setBackground(SwingUtils.getBackgroundColor()); this.setForeground(SwingUtils.getForegroundColor()); isDropCell = false; } setLabelDimension(); } catch (Exception e) { LoggerFactory.getLogger(this).log(Level.WARNING, "Failed to render Jtree row", e); } return this; } private void resetLabelFont() { if(label.getFont() != labelNormalFont) { label.setFont(labelNormalFont); } } private void setLabelEnabled(final APreferenceStore preferenceStore, final BasePathList basePaths, IResourceHandler pathResource) { if(pathResource != null) { String pathresourceString = pathResource.toString(); label.setEnabled(true); for(String basePath : basePaths) { if(pathresourceString.startsWith(basePath)) { boolean basePathVisible = preferenceStore.isBasePathVisible(basePath); if(!basePathVisible) { label.setEnabled(false); } } } } } private void setLabelDimension() { Dimension textDimension = SwingUtils.getTextDimension(label.getText(), label.getFont()); textDimension.width += 15; label.setPreferredSize(textDimension); } private void setBasePathColorIndicator(IResourceHandler pathResourceHandler, final BasePathList basePaths) { int idx = basePaths.find(pathResourceHandler); if(idx != -1) { // found label.setUnderline(basePaths.getColor(idx)); } else { label.setUnderline(null); // no underline } } private void setCheckboxCheck(IResourceHandler pathResourceHandler, final BasePathList basePaths) { final String pathResourceString = StringUtil.toString(pathResourceHandler); removeCheckboxItemListener(); try { checkbox.setShowTriStateIcon(false); if(basePaths.contains(pathResourceString)) { if(MainMenuBarController.getController().containsHiddenBasePathEntry(pathResourceString)) { //hidden checkbox.setSelected(false); } else { //checked checkbox.setSelected(true); } checkbox.setVisible(true); } else if(pathResourceString.indexOf(File.separatorChar) != -1) { //a path but not a base path checkbox.setSelected(false); checkbox.setVisible(false); } else { //Some other item that have an eye icon. boolean allPathElementsVisible = basePaths.isAllPathElementsVisible(); boolean noPathElementsVisible = basePaths.isNoPathElementsVisible(); if(!allPathElementsVisible && !noPathElementsVisible) { checkbox.setShowTriStateIcon(true); checkbox.setSelected(false); } else if(allPathElementsVisible) { checkbox.setSelected(true); } else { checkbox.setSelected(false); } checkbox.setVisible(true); } } finally { addCheckboxItemListener(); } } public Object getValue() { return value; } public boolean isDropCell() { return isDropCell; } private void setupLabelFont() { this.labelNormalFont = label.getFont(); this.labelBoldFont = new Font(this.labelNormalFont.getName(), Font.BOLD, this.labelNormalFont.getSize()); } private void removeCheckboxItemListener() { allCheckboxItemListeners = checkbox.getItemListeners(); for (ItemListener itemListener : allCheckboxItemListeners) { checkbox.removeItemListener(itemListener); } } private void addCheckboxItemListener() { if(allCheckboxItemListeners != null) { for (ItemListener itemListener : allCheckboxItemListeners) { checkbox.addItemListener(itemListener); } } } }