/* * Copyright (C) 2015, VistaTEC or third-party contributors as indicated * by the @author tags or express copyright attribution statements applied by * the authors. All third-party contributions are distributed under license by * VistaTEC. * * This file is part of Ocelot. * * Ocelot is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Ocelot 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, write to: * * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 * USA * * Also, see the full LGPL text here: <http://www.gnu.org/copyleft/lesser.html> */ package com.vistatec.ocelot; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.List; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.xml.stream.XMLStreamException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import com.vistatec.ocelot.events.OpenFileEvent; import com.vistatec.ocelot.events.ProvenanceAddEvent; import com.vistatec.ocelot.events.SegmentEditEvent; import com.vistatec.ocelot.events.SegmentNoteEditEvent; import com.vistatec.ocelot.events.api.OcelotEventQueue; import com.vistatec.ocelot.events.api.OcelotEventQueueListener; import com.vistatec.ocelot.plugins.PluginManager; import com.vistatec.ocelot.segment.model.BaseSegmentVariant; import com.vistatec.ocelot.segment.model.OcelotSegment; import com.vistatec.ocelot.services.EditDistanceReportService; import com.vistatec.ocelot.services.SegmentService; import com.vistatec.ocelot.services.XliffService; import com.vistatec.ocelot.xliff.XLIFFDocument; import com.vistatec.ocelot.xliff.freme.XliffFremeAnnotationWriter; /** * Main Ocelot application context. */ public class OcelotApp implements OcelotEventQueueListener { private static final Logger LOG = LoggerFactory.getLogger(OcelotApp.class); private final OcelotEventQueue eventQueue; private final PluginManager pluginManager; private final SegmentService segmentService; private final XliffService xliffService; private final EditDistanceReportService editDistService; private XLIFFDocument openXliffFile; private File openFile; private boolean fileDirty = false, hasOpenFile = false; @Inject public OcelotApp(OcelotEventQueue eventQueue, PluginManager pluginManager, SegmentService segmentService, XliffService xliffService) { this.eventQueue = eventQueue; this.pluginManager = pluginManager; this.segmentService = segmentService; this.xliffService = xliffService; this.editDistService = new EditDistanceReportService(segmentService); } public File getOpenFile() { return openFile; } /** * Check if a file has been opened by the workbench. * @return */ public boolean hasOpenFile() { return hasOpenFile; } /** * Returns whether there are unsaved changes in the segment data. * This includes segment edits and changes to LQI and Provenance data. * @return true if there are unsaved changes */ public boolean isFileDirty() { return fileDirty; } public void openFile(File openFile) throws IOException, FileNotFoundException, XMLStreamException { openXliffFile = xliffService.parse(openFile); segmentService.clearAllSegments(); segmentService.setSegments(openXliffFile); this.pluginManager.notifyOpenFile(openFile.getName(), openXliffFile.getSegments()); this.pluginManager.setSourceAndTargetLangs(openXliffFile.getSrcLocale().toString(), openXliffFile.getTgtLocale().toString()); this.pluginManager.enrichSegments(openXliffFile.getSegments()); this.openFile = openFile; hasOpenFile = true; fileDirty = false; eventQueue.post(new OpenFileEvent(openFile.getName(), openXliffFile)); } public void saveFile(File saveFile) throws ErrorAlertException, IOException { if (saveFile == null) { throw new ErrorAlertException("No file to save!", "No file was specified to save to."); } String filename = saveFile.getName(); if (saveFile.exists() && !saveFile.canWrite()) { throw new ErrorAlertException("Unable to save!", "The file " + filename + " can not be saved, because the file is not writeable."); } // Save to temp file, then move over actual target. This lets us ensure // the output is well-formed, as we save and then parse again to save // the annotations. Path tmpPath = Files.createTempFile("ocelot", "save"); File tmpFile = tmpPath.toFile(); xliffService.save(openXliffFile, tmpFile); try { XliffFremeAnnotationWriter annotationWriter = new XliffFremeAnnotationWriter( openXliffFile.getSrcLocale().toString(), openXliffFile .getTgtLocale().toString()); annotationWriter.saveAnnotations(tmpFile, segmentService); } catch (Exception e) { if (!tmpFile.delete()) { LOG.info("Failed to delete temp file: " + tmpFile.getPath()); } throw new ErrorAlertException("Unable to save!", "The file " + filename + " cannot be saved because the content is invalid. " + "If you edited tags, ensure they are correctly nested."); } this.fileDirty = false; editDistService.createEditDistanceReport(filename); pluginManager.notifySaveFile(filename); Files.move(tmpPath, saveFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } public String getFileSourceLang() { return openXliffFile.getSrcLocale().toString(); } public String getFileTargetLang() { return openXliffFile.getTgtLocale().toString(); } @Subscribe public void segmentEdit(SegmentEditEvent e) { this.fileDirty = true; } @Subscribe public void provenanceAdded(ProvenanceAddEvent e) { this.fileDirty = true; } @Subscribe public void noteEdit(SegmentNoteEditEvent e) { this.fileDirty = true; } public class ErrorAlertException extends Exception { private static final long serialVersionUID = 1L; public final String title, body; public ErrorAlertException(String title, String body) { this.title = title; this.body = body; } } public List<JMenu> getPluginMenuList(JFrame mainframe) { return pluginManager.getPluginMenuList(mainframe); } public List<JMenuItem> getSegmentContexPluginMenues(OcelotSegment segment, BaseSegmentVariant variant, boolean target) { return pluginManager.getSegmentContextMenuItems(segment, variant, target); } }