All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.palexdev.mfxcomponents.theming.base.Theme Maven / Gradle / Ivy

There is a newer version: 11.26.0
Show newest version
/*
 * Copyright (C) 2023 Parisi Alessandro - [email protected]
 * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX)
 *
 * MaterialFX 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.
 *
 * MaterialFX 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 MaterialFX. If not, see .
 */

package io.github.palexdev.mfxcomponents.theming.base;

import io.github.palexdev.mfxcomponents.theming.Deployer;
import io.github.palexdev.mfxcomponents.theming.UserAgentBuilder;
import io.github.palexdev.mfxresources.MFXResources;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;

import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * Public API for all MaterialFX themes/stylesheets. Ideally every theme should have: a name that identifies it,
 * and the path at which it is located.
 * 

* Very important is the load mechanism. This interface assumes that stylesheets reside in the MFXResources module, and * thus uses {@link MFXResources} to load them. Custom user themes must override {@link #get()}! *

* Until JavaFX adds support for Themes and multiple user agent stylesheets, this in combination with {@link UserAgentBuilder}, * offers a workaround for it. I noticed JavaFX themes were correctly merged but were still missing something: assets. * Their themes use images that unfortunately cannot be retrieved after the merge unless...we deploy them. *

* I was thinking about a possible solution and the only idea I came up with was to copy the necessary assets on the disk, * and then during post-processing correct the relative paths to point to the resources on the disk. *

* So, for now, the API has been extended to allow themes to deploy any kind of resources they need. The assets should * all be contained in a zip file as then the {@link Deployer} class will extract its contents when {@link #deploy()} is * invoked. All the deployment methods have been made {@code default}, in other words optional. The {@link #assets()} method * by default returns null, this indicates to the {@link Deployer} that there's nothing to do. * * @see Deployer */ public interface Theme { /** * @return the theme's name */ String name(); /** * @return the path at which the stylesheet is located as a string */ String path(); /** * Responsible for loading the stylesheet specified by {@link #path()}. *

* This assumes that the theme comes from the MFXResources module and thus uses {@link MFXResources} to load it. * Custom user themes must override this method!. *

* Last but not least, themes loaded through this are automatically cached for faster subsequent loadings. */ default URL get() { if (Helper.isCached(this) && Helper.getCachedTheme(this) != null) return Helper.getCachedTheme(this); return Helper.cacheTheme(this, MFXResources.loadURL(path())); } /** * @return the {@link URL} loaded through {@link #get()} as a string, see {@link URL#toExternalForm()} */ default String toData() { return get().toExternalForm(); } /** * Applies the theme as the global user agent stylesheet, see {@link Application#setUserAgentStylesheet(String)}. */ default void applyGlobal() { Application.setUserAgentStylesheet(toData()); } /** * Adds the loaded theme ({@link #toData()}) to the given {@link Scene}. */ default void applyOn(Scene scene) { scene.getStylesheets().add(toData()); } /** * Adds the loaded theme ({@link #toData()}) to the given {@link Parent}. */ default void applyOn(Parent parent) { parent.getStylesheets().add(toData()); } /** * @return the stream to the theme's assets, these are expected to be contained in a zip file */ default InputStream assets() { return null; } /** * Asks the {@link Deployer} to deploy this theme's resources. * * @see Deployer#deploy(Theme) */ default void deploy() { try { Deployer.instance().deploy(this); } catch (Exception ex) { System.err.println("Failed to deploy theme: " + name() + ", because: " + ex.getMessage()); } } /** * This is used by the {@link Deployer} to identify the theme in its cache map, and it is also the parent folder * in which assets will be extracted on the disk. */ default String deployName() { return name().toLowerCase(); } /** * Removes any deployed files from the disk and memory. * * @see Deployer#clean(Theme) */ default void clean() { Deployer.instance().clean(this); } /** * @return whether the theme has been already deployed before by the {@link Deployer}. Beware, this is just a check * to see if the deployment is in the cache map. No checks are done on the file system as it would be too costly. * And this is true for {@link #deploy()} too, files will be extracted not matter if they are/are not on the disk */ default boolean isDeployed() { return Deployer.instance().getDeployed(this) != null; } class Helper { private static final Map CACHE = new HashMap<>(); public static boolean isCached(Theme theme) { return CACHE.containsKey(theme); } public static URL cacheTheme(Theme theme, URL url) { CACHE.put(theme, url); return url; } public static URL getCachedTheme(Theme theme) { return CACHE.get(theme); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy