/************************************************************************** OmegaT - Computer Assisted Translation (CAT) tool with fuzzy matching, translation memory, keyword search, glossaries, and translation leveraging into updated projects. Copyright (C) 2016 Chihiro Hio, Aaron Madlon-Kay Home page: http://www.omegat.org/ Support center: http://groups.yahoo.com/group/OmegaT/ This file is part of OmegaT. OmegaT is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OmegaT 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. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. **************************************************************************/ package org.omegat.externalfinder; import java.awt.Component; import java.io.File; import java.io.FileNotFoundException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import org.omegat.core.Core; import org.omegat.core.CoreEvents; import org.omegat.core.data.IProject; import org.omegat.core.data.ProjectProperties; import org.omegat.core.events.IApplicationEventListener; import org.omegat.core.events.IProjectEventListener; import org.omegat.externalfinder.item.ExternalFinderConfiguration; import org.omegat.externalfinder.item.ExternalFinderItem; import org.omegat.externalfinder.item.ExternalFinderItem.SCOPE; import org.omegat.externalfinder.item.ExternalFinderItemMenuGenerator; import org.omegat.externalfinder.item.ExternalFinderItemPopupMenuConstructor; import org.omegat.externalfinder.item.ExternalFinderXMLLoader; import org.omegat.externalfinder.item.ExternalFinderXMLWriter; import org.omegat.externalfinder.item.IExternalFinderItemLoader; import org.omegat.externalfinder.item.IExternalFinderItemMenuGenerator; import org.omegat.util.StaticUtils; import org.omegat.util.gui.MenuItemPager; /** * Entry point for ExternalFinder functionality. * <p> * ExternalFinder was originally a plugin developed by Chihiro Hio, and * generously donated for inclusion in OmegaT itself. * <p> * See {@link #getProjectFile(IProject)} and {@link ExternalFinderItem} for * details about how this implementation's behavior differs from the original * plugin. * <p> * See the plugin page or <code>package.html</code> for information about the * XML format. * * @see <a href= * "https://github.com/hiohiohio/omegat-plugin-externalfinder">omegat-plugin-externalfinder * on GitHub</a> */ public class ExternalFinder { public static final String FINDER_FILE = "finder.xml"; private static Logger LOGGER = Logger.getLogger(ExternalFinder.class.getName()); /** * OmegaT will call this method when loading. */ public static void loadPlugins() { // register listeners CoreEvents.registerApplicationEventListener(generateIApplicationEventListener()); CoreEvents.registerProjectChangeListener(generateIProjectEventListener()); } private static IProjectEventListener generateIProjectEventListener() { return new IProjectEventListener() { private final List<Component> menuItems = new ArrayList<Component>(); @Override public void onProjectChanged(final IProjectEventListener.PROJECT_CHANGE_TYPE eventType) { switch (eventType) { case LOAD: onLoad(); break; case CLOSE: onClose(); break; default: // ignore } } private void onLoad() { // clear old items menuItems.clear(); // add finder items to menuItems IExternalFinderItemMenuGenerator generator = new ExternalFinderItemMenuGenerator(ExternalFinderItem.TARGET.BOTH, false); List<JMenuItem> newMenuItems = generator.generate(); JMenu toolsMenu = Core.getMainWindow().getMainMenu().getToolsMenu(); // Separator Component separator = new JPopupMenu.Separator(); toolsMenu.add(separator); menuItems.add(separator); // add menuItems to menu MenuItemPager pager = new MenuItemPager(toolsMenu); for (JMenuItem component : newMenuItems) { pager.add(component); } menuItems.addAll(pager.getFirstPage()); } private void onClose() { // remove menu items final JMenu menu = Core.getMainWindow().getMainMenu().getToolsMenu(); menuItems.forEach(menu::remove); menuItems.clear(); PROJECT_CONFIG = null; } }; } private static IApplicationEventListener generateIApplicationEventListener() { return new IApplicationEventListener() { @Override public void onApplicationStartup() { Core.getEditor().registerPopupMenuConstructors(getGlobalConfig().getPriority(), new ExternalFinderItemPopupMenuConstructor()); } @Override public void onApplicationShutdown() { } }; } public static void unloadPlugins() { } private static ExternalFinderConfiguration GLOBAL_CONFIG; /** * Get the global configuration. This is stored in the user's OmegaT * configuration directory. If the file does not exist, an empty * configuration will be created and returned. * * @return The configuration (will never be null) */ public static ExternalFinderConfiguration getGlobalConfig() { if (GLOBAL_CONFIG == null) { try { File globalFile = getGlobalConfigFile(); IExternalFinderItemLoader userItemLoader = new ExternalFinderXMLLoader(globalFile, SCOPE.GLOBAL); GLOBAL_CONFIG = userItemLoader.load(); } catch (FileNotFoundException e) { // Ignore } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } if (GLOBAL_CONFIG == null) { GLOBAL_CONFIG = ExternalFinderConfiguration.empty(); } } return GLOBAL_CONFIG; } /** * Set the global configuration. Any existing configuration file will be * overwritten with the new one. Pass null to delete the config file. */ public static void setGlobalConfig(ExternalFinderConfiguration newConfig) { ExternalFinderConfiguration oldConfig = GLOBAL_CONFIG; GLOBAL_CONFIG = newConfig; if (!Objects.equals(newConfig, oldConfig)) { writeConfig(newConfig, getGlobalConfigFile()); } } private static File getGlobalConfigFile() { String configDir = StaticUtils.getConfigDir(); return new File(configDir, FINDER_FILE); } private static ExternalFinderConfiguration PROJECT_CONFIG; /** * Get the project-specific configuration. * * @return The configuration, or null if no project is loaded or the project * has no config file */ public static ExternalFinderConfiguration getProjectConfig() { IProject currentProject = Core.getProject(); if (!currentProject.isProjectLoaded()) { return null; } if (PROJECT_CONFIG == null) { // load project's xml file File projectFile = getProjectFile(currentProject); IExternalFinderItemLoader projectItemLoader = new ExternalFinderXMLLoader(projectFile, SCOPE.PROJECT); try { PROJECT_CONFIG = projectItemLoader.load(); } catch (FileNotFoundException e) { // Ignore } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } } return PROJECT_CONFIG; } /** * Set the project-specific configuration. Has no effect if no project is * loaded. Any existing configuration file will be overwritten with the new * one. Pass null to delete the config file. */ public static void setProjectConfig(ExternalFinderConfiguration newConfig) { IProject currentProject = Core.getProject(); if (!currentProject.isProjectLoaded()) { return; } ExternalFinderConfiguration oldConfig = PROJECT_CONFIG; PROJECT_CONFIG = newConfig; if (!Objects.equals(newConfig, oldConfig)) { File projectFile = getProjectFile(currentProject); writeConfig(newConfig, projectFile); } } private static void writeConfig(ExternalFinderConfiguration config, File toFile) { if (config == null) { boolean deleted = toFile.delete(); if (!deleted) { LOGGER.log(Level.SEVERE, "Unable to delete ExternalFinder config file: {0}", toFile); } } else { try { File tmpFile = File.createTempFile("omt", "externalfinder"); ExternalFinderXMLWriter writer = new ExternalFinderXMLWriter(tmpFile); writer.write(config); Files.move(tmpFile.toPath(), toFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } } } /** * Get the project-specific config file. In the original plugin this was * stored in the project root ({@link ProjectProperties#getProjectRoot()}); * now it's in the <code>omegat</code> directory for consistency with other * project-specific config files. */ private static File getProjectFile(IProject project) { ProjectProperties projectProperties = project.getProjectProperties(); File projectRoot = projectProperties.getProjectInternalDir(); return new File(projectRoot, FINDER_FILE); } public static List<ExternalFinderItem> getItems() { // replace duplicated items based on name List<ExternalFinderItem> result = new ArrayList<>(getGlobalConfig().getItems()); ExternalFinderConfiguration projectConfig = getProjectConfig(); if (projectConfig != null) { projectConfig.getItems().forEach(item -> addOrReplaceByName(result, item)); } return Collections.unmodifiableList(result); } static void addOrReplaceByName(List<ExternalFinderItem> items, ExternalFinderItem item) { for (int i = 0; i < items.size(); i++) { if (items.get(i).getName().equals(item.getName())) { items.set(i, item); return; } } items.add(item); } }