Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature block content edit view [View] #416

Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f959350
Add logic as a parameter to BlockContentEditView
HemanshuGandhi Apr 7, 2020
28b79a0
Refactor methods in BlockContentEditView
HemanshuGandhi Apr 7, 2020
865ed2c
Standardize code convention
HemanshuGandhi Apr 7, 2020
512e3a3
Add Edit Modal skeleton
HemanshuGandhi Apr 8, 2020
6897708
Fix checkstyle violations
HemanshuGandhi Apr 8, 2020
e4b01db
Link up edit modal to logic for updating block content
HemanshuGandhi Apr 8, 2020
656e688
fix checkstyle violations
HemanshuGandhi Apr 8, 2020
febe0d4
Fix window resizing bug
HemanshuGandhi Apr 8, 2020
b94893d
Add background darken effect when Edit modal is showing
HemanshuGandhi Apr 8, 2020
5a3faa6
Allow exiting of edit modal on pressing esc
HemanshuGandhi Apr 8, 2020
55b048c
Add dropshadow to edit modal
HemanshuGandhi Apr 8, 2020
f6516c1
Change edit modal to appear minimalistic
HemanshuGandhi Apr 8, 2020
3440e47
Remove unused import
HemanshuGandhi Apr 8, 2020
b0b437b
Merge branch 'master' into feature-block-content-edit-view
HemanshuGandhi Apr 8, 2020
50a51dc
Remove commented line in EditCommand
HemanshuGandhi Apr 9, 2020
9bfed5f
Merge branch 'feature-block-content-edit-view' of https://github.com/…
HemanshuGandhi Apr 9, 2020
0f372d9
Refactor methods in BlockContentEditView
HemanshuGandhi Apr 9, 2020
1855a38
Remove window darkening bug when other applications are opened
HemanshuGandhi Apr 9, 2020
3f2659b
Edit javadoc for #setKeyboardListeners
HemanshuGandhi Apr 10, 2020
962adaa
Merge branch 'master' into feature-block-content-edit-view
HemanshuGandhi Apr 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/com/notably/logic/commands/EditCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public EditCommand(Body body) {
public void execute(Model notablyModel) throws CommandException {
requireNonNull(notablyModel);
try {
notablyModel.updateCurrentlyOpenBlockBody(body);
//notablyModel.updateCurrentlyOpenBlockBody(body);
HemanshuGandhi marked this conversation as resolved.
Show resolved Hide resolved
notablyModel.setBlockEditable(true);
} catch (CannotModifyRootException ex) {
throw new CommandException(ex.getMessage());
}
HemanshuGandhi marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
28 changes: 24 additions & 4 deletions src/main/java/com/notably/view/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import javafx.fxml.FXML;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputControl;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
Expand Down Expand Up @@ -47,6 +48,9 @@ public class MainWindow extends ViewPart<Stage> {
@FXML
private MenuItem helpMenuItem;

@FXML
private VBox mainWindow;

@FXML
private StackPane sideBarPlaceholder;

Expand All @@ -62,14 +66,12 @@ public class MainWindow extends ViewPart<Stage> {
public MainWindow(Stage primaryStage, Logic logic, Model model) {
super(FXML, primaryStage);

// Set dependencies
this.primaryStage = primaryStage;
this.logic = logic;
this.model = model;

// Configure the VIEW
setWindowDefaultSize(logic.getGuiSettings());

setWindowSettings(primaryStage);
setAccelerators();

initializeHelpWindow(model);
Expand All @@ -79,6 +81,24 @@ 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);
}
}));
}

