3
\$\begingroup\$

SCENARIO:

As a follow-up of this question on Stackoverflow asked few days back, I am working on a swing application(article tagging tool) where the user(on an initial jpanel) would fill up some mandatory fields and then proceed to different sections(front, body and back matter of the article) where the application would need to process a lot of RTF files and create corresponding XML files.

The application(using GridBagLayout as the layout manager and the mediator as the design pattern) has the LaunchApplication class having the static SwingUtilities.invokeLater method which invokes the createAndShowGUI method and the application just starts off.

QUESTIONS:

  1. Am I implementing the mediator pattern correctly?
  2. I want to create add/remove pannels for each button click and switch between them. What would be the recommended way to do it?

Any help, suggestions, criticisms are appreciated. The output UI and relevant code are posted below.

enter image description here

Mediator interface:

package com.lspl.www.jbac.core;

import com.lspl.www.jbac.ui.BackMatterBtn;
import com.lspl.www.jbac.ui.BodyMatterBtn;
import com.lspl.www.jbac.ui.FrontMatterBtn;
import com.lspl.www.jbac.ui.HeaderLabel;

/**
* The Interface Mediator.
*
* @author sandeep
* @version 1.0
* @see http://en.wikipedia.org/wiki/Mediator_pattern#Java
*
*      Each participant communicates to the mediator its
*      activity and the mediator dispatches the expected behavior to the other
*      participants.
*/
public interface Mediator {

    /**
    * Front matter.
    */
    public void frontMatter();

    /**
    * Body matter.
    */
    public void bodyMatter();

    /**
    * Back matter.
    */
    public void backMatter();

    /**
    * Register front matter.
    *
    * @param frontMatterButton the front matter button
    */
    public void registerFrontMatter(FrontMatterBtn frontMatterButton);

    /**
    * Register body matter.
    *
    * @param bodyMatterButton the body matter button
    */
    public void registerBodyMatter(BodyMatterBtn bodyMatterButton);

    /**
    * Register back matter.
    *
    * @param backMatterButton the back matter button
    */
    public void registerBackMatter(BackMatterBtn backMatterButton);

    /**
    * Register display header.
    *
    * @param headerLabel the header label
    */
    public void registerDisplayHeader(HeaderLabel headerLabel);

}

Mediator implementation:

package com.lspl.www.jbac.core;

import javax.swing.JButton;
import javax.swing.JLabel;

import com.lspl.www.jbac.ui.BackMatterBtn;
import com.lspl.www.jbac.ui.BodyMatterBtn;
import com.lspl.www.jbac.ui.FrontMatterBtn;
import com.lspl.www.jbac.ui.HeaderLabel;

/**
* The Class MediatorImpl.
*
* @author sandeep
*/
public class MediatorImpl implements Mediator {

    /** The front matter button. */
    private JButton frontMatterButton;

    /** The body matter button. */
    private JButton bodyMatterButton;

    /** The back matter button. */
    private JButton backMatterButton;

