ch.cyberduck.ui.cocoa.odb.EditorFactory.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.ui.cocoa.odb.EditorFactory.java

Source

package ch.cyberduck.ui.cocoa.odb;

/*
 *  Copyright (c) 2007 David Kocher. All rights reserved.
 *  http://cyberduck.ch/
 *
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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.
 *
 *  Bug fixes, suggestions and comments should be sent to:
 *  dkocher@cyberduck.ch
 */

import ch.cyberduck.core.Local;
import ch.cyberduck.core.LocalFactory;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.Preferences;
import ch.cyberduck.ui.cocoa.BrowserController;
import ch.cyberduck.ui.cocoa.application.NSWorkspace;
import ch.cyberduck.ui.cocoa.foundation.NSBundle;
import ch.cyberduck.ui.cocoa.foundation.NSDictionary;
import ch.cyberduck.ui.cocoa.foundation.NSObject;

import org.apache.commons.collections.map.AbstractLinkedMap;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @version $Id$
 */
public class EditorFactory {
    private static Logger log = Logger.getLogger(EditorFactory.class);

    /**
     * @param c
     * @param path
     * @return New editor instance for the given file type.
     */
    public static Editor createEditor(BrowserController c, final Path path) {
        return createEditor(c, defaultEditor(path.getLocal()), path);
    }

    /**
     * @param c
     * @param bundleIdentifier The application bundle identifier of the editor to use
     * @param path
     * @return New editor instance for the given file type.
     */
    public static Editor createEditor(BrowserController c, String bundleIdentifier, final Path path) {
        if (Preferences.instance().getBoolean("editor.odb.enable")) {
            if (ODBEditor.getInstalledEditors().containsValue(bundleIdentifier)) {
                return new ODBEditor(c, bundleIdentifier, path);
            }
        }
        if (Preferences.instance().getBoolean("editor.kqueue.enable")) {
            return new WatchEditor(c, bundleIdentifier, path);
        }
        log.error("No editor support enabled");
        return null;
    }

    /**
     * Determine the default editor set
     *
     * @return The bundle identifier of the default editor configured in
     *         Preferences or null if not installed.
     */
    public static String defaultEditor() {
        if (log.isTraceEnabled()) {
            log.trace("defaultEditor");
        }
        if (StringUtils.isEmpty(
                EditorFactory.getApplicationName(Preferences.instance().getProperty("editor.bundleIdentifier")))) {
            return null;
        }
        return Preferences.instance().getProperty("editor.bundleIdentifier");
    }

    /**
     * @param file
     * @return The bundle identifier of the application for this file or null if no
     *         suitable and installed editor is found.
     */
    public static String defaultEditor(final Local file) {
        if (log.isDebugEnabled()) {
            log.debug("defaultEditor:" + file);
        }
        if (null == file) {
            return defaultEditor();
        }
        if (Preferences.instance().getBoolean("editor.alwaysUseDefault")) {
            return defaultEditor();
        }
        // The default application set by launch services to open files of
        // the given type
        final String defaultApplication = file.getDefaultApplication();
        if (null == defaultApplication) {
            // Use default editor if not applicable application found which handles this file type
            return defaultEditor();
        }
        if (Preferences.instance().getBoolean("editor.odb.enable")) {
            // Find matching ODB editor if any
            for (final String bundleIdentifier : ODBEditor.getInstalledEditors().values()) {
                if (bundleIdentifier.equals(defaultApplication)) {
                    return bundleIdentifier;
                }
            }
        }
        if (Preferences.instance().getBoolean("editor.kqueue.enable")) {
            // Use application determined by launch services using file system notifications
            return defaultApplication;
        }
        log.warn("No editor for file type " + file.getExtension());
        return defaultEditor();
    }

    /**
     * @return All statically registered but possibly not installed editors
     */
    public static Map<String, String> getSupportedEditors() {
        if (log.isTraceEnabled()) {
            log.trace("getSupportedEditors");
        }
        Map<String, String> supported = new HashMap<String, String>();
        if (Preferences.instance().getBoolean("editor.odb.enable")) {
            supported.putAll(ODBEditor.getSupportedEditors());
        }
        if (Preferences.instance().getBoolean("editor.kqueue.enable")) {
            supported.putAll(WatchEditor.getSupportedEditors());
        }
        final String defaultEditor = defaultEditor();
        if (null == defaultEditor) {
            return supported;
        }
        if (!supported.values().contains(defaultEditor)) {
            supported.put(EditorFactory.getApplicationName(defaultEditor), defaultEditor);
        }
        return supported;
    }

    /**
     * @return All statically registered and installed editors
     */
    public static Map<String, String> getInstalledEditors() {
        if (log.isTraceEnabled()) {
            log.trace("getInstalledEditors");
        }
        Map<String, String> installed = new HashMap<String, String>();
        if (Preferences.instance().getBoolean("editor.odb.enable")) {
            installed.putAll(ODBEditor.getInstalledEditors());
        }
        if (Preferences.instance().getBoolean("editor.kqueue.enable")) {
            installed.putAll(WatchEditor.getInstalledEditors());
        }
        return installed;
    }

    /**
     * @param file
     * @return Installed applications suitable to edit the given file type. Does always include
     *         the default editor set in the Preferences
     */
    public static Map<String, String> getInstalledEditors(final Local file) {
        if (log.isTraceEnabled()) {
            log.trace("getInstalledEditors:" + file);
        }
        if (null == file) {
            return getInstalledEditors();
        }
        if (!Preferences.instance().getBoolean("editor.kqueue.enable")) {
            return getInstalledEditors();
        }
        Map<String, String> editors = new HashMap<String, String>();
        for (String bundleIdentifier : file.getDefaultApplications()) {
            final String name = getApplicationName(bundleIdentifier);
            if (null == name) {
                continue;
            }
            editors.put(name, bundleIdentifier);
        }
        // Add the application set as the default editor in the Preferences to be always
        // included in the list of available editors.
        final String defaultEditor = defaultEditor();
        if (null != defaultEditor) {
            if (!editors.values().contains(defaultEditor)) {
                editors.put(getApplicationName(defaultEditor), defaultEditor);
            }
        }
        return editors;
    }

    /**
     * Caching map between application bundle identifier and
     * display name of application
     */
    private static Map<String, String> applicationNameCache = Collections
            .<String, String>synchronizedMap(new LRUMap(20) {
                @Override
                protected boolean removeLRU(AbstractLinkedMap.LinkEntry entry) {
                    log.debug("Removing from cache:" + entry);
                    return true;
                }
            });

    /**
     * Determine the human readable application name for a given bundle identifier.
     *
     * @param bundleIdentifier
     * @return
     */
    public static String getApplicationName(String bundleIdentifier) {
        if (!applicationNameCache.containsKey(bundleIdentifier)) {
            log.debug("getApplicationName:" + bundleIdentifier);
            final String path = NSWorkspace.sharedWorkspace()
                    .absolutePathForAppBundleWithIdentifier(bundleIdentifier);
            if (StringUtils.isBlank(path)) {
                log.warn("Cannot determine installation path for " + bundleIdentifier);
                applicationNameCache.put(bundleIdentifier, null);
                return null;
            }
            NSBundle app = NSBundle.bundleWithPath(path);
            if (null == app) {
                log.error("Loading bundle failed:" + path);
                applicationNameCache.put(bundleIdentifier, null);
                return null;
            }
            NSDictionary dict = app.infoDictionary();
            if (null == dict) {
                log.error("Loading application dictionary failed:" + path);
                applicationNameCache.put(bundleIdentifier, null);
                return null;
            }
            final NSObject name = dict.objectForKey("CFBundleName");
            if (null == name) {
                log.warn("No CFBundleName for " + bundleIdentifier);
                applicationNameCache.put(bundleIdentifier,
                        FilenameUtils.removeExtension(LocalFactory.createLocal(path).getDisplayName()));
            } else {
                applicationNameCache.put(bundleIdentifier, name.toString());
            }
        }
        return applicationNameCache.get(bundleIdentifier);
    }
}