com.the.todo.MainToDoController.java Source code

Java tutorial

Introduction

Here is the source code for com.the.todo.MainToDoController.java

Source

/**
 * This file is part of TheTODO, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2014 TheTODO
 * Copyright (c) Poh Wei Cheng <calvinpohwc@gmail.com>
 *             Chen Kai Hsiang <kaihsiang95@gmail.com>
 *             Khin Wathan Aye <y.caiyun@gmail.com>
 *             Neo Eng Tai <neoengtai@gamil.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.the.todo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

import org.joda.time.LocalDateTime;

import com.the.todo.Logic.DateCategory;
import com.the.todo.command.CommandStatus;
import com.the.todo.command.CommandStatus.Status;
import com.the.todo.model.ToDo;
import com.the.todo.task.ReminderTask;

public class MainToDoController {

    @FXML
    private BorderPane mainPane;
    @FXML
    private Pane appTitleIcon;
    @FXML
    private Button minimizeButton;
    @FXML
    private ScrollPane mainScrollpane;
    @FXML
    private VBox mainVBox;
    @FXML
    private Label promptLabel;
    @FXML
    private TextField mainInput;
    @FXML
    private Label hintLabel;

    private Logic appLogic = Logic.getInstance();
    private CommandHistory commandHistory = new CommandHistory();
    private FadeTransition fadeOut;
    private ArrayList<Object> oldItems = new ArrayList<Object>();

    /************************ ALL HANDLERS ***************************/
    private EventHandler<KeyEvent> ctrlUpHandler;
    private EventHandler<KeyEvent> ctrlDownHandler;
    private EventHandler<KeyEvent> ctrlZHandler;
    private EventHandler<KeyEvent> upHandler;
    private EventHandler<KeyEvent> downHandler;
    private ChangeListener<Boolean> mainInputFocusListener;
    private ChangeListener<String> inputChangeListener;

    // @author A0119764W
    @FXML
    void initialize() {
        mainPane.applyCss();
        mainPane.layout();

        mainScrollpane.setFitToWidth(true);
        appTitleIcon.minWidthProperty().bind(appTitleIcon.heightProperty());

        fadeOut = new FadeTransition(Duration.millis(1500), promptLabel);
        fadeOut.setDelay(Duration.millis(2000));

        initilizeHandlers();
        mainPane.addEventFilter(KeyEvent.KEY_PRESSED, ctrlUpHandler);
        mainPane.addEventFilter(KeyEvent.KEY_PRESSED, ctrlDownHandler);
        mainPane.addEventFilter(KeyEvent.KEY_PRESSED, ctrlZHandler);

        mainInput.addEventFilter(KeyEvent.KEY_PRESSED, upHandler);
        mainInput.addEventFilter(KeyEvent.KEY_PRESSED, downHandler);
        mainInput.focusedProperty().addListener(mainInputFocusListener);
        mainInput.textProperty().addListener(inputChangeListener);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                mainInput.requestFocus();
                updateUI(appLogic.getToDoMapDisplay());
                oldItems.addAll(mapToList(appLogic.getToDoMapDisplay()));
                scrollToToday();
                generateAllReminders();
            }
        });
    }

    // @author A0112969W
    /**
     * Processes user input upon enter pressed.
     */
    public void processInput() {
        String userInput = mainInput.getText();
        if (userInput == null || userInput.equals("")) {
            return;
        }

        commandHistory.add(userInput);

        processInput(userInput);
    }

    public void processInput(String userInput) {
        CommandStatus status = appLogic.processCommand(userInput);

        switch (status.getStatus()) {
        case SUCCESS:
            Map<DateCategory, List<ToDo>> newDisplayMap = appLogic.getToDoMapDisplay();
            List<Object> newDisplayList = mapToList(newDisplayMap);

            switch (appLogic.getLastCommand()) {
            /* SINGLE CHANGES COMMAND */
            case ADD:
            case EDIT:
            case COMPLETE:
            case INCOMPLETE:
            case UNDO:
                ToDo lastChangedToDo = appLogic.getLastChangedToDo();
                int changedPosition = newDisplayList.indexOf(lastChangedToDo);

                updateUI(newDisplayMap);
                if (changedPosition != -1) {
                    scrollToIndex(changedPosition);
                    highlightItem(changedPosition);
                }

                break;

            case DELETE:
                updateUI(newDisplayMap);
                showPrompt("Deleted successfully", Status.SUCCESS);
                break;

            /* COMMAND THAT GIVES CUSTOMIZED VIEW */
            case VIEW:
            case SEARCH:
                updateUI(newDisplayMap);
                scrollToIndex(0);
                break;

            case INVALID:
            default:
                break;
            }

            updateOldItems(newDisplayList);

            break;

        case ERROR:
            // Fallthrough

        case INVALID:
            // Fallthrough

        default:
            showPrompt(status.getMessage(), Status.INVALID);
            break;
        }
    }

    // @author A0119764W
    private void updateOldItems(List<Object> newDisplayList) {
        oldItems.clear();
        oldItems.addAll(newDisplayList);
    }

    // @author A0119764W
    private void highlightItem(int index) {
        mainVBox.getChildren().get(index).setStyle("-fx-background-color: #E8F5E9;");
    }

    // @author A0112969W
    public void showPrompt(String str, Status status) {
        if (status.equals(Status.SUCCESS)) {
            promptLabel.setStyle("-fx-background-color: #43A047");
        } else {
            promptLabel.setStyle("-fx-background-color: #B71C1C");
        }

        if (!str.isEmpty()) {
            promptLabel.setText(str);

            Platform.runLater(new Runnable() {
                public void run() {
                    promptLabel.setOpacity(1);
                    fadeOut.setToValue(0.0);
                    fadeOut.playFromStart();
                }
            });
        }
    }

    // @author A0119764W
    public void clearUI() {
        mainInput.clear();
        mainVBox.getChildren().clear();
    }

    // @author A0112969W
    public void updateUI(Map<DateCategory, List<ToDo>> todoItems) {
        clearUI();

        int index = 1;
        ObservableList<Node> newVBoxItems = mainVBox.getChildren();

        if (todoItems == null || todoItems.isEmpty()) {
            Label temp = new Label("No items to show.");
            newVBoxItems.add(temp);
        } else {
            Label lblDate;

            for (Entry<DateCategory, List<ToDo>> entry : todoItems.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
                lblDate = createGroupLabel(entry.getKey());
                newVBoxItems.add(lblDate);

                for (ToDo todo : entry.getValue()) {
                    try {
                        ToDoContainer item = new ToDoContainer(index, todo);
                        detectCheckBoxChanges(item);
                        newVBoxItems.add(item);
                        index++;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // @author A0112969W
    /**
     * Listens the change in CheckedProperty of the check box of each task and
     * passes it as a command.
     * 
     * @param ToDoContainer
     *            which is a collection of fxml components of each task
     */
    private void detectCheckBoxChanges(ToDoContainer container) {
        container.getCheckedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) {

                if (new_val) {
                    processInput("complete " + container.getID());
                } else {
                    processInput("incomplete " + container.getID());
                }

            }
        });
    }

    // @author A0119764W
    public void minimizeWindow() {
        Stage stage = (Stage) minimizeButton.getScene().getWindow();
        stage.hide();
    }

    // @author A0119764W
    public Label createGroupLabel(DateCategory date) {
        Label label = new Label(date.toString());

        if (date.equals(DateCategory.OVERDUE)) {
            label.setStyle("-fx-background-color: #FF5050;");
        }

        label.getStyleClass().add("groupLabel");
        label.setMaxWidth(Double.MAX_VALUE);

        return label;
    }

    // @author A0111815R
    private void generateAllReminders() {
        LocalDateTime currentDateTime = new LocalDateTime();
        LocalDateTime tomorrowDateTime = new LocalDateTime().plusDays(1);

        for (ToDo todo : appLogic.getTodoStorage().getAll()) {
            if (todo.isDeadlineToDo()) {
                if (todo.getEndDate().isBefore(tomorrowDateTime) && todo.getEndDate().isAfter(currentDateTime)) {
                    new ReminderTask(todo, currentDateTime);
                }
            }
        }
    }

    // @author A0119764W
    private void scrollToIndex(int index) {
        mainScrollpane.applyCss();
        mainScrollpane.layout();

        double vBoxHeight = mainVBox.getHeight();
        double scrollPaneHeight = mainScrollpane.getViewportBounds().getHeight();

        double yValue = mainVBox.getChildren().get(index).getLayoutY();
        double vValue = 0;

        if (vBoxHeight > scrollPaneHeight) {
            vValue = yValue / (vBoxHeight - scrollPaneHeight);
        }

        mainScrollpane.setVvalue(vValue);
    }

    // @author A0119764W
    /**
     * Converts a map into a list.
     * 
     * @param map
     * @return a list of items in the map.
     */
    private List<Object> mapToList(Map<DateCategory, List<ToDo>> map) {
        List<Object> list = new ArrayList<Object>();

        for (Entry<DateCategory, List<ToDo>> entry : map.entrySet()) {
            list.add(entry.getKey());
            for (ToDo todo : entry.getValue()) {
                list.add(todo);
            }
        }
        return list;
    }

    // @author A0119764W
    private void scrollToToday() {
        int todayIndex = oldItems.indexOf(DateCategory.TODAY);
        if (todayIndex == -1) {
            todayIndex = 0;
        }
        scrollToIndex(todayIndex);
    }

    // @author A0112969W
    private void initilizeHandlers() {
        ctrlUpHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent keyevent) {
                if (keyevent.getCode().equals(KeyCode.UP) && keyevent.isControlDown()) {
                    mainScrollpane.setVvalue(mainScrollpane.getVvalue() - 0.1);
                }
            }
        };

        ctrlDownHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent keyevent) {
                if (keyevent.getCode().equals(KeyCode.DOWN) && keyevent.isControlDown()) {
                    mainScrollpane.setVvalue(mainScrollpane.getVvalue() + 0.1);
                }
            }
        };

        ctrlZHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent keyevent) {
                if (keyevent.getCode().equals(KeyCode.Z) && keyevent.isControlDown()) {
                    processInput("undo");
                }
            }
        };

        upHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent keyevent) {
                if (keyevent.getCode().equals(KeyCode.UP) && !keyevent.isControlDown()) {
                    String prevCmd = commandHistory.previous();
                    if (prevCmd != null) {
                        mainInput.setText(prevCmd);
                    }
                    mainInput.end();
                    keyevent.consume();
                }
            }
        };

        downHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent keyevent) {
                if (keyevent.getCode().equals(KeyCode.DOWN) && !keyevent.isControlDown()) {
                    String nextCmd = commandHistory.next();
                    if (nextCmd != null) {
                        mainInput.setText(nextCmd);
                    } else {
                        mainInput.setText("");
                    }
                    mainInput.end();
                    keyevent.consume();
                }
            }
        };

        mainInputFocusListener = new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {

                if (oldValue == true && newValue == false) {
                    mainInput.requestFocus();
                }
            }
        };

        inputChangeListener = new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ov, String oldStr, String newStr) {
                ToDoHint hint = new ToDoHint(appLogic, newStr);
                String str = hint.getHints();
                hintLabel.setText(str);
            }
        };
    }
}