View Part 2 - Create Manufacturer WindowJ8 Home « View Part 2 - Create Manufacturer Window

We finish the section and complete the coding for the Manufacturer application by coding the ManufacturerWindow class and uncommenting the instantiations of the ManufacturerServerStartupWindow and ManufacturerWindow objects within the ManufacturerApplicationStartup class.

Create Manufacturer WindowTop

In the final lesson of the section we complete the coding for the Manufacturer application by coding the ManufacturerWindow class which allows users to view and interact with the Manufacturer file in an application window. We also uncomment the instantiations of the ManufacturerServerStartupWindow and ManufacturerWindow objects within the ManufacturerApplicationStartup class.

Creating The ManufacturerWindow Class Top

The ManufacturerWindow class allows users to view and interact with the Manufacturer file in an application window. This is the view element of the MVC paradigm.

Create the ManufacturerWindow class in the client package and cut and paste the following code into it.


package client;

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.*;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import model.StockingException;

import services.*;

/**
 * This class allows users to view and interact with the  Manufacturer file 
 * in an application window. This is the view element of the MVC paradigm.
 * 
 * The class is invoked via the following run modes: 
 * "client" - non-networked client mode. 
 * ""       - Networked client mode (no mode entered).
 * 
 * @author Charlie 
 * @version 1.0
  * 
 */
public class ManufacturerWindow extends JFrame implements ListSelectionListener {
    /**
     * The Logger instance through which all log messages from this class are
     * routed. Logger namespace is J8CaseStudy.
     */
    private static Logger log = Logger.getLogger("J8CaseStudy"); // Log output

    /**
     * A version number for the ManufacturerWindow class so that serialisation can
     * occur without worrying about the underlying class changing between
     * serialisation and deserialisation.
     */
    private static final long serialVersionUID = 2498052502L;

    /**
     * The strings for the buttons in the Manufacturer window. 
     */
    private static final String SEARCH = "Search";
    private static final String SEARCHALL = "Search All";
    private static final String STOCK = "Stock";
    private static final String UNSTOCK = "Unstock";

    /**
     * The internal reference to the Services controller.
     */
    private Services services;

    /**
     * The JTable that displays the Manufacturers stored on the
     * Manufacturer file.
     */
    private JTable manufacturerTable = new JTable();

    /**
     * Holds a copy of the combo boxes used so we can get selected items to use
     * in our search criteria.
     */
    private JComboBox<?> chooseName;
    private JComboBox<?> chooseLocation;

    /**
     *  Buttons for the Manufacturer window.
     */
    private JButton searchButton = new JButton(SEARCH);
    private JButton searchAllButton = new JButton(SEARCHALL);
    private JButton stockButton = new JButton(STOCK);
    private JButton unstockButton = new JButton(UNSTOCK);

    /**
     * The internal reference to the the currently displayed table of Manufacturer
     * data.
     */
    private ManufacturerTableModel tableData;

    /**
     * Builds and displays the Manufacturer application window. The constructor
     * begins by building the connection selection dialog box. The user mode is
     * selected and the Manufacturer file located. A reference is then
     * acquired for the Services Singleton and the Manufacturer window is
     * populated using an empty search (returns all). The constructed window is
     * then centred in middle of screen and displayed.
     * 
     * @param args specifying the following modes: 
     * "client" - Non-Network client. 
     *  ""      - Network client (no mode entered).
     */
    public ManufacturerWindow(String[] args) {
        super("Stocking Goods Limited: Manufacturer Stock System");
        log.entering("ManufacturerWindow", "ManufacturerWindow");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        /*
         * Setup an Enum Constant for access mode entered for use throughout 
         * the application.
         */
        RunMode runMode = (args.length == 0) ? RunMode.NETWORK_CLIENT
                : RunMode.NON_NETWORK_CLIENT;
        // Locate the Manufacturer file
        RunModeDialog manufacturerFileLocation = new RunModeDialog(this, runMode);
        // User terminated Manufacturer file location dialog box so exit application
        if (manufacturerFileLocation.userCancelled()) {
            System.exit(0);
        }
        // Get a reference to the Services singleton  
        try {     
            services = (Services) ServicesImpl.getServicesImplInstance(runMode,
                                  manufacturerFileLocation.getLocation(),
                                  manufacturerFileLocation.getPort());
        } catch (ServicesException se) {
            log.log(Level.SEVERE, "Connecting to the server caused a fatal error: " 
                    + "\n" + se);
            ManufacturerApplicationStartup.handleException(
                    "Failed to connect to Manufacturer file");
            System.exit(0);
        }
        // Handle the table listener
        ListSelectionModel selectionModel = manufacturerTable.getSelectionModel();
        selectionModel.addListSelectionListener( this );
        // Use an empty search to initially populate Manufacturer table data
        try {
            tableData = services.searchManufacturers("", "");
            setupManufacturerTable();
        } catch (IOException se) {
            ManufacturerApplicationStartup.handleException(
                    "Failed to acquire initial Manufacturer information."
                    + "\nPlease check the Manufacturer Database connection.");
        }
        this.add(new ManufacturerScreen());
        this.pack();
        this.setSize(900, 400);
        // Centre on screen
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (int) ((d.getWidth() - this.getWidth()) / 2);
        int y = (int) ((d.getHeight() - this.getHeight()) / 2);
        this.setLocation(x, y);
        this.setVisible(true);
        log.exiting("ManufacturerWindow", "ManufacturerWindow");
    }

    /**
     * Try to store last selection. Refresh the manufacturerTable
     * from the tableData member. Reselect the previous item if it
     * still exists.
     */
    private void setupManufacturerTable() {
        log.entering("ManufacturerWindow", "setupManufacturerTable");
        // Store previous selection
        int index = manufacturerTable.getSelectedRow();
        String prevSelected = (index >= 0) ? (String) manufacturerTable.getValueAt(index, 0)
                                           + (String) manufacturerTable.getValueAt(index, 1) 
                                           : "";
        // Reset the table data
        this.manufacturerTable.setModel(this.tableData);
        // Disable the stocking button 
        stockButton.setEnabled(false);
        // Disable the unstocking button 
        unstockButton.setEnabled(false);
		
        // Reselect the previous item if it still exists
        for (int i = 0; i < this.manufacturerTable.getRowCount(); i++) {
            String selectedManufacturer = (String) manufacturerTable.getValueAt(i, 0)
                        + (String) manufacturerTable.getValueAt(i, 1);
            if (selectedManufacturer.equals(prevSelected)) {
                this.manufacturerTable.setRowSelectionInterval(i, i);
                String stockOrdered = (String) manufacturerTable.getValueAt(i, 5);
                // If there is stock ordered enable the unstock button and disable 
                // the stock button, otherwise enable the stock button
                if (stockOrdered.equals("")) {
                    stockButton.setEnabled(true);
                } else {
                    stockButton.setEnabled(false);
                    unstockButton.setEnabled(true);
                }
                break;
            }
        }
        log.exiting("ManufacturerWindow", "setupManufacturerTable");
    }

    /**
     * Setup the panels of the Manufacturer application. Having this here helps
     * 
     * @author Charlie
     * @version 1.0
     * 
     */
    private class ManufacturerScreen extends JPanel {
        /**
         * A version number for the ManufacturerScreen class so that serialisation
         * can occur without worrying about the underlying class changing
         * between serialisation and deserialisation.
         */
        private static final long serialVersionUID = 2498052502L;
        // Set up border titles
        private static final String SEARCHTITLE = "Search Manufacturer File";
        private static final String TABLETITLE = "Manufacturer Information";
        private static final String ACTIONTITLE = "Actions";
        /**
         * Constructs the main panel for the Manufacturer application.
         */
        public ManufacturerScreen() {
            this.setLayout(new BorderLayout());
            /*
             *  Search Panel 1 components
             */
            // Name Combo box
            Set<String> manufacturerNames = new TreeSet<String>();
            manufacturerNames.add("---ANY---");
            // Populate search on Manufacturer names combo box
            for (int i = 0; i < manufacturerTable.getRowCount(); i++) {
                manufacturerNames.add((String) manufacturerTable.getValueAt(i, 0));
            }
            Object[] nameObj = manufacturerNames.toArray();
            chooseName = JComboBoxFromObj(nameObj);
            // Create Search panel 1
            JPanel searchPanel1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
            JLabel manufacturerLabel = new JLabel("Manufacturer Name    ");
            searchPanel1.add(manufacturerLabel);
            searchPanel1.add(chooseName);
            /*
             *  Search panel 2 components
             */
            // Location Combo box
            Set<String> locations = new TreeSet<String>();
            locations.add("---ANY---");
            // Populate search on locations combo box
            for (int i = 0; i < manufacturerTable.getRowCount(); i++) {
                locations.add((String) manufacturerTable.getValueAt(i, 1));
            }
            Object[] locationObj = locations.toArray();
            chooseLocation = JComboBoxFromObj(locationObj);
            // Create Search panel 2
            JPanel searchPanel2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
            JLabel locationLabel = new JLabel("Manufacturer Location");
            searchPanel2.add(locationLabel);
            searchPanel2.add(chooseLocation);
            /*
             *  Search panel 3 components
             */
            // Search and search all buttons
            searchButton.addActionListener(new SearchManufacturers());
            searchButton.setMnemonic(KeyEvent.VK_S);
            searchAllButton.addActionListener(new SearchAll());
            searchAllButton.setMnemonic(KeyEvent.VK_R);
            // Create Search panel 3
            JPanel searchPanel3 = new JPanel(new FlowLayout(FlowLayout.LEFT));
            searchPanel3.add(searchButton);
            searchPanel3.add(searchAllButton);
            // combine the 3 search panes into 1
            JPanel topPanel = new JPanel(new BorderLayout());
            topPanel.setBorder(BorderFactory.createTitledBorder(SEARCHTITLE));
            topPanel.add(searchPanel1, BorderLayout.NORTH);
            topPanel.add(searchPanel2, BorderLayout.CENTER);
            topPanel.add(searchPanel3, BorderLayout.SOUTH);
            // Add the top panel to the main window
            this.add(topPanel, BorderLayout.NORTH);
            // Add the manufacturer table to the main window
            JScrollPane tableScroll = new JScrollPane(manufacturerTable);
            tableScroll.setBorder(BorderFactory.createTitledBorder(TABLETITLE));
            tableScroll.setSize(500, 250);
            this.add(tableScroll, BorderLayout.CENTER);
            // Setup stocking button
            stockButton.addActionListener(new StockFromManufacturer());
            stockButton.setMnemonic(KeyEvent.VK_B);
            // Disable the stocking button 
            stockButton.setEnabled(false);
            // Set the stocking button to refuse focus
            stockButton.setRequestFocusEnabled(false);
            // Setup unstocking button
            unstockButton.addActionListener(new UnstockBackToManufacturer());
            unstockButton.setMnemonic(KeyEvent.VK_U);
            // Disable the unstocking button 
            unstockButton.setEnabled(false);
            // Set the unstocking button to refuse focus
            unstockButton.setRequestFocusEnabled(false);
            // Create a panel for stocking and unstocking buttons
            JPanel stockingPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
            stockingPanel.setBorder(BorderFactory.createTitledBorder(ACTIONTITLE));
            stockingPanel.add(stockButton);
            stockingPanel.add(unstockButton);
            // Add the stocking panel to the main window
            this.add(stockingPanel, BorderLayout.SOUTH);
            // Set table properties
            manufacturerTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            manufacturerTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
            // Add Tool Tips
            chooseName.setToolTipText(
                    "Select a value from the combo box for the name of the manufacturer.");
            chooseLocation.setToolTipText(
                    "Select a value from the combo box for the location of the manufacturer.");
            searchButton.setToolTipText("Manufacturer search.");
            searchAllButton.setToolTipText("Show all Manufacturers");
            manufacturerTable.setToolTipText("Select a Manufacturer to stock/unstock from.");
            stockButton.setToolTipText("Stock product from the selected Manufacturer");
            unstockButton.setToolTipText("Unstock product back to the selected Manufacturer");
        }

        /**
         * Private method that allows us to convert our object array into a
         * comboBox.
         * 
         * @see JComboBox
         */
        private JComboBox<?> JComboBoxFromObj(Object[] obj) {
            JComboBox<?> comboBox = new JComboBox<Object>(obj);
            return comboBox;
        }
    }

    /**
     * Handles all Manufacturer search events.
     * 
     * @author Charlie
     * @version 1.0
     */
    private class SearchManufacturers implements ActionListener {
        /**
         * Handles the actionPerformed event for the search button.
         * 
         * @param ae The event initiated by the Search button.
         */
        public void actionPerformed(ActionEvent ae) {
            try {
                String name = (String) chooseName.getSelectedItem();
                if (name == "---ANY---") {
                    name = "";
                }
                String location = (String) chooseLocation.getSelectedItem();
                if (location == "---ANY---") {
                    location = "";
                }
                tableData = services.searchManufacturers(name, location);
                setupManufacturerTable();
            } catch (IOException se) {
                String msg = "Problem with search - operation failed.";
                ManufacturerApplicationStartup.handleException(msg);
            }
        }
    }

    /**
     * Resets Manufacturer search.
     * 
     * @author Charlie
     * @version 1.0
     */
    private class SearchAll implements ActionListener {
        /**
         * Handles the actionPerformed event for the search all button.
         * 
         * @param ae The event initiated by the SearchAll button.
         */
        public void actionPerformed(ActionEvent ae) {
            try {
                chooseName.setSelectedIndex(0);
                String name = "";
                chooseLocation.setSelectedIndex(0);
                repaint();
                String location = "";
                tableData = services.searchManufacturers(name, location);
                setupManufacturerTable();
            } catch (IOException se) {
                String msg = "Problem with search - operation failed.";
                ManufacturerApplicationStartup.handleException(msg);
            }
        }
    }

    /**
     * Handles all Manufacturer stocking events.
     * 
     * @author Charlie 
     * @version 1.0
     */
    private class StockFromManufacturer implements ActionListener {
        private String stockOrdered; // Used for validation
        private int stockOrd;        // Used for calculations 
        private int stockLvl;      // Calculated stock level

        /**
         * Handles the actionPerformed event for the stock order button.
         * 
         * @param ae The event initiated by the book button.
         */
        public void actionPerformed(ActionEvent ae) {
            int index = manufacturerTable.getSelectedRow();
            if (index >= 0) {
                /*
                 * Display a dialog box for stock entry that validates
                 * stock order entered or exits on user cancel
                 */
                boolean exitLoop = false;
                while (!exitLoop) {
                    stockOrdered = (String) JOptionPane.showInputDialog(rootPane,
                            "Please enter stock amount (1-999) to order",
                            "Requesting stock order", JOptionPane.PLAIN_MESSAGE,
                            null, null, "");
                    // null indicates user pressed cancel or exited window
                    if (stockOrdered == null) {
                        break;
                    // validate user entry
                    } else if (validStockOrdered(stockOrdered)) {
                        exitLoop = true;
                    }
                }
                if (exitLoop) {
                    // Get record number using unique name/location fields
                    String name = (String) manufacturerTable.getValueAt(index, 0);
                    String location = (String) manufacturerTable.getValueAt(index, 1);
                    try {
                        //Call services
                        services.stockFromManufacturer(name, location, stockLvl, stockOrd);
                        // Update column and row with stoclLevel and stockOrdered
                        String stockLevelStr = "" + stockLvl;
                        manufacturerTable.setValueAt(stockLevelStr, index, 4);
                        String stockOrderedStr = "" + stockOrd;
                        manufacturerTable.setValueAt(stockOrderedStr, index, 5);
                        // Disable the stocking button 
                        stockButton.setEnabled(false);
                        // Enable the unstocking button 
                        unstockButton.setEnabled(true);
                        setupManufacturerTable();
                        manufacturerTable.repaint();
                    } catch (IOException se) {
                        String msg = "Problem with stocking - operation failed.";
                        ManufacturerApplicationStartup.handleException(msg); 
                    } catch (StockingException e) {
                        String msg = "Stocking already set by another user - operation failed. " 
                                + " Press the 'Search' button to refresh table.";
                        ManufacturerApplicationStartup.handleException(msg); 
                    }
                }
            }
        }
        /**
         * Validate stock order entered in dialog box.
         * 
         * @param stockOrdered The amount of stock ordered.
         * @return A boolean indicating whether stockOrdered is valid.
         */
        private boolean validStockOrdered(String stockOrdered) {
            int index = manufacturerTable.getSelectedRow();
            try {
                stockOrd = Integer.parseInt(stockOrdered);
            } catch (NumberFormatException e) {
                // Stock ordered must be numeric
                JOptionPane.showMessageDialog(rootPane,
                            "Stock order must be numeric. Please try again. ");
                return false;
            }
            if (stockOrd < 1 || stockOrdered.length() > 3) {
                // Stock ordered must be in range (1-999)
                JOptionPane.showMessageDialog(rootPane,
                            "Stock order valid range 1 - 999. Please try again. ");
                return false;
            } else {
                // Stock ordered must not exceed stock amount
                String stock = (String) manufacturerTable.getValueAt(index, 4);
                int stockLevel = 0;
                try {
                    stockLevel = Integer.parseInt(stock);
                    if (stockLevel < stockOrd) {
                        JOptionPane.showMessageDialog(rootPane,
                                "You cannot order more stock than is available. Please try again");
                        return false;
                    } else  {
                        stockLvl = stockLevel - stockOrd;
                        return true;
                    }
                } catch (NumberFormatException e) {
                    log.log(Level.INFO, "Stocking problem: " + stock + 
                            ", passed stock was not numeric. ");
                    JOptionPane.showMessageDialog(rootPane,
                            "Stock level must be numeric. Please try again");
                    return false;
                }
            }
        }
    }

    /**
     * Handles all Manufacturer unstocking events.
     * 
     * @author Charlie 
     * @version 1.0
     */
    private class UnstockBackToManufacturer implements ActionListener {

