Tutorial

lindyFrame HTML Viewer Plugin

Janurary 03, 2017

Introduction


    LindyFrame is a desktop application framework that allows the quick development of software that supports internationalization and a modular plugin environment. The lindyFrame plugin tutorial documents the highlights of creating the HTML Viewer plugin that is included with the framework.

    The lindyFrame plugin architecture allows the application to dynamically load code from the installation's sub-directory, lib/plugin, as the program is initialized when first run. Any Java JAR file placed in that directory will be scanned for the proper contents that can be identified as a lindyFrame plugin. Once identified the framework will attempt to add that plugin as one of the main tabs the user will see on the right hand side of the lindyFrame window as shown in Figure 1. As an alternative to loading plugins automatically from the plugin directory a user may use the Tools | Plugin Management interface to manually load plugins that thereafter will also be available for use. Plugins may be loaded via the local file system, LAN, or Internet.

illustration 1

Figure 1. lindyFrame Main Interface


LindyFrame_PluginModule


    The core aspect of the lindyFrame framework plugin module architecture is oriented around the abstract LindyFrame_PluginModule class. This class implements the Plugin Module Interface which defines the needed routines, class methods, that are required for loading and running a plugin module. The code for the LindyFrame_PluginModule is provided here and shown in Listing 1. below. From this code listing we see the LindyFrame_PluginModule class has a default no argument constructor and several methods. All plugins which will extend this class should do no initialization work in the constructor and just allow the default super() to be called. The key initialization for a plugin should be allocated to the initPlugin() method. The initPlugin() method has two argument instances of Main_Frame and String. The Main_Frame argument instance will allow a plugin to gain access to lindyFrame's Menu commands and the String argument, path, is the plugin's location be it local or network based. Now from the listing one should see that the initPlugin() method is commented out for the LindyFrame_PluginModule abstract class. This is because this will force you as a developer to implement this method in your plugin module class.

Code Listing 1: (LindyFrame_PluginModule.java)

//=================================================================
//                LindyFrame_PluginModule Class
//=================================================================
//
//    This class provides the abstract framework for plugin classes
// to extends in order to properly function within the lindyFrame
// application.
//
//             << LindyFrame_PluginModule.java >>
//
//=================================================================
// Copyright (C) 2013-2016 Dana M. Proctor
// Version 1.5 05/21/2016
//
// 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
// 2 of the License, or (at your option) any later version. This
~
~
~
//=================================================================
// Version 1.0 Initial LindyFrame_PluginModule Class.
//         1.1 Cleaned Up Un-needed Methods.
//         1.2 Added Interface Method shutdown().
//         1.3 Changed the Return Types for Methods getToolBar(), getPanel(),
//             getControlledToolBar(), & getControlledPanel() From JToolBar
//             & JPanel to JComponent. Class Instance toolBar & panel Changed
//             Accordingly.
//         1.4 Added Interface Methods start() & stop().
//         1.5 Updated Copyright.
//         1.6 Source Formatting Changes & Class Instance pathFileName Changed to
//             path_FileName. Removed All getControlledXXX() Methods.
//         1.7 Returned Methods getControlledXXX(). 
//             
//-----------------------------------------------------------------
//                 danap@dandymadeproductions.com
//=================================================================

package com.dandymadeproductions.lindyframe.plugin;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuBar;

/**
 *    The LindyFrame_PluginModule class provides the abstract framework
 * for plugin classes to extends in order to properly function within
 * the lindyFrame application.
 * 
 * @author Dana M. Proctor
 * @version 1.7 10/03/2016
 */

public abstract class LindyFrame_PluginModule implements PluginModuleInterface
{
   // Class Instances.
   //protected Main_Frame parent;
   protected String path_FileName;
   public String name;
   public String author;
   protected String version;
   protected String description;
   protected String category;
   protected int size;
   protected ImageIcon tabIcon;
   protected JMenuBar menuBar;
   protected JComponent toolBar;
   protected JComponent panel;

   //===========================================================
   // LindyFrame_PluginModule Constructor
   //===========================================================

