diff --git a/src/main/java/com/notably/view/CommandBox.java b/src/main/java/com/notably/view/CommandBox.java index 8e1cb6ccc95..1a8ca6ce9d6 100644 --- a/src/main/java/com/notably/view/CommandBox.java +++ b/src/main/java/com/notably/view/CommandBox.java @@ -2,6 +2,7 @@ import com.notably.logic.commands.exceptions.CommandException; import com.notably.logic.parser.exceptions.ParseException; +import com.notably.view.suggestion.SuggestionsWindowView; import javafx.application.Platform; import javafx.beans.property.StringProperty; diff --git a/src/main/java/com/notably/view/MainWindow.java b/src/main/java/com/notably/view/MainWindow.java index 57de8dc8861..9f4a395b7e6 100644 --- a/src/main/java/com/notably/view/MainWindow.java +++ b/src/main/java/com/notably/view/MainWindow.java @@ -9,11 +9,12 @@ import com.notably.logic.parser.exceptions.ParseException; import com.notably.model.Model; import com.notably.view.blockcontent.BlockContent; +import com.notably.view.sidebar.SideBarTreeView; +import com.notably.view.suggestion.SuggestionsWindowView; import javafx.beans.Observable; import javafx.fxml.FXML; import javafx.scene.control.Label; -import javafx.scene.effect.ColorAdjust; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; @@ -54,7 +55,7 @@ public class MainWindow extends ViewPart { private StackPane sideBarPlaceholder; @FXML - private StackPane blockContentPlaceholder; + private VBox blockContentPlaceholder; @FXML private VBox suggestionsWindow; @@ -67,8 +68,6 @@ public MainWindow(Stage primaryStage, Logic logic, Model model) { this.model = model; setWindowDefaultSize(logic.getGuiSettings()); - //setWindowSettings(primaryStage); - initializeHelpWindow(model); } @@ -76,24 +75,6 @@ public Stage getPrimaryStage() { return primaryStage; } - /** - * Provides an alternative way to set the settings of the main window, as an alternative - * to doing so via fxml tags. - * - * @param primaryStage the stage corresponding to the main app window. - */ - private void setWindowSettings(Stage primaryStage) { - primaryStage.focusedProperty().addListener(((observable, unused, isFocused) -> { - if (isFocused) { - mainWindow.setEffect(null); - } else { - ColorAdjust colorAdjust = new ColorAdjust(); - colorAdjust.setBrightness(-0.4); - mainWindow.setEffect(colorAdjust); - } - })); - } - /** * Fills up all the placeholders of this window. */ @@ -106,7 +87,8 @@ void fillInnerParts() { blockContent = new BlockContent(blockContentPlaceholder, logic, model); - suggestionsWindowView = new SuggestionsWindowView(model.getSuggestions(), model.responseTextProperty()); + suggestionsWindowView = new SuggestionsWindowView(model.getSuggestions(), + model.responseTextProperty()); suggestionsWindow.getChildren().add(suggestionsWindowView.getRoot()); } diff --git a/src/main/java/com/notably/view/blockcontent/BlockContent.java b/src/main/java/com/notably/view/blockcontent/BlockContent.java index d6657905c21..d3e41077781 100644 --- a/src/main/java/com/notably/view/blockcontent/BlockContent.java +++ b/src/main/java/com/notably/view/blockcontent/BlockContent.java @@ -5,7 +5,7 @@ import com.notably.logic.Logic; import com.notably.model.Model; -import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; /** * View of the currently open block's content. @@ -15,14 +15,13 @@ public class BlockContent { private final BlockContentDisplayView blockContentDisplayView; private final BlockContentEditView blockContentEditView; - public BlockContent(StackPane blockContentPlaceholder, Logic logic, Model model) { + public BlockContent(VBox blockContentPlaceholder, Logic logic, Model model) { requireAllNonNull(blockContentPlaceholder, model, logic); blockContentDisplayView = new BlockContentDisplayView(model); blockContentEditView = new BlockContentEditView(logic, model); - // TODO: Integrate BlockContentEditView - blockContentPlaceholder.getChildren().addAll(blockContentDisplayView.getRoot()); + blockContentPlaceholder.getChildren().add(blockContentDisplayView.getRoot()); } } diff --git a/src/main/java/com/notably/view/blockcontent/BlockContentDisplayView.java b/src/main/java/com/notably/view/blockcontent/BlockContentDisplayView.java index 22fdb73fecb..7793196fa76 100644 --- a/src/main/java/com/notably/view/blockcontent/BlockContentDisplayView.java +++ b/src/main/java/com/notably/view/blockcontent/BlockContentDisplayView.java @@ -9,7 +9,11 @@ import com.notably.view.ViewPart; import javafx.fxml.FXML; +import javafx.scene.control.Label; import javafx.scene.control.TreeItem; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; import javafx.scene.web.WebView; /** @@ -21,47 +25,114 @@ public class BlockContentDisplayView extends ViewPart { private final Model model; @FXML - private WebView blockContentDisplay; + private VBox blockContentDisplay; + + @FXML + private HBox blockTitlePathContainer; + + @FXML + private Label blockTitleDisplay; + + @FXML + private Pane separator; + + @FXML + private Label blockPathDisplay; + + @FXML + private WebView blockBodyDisplay; public BlockContentDisplayView(Model model) { super(FXML); - Objects.requireNonNull(model); - this.model = model; - setup(); } /** - * Sets up the view's initial data and wire up all required change listeners. + * Sets up the view's initial data and wires up all required change listeners. */ private void setup() { - // Initialize content display - reload(model); - - // Setup change listeners - model.currentlyOpenPathProperty().addListener(observable -> reload(model)); - model.getBlockTree().getRootBlock().getTreeItem() - .addEventHandler(TreeItem.treeNotificationEvent(), event -> reload(model)); + updateBlockContentDisplay(model); + setChangeListeners(); } /** - * Reloads the {@link WebView}'s content with the currently open block's rendered HTML body. + * Updates the content of the view-components to that of the currently open block. * - * @param model App's model + * @param model App's model. */ - private void reload(Model model) { + private void updateBlockContentDisplay(Model model) { Objects.requireNonNull(model); AbsolutePath currentlyOpenPath = model.getCurrentlyOpenPath(); BlockTreeItem currentlyOpenBlock = model.getBlockTree().get(currentlyOpenPath); - String markdownBody = currentlyOpenBlock.getBody().getText(); - String htmlBody = Compiler.compile(markdownBody); - blockContentDisplay.getEngine().setUserStyleSheetLocation(getClass() + updateBlockTitleDisplay(currentlyOpenBlock); + updateBlockPathDisplay(currentlyOpenPath); + updateBlockBodyDisplay(currentlyOpenBlock); + } + + /** + * Sets the blockTitleDisplay's text to the currently open block's {@link com.notably.model.block.Title}. + * + * @param currentlyOpenBlock A {@link BlockTreeItem} representing the currently open note block. + */ + private void updateBlockTitleDisplay(BlockTreeItem currentlyOpenBlock) { + Objects.requireNonNull(currentlyOpenBlock); + + String titleString = currentlyOpenBlock.getTitle().getText(); + blockTitleDisplay.setText(titleString); + } + + /** + * Sets the blockPathDisplay's text to the currently open block's {@link AbsolutePath}. + * + * @param currentlyOpenPath A {@link BlockTreeItem} representing the currently open note block. + */ + private void updateBlockPathDisplay(AbsolutePath currentlyOpenPath) { + Objects.requireNonNull(currentlyOpenPath); + + String pathString = currentlyOpenPath.getStringRepresentation(); + blockPathDisplay.setText(pathString); + } + + /** + * Sets the blockBodyDisplay's text to the currently open block's {@link com.notably.model.block.Body}. + * + * @param currentlyOpenBlock A {@link BlockTreeItem} representing the currently open note block. + */ + private void updateBlockBodyDisplay(BlockTreeItem currentlyOpenBlock) { + Objects.requireNonNull(currentlyOpenBlock); + + String htmlBody = getHtmlBody(currentlyOpenBlock); + blockBodyDisplay.getEngine().loadContent(htmlBody); + blockBodyDisplay.getEngine().setUserStyleSheetLocation(getClass() .getResource("/view/blockcontent/BlockContentDisplay.css").toExternalForm()); - blockContentDisplay.getEngine().loadContent(htmlBody); + } + + /** + * Helper function to retrieve the currently open block's {@link com.notably.model.block.Body} + * rendered as HTML. + * + * @param currentlyOpenBlock A {@link BlockTreeItem} representing the currently open note block. + * @return A String representing the note's body. + */ + private String getHtmlBody(BlockTreeItem currentlyOpenBlock) { + Objects.requireNonNull(currentlyOpenBlock); + + String markdownBody = currentlyOpenBlock.getBody().getText(); + String htmlBody = Compiler.compile(markdownBody); + return htmlBody; + } + + /** + * Sets up listeners for View state management. + */ + private void setChangeListeners() { + model.currentlyOpenPathProperty().addListener(observable -> updateBlockContentDisplay(model)); + model.getBlockTree().getRootBlock().getTreeItem() + .addEventHandler(TreeItem.treeNotificationEvent(), event -> updateBlockContentDisplay(model)); } } diff --git a/src/main/java/com/notably/view/blockcontent/BlockContentEditView.java b/src/main/java/com/notably/view/blockcontent/BlockContentEditView.java index dc3db21be43..37bd73770b2 100644 --- a/src/main/java/com/notably/view/blockcontent/BlockContentEditView.java +++ b/src/main/java/com/notably/view/blockcontent/BlockContentEditView.java @@ -159,7 +159,7 @@ private void setInitialData() { } /** - * Sets the {@link TextArea}'s content to the currently open block's Markdown body. + * Sets the {@link TextArea}'s content to the currently open block's content in markdown form. * * @param model App's model */ @@ -168,6 +168,7 @@ private void setText(Model model) { AbsolutePath currentlyOpenPath = model.getCurrentlyOpenPath(); BlockTreeItem currentlyOpenBlock = model.getBlockTree().get(currentlyOpenPath); + String markdownBody = currentlyOpenBlock.getBody().getText(); blockContentTextArea.setText(markdownBody); @@ -201,7 +202,6 @@ private void handleEdit() { * ie. the Block Edit modal is to be shown, false otherwise. */ private void updateMainWindowStyle(Boolean isBlockEditable) { - //logger.severe(isBlockEditable.toString()); Node mainWindow = parentStage.getScene().lookup("#mainWindow"); ChangeListener focusedListener = (observable, unused, isFocused) -> { if (!isFocused && stage.isShowing()) { diff --git a/src/main/java/com/notably/view/SideBarTreeView.java b/src/main/java/com/notably/view/sidebar/SideBarTreeView.java similarity index 73% rename from src/main/java/com/notably/view/SideBarTreeView.java rename to src/main/java/com/notably/view/sidebar/SideBarTreeView.java index d9ab407ff8d..d818236a7fd 100644 --- a/src/main/java/com/notably/view/SideBarTreeView.java +++ b/src/main/java/com/notably/view/sidebar/SideBarTreeView.java @@ -1,19 +1,16 @@ -package com.notably.view; +package com.notably.view.sidebar; import com.notably.commons.path.AbsolutePath; import com.notably.model.block.Block; import com.notably.model.block.BlockTree; import com.notably.model.block.BlockTreeItem; +import com.notably.view.ViewPart; import javafx.beans.property.Property; -import javafx.event.Event; -import javafx.event.EventDispatchChain; import javafx.event.EventDispatcher; import javafx.fxml.FXML; -import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; /** @@ -69,7 +66,7 @@ private void setTreeSettings() { * Calls helper functions that set the strategies for populating the SideBarTreeView with data. */ private void setTreeStructure() { - sideBarTreeView.setCellFactory(treeView -> new SideBarTreeViewCell()); + sideBarTreeView.setCellFactory(treeView -> new SideBarTreeViewCell(currentlyOpenedNote)); useLevelDisplayStrategy(); useExpansionStrategy(); } @@ -135,56 +132,4 @@ private void useExpansionStrategy() { }); }); } - - /** - * Custom {@code TreeCell} that displays the text of a {@code Block}. - */ - class SideBarTreeViewCell extends TreeCell { - @Override - protected void updateItem(Block block, boolean empty) { - super.updateItem(block, empty); - - setGraphic(null); - if (empty || block == null) { - setText(null); - } else { - setText(getNoteTitle()); - setSelectedProperty(block); - } - } - - private String getNoteTitle() { - return getItem().getTitle().getText(); - } - - private void setSelectedProperty(Block block) { - if ((block == currentlyOpenedNote.getBlock())) { - updateSelected(true); - } else { - updateSelected(false); - } - } - } - - /** - * Custom {@code EventDispatcher} to allow for finer control over mouse click events. - * A {@link SideBarTreeViewCell} should not respond to any mouse click events. - * - */ - class TreeCellEventDispatcher implements EventDispatcher { - private final EventDispatcher original; - - public TreeCellEventDispatcher(EventDispatcher original) { - this.original = original; - } - - @Override - public Event dispatchEvent(Event event, EventDispatchChain tail) { - - if (event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) { - event.consume(); - } - return original.dispatchEvent(event, tail); - } - } } diff --git a/src/main/java/com/notably/view/sidebar/SideBarTreeViewCell.java b/src/main/java/com/notably/view/sidebar/SideBarTreeViewCell.java new file mode 100644 index 00000000000..c2de8f44b3f --- /dev/null +++ b/src/main/java/com/notably/view/sidebar/SideBarTreeViewCell.java @@ -0,0 +1,43 @@ +package com.notably.view.sidebar; + +import com.notably.model.block.Block; +import com.notably.model.block.BlockTreeItem; + +import javafx.scene.control.TreeCell; + +/** + * Custom {@code TreeCell} that displays the text of a {@code Block} within {@link SideBarTreeView}. + */ +class SideBarTreeViewCell extends TreeCell { + private BlockTreeItem currentlyOpenedNote; + + public SideBarTreeViewCell(BlockTreeItem currentlyOpenedNote) { + super(); + this.currentlyOpenedNote = currentlyOpenedNote; + } + + @Override + protected void updateItem(Block block, boolean empty) { + super.updateItem(block, empty); + + setGraphic(null); + if (empty || block == null) { + setText(null); + } else { + setText(getNoteTitle()); + setSelectedProperty(block); + } + } + + private String getNoteTitle() { + return getItem().getTitle().getText(); + } + + private void setSelectedProperty(Block block) { + if ((block == currentlyOpenedNote.getBlock())) { + updateSelected(true); + } else { + updateSelected(false); + } + } +} diff --git a/src/main/java/com/notably/view/sidebar/TreeCellEventDispatcher.java b/src/main/java/com/notably/view/sidebar/TreeCellEventDispatcher.java new file mode 100644 index 00000000000..e124ae4366a --- /dev/null +++ b/src/main/java/com/notably/view/sidebar/TreeCellEventDispatcher.java @@ -0,0 +1,28 @@ +package com.notably.view.sidebar; + +import javafx.event.Event; +import javafx.event.EventDispatchChain; +import javafx.event.EventDispatcher; +import javafx.scene.input.MouseEvent; + +/** + * Custom {@code EventDispatcher} to allow for finer control over mouse click events. + * A {@link SideBarTreeViewCell} should not respond to any mouse click events. + * + */ +class TreeCellEventDispatcher implements EventDispatcher { + private final EventDispatcher original; + + public TreeCellEventDispatcher(EventDispatcher original) { + this.original = original; + } + + @Override + public Event dispatchEvent(Event event, EventDispatchChain tail) { + + if (event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) { + event.consume(); + } + return original.dispatchEvent(event, tail); + } +} diff --git a/src/main/java/com/notably/view/suggestion/SuggestionsListCellData.java b/src/main/java/com/notably/view/suggestion/SuggestionsListCellData.java new file mode 100644 index 00000000000..f09fce68b47 --- /dev/null +++ b/src/main/java/com/notably/view/suggestion/SuggestionsListCellData.java @@ -0,0 +1,108 @@ +package com.notably.view.suggestion; + +import static com.notably.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Optional; + +import com.notably.model.suggestion.SuggestionItem; +import com.notably.view.ViewPart; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Region; + +/** + * Custom View-Controller for the components within a {@code SuggestionsListViewCell}. + */ +public class SuggestionsListCellData extends ViewPart { + + private static final String FXML = "suggestion/SuggestionsListViewCell.fxml"; + + @FXML + private HBox container; + + @FXML + private Label pathLabel; + + @FXML + private Label selectedItemLabel; + + @FXML + private Label searchFrequencyLabel; + + @FXML + private Pane leftPlaceholderPane; + + @FXML + private Pane rightPlaceholderPane; + + public SuggestionsListCellData(SuggestionItem suggestionItem, boolean isSelected) { + super(FXML); + requireAllNonNull(suggestionItem, isSelected); + setPathLabel(suggestionItem); + setSearchFrequencyLabel(suggestionItem); + setSelectedItemLabel(suggestionItem, isSelected); + } + + /** + * Getter for the Root Component. + * @return container of type {@code HBox}. + */ + public HBox getHBox() { + return container; + } + + /** + * Updates the pathLabel with the String representation of the {@code SuggestionItem's} path. + * + * @param item a particular {@code SuggestionItem} from the list of current suggestions. + */ + private void setPathLabel(SuggestionItem item) { + Optional displayProperty = item.getProperty("displayText"); + String displayString = displayProperty.orElse(""); + pathLabel.setText(displayString); + } + + /** + * Updates the searchFrequencyLabel with the {@code SuggestionItem's} search count. If the current + * list of suggestions was not generated for a search command, the label is set to an empty string. + * + * See {@link com.notably.logic.commands.suggestion.SearchSuggestionCommand}. + * + * @param item a particular {@code SuggestionItem} from the list of current suggestions. + */ + private void setSearchFrequencyLabel(SuggestionItem item) { + Optional frequencyProperty = item.getProperty("frequency"); + String frequencyString = ""; + if (frequencyProperty.isPresent()) { + frequencyString += frequencyProperty.get() + " matches in body"; + } + searchFrequencyLabel.setText(frequencyString); + } + + + /** + * Updates the selectedItemLabel with a prompt text based on the current command. The prompt + * text is set to a non-empty String if the {@code SuggestionsListViewCell} is currently + * selected, but empty otherwise. + * + * @param item a particular {@code SuggestionItem} from the list of current suggestions. + */ + private void setSelectedItemLabel(SuggestionItem item, boolean isSelected) { + if (isSelected) { + rightPlaceholderPane.setMinWidth(30); + selectedItemLabel.setVisible(true); + Boolean isSearchCommand = item.getProperty("frequency").isPresent(); + if (isSearchCommand) { + selectedItemLabel.setText(("Press enter to go to file")); + } else { + selectedItemLabel.setText("Press enter to autofill"); + } + } else { + selectedItemLabel.setVisible(false); + rightPlaceholderPane.setMinWidth(0); + } + } +} diff --git a/src/main/java/com/notably/view/suggestion/SuggestionsListViewCell.java b/src/main/java/com/notably/view/suggestion/SuggestionsListViewCell.java new file mode 100644 index 00000000000..38c47cd9902 --- /dev/null +++ b/src/main/java/com/notably/view/suggestion/SuggestionsListViewCell.java @@ -0,0 +1,27 @@ +package com.notably.view.suggestion; + +import com.notably.model.suggestion.SuggestionItem; + +import javafx.scene.control.ListCell; + +/** + * Custom {@code ListCell} that displays the graphics of a {@code SuggestionItem} + * within {@code SuggestionsWindowView}. + * + * The layout of the components within a {@code SuggestionsListViewCell} is managed by + * another custom View-Controller, {@link SuggestionsListCellData}. + */ +public class SuggestionsListViewCell extends ListCell { + @Override + public void updateItem(SuggestionItem suggestionItem, boolean empty) { + super.updateItem(suggestionItem, empty); + + if (empty || suggestionItem == null) { + setText(""); + setGraphic(null); + } else { + SuggestionsListCellData data = new SuggestionsListCellData(suggestionItem, isSelected()); + setGraphic(data.getHBox()); + } + } +} diff --git a/src/main/java/com/notably/view/SuggestionsWindowView.java b/src/main/java/com/notably/view/suggestion/SuggestionsWindowView.java similarity index 68% rename from src/main/java/com/notably/view/SuggestionsWindowView.java rename to src/main/java/com/notably/view/suggestion/SuggestionsWindowView.java index 76023405f57..fa0babaf22d 100644 --- a/src/main/java/com/notably/view/SuggestionsWindowView.java +++ b/src/main/java/com/notably/view/suggestion/SuggestionsWindowView.java @@ -1,25 +1,21 @@ -package com.notably.view; +package com.notably.view.suggestion; import java.util.Optional; import com.notably.model.suggestion.SuggestionItem; +import com.notably.view.CommandBox; +import com.notably.view.ViewPart; import javafx.beans.Observable; import javafx.beans.property.Property; import javafx.collections.ObservableList; import javafx.fxml.FXML; -import javafx.geometry.Pos; import javafx.scene.control.Label; -import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; -import javafx.scene.text.TextAlignment; import javafx.stage.Stage; import javafx.stage.Window; @@ -29,7 +25,7 @@ */ public class SuggestionsWindowView extends ViewPart { - private static final String FXML = "SuggestionsWindowView.fxml"; + private static final String FXML = "suggestion/SuggestionsWindowView.fxml"; private static final int LIST_CELL_HEIGHT = 36; @FXML @@ -148,62 +144,4 @@ private void setResponseTextRenderingStatus(boolean bool) { private int computePrefListHeight(int listSize) { return listSize * LIST_CELL_HEIGHT; } - - /** - * Custom {@code ListCell} that displays the graphics of a {@code SuggestionItem}. - */ - class SuggestionsListViewCell extends ListCell { - private final Label pathLabel; - private final Label selectedItemLabel; - private final Pane placeholderPane; - private final HBox container; - - public SuggestionsListViewCell() { - pathLabel = new Label(); - selectedItemLabel = new Label(); - placeholderPane = new Pane(); - container = new HBox(pathLabel, placeholderPane, selectedItemLabel); - - setComponentSettings(selectedItemLabel, placeholderPane, container); - } - - private void setComponentSettings(Label selectedItemLabel, Pane placeholderPane, HBox container) { - selectedItemLabel.setTextAlignment(TextAlignment.RIGHT); - placeholderPane.setMinWidth(30); - container.setMinWidth(0); - container.setPrefWidth(1); - container.setAlignment(Pos.CENTER_LEFT); - container.setHgrow(selectedItemLabel, Priority.ALWAYS); - container.setHgrow(placeholderPane, Priority.SOMETIMES); - container.setHgrow(pathLabel, Priority.SOMETIMES); - } - - @Override - protected void updateItem(SuggestionItem suggestionItem, boolean empty) { - super.updateItem(suggestionItem, empty); - - if (empty || suggestionItem == null) { - setText(""); - setGraphic(null); - } else { - setPathLabel(getItem()); - setSelectedItemLabel(); - setGraphic(container); - } - } - - private void setPathLabel(SuggestionItem item) { - Optional displayProperty = item.getProperty("displayText"); - String displayString = displayProperty.orElse(""); - pathLabel.setText(displayString); - } - - private void setSelectedItemLabel() { - if (isSelected()) { - selectedItemLabel.setText("Press enter to autofill"); - } else { - selectedItemLabel.setText(""); - } - } - } } diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 52e516792fb..316ca48f35f 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -2,13 +2,13 @@ - + + - @@ -23,8 +23,9 @@ - -