jmemorize.gui.swing.panels.CardPanel.java Source code

Java tutorial

Introduction

Here is the source code for jmemorize.gui.swing.panels.CardPanel.java

Source

/*
 * jMemorize - Learning made easy (and fun) - A Leitner flashcards tool
 * Copyright(C) 2004-2008 Riad Djemili and contributors
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package jmemorize.gui.swing.panels;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.StyledEditorKit.StyledTextAction;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.Sizes;

import jmemorize.core.FileRepository.FileItem;
import jmemorize.core.Settings;
import jmemorize.gui.LC;
import jmemorize.gui.Localization;
import jmemorize.gui.swing.ColorConstants;
import jmemorize.gui.swing.GeneralTransferHandler;
import jmemorize.gui.swing.actions.file.AbstractImportAction;
import jmemorize.gui.swing.panels.CardSidePanel.CardImageObserver;
import jmemorize.gui.swing.widgets.CategoryComboBox;
import jmemorize.tools.pearson.PearsonHelper;

/**
 * A panel that displays the front and flip side of a card.
 * 
 * @author djemili
 */
public class CardPanel extends JPanel {
    /**
     * A interface that allows to listen for textchanges to the card side text
     * panes. Use {@link CardPanel#addTextObserver} method to hook it to the
     * CardPanel.
     */
    public interface CardPanelObserver {
        public void onTextChanged();

        public void onImageChanged();
    }

    private class PearsonAction extends StyledTextAction {
        public PearsonAction() {
            super("prs");
        }