   public LindyFrame_PluginModule()
   {
      // Just Initialize to a NULL condition.
      
      path_FileName = null;
      name = null;
      author = null;
      version = null;
      description = null;
      category = null;
      size = 0;
      tabIcon = null;
      menuBar = null;
      toolBar = null;
      panel = null;
   }
   
   //==============================================================
   // Class method to setup up your plugin.
   // OVERIDE THIS METHOD!
   //==============================================================

   /*
   public void initPlugin(Main_Frame mainFrame, String path)
   {
      // This is where the plugin should be initialized.
      parent = mainFrame;
   }
   */
   
   //==============================================================
   // Class methods to get/set the plugin's file name.
   //==============================================================
   
   public String getPath_FileName()
   {
      return path_FileName;
   }
   
   protected String getControlledPath_FileName()
   {
      return path_FileName;
   }
   
   //==============================================================
   // Class method to get/set the plugin's name.
   // Interface requirement.
   //==============================================================

   public String getName()
   {
      return name;
   }
   
   public String getControlledName()
   {
      return name;
   }
   
   //==============================================================
   // Class method to get/set the plugin's author.
   // Interface requirement.
   //==============================================================

   public String getAuthor()
   {
      return author;
   }
   
   public String getControlledAuthor()
   {
      return author;
   }
   
   //==============================================================
   // Class method to obtain the plugin's version number.
   // Interface requirement.
   //==============================================================

   public String getVersion()
   {
      return version;
   }
   
   public String getControlledVersion()
   {
      return version;
   }
   
   //==============================================================
   // Class method to obtain the plugin's description.
   // Interface requirement.
   //==============================================================

   public String getDescription()
   {
      return description;
   }
   
   public String getControlledDescription()
   {
      return description;
   }
   
   //==============================================================
   // Class method to obtain the plugin's category.
   // Interface requirement.
   //==============================================================

   public String getCategory()
   {
      return category;
   }
   
   public String getControlledCategory()
   {
      return category;
   }
   
   //==============================================================
   // Class method to obtain the plugin's size.
   // Interface requirement.
   //==============================================================

   public int getSize()
   {
      return size;
   }
   
   public int getControlledSize()
   {
      return size;
   }
   
   //==============================================================
   // Class method to allow the collection of a image icon that
   // will be used as an identifier in the lindyFrame tab structure.
   //
   // NOTE: The tab icon should be no larger than 16 x 16.
   // Interface requirement.
   //==============================================================

   public ImageIcon getTabIcon()
   {
      return tabIcon;
   }
   
   public ImageIcon getControlledTabIcon()
   {
      return tabIcon;
   }
   
   //==============================================================
   // Class method to obtain the plugin's JMenuBar that can be
   // used to control various aspects of the modules functionality.
   // Interface requirement.
   //==============================================================

   public JMenuBar getMenuBar()
   {
      return menuBar;
   }
   
   public JMenuBar getControlledMenuBar()
   {
      return menuBar;
   }
   
   //==============================================================
   // Class method to allow the collection of a JToolBar to be
   // used with the plugin module.
   // Interface requirement.
   //==============================================================

   public JComponent getToolBar()
   {
      return toolBar;
   }
   
   public JComponent getControlledToolBar()
   {
      return toolBar;
   }
   
   //==============================================================
   // Class method for returning a JComponent, JPanel or JFXPanel
   // for inclusion in the application's main tab. Interface
   // requirement.
   //==============================================================

   public JComponent getPanel()
   {
      return panel;
   }
   
   public JComponent getControlledPanel()
   {
      return panel;
   }
   
   //==============================================================
   // Class method to allow the plugin to start activities back
   // up after a stop() sequence.
   // (USED FOR CONTROLLING THREADS)
   //==============================================================

   public void start()
   {
      // Do what you will to start again from stop.
   }
   
   //==============================================================
   // Class method to allow the plugin to temporarily stop 
   // activities that may then be started again.
   // (USED FOR CONTROLLING THREADS)
   //==============================================================

