package com.twasyl.slideshowfx.controls.builder.editor; import com.twasyl.slideshowfx.utils.ResourceHelper; import com.twasyl.slideshowfx.utils.ZipUtils; import com.twasyl.slideshowfx.utils.io.DefaultCharsetWriter; import javafx.concurrent.Worker; import javafx.scene.web.WebView; import java.io.*; import java.nio.file.Files; import java.util.Base64; import java.util.logging.Level; import java.util.logging.Logger; import static com.twasyl.slideshowfx.global.configuration.GlobalConfiguration.getDefaultCharset; /** * This file editor uses ACE in order to display the content of files. ACE provides * syntax highlighting and other options. * * @author Thierry Wasylczenko * @version 1.0 * @since SlideshowFX 1.0 */ public class ACEFileEditor extends AbstractFileEditor<WebView> { private static final Logger LOGGER = Logger.getLogger(ACEFileEditor.class.getName()); public ACEFileEditor() { super(); final WebView webView = new WebView(); webView.getEngine().load(this.prepareAndGetEditorPageURI()); this.setFileContent(webView); } public ACEFileEditor(File file) { this(); this.setFile(file); } /** * Prepare the HTML page that is used to define and edit slides' content and return the {@link java.net.URI} of the * page in order to be loaded by a {@link WebView}. * @return The {@link java.net.URI} of the page to load. */ private String prepareAndGetEditorPageURI() { final File tempDirectory = new File(System.getProperty("java.io.tmpdir")); final File editorDir = new File(tempDirectory, "sfx-slide-content-editor"); final File editorFile = new File(editorDir, "ace-file-editor.html"); final String uri = editorFile.toURI().toASCIIString(); if(!editorFile.exists()) { try(final InputStream editorZip = ResourceHelper.getInputStream("/com/twasyl/slideshowfx/sfx-slide-content-editor.zip")) { ZipUtils.unzip(editorZip, tempDirectory); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Can not extract the slide content editor ZIP", e); } } return uri; } @Override public void updateFileContent() { if(getFile() == null) throw new NullPointerException("The fileProperty is null"); try(final FileInputStream fileInput = new FileInputStream(getFile()); final InputStreamReader inputReader = new InputStreamReader(fileInput, getDefaultCharset()); final BufferedReader reader = new BufferedReader(inputReader)) { final StringBuilder builder = new StringBuilder(); reader.lines().forEach(line -> builder.append(line).append("\n")); getFileContent().getEngine().getLoadWorker().stateProperty().addListener((value, oldState, newState) -> { if(newState == Worker.State.SUCCEEDED) { getFileContent().getEngine().executeScript("setContent(\"".concat(Base64.getEncoder().encodeToString(builder.toString().getBytes())).concat("\");")); // Set the mode of the editor depending on the file MIME type String mode = "ace/mode/"; try { final String mimeType = Files.probeContentType(getFile().toPath()); // If no mime type, fallback on the extension if (mimeType == null) { if(getFile().getName().endsWith(".js")) mode = mode.concat("javascript"); else if(getFile().getName().endsWith(".html"))mode = mode.concat("html"); else if(getFile().getName().endsWith(".css")) mode = mode.concat("css"); else mode = mode.concat("plain_text"); } else if(mimeType.contains("text/html")) mode = mode.concat("html"); else if(mimeType.contains("text/css")) mode = mode.concat("css"); } catch (IOException e) { LOGGER.log(Level.FINE, "Can not determine MIME type for the file editor", e); mode = mode.concat("plain_text"); } getFileContent().getEngine().executeScript("setMode(\"".concat(mode).concat("\");")); } }); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Can not save the content", e); } } @Override public void saveContent() { if(getFile() == null) throw new NullPointerException("The fileProperty is null"); try(final DefaultCharsetWriter writer = new DefaultCharsetWriter(getFile())) { final String content = (String) this.getFileContent().getEngine().executeScript("getContent();"); byte[] bytes = Base64.getDecoder().decode(content); writer.write(new String(bytes, getDefaultCharset())); writer.flush(); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Can not save the content", e); } } }