        public void actionPerformed(java.awt.event.ActionEvent e) {
            // TODO we suppose that m_cardSides has 2 elements and index 0 is
            // for front and index 1 for backside
            if (m_cardSides.size() != 2)
                return;

            CardSidePanel cardSidePanel1 = m_cardSides.get(0);// front side
            CardSidePanel cardSidePanel2 = m_cardSides.get(1);// front side
            if (cardSidePanel1.getText().getUnformatted().trim().isEmpty()
                    || cardSidePanel1.getText().getUnformatted().trim().split(" ").length == 0)
                return;
            String z = cardSidePanel1.getText().getUnformatted().trim().split(" ")[0];
            if (z.trim().isEmpty())
                return;

            String text = z;
            String s;
            try {
                s = new PearsonHelper().getWordData(text);
            } catch (SocketTimeoutException e3) {
                JOptionPane.showMessageDialog(null, "Time Out. Try Again.", "Error", JOptionPane.ERROR_MESSAGE);
                return;
            } catch (IOException e2) {

                e2.printStackTrace();
                return;
            }
            if (s.length() > 0) {
                if (cardSidePanel2.getText().getUnformatted().isEmpty()) {
                    cardSidePanel2.getTextPane().setText(s);
                } else {
                    InputStream stream = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
                    try {
                        cardSidePanel2.addCardFile(new FileItem(stream, text + ".txt"));
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
                cardSidePanel2.getTextPane().requestFocus();
            }

        }
    }

    private class DownloadPronAction extends StyledTextAction {
        public DownloadPronAction() {
            super("prn");
        }

        public void actionPerformed(java.awt.event.ActionEvent e) {
            // TODO we suppose that m_cardSides has 2 elements and index 0 is
            // for front and index 1 for backside
            if (m_cardSides.size() != 2)
                return;

            CardSidePanel cardSidePanel1 = m_cardSides.get(0);// front side
            CardSidePanel cardSidePanel2 = m_cardSides.get(1);// front side
            if (cardSidePanel1.getText().getUnformatted().trim().isEmpty()
                    || cardSidePanel1.getText().getUnformatted().trim().split(" ").length == 0)
                return;
            String z = cardSidePanel1.getText().getUnformatted().trim().split(" ")[0];
            if (z.trim().isEmpty())
                return;
            String text = z + ".mp3";
            String url = "https://ssl.gstatic.com/dictionary/static/sounds/de/0/" + text;
            URL u = null;
            try {
                u = new URL(url);
            } catch (MalformedURLException e1) {
                e1.printStackTrace();
                return;
            }
            HttpURLConnection rsp;
            try {
                rsp = (HttpURLConnection) u.openConnection();
                rsp.setReadTimeout(15000);
                rsp.setConnectTimeout(15000);
                if (rsp.getResponseCode() != 200)
                    return;

                cardSidePanel1.addCardFile(new FileItem(rsp.getInputStream(), text));
                cardSidePanel1.getTextPane().requestFocus();
            } catch (IOException e1) {
                e1.printStackTrace();
                return;
            }
        }
    }

    private class InsertImageAction extends StyledTextAction {
        public InsertImageAction() {
            super("img");
        }

        public void actionPerformed(java.awt.event.ActionEvent e) {
            JEditorPane editor = getEditor(e);
            if (editor != null && editor instanceof JTextPane) {
                for (CardSidePanel cardSidePanel : m_cardSides) {
                    if (cardSidePanel.getTextPane() != editor)
                        continue;

                    JFileChooser chooser = new JFileChooser();
                    chooser.setCurrentDirectory(Settings.loadLastDirectory());
                    File file = AbstractImportAction.showOpenDialog(null, null);

                    if (file == null)
                        return;

                    // ImageIcon icon = new ImageIcon(file.toString());
                    // icon.setDescription(file.toString());

                    try {
                        cardSidePanel.addCardFile(new FileItem(file.toString(), file));
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                    editor.requestFocus();
                }
            }
        }
    }

    private class RemoveImageAction extends StyledTextAction {
        public RemoveImageAction() {
            super("img-remove");
        }

        public void actionPerformed(ActionEvent e) {
            JEditorPane editor = getEditor(e);
            if (editor != null && editor instanceof JTextPane) {
                for (CardSidePanel cardSidePanel : m_cardSides) {
                    if (cardSidePanel.getTextPane() != editor)
                        continue;

                    cardSidePanel.removeImage();
                    editor.requestFocus();
                }
            }
        }
    }

    private abstract class AbstractStyledTextAction extends StyledTextAction {
        private AbstractButton m_button;
        private List<KeyStroke> m_shortcuts = new ArrayList<KeyStroke>();
        private CaretListener m_caretListener;

        public AbstractStyledTextAction(String nm) {
            super(nm);

            m_textActions.add(this);

            m_caretListener = new CaretListener() {
                public void caretUpdate(CaretEvent e) {
                    if (!(e.getSource() instanceof JTextPane))
                        return;

                    JTextPane editor = (JTextPane) e.getSource();
                    updateButton(editor);
                }
            };
        }

        public void addShortcut(KeyStroke shortcut) {
            m_shortcuts.add(shortcut);
        }

        public void actionPerformed(ActionEvent e) {
            JEditorPane editor = getEditor(e);
            if (editor != null) {
                editor.requestFocus();

                StyledEditorKit kit = getStyledEditorKit(editor);
                MutableAttributeSet attr = kit.getInputAttributes();

                SimpleAttributeSet sas = new SimpleAttributeSet();
                setStyle(sas, !hasStyle(attr));

                setCharacterAttributes(editor, sas, false);
                notifyTextObservers();

                updateButton(editor);
            }
        }

        public void setButton(AbstractButton button) {
            m_button = button;
        }

        public void attachTextPane(CardSidePanel cardSide) {
            String name = (String) getValue(Action.NAME);
            JTextPane textPane = cardSide.getTextPane();

            for (KeyStroke shortcut : m_shortcuts) {
                textPane.getInputMap().put(shortcut, name);
            }

            textPane.getActionMap().put(name, this);

            cardSide.addCaretListener(m_caretListener);
        }

        /**
         * @return <code>true</code> if the style associated with this text
         *         action is enabled. <code>false</code> otherwise.
         */
        public abstract boolean hasStyle(AttributeSet attr);

        /**
         * Enables/disables the style associated with this text action in the
         * given attributes.
         */
        public abstract void setStyle(MutableAttributeSet attr, boolean enabled);

        private void updateButton(JEditorPane editor) {
            StyledEditorKit kit = (StyledEditorKit) editor.getEditorKit();
            MutableAttributeSet attr = kit.getInputAttributes();

            m_button.setSelected(hasStyle(attr));
        }
    }

    private class BoldAction extends AbstractStyledTextAction {
        public BoldAction() {
            super("font-bold");
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_B, CTRL_MASK));
        }

        public boolean hasStyle(AttributeSet attr) {
            return StyleConstants.isBold(attr);
        }

        public void setStyle(MutableAttributeSet attr, boolean enabled) {
            StyleConstants.setBold(attr, enabled);
        }
    }