    /** The header label. */
    private JLabel headerLabel;

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#registerFrontMatter(com.lspl.www.jbac.ui.FrontMatterBtn)
    */
    @Override
    public void registerFrontMatter(FrontMatterBtn fmb) {

        frontMatterButton = fmb;

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#registerBodyMatter(com.lspl.www.jbac.ui.BodyMatterBtn)
    */
    @Override
    public void registerBodyMatter(BodyMatterBtn bmb) {

        bodyMatterButton = bmb;

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#registerBackMatter(com.lspl.www.jbac.ui.BackMatterBtn)
    */
    @Override
    public void registerBackMatter(BackMatterBtn bmb) {

        backMatterButton = bmb;

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#registerDisplayHeader(com.lspl.www.jbac.ui.HeaderLabel)
    */
    @Override
    public void registerDisplayHeader(HeaderLabel hrl) {

        headerLabel = hrl;

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#frontMatter()
    */
    @Override
    public void frontMatter() {

        frontMatterButton.setEnabled(false);

        bodyMatterButton.setEnabled(true);

        backMatterButton.setEnabled(true);

        headerLabel.setText("FRONT MATTER UI");

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#bodyMatter()
    */
    @Override
    public void bodyMatter() {

        bodyMatterButton.setEnabled(false);

        frontMatterButton.setEnabled(true);

        backMatterButton.setEnabled(true);

        headerLabel.setText("BODY MATTER UI");

    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Mediator#backMatter()
    */
    @Override
    public void backMatter() {

        backMatterButton.setEnabled(false);

        bodyMatterButton.setEnabled(true);

        frontMatterButton.setEnabled(true);

        headerLabel.setText("BACK MATTER UI");

    }

}

Command interface:

package com.lspl.www.jbac.core;

/**
 * The Interface Command.
 *
 * @author sandeep
 * @version 1.0
 */
public interface Command {

    /**
     * Execute.
     */
    void execute();

}

FrontMatterBtn:

package com.lspl.www.jbac.ui;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import com.lspl.www.jbac.core.Command;
import com.lspl.www.jbac.core.Mediator;

/**
* The Class FrontMatterBtn.
*
* @author sandeep
*/
public class FrontMatterBtn extends JButton implements Command {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 2508539554211132849L;

    /** The mediator. */
    Mediator mediator;


    /**
    * Instantiates a new front matter btn.
    *
    * @param actionListener the action listener
    * @param mediator the mediator
    */
    public FrontMatterBtn(ActionListener actionListener, Mediator mediator) {

        super("FRONT MATTER");

        addActionListener(actionListener);

        this.mediator = mediator;

        mediator.registerFrontMatter(this);
    }

    // Accessors and mutators.

    /**
    * Gets the mediator.
    *
    * @return the mediator
    */
    public Mediator getMediator() {
        return mediator;
    }

    /**
    * Sets the mediator.
    *
    * @param mediator the mediator to set
    */
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    /* (non-Javadoc)
    * @see com.lspl.www.jbac.core.Command#execute()
    */
    @Override
    public void execute() {

        // System.out.println("Front matter button clicked !!!!");

        mediator.frontMatter();

    }

}

LaunchApplication:

package com.lspl.www.jbac;

import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.lspl.www.jbac.core.Mediator;
import com.lspl.www.jbac.core.MediatorImpl;
import com.lspl.www.jbac.core.Model;
import com.lspl.www.jbac.ui.View;

/**
* The Class LaunchApplication.
*
* @author sandeep
*/
public class LaunchApplication {

    /** The model. */
    private Model model = null;

    /**
    * The main method.
    *
    * @param args the arguments
    */
    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            /* (non-Javadoc)
            * @see java.lang.Runnable#run()
            */
            public void run() {

                try {
                    UIManager.setLookAndFeel(UIManager
                    .getSystemLookAndFeelClassName());

                    LaunchApplication launchApplication = new LaunchApplication();

                    launchApplication.createAndShowGUI();

                } catch (ClassNotFoundException e) {

                    e.printStackTrace();

                } catch (InstantiationException e) {

                    e.printStackTrace();

                } catch (IllegalAccessException e) {

                    e.printStackTrace();

                } catch (UnsupportedLookAndFeelException e) {

                    e.printStackTrace();
                }

            }
        });

    }

    /**
    * Creates and displays GUI.
    */
    protected void createAndShowGUI() {

        // 1. Create Model instance.

        model = new Model();

        // 2. Instantiate mediator implementation.

        Mediator mediator = new MediatorImpl();

        // 3. Create view and pass mediator and model instance as parameter.

        View view = new View(mediator, model);

        view.initComponents();

    }

}

View:

package com.lspl.www.jbac.ui;

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

import com.lspl.www.jbac.core.Model;
import com.lspl.www.jbac.core.Mediator;
import com.lspl.www.jbac.ui.InitialPanel;

/**
 * The Class View.
 *
 * @author sandeep
 */
public class View {

    /** The mediator. */
    private Mediator mediator;

    /** The model. */
    private Model model;

    /** The application title. */
    private final String APPLICATION_TITLE = "Article Tagging Tool: Version 1.0";

    /** The jframe. */
    private JFrame jFrame;

    /** The initial panel. */
    private InitialPanel initialPanel;

    // Constructor.

    /**
     * Instantiates a new view.
     *
     * @param mediator the mediator
     * @param model the model
     */
    public View(Mediator mediator, Model model) {

        super();

        this.setMediator(mediator);

        this.setModel(model);
    }

    // Accessors and mutators.

    /**
     * Gets the mediator.
     *
     * @return the mediator
     */
    public Mediator getMediator() {
        return mediator;
    }

    /**
     * Sets the mediator.
     *
     * @param mediator the mediator to set
     */
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    /**
     * Gets the model.
     *
     * @return the model
     */
    public Model getModel() {
        return model;
    }

    /**
     * Sets the model.
     *
     * @param model the model to set
     */
    public void setModel(Model model) {
        this.model = model;
    }

    /**
     * Gets the jframe.
     *
     * @return the jFrame
     */
    public JFrame getjFrame() {
        return jFrame;
    }

    /**
     * Sets the j frame.
     *
     * @param jFrame the jFrame to set
     */
    public void setjFrame(JFrame jFrame) {
        this.jFrame = jFrame;
    }

    /**
     * Gets the initial panel.
     *
     * @return the initialPanel
     */
    public InitialPanel getInitialPanel() {
        return initialPanel;
    }

    /**
     * Sets the initial panel.
     *
     * @param initialPanel  the initialPanel to set
     */
    public void setInitialPanel(InitialPanel initialPanel) {
        this.initialPanel = initialPanel;
    }

    /**
     * Initializes the components.
     */
    public void initComponents() {

        jFrame = new JFrame(APPLICATION_TITLE);

        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jFrame.setSize(new Dimension(500, 500));

        initialPanel = new InitialPanel(mediator);

        jFrame.add(initialPanel);

        jFrame.setResizable(false);

        // jFrame.pack(); // Display the window.

        jFrame.setVisible(true);

    }

}

InitialPanel:

package com.lspl.www.jbac.ui;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JTextField;

import com.lspl.www.jbac.core.Command;
import com.lspl.www.jbac.core.Mediator;
import com.lspl.www.jbac.core.MediatorImpl;

/**
 * The Class InitialPanel.
 * 
 * @author sandeep
 */
public class InitialPanel extends JPanel {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 6553059374217590291L;

    /** The mediator. */
    private Mediator mediator;

    /** The mandatory labels. */
    private JLabel hwCodeLabel, publisherIdLabel, journalTitleLabel,
            printISSNLabel, eISSNLabel, publisherNameLabel, publisherLOCLabel,
            coverDateLabel, volumeLabel, issueLabel, copyrightStatementLabel,
            copyRightYearLabel;

    /** The mandatory text fields. */
    private JTextField hwCodeTextField, publisherIdTextField,
            journalTitleTextField, printISSNTextField, eISSNTextField,
            publisherNameTextField, publisherLOCTextField, coverDateTextField,
            volumeTextField, issueTextField, copyrightStatementTextField,
            copyRightYearTextField;

    /** The mandatory buttons. */
    private JButton frontMatterButton, bodyMatterButton, backMatterButton;

    /** The header label. */
    private JLabel headerLabel;

    // Constructor.

    /**
     * Instantiates a new initial panel.
     *
     * @param mediator
     *            the mediator
     */
    public InitialPanel(Mediator mediator) {

        super();

        this.mediator = mediator;

        initComponents();
    }

    // Accessors and mutators....


    /**
     * Initializes the components.
     */
    public void initComponents() {

        this.setLayout(new GridBagLayout());

        this.setBorder(BorderFactory.createMatteBorder(10, 10, 10, 10, Color.GRAY));

        this.setOpaque(false);

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.fill = GridBagConstraints.BOTH;

        gridBagConstraints.insets = new Insets(0, 0, 10, 0);

        mediator = new MediatorImpl();

        // All mandatory fields.

        // 1.
        hwCodeLabel = addLabelCell(1, "HW CODE:");

        hwCodeTextField = addTextFieldCell(1, "");

        // 2.
        publisherIdLabel = addLabelCell(2, "PUBLISHER ID:");

        publisherIdTextField = addTextFieldCell(2, "");

        // 3.
        journalTitleLabel = addLabelCell(3, "JOURNAL TITLE:");

        journalTitleTextField = addTextFieldCell(3, "");

        // 4.
        printISSNLabel = addLabelCell(4, "PRINT ISSN:");

        printISSNTextField = addTextFieldCell(4, "");

        // 5.
        eISSNLabel = addLabelCell(5, "ELECTRONIC ISSN:");

        eISSNTextField = addTextFieldCell(5, "");

        // 6.
        publisherNameLabel = addLabelCell(6, "PUBLISHER NAME:");

        publisherNameTextField = addTextFieldCell(6, "");

        // 7.
        publisherLOCLabel = addLabelCell(7, "PUBLISHER LOCATION:");

        publisherLOCTextField = addTextFieldCell(7, "");

        // 8.
        coverDateLabel = addLabelCell(8, "COVER DATE:");

        coverDateTextField = addTextFieldCell(8, "");

        // 9.
        volumeLabel = addLabelCell(9, "VOLUME:");

        volumeTextField = addTextFieldCell(9, "");

        // 10.
        issueLabel = addLabelCell(10, "ISSUE:");

        issueTextField = addTextFieldCell(10, "");

        // 11.
        copyrightStatementLabel = addLabelCell(11, "COPYRIGHT STATEMENT:");

        copyrightStatementTextField = addTextFieldCell(11, "");

        // 12.
        copyRightYearLabel = addLabelCell(12, "COPYRIGHT YEAR:");

        copyRightYearTextField = addTextFieldCell(12, "");

        // 13.
        frontMatterButton = addfrontMatterButtonCell(15);

        // 14.
        bodyMatterButton = addbodyMatterButtonCell(15);

        // 15.
        backMatterButton = addbackMatterButtonCell(15);

        headerLabel = addheaderLabelCell(0);

    }

    /**
     * Add header label cell.
     *
     * @param position
     *            the position
     * @return the jlabel
     */
    private JLabel addheaderLabelCell(int position) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.gridwidth = 2; // Span 2 columns

        gridBagConstraints.gridx = 0;

        gridBagConstraints.gridy = position;

        JLabel headerLabel = new HeaderLabel(mediator);

        // headerLabel.setHorizontalAlignment(SwingConstants.CENTER);

        this.add(headerLabel, gridBagConstraints);

        return headerLabel;
    }

    /**
     * For all rows, gridy should be the row number, and gridx will be 0 for the
     * label and 1 for the textfield.
     *
     * @param position
     *            the position
     * @return the j button
     */
    private JButton addfrontMatterButtonCell(int position) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.gridx = 0;

        gridBagConstraints.gridy = position;

        JButton frontMatterButton = new FrontMatterBtn(new ActionListener() {

            /*
             * (non-Javadoc)
             * 
             * @see
             * java.awt.event.ActionListener#actionPerformed(java.awt.event.
             * ActionEvent)
             */
            @Override
            public void actionPerformed(ActionEvent actionEvent) {

                Command comd = (Command) actionEvent.getSource();

                comd.execute();

            }
        }, mediator);

        this.add(frontMatterButton, gridBagConstraints);

        return frontMatterButton;

    }

    /**
     * For all rows, gridy should be the row number, and gridx will be 0 for the
     * label and 1 for the textfield.
     *
     * @param position
     *            the position
     * @return the j button
     */
    private JButton addbodyMatterButtonCell(int position) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.gridx = 1;

        gridBagConstraints.gridy = position;

        JButton bodyMatterButton = new BodyMatterBtn(new ActionListener() {

            /*
             * (non-Javadoc)
             * 
             * @see
             * java.awt.event.ActionListener#actionPerformed(java.awt.event.
             * ActionEvent)
             */
            @Override
            public void actionPerformed(ActionEvent actionEvent) {

                Command command = (Command) actionEvent.getSource();

                command.execute();

            }
        }, mediator);

        this.add(bodyMatterButton, gridBagConstraints);

        return bodyMatterButton;
    }

    /**
     * For all rows, gridy should be the row number, and gridx will be 0 for the
     * label and 1 for the textfield.
     *
     * @param position
     *            the position
     * @return the j button
     */
    private JButton addbackMatterButtonCell(int position) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.gridx = 2;

        gridBagConstraints.gridy = position;

        JButton backMatterButton = new BackMatterBtn(new ActionListener() {

            /*
             * (non-Javadoc)
             * 
             * @see
             * java.awt.event.ActionListener#actionPerformed(java.awt.event.
             * ActionEvent)
             */
            @Override
            public void actionPerformed(ActionEvent actionEvent) {

                Command comd = (Command) actionEvent.getSource();

                comd.execute();

            }
        }, mediator);

        this.add(backMatterButton, gridBagConstraints);

        return backMatterButton;
    }

    /**
     * For all rows, gridy should be the row number, and gridx will be 0 for the
     * label and 1 for the textfield.
     *
     * @param position
     *            the position
     * @param labelstr
     *            the labelstr
     * @return the j label
     */
    private JLabel addLabelCell(int position, String labelstr) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.gridx = 0;

        gridBagConstraints.gridy = position;

        JLabel label = new JLabel(labelstr);

        this.add(label, gridBagConstraints);

        return label;

    }

    /**
     * For all rows, gridy should be the row number, and gridx will be 0 for the
     * label and 1 for the textfield.
     *
     * @param position
     *            the position
     * @param string
     *            the string
     * @return the jtext field
     */
    private JTextField addTextFieldCell(int position, String string) {

        GridBagConstraints gridBagConstraints = new GridBagConstraints();

        gridBagConstraints.anchor = GridBagConstraints.EAST;

        gridBagConstraints.ipadx = 10;

        JTextField textField = new JTextField(string);

        gridBagConstraints.gridx = 1;

        gridBagConstraints.gridy = position;

        textField.setColumns(10);

        this.add(textField, gridBagConstraints);

        return textField;

    }

}
\$\endgroup\$
2
\$\begingroup\$