        /**
         * Handles the actionPerformed event for the unstock button.
         * 
         * @param ae The event initiated by the unstock button.
         */
        public void actionPerformed(ActionEvent ae) {
            int index = manufacturerTable.getSelectedRow();
            if (index >= 0) {
                String name = (String) manufacturerTable.getValueAt(index, 0);
                String location = (String) manufacturerTable.getValueAt(index, 1);
                String stockLevel = (String) manufacturerTable.getValueAt(index, 4);
                String stockOrdered = (String) manufacturerTable.getValueAt(index, 5);
                int manStockLevel = 0;
                int stockOrd = 0;
                try {
                    manStockLevel = Integer.parseInt(stockLevel);
                    try {
                        stockOrd = Integer.parseInt(stockOrdered);
                    } catch (NumberFormatException e) {
                        log.log(Level.INFO, "Manufacturer: " + name + ", " + location + 
                                " stock ordered wasn't numeric.");
                    }	
                } catch (NumberFormatException e) {
                    log.log(Level.INFO, "Manufacturer: " + name + ", " + location + 
							" stock level wasn't numeric.");
                } finally {
                    try {
                        //We can restock manufacturer
                        services.unstockBackToManufacturer(name, location, stockOrd);
                        // Disable the unstocking button 
                        unstockButton.setEnabled(false);
                        // Enable the stocking button 
                        stockButton.setEnabled(true);
                        // Update Stock level and stock ordered
                        manStockLevel = manStockLevel + stockOrd;
                        String strStock = "" + manStockLevel;
                        manufacturerTable.setValueAt(strStock, index, 4);
                        manufacturerTable.setValueAt("", index, 5);
                        setupManufacturerTable();
                        manufacturerTable.repaint();
                    } catch (IOException se) {
                        String msg = "Problem with unstocking - operation failed.";
                        ManufacturerApplicationStartup.handleException(msg); 
                    }
                }
            }
        }
    }

    public void valueChanged(ListSelectionEvent e) {
        // See if this is a valid table selection
        if( e.getSource() == manufacturerTable.getSelectionModel() 
                && e.getFirstIndex() >= 0 ) {
            // Enable the Stocking button);
            int index = manufacturerTable.getSelectedRow();
            if (index >= 0) {
                String stockOrdered = (String) manufacturerTable.getValueAt(index, 5);
                if (stockOrdered.equals("")) {
                    stockButton.setEnabled(true);
                    unstockButton.setEnabled(false);
                } else {
                    stockButton.setEnabled(false);
                    unstockButton.setEnabled(true);
                }
            }
        }
    }
}

Updating The ManufacturerApplicationStartup ClassTop

The last thing we need to do is uncomment the instantiations of the ManufacturerServerStartupWindow and ManufacturerWindow objects within the ManufacturerApplicationStartup class.

Open the ManufacturerApplicationStartup class in your text editor.

Uncomment the instantiations and remove the System.out.println lines, near the end of the the ManufacturerApplicationStartup constructor, to look like the following snippet in the client package.


        if (args.length == 0 || "client".equalsIgnoreCase(args[0])) {
            // Create an instance of the Manufacturer application window
            new ManufacturerWindow(args);
        } else if ("server".equalsIgnoreCase(args[0])) {
            // Create an instance of the Manufacturer server startup application window
            new ManufacturerServerStartupWindow();
        } else {

The following screenshot shows the client package structure after adding the ManufacturerWindow class.

create ManufacturerWindow
Screenshot 1. The client package after adding the ManufacturerWindow class.

This completes the coding for the Manufacturer application.

Lesson 17 Complete

In this lesson we coded the View elements of the MVC pattern that relate to the manufacturer window.

Related Java Tutorials

Fundamentals - Primitive Variables
Fundamentals - Conditional Statements
Fundamentals - if Construct
Fundamentals - while Construct
Objects & Classes - Class Structure and Syntax
Objects & Classes - Reference Variables
Objects & Classes - Methods
Objects & Classes - Instance Variables & Scope
Objects & Classes - Constructors
Objects & Classes - Static Members
Objects & Classes - Enumerations
OO Concepts - Encapsulation
OO Concepts - Inheritance Concepts - Using the super keyword
Exceptions - Handling Exceptions
API Contents - Inheritance - Using the package keyword
API Contents - Inheritance - Using the import keyword
API Contents - Java I/O Overview - The java.io.File Class
Concurrency - Synchronization - Synchronized Blocks
Swing - RMI - Serialization
Swing - Components

What's Next?

In the next section we commence testing of the model aspects of the MVC paradigm.