Displaying or hiding navigator buttons at run time

At run time, you can hide or show NavigatorControl buttons in response to user actions or application states. For example, suppose you provide a single navigator for navigating through two different data sets, one read/write, and the other read-only. When you switch between data sets, you want to hide the navigator's Insert, Delete, Post, Cancel, Ditto, Save, and Refresh buttons when viewing the read-only data set, but show these buttons when viewing the editable data set.

Suppose you want to prevent edits to the DEPARTMENT table by hiding the Insert, Delete, Post, Cancel, Ditto, Save, and Refresh buttons on the navigator, but you also want to allow editing for the EMPLOYEE table. By default, all possible buttons are displayed. The following sections provide an example of how you might code this application. It also provides code for allowing two data sets to share a status bar. The information displayed in the status bar depends on which data set is active.

Example: Sharing a visual control between two data sets

The first steps of this example add a Database component and two QueryDataSet components, link the data sets on the DEPT_NO field, and connect the data sets to visual controls. The remaining steps provide the code necessary to determine which data set has focus and to customize the navigator accordingly. The completed application can be viewed as a finished project in the sample project VisualEvents.jpr, located in the samples/borland/samples/tutorial/dataset/VisualEvents directory of your JBuilder installation. To create this application,

  1. Select File|Close All. Select File|New, then double-click the Application icon. Accept all defaults.

  2. Add a Database component to the Frame file. Open the connection property editor for the Database component by selecting the connection property in the Inspector. Set the connection properties to the Local InterBase sample tables:
    Property name Value
    Connection URL jdbc:odbc:DataSet Tutorial
    Username SYSDBA
    Password masterkey

    The code generated by the designer for this step is:

    database1.setConnection(new borland.jbcl.dataset.ConnectionDescriptor
      ("jdbc:odbc:DataSet Tutorial", "SYSDBA", "masterkey", false,    "sun.jdbc.odbc.JdbcOdbcDriver"));

    Click the Test Connection button to check that the connection properties have been correctly set. Results of the connection attempt are displayed in the gray area below the button.

  3. Add a QueryDataSet component. Select the component in the Component tree and set the query property of queryDataSet1 in the Inspector as follows:

    The code generated by this step is:

    queryDataSet1.setQuery(new borland.jbcl.dataset.QueryDescriptor(database1, "select * from department", null, true, false));

    Click Test Query to ensure that the query is runnable. When the gray area beneath the button indicates Success, click OK to close the dialog.

  4. Add a second QueryDataSet component. Select the component in the Component tree and set the query property of queryDataSet2 in the Inspector as follows:

    The code generated by this step is:

    queryDataSet1.setQuery(new borland.jbcl.dataset.QueryDescriptor(database1, "select * from employee", null, true, false));

    Click Test Query to ensure that the query is runnable. When the gray area beneath the button indicates Success, click OK to close the dialog.

  5. Select queryDataSet2 and select the masterLink property from the Properties page of the Inspector. This step will establish a master-detail relationship between the data sets, making queryDataSet1 the master table, and queryDataSet2 the detail table. In the masterLink custom property editor, specify the following properties:

    The code generated by this step is:

    queryDataSet2.setMasterLink(new MasterLinkDescriptor(queryDataSet1, new String[] {"DEPT_NO"}, new String[] {"DEPT_NO"}, false));

  6. Add two GridControls. Set the dataSet property of gridControl1 to queryDataSet1. Set the dataSet property of gridControl2 to queryDataSet2.

    The code generated by this step is:

    gridControl1.setDataSet(queryDataSet1);
    gridControl2.setDataSet(queryDataSet2);

Now that the components we need to access and view data are complete, the next step is to add the navigator control and the code that will enable it to display differently depending on which data set has focus.

  1. Add a NavigatorControl from the JBCL tab to the UI Designer.

  2. Add the following code to the jbInit() method of the Frame file to define which navigator buttons to display for each data set, instantiate a listener for each data set, and tie each listener to its grid. Note that only one status bar and one navigator control are instantiated. The data set that has focus will determine which set of navigator buttons are displayed and which data set's status to display.

    Tip: If you are only using one NavigatorControl for one data set, you can choose which buttons to display using the Property Inspector.

          //define which navigator buttons to show for each data set    
          int[] grid1EnabledFlags = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };  
          int[] grid2EnabledFlags = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 
    	
          //instantiate a listener for each data set
          FocusListener grid1Focus = new VisualEvents_Focus(this, queryDataSet1,
            grid1EnabledFlags); 
          FocusListener grid2Focus = new VisualEvents_Focus(this, queryDataSet2,
            grid2EnabledFlags);
    
          //tie each listener to its grid
          gridControl1.addFocusListener(grid1Focus); 
          gridControl2.addFocusListener(grid2Focus);
    
  3. Write the FocusListener class. In this example, we use an instance of the focusListener for each data set. You can use this code, or you can write your own method that keeps all the data in the frame class, instantiates only one focusListener, and uses the gridFocusGained method to determine which data set got focus and customize the grid accordingly.

    This class gets data members when it is constructed and passes them on when gridFocusGained happens.

    package borland.samples.tutorial.dataset.visualevents;
    
    import java.awt.*;
    import java.awt.event.*;
    import borland.SQL.dataset.QueryDataSet;
    
    public class VisualEvents_Focus implements FocusListener {
      VisualEvents_Frame target;
      QueryDataSet       qds;
      int[]              navEnabledFlags;
    
      public VisualEvents_Focus(VisualEvents_Frame target, QueryDataSet qds,
        int[] navEnabledFlags) {
        this.target = target;
        this.qds = qds;
        this.navEnabledFlags = navEnabledFlags;
      }
    
      public void focusGained(FocusEvent focusEvent) {
        target.gridFocusGained(qds, navEnabledFlags);
      }
    
      public void focusLost(FocusEvent parm1) { }
    }
    

  4. Add the following code to handle the focus event for either grid. The parameters tell us what we need to know to customize behavior depending on which grid got focus.
      // set navigator and statusBar properties for the grid that got focus
      public void gridFocusGained(QueryDataSet qds, int[] navEnabledFlags) {
    	
        navigatorControl1.setDataSet(qds);
        for (int i = 0; i < navEnabledFlags.length; ++i)
          navigatorControl1.setButtonEnabled(i, navEnabledFlags[i] == 1);
        statusBar1.setDataSet(qds);
      }
    

This concludes the re-creation of the sample application VisualEvents.jpr and the demonstration of using a single navigator for two data sets. The finished application looks like the following. Notice that when you are in the DEPARTMENT table, the Insert, Delete, Post, Cancel, Ditto, Save, and Revert buttons are disabled, disallowing changes to that table.