ch.cyberduck.core.preferences.UserDefaultsPreferences.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.core.preferences.UserDefaultsPreferences.java

Source

package ch.cyberduck.core.preferences;

/*
 *  Copyright (c) 2005 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.binding.foundation.FoundationKitFunctionsLibrary;
import ch.cyberduck.binding.foundation.NSArray;
import ch.cyberduck.binding.foundation.NSBundle;
import ch.cyberduck.binding.foundation.NSEnumerator;
import ch.cyberduck.binding.foundation.NSLocale;
import ch.cyberduck.binding.foundation.NSObject;
import ch.cyberduck.binding.foundation.NSString;
import ch.cyberduck.binding.foundation.NSUserDefaults;
import ch.cyberduck.core.Factory;
import ch.cyberduck.core.Local;
import ch.cyberduck.core.LocalFactory;
import ch.cyberduck.core.Scheme;
import ch.cyberduck.core.sparkle.Updater;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.rococoa.Rococoa;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Concrete subclass using the Cocoa Preferences classes. The NSUserDefaults class is thread-safe.
 *
 * @see ch.cyberduck.binding.foundation.NSUserDefaults
 */
public class UserDefaultsPreferences extends Preferences {
    private static final Logger log = Logger.getLogger(UserDefaultsPreferences.class);

    public final NSBundle bundle = new BundleApplicationResourcesFinder().bundle();

    private NSUserDefaults store;

    /**
     * Additionally look for default values in Info.plist of application bundle.
     *
     * @param property The property to query.
     * @return A default value if any or null if not found.
     */
    @Override
    public String getDefault(final String property) {
        // Lookup in the default map
        final String value = super.getDefault(property);
        if (null == value) {
            // Missing in default. Lookup in Info.plist
            NSObject plist = bundle.infoDictionary().objectForKey(property);
            if (null == plist) {
                log.warn(String.format("No default value for property %s", property));
                return null;
            }
            return plist.toString();
        }
        // Default value of property found
        return value;
    }

    @Override
    public String getProperty(final String property) {
        final NSObject value = store.objectForKey(property);
        if (null == value) {
            return this.getDefault(property);
        }
        // Customized property found
        return value.toString();
    }

    @Override
    public void setProperty(final String property, final String value) {
        if (log.isInfoEnabled()) {
            log.info(String.format("Set property %s for key %s", value, property));
        }
        if (StringUtils.isNotEmpty(value)) {
            // Sets the value of the default identified by defaultName in the standard application domain.
            // Setting a default has no effect on the value returned by the objectForKey method if
            // the same key exists in a domain that precedes the application domain in the search list.
            store.setObjectForKey(NSString.stringWithString(value), property);
        } else {
            this.deleteProperty(property);
        }
    }

    @Override
    public void setProperty(final String property, final List<String> value) {
        // Sets the value of the default identified by defaultName in the standard application domain.
        // Setting a default has no effect on the value returned by the objectForKey method if
        // the same key exists in a domain that precedes the application domain in the search list.
        store.setObjectForKey(NSArray.arrayWithObjects(value.toArray(new String[value.size()])), property);
    }

    @Override
    public void deleteProperty(final String property) {
        if (log.isDebugEnabled()) {
            log.debug(String.format("Delete property %s", property));
        }
        store.removeObjectForKey(property);
    }

    /**
     * Overwrite the default values with user props if any.
     */
    @Override
    public void load() {
        store = NSUserDefaults.standardUserDefaults();
    }

    /**
     * Properties that must be accessible in NSUserDefaults with default values
     */
    @Override
    protected void post() {
        _init("browser.view.autoexpand.useDelay");
        _init("browser.view.autoexpand.delay");

        _init("connection.retry");
        _init("connection.retry.delay");
        _init("connection.timeout.seconds");

        _init("bookmark.icon.size");

        super.post();
    }