    private class ItalicAction extends AbstractStyledTextAction {
        public ItalicAction() {
            super("font-italic");
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_I, CTRL_MASK));
        }

        public boolean hasStyle(AttributeSet attr) {
            return StyleConstants.isItalic(attr);
        }

        public void setStyle(MutableAttributeSet attr, boolean enabled) {
            StyleConstants.setItalic(attr, enabled);
        }
    }

    private class UnderlineAction extends AbstractStyledTextAction {
        public UnderlineAction() {
            super("font-underline");
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_U, CTRL_MASK));
        }

        public boolean hasStyle(AttributeSet attr) {
            return StyleConstants.isUnderline(attr);
        }

        public void setStyle(MutableAttributeSet attr, boolean enabled) {
            StyleConstants.setUnderline(attr, enabled);
        }
    }

    private class SupAction extends AbstractStyledTextAction {
        public SupAction() {
            super("sup");
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, CTRL_MASK | InputEvent.SHIFT_DOWN_MASK));
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, CTRL_MASK | InputEvent.SHIFT_DOWN_MASK));
        }

        public boolean hasStyle(AttributeSet attr) {
            return StyleConstants.isSuperscript(attr);
        }

        public void setStyle(MutableAttributeSet attr, boolean enabled) {
            StyleConstants.setSuperscript(attr, enabled);
            StyleConstants.setSubscript(attr, false);
        }
    }

    private class SubAction extends AbstractStyledTextAction {
        public SubAction() {
            super("sub");
            addShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, CTRL_MASK));
        }

        public boolean hasStyle(AttributeSet attr) {
            return StyleConstants.isSubscript(attr);
        }

        public void setStyle(MutableAttributeSet attr, boolean enabled) {
            StyleConstants.setSubscript(attr, enabled);
            StyleConstants.setSuperscript(attr, false);
        }
    }

    private class ShowCardSideButton extends JButton implements ActionListener {
        private String m_text;
        private int[] m_sides;

        public ShowCardSideButton(String text, int... sides) {
            m_text = text;
            m_sides = sides;
            m_showSideButtons.add(this);

            setBackground(ColorConstants.CARD_SIDE_BAR_COLOR);
            addActionListener(this);

            // Character character = new
            // Character(Integer.toString(index).charAt(0));
            // String actionName = "show-card-side-action-"+index;
            // getInputMap().put(KeyStroke.getKeyStroke(character,
            // InputEvent.CTRL_MASK), actionName);
            // getActionMap().put(actionName, this);
        }

        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < m_cardSidesPanel.getComponentCount(); i++)
                setCardSideVisible(i, hasSide(i));

            updateCardSideButtons();
        }

        public boolean hasSide(int index) {
            for (int i = 0; i < m_sides.length; i++) {
                if (m_sides[i] == index)
                    return true;
            }

            return false;
        }

        private void updateText() {
            boolean highlight = true;
            for (int i = 0; i < m_cardSidesPanel.getComponentCount(); i++)
                highlight &= hasSide(i) == isCardSideVisible(i);

            String name = highlight ? "[" + m_text + "]" : m_text;
            setText("  " + name + "  ");

            // setFont(getFont().deriveFont(highlight ? Font.ITALIC :
            // Font.PLAIN));
            //// setBackground(highlight ? new Color(255, 180, 0) :
            // ColorConstants.CARD_SIDE_BAR_COLOR);
        }
    }

    private static final int CTRL_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

    protected boolean m_flippedCardSides = false;
    private boolean m_verticalLayout = true;

    private CategoryComboBox m_categoryBox = new CategoryComboBox();

    private List<CardPanelObserver> m_observers = new LinkedList<CardPanelObserver>();
    private List<CardSidePanel> m_cardSides = new LinkedList<CardSidePanel>();
    private List<AbstractStyledTextAction> m_textActions = new LinkedList<AbstractStyledTextAction>();
    private List<ShowCardSideButton> m_showSideButtons = new LinkedList<ShowCardSideButton>();

    private JPanel m_cardSidesPanel;
    private JPopupMenu m_popupMenu;
    private MouseAdapter m_menuAdapter;

    private CardImageObserver m_imageObserver;

    /**
     * Creates new form EditCardPanel
     */
    public CardPanel(boolean allowEdits) {
        initComponent(allowEdits);
        updateCardSideButtons();

        m_popupMenu = buildPopupMenu(allowEdits);

        m_menuAdapter = new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) {
                    JTextPane textPane = (JTextPane) e.getSource();
                    textPane.requestFocus();

                    m_popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        };

        m_imageObserver = new CardImageObserver() {
            public void onImageChanged() {
                notifyImageObservers();
            }
        };
    }

    public void addCardSide(String title, JComponent component) {
        JPanel cardSideWithTitle = wrapCardSide(title, component);

        if (component instanceof CardSidePanel) {
            CardSidePanel cardSide = (CardSidePanel) component;

            m_cardSides.add(cardSide);

            for (AbstractStyledTextAction textAction : m_textActions) {
                textAction.attachTextPane(cardSide);
            }

            cardSide.getTextPane().addMouseListener(m_menuAdapter);
            GeneralTransferHandler handler = new GeneralTransferHandler(cardSide);
            cardSide.getTextPane().setTransferHandler(handler);

            cardSide.addImageListener(m_imageObserver);
        }

        m_cardSidesPanel.add(cardSideWithTitle);

        updateCardSideButtons();
        updateCardSideBorders();
    }

    public void removeCardSide(int index) {
        m_cardSidesPanel.getComponent(index);

        m_cardSidesPanel.remove(index);

        // TODO
    }

    public void setCardSideVisible(int index, boolean visible) {
        m_cardSidesPanel.getComponent(index).setVisible(visible);

        updateCardSideBorders();
        updateCardSideButtons();
    }

    public void setCardSideEnabled(int index, boolean enabled) {
        for (ShowCardSideButton button : m_showSideButtons) {
            if (button.hasSide(index))
                button.setEnabled(enabled);
        }

        // m_showSideButtons.get(index).setEnabled(enabled);
    }

    public boolean isCardSideVisible(int index) {
        if (index >= m_cardSidesPanel.getComponentCount())
            return false;

        return m_cardSidesPanel.getComponent(index).isVisible();
    }

    /**
     * @param editable
     *            <code>true</code> if front/back side textpanes should be
     *            editable. <code>false</code> otherwise.
     */
    public void setEditable(boolean editable) {
        for (CardSidePanel cardSide : m_cardSides) {
            cardSide.setEditable(editable);
        }
    }

    public List<CardSidePanel> getCardSides() {
        return Collections.unmodifiableList(m_cardSides);
    }

    public CategoryComboBox getCategoryComboBox() {
        return m_categoryBox;
    }

    /**
     * Adds a text observer that will be triggered when the text of the
     * frontside textpane or backside textpane is changed by the users key
     * input.
     * 
     * @param observer
     *            The text observer that is to be added as observer.
     */
    public void addObserver(CardPanelObserver observer) {
        m_observers.add(observer);
    }

    /**
     * Notify all observers that the text of the frontside textpane or backside
     * textpane has been changed by the users keyinput.
     */
    protected void notifyTextObservers() {
        for (CardPanelObserver observer : m_observers) {
            observer.onTextChanged();
        }
    }

    private void notifyImageObservers() {
        for (CardPanelObserver observer : m_observers) {
            observer.onImageChanged();
        }
    }

    private void updateCardSideButtons() {
        for (ShowCardSideButton action : m_showSideButtons)
            action.updateText();
    }

    private void updateCardSideBorders() {
        int margin = Sizes.dialogUnitYAsPixel(3, this);

        int mx = 0;
        int my = 0;

        if (m_verticalLayout)
            my = margin;
        else
            mx = margin;

        boolean addBorder = false;
        for (int i = 0; i < m_cardSidesPanel.getComponentCount(); i++) {
            Component comp = m_cardSidesPanel.getComponent(i);

            if (!(comp instanceof JPanel))
                continue;

            JPanel sidePanel = (JPanel) comp;

            if (addBorder)
                sidePanel.setBorder(new EmptyBorder(my, mx, 0, 0));
            else
                sidePanel.setBorder(null);

            if (sidePanel.isVisible())
                addBorder = true;
        }

        // if (m_cardSides.size() > 0)
        // {
        // int px = Sizes.dialogUnitYAsPixel(3, this);
        // cardSideWithTitle.setBorder(new EmptyBorder(px, 0, 0, 0));
        // }
    }

    private JPanel wrapCardSide(String title, JComponent cardSide) {
        FormLayout layout = new FormLayout(
                // "38dlu, 3dlu, d:grow", // columns //$NON-NLS-1$
                "d:grow", // columns //$NON-NLS-1$
                "fill:20dlu:grow"); // rows //$NON-NLS-1$

        CellConstraints cc = new CellConstraints();
        DefaultFormBuilder builder = new DefaultFormBuilder(layout);

        // builder.addLabel(title, cc.xy(1, 1, "left, top")); //$NON-NLS-1$
        // builder.add(cardSide, cc.xy(3, 1 ));
        builder.add(cardSide, cc.xy(1, 1));

        return builder.getPanel();
    }

    private void initComponent(boolean allowEdits) {
        setLayout(new BorderLayout());

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));

        if (allowEdits)
            topPanel.add(buildCategoryPanel());

        topPanel.add(buildInnerPanel(buildSetSidesToolbar()));

        if (allowEdits)
            topPanel.add(buildInnerPanel(buildEditToolbar()));

        add(topPanel, BorderLayout.NORTH);

        m_cardSidesPanel = new JPanel();
        m_cardSidesPanel.setLayout(new BoxLayout(m_cardSidesPanel, BoxLayout.Y_AXIS));
        add(m_cardSidesPanel, BorderLayout.CENTER);
    }

    private JToolBar buildSetSidesToolbar() {
        JToolBar toolBar = new JToolBar();

        toolBar.add(new ShowCardSideButton("Frontside/Flipside", 0, 1));
        toolBar.add(new ShowCardSideButton("Frontside", 0));
        toolBar.add(new ShowCardSideButton("Flipside", 1));

        toolBar.setBorder(new EtchedBorder());
        toolBar.setBackground(ColorConstants.CARD_SIDE_BAR_COLOR);

        toolBar.setFloatable(false);
        return toolBar;
    }

    private JToolBar buildEditToolbar() {
        JToolBar toolBar = new JToolBar();

        toolBar.add(createButton(new DefaultEditorKit.CopyAction(), "edit_copy.gif"));
        toolBar.add(createButton(new DefaultEditorKit.CutAction(), "edit_cut.gif"));
        toolBar.add(createButton(new DefaultEditorKit.PasteAction(), "edit_paste.gif"));
        toolBar.addSeparator();

        toolBar.add(createButton(new BoldAction(), "text_bold.png"));
        toolBar.add(createButton(new ItalicAction(), "text_italic.png"));
        toolBar.add(createButton(new UnderlineAction(), "text_underline.png"));
        toolBar.add(createButton(new SupAction(), "text_superscript.png"));
        toolBar.add(createButton(new SubAction(), "text_subscript.png"));

        toolBar.addSeparator();
        toolBar.add(createButton(new InsertImageAction(), "picture_add.png"));
        toolBar.add(createButton(new RemoveImageAction(), "picture_delete.png"));
        toolBar.addSeparator();
        toolBar.add(createButton(new DownloadPronAction(), "spkr.png"));
        toolBar.add(createButton(new PearsonAction(), "pearson.png"));
        toolBar.setFloatable(false);
        return toolBar;
    }

    private JPopupMenu buildPopupMenu(boolean editable) {
        JPopupMenu menu = new JPopupMenu();
        menu.add(createMenuItem(new DefaultEditorKit.CopyAction(), Localization.get(LC.COPY), "edit_copy.gif"));

        if (editable) {
            menu.add(createMenuItem(new DefaultEditorKit.CutAction(), Localization.get(LC.CUT), "edit_cut.gif"));

            menu.add(createMenuItem(new DefaultEditorKit.PasteAction(), Localization.get(LC.PASTE),
                    "edit_paste.gif"));

            menu.addSeparator();

            // TODO add localization
            menu.add(createMenuItem(new BoldAction(), "Bold", "text_bold.png"));
            menu.add(createMenuItem(new ItalicAction(), "Italic", "text_italic.png"));
            menu.add(createMenuItem(new UnderlineAction(), "Underline", "text_underline.png"));
            menu.add(createMenuItem(new SupAction(), "Superscript", "text_superscript.png"));
            menu.add(createMenuItem(new SubAction(), "Subscript", "text_subscript.png"));
        }

        return menu;
    }

    private JButton createButton(AbstractStyledTextAction action, String icon) {
        JButton button = new JButton(action);
        action.setButton(button);

        button.setText("");
        button.setIcon(new ImageIcon(getClass().getResource("/resource/icons/" + icon)));
        return button;
    }

    private JMenuItem createMenuItem(Action action, String text, String icon) {
        JMenuItem item = new JMenuItem(action);

        if (action instanceof AbstractStyledTextAction)
            ((AbstractStyledTextAction) action).setButton(item);

        item.setIcon(new ImageIcon(getClass().getResource("/resource/icons/" + icon)));
        item.setText(text);
        return item;
    }

    private JPanel buildCategoryPanel() {
        CellConstraints cc = new CellConstraints();

        DefaultFormBuilder builder;

        FormLayout layout = new FormLayout(
                // "38dlu, 3dlu, d:grow", // columns //$NON-NLS-1$
                "d:grow", // columns //$NON-NLS-1$
                "p, 3dlu"); // rows //$NON-NLS-1$

        builder = new DefaultFormBuilder(layout);
        // builder.addLabel(Localization.get(LC.CATEGORY), cc.xy ( 1, 1));
        // builder.add(m_categoryBox, cc.xy(3, 1));
        builder.add(m_categoryBox, cc.xy(1, 1));

        return builder.getPanel();
    }

    private JPanel buildInnerPanel(Component comp) {
        CellConstraints cc = new CellConstraints();

        DefaultFormBuilder builder;
        FormLayout layout = new FormLayout(
                // "38dlu, 3dlu, d:grow", // columns //$NON-NLS-1$
                "d:grow", // columns //$NON-NLS-1$
                "p, 3dlu"); // rows //$NON-NLS-1$

        builder = new DefaultFormBuilder(layout);
        // builder.add(comp, cc.xy (3, 1));
        builder.add(comp, cc.xy(1, 1));

        return builder.getPanel();
    }

    private JButton createButton(Action action, String icon) {
        JButton button = new JButton(action);
        button.setText("");
        button.setIcon(new ImageIcon(getClass().getResource("/resource/icons/" + icon)));
        return button;
    }
}