PanelNode.java

/*******************************************************************************
 * Copyhacked (H) 2012-2025.
 * This program and the accompanying materials
 * are made available under no term at all, use it like
 * you want, but share and discuss 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.I18nUtil;
import com.jsql.view.swing.tree.model.AbstractNodeModel;
import com.jsql.view.swing.util.UiStringUtil;
import com.jsql.view.swing.util.UiUtil;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.nio.charset.StandardCharsets;
import java.util.stream.Stream;

/**
 * A tree Node composed of an icon, a GIF loader, a progress bar, a label.
 */
public class PanelNode extends JPanel {
    
    /**
     * Default icon of the node (database or table).
     */
    private final JLabel iconNode = new JLabel();

    /**
     * A GIF loader, displayed if progress track is unknown (like columns).
     */
    private final JLabel loaderWait = new JLabel();

    /**
     * Progress bar displayed during injection, with pause icon displayed if user paused the process.
     */
    private final ProgressBarPausable progressBar = new ProgressBarPausable();

    /**
     * Text of the node.
     */
    private final JLabel nodeLabel = new JLabel();
    private final JTextField textFieldEditable = new JTextField(15);
    
    /**
     * Create Panel for tree nodes.
     * @param tree JTree to populate
     * @param currentNode Node to draw in the tree
     */
    public PanelNode(final JTree tree, final DefaultMutableTreeNode currentNode) {
        this.loaderWait.setIcon(UiUtil.HOURGLASS.getIcon());
        this.loaderWait.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));

        this.progressBar.setPreferredSize(new Dimension(20, 20));
        this.progressBar.setBorder(BorderFactory.createEmptyBorder(4, 3, 4, 3));

        this.nodeLabel.setOpaque(true);

        this.iconNode.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        
        this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        
        Stream.of(
            this.iconNode,
            this.loaderWait,
            this.progressBar,
            this.nodeLabel,
            this.textFieldEditable
        )
        .forEach(component -> {
            this.add(component);
            component.setVisible(false);
        });
        
        this.setComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
        
        this.initTextFieldEditable(tree, currentNode);
    }

    private void initTextFieldEditable(final JTree tree, final DefaultMutableTreeNode currentNode) {
        this.textFieldEditable.addActionListener(e -> {
            AbstractNodeModel nodeModel = (AbstractNodeModel) currentNode.getUserObject();
            nodeModel.setIsEdited(false);
            
            this.nodeLabel.setVisible(true);
            this.textFieldEditable.setVisible(false);
            tree.requestFocusInWindow();

            nodeModel.getElementDatabase().setElementValue(new String(
                this.textFieldEditable.getText().getBytes(StandardCharsets.UTF_8),
                StandardCharsets.UTF_8
            ));
            this.nodeLabel.setText(UiStringUtil.detectUtf8Html(nodeModel.getElementDatabase().getLabelWithCount()));
            
            tree.revalidate();
            tree.repaint();
        });
        
        this.textFieldEditable.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                AbstractNodeModel nodeModel = (AbstractNodeModel) currentNode.getUserObject();
                nodeModel.setIsEdited(false);
                tree.revalidate();
                tree.repaint();
            }
        });
        
        KeyAdapter keyAdapterF2 = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                AbstractNodeModel nodeModel = (AbstractNodeModel) currentNode.getUserObject();
                
                if (e.getKeyCode() == KeyEvent.VK_F2 && !nodeModel.isRunning()) {
                    nodeModel.setIsEdited(true);
                    
                    PanelNode.this.nodeLabel.setVisible(false);
                    PanelNode.this.textFieldEditable.setVisible(true);
                    PanelNode.this.textFieldEditable.requestFocusInWindow();
                    
                    tree.revalidate();
                    tree.repaint();
                }
            }
        };
        
        this.addKeyListener(keyAdapterF2);
        this.textFieldEditable.addKeyListener(keyAdapterF2);
    }

    /**
     * Change the text icon.
     * @param newIcon An icon to display next to the text.
     */
    public void setIconNode(Icon newIcon) {
        this.iconNode.setIcon(newIcon);
    }
    
    /**
     * Display text icon to the left.
     */
    public void showIcon() {
        this.iconNode.setVisible(true);
    }
    
    /**
     * Mask the node icon for example when the loader component is displayed.
     */
    public void hideIcon() {
        this.iconNode.setVisible(false);
    }
    
    /**
     * Change the loader icon.
     * @param newIcon An icon to display for the loader.
     */
    public void setLoaderIcon(Icon newIcon) {
        this.loaderWait.setIcon(newIcon);
    }

    /**
     * Display the animated gif loader.
     */
    public void showLoader() {
        this.loaderWait.setVisible(true);
    }
    
    
    // Getter and setter

    public ProgressBarPausable getProgressBar() {
        return this.progressBar;
    }

    public JLabel getNodeLabel() {
        return this.nodeLabel;
    }

    public JTextField getTextFieldEditable() {
        return this.textFieldEditable;
    }
}