All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codemagi.burp.ui.BurpTabComponent Maven / Gradle / Ivy

Go to download

The Burp Suite Utils project provides developers with APIs for building Burp Suite Extensions.

The newest version!
package com.codemagi.burp.ui;

import com.codemagi.burp.BaseExtender;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.*;
import javax.swing.plaf.LayerUI;
import javax.swing.plaf.basic.BasicButtonUI;

/**
 * Component to be used as tabComponent: Renders instead of a default tab name.
 *
 * Contains a JLabel to show the (editable) tab name and a JButton to close the tab. 
 * 
 * @author August Detlefsen [augustd at codemagi dot com]
 */
public class BurpTabComponent extends JPanel {

    private final JTabbedPane pane; //the pane of tabs that will contain this one
    private final JTextField editor = new JTextField();
    private static final Color TRANSPARENT = new Color(255, 255, 255, 0);

    public BurpTabComponent(String title, final JTabbedPane pane) {
        //unset default FlowLayout' gaps
        super(new FlowLayout(FlowLayout.LEFT, 0, 0));
        if (pane == null) {
            throw new NullPointerException("TabbedPane is null");
        }
        this.pane = pane;

        //create an editor component
        editor.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 7));
        editor.setText(title);
        editor.setBackground(TRANSPARENT);
        editor.setOpaque(false);
        editor.setEditable(false);
        BaseExtender.getCallbacks().customizeUiComponent(editor);
        add(new JLayer(editor, new DispatchEventLayerUI()));

        //Make editor not editable until double-click
        editor.setEditable(false);
        editor.setEnabled(false);
        editor.setDisabledTextColor(Color.BLACK);
        editor.addMouseListener(MOUSE_CLICK_LISTENER);
        editor.addFocusListener(FOCUS_LOST_LISTENER);

        //Add the close button
        JButton button = new TabButton();
        add(button);

        //add more space to the top of the component
        setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
        setBackground(TRANSPARENT);
        setOpaque(false);
    }

    private class TabButton extends JButton implements ActionListener {

        public TabButton() {
            int size = 9;
            setPreferredSize(new Dimension(size, size));
            setToolTipText("close this tab");
            //Make the button looks the same for all Laf's
            setUI(new BasicButtonUI());
            //Make it transparent
            setContentAreaFilled(false);
            //No need to be focusable
            setFocusable(false);
            setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            setBorderPainted(false);
            this.setMargin(new Insets(11, 6, 0, 0));

            //Making nice rollover effect
            //we use the same listener for all buttons
            addMouseListener(BUTTON_MOUSE_LISTENER);
            setRolloverEnabled(true);
            //Close the proper tab by clicking the button
            addActionListener(this);
            BaseExtender.getCallbacks().customizeUiComponent(this);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int i = pane.indexOfTabComponent(BurpTabComponent.this);
            if (i != -1) {
                pane.remove(i);
            }
        }

        //we don't want to update UI for this button
        @Override
        public void updateUI() {
        }

        //paint the cross
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g.create();
            //shift the image for pressed buttons
            if (getModel().isPressed()) {
                g2.translate(1, 1);
            }
            g2.setStroke(new BasicStroke(1));
            g2.setColor(Color.GRAY);
            if (getModel().isRollover()) {
                g2.setColor(Color.BLACK);
            }
            int delta = 6;
            g2.drawLine(2, 3, 6, 7);
            g2.drawLine(2, 7, 6, 3);
            g2.dispose();
        }
    }

    /**
     * Create rollover effect for X button
     */
    private final static MouseListener BUTTON_MOUSE_LISTENER = new MouseAdapter() {
        @Override
        public void mouseEntered(MouseEvent e) {
            Component component = e.getComponent();
            if (component instanceof AbstractButton) {
                AbstractButton button = (AbstractButton) component;
                button.setBorderPainted(true);
            }
        }

        @Override
        public void mouseExited(MouseEvent e) {
            Component component = e.getComponent();
            if (component instanceof AbstractButton) {
                AbstractButton button = (AbstractButton) component;
                button.setBorderPainted(false);
            }
        }
    };

    private final MouseListener MOUSE_CLICK_LISTENER = new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            System.out.println("MOUSE_CLICK_LISTENER.mouseClicked()");

            Component component = e.getComponent();
            component.requestFocusInWindow();

            //no matter how many clicks, always select the tab
            System.out.println("single-click");
            System.out.println("index: " + pane.indexOfTabComponent(BurpTabComponent.this));
            pane.setSelectedIndex(pane.indexOfTabComponent(BurpTabComponent.this));
            
            if (e.getClickCount() == 2) {
                System.out.println("double-click");
                JTextField field = (JTextField) component;
                field.setEditable(true);
                field.setEnabled(true);
            }
        }
    };

    /**
     * Make label field un-editable when it loses focus
     */
    private static final FocusListener FOCUS_LOST_LISTENER = new FocusAdapter() {
        @Override
        public void focusLost(FocusEvent e) {
            Component component = e.getComponent();
            System.out.println("User exited");
            JTextField field = (JTextField) component;
            field.setEditable(false);
            field.setEnabled(false);
        }
    };

    class DispatchEventLayerUI extends LayerUI {

        @Override
        public void installUI(JComponent c) {
            super.installUI(c);
            if (c instanceof JLayer) {
                ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
            }
        }

        @Override
        public void uninstallUI(JComponent c) {
            if (c instanceof JLayer) {
                ((JLayer) c).setLayerEventMask(0);
            }
            super.uninstallUI(c);
        }

        /**
         * Pass mouse motion events (in/out) to the underlying tabbed pane to
         * handle highlighting of the tab.
         *
         * @param e
         * @param l
         */
        @Override
        protected void processMouseMotionEvent(MouseEvent e, JLayer l) {
            Component src = e.getComponent();
            Container tgt = SwingUtilities.getAncestorOfClass(JTabbedPane.class, src);
            tgt.dispatchEvent(SwingUtilities.convertMouseEvent(src, e, tgt));
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy