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
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); |
|
} |
|
} |
|
} |
|
} |