/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.ks.idnadrev.information.uml; import de.ks.BaseController; import de.ks.executor.group.LastTextChange; import de.ks.file.FileOptions; import de.ks.i18n.Localized; import de.ks.idnadrev.category.CategorySelection; import de.ks.idnadrev.entity.information.UmlDiagramInfo; import de.ks.idnadrev.tag.TagContainer; import de.ks.option.Options; import de.ks.text.PersistentStoreBack; import de.ks.validation.validators.NamedEntityMustNotExistValidator; import de.ks.validation.validators.NotEmptyValidator; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; import javafx.geometry.HPos; import javafx.geometry.Rectangle2D; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.scene.layout.StackPane; import javafx.scene.web.WebView; import javafx.stage.FileChooser; import javafx.stage.Popup; import javafx.stage.Screen; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils; import org.controlsfx.dialog.Dialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ResourceBundle; import java.util.concurrent.CompletableFuture; public class UmlDiagramController extends BaseController<UmlDiagramInfo> { private static final Logger log = LoggerFactory.getLogger(UmlDiagramController.class); @FXML protected Button saveImage; @FXML protected Button fullscreen; @FXML protected StackPane previewContainer; @FXML protected TextField name; @FXML protected SplitPane splitPane; @FXML protected TextArea content; @FXML protected Button saveBtn; @FXML protected TagContainer tagContainerController; @FXML protected CategorySelection categorySelectionController; protected WebView webView; protected WebView fullScreenWebView; protected LastTextChange lastTextChange; protected boolean showFullScreen = false; protected PersistentStoreBack persistentStoreBack; protected final UmlDiagramRender render = new UmlDiagramRender(); @Override public void initialize(URL location, ResourceBundle resources) { CompletableFuture.supplyAsync(() -> new WebView(), controller.getJavaFXExecutor()).thenAccept(view -> { webView = view; webView.setMinSize(100, 100); webView.setPrefSize(Control.USE_COMPUTED_SIZE, Control.USE_COMPUTED_SIZE); webView.widthProperty().addListener((p, o, n) -> { lastTextChange.trigger(); }); previewContainer.getChildren().add(webView); }); CompletableFuture.supplyAsync(() -> new WebView(), controller.getJavaFXExecutor()).thenAccept(view -> { fullScreenWebView = view; fullScreenWebView.setMinSize(100, 100); fullScreenWebView.setPrefSize(Control.USE_COMPUTED_SIZE, Control.USE_COMPUTED_SIZE); }); StringProperty nameProperty = store.getBinding().getStringProperty(UmlDiagramInfo.class, t -> t.getName()); name.textProperty().bindBidirectional(nameProperty); StringProperty contentProperty = store.getBinding().getStringProperty(UmlDiagramInfo.class, t -> t.getContent()); content.textProperty().bindBidirectional(contentProperty); validationRegistry.registerValidator(name, new NotEmptyValidator()); validationRegistry.registerValidator(name, new NamedEntityMustNotExistValidator<>(UmlDiagramInfo.class, t -> t.getId() == store.<UmlDiagramInfo>getModel().getId())); saveBtn.disableProperty().bind(validationRegistry.invalidProperty()); lastTextChange = new LastTextChange(content, 750, controller.getExecutorService()); lastTextChange.registerHandler(f -> { f.thenApplyAsync(s -> render.generatePng(s, getFullScreenWidth(), getFullScreenImagePath()), controller.getExecutorService())// .thenAcceptAsync(file -> { file.deleteOnExit(); if (showFullScreen) { showRenderedFile(file, fullScreenWebView); } }, controller.getJavaFXExecutor()); f.thenAcceptAsync(persistentStoreBack::save, controller.getExecutorService()); f.thenApply(s -> render.generatePng(s, webView.getWidth(), getImagePath()))// .thenAcceptAsync(file -> showRenderedFile(file, webView), controller.getJavaFXExecutor()); }); persistentStoreBack = new PersistentStoreBack(getClass().getSimpleName(), new File(Options.get(FileOptions.class).getFileStoreDir())); } private void showRenderedFile(File file, WebView view) { if (file == null) { return; } try { file.deleteOnExit(); URL url = file.toURI().toURL(); view.getEngine().load(url.toExternalForm()); } catch (MalformedURLException e) { log.error("Could not load {}", file, e); } } private Path getImagePath() { return Paths.get(System.getProperty("java.io.tmpdir"), "idnadrev_uml_editor.png"); } private Path getFullScreenImagePath() { return Paths.get(System.getProperty("java.io.tmpdir"), "idnadrev_uml_editor_fullscreen.png"); } @Override protected void onRefresh(UmlDiagramInfo model) { super.onRefresh(model); File s = GraphvizUtils.getDotExe(); if (s == null) { Dialog dialog = new Dialog(saveBtn.getScene().getRoot(), Localized.get("install.graphviz"), true); GridPane gridPane = new GridPane(); gridPane.setVgap(10); Label label = new Label(Localized.get("install.graphviz.detailed")); Hyperlink link = new Hyperlink("http://www.graphviz.org/Download.php"); link.setOnAction(e -> openGraphvizUrl()); gridPane.add(label, 0, 0); gridPane.add(link, 0, 1); GridPane.setHalignment(link, HPos.CENTER); dialog.setContent(gridPane); dialog.show(); } if (content.textProperty().getValueSafe().trim().isEmpty()) { String text = persistentStoreBack.load(); content.setText(text); } } private void openGraphvizUrl() { controller.getJavaFXExecutor().submit(() -> { try { java.awt.Desktop.getDesktop().browse(URI.create("http://www.graphviz.org/Download.php")); } catch (IOException e) { log.error("Could not open graphviz browse", e); } }); } @Override public void duringSave(UmlDiagramInfo model) { persistentStoreBack.delete(); } @FXML protected void onSave() { controller.save(); controller.stopCurrent(); } @FXML protected void onSaveImage() { FileChooser fileChooser = new FileChooser(); fileChooser.setInitialFileName("umlDiagram"); FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("png", "png"); fileChooser.setSelectedExtensionFilter(filter); File file = fileChooser.showOpenDialog(saveBtn.getScene().getWindow()); if (file != null) { try { Files.copy(getFullScreenImagePath(), file.toPath()); } catch (IOException e) { log.error("could nto save file {}", file, e); } } } private double getFullScreenWidth() { Screen primary = Screen.getPrimary(); Rectangle2D visualBounds = primary.getVisualBounds(); return visualBounds.getWidth(); } @FXML public void onShowFullScreen() { Screen primary = Screen.getPrimary(); Rectangle2D visualBounds = primary.getVisualBounds(); this.showFullScreen = true; CompletableFuture<File> future = CompletableFuture.supplyAsync(() -> { Path path = getFullScreenImagePath(); if (path.toFile().exists()) { return path.toFile(); } else { return null; } }, controller.getExecutorService()); future.thenAcceptAsync(file -> showRenderedFile(file, fullScreenWebView), controller.getJavaFXExecutor()); Popup popup = new Popup(); StackPane pane = new StackPane(); pane.setPrefWidth(visualBounds.getWidth()); pane.setPrefHeight(visualBounds.getHeight()); pane.getChildren().add(fullScreenWebView); popup.getContent().add(pane); popup.setX(0); popup.setY(0); popup.setWidth(visualBounds.getWidth()); popup.setHeight(visualBounds.getHeight()); popup.setOnHiding(e -> showFullScreen = false); popup.show(fullscreen.getScene().getWindow()); } public PersistentStoreBack getPersistentStoreBack() { return persistentStoreBack; } }