package fetcher.controller;
import fetcher.model.PageEntry;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
*
* File name : EntryCell.java
*
* This class is the controller for the EntryCell.fxml file.
* Its main purpose is to react to user interaction with the single entry. (e.g : updating tags ) .
*
*/
public class EntryCell extends ListCell<PageEntry> {
PageEntry entry;
MainController controller;
@FXML
HBox hbox;
@FXML
TextField title;
@FXML
TextField description;
@FXML
ImageView imageView;
@FXML
Label date;
@FXML
Label urllbl;
@FXML
Label tags;
/**
* Constructor for EntryCell . The structure is a Horizontal box that has inside a picture and a vertical box. Inside the vertical box we have the title and the description.
*/
public EntryCell(MainController controller){
super();
this.controller = controller;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/EntryCell.fxml"));
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
title.textProperty().addListener(new TextFieldListener("title"));
description.textProperty().addListener(new TextFieldListener("description"));
tags.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
(new mouseClickedHandler()).openAddTagDialog();
}
});
}
/**
* This is used to update a cell entry.
* @param item the PageEntry that is being inserted / updated
* @param empty whether or not this cell represents data from the list. If it is empty, then it does not represent any domain data, but is a cell being used to render an "empty" row.
*/
@Override
protected void updateItem(PageEntry item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setGraphic(null);
setText(null);
}
else{
this.entry = item;
date.setText("Added on : " + item.getDateAdded().toString());
title.setText(item.getName());
urllbl.setText(item.getURL());
description.setText(item.getDescription());
Image image;
if(item.getPageSnapshot().isEmpty()){
image = new Image("images/octopus.png", 200 , 200, false , false );
}
else{
image = new Image(item.getPageSnapshot(), 200 , 200, false , false );
}
imageView.setImage(image);
updateTags();
setGraphic(hbox);
this.setOnMouseClicked(new mouseClickedHandler());
}
}
/**
* Updates the UI with all the new added tags.
*/
public void updateTags(){
this.tags.setText("");
for(String tag : entry.getTags()) {
if (tags.getText().isEmpty())
tags.setText(tag);
else
tags.setText(tags.getText() + "," + tag);
}
}
class mouseClickedHandler implements EventHandler<MouseEvent>{
/**
* Opens up the default browser to open the url of the selected entry. Only works if double-clicked.
* @param event the event which occurred.
*/
@Override
public void handle(MouseEvent event) {
//Double left click : Open URL.
if(event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2 && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(new URI(urllbl.getText()));
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
//TODO: Tell the user the URL is probably wrong.
e.printStackTrace();
}
}
//Right click: Add tag to selected item.
else if(event.getButton() == MouseButton.SECONDARY){
openAddTagDialog();
}
}
/**
* Creates and opens the dialog to add a tag.
*/
public void openAddTagDialog(){
final Stage dialogStage = new Stage();
dialogStage.initModality(Modality.WINDOW_MODAL);
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
Button ok = new Button("OK");
final TextField textfield = new TextField();
textfield.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
handleActionTagAdded(textfield,dialogStage);
}
});
vBox.getChildren().addAll(new Label("Tag:"),textfield,ok);
//Handler of the OK pressing button. Gets the tag and adds it to the existing ones if it doesn't already exists.
ok.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
handleActionTagAdded(textfield,dialogStage);
}
});
dialogStage.setScene(new Scene(vBox));
dialogStage.show();
}
/**
* Adds the tag to the PageEntry associated with the EntryCell.
* @param textfield , the textfield where the tag text is located.
* @param dialogStage , the dialog of add a tag.
*/
private void handleActionTagAdded(TextField textfield , Stage dialogStage){
String text = textfield.getText();
if(!text.isEmpty()) {
//Making sure the tag doesn't already exists.
if(!entry.getTags().contains(text)) {
entry.addTag(text);
updateTags();
controller.pad.addTag(text);
}
dialogStage.close();
}
}
}
/**
* TextFieldListener for the title and description. Updates the corrisponding entry's fields.
*/
class TextFieldListener implements ChangeListener<String> {
String FieldToModify;
public TextFieldListener(String FieldToModify){
this.FieldToModify = FieldToModify;
}
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if(FieldToModify.equalsIgnoreCase("Title"))
entry.setName(title.getText());
else if(FieldToModify.equalsIgnoreCase("Description"))
entry.setDescription(description.getText());
}
}
}