Implementing the text editor canvas

The LoginView, NewPostView, and NewCommentView classes utilize the canvas text editor control (the TextEditor class), which provides a customizable appearance and full text editing features with the QWERTY keyboard. The Canvas-based text editor is very useful in applications with a custom UI, since the QWERTY keyboard eases the use of applications that depend on entering large amounts of text, and the text editor is easy to use since the canvas QWERTY input support requires no extra effort.

The following figure shows the class diagram related to the text editor features of the MIDlet.

Figure: Text editor classes

The following step list shows how to implement the text editor in the LoginView class, which displays the login view of the MIDlet. The implementation for the NewPostView and NewCommentView classes is similar.

Figure: Login view

To implement the text editor in the LoginView class:

  1. Create the LoginView.java class file.

  2. Import the required classes.

    import com.nokia.example.wordpress.components.OptionsMenu;
    import com.nokia.example.wordpress.helpers.KeyCodes;
    import com.nokia.mid.ui.TextEditor;
    import com.nokia.mid.ui.TextEditorListener;
    import javax.microedition.lcdui.Font;
    import javax.microedition.lcdui.Graphics;
    import javax.microedition.lcdui.TextField;
  3. Set LoginView to extend BaseView and implement TextEditorListener. MIDlets use the TextEditorListener interface to receive notifications of content changes and other editor events from the TextEditor objects. Define three text editors for the login view.

    public class LoginView extends BaseView implements TextEditorListener {
    
        private TextEditor usernameEditor;
        private TextEditor passwordEditor;
        private TextEditor blogUrlEditor;
        private Font font = Visual.SMALL_FONT;
        private int fontHeight = font.getHeight();
  4. In the class constructor, set up the text editors for getting the login information. When creating a text editor, you must define various visual settings. The most important one is the setParent method call, which makes the editor appear on the canvas and therefore the screen. In this case, the ViewMaster class represents the canvas.

        LoginView(Graphics g, int x, int y, int width, int height) {
            super(g, ViewMaster.VIEW_LOGIN, x, y, width, height);
            haveTabs = false;
    
            int border = 2;
            int editorWidth = width - 2 * border;
    
            // Reserve three rows at the top for text
            int yPosition = fontHeight * 3;
    
            usernameEditor = TextEditor.createTextEditor(32, TextField.ANY, editorWidth, 1);
            usernameEditor.setFont(font);
            usernameEditor.setBackgroundColor(Visual.EDITOR_ACTIVE_BACKGROUND_COLOR);
            usernameEditor.setForegroundColor(Visual.EDITOR_ACTIVE_FOREGROUND_COLOR);
            usernameEditor.setContent(data.getLoginUsername());
            usernameEditor.setParent(viewMaster);
            usernameEditor.setPosition(border, yPosition);
            usernameEditor.setVisible(false);
            usernameEditor.setTextEditorListener(this);
    
            // Reserve some space for text for draw()
            yPosition += fontHeight + usernameEditor.getHeight();
    
            passwordEditor = TextEditor.createTextEditor(32, TextField.ANY, editorWidth, 1);
            passwordEditor.setFont(font);
            passwordEditor.setBackgroundColor(Visual.EDITOR_PASSIVE_BACKGROUND_COLOR);
            passwordEditor.setForegroundColor(Visual.EDITOR_PASSIVE_FOREGROUND_COLOR);
            passwordEditor.setContent(data.getLoginPassword());
            passwordEditor.setParent(viewMaster);
            passwordEditor.setPosition(border, yPosition);
            passwordEditor.setVisible(false);
            passwordEditor.setTextEditorListener(this);
    
            yPosition += fontHeight + usernameEditor.getHeight();
    
            blogUrlEditor = TextEditor.createTextEditor(200, TextField.ANY, editorWidth, 3);
            blogUrlEditor.setFont(font);
            blogUrlEditor.setBackgroundColor(Visual.EDITOR_PASSIVE_BACKGROUND_COLOR);
            blogUrlEditor.setForegroundColor(Visual.EDITOR_PASSIVE_FOREGROUND_COLOR);
            blogUrlEditor.setContent(data.getBlogUrl());
            blogUrlEditor.setParent(viewMaster);
            blogUrlEditor.setPosition(border, yPosition);
            blogUrlEditor.setVisible(false);
            blogUrlEditor.setTextEditorListener(this);
  5. At the end of the class constructor, add an options menu with an exit option, and labels for the three soft keys.

            // Create options menu
            menu = new OptionsMenu(width, height) {
    
                {
                    addExitItem();
                }
            };
    
            softkey1Label = "Options";
            softkey2Label = "Login";
            softkey3Label = "Exit";
        }
  6. When the login view becomes active, the activate method makes the text editors visible and gives the focus to the first one, which receives the subsequent key events.

        public void activate() {
            System.out.println("login activate");
            super.activate();
    
            usernameEditor.setVisible(true);
            usernameEditor.setFocus(true);
            passwordEditor.setVisible(true);
            passwordEditor.setFocus(false);
            blogUrlEditor.setVisible(true);
            blogUrlEditor.setFocus(false);
        }
  7. The deactivate method hides the text editors. The draw method is used to draw UI text between the text editors.

        public void deactivate() {
            System.out.println("login deactivate");
            usernameEditor.setVisible(false);
            passwordEditor.setVisible(false);
            blogUrlEditor.setVisible(false);
        }
    
        public void draw(int x, int y, int width, int height) {
            System.out.println("login render");
            if (menu.isVisible()) {
                menu.draw(g);
                return;
            }
            viewMaster.drawBackground(g, x, y, width, height, false);
    
            // Draw some text between the text editors.
            g.setColor(Visual.LIST_PRIMARY_COLOR);
            g.setFont(Visual.SMALL_BOLD_FONT);
            g.drawString("Wordpress login", width / 2, 0, g.TOP | g.HCENTER);
            g.setFont(Visual.SMALL_FONT);
            g.setColor(Visual.LOGIN_MESSAGE_COLOR);
            // This may contain an error message from the previous logging attempt.
            g.drawString(data.getLoginMessage(), width / 2, fontHeight, g.TOP | g.HCENTER);
            g.setColor(Visual.LIST_PRIMARY_COLOR);
            g.drawString("Username:", width / 2, usernameEditor.getPositionY() - fontHeight, g.TOP | g.HCENTER);
            g.drawString("Password:", width / 2, passwordEditor.getPositionY() - fontHeight, g.TOP | g.HCENTER);
            g.drawString("Blog URL:", width / 2, blogUrlEditor.getPositionY() - fontHeight, g.TOP | g.HCENTER);
            drawSoftkeys();
        }
  8. When the user has entered the required information, the Selection Key press is checked in the keyReleased method. The MIDlet reads the editor content with the getContent method, and passes it to an application data object. Finally, since the login phase is done, the view is changed to the loader view.

        public void keyReleased(int keyCode) {
    
            if (menu != null && menu.notifyKeyEvents(keyCode)) {
                // menu used this keycode, let's not use for anything else.
                viewMaster.draw();
                return;
            }
    
            switch (keyCode) {
                case KeyCodes.MIDDLE_SOFTKEY:
                    data.setLoginUsername(usernameEditor.getContent());
                    data.setLoginPassword(passwordEditor.getContent());
                    data.setBlogUrl(blogUrlEditor.getContent());
                    viewMaster.setView(ViewMaster.VIEW_LOADER);
                    break;
                case KeyCodes.RIGHT_SOFTKEY:
                    midlet.commandExit();
                    break;
                default:
                    break;
    
            }
        }
  9. The TextEditorListener.inputAction method determines which of the three editors receives the focus by checking for the ACTION_TRAVERSE_NEXT and ACTION_TRAVERSE_PREVIOUS actions. Depending on the current action, the correct editor receives the focus and the others lose it. Similarly, the editor background colors are modified to indicate the active editor to the user.

        public void inputAction(TextEditor editor, int actions) {
            // Set focus to a correct editor.
            if ((actions & TextEditorListener.ACTION_TRAVERSE_NEXT) != 0) {
                if (editor == usernameEditor) {
                    usernameEditor.setFocus(false);
                    passwordEditor.setFocus(true);
                }
                if (editor == passwordEditor) {
                    passwordEditor.setFocus(false);
                    blogUrlEditor.setFocus(true);
                }
            }
    
            if ((actions & TextEditorListener.ACTION_TRAVERSE_PREVIOUS) != 0) {
                if (editor == blogUrlEditor) {
                    passwordEditor.setFocus(true);
                    blogUrlEditor.setFocus(false);
                }
                if (editor == passwordEditor) {
                    usernameEditor.setFocus(true);
                    passwordEditor.setFocus(false);
                }
            }
    
            // Set colors to indicate active and passives states.
            if (usernameEditor.hasFocus()) {
                usernameEditor.setBackgroundColor(Visual.EDITOR_ACTIVE_BACKGROUND_COLOR);
                usernameEditor.setForegroundColor(Visual.EDITOR_ACTIVE_FOREGROUND_COLOR);
            } else {
                usernameEditor.setBackgroundColor(Visual.EDITOR_PASSIVE_BACKGROUND_COLOR);
                usernameEditor.setForegroundColor(Visual.EDITOR_PASSIVE_FOREGROUND_COLOR);
            }
            if (passwordEditor.hasFocus()) {
                passwordEditor.setBackgroundColor(Visual.EDITOR_ACTIVE_BACKGROUND_COLOR);
                passwordEditor.setForegroundColor(Visual.EDITOR_ACTIVE_FOREGROUND_COLOR);
            } else {
                passwordEditor.setBackgroundColor(Visual.EDITOR_PASSIVE_BACKGROUND_COLOR);
                passwordEditor.setForegroundColor(Visual.EDITOR_PASSIVE_FOREGROUND_COLOR);
            }
            if (blogUrlEditor.hasFocus()) {
                blogUrlEditor.setBackgroundColor(Visual.EDITOR_ACTIVE_BACKGROUND_COLOR);
                blogUrlEditor.setForegroundColor(Visual.EDITOR_ACTIVE_FOREGROUND_COLOR);
            } else {
                blogUrlEditor.setBackgroundColor(Visual.EDITOR_PASSIVE_BACKGROUND_COLOR);
                blogUrlEditor.setForegroundColor(Visual.EDITOR_PASSIVE_FOREGROUND_COLOR);
            }
        }
    }