private void createLabels() {
    Context context = new ContextThemeWrapper(getContext(), mLabelsStyle);

    for (int i = 0; i < mButtonsCount; i++) {

      if (getChildAt(i) == mImageToggle) continue;

      final FloatingActionButton fab = (FloatingActionButton) getChildAt(i);
      String text = fab.getLabelText();

      if (fab == mMenuButton || TextUtils.isEmpty(text) || fab.getTag(R.id.fab_label) != null) {
        continue;
      }

      final Label label = new Label(context);
      label.setFab(fab);
      label.setShowAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsShowAnimation));
      label.setHideAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsHideAnimation));

      if (mLabelsStyle > 0) {
        label.setTextAppearance(getContext(), mLabelsStyle);
        label.setShowShadow(false);
        label.setUsingStyle(true);
      } else {
        label.setColors(mLabelsColorNormal, mLabelsColorPressed, mLabelsColorRipple);
        label.setShowShadow(mLabelsShowShadow);
        label.setCornerRadius(mLabelsCornerRadius);
        if (mLabelsEllipsize > 0) {
          setLabelEllipsize(label);
        }
        label.setMaxLines(mLabelsMaxLines);
        label.updateBackground();

        label.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLabelsTextSize);
        label.setTextColor(mLabelsTextColor);

        int left = mLabelsPaddingLeft;
        int top = mLabelsPaddingTop;
        if (mLabelsShowShadow) {
          left += fab.getShadowRadius() + Math.abs(fab.getShadowXOffset());
          top += fab.getShadowRadius() + Math.abs(fab.getShadowYOffset());
        }

        label.setPadding(left, top, mLabelsPaddingLeft, mLabelsPaddingTop);

        if (mLabelsMaxLines < 0 || mLabelsSingleLine) {
          label.setSingleLine(mLabelsSingleLine);
        }
      }

      label.setText(text);

      addView(label);
      fab.setTag(R.id.fab_label, label);
    }
  }
Beispiel #2
0
 public Tooltip(Skatolo theskatolo) {
   skatolo = theskatolo;
   position = new PVector(-1000, -1000);
   currentPosition = new PVector();
   previousPosition = new PVector();
   offset = new PVector(0, 24, 0);
   map = new HashMap<Controller<?>, String>();
   label = new Label(skatolo, "tooltip");
   label.setColor(color);
   label.setPadding(0, 0);
   setView(new TooltipView());
   setBorder(4);
 }
Beispiel #3
0
 Tooltip(ControlP5 theControlP5) {
   cp5 = theControlP5;
   position = new PVector(-1000, -1000);
   currentPosition = new PVector();
   previousPosition = new PVector();
   offset = new PVector(0, 24, 0);
   map = new HashMap<Controller<?>, String>();
   _myLabel = new Label(cp5, "tooltip");
   _myLabel.setColor(_myColor);
   _myLabel.setPadding(0, 0);
   setView(new TooltipView());
   setBorder(4);
 }
Beispiel #4
0
 Tooltip(ControlP5 theControlP5) {
   cp5 = theControlP5;
   position[0] = -1000;
   position[1] = -1000;
   currentPosition = new float[3];
   previousPosition = new float[3];
   offset = new float[] {0, 24, 0};
   map = new HashMap<Controller<?>, String>();
   _myLabel = new Label(cp5, "tooltip");
   _myLabel.setColor(_myColor);
   _myLabel.setPadding(0, 0);
   setView(new TooltipView());
   setBorder(4);
 }