   public void stop()
   {
      // Do what you will to notify stop.
   }
   
   //==============================================================
   // Class method to allow the plugin to close activities pending
   // a closing of the application.
   //==============================================================
   
   public void shutdown()
   {
      // Do what you will to notify pending closing.
   }
}
					

The key aspect of the initPlugin() method that a developer should know is that it should create a custom JComponent object that lindyFrame will use to load into its tabbed pane for your plugin. That JComponent should be a panel or pane and will be what users will see when your plugin tab is selected from the framework's main interface window on the right hand side. The correlated companion class method in the LindyFrame_PluginModule class is the getPanel() method. That method should return the JComponent component that is created in the initPlugin() method.

    Other methods in the LindyFrame_PluginModule class, allow the developer to return the name and an icon that will be used to identify a plugin's tab. The name will appear as the tooltip for the tab and the icon will become the insignia for the tab. The icon returned through the getTabIcon() method should be no larger than 12 x 12 pixels. Two of the other getter methods shown in the listing allows a plugin to create its own Menu and Toolbar that will be used in conjunction with the module. Several other getter methods are also provided that allow the plugin to provide various other information for consumption via lindyFrame's Plugin Management interface.

HTML Viewer Plugin Example


    The lindyFrame application comes with the pre-installed plugin, HTMLViewer, that is loaded from the lib/plugins directory of the installation. The source code for the HTMLViewer is available as a separate download that includes all the source code files for the plugin. The download may be found at the Dandy Made Productions' web site under the lindyFrame application page, HTML Viewer Plugin. The HTML Viewer plugin code provides the outline of the discussion that follows. All resources for the discussion in this article are made available via links at the end. Any classes given as part of this tutorial are covered by the GPL and may be used in accordance with that license.

    Like all plugins for lindyFrame a developer should create a new class called PluginModule that extends the LindyFrame_PluginModule class. The abbreviated code for the HTMLViewer plugin PluginModule class is shown below in listing 2. The constructor for the new class should perform no work except call the super() to the parent, LindyFrame_PluginModule. The new PluginModule class should orientate initialization of components for the plugin in the initPlugin() method. As can be seen from the listing the HTMLViewer initializes three instances, pluginName, pluginAuthor, and htmlViewer. The first two will be used to identify the name and author of the plugin and the third calls for the construction of a new class that will handle the creation of the main JPanel component needed by the plugin. Though not shown in the abbreviated listing the HTMLViewer PluginModule class overrides all the methods of the LindyFrame_PluginModule class and either returns directly or indirectly through the instance htmlViewer the requirements for the plugin. A developer need not override all the getter methods for a PluginModule class since the lindyFrame framework will substitute defaults for these instances, but without a JPanel component no visibility will be given to your plugin.

NOTICE: All PLUGINS MUST FOLLOW THE BASIC INTERFACE DESCRIBED HERE FOR A LindyFrame_PluginModule AND BE GIVEN THE CLASS NAME PluginModule. lindyFrame WILL ONLY SEARCH FOR AND LOAD PLUGIN CLASSES GIVEN THE NAME PluginModule!

Code Listing 2: (PluginModule.java)

//=================================================================
//              HTMLViewer PluginModule Class
//=================================================================
//
//    This class provides the hook to incorporate a external plugin
// module into the lindyFrame framework.
//
//              < PluginModule.java >
//
//=================================================================
// Copyright (C) 2013 Dana M. Proctor
// Version 1.0 07/26/2013
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
~
~
~
~
//-----------------------------------------------------------------
//                 danap@dandymadeproductions.com
//=================================================================

package com.dandymadeproductions.htmlviewer;

import javax.swing.ImageIcon;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JToolBar;

import com.dandymadeproductions.lindyframe.gui.Main_Frame;
import com.dandymadeproductions.lindyframe.plugin.LindyFrame_PluginModule;

/**
 *    The PluginModule class provides the hook to incorporate a external plugin
 * module into the lindyFrame framework.
 * 
 * @author Dana M. Proctor
 * @version 1.0 07/26/2013
 */