Java 7 comes with multi-catch: You can catch multiple exceptions with the same code block.

By using it, you can change

/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {

    SwingUtilities.invokeLater(new Runnable() {

        /* (non-Javadoc)
        * @see java.lang.Runnable#run()
        */
        public void run() {

            try {
                UIManager.setLookAndFeel(UIManager
                .getSystemLookAndFeelClassName());

                LaunchApplication launchApplication = new LaunchApplication();
                launchApplication.createAndShowGUI();

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (UnsupportedLookAndFeelException e) {
                e.printStackTrace();
            }

        }
    });

}

to

/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {

    SwingUtilities.invokeLater(new Runnable() {

        /* (non-Javadoc)
        * @see java.lang.Runnable#run()
        */
        public void run() {

            try {
                UIManager.setLookAndFeel(UIManager
                .getSystemLookAndFeelClassName());

                LaunchApplication launchApplication = new LaunchApplication();
                launchApplication.createAndShowGUI();

            } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|UnsupportedLookAndFeelException e) {
                e.printStackTrace();
            }

        }
    });

}

Even if you think this is not as readable as it could be, blank lines could make it readable:

/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {

    SwingUtilities.invokeLater(new Runnable() {

        /* (non-Javadoc)
        * @see java.lang.Runnable#run()
        */
        public void run() {

            try {
                UIManager.setLookAndFeel(UIManager
                .getSystemLookAndFeelClassName());

                LaunchApplication launchApplication = new LaunchApplication();
                launchApplication.createAndShowGUI();

            } catch (ClassNotFoundException | 
                     InstantiationException | 
                     IllegalAccessException | 
                     UnsupportedLookAndFeelException e) {
                e.printStackTrace();
            }

        }
    });

}

