Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion viewers/wicket/ui/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
requires spring.beans;
requires spring.context;
requires spring.core;
requires wicket.bootstrap.core;
requires transitive wicket.bootstrap.core;
requires wicket.bootstrap.extensions;
requires wicket.bootstrap.themes;
requires de.agilecoders.wicket.webjars;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,83 @@
*/
package org.apache.causeway.viewer.wicket.ui;

import java.util.List;

import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.HeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import org.apache.causeway.viewer.commons.services.CausewayModuleViewerCommonsServices;
import org.apache.causeway.viewer.wicket.model.CausewayModuleViewerWicketModel;
import org.apache.causeway.viewer.wicket.ui.app.logout.LogoutHandlerWkt;
import org.apache.causeway.viewer.wicket.ui.components.widgets.themepicker.CausewayWicketThemeSupportDefault;
import org.apache.causeway.viewer.wicket.ui.components.widgets.themepicker.CausewayWicketThemeSupport;

import de.agilecoders.wicket.core.Bootstrap;
import de.agilecoders.wicket.core.settings.ITheme;
import de.agilecoders.wicket.core.settings.NoopThemeProvider;
import de.agilecoders.wicket.core.settings.ThemeProvider;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchTheme;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchThemeProvider;

/**
* @since 1.x {@index}
*/
@Configuration
@Configuration(proxyBeanMethods = false)
@Import({
// Modules
CausewayModuleViewerCommonsServices.class,
CausewayModuleViewerWicketModel.class,

// @Service's
CausewayWicketThemeSupportDefault.class,
CausewayWicketThemeSupport.class,
LogoutHandlerWkt.class,
})
public class CausewayModuleViewerWicketUi {

@Bean
ThemeProvider bootstrapDefaultThemeProvider() {
return new BootstrapDefaultThemeProvider();
}

@Bean
ThemeProvider bootswatchThemeProvider() {
return new BootswatchThemeProvider(BootswatchTheme.Flatly);
}

/**
* Default Bootstrap Theme
*
* @see NoopThemeProvider
*/
private static class BootstrapDefaultThemeProvider implements ThemeProvider {
private final ITheme theme = new BootstrapDefaultTheme();
@Override public ITheme byName(final String name) {
return theme;
}
@Override public List<ITheme> available() {
return List.of(theme);
}
@Override public ITheme defaultTheme() {
return theme;
}
private static final class BootstrapDefaultTheme implements ITheme {
@Override public String name() {
return "Default";
}
@Override public List<HeaderItem> getDependencies() {
return List.of();
}
@Override public void renderHead(final IHeaderResponse response) {
response.render(CssHeaderItem.forReference(Bootstrap.getSettings().getCssResourceReference()));
}
@Override public Iterable<String> getCdnUrls() {
return List.of();
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,147 @@
*/
package org.apache.causeway.viewer.wicket.ui.components.widgets.themepicker;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.apache.wicket.Component;
import org.apache.wicket.util.string.Strings;

import org.springframework.stereotype.Service;

import org.apache.causeway.applib.services.registry.ServiceRegistry;
import org.apache.causeway.commons.internal.base._NullSafe;
import org.apache.causeway.core.config.CausewayConfiguration;

import lombok.extern.slf4j.Slf4j;

import de.agilecoders.wicket.core.Bootstrap;
import de.agilecoders.wicket.core.settings.ITheme;
import de.agilecoders.wicket.core.settings.NoopThemeProvider;
import de.agilecoders.wicket.core.settings.ThemeProvider;

/**
* @since 2.0
*/
public interface CausewayWicketThemeSupport {
@Service
@Named("causeway.viewer.wicket.CausewayWicketThemeSupport")
@Slf4j
public record CausewayWicketThemeSupport(
ITheme defaultTheme,
Map<String, ITheme> themeByNameLower,
Map<String, ThemeProvider> providerByThemeNameLower) {

@Inject
public CausewayWicketThemeSupport(final CausewayConfiguration configuration, final ServiceRegistry serviceRegistry) {
this(Args.create(configuration, serviceRegistry));
}

private CausewayWicketThemeSupport(final Args args) {
this(args.defaultTheme, args.themeByNameLower, args.providerByThemeNameLower);
}

public ITheme byName(final String name) {
if (!Strings.isEmpty(name)) {
var theme = themeByNameLower.get(name.toLowerCase());
if(theme!=null)
return theme;
}

log.warn("'{}' theme not found amoung enabled {}, "
+ "falling back to '{}'",
name,
available().stream().map(ITheme::name).collect(Collectors.joining(", ")),
defaultTheme.name());

return defaultTheme;
}

public List<ITheme> available() {
return themeByNameLower.values()
.stream()
.toList();
}

public List<String> availableNames() {
return available()
.stream()
.map(ITheme::name)
.toList();
}

public ThemeProvider compositeThemeProvider() {
return new ThemeProvider() {
@Override public ITheme defaultTheme() {
return defaultTheme;
}
@Override public ITheme byName(final String name) {
return CausewayWicketThemeSupport.this.byName(name);
}
@Override public List<ITheme> available() {
return CausewayWicketThemeSupport.this.available();
}
};
}

/**
* Required in order for ThemeProvider specific resources to be made available.
*
* <p> set during {@link Component#beforeRender()}, un-set during {@link Component#afterRender()}
*
* @see #unsetCustomThemeProvider()
*/
public void setCustomThemeProvider(final ITheme theme) {
Optional.ofNullable(providerByThemeNameLower.get(theme.name().toLowerCase()))
.ifPresent(Bootstrap.getSettings()::setThemeProvider);
}

public void unsetCustomThemeProvider() {
Bootstrap.getSettings().setThemeProvider(compositeThemeProvider());
}

// -- HELPER

/**
* Can be refactored/removed once we have flexible constructor bodies in Java.
*/
private record Args(
ITheme defaultTheme,
Map<String, ITheme> themeByNameLower,
Map<String, ThemeProvider> providerByThemeNameLower) {

static Args create(
final CausewayConfiguration configuration,
final ServiceRegistry serviceRegistry) {

var enabledThemeNamesLowercase = _NullSafe.stream(configuration.viewer().wicket().themes().enabled())
.map(String::toLowerCase)
.collect(Collectors.toCollection(HashSet::new));

var providerByThemeNameLower = new LinkedHashMap<String, ThemeProvider>();
var themeByNameLower = new LinkedHashMap<String, ITheme>();
serviceRegistry.select(ThemeProvider.class)
.forEach(provider->{
_NullSafe.stream(provider.available())
.filter(theme->enabledThemeNamesLowercase.contains(theme.name().toLowerCase()))
.forEach(theme->{
var themeKey = theme.name().toLowerCase();
themeByNameLower.put(themeKey, theme);
providerByThemeNameLower.put(themeKey, provider);
});
});

// -- INTERFACE
var defaultTheme = Optional.ofNullable(themeByNameLower.get(configuration.viewer().wicket().themes().initial()))
.orElseGet(()->new NoopThemeProvider().defaultTheme());

ThemeProvider getThemeProvider();
List<String> getEnabledThemeNames();
return new Args(defaultTheme, themeByNameLower, providerByThemeNameLower);
}
}

}

This file was deleted.

Loading