public class PluginModule extends LindyFrame_PluginModule
{
   // Class Instances
   private String pluginName, pluginAuthor;
   private HTMLViewer htmlViewer;

   //==============================================================
   // PluginModule Constructor.
   //==============================================================

   public PluginModule()
   {
      super();
   }

   //==============================================================
   // Class method to initialize your plugin.
   //==============================================================

   public void initPlugin(Main_Frame parentFrame, String path)
   {
      pluginName = "HTML Viewer";
      pluginAuthor = "Dandy Made Productions";
      htmlViewer = new HTMLViewer(parentFrame, path);
   }
~
~
~
   public String getName() {
      return pluginName;
   }
~
~
~
   public String getAuthor() {
      return pluginAuthor;
   }
~
~
~ 
   public JPanel getPanel() {
     return htmlViewer.getPanel();
   }
}
					

HTMLViewer Class


    The HTMLViewer class is the main component of the HTMLViewer plugin and was instantiated in the PluginModule class method initPlugin() with the instance htmlViewer. The constructor for this class takes two arguments, Main_Frame and String. More will be detailed of the Main_Frame argument, but first lets speak more about of the path argument because it is used to derive resources for the plugin

The path instance that is passed to plugin modules gives the URL that was derived by lindyFrame in loading the plugin's JAR file. A developer should create resources for a plugin with this in mind. The standard taken by the lindyFrame group is to have a directory in this path, location of JAR file, by the same name as the plugin and in this directory have images and other pertinent objects required by the plugin. Please see Figure 2. below. With this in mind lets move on to the htmlViewer object to understand the use of this path and the other argument in the instantiation of this class.

illustration 2

Figure 2. Plugin Directory Structure


    Though the HTMLViewer class is the core main object for the HTMLViewer plugin it is not per say a main class. All plugins do not have a main class, but as discussed previously just the PluginModule class which lindyFrame initializes through the initPlugin() method and then loads the various components needed to utilize the plugin. The main object for plugins is always a Java JPanel or JFXPanel component that is the face of the plugin in the lindyFrame application tab interface. So what we will see in the HTMLViewer core class is the creation of a main Panel object and the creation of resources and menu and toolbar objects. Listing 3. below shows the HTMLViewer condensed class and as seen is composed of a constructor and several methods. Three of the methods just return the objects indicated, JPanel, JMenuBar, and JToolBar. The other three a version and description, Strings and an ImageIcon. The constructor for the class creates each of these objects directly or through additional classes.

Code Listing 3: (HTMLViewer Main Class HTMLViewer.java)

//=================================================================
//                        HTMLViewer
//=================================================================
//
//    This class provides the main access point for setting up the
// requirements for the HTMLView plugin module for the lindyFrame
// framework.
//
//                     << HTMLViewer.java >>
//
//=================================================================
// Copyright (C) 2013-2016 Dana M. Proctor
// Version 1.5 11/07/2016
//
// 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
// 2 of the License, or (at your option) any later version. This
~
~
~
//=================================================================
// Revision History
// Changes to the code should be documented here and reflected
// in the present version number. Author information should
// also be included with the original copyright author.
//=================================================================
// Version 1.0 07/27/2013 Initial HTMLViewer Class.
//         1.1 08/02/2013 Added History Functionality and URL Entry
//                        Capability.
//         1.2 08/29/2013 Resources Should NOT Use Local System File Separator
//                        Definition, But Rather Standard File Delimitor Forward
//                        Slash.
//         1.3 06/24/2016 Updated VERSION to Bring Class Into Sync With lindyFrame
//                        v2.5. Now Compiled to Comply With JRE7.
//         1.4 11/07/2016 Updated VERSION & Made Resources Specified in Jar.
//         1.5 11/07/2016 Used imagesDirectory Instead of path as Argument for
//                        Viewer_ToolBar. Updated Version.
//                           
//-----------------------------------------------------------------
//                 danap@dandymadeproductions.com
//=================================================================

package com.dandymadeproductions.htmlviewer;

import java.awt.BorderLayout;
~
~
~
import javax.swing.text.html.HTMLEditorKit;

import com.dandymadeproductions.lindyframe.LindyFrame;
import com.dandymadeproductions.lindyframe.gui.Main_Frame;
import com.dandymadeproductions.lindyframe.utilities.LindyFrame_ResourceBundle;
import com.dandymadeproductions.lindyframe.utilities.LindyFrame_Utils;

/**
 *    The HTMLViewer class provides the main access point for
 * setting up the requirements for the HTMLView plugin module
 * for the lindyFrame framework.
 * 
 * @author Dana M. Proctor
 * @version 1.5 11/07/2016
 */

class HTMLViewer implements ActionListener
{
   // Class Instances
   private ImageIcon tabIcon;
   
   private GridBagLayout gridbag;
   private GridBagConstraints constraints;

   private JPanel mainPanel, urlEntryPanel, statusPanel;
   private JButton historyBackButton, historyForwardButton, refreshButton;
   private JTextField urlEntryTextField;
   private LinkedList historyList;
   protected HTMLEditorPane viewerPane;
   private JProgressBar progressBar;
   private JLabel statusLabel;

   private Viewer_MenuBar menuBar;
   private Viewer_ToolBar toolBar;

   private LindyFrame_ResourceBundle resourceBundle;
   
   private String loadingPageResource, pageNotFoundResource;
   private int stateHistoryIndex;

   private final static String VERSION = "Version 1.5";
   private final static String DESCRIPTION = "The HTMLViewer plugin provides a mean to demostrate a module"
                                             + " example for the lindyFrame framework. The plugin is a basic"
                                             + " HTML viewer that displays the tutorial for creating plugins"
                                             + " with lindyFrame.";
   
   private static final int STATE_HISTORY_LIMIT = 25;

   //==============================================================
   // HTMLViewer Constructor
   //==============================================================

   public HTMLViewer(Main_Frame parent, String path)
   {
      // Constructor Instances.
      String pathDirectory, localeDirectory, imagesDirectory;
      MenuActionListener pluginMenuListener;

      // Setup the Main panel and the plugin's components.

      mainPanel = new JPanel(new BorderLayout());

      // ** NOTE: file/local network only, locale resource not in JAR **
      pathDirectory = path + "/" + "HTMLViewer" + "/";
      localeDirectory = "locale/";
      imagesDirectory = "images/";

      // ** NOTE: http/ftp locale resource in JAR **
      // pathDirectory = path + "/" + "HTMLViewer.jar";
      // localeDirectory = "lib/plugins/HTMLViewer/locale/";
      // imagesDirectory = "lib/plugins/HTMLViewer/images/";

      resourceBundle = new LindyFrame_ResourceBundle(pathDirectory, LindyFrame.getDebug());
      resourceBundle.setLocaleResource(localeDirectory, "HTMLViewer", LindyFrame.getLocaleString());

      tabIcon = resourceBundle.getResourceImage(imagesDirectory + "icons/htmlViewerIcon.png");
      loadingPageResource = resourceBundle.getResourceString("HTMLViewer.label.LoadingPage", "Loading Page");
      pageNotFoundResource = resourceBundle.getResourceString("HTMLViewer.label.PageNotFound",
                                                              "Page Not Found");
      
      // Create the GUI components.
      
      gridbag = new GridBagLayout();
      constraints = new GridBagConstraints();

      // URL Entry Panel.
      initURLEntryPanel(imagesDirectory);
      mainPanel.add(urlEntryPanel, BorderLayout.NORTH);

      // HTML Panel.
      initViewer();
      mainPanel.add(new JScrollPane(viewerPane), BorderLayout.CENTER);

      // Status Panel
      initStatusPanel();
      mainPanel.add(statusPanel, BorderLayout.SOUTH);

      // Setup the MenuBar and ToolBar to be used by the plugin.

      pluginMenuListener = new MenuActionListener(parent, this, resourceBundle);
      menuBar = new Viewer_MenuBar(parent, resourceBundle, pluginMenuListener);
      toolBar = new Viewer_ToolBar("HTMLViewer ToolBar", parent, imagesDirectory, resourceBundle,
                                   pluginMenuListener);
      
      loadPage("file:"
         + LindyFrame_Utils.getResourceBundle().getResourceFile(
            "docs/Plugins/Tutorial/LindyFrame_PluginTutorial.html").getPath());
   }
~
~
~
~ 
   //==============================================================
   // Class method to to the plugin's JMenuBar
   //==============================================================

   protected JMenuBar getMenuBar()
   {
      return menuBar;
   }

   //==============================================================
   // Class method get the plugin's JToolBar
   //==============================================================

   protected JToolBar getToolBar()
   {
      return toolBar;
   }

   //==============================================================
   // Class method to get the main panel associated with the plugin.
   //==============================================================

   protected JPanel getPanel()
   {
      return mainPanel;
   }

   //==============================================================
   // Class method to get the plugin's version.
   //==============================================================

   protected String getVersion()
   {
      return VERSION;
   }

   //==============================================================
   // Class method to get the plugin's description.
   //==============================================================

   protected String getDescription()
   {
      return DESCRIPTION;
   }

   //==============================================================
   // Class method to get the icon that will be used in the
   // lindyFrame tab.
   //==============================================================

   protected ImageIcon getTabIcon()
   {
      return tabIcon;
   }
}
					

    The constructor for the HTMLViewer class like most classes is where the setup for the HTML Viewer plugin occurs. The first thing that is done in the constructor is to create the JPanel, mainPanel. This panel is the face of the plugin that users will see in the selected tab for the HTMLViewer module. The mainPanel has several components added to it in order to create the plugin and those objects are created in the helper methods not shown, but called through initURLEntryPanel(), initViewer(), and initStatusPanel(). Those methods are not pertinate to the discussion here since they just serve to help create the GUI for the HTML Viewer. Before the call to those additional methods it is noted that we begin the derivation of a resource reference for the plugin that is based on the path argument string in the constructor. LindyFrame has the capability of installing a plugin locally automatically from the lib/plugins directory or be loaded via the Plugin Management tool. When a developer creates the plugin a decision should be made to allow these local/remote resources to be either sourced in the JAR file of the plugin or not. Note; All plugins that will be loaded remotely, Internet, must store resouces in the JAR file.

In the HTMLViewer constructor we see the two ways that this may be implemented, one commented out. The example uses resources that will NOT be included in the JAR and uses three instances to derive the pathDirectory, localeDirectory, & imagesDirectory from the path and layout that was chosen by the plugin as shown in Figure 2. We then create a LindyFrame_ResourceBundle based on the pathDirectory and set the locale for the plugin. The language locale can be obtained directly from the LindyFrame API method getLocaleString(). That language locale string is chosen by the user when lindyFrame is first run or by argument to the application. Though one could use the standard Java API for a Resource object lindyFrame uses its own resource class which provides greater flexibility, and control in organizing resources in a plugin environment.

In the constructor we now see the use of a resource object. The tabIcon is acquired through the LindyFrame_ResourceBundle's getResourceImage(). In that method we pass the imagesDirectory and the name of the image file. The tabIcon will be returned through the class method getTabIcon() for the plugin module so that it may be displayed in lindyFrame's main tab pane. Likewise we may also use the resourceBundle object to obtain a getResourceString() that relates to properly displaying language aspects of the GUI for the locale.

    Now that all the main setup in the constructor has been accomplished then the only activities left to do is to create the menu and toolbar objects. The menu and toolbar objects for the plugin are created through two separate classes Viewer_MenuBar and Viewer_ToolBar. An Action Listener object is also created to handle the processing of events in the plugin. The Action Listener class, MenuActionListener, is not covered in this tutorial, but is supplied as a resource via links available at the end of this tutorial.

Note: Any classes given as part of this tutorial are covered by the GPL and may be used in accordance with that license.

