# Lab-5540: Save Time—Build Desktop Applications Quickly with the NetBeans Platform

Expected Duration: 100 minutes
Contacts: Jiri Rechtacek, Lukas Hasik

Introduction | Exercise 0 | Exercise 1 | Exercise 2 | Exercise 3 | Exercise 4 | Summary
2. Introduction Background Information Steps to Follow Summary ## Exercise 3: Create a admin module for Anagram Application (30 minutes) ### Background Information In the previous exercise we prepared the JavaOne 2009 Anagram Application built on top of NetBeans Platform. It allows to start new game and store, visualize the best results. We will create new module Word Scrambler to improve the functionality of this application. Word Scrambler will serve as admin module for the Anagram Application. We prepared this module for you as its functionality is very complex to be covered in the HOL. What does Word Scrambler provide? It can read a text from file, makes pairs of scrambled and unscrambled words from the read text. And in addition it makes words with fixed length by a given parameter that express the complexity. We need to provide some UI for calling this code and then establish a way to exchange words between Anagram Application and Word Scrambler. ### Steps to Follow Step 1: Add new module into application Open project Word Scrambler in `<lab_root>/exercises/exercise3/` in NetBeans IDE Add Existing Module Word Scrambler to the JavaOne 2009 Anagram Application module. Double click the new module to open it in NetBeans IDE. Step 2: Run the test in Unit Test packages To run all tests of project just open the popup menu of Word Scrambler project and choose Test menu item or use a short cut Alt-F6. Check the test results. All test should pass. Step 3: Create a main window of Word Scrambler module Create new Window Component in org.javaone.scrambler package in Word Scrambler module like in Exercise 1, Step 6. Component should be docked into editor mode. It should open on application start. Use prefix AnalyzeText. Open the class `AnalyzeTextTopComponent` that was created by the Window Component wizard. Use Design button and sketch out UI. The UI should like on following picture: Use following naming and components, please
   Swing Component | Text | Variable Name
   --- | --- | ---
   JLable | File | lFile
   JTextField | <none> | tfFile
   JButton | &Browse | bBrowse
   JButton | &Analyze | bAnalyze
   JButton | &Upload to Anagram Game | bUpload
   JLabel | Word Scrambler has 4 complexity | lComplexity
   JList | <No words> | lWords
3. Add new private fields to the AnalyzeTextTopComponent class.
            private File textFile;
            private Scrambler scrambler;
4. Add a handling of `actionPerformed` event for the Browse button. Tip: Invoke a popup over Browse button in UI designer and then choose Events|Action|actionPerformed. It will create the actionPerform method and give focus into the right place in editor. In editor type following code that opens `JFileChooser` when you press Browse button.
            private void bBrowseActionPerformed(java.awt.event.ActionEvent evt) {
                JFileChooser chooser = new JFileChooser();
                chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
                chooser.setMultiSelectionEnabled (false);
                chooser.setFileHidingEnabled (true);
                chooser.setDialogTitle ("Select a text file");
                if (chooser.showOpenDialog (this) == JFileChooser.APPROVE_OPTION) {
                    textFile = chooser.getSelectedFile ();
                    tfFile.setText(textFile.getPath());
                    bAnalyze.setEnabled(true);
                }
            }
6. It also sets the chosen file as content of the File textfield. Fix imports. File - java.io.File Using as same way as before now to add a code handling the bAnalyze button. Analyze button should scramble text of given file. Tip: You can use `<lab_root>/words.txt` file to play with the Analyze functionality.
            private void bAnalyzeActionPerformed(java.awt.event.ActionEvent evt) {
                File f = new File(tfFile.getText());
                if (! f.exists()) {
                    NotifyDescriptor.Message nd = new NotifyDescriptor.Message
                            ("The file " + f.getPath() + " doesn't exist!", NotifyDescriptor.ERROR_MESSAGE);
                    DialogDisplayer.getDefault().notify(nd);
                    bUpload.setEnabled(false);
                    bAnalyze.setEnabled(false);
                    return;
                }
                String text = File2String.file2string(f);
                scrambler = new Scrambler(text, pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4));
                lWords.setListData(scrambler.getWords());
                bUpload.setEnabled(true);
                bAnalyze.setEnabled(false);
            }
6. Please, do not bother about the error of missing pref variable. We will fix it in next steps. Step 4: Add new options to NetBeans Options framework Invoke New > Other on org.javaone.scrambler package in WordScrambler module. Choose Options Panel in Module Development category. Select Create Primary Panel radio button. Use value as on picture bellow. Browse the icon anagram32.png in `<lab_root>/exercise3` directory. Class Name Prefix should be ScramblerComplexity. Design the Scrambler Options Panel. Open ScramblerComplexityPanel. Add one label and one combo box to design. Change the model of the combo box in Properties. Implement both effective methods load() and store() of the options panel in source code of ScramblerComplexityPanel class. These methods store and load the options to be persistent even during several starts of the application. As you can see from the following code we used NbPreferences functionality that makes it quite simple.
            private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);

            void load() {
                int complex = pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4);
                jComboBox1.setSelectedItem(Integer.toString(complex));
            }

            void store() {
                String complex = (String) jComboBox1.getSelectedItem();
                pref.putInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, new Integer (complex));
                AnalyzeTextTopComponent.getDefault().setComplexity(complex);
            }

            boolean valid() {
                return true;
            }
