CellEditorNode.java

/*******************************************************************************
 * Copyhacked (H) 2012-2020.
 * This program and the accompanying materials
 * are made available under no term at all, use it like
 * you want, but share and discuss about it
 * every time possible with every body.
 * 
 * Contributors:
 *      ron190 at ymail dot com - initial implementation
 ******************************************************************************/
package com.jsql.view.swing.tree;

import com.jsql.util.LogLevelUtil;
import com.jsql.view.swing.tree.model.AbstractNodeModel;
import com.jsql.view.swing.util.MediatorHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * Tree cell editor responsible for mouse action on nodes.
 */
public class CellEditorNode extends AbstractCellEditor implements TreeCellEditor, TreeSelectionListener, MouseListener {
    
    /**
     * Log4j logger sent to view.
     */
    private static final Logger LOGGER = LogManager.getRootLogger();

    /**
     * Renderer for nodes included JPanel, button, checkbox, icons...
     */
    private final CellRendererNode defaultTreeRenderer;

    /**
     * Value contained in the editor.
     * Returned by getCellEditorValue().
     */
    private transient AbstractNodeModel nodeModel;

    /**
     * Build editor, add tree and mouse listener.
     */
    public CellEditorNode() {
        
        this.defaultTreeRenderer = new CellRendererNode();
        MediatorHelper.treeDatabase().addTreeSelectionListener(this);
        MediatorHelper.treeDatabase().addMouseListener(this);
    }

    @Override
    public Component getTreeCellEditorComponent(
        JTree tree, 
        Object nodeRenderer, 
        boolean selected, 
        boolean expanded, 
        boolean leaf, 
        int row
    ) {

        var componentRenderer = this.defaultTreeRenderer.getTreeCellRendererComponent(
            tree, nodeRenderer, true, expanded, leaf, row, true
        );

        final DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) nodeRenderer;
        var currentNodeModel = currentNode.getUserObject();
        
        try {
            this.nodeModel = (AbstractNodeModel) currentNodeModel;
            
            if (componentRenderer instanceof JCheckBox) {
                ((JCheckBox) componentRenderer).addActionListener(
                    new ActionCheckUncheck(this.nodeModel, currentNode)
                );
            }
        } catch (Exception e) {
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
        }

        return componentRenderer;
    }

    @Override
    public Object getCellEditorValue() {
        return this.nodeModel;
    }
    
    @Override
    public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
        
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) MediatorHelper.treeDatabase().getLastSelectedPathComponent();

        // Get rid of java.lang.NullPointerException
        if (node == null) {
            return;
        }

        if (node.getUserObject() instanceof AbstractNodeModel) {
            
            AbstractNodeModel dataModel = (AbstractNodeModel) node.getUserObject();
            if (!dataModel.isLoaded()) {
                dataModel.runAction();
            }
        }
    }

    /**
     * Fix compatibility issue with right click on Linux.
     * @param mouseEvent Mouse event
     */
    private void showPopup(MouseEvent mouseEvent) {
        
        if (!mouseEvent.isPopupTrigger()) {
            return;
        }
        
        JTree tree = (JTree) mouseEvent.getSource();
        TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
        
        if (path == null) {
            return;
        }

        DefaultMutableTreeNode currentTableNode = (DefaultMutableTreeNode) path.getLastPathComponent();

        if (currentTableNode.getUserObject() instanceof AbstractNodeModel) {
            
            AbstractNodeModel currentTableModel = (AbstractNodeModel) currentTableNode.getUserObject();
            
            if (currentTableModel.isPopupDisplayable()) {
                currentTableModel.showPopup(currentTableNode, path, mouseEvent);
            }
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        this.showPopup(e);
    }
    
    @Override
    public void mouseReleased(MouseEvent e) {
        this.showPopup(e);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // Do nothing
    }
    
    @Override
    public void mouseEntered(MouseEvent e) {
        // Do nothing
    }
    
    @Override
    public void mouseExited(MouseEvent e) {
        // Do nothing
    }
}