HTMLViewer Viewer_MenuBar Class


    The last aspect of this advanced lindyFrame plugin tutorial that is to be dealt with is the creation of a custom menu bar and tool bar components for the plugin. LindyFrame allows each plugin to share its controls, action events, and create their own. As each plugin tab is selected in the main interface of lindyFrame the MenuBar and ToolBar for that plugin is activated and available for use. Since a tool bar houses essential duplicate items in the form of buttons with icons as a menu system we will just review the MenuBar object for the HTMLViewer plugin.

The partial Code Listing 4. shown below is of the HTMLViewer's Viewer_MenuBar class. Though the menu systems has both a File and Edit entry all that is needed to demonstrate the desired concepts is the creation of the File menu. What one should note immediately about this class is it extends the Java JMenuBar component so that its meets the needs of a standard MenuBar. The constructor for the Viewer_MenuBar class is straight forward with the assignment of the three passed arguments to class instances. Remember those objects were the lindyFrame main frame, the resourceBundle, and the custom Action Listener object. Up to this point we have not used the lindyFrame main frame object, but we will shortly. The constructor code continues with calling two helper methods to build the file and edit menu systems and then producing a custom logo object. Of interest here is the use of the LindyFrame_Utils class to obtain the icons directory and loading one of lindyFrame's own icon images for the logo.

Code Listing 3: (HTMLViewer Viewer_MenuBar.java)

//=================================================================
//                  HTMLViewer Viewer_MenuBar
//=================================================================
//
//    This class is used to constructed the menubar for the HTML
// Viewer plugin module.
//
//                 < Viewer_MenuBar.java >
//
//=================================================================
// Copyright (C) 2013 Dana M. Proctor.
// Version 1.0 07/27/2013
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
~
~
~
// Version 1.0 07/27/2013 Original Viewer_MenuBar Class.
//
//-----------------------------------------------------------------
//                 danap@dandymadeproductions.com
//=================================================================

package com.dandymadeproductions.htmlviewer;

import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import com.dandymadeproductions.lindyframe.LindyFrame;
import com.dandymadeproductions.lindyframe.gui.LindyFrame_MenuActionCommands;
import com.dandymadeproductions.lindyframe.gui.Main_Frame;
import com.dandymadeproductions.lindyframe.utilities.LindyFrame_ResourceBundle;
import com.dandymadeproductions.lindyframe.utilities.LindyFrame_Utils;

/**
 *    The Viewer_MenuBar class is used to constructed the menubar for
 * the HTML Viewer plugin module.
 * 
 * @author Dana M. Proctor
 * @version 1.0 07/27/2013
 */

class Viewer_MenuBar extends JMenuBar
{
   // Instance & Class Fields.
   private static final long serialVersionUID = -6134364585633519070L;

   private Main_Frame mainFrame;
   private LindyFrame_ResourceBundle resourceBundle;
   private MenuActionListener menuListener;

   public static final String ACTION_FILE_OPEN = "File Open";
   public static final String ACTION_EDIT_SEARCH = "Edit Search";

   //==============================================================
   // Viewer_MenuBar JMenuBar Constructor.
   //==============================================================

   protected Viewer_MenuBar(Main_Frame parent, LindyFrame_ResourceBundle resourceBundle,
                            MenuActionListener plugin)
   {
      mainFrame = parent;
      this.resourceBundle = resourceBundle;
      menuListener = plugin;

      // Constructor Instances.
      String iconsDirectory;

      // JMenu Bar for the plugin.
      setBorder(BorderFactory.createEtchedBorder());

      // Creating the File, and Tools Menus
      createFileMenu();
      createEditMenu();

      add(Box.createHorizontalGlue());

      // Logo
      iconsDirectory = LindyFrame_Utils.getIconsDirectory() + LindyFrame_Utils.getFileSeparator();
      ImageIcon logoIcon = LindyFrame.getResourceBundle().getResourceImage(iconsDirectory
                                                                           + "lindyFrameIcon.gif");
      JButton logoIconItem = new JButton(logoIcon);
      logoIconItem.setDisabledIcon(logoIcon);
      logoIconItem.setFocusPainted(false);
      logoIconItem.setBorder(BorderFactory.createLoweredBevelBorder());
      add(logoIconItem);
   }

   //==============================================================
   // Helper Method to create the File Menu.
   //==============================================================

   private void createFileMenu()
   {
      // Method Instances.
      String resource;
      JMenu fileMenu;
      JMenuItem item;

      // ===========
      // File Menu

      resource = resourceBundle.getResourceString("Viewer_MenuBar.menu.File",
                                                  "File");
      fileMenu = new JMenu(resource);
      fileMenu.setFont(fileMenu.getFont().deriveFont(Font.BOLD));

      // Open
      resource = resourceBundle.getResourceString("Viewer_MenuBar.menu.Open",
                                                  "Open");
      fileMenu.add(menuItem(resource, ACTION_FILE_OPEN));
      fileMenu.addSeparator();

      // Exit
      resource = resourceBundle.getResourceString("Viewer_MenuBar.menu.Exit",
                                                  "Exit");
      item = new JMenuItem(resource);
      item.addActionListener(mainFrame);
      item.setActionCommand(LindyFrame_MenuActionCommands.ACTION_EXIT);
      fileMenu.add(item);

      add(fileMenu);
   }
   
   //==============================================================
   // Helper Method to create the Edit Menu.
   //==============================================================

   private void createEditMenu()
   {
      // Method Instances.
      String resource;
      JMenu editMenu;

      // ===========
      // Edit Menu

      resource = resourceBundle.getResourceString("Viewer_MenuBar.menu.Edit",
                                                  "Edit");
      editMenu = new JMenu(resource);
      editMenu.setFont(editMenu.getFont().deriveFont(Font.BOLD));

      // Search
      resource = resourceBundle.getResourceString("Viewer_MenuBar.menu.Search",
                                                  "Search");
      editMenu.add(menuItem(resource, ACTION_EDIT_SEARCH));
     
      add(editMenu);
   }
   
   //==============================================================
   // Instance method used for the creation of menu bar items.
   // Helper Method.
   //==============================================================

   private JMenuItem menuItem(String label, String actionLabel)
   {
      JMenuItem item = new JMenuItem(label);
      item.addActionListener(menuListener);
      item.setActionCommand(actionLabel);
      return item;
   }
}
					

    Moving forward with the menu systems for the plugin we have the class method createFileMenu(). Here is where we will create a File menu with sub items of File | Open, and File | Exit. The first is basic in nature and is derived by using the resourceBundle.getResourceString() and calling an additional helper method to create the JMenuItem. Note we assign an ActionListener for that sub item of the custom MenuActionListener, menuListener, in the helper method menuItem(). The last menu sub item is slightly different from the first because it is a call to exit the application. It is done via one of lindyFrame's own action events that is part of main frame. We find the action event needed by making a reference to the LindyFrame_MenuActionCommands class. In this case the action command string is ACTION_EXIT. We complete the File menu by adding the JMenu to the classes' own add method.

Summary


    In this lindyFrame plugin tutorial we have discussed the implementation of the HTMLViewer plugin. The HTML Viewer module was chosen because it demonstrates advanced features that a plugin may need in order to accomplish its purposes. Some of those advanced aspects of plugin creation have to do with returning a version string and tab icon image for the lindyFrame's tabbed pane. Other requirements that a plugin may need to implement is language support. LindyFrame provides a class, LindyFrame_ResourceBundle, and a method to return user selected locale information via LindyFrame.getLocaleString() to accomplish this goal. LindyFrame determines the location of resources via the path string object that is passed to the initPlugin() method of the PluginModule class. The final advanced features that a plugin may wish to produce is a menu and tool bar components. The PluginModule class provides a means to return those objects so they may be assigned to the tab interface for the plugin. In addition lindyFrame also makes its own menu items, and action events available to a plugin via the Main_Frame class and its corresponding action commands in the LindyFrame_MenuActionCommands class.


Resources

LindyFrame_PluginModule Class
PluginModule Class
HTMLViewer Main Class
MenuActionListener Class
Viewer_MenuBar Class
Viewer_ToolBar Class