7. Add new SCRAMBLER_COMPLEXITY field into the ScramblerComplexityOptionsPanelController class.
            public static final String SCRAMBLER_COMPLEXITY = "scrambler_complexity";
8. Create new method setComplexity(String complex) in AnalyzeTextTopComponent class.
            void setComplexity(String complex) {
                lComplexity.setText("Word Scrambler has " + complex + " complexity.");
                boolean canAnalyze = new File(tfFile.getText()).exists();
                bAnalyze.setEnabled(canAnalyze);
                bUpload.setEnabled(false);
            }
9. Now we have to modify the constructor of the AnalyzeTextTopComponent class to setup the complexity according to value selected in Options.
            public AnalyzeTextTopComponent() {
                initComponents();
                setComplexity(pref.get(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, "4"));
                bAnalyze.setEnabled(false);
                bUpload.setEnabled(false);
                setName(NbBundle.getMessage(AnalyzeTextTopComponent.class, "CTL_AnalyzeTextTopComponent"));
                setToolTipText(NbBundle.getMessage(AnalyzeTextTopComponent.class, "HINT_AnalyzeTextTopComponent"));
           }
10. Add new private field pref for reading the preferences in the AnalyzeTextTopComponent class.
             private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);
1. To be able to Fix Imports you will have to add new dependency on Dialogs API library first. Delete all other instances from OptionsCategory.createCategory except the one that we created from the layer file. The one created by us is in bold. In this way you'll mask out the other Options Panels. Step 5: Make a relation between Anagram Game module and this Word Scrambler admin module NetBeans Platform Module System discriminates between public and private modules and a module can uses only classes from public part of modules. Only a part of a module is visible to the rest of modules. This public part that is visible to other modules is known as the public packages. We have to explicitly indicate that a Java packages of Anagram Game project are visible to Word Scrambler module. Make org.javaone.anagram.lib package public. It will allow us to use it in other modules. Add Anagram Game JavaOne 2009 as a new dependency of Word Scrambler module. Please, note that Anagram is Non-API module, don't forget to check the Show Non-API Modules checkbox. Step 6: Post new words into Anagram Game Create new class AdditionalWordLibrary extending org.javaone.anagram.lib.WordLibrary in the org.javaone.scrambler package.
        /*
         * To change this template, choose Tools | Templates
         * and open the template in the editor.
         */

        package org.javaone.scrambler;

        import org.javaone.anagram.lib.WordLibrary;

        /**
         *
         * @author jirka
         */
        public class AdditionalWordLibrary extends WordLibrary {
            private final String[] words;
            private final String[] scramblers;
            private final int size;

            public AdditionalWordLibrary (final String [] words, final String [] scramblers) {
                this.words = words;
                this.scramblers = scramblers;
                this.size = words.length;
            }

            @Override
            public String getWord(int idx) {
                assert idx < size;
                return words[idx];
            }

            @Override
            public String getScrambledWord(int idx) {
                assert idx < size;
                return scramblers[idx];
            }

            @Override
            public int getSize() {
                return size;
            }

            @Override
            public boolean isCorrect(int idx, String userGuess) {
                assert idx < size;
                return words [idx].equalsIgnoreCase(userGuess);
            }

        }
3. Now we have to use the dynamic approach of the AdditionalWordLibrary and connect it with the AnalyzeTextTopComponent. Create action handler for the Upload to Anagram Game button at AnalyzeTextTopComponent. Right click the Upload button and choose Events > Action > actionPerformed. Post scrambler words from Scrambler into Anagram Game. Add following code to AnalyzeTextTopComponent.
            private void bUploadActionPerformed(java.awt.event.ActionEvent evt) {
                // upload to Anagram Game
                WordLibrary wd = new AdditionalWordLibrary (scrambler.getWords(), scrambler.getScrambledWords());
                WordLibrary.setDefault(wd);
                bUpload.setEnabled(false);
                bAnalyze.setEnabled(false);
            }
1. Fix imports. Step 6: Run the application We removed all the menu items in Exercise 1 therefore we have to delete following line from XML Layer file under Important Files in Anagram JavaOne 2009 project.
             <file name="Tools_hidden"/>
### Summary In this exercise we created new module that allows to manage the words in the anagram game. You learned how to design new top component and how to use a module as library. You should know how to add new panel to Options and how to store and load their values. Back to top Next exercise