/* * This file is part of the Illarion project. * * Copyright © 2014 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.easynpc.gui; import illarion.common.util.Base64; import illarion.easynpc.EasyNpcScript; import illarion.easynpc.Lang; import illarion.easynpc.ParsedNpc; import illarion.easynpc.ScriptWriter; import org.pushingpixels.flamingo.api.common.icon.ImageWrapperResizableIcon; import org.pushingpixels.flamingo.api.common.icon.ResizableIcon; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.filechooser.FileFilter; import java.awt.*; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; /** * A small set of static utility functions that help at some points. * * @author Martin Karing <nitram@illarion.org> */ final class Utils { /** * The logger instance that takes care for the logging output of this class. */ private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class); private Utils() { } @Nullable public static ResizableIcon getResizableIconFromResource(String resource) { Image image; try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); image = ImageIO.read(cl.getResource(resource)); } catch (@Nonnull IOException e) { LOGGER.error("Failed to read image: \"{}\"", resource); return null; } int height = image.getHeight(null); int width = image.getWidth(null); return ImageWrapperResizableIcon.getIcon(image, new Dimension(width, height)); } /** * Parse the script shown in this editor but don't do anything with it but * showing the errors. * * @param editor the editor that contains the script to parse */ public static void reparseSilent(@Nonnull Editor editor) { // NO_UCD editor.getParsedData(); } /** * Open a script from a file and display it in a new editor. * * @param file the file that is the source of this script */ static void openScript(@Nonnull MainFrame frame, @Nonnull Path file) { try { int editorIndex = frame.alreadyOpen(file); if (editorIndex > -1) { frame.setCurrentEditorTab(editorIndex); return; } EasyNpcScript easyScript = new EasyNpcScript(file); frame.addNewScript().loadScript(easyScript); frame.setCurrentTabTitle(file.getFileName().toString()); Config.getInstance().addLastOpenedFile(file); } catch (@Nonnull IOException e1) { LOGGER.error("Reading the script failed.", e1); //$NON-NLS-1$ } } /** * Save a script in the editor as easyNPC script. This saves the current * state of the script and does not parse it again. * * @param editor the editor that supplies the script text */ static void saveEasyNPC(@Nonnull MainFrame frame, @Nonnull Editor editor) { Path targetFile = editor.getScriptFile(); if (targetFile == null) { selectAndSaveEasyNPC(frame, editor); return; } saveEasyNPCImpl(editor, targetFile); editor.saved(); } /** * Save the script in the editor as a LUA script. This results in parsing * the script and in case this went fine the user is ordered to select a * location to save the LUA version of the script. * * @param editor the editor containing the original script. */ static void saveLuaScript(@Nonnull MainFrame frame, @Nonnull Editor editor) { ParsedNpc npc = editor.getParsedData(); if (npc == null) { JOptionPane.showMessageDialog(frame, Lang.getMsg(Utils.class, "saveLuaErrors"), Lang.getMsg(Utils.class, "saveLuaErrorsTitle"), JOptionPane.ERROR_MESSAGE); return; } JFileChooser fileDiag = new JFileChooser(); fileDiag.setFileFilter(new FileFilter() { @Override public boolean accept(@Nonnull File f) { return !f.isFile() || f.getName().endsWith(".lua"); //$NON-NLS-1$ } @Override public String getDescription() { return Lang.getMsg(Utils.class, "luaScriptsFileType"); //$NON-NLS-1$ } }); fileDiag.setCurrentDirectory(new File(Config.getInstance().getLuaNpcFolder())); fileDiag.setSelectedFile( new File(Config.getInstance().getLuaNpcFolder() + File.separator + npc.getLuaFilename())); int fileReturn = fileDiag.showSaveDialog(frame); if (fileReturn == JFileChooser.APPROVE_OPTION) { File targetFile = fileDiag.getSelectedFile(); File backupFile = new File(targetFile.getAbsolutePath() + ".bak"); if (targetFile.exists()) { targetFile.renameTo(backupFile); } try { ScriptWriter writer = new ScriptWriter(); writer.setSource(npc); Writer outputWriter = new OutputStreamWriter(new FileOutputStream(targetFile), "ISO-8859-1"); writer.setWritingTarget(outputWriter); writer.write(); outputWriter.close(); if (backupFile.exists()) { backupFile.delete(); } } catch (@Nonnull IOException ex) { if (backupFile.exists()) { if (targetFile.exists()) { targetFile.delete(); } backupFile.renameTo(targetFile); } } } } /** * Display a file selection dialog to allow the player to select a easyNPC * script that is load after. */ static void selectAndOpenScript(@Nonnull MainFrame frame) { JFileChooser fileDiag = new JFileChooser(); fileDiag.setFileFilter(new FileFilter() { @Override public boolean accept(@Nonnull File f) { return !f.isFile() || f.getName().endsWith(".npc"); //$NON-NLS-1$ } @Override public String getDescription() { return Lang.getMsg(Utils.class, "easyNpcScriptsFileType"); //$NON-NLS-1$ } }); fileDiag.setCurrentDirectory(new File(Config.getInstance().getEasyNpcFolder())); int fileReturn = fileDiag.showOpenDialog(frame); if (fileReturn == JFileChooser.APPROVE_OPTION) { File selectedFile = fileDiag.getSelectedFile(); openScript(frame, selectedFile.toPath()); } } /** * Allow the user to select the folder and the file name where to store the * easyNPC script. Once selected the function saves the current state of the * script. * * @param editor the editor that supplies the script text */ static void selectAndSaveEasyNPC(@Nonnull MainFrame frame, @Nonnull Editor editor) { JFileChooser fileDiag = new JFileChooser(); fileDiag.setFileFilter(new FileFilter() { @Override public boolean accept(@Nonnull File f) { return !f.isFile() || f.getName().endsWith(".npc"); //$NON-NLS-1$ } @Override public String getDescription() { return Lang.getMsg(Utils.class, "easyNpcScriptsFileType"); //$NON-NLS-1$ } }); fileDiag.setCurrentDirectory(new File(Config.getInstance().getEasyNpcFolder())); Path scriptFile = editor.getScriptFile(); fileDiag.setSelectedFile((scriptFile == null) ? null : scriptFile.toFile()); int fileReturn = fileDiag.showSaveDialog(frame); if (fileReturn == JFileChooser.APPROVE_OPTION) { String targetFile = fileDiag.getSelectedFile().getAbsolutePath(); if (!targetFile.endsWith(".npc")) { targetFile += ".npc"; } Path realTargetFile = Paths.get(targetFile); saveEasyNPCImpl(editor, realTargetFile); editor.setLoadScriptFile(realTargetFile); frame.setTabTitle(editor, realTargetFile.getFileName().toString()); } editor.saved(); } static void uploadLuaScript(@Nonnull MainFrame frame, @Nonnull Editor editor) { ParsedNpc npc = editor.getParsedData(); if (npc == null) { JOptionPane.showMessageDialog(frame, Lang.getMsg(Utils.class, "uploadLuaErrors"), Lang.getMsg(Utils.class, "uploadLuaErrorsTitle"), JOptionPane.ERROR_MESSAGE); return; } try { URL url = new URL("http://illarion.org/~nitram/test_npc.php"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setDoInput(true); ScriptWriter writer = new ScriptWriter(); writer.setSource(npc); StringWriter stringWriter = new StringWriter(); writer.setWritingTarget(stringWriter); writer.write(); String script = stringWriter.toString(); String base64Script = Base64.encode(script, "UTF-8"); String fixedScript = base64Script.replace('\\', '_').replace('+', '-').replace('=', '*'); String query = "script=" + URLEncoder.encode(fixedScript, "UTF-8"); try (Writer output = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"))) { output.write(query); output.flush(); } try (InputStream input = conn.getInputStream()) { input.close(); } JOptionPane.showMessageDialog(frame, Lang.getMsg(Utils.class, "luaUploadInfos"), Lang.getMsg(Utils.class, "luaUploadInfosTitle"), JOptionPane.INFORMATION_MESSAGE); } catch (@Nonnull IOException ex) { LOGGER.error("Connection to host failed", ex); } } /** * The private implementation of the of the save easyScript function. This * writes a text to a file using the correct encoding. * * @param editor the editor supplying the script * @param targetFile the file that is the target of this writing operation */ private static void saveEasyNPCImpl(@Nonnull Editor editor, @Nonnull Path targetFile) { try { @Nullable Path backupFile = Files.createTempFile(targetFile.getParent(), "npc_", ".bak"); if (Files.isReadable(targetFile)) { Files.copy(targetFile, backupFile, StandardCopyOption.REPLACE_EXISTING); } else { Files.deleteIfExists(backupFile); backupFile = null; } try (Writer bufferedWriter = Files.newBufferedWriter(targetFile, EasyNpcScript.DEFAULT_CHARSET)) { String scriptText = editor.getScriptText(); EasyNpcScript.COPYRIGHT_HEADER.writeTo(bufferedWriter); bufferedWriter.write(scriptText); bufferedWriter.flush(); } catch (@Nonnull Exception e) { if (backupFile != null) { Files.copy(backupFile, targetFile, StandardCopyOption.REPLACE_EXISTING); } } if (backupFile != null) { Files.deleteIfExists(backupFile); } } catch (@Nonnull Exception e) { LOGGER.error("Writing the easyNPC Script failed.", e); //$NON-NLS-1$ } } }