Additionally, you seem to have a blank line in between each line of code. I don't know whether this is due to your line endings (I don't think so). But consider using blank lines to indicate a semantic cohesion of sorts - group related lines together.

Compare the following:

/**
 * For all rows, gridy should be the row number, and gridx will be 0 for the
 * label and 1 for the textfield.
 *
 * @param position
 *            the position
 * @param string
 *            the string
 * @return the jtext field
 */
private JTextField addTextFieldCell(int position, String string) {

    GridBagConstraints gridBagConstraints = new GridBagConstraints();

    gridBagConstraints.anchor = GridBagConstraints.EAST;

    gridBagConstraints.ipadx = 10;

    JTextField textField = new JTextField(string);

    gridBagConstraints.gridx = 1;

    gridBagConstraints.gridy = position;

    textField.setColumns(10);

    this.add(textField, gridBagConstraints);

    return textField;

}

with

/**
 * For all rows, gridy should be the row number, and gridx will be 0 for the
 * label and 1 for the textfield.
 *
 * @param position
 *            the position
 * @param string
 *            the string
 * @return the jtext field
 */
private JTextField addTextFieldCell(int position, String string) {
    GridBagConstraints gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.anchor = GridBagConstraints.EAST;
    gridBagConstraints.ipadx = 10;
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = position;

    JTextField textField = new JTextField(string);
    textField.setColumns(10);

    this.add(textField, gridBagConstraints);

    return textField;
}

To me, this is far more readable. You have a bit that creates the GridBagConstraints, a bit that creates a JTextField, a bit that adds the JTextField and the GridBagConstraints and a bit that returns the textfield.

Heck, you could even extract them:

/**
 * For all rows, gridy should be the row number, and gridx will be 0 for the
 * label and 1 for the textfield.
 *
 * @param position
 *            the position
 * @param string
 *            the string
 * @return the jtext field
 */
private JTextField addTextFieldCell(int position, String string) {
    GridBagConstraints gridBagConstraints = createGridBagConstraintsForTextField(position);
    JTextField textField = createTextFieldCell(string);

    this.add(textField, gridBagConstraints);

    return textField;
}

By doing these things, you can reduce the mental capacity required to understand what the code does.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.