HemanshuGandhi marked this conversation as resolved.
Show resolved Hide resolved
private void setAccelerators() {
setAccelerator(helpMenuItem, KeyCombination.valueOf("F1"));
}
Expand Down Expand Up @@ -125,7 +145,7 @@ void fillInnerParts() {
sidebarTreeView = new SideBarTreeView(model.getBlockTree(), model.currentlyOpenPathProperty());
sideBarPlaceholder.getChildren().add(sidebarTreeView.getRoot());

blockContent = new BlockContent(blockContentPlaceholder, model);
blockContent = new BlockContent(blockContentPlaceholder, logic, model);

suggestionsWindowView = new SuggestionsWindowView(model.getSuggestions(), model.responseTextProperty());
suggestionsWindow.getChildren().add(suggestionsWindowView.getRoot());
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/com/notably/view/blockcontent/BlockContent.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.notably.view.blockcontent;

import java.util.Objects;
import static com.notably.commons.util.CollectionUtil.requireAllNonNull;

import com.notably.logic.Logic;
import com.notably.model.Model;

import javafx.scene.layout.StackPane;
Expand All @@ -10,15 +11,15 @@
* View of the currently open block's content.
*/
public class BlockContent {

private final BlockContentDisplayView blockContentDisplayView;
private final BlockContentEditView blockContentEditView;

public BlockContent(StackPane blockContentPlaceholder, Model model) {
Objects.requireNonNull(blockContentPlaceholder);
Objects.requireNonNull(model);
public BlockContent(StackPane blockContentPlaceholder, Logic logic, Model model) {
requireAllNonNull(blockContentPlaceholder, model, logic);

blockContentDisplayView = new BlockContentDisplayView(model);
blockContentEditView = new BlockContentEditView(model);
blockContentEditView = new BlockContentEditView(logic, model);

// TODO: Integrate BlockContentEditView
blockContentPlaceholder.getChildren().addAll(blockContentDisplayView.getRoot());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* Read-only and rendered view of the currently open block's content.
*/
public class BlockContentDisplayView extends ViewPart<WebView> {
private static final String FXML = "blockcontent/BlockContentDisplayView.fxml";

private static final String FXML = "blockcontent/BlockContentDisplayView.fxml";
private final Model model;

@FXML
Expand Down
222 changes: 206 additions & 16 deletions src/main/java/com/notably/view/blockcontent/BlockContentEditView.java
Original file line number Diff line number Diff line change
@@ -1,63 +1,253 @@
package com.notably.view.blockcontent;

import java.util.Objects;
import static com.notably.commons.util.CollectionUtil.requireAllNonNull;

import static java.util.Objects.requireNonNull;

import java.util.logging.Logger;

import com.notably.commons.LogsCenter;
import com.notably.commons.path.AbsolutePath;
import com.notably.logic.Logic;
import com.notably.logic.exceptions.EditBlockBodyException;
import com.notably.model.Model;
import com.notably.model.block.BlockTreeItem;
import com.notably.view.ViewPart;

import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TreeItem;
import javafx.scene.layout.Region;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;

/**
* Editable view of the currently open block's content.
* View-Controller for the Editable view of the currently open block's content.
*/
public class BlockContentEditView extends ViewPart<Region> {
private static final String FXML = "blockcontent/BlockContentEditView.fxml";
public class BlockContentEditView extends ViewPart<Stage> {

private static final Logger logger = LogsCenter.getLogger(BlockContentEditView.class);
private static final String FXML = "blockcontent/BlockContentEditView.fxml";
private final Stage stage;
private final Window parentStage;
private final Logic logic;
private final Model model;

@FXML
private TextArea blockContentTextArea;

public BlockContentEditView(Model model) {
super(FXML);
public BlockContentEditView(Logic logic, Model model) {
this(new Stage(), logic, model);
}

Objects.requireNonNull(model);
private BlockContentEditView(Stage root, Logic logic, Model model) {
super(FXML, root);

requireAllNonNull(logic, model);

this.stage = root;
this.logic = logic;
this.model = model;
this.parentStage = Stage.getWindows().stream().filter(Window::isShowing).findFirst().get();

setup();
setStageStyle();
setChangeListeners();
setInitialData();
}

/**
* Sets up the view's initial data and wire up all required change listeners.
* Customizes the appearance and attributes of the Block Edit Modal
*/
private void setup() {
// Initialize text area content
setText(model);
private void setStageStyle() {
stage.initStyle(StageStyle.TRANSPARENT);
stage.initOwner(parentStage);
stage.initModality(Modality.WINDOW_MODAL);
}

// Setup change listeners
/**
* Sets listeners that update the content in the Block Edit modal to that of the
* currently opened note, and toggle the visibility of the edit modal.
*/
private void setChangeListeners() {
model.currentlyOpenPathProperty().addListener(observable -> setText(model));
model.getBlockTree().getRootBlock().getTreeItem()
.addEventHandler(TreeItem.treeNotificationEvent(), event -> setText(model));
model.blockEditableProperty().addListener(observable -> {
if (model.isBlockEditable()) {
handleEdit();
model.setBlockEditable(false);
}
});

setKeyboardListeners();
setInitialDimensions();
setStageDimensionListeners();
}

/**
* Sets the {@link TextArea}'s content of with the currently open block's Markdown body.
* Triggers changes in the visibility of the Edit modal when certain Keystrokes are registered.
* Primarily, allows for the user to exit the Block Edit modal using the "ESC" keyboard shortcut.
*/
private void setKeyboardListeners() {
stage.addEventHandler(KeyEvent.KEY_RELEASED, (KeyEvent event) -> {
if (KeyCode.ESCAPE == event.getCode()) {
handleClose();
}
});
}
HemanshuGandhi marked this conversation as resolved.
Show resolved Hide resolved

/**
* Sets the initial X and Y coordinates of the Block Edit modal such that it is centered
* to the main app window.
*/
private void setInitialDimensions() {
ChangeListener<Number> widthListener = (observable, oldValue, newValue) -> {
setXDisplacement();
};
ChangeListener<Number> heightListener = (observable, oldValue, newValue) -> {
setYDisplacement();
};
stage.widthProperty().addListener(widthListener);
stage.heightProperty().addListener(heightListener);

stage.setOnShown(e -> {
stage.widthProperty().removeListener(widthListener);
stage.heightProperty().removeListener(heightListener);
});
}

/**
* Sets listeners that change the dimensions of the Block Edit modal upon being repeatedly
* opened and closed.
*/
private void setStageDimensionListeners() {
setXDisplacement();
setYDisplacement();
stage.setOnShowing(event -> {
setStageDimensionListeners();
});
}

/**
* Sets up the view's initial data and wire up all required change listeners.
*/
private void setInitialData() {
setText(model);
}

/**
* Sets the {@link TextArea}'s content to the currently open block's Markdown body.
*
* @param model App's model
*/
private void setText(Model model) {
Objects.requireNonNull(model);
requireNonNull(model);

AbsolutePath currentlyOpenPath = model.getCurrentlyOpenPath();
BlockTreeItem currentlyOpenBlock = model.getBlockTree().get(currentlyOpenPath);
String markdownBody = currentlyOpenBlock.getBody().getText();

blockContentTextArea.setText(markdownBody);
}

/**
* Closes the Block Edit modal after saving the changes to the note's contents.
*/
@FXML
public void handleClose() {
saveData();
hide();
}

/**
* Opens the Block Edit modal or focuses on it if it's already opened.
*/
private void handleEdit() {
if (!isShowing()) {
show();
} else {
focus();
}
}

/**
* Shows the Block Edit Modal.
*
* @throws IllegalStateException <ul>
* <li>
* if this method is called on a thread other than the JavaFX
* Application Thread.
* </li>
* <li>
* if this method is called during animation or layout processing.
* </li>
* <li>
* if this method is called on the primary stage.
* </li>
* <li>
* if {@code dialogStage} is already showing.
* </li>
* </ul>
*/
public void show() {
logger.info("Showing Edit Modal for currently open note...");
getRoot().show();
}

/**
* Returns true if the Block Edit modal is currently being shown.
*/
public boolean isShowing() {
return getRoot().isShowing();
}

/**
* Hides the Block Edit modal.
*/
public void hide() {
getRoot().hide();
logger.info("Closing Edit Modal for currently open note.");
}

/**
* Focuses on the Block Edit modal.
*/
public void focus() {
getRoot().requestFocus();
}

/**
* Saves the data in the Block Edit Modal by notifying the {@link Logic} layer of the app.
*/
private void saveData() {
try {
this.logic.editCurrentBlockBody(blockContentTextArea.getText());
logger.info("Writing new Note's contents to file...");
} catch (EditBlockBodyException e) {
logger.warning("Unable to write new contents to file.");
}
}

/**
* Calculates and sets the width of the Block Edit modal with respect to the main app window.
*/
private void setXDisplacement() {
Double newWidth = parentStage.getWidth() * 0.8;
stage.setWidth(newWidth);
stage.setX(parentStage.getX() + parentStage.getWidth() / 2 - newWidth / 2);
}

/**
* Calculates and sets the height of the Block Edit modal with respect to the main app window.
*/
private void setYDisplacement() {
Double newHeight = parentStage.getHeight() * 0.7;
stage.setHeight(newHeight);
stage.setY(parentStage.getY() + parentStage.getHeight() / 3 - newHeight / 3);
}
}

Loading