Beispiel #5
0
  public static Tuple3<Button, ProgressIndicator, Label> addButtonWithStatus(
      GridPane gridPane, int rowIndex, String buttonTitle, double top) {
    HBox hBox = new HBox();
    hBox.setSpacing(10);
    Button button = new Button(buttonTitle);
    button.setDefaultButton(true);

    ProgressIndicator progressIndicator = new ProgressIndicator(0);
    progressIndicator.setPrefHeight(24);
    progressIndicator.setPrefWidth(24);
    progressIndicator.setVisible(false);

    Label label = new Label();
    label.setPadding(new Insets(5, 0, 0, 0));

    hBox.getChildren().addAll(button, progressIndicator, label);

    GridPane.setRowIndex(hBox, rowIndex);
    GridPane.setColumnIndex(hBox, 1);
    GridPane.setMargin(hBox, new Insets(top, 0, 0, 0));
    gridPane.getChildren().add(hBox);

    return new Tuple3<>(button, progressIndicator, label);
  }
  private void onSelectDispute(Dispute dispute) {
    if (dispute == null) {
      if (root.getChildren().size() > 1) root.getChildren().remove(1);

      selectedDispute = null;
    } else if (selectedDispute != dispute) {
      this.selectedDispute = dispute;

      boolean isTrader = disputeManager.isTrader(dispute);

      TableGroupHeadline tableGroupHeadline = new TableGroupHeadline();
      tableGroupHeadline.setText("Messages");
      tableGroupHeadline.prefWidthProperty().bind(root.widthProperty());
      AnchorPane.setTopAnchor(tableGroupHeadline, 10d);
      AnchorPane.setRightAnchor(tableGroupHeadline, 0d);
      AnchorPane.setBottomAnchor(tableGroupHeadline, 0d);
      AnchorPane.setLeftAnchor(tableGroupHeadline, 0d);

      ObservableList<DisputeDirectMessage> list =
          dispute.getDisputeDirectMessagesAsObservableList();
      SortedList<DisputeDirectMessage> sortedList = new SortedList<>(list);
      sortedList.setComparator((o1, o2) -> o1.getDate().compareTo(o2.getDate()));
      list.addListener((ListChangeListener<DisputeDirectMessage>) c -> scrollToBottom());
      messageListView = new ListView<>(sortedList);
      messageListView.setId("message-list-view");
      messageListView.prefWidthProperty().bind(root.widthProperty());
      messageListView.setMinHeight(150);
      AnchorPane.setTopAnchor(messageListView, 30d);
      AnchorPane.setRightAnchor(messageListView, 0d);
      AnchorPane.setLeftAnchor(messageListView, 0d);

      messagesAnchorPane = new AnchorPane();
      messagesAnchorPane.prefWidthProperty().bind(root.widthProperty());
      VBox.setVgrow(messagesAnchorPane, Priority.ALWAYS);

      inputTextArea = new TextArea();
      inputTextArea.setPrefHeight(70);
      inputTextArea.setWrapText(true);

      Button sendButton = new Button("Send");
      sendButton.setDefaultButton(true);
      sendButton.setOnAction(e -> onSendMessage(inputTextArea.getText(), dispute));
      sendButton.setDisable(true);
      inputTextArea
          .textProperty()
          .addListener(
              (observable, oldValue, newValue) -> {
                sendButton.setDisable(
                    newValue.length() == 0
                        && tempAttachments.size() == 0
                        && dispute.disputeResultProperty().get() == null);
              });

      Button uploadButton = new Button("Add attachments");
      uploadButton.setOnAction(e -> onRequestUpload());

      sendMsgInfoLabel = new Label();
      sendMsgInfoLabel.setVisible(false);
      sendMsgInfoLabel.setManaged(false);
      sendMsgInfoLabel.setPadding(new Insets(5, 0, 0, 0));

      sendMsgProgressIndicator = new ProgressIndicator(0);
      sendMsgProgressIndicator.setPrefHeight(24);
      sendMsgProgressIndicator.setPrefWidth(24);
      sendMsgProgressIndicator.setVisible(false);
      sendMsgProgressIndicator.setManaged(false);

      dispute
          .isClosedProperty()
          .addListener(
              (observable, oldValue, newValue) -> {
                messagesInputBox.setVisible(!newValue);
                messagesInputBox.setManaged(!newValue);
                AnchorPane.setBottomAnchor(messageListView, newValue ? 0d : 120d);
              });
      if (!dispute.isClosed()) {
        HBox buttonBox = new HBox();
        buttonBox.setSpacing(10);
        buttonBox
            .getChildren()
            .addAll(sendButton, uploadButton, sendMsgProgressIndicator, sendMsgInfoLabel);

        if (!isTrader) {
          Button closeDisputeButton = new Button("Close ticket");
          closeDisputeButton.setOnAction(e -> onCloseDispute(dispute));
          closeDisputeButton.setDefaultButton(true);
          Pane spacer = new Pane();
          HBox.setHgrow(spacer, Priority.ALWAYS);
          buttonBox.getChildren().addAll(spacer, closeDisputeButton);
        }

        messagesInputBox = new VBox();
        messagesInputBox.setSpacing(10);
        messagesInputBox.getChildren().addAll(inputTextArea, buttonBox);
        VBox.setVgrow(buttonBox, Priority.ALWAYS);

        AnchorPane.setRightAnchor(messagesInputBox, 0d);
        AnchorPane.setBottomAnchor(messagesInputBox, 5d);
        AnchorPane.setLeftAnchor(messagesInputBox, 0d);

        AnchorPane.setBottomAnchor(messageListView, 120d);

        messagesAnchorPane
            .getChildren()
            .addAll(tableGroupHeadline, messageListView, messagesInputBox);
      } else {
        AnchorPane.setBottomAnchor(messageListView, 0d);
        messagesAnchorPane.getChildren().addAll(tableGroupHeadline, messageListView);
      }

      messageListView.setCellFactory(
          new Callback<ListView<DisputeDirectMessage>, ListCell<DisputeDirectMessage>>() {
            @Override
            public ListCell<DisputeDirectMessage> call(ListView<DisputeDirectMessage> list) {
              return new ListCell<DisputeDirectMessage>() {
                final Pane bg = new Pane();
                final ImageView arrow = new ImageView();
                final Label headerLabel = new Label();
                final Label messageLabel = new Label();
                final HBox attachmentsBox = new HBox();
                final AnchorPane messageAnchorPane = new AnchorPane();
                final Label statusIcon = new Label();
                final double arrowWidth = 15d;
                final double attachmentsBoxHeight = 20d;
                final double border = 10d;
                final double bottomBorder = 25d;
                final double padding = border + 10d;

                {
                  bg.setMinHeight(30);
                  messageLabel.setWrapText(true);
                  headerLabel.setTextAlignment(TextAlignment.CENTER);
                  attachmentsBox.setSpacing(5);
                  statusIcon.setStyle("-fx-font-size: 10;");
                  messageAnchorPane
                      .getChildren()
                      .addAll(bg, arrow, headerLabel, messageLabel, attachmentsBox, statusIcon);
                }

                @Override
                public void updateItem(final DisputeDirectMessage item, boolean empty) {
                  super.updateItem(item, empty);

                  if (item != null && !empty) {
                    /* messageAnchorPane.prefWidthProperty().bind(EasyBind.map(messageListView.widthProperty(),
                    w -> (double) w - padding - GUIUtil.getScrollbarWidth(messageListView)));*/
                    if (!messageAnchorPane.prefWidthProperty().isBound())
                      messageAnchorPane
                          .prefWidthProperty()
                          .bind(
                              messageListView
                                  .widthProperty()
                                  .subtract(padding + GUIUtil.getScrollbarWidth(messageListView)));

                    AnchorPane.setTopAnchor(bg, 15d);
                    AnchorPane.setBottomAnchor(bg, bottomBorder);
                    AnchorPane.setTopAnchor(headerLabel, 0d);
                    AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d);
                    AnchorPane.setTopAnchor(messageLabel, 25d);
                    AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10);

                    boolean senderIsTrader = item.isSenderIsTrader();
                    boolean isMyMsg = isTrader ? senderIsTrader : !senderIsTrader;

                    arrow.setVisible(!item.isSystemMessage());
                    arrow.setManaged(!item.isSystemMessage());
                    statusIcon.setVisible(false);
                    if (item.isSystemMessage()) {
                      headerLabel.setStyle("-fx-text-fill: -bs-green; -fx-font-size: 11;");
                      bg.setId("message-bubble-green");
                      messageLabel.setStyle("-fx-text-fill: white;");
                    } else if (isMyMsg) {
                      headerLabel.setStyle("-fx-text-fill: -fx-accent; -fx-font-size: 11;");
                      bg.setId("message-bubble-blue");
                      messageLabel.setStyle("-fx-text-fill: white;");
                      if (isTrader) arrow.setId("bubble_arrow_blue_left");
                      else arrow.setId("bubble_arrow_blue_right");

                      sendMsgProgressIndicator
                          .progressProperty()
                          .addListener(
                              (observable, oldValue, newValue) -> {
                                if ((double) oldValue == -1 && (double) newValue == 0) {
                                  if (item.arrivedProperty().get()) showArrivedIcon();
                                  else if (item.storedInMailboxProperty().get()) showMailboxIcon();
                                }
                              });

                      if (item.arrivedProperty().get()) showArrivedIcon();
                      else if (item.storedInMailboxProperty().get()) showMailboxIcon();
                      // TODO show that icon on error
                      /*else if (sendMsgProgressIndicator.getProgress() == 0)
                      showNotArrivedIcon();*/
                    } else {
                      headerLabel.setStyle("-fx-text-fill: -bs-light-grey; -fx-font-size: 11;");
                      bg.setId("message-bubble-grey");
                      messageLabel.setStyle("-fx-text-fill: black;");
                      if (isTrader) arrow.setId("bubble_arrow_grey_right");
                      else arrow.setId("bubble_arrow_grey_left");
                    }

                    if (item.isSystemMessage()) {
                      AnchorPane.setLeftAnchor(headerLabel, padding);
                      AnchorPane.setRightAnchor(headerLabel, padding);
                      AnchorPane.setLeftAnchor(bg, border);
                      AnchorPane.setRightAnchor(bg, border);
                      AnchorPane.setLeftAnchor(messageLabel, padding);
                      AnchorPane.setRightAnchor(messageLabel, padding);
                      AnchorPane.setLeftAnchor(attachmentsBox, padding);
                      AnchorPane.setRightAnchor(attachmentsBox, padding);
                    } else if (senderIsTrader) {
                      AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth);
                      AnchorPane.setLeftAnchor(bg, border + arrowWidth);
                      AnchorPane.setRightAnchor(bg, border);
                      AnchorPane.setLeftAnchor(arrow, border);
                      AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth);
                      AnchorPane.setRightAnchor(messageLabel, padding);
                      AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth);
                      AnchorPane.setRightAnchor(attachmentsBox, padding);
                      AnchorPane.setRightAnchor(statusIcon, padding);
                    } else {
                      AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth);
                      AnchorPane.setLeftAnchor(bg, border);
                      AnchorPane.setRightAnchor(bg, border + arrowWidth);
                      AnchorPane.setRightAnchor(arrow, border);
                      AnchorPane.setLeftAnchor(messageLabel, padding);
                      AnchorPane.setRightAnchor(messageLabel, padding + arrowWidth);
                      AnchorPane.setLeftAnchor(attachmentsBox, padding);
                      AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth);
                      AnchorPane.setLeftAnchor(statusIcon, padding);
                    }

                    AnchorPane.setBottomAnchor(statusIcon, 7d);
                    headerLabel.setText(formatter.formatDateTime(item.getDate()));
                    messageLabel.setText(item.getMessage());
                    if (item.getAttachments().size() > 0) {
                      AnchorPane.setBottomAnchor(
                          messageLabel, bottomBorder + attachmentsBoxHeight + 10);
                      attachmentsBox
                          .getChildren()
                          .add(
                              new Label("Attachments: ") {
                                {
                                  setPadding(new Insets(0, 0, 3, 0));
                                  if (isMyMsg) setStyle("-fx-text-fill: white;");
                                  else setStyle("-fx-text-fill: black;");
                                }
                              });

                      item.getAttachments()
                          .stream()
                          .forEach(
                              attachment -> {
                                final Label icon = new Label();
                                setPadding(new Insets(0, 0, 3, 0));
                                if (isMyMsg) icon.getStyleClass().add("attachment-icon");
                                else icon.getStyleClass().add("attachment-icon-black");

                                AwesomeDude.setIcon(icon, AwesomeIcon.FILE_TEXT);
                                icon.setPadding(new Insets(-2, 0, 0, 0));
                                icon.setTooltip(new Tooltip(attachment.getFileName()));
                                icon.setOnMouseClicked(event -> onOpenAttachment(attachment));
                                attachmentsBox.getChildren().add(icon);
                              });
                    } else {
                      attachmentsBox.getChildren().clear();
                      AnchorPane.setBottomAnchor(messageLabel, bottomBorder + 10);
                    }

                    // TODO There are still some cell rendering issues on updates
                    setGraphic(messageAnchorPane);
                  } else {
                    messageAnchorPane.prefWidthProperty().unbind();

                    AnchorPane.clearConstraints(bg);
                    AnchorPane.clearConstraints(headerLabel);
                    AnchorPane.clearConstraints(arrow);
                    AnchorPane.clearConstraints(messageLabel);
                    AnchorPane.clearConstraints(statusIcon);
                    AnchorPane.clearConstraints(attachmentsBox);

                    setGraphic(null);
                  }
                }

                /*  private void showNotArrivedIcon() {
                    statusIcon.setVisible(true);
                    AwesomeDude.setIcon(statusIcon, AwesomeIcon.WARNING_SIGN, "14");
                    Tooltip.install(statusIcon, new Tooltip("Message did not arrive. Please try to send again."));
                    statusIcon.setTextFill(Paint.valueOf("#dd0000"));
                }*/

                private void showMailboxIcon() {
                  statusIcon.setVisible(true);
                  AwesomeDude.setIcon(statusIcon, AwesomeIcon.ENVELOPE_ALT, "14");
                  Tooltip.install(statusIcon, new Tooltip("Message saved in receivers mailbox"));
                  statusIcon.setTextFill(Paint.valueOf("#0f87c3"));
                }

                private void showArrivedIcon() {
                  statusIcon.setVisible(true);
                  AwesomeDude.setIcon(statusIcon, AwesomeIcon.OK, "14");
                  Tooltip.install(statusIcon, new Tooltip("Message arrived at receiver"));
                  statusIcon.setTextFill(Paint.valueOf("#0f87c3"));
                }
              };
            }
          });

      if (root.getChildren().size() > 1) root.getChildren().remove(1);
      root.getChildren().add(1, messagesAnchorPane);

      scrollToBottom();
    }
  }
  private void updateStatisticsData(List<TaskWithWorklogs> displayResult) {

    if (!SettingsUtil.loadSettings().isShowStatistics()) {
      return;
    }

    statisticsView.getChildren().clear();

    WorklogStatistics statistics = new WorklogStatistics();

    // generic statistics
    displayResult.forEach(
        taskWithWorklogs -> {
          statistics.getTotalTimeSpent().addAndGet(taskWithWorklogs.getTotalInMinutes());

          for (WorklogItem worklogItem : taskWithWorklogs.getWorklogItemList()) {
            String employee = worklogItem.getUserDisplayname();

            // employee total time spent
            AtomicLong totalTimeSpent = statistics.getEmployeeToTotaltimeSpent().get(employee);
            if (totalTimeSpent == null) {
              totalTimeSpent = new AtomicLong(0);
              statistics.getEmployeeToTotaltimeSpent().put(employee, totalTimeSpent);
            }
            totalTimeSpent.addAndGet(worklogItem.getDurationInMinutes());

            // distinct tasks per employee
            Set<String> totalDistinctTasks =
                statistics.getEmployeeToTotalDistinctTasks().get(employee);
            if (totalDistinctTasks == null) {
              totalDistinctTasks = new HashSet<>();
              statistics.getEmployeeToTotalDistinctTasks().put(employee, totalDistinctTasks);
            }
            totalDistinctTasks.add(taskWithWorklogs.getIssue());

            // distinct tasks per employee per project
            Map<String, Set<String>> projectToDistinctTasks =
                statistics.getEmployeeToProjectToDistinctTasks().get(employee);
            if (projectToDistinctTasks == null) {
              projectToDistinctTasks = new HashMap<>();
              statistics
                  .getEmployeeToProjectToDistinctTasks()
                  .put(employee, projectToDistinctTasks);
            }

            Set<String> distinctTasks = projectToDistinctTasks.get(taskWithWorklogs.getProject());
            if (distinctTasks == null) {
              distinctTasks = new HashSet<>();
              projectToDistinctTasks.put(taskWithWorklogs.getProject(), distinctTasks);
            }

            distinctTasks.add(taskWithWorklogs.getIssue());

            // time spent per project
            Map<String, AtomicLong> projectToTimespent =
                statistics.getEmployeeToProjectToWorktime().get(employee);
            if (projectToTimespent == null) {
              projectToTimespent = new HashMap<>();
              statistics.getEmployeeToProjectToWorktime().put(employee, projectToTimespent);
            }

            AtomicLong timespentOnProject = projectToTimespent.get(taskWithWorklogs.getProject());
            if (timespentOnProject == null) {
              timespentOnProject = new AtomicLong(0);
              projectToTimespent.put(taskWithWorklogs.getProject(), timespentOnProject);
            }

            timespentOnProject.addAndGet(worklogItem.getDurationInMinutes());
          }
        });

    // render grid and bar graph
    final AtomicInteger currentGridRow = new AtomicInteger(0);

    GridPane employeeProjectSummaryGrid = new GridPane();
    employeeProjectSummaryGrid.setHgap(5);
    employeeProjectSummaryGrid.setVgap(5);

    NumberAxis projectEmployeeXAxis = new NumberAxis();
    projectEmployeeXAxis.setLabel(FormattingUtil.getFormatted("view.statistics.timespentinhours"));
    projectEmployeeXAxis.setTickLabelRotation(90);

    NumberAxis employeeProjectXAxis = new NumberAxis();
    employeeProjectXAxis.setLabel(FormattingUtil.getFormatted("view.statistics.timespentinhours"));
    employeeProjectXAxis.setTickLabelRotation(90);

    CategoryAxis projectEmployeeYAxis = new CategoryAxis();
    CategoryAxis employeeProjectYAxis = new CategoryAxis();

    StackedBarChart<Number, String> projectEmployeeBargraph =
        new StackedBarChart<>(projectEmployeeXAxis, projectEmployeeYAxis);
    StackedBarChart<Number, String> employeeProjectBargraph =
        new StackedBarChart<>(employeeProjectXAxis, employeeProjectYAxis);

    projectEmployeeBargraph.setTitle(
        FormattingUtil.getFormatted("view.statistics.byprojectandemployee"));
    employeeProjectBargraph.setTitle(
        FormattingUtil.getFormatted("view.statistics.byemployeeandproject"));

    Set<String> projectsToDisplay = new HashSet<>();
    displayResult.forEach(
        taskWithWorklogs -> {
          projectsToDisplay.add(taskWithWorklogs.getProject());
        });
    int projectEmployeeBargraphPreferedHeight =
        HEIGHT_PER_Y_AXIS_ELEMENT * projectsToDisplay.size()
            + HEIGHT_PER_X_AXIS_ELEMENT * statistics.getEmployeeToTotaltimeSpent().keySet().size()
            + ADDITIONAL_HEIGHT;
    projectEmployeeBargraph.setPrefHeight(projectEmployeeBargraphPreferedHeight);
    VBox.setVgrow(projectEmployeeBargraph, Priority.ALWAYS);

    int employeeProjectBargraphPreferedHeight =
        HEIGHT_PER_Y_AXIS_ELEMENT * statistics.getEmployeeToProjectToWorktime().keySet().size()
            + HEIGHT_PER_X_AXIS_ELEMENT * projectsToDisplay.size()
            + ADDITIONAL_HEIGHT;
    employeeProjectBargraph.setPrefHeight(employeeProjectBargraphPreferedHeight);
    VBox.setVgrow(employeeProjectBargraph, Priority.ALWAYS);

    Map<String, XYChart.Series<Number, String>> projectNameToSeries = Maps.newHashMap();

    statistics
        .getEmployeeToProjectToWorktime()
        .keySet()
        .stream()
        .sorted(COLLATOR::compare)
        .forEach(
            employee -> {

              // employee headline label
              Set<String> totalDistinctTasksOfEmployee =
                  statistics.getEmployeeToTotalDistinctTasks().get(employee);
              Label employeeLabel =
                  getBoldLabel(
                      FormattingUtil.getFormatted(
                          "view.statistics.somethingtoamountoftickets",
                          employee,
                          totalDistinctTasksOfEmployee.size()));
              employeeLabel.setPadding(new Insets(20, 0, 0, 0));
              GridPane.setConstraints(employeeLabel, 0, currentGridRow.getAndIncrement());
              GridPane.setColumnSpan(employeeLabel, 4);
              employeeProjectSummaryGrid.getChildren().addAll(employeeLabel);

              // bar graph data container
              XYChart.Series<Number, String> projectEmployeeSeries = new XYChart.Series<>();
              projectEmployeeSeries.setName(employee);
              projectEmployeeBargraph.getData().add(projectEmployeeSeries);

              // time spent per project
              Map<String, AtomicLong> projectToWorktime =
                  statistics.getEmployeeToProjectToWorktime().get(employee);
              Map<String, Label> projectToPercentageLabel = Maps.newHashMap();

              projectToWorktime
                  .keySet()
                  .stream()
                  .sorted(COLLATOR::compare)
                  .forEach(
                      projectName -> {
                        XYChart.Series<Number, String> employeeProjectSeries =
                            projectNameToSeries.get(projectName);
                        if (employeeProjectSeries == null) {
                          employeeProjectSeries = new XYChart.Series<>();
                          employeeProjectSeries.setName(projectName);
                          employeeProjectBargraph.getData().add(employeeProjectSeries);
                          projectNameToSeries.put(projectName, employeeProjectSeries);
                        }

                        // percentage label
                        Label percentageLabel = getBoldLabel("PLACEHOLDER");
                        percentageLabel.setAlignment(Pos.CENTER_RIGHT);
                        percentageLabel.setPadding(new Insets(0, 0, 0, 20));
                        GridPane.setConstraints(percentageLabel, 1, currentGridRow.get());
                        GridPane.setHalignment(percentageLabel, HPos.RIGHT);
                        projectToPercentageLabel.put(projectName, percentageLabel);

                        // project label
                        Set<String> distinctTasksPerProject =
                            statistics
                                .getEmployeeToProjectToDistinctTasks()
                                .get(employee)
                                .get(projectName);
                        Label projectLabel =
                            getBoldLabel(
                                FormattingUtil.getFormatted(
                                    "view.statistics.somethingtoamountoftickets",
                                    projectName,
                                    distinctTasksPerProject.size()));
                        GridPane.setConstraints(projectLabel, 2, currentGridRow.get());

                        // time spent for project label
                        long timespentInMinutes = projectToWorktime.get(projectName).longValue();
                        Label timespentLabel =
                            new Label(FormattingUtil.formatMinutes(timespentInMinutes, true));
                        GridPane.setConstraints(timespentLabel, 3, currentGridRow.get());
                        GridPane.setHgrow(timespentLabel, Priority.ALWAYS);
                        GridPane.setHalignment(timespentLabel, HPos.RIGHT);

                        employeeProjectSummaryGrid
                            .getChildren()
                            .addAll(percentageLabel, projectLabel, timespentLabel);
                        currentGridRow.incrementAndGet();

                        // bargraph data
                        projectEmployeeSeries
                            .getData()
                            .add(new XYChart.Data<>(timespentInMinutes / 60d, projectName));
                        employeeProjectSeries
                            .getData()
                            .addAll(new XYChart.Data<>(timespentInMinutes / 60d, employee));
                      });

              // total time spent
              Label totalLabel =
                  getBoldLabel(FormattingUtil.getFormatted("view.statistics.totaltimespent"));
              GridPane.setConstraints(totalLabel, 0, currentGridRow.get());
              GridPane.setColumnSpan(totalLabel, 4);

              Label timespentLabel =
                  new Label(
                      FormattingUtil.formatMinutes(
                          statistics.getEmployeeToTotaltimeSpent().get(employee).get(), true));
              GridPane.setConstraints(timespentLabel, 3, currentGridRow.get());
              GridPane.setHgrow(timespentLabel, Priority.ALWAYS);
              GridPane.setHalignment(timespentLabel, HPos.RIGHT);
              employeeProjectSummaryGrid.getChildren().addAll(totalLabel, timespentLabel);

              // set label now that we can calculate the percentage
              projectToWorktime
                  .keySet()
                  .forEach(
                      projectName -> {
                        Label percentageLabel = projectToPercentageLabel.get(projectName);

                        double totalSpentTime =
                            statistics.getEmployeeToTotaltimeSpent().get(employee).doubleValue();
                        double spentTimeOnProject =
                            projectToWorktime.get(projectName).doubleValue();

                        double percentage = spentTimeOnProject / totalSpentTime;
                        String percentageFormatted = FormattingUtil.formatPercentage(percentage);
                        percentageLabel.setText(percentageFormatted);
                      });

              currentGridRow.incrementAndGet();
            });

    // employeeProjectBargraph

    statisticsView
        .getChildren()
        .addAll(employeeProjectSummaryGrid, projectEmployeeBargraph, employeeProjectBargraph);

    // custom view statistics
    addAdditionalStatistics(statisticsView, statistics, displayResult);
  }
  /**
   * Draws the MapMaker screen and displays it to the user
   *
   * @param primaryStage the stage to show it in
   * @throws Exception
   */
  public void drawScreen(Stage primaryStage) throws Exception {
    // Create the base BorderPane for the whole window
    BorderPane borderPane = new BorderPane();
    borderPane.setStyle("-fx-background-color: papayawhip");

    // Add some instructions to the user
    String text =
        "Instructions:\n"
            + "1. Click on the map component that you would like to place in the map\n"
            + "2. Click on the place in the map where you want to place the component\n"
            + "3. Repeat until you built the map you want!\n"
            + "4. Hit the 'Save' button when you are done";
    Label instructions = new Label(text);
    instructions.setFont(Font.font("Arial", FontWeight.BOLD, 12));
    instructions.setPadding(new Insets(5, 5, 5, 5));
    borderPane.setTop(instructions);

    // Create the blank Map
    Pane mapPane = new Pane();
    Map map = new Map(width, height);
    MapGridGUIDecorator mapGridGUIDecorator = new MapGridGUIDecorator(map.getGrid());
    ResizeFactor rf = ResizeFactor.getSuggestedResizeFactor(width, height);
    mapGridGUIDecorator.setResizeFactor(rf);
    GridPane mapGridPane = mapGridGUIDecorator.drawComponents();
    mapGridPane.setPadding(new Insets(0, 0, 5, 5));
    mapPane.getChildren().add(mapGridPane);
    borderPane.setCenter(mapPane);
    MapMakerController.setCurrentFocused(ComponentType.NOTHING);

    VBox sideComponents = new VBox();

    /* Add "Components" label */
    Label componentsLabel = new Label("Components");
    componentsLabel.setFont(Font.font("Arial", FontWeight.EXTRA_BOLD, 14));
    componentsLabel.setPadding(new Insets(15, 5, 0, 20));
    sideComponents.getChildren().add(componentsLabel);

    /* Add Intersection square image */
    VBox intersectionPane = new VBox();
    Label intersectionLabel = new Label("Intersection");
    intersectionLabel.setPadding(new Insets(5, 5, 0, 30));
    intersectionLabel.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12));
    Image intersectionImg = new Image("IntersectionX.png", 60, 60, true, false);
    intersectionImgView = new ImageView(intersectionImg);
    StackPane intersectionStackPane = new StackPane(intersectionImgView);
    intersectionStackPane.setPadding(new Insets(0, 10, 10, 10));
    intersectionPane.getChildren().add(intersectionLabel);
    intersectionPane.getChildren().add(intersectionStackPane);
    sideComponents.getChildren().add(intersectionPane);

    /* Add RoadNS square image */
    VBox roadNSPane = new VBox();
    Label roadNSLabel = new Label("Road (North-South)");
    roadNSLabel.setPadding(new Insets(5, 5, 0, 15));
    roadNSLabel.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12));
    Image roadNSImg = new Image("RoadBackgroundNS.png", 60, 60, true, false);
    roadNSImgView = new ImageView(roadNSImg);
    StackPane roadNSStackPane = new StackPane(roadNSImgView);
    roadNSStackPane.setPadding(new Insets(0, 10, 10, 10));
    roadNSPane.getChildren().add(roadNSLabel);
    roadNSPane.getChildren().add(roadNSStackPane);
    sideComponents.getChildren().add(roadNSPane);

    /* Add RoadEW square image */
    VBox roadEWPane = new VBox();
    Label roadEWLabel = new Label("Road (East-West)");
    roadEWLabel.setPadding(new Insets(5, 5, 0, 15));
    roadEWLabel.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12));
    Image roadEWImg = new Image("RoadBackgroundEW.png", 60, 60, true, false);
    roadEWImgView = new ImageView(roadEWImg);
    StackPane roadEWStackPane = new StackPane(roadEWImgView);
    roadEWStackPane.setPadding(new Insets(0, 10, 10, 10));
    roadEWPane.getChildren().add(roadEWLabel);
    roadEWPane.getChildren().add(roadEWStackPane);
    sideComponents.getChildren().add(roadEWPane);

    /* Add Grass square image to empty out cells */
    VBox grassPane = new VBox();
    Label grassLabel = new Label("Grass (clear square)");
    grassLabel.setPadding(new Insets(5, 5, 0, 15));
    grassLabel.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12));
    Image grassImg = new Image("Grass.png", 60, 60, true, false);
    grassImgView = new ImageView(grassImg);
    StackPane grassStackPane = new StackPane(grassImgView);
    grassStackPane.setPadding(new Insets(0, 10, 10, 10));
    grassPane.getChildren().add(grassLabel);
    grassPane.getChildren().add(grassStackPane);
    sideComponents.getChildren().add(grassPane);

    /* Add Save, Reset buttons */
    VBox buttonsPane = new VBox();
    buttonsPane.setPadding(new Insets(0, 0, 0, 10));
    Label toolsLabel = new Label("Tools");
    toolsLabel.setFont(Font.font("Arial", FontWeight.EXTRA_BOLD, 14));
    toolsLabel.setPadding(new Insets(15, 5, 5, 35));
    buttonsPane.getChildren().add(toolsLabel);
    Insets padding = new Insets(0, 0, 5, 0);
    Button saveButton = new Button("Save Map");
    StackPane saveButtonPane = new StackPane(saveButton);
    saveButtonPane.setPadding(padding);
    saveButton.setStyle("-fx-base:Gold");
    saveButton.setFont(Font.font("System Bold Italic", FontWeight.BOLD, 13));
    buttonsPane.getChildren().add(saveButtonPane);
    Button resetButton = new Button("Reset Map");
    resetButton.setStyle("-fx-base:Gold");
    resetButton.setFont(Font.font("System Bold Italic", FontWeight.BOLD, 13));
    StackPane resetButtonPane = new StackPane(resetButton);
    resetButtonPane.setPadding(padding);
    buttonsPane.getChildren().add(resetButtonPane);
    Button backButton = new Button("Go Back");
    backButton.setStyle("-fx-base:Gold");
    backButton.setFont(Font.font("System Bold Italic", FontWeight.BOLD, 13));
    StackPane backButtonPane = new StackPane(backButton);
    backButtonPane.setPadding(padding);
    buttonsPane.getChildren().add(backButtonPane);

    sideComponents.getChildren().add(buttonsPane);

    Ticker.start();

    /* Add click processing for Map grid squares */
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        Node current = getNodeFromIndex(i, j, mapGridPane);
        final int x = j;
        final int y = i;
        current.setOnMouseClicked(
            (MouseEvent click) -> {
              MapMakerController.setPreviousFocused(MapMakerController.getCurrentFocused());
              MapMakerController.setCurrentFocused(ComponentType.MAP_SQUARE);
              current.requestFocus();
            });
        current
            .focusedProperty()
            .addListener(
                (ObservableValue<? extends Boolean> observable,
                    Boolean oldValue,
                    Boolean newValue) -> {
                  ComponentType previous = MapMakerController.getPreviousFocused();
                  if (previous == ComponentType.INTERSECTION) {
                    addIntersection(
                        x, y, map, mapGridGUIDecorator, mapGridPane, intersectionImgView);
                  } else if (previous == ComponentType.ROADNS) {
                    addRoadNS(x, y, map, mapGridGUIDecorator, mapGridPane, roadNSImgView);
                  } else if (previous == ComponentType.ROADEW) {
                    addRoadEW(x, y, map, mapGridGUIDecorator, mapGridPane, roadEWImgView);
                  } else if (previous == ComponentType.GRASS) {
                    addGrass(x, y, map, mapGridGUIDecorator, mapGridPane, grassImgView);
                  }
                });
      }
    }

    /* Add intersection icon click processing */
    DropShadow ds = new DropShadow(15, Color.BLUE);
    intersectionImgView.setOnMouseClicked(
        click -> {
          MapMakerController.setPreviousFocused(MapMakerController.getCurrentFocused());
          MapMakerController.setCurrentFocused(ComponentType.INTERSECTION);
          intersectionImgView.requestFocus();
        });
    intersectionImgView
        .focusedProperty()
        .addListener(
            (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
              if (newValue) intersectionImgView.setEffect(ds);
              else intersectionImgView.setEffect(null);
            });

    /* Add roadNS icon click processing */
    roadNSImgView.setOnMouseClicked(
        click -> {
          MapMakerController.setPreviousFocused(MapMakerController.getCurrentFocused());
          MapMakerController.setCurrentFocused(ComponentType.ROADNS);
          roadNSImgView.requestFocus();
        });
    roadNSImgView
        .focusedProperty()
        .addListener(
            (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
              if (newValue) roadNSImgView.setEffect(ds);
              else roadNSImgView.setEffect(null);
            });

    /* Add roadEW icon click processing */
    roadEWImgView.setOnMouseClicked(
        click -> {
          MapMakerController.setPreviousFocused(MapMakerController.getCurrentFocused());
          MapMakerController.setCurrentFocused(ComponentType.ROADEW);
          roadEWImgView.requestFocus();
        });
    roadEWImgView
        .focusedProperty()
        .addListener(
            (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
              if (newValue) roadEWImgView.setEffect(ds);
              else roadEWImgView.setEffect(null);
            });

    /* Add grass icon click processing */
    grassImgView.setOnMouseClicked(
        click -> {
          MapMakerController.setPreviousFocused(MapMakerController.getCurrentFocused());
          MapMakerController.setCurrentFocused(ComponentType.GRASS);
          grassImgView.requestFocus();
        });
    grassImgView
        .focusedProperty()
        .addListener(
            (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
              if (newValue) grassImgView.setEffect(ds);
              else grassImgView.setEffect(null);
            });

    /* Add save button functionality */
    saveButton.setOnMouseClicked(
        click -> {
          TextInputDialog nameDialog = new TextInputDialog();
          nameDialog.setTitle("Save Map");
          nameDialog.setHeaderText(
              "Please provide a name for your map (no spaces or special characters).\nSaved maps go into the /maps directory of your working directory.");
          nameDialog.setContentText("File name");
          Button btOk = (Button) nameDialog.getDialogPane().lookupButton(ButtonType.OK);
          TextField textfield = nameDialog.getEditor();
          Platform.runLater(() -> textfield.requestFocus());
          btOk.setDisable(true);
          textfield
              .textProperty()
              .addListener(
                  ((observable, oldValue, newValue) -> {
                    btOk.setDisable(newValue.trim().isEmpty());
                  }));

          Optional<String> result = nameDialog.showAndWait();
          result.ifPresent(
              name -> {
                name = name.concat(".map");
                try {
                  Map finalMap = buildAndSaveMap(map);
                  finalMap.saveMap(name);
                  goBack(primaryStage);
                } catch (Exception e) {
                  e.printStackTrace();
                }
              });
        });

    resetButton.setOnMouseClicked(
        click -> {
          for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
              Component component = map.getAtLocation(new Coordinate(x, y));
              if (component instanceof Road || component instanceof Intersection) {
                addGrass(x, y, map, mapGridGUIDecorator, mapGridPane, grassImgView);
              }
            }
          }
        });

    backButton.setOnMouseClicked(
        click -> {
          try {
            goBack(primaryStage);
          } catch (Exception e) {
            e.printStackTrace();
          }
        });

    borderPane.setRight(sideComponents);
    Scene scene = new Scene(borderPane);
    primaryStage.setScene(scene);
    primaryStage.centerOnScreen();
    primaryStage.setResizable(false);
  }