    @Override
    protected void setDefaults() {
        // Parent defaults
        super.setDefaults();

        defaults.put("tmp.dir", FoundationKitFunctionsLibrary.NSTemporaryDirectory());

        final NSBundle bundle = this.bundle;
        if (null != bundle) {
            if (bundle.objectForInfoDictionaryKey("CFBundleName") != null) {
                defaults.put("application.name", bundle.objectForInfoDictionaryKey("CFBundleName").toString());
            }
            if (bundle.objectForInfoDictionaryKey("NSHumanReadableCopyright") != null) {
                defaults.put("application.copyright",
                        bundle.objectForInfoDictionaryKey("NSHumanReadableCopyright").toString());
            }
            if (bundle.objectForInfoDictionaryKey("CFBundleIdentifier") != null) {
                defaults.put("application.identifier",
                        bundle.objectForInfoDictionaryKey("CFBundleIdentifier").toString());
            }
            if (bundle.objectForInfoDictionaryKey("CFBundleShortVersionString") != null) {
                defaults.put("application.version",
                        bundle.objectForInfoDictionaryKey("CFBundleShortVersionString").toString());
            }
            if (bundle.objectForInfoDictionaryKey("CFBundleVersion") != null) {
                defaults.put("application.revision",
                        bundle.objectForInfoDictionaryKey("CFBundleVersion").toString());
            }
            defaults.put("application.receipt.path", String.format("%s/Contents/_MASReceipt", bundle.bundlePath()));
        }
        final Local resources = ApplicationResourcesFinderFactory.get().find();
        defaults.put("application.bookmarks.path", String.format("%s/Bookmarks", resources.getAbsolute()));
        defaults.put("application.profiles.path", String.format("%s/Profiles", resources.getAbsolute()));

        defaults.put("update.feed.release", "https://version.cyberduck.io/changelog.rss");
        defaults.put("update.feed.beta", "https://version.cyberduck.io/beta/changelog.rss");
        defaults.put("update.feed.nightly", "https://version.cyberduck.io/nightly/changelog.rss");
        // Fix #9395
        if (!StringUtils.startsWith(this.getProperty(Updater.PROPERTY_FEED_URL), Scheme.https.name())) {
            this.deleteProperty(Updater.PROPERTY_FEED_URL);
            this.save();
        }

        defaults.put("bookmark.import.filezilla.location", "~/.config/filezilla/sitemanager.xml");
        defaults.put("bookmark.import.fetch.location",
                "~/Library/Preferences/com.fetchsoftworks.Fetch.Shortcuts.plist");
        defaults.put("bookmark.import.flow.location", "~/Library/Application Support/Flow/Bookmarks.plist");
        defaults.put("bookmark.import.interarchy.location",
                "~/Library/Application Support/Interarchy/Bookmarks.plist");
        defaults.put("bookmark.import.transmit.location", "~/Library/Preferences/com.panic.Transmit.plist");
        defaults.put("bookmark.import.transmit4.location",
                "~/Library/Application Support/Transmit/Favorites/Favorites.xml");
        defaults.put("bookmark.import.crossftp.location", "~/.crossftp/sites.xml");
        defaults.put("bookmark.import.fireftp.location", "~/Library/Application Support/Firefox/Profiles");
        defaults.put("bookmark.import.expandrive3.location",
                "~/Library/Application Support/ExpanDrive/favorites.js");
        defaults.put("bookmark.import.expandrive4.location",
                "~/Library/Application Support/ExpanDrive/expandrive4.favorites.js");
        defaults.put("bookmark.import.expandrive5.location",
                "~/Library/Application Support/ExpanDrive/expandrive5.favorites.js");
        if (LocalFactory.get("~/Downloads").exists()) {
            // For 10.5+ this usually exists and should be preferrred
            defaults.put("queue.download.folder", "~/Downloads");
        } else {
            defaults.put("queue.download.folder", "~/Desktop");
        }
        defaults.put("browser.filesize.decimal", String.valueOf(!Factory.Platform.osversion.matches("10\\.5.*")));

        // SSL Keystore
        defaults.put("connection.ssl.keystore.type", "KeychainStore");
        defaults.put("connection.ssl.keystore.provider", "Apple");

        defaults.put("network.interface.blacklist", "awdl0 utun0");

        defaults.put("browser.window.tabbing.identifier", "browser.window.tabbing.identifier");
        // Allow to show transfers in browser window as tab
        defaults.put("queue.window.tabbing.identifier", "browser.window.tabbing.identifier");
    }

    /**
     * Setting default values that must be accessible using [NSUserDefaults standardUserDefaults]
     *
     * @param property Initial property name to store default value for.
     */
    private void _init(final String property) {
        if (null == store.objectForKey(property)) {
            // Set the default value
            this.setProperty(property, this.getDefault(property));
        }
    }

    @Override
    public void save() {
        // Saves any modifications to the persistent domains and updates all
        // persistent domains that were not modified to  what is on disk.
        // Returns false if it could not save data to disk. Because synchronize
        // is automatically invoked at periodic intervals, use this method only
        // if you cannot wait for the automatic synchronization (for example, if
        // your application is about to exit) or if you want to update user props
        // to what is on disk even though you have not made any changes.
        store.synchronize();
    }

    @Override
    public String locale() {
        final NSObject value = store.objectForKey("AppleLanguages");
        if (null == value) {
            return super.locale();
        }
        if (value.isKindOfClass(Rococoa.createClass("NSArray", NSArray._Class.class))) {
            final List<String> languages = this.toList(Rococoa.cast(value, NSArray.class));
            if (null != languages) {
                return languages.iterator().next();
            }
        }
        return super.locale();
    }

    @Override
    public List<String> applicationLocales() {
        return this.toList(bundle.localizations());
    }

    @Override
    public List<String> systemLocales() {
        // Language ordering in system preferences. Can be overridden
        // using the "AppleLanguages" user default
        return this.toList(NSLocale.preferredLanguages());
    }

    /**
     * Convert collection
     *
     * @param list List of properties
     * @return Collection
     */
    private List<String> toList(final NSArray list) {
        if (null == list) {
            return Collections.emptyList();
        }
        final List<String> localizations = new ArrayList<String>();
        NSEnumerator ordered = list.objectEnumerator();
        NSObject next;
        while (((next = ordered.nextObject()) != null)) {
            localizations.add(next.toString());
        }
        return localizations;
    }
}