Java tutorial
package org.ado.biblio.desktop; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.Event; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.util.Callback; import org.ado.biblio.desktop.about.AboutPresenter; import org.ado.biblio.desktop.about.AboutView; import org.ado.biblio.desktop.android.AndroidView; import org.ado.biblio.desktop.db.DatabaseConnection; import org.ado.biblio.desktop.dropbox.DropboxException; import org.ado.biblio.desktop.dropbox.DropboxManager; import org.ado.biblio.desktop.dropbox.DropboxPresenter; import org.ado.biblio.desktop.dropbox.DropboxView; import org.ado.biblio.desktop.lend.LendPresenter; import org.ado.biblio.desktop.lend.LendView; import org.ado.biblio.desktop.model.Book; import org.ado.biblio.desktop.model.BookDetails; import org.ado.biblio.desktop.model.LendBook; import org.ado.biblio.desktop.returnbook.ReturnBookPresenter; import org.ado.biblio.desktop.returnbook.ReturnBookView; import org.ado.biblio.desktop.server.ServerPullingService; import org.ado.biblio.desktop.server.ServerStatusEnum; import org.ado.biblio.desktop.server.ServerStatusService; import org.ado.biblio.desktop.settings.SettingsPresenter; import org.ado.biblio.desktop.settings.SettingsView; import org.ado.biblio.desktop.update.UpdateManager; import org.ado.biblio.desktop.update.UpdateService; import org.ado.biblio.desktop.util.ImageUtils; import org.ado.biblio.domain.BookMessageDTO; import org.ado.googleapis.books.BookInfo; import org.ado.googleapis.books.NoBookInfoFoundException; import org.apache.commons.lang3.StringUtils; import org.controlsfx.control.action.Action; import org.controlsfx.dialog.Dialogs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.ResourceBundle; import java.util.function.Predicate; import java.util.stream.Collectors; /* * The MIT License (MIT) * * Copyright (c) 2015 Andoni del Olmo * * 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. */ /** * Class description here. * * @author andoni * @since 25.10.2014 */ public class AppPresenter implements Initializable, LendPresenter.LendBookListener, ReturnBookPresenter.ReturnBookListener { private final Logger LOGGER = LoggerFactory.getLogger(AppPresenter.class); private final ObservableList<Book> bookData = FXCollections.observableArrayList(); private final ObservableList<LendBook> lendBookData = FXCollections.observableArrayList(); @FXML private TextField textFieldSearch; @FXML private TableView<Book> tableViewBooks; @FXML private TableColumn<Book, String> tableColumnId; @FXML private TableColumn<Book, String> tableColumnAuthor; @FXML private TableColumn<Book, String> tableColumnTitle; @FXML private TableColumn<Book, String> tableColumnCreation; @FXML private TableView<LendBook> tableViewLentBooks; @FXML private TableColumn<LendBook, String> tableColumnLendTitle; @FXML private TableColumn<LendBook, String> tableColumnLendAuthor; @FXML private TableColumn<LendBook, String> tableColumnLendLentTo; @FXML private TableColumn<LendBook, String> tableColumnLendDate; @FXML private TextField textFieldTitle; @FXML private TextField textFieldAuthor; @FXML private TextField textFieldIsbn; @FXML private TextField textFieldTags; @FXML private ImageView imageViewCover; @FXML private Button buttonReturnBook; @FXML private Button buttonLend; @FXML private ImageView imageViewServerStatus; @FXML private Label labelSystem; @Inject private BookInfoLoader bookInfoLoader; @Inject private ServerPullingService serverPullingService; @Inject private ServerStatusService serverStatusService; @Inject private UpdateService updateService; @Inject private DatabaseConnection databaseConnection; @Inject private DropboxManager dropboxManager; @Inject private UpdateManager updateManager; private Stage stage; private Integer bookId; private int bookFocusedIndex; @PostConstruct public void init() throws Exception { LOGGER.info("PostConstruct..."); serverPullingService.setClientId(AppConfiguration.getAppId()); reloadBooksTable(); reloadLentTable(); } @Override public void initialize(URL location, ResourceBundle resources) { LOGGER.info("initializing..."); updateService.setOnSucceeded(updateManager.getOnSucceeded()); updateService.setOnFailed(updateManager.getOnFailed()); updateService.start(); tableColumnTitle.setCellValueFactory(cellData -> cellData.getValue().titleProperty()); tableColumnTitle.setCellFactory(getHighlightCellFactory()); tableColumnAuthor.setCellValueFactory(cellData -> cellData.getValue().authorProperty()); tableColumnCreation.setCellValueFactory(cellData -> cellData.getValue().creationProperty()); tableColumnLendAuthor.setCellValueFactory(cellData -> cellData.getValue().authorProperty()); tableColumnLendTitle.setCellValueFactory(cellData -> cellData.getValue().titleProperty()); tableColumnLendLentTo.setCellValueFactory(cellData -> cellData.getValue().personProperty()); tableColumnLendDate.setCellValueFactory(cellData -> cellData.getValue().creationProperty()); tableViewBooks.setItems(bookData); tableViewLentBooks.setItems(lendBookData); buttonLend.setDisable(true); buttonReturnBook.setDisable(true); serverStatusService.setOnSucceeded(event -> { final ServerStatusEnum serverStatus = (ServerStatusEnum) event.getSource().getValue(); switch (serverStatus) { case ONLINE: serverStatusImageOnline(); break; case OFFLINE: serverStatusImageOffline(); break; } }); serverStatusService.start(); serverPullingService.setOnSucceeded(event -> { serverStatusImageOnline(); BookMessageDTO[] bookMessages = (BookMessageDTO[]) event.getSource().getValue(); if (bookMessages != null) { for (BookMessageDTO bookMessage : bookMessages) { LOGGER.info("processing book [{}]", bookMessage); try { addBook(bookInfoLoader.getBookInfo(bookMessage)); labelSystem.setText(null); } catch (IOException e) { LOGGER.error(e.getMessage()); labelSystem.setText(e.getMessage()); } catch (NoBookInfoFoundException e) { LOGGER.error(e.getMessage()); labelSystem.setText(e.getMessage()); } } } serverPullingService.restart(); }); serverPullingService.setOnFailed(event -> { LOGGER.error(event.getSource().getMessage()); serverStatusImageOffline(); serverPullingService.restart(); }); serverPullingService.start(); tableViewBooks.setOnMouseClicked(this::loadBookDetails); tableViewLentBooks.setOnMouseClicked(this::loadBookDetails); } public void setStage(Stage stage) { this.stage = stage; } @PreDestroy private void destroy() { LOGGER.info("destroy"); serverPullingService.cancel(); } public void linkAndroid() { final AndroidView androidView = new AndroidView(); Stage stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(androidView.getView())); stage.setTitle("Android"); stage.show(); } public void linkDropbox() throws DropboxException { Stage stage = new Stage(); DropboxView dropboxView = new DropboxView(); final DropboxPresenter dropboxPresenter = (DropboxPresenter) dropboxView.getPresenter(); dropboxPresenter.setStage(stage); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(dropboxView.getView())); stage.setTitle("Dropbox"); stage.show(); } public void settings() { Stage stage = new Stage(); final SettingsView settingsView = new SettingsView(); final SettingsPresenter presenter = (SettingsPresenter) settingsView.getPresenter(); presenter.setStage(stage); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(settingsView.getView())); stage.setTitle("Settings"); stage.show(); } public void exit() { LOGGER.info("exit"); stage.close(); } public void about() { LOGGER.info("about"); Stage stage = new Stage(); final AboutView aboutView = new AboutView(); final AboutPresenter presenter = (AboutPresenter) aboutView.getPresenter(); presenter.setStage(stage); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(aboutView.getView())); stage.setTitle("About"); stage.show(); } public void search(Event event) throws SQLException { LOGGER.info("search"); String searchSequence = textFieldSearch.getCharacters().toString(); LOGGER.debug(searchSequence); reloadBooksTable(); if (!StringUtils.isBlank(searchSequence)) { bookData.removeIf(new Predicate<Book>() { @Override public boolean test(Book book) { final boolean containsMatch = book.getTitle().toLowerCase().contains(searchSequence) || book.getAuthor().toLowerCase().contains(searchSequence) || book.getTags().toLowerCase().contains(searchSequence); return !containsMatch; } }); } } public void clear() throws SQLException { LOGGER.info("clear"); textFieldSearch.clear(); reloadBooksTable(); } public void save() throws SQLException { LOGGER.info("save"); Collections.addAll(new ArrayList<>(), textFieldTags.getText().split(",")); if (bookId != null) { final Book book = new Book(bookId, textFieldTitle.getText(), textFieldAuthor.getText(), textFieldIsbn.getText(), new Date(), textFieldTags.getText()); databaseConnection.updateBook(book); bookData.set(bookFocusedIndex, book); } else { final Book book = databaseConnection.insertBook(new Book(textFieldTitle.getText(), textFieldAuthor.getText(), textFieldIsbn.getText(), new Date(), textFieldTags.getText())); bookData.add(book); } } public void add() { LOGGER.info("add"); resetBookView(); textFieldTitle.requestFocus(); tableViewBooks.scrollTo(bookData.size()); } public void delete() throws SQLException, DropboxException { LOGGER.info("delete"); Action response = Dialogs.create().title("Delete").message("Do you want to delete the book?").showConfirm(); if (response == org.controlsfx.dialog.Dialog.ACTION_YES) { databaseConnection.deleteBook(bookId); bookData.remove(bookFocusedIndex); ImageUtils.deleteCover(textFieldIsbn.getText()); dropboxManager.deleteCover(textFieldIsbn.getText()); resetBookView(); } } public void returnBook() { LOGGER.info("returnBook"); Stage stage = new Stage(); final ReturnBookView returnBookView = new ReturnBookView(); final ReturnBookPresenter presenter = (ReturnBookPresenter) returnBookView.getPresenter(); presenter.init(stage, this, bookId); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(returnBookView.getView())); stage.setTitle("Return Book"); stage.show(); } @Override public void returnBook(Book book) { bookData.set(bookFocusedIndex, book); setButtonsToLend(); try { reloadBooksTable(); reloadLentTable(); } catch (SQLException e) { e.printStackTrace(); } } public void lend() throws SQLException { LOGGER.info("lend"); Stage stage = new Stage(); final LendView lendView = new LendView(); final LendPresenter presenter = (LendPresenter) lendView.getPresenter(); presenter.init(stage, this, bookId); stage.initModality(Modality.APPLICATION_MODAL); stage.setScene(new Scene(lendView.getView())); stage.setTitle("Lend Book"); stage.show(); } @Override public void lentBook(Book book) { bookData.set(bookFocusedIndex, book); setButtonsToReturn(); try { reloadBooksTable(); reloadLentTable(); } catch (SQLException e) { e.printStackTrace(); } } private void reloadBooksTable() throws SQLException { bookData.clear(); bookData.addAll(databaseConnection.getBookList().stream().collect(Collectors.toList())); } private void reloadLentTable() throws SQLException { lendBookData.clear(); lendBookData.addAll(databaseConnection.getLentBookList().stream().collect(Collectors.toList())); } private void loadBookDetails(MouseEvent event) { bookFocusedIndex = ((TableView) event.getSource()).getFocusModel().getFocusedIndex(); BookDetails bookDetails = (BookDetails) ((TableView) event.getSource()).getFocusModel().getFocusedItem(); if (bookDetails != null) { bookId = bookDetails.getId(); textFieldTitle.setText(bookDetails.getTitle()); textFieldAuthor.setText(bookDetails.getAuthor()); textFieldIsbn.setText(bookDetails.getIsbn()); textFieldTags.setText(bookDetails.getTags()); if (bookDetails.isLent()) { setButtonsToReturn(); } else { setButtonsToLend(); } if (StringUtils.isNotBlank(bookDetails.getIsbn())) { imageViewCover.setImage(ImageUtils.readCoverOrDefault(bookDetails.getIsbn())); } else { imageViewCover.setImage(null); } } } private void addBook(BookInfo bookInfo) { LOGGER.info(bookInfo.toString()); try { final Book book = databaseConnection.insertBook( new Book(bookInfo.getTitle(), bookInfo.getAuthor(), bookInfo.getIsbn(), new Date(), "")); bookData.add(book); } catch (SQLException e) { LOGGER.error(String.format("Cannot insert book into database. %s", bookInfo.toString()), e); } if (bookInfo.getThumbnail() != null && StringUtils.isNotBlank(bookInfo.getIsbn())) { try { final File file = ImageUtils.writeCover(bookInfo.getThumbnail(), bookInfo.getIsbn()); dropboxManager.uploadCover(bookInfo.getIsbn(), file); } catch (IOException e) { LOGGER.error(String.format("Cannot write book's cover into disk. %s", bookInfo.toString()), e); } catch (DropboxException e) { e.printStackTrace(); } } } private void resetBookView() { bookId = null; textFieldTitle.setText(null); textFieldAuthor.setText(null); textFieldIsbn.setText(null); imageViewCover.setImage(null); } private void setButtonsToReturn() { buttonLend.setDisable(true); buttonReturnBook.setDisable(false); } private Callback<TableColumn<Book, String>, TableCell<Book, String>> getHighlightCellFactory() { return param -> new TableCell<Book, String>() { @Override protected void updateItem(String item, boolean empty) { getTableRow().getStyleClass().remove("bookLent"); if (getTableRow().getItem() != null) { setText(item); final boolean lent = isBookLend(); if (lent) { getTableRow().getStyleClass().add("bookLent"); } } else { setText(null); } } private boolean isBookLend() { final TableRow tableRow = getTableRow(); if (tableRow == null) { return false; } final Object item = tableRow.getItem(); if (item == null) { LOGGER.warn("Unexpected null in table row \"{}\".", tableRow.getIndex()); return false; } return ((BookDetails) item).isLent(); } }; } private void setButtonsToLend() { buttonLend.setDisable(false); buttonReturnBook.setDisable(true); } private void serverStatusImageOffline() { imageViewServerStatus.setImage(getImageResource("trafficlight-red.png")); } private void serverStatusImageOnline() { imageViewServerStatus.setImage(getImageResource("trafficlight-green.png")); } private Image getImageResource(String resourceName) { return new Image(AppPresenter.class.getResourceAsStream(resourceName)); } }