帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

278 lines
11 KiB

package com.fr.design.mainframe.theme;
import com.fine.theme.utils.FineUIScale;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.base.theme.TemplateTheme;
import com.fr.base.theme.TemplateThemeConfig;
import com.fr.design.designer.IntervalConstants;
import com.fr.design.dialog.BasicPane;
import com.fr.design.event.ChangeEvent;
import com.fr.design.event.ChangeListener;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.StringUtils;
import com.fr.third.javax.annotation.Nullable;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Starryi
* @version 1.0
* Created by Starryi on 2021/8/13
*/
public class TemplateThemeGridPane<T extends TemplateTheme> extends BasicPane {
public static final int BLOCK_COUNT_ROW_LINE = 3;
public static final int BLOCK_GAP = IntervalConstants.INTERVAL_L1;
public static final int CONTENT_WIDTH = TemplateThemeBlock.CONTENT_WIDTH * BLOCK_COUNT_ROW_LINE + FineUIScale.scale(BLOCK_GAP) * (BLOCK_COUNT_ROW_LINE - 1) + FineUIScale.scale(10);
public static final int BLOCK_ROWS_PER_PAGE = 3;
public static final int CONTENT_HEIGHT = Math.min(FineUIScale.scale(527), TemplateThemeBlock.CONTENT_HEIGHT * BLOCK_ROWS_PER_PAGE + FineUIScale.scale(BLOCK_GAP) * (BLOCK_ROWS_PER_PAGE + 1));
public static final int ASYNC_FETCH_THEME_THREAD_COUNT = 10;
private final AsyncThemeFetcher<T> asyncThemeFetcher;
private final boolean displayTheme4NewTemplateMarker;
protected final TemplateThemeConfig<T> config;
private final TemplateThemeProfilePane<T> profilePane;
private final JPanel contentListPane;
private final Map<String, TemplateThemeBlock<T>> blockCache = new HashMap<>();
private TemplateThemeBlock<T> selectedBlock;
private TemplateThemeBlock<T> block4newTemplate;
private TemplateThemeConfig.ThemeConfigChangeListener themeConfigChangeListener;
private ChangeListener changeListener;
private final Window window;
public TemplateThemeGridPane(@Nullable Window window, boolean displayTheme4NewTemplateMarker, TemplateThemeConfig<T> config, TemplateThemeProfilePane<T> profilePane) {
this.window = window;
this.displayTheme4NewTemplateMarker = displayTheme4NewTemplateMarker;
this.config = config;
this.profilePane = profilePane;
this.contentListPane = new JPanel();
this.asyncThemeFetcher = new AsyncThemeFetcher<>(ASYNC_FETCH_THEME_THREAD_COUNT, config);
initializePane();
registerWindowListener();
}
private void initializePane() {
setLayout(FRGUIPaneFactory.createBorderLayout());
setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
contentListPane.setBorder(new ScaledEmptyBorder(BLOCK_GAP, 0, BLOCK_GAP, 10));
contentListPane.setLayout(new GridLayout(0, BLOCK_COUNT_ROW_LINE, BLOCK_GAP, BLOCK_GAP));
fillContentListPane();
JPanel wrapper1 = FRGUIPaneFactory.createBorderLayout_S_Pane();
wrapper1.add(contentListPane, BorderLayout.NORTH);
JPanel wrapper2 = FRGUIPaneFactory.createBorderLayout_S_Pane();
wrapper2.add(wrapper1, BorderLayout.WEST);
UIScrollPane scrollPane = new UIScrollPane(wrapper2);
scrollPane.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
add(scrollPane, BorderLayout.CENTER);
}
private void registerWindowListener() {
if (window != null) {
window.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
super.windowOpened(e);
startListenThemeConfig();
asyncFetchThemes();
}
@Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e);
stopListenThemeConfig();
asyncThemeFetcher.shutdown();
}
});
}
}
public void fillContentListPane() {
contentListPane.removeAll();
List<String> names = config.getThemeNames();
for (String name: names) {
if (config.contains(name)) {
TemplateThemeBlock<T> block = createCachedTemplateThemeBlock(name);
contentListPane.add(block);
if (StringUtils.equals(name, config.getThemeName4NewTemplate())) {
block4newTemplate = block;
}
}
}
}
private TemplateThemeBlock<T> createCachedTemplateThemeBlock(String name) {
TemplateThemeBlock<T> block = blockCache.get(name);
if (block == null) {
block = createNewTemplateThemeBlock(name);
blockCache.put(name, block);
}
return block;
}
private TemplateThemeBlock<T> createNewTemplateThemeBlock(String name) {
final TemplateThemeBlock<T> block = new TemplateThemeBlock<>(name, displayTheme4NewTemplateMarker, config, profilePane);
block.addClickListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
setSelectedBlock(block);
}
});
return block;
}
public void setSelectedChangeListener(ChangeListener changeListener) {
this.changeListener = changeListener;
}
private void setSelectedBlock(TemplateThemeBlock<T> block) {
if (selectedBlock != block) {
if (selectedBlock != null) {
selectedBlock.setSelected(false);
}
selectedBlock = block;
if (selectedBlock != null) {
selectedBlock.setSelected(true);
}
if (changeListener != null) {
changeListener.fireChanged(new ChangeEvent(this));
}
}
}
private void asyncFetchTheme(String themeName) {
asyncThemeFetcher.submit(themeName, new AsyncThemeListItemFetchCallback(themeName));
}
private void asyncFetchThemes() {
List<String> names = config.getThemeNames();
for (String name: names) {
if (config.contains(name)) {
asyncThemeFetcher.submit(name, new AsyncThemeListItemFetchCallback(name));
}
}
}
@Override
protected String title4PopupWindow() {
return null;
}
public T getSelectedTheme() {
return selectedBlock != null ? selectedBlock.getTheme() : null;
}
private void startListenThemeConfig() {
if (themeConfigChangeListener == null) {
themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() {
@Override
public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) {
String themeName = event.themName;
TemplateThemeBlock<T> existingBlock = blockCache.get(event.themName);
switch (event.action) {
case DEFAULT_THEME_4_NEW_TEMPLATE_UPDATE: {
if (block4newTemplate != null) {
block4newTemplate.repaint();
}
if (existingBlock != null) {
existingBlock.repaint();
}
block4newTemplate = existingBlock;
break;
}
case UPDATE: {
if (existingBlock != null) {
fillContentListPane();
asyncFetchTheme(themeName);
validate();
repaint();
}
break;
}
case REMOVE: {
if (existingBlock != null) {
contentListPane.remove(existingBlock);
if (existingBlock == selectedBlock) {
setSelectedBlock(null);
}
validate();
repaint();
blockCache.remove(event.themName);
}
break;
}
case ADD: {
if (existingBlock == null) {
// TODO 这里是否还能继续优化?
fillContentListPane();
asyncFetchTheme(themeName);
validate();
repaint();
}
break;
}
}
}
};
config.addThemeConfigChangeListener(themeConfigChangeListener);
}
}
private void stopListenThemeConfig() {
if (themeConfigChangeListener != null) {
config.removeThemeConfigChangeListener(themeConfigChangeListener);
themeConfigChangeListener = null;
}
}
private class AsyncThemeListItemFetchCallback extends AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter<T> {
private final String themeName;
public AsyncThemeListItemFetchCallback(String themeName) {
this.themeName = themeName;
}
@Override
public void beforeCachedFetch() {
super.beforeCachedFetch();
TemplateThemeBlock<T> block = blockCache.get(themeName);
if (block != null) {
block.setTheme(null);
}
}
@Override
public void afterCachedFetch(T theme) {
super.afterCachedFetch(theme);
TemplateThemeBlock<T> block = blockCache.get(themeName);
if (block != null) {
block.setTheme(theme);
}
}
}
}