Browse Source
REPORT-59078 【主题切换】主题编辑界面 保存按钮交互优化 【问题原因】 1. 整理拆分主题编辑面板实现 2. 添加保存成功提示 3. 仅在修改主题配置且主题名称有效且自定义主题时,保存按钮可点击 【改动思路】 同上research/11.0
Starryi
3 years ago
7 changed files with 626 additions and 459 deletions
@ -0,0 +1,318 @@
|
||||
package com.fr.design.mainframe.theme; |
||||
|
||||
import com.fr.base.theme.FineColorFlushUtils; |
||||
import com.fr.base.theme.FineColorManager; |
||||
import com.fr.base.theme.TemplateTheme; |
||||
import com.fr.base.theme.TemplateThemeConfig; |
||||
import com.fr.base.theme.settings.ThemedCellStyleList; |
||||
import com.fr.base.theme.settings.ThemedColorScheme; |
||||
import com.fr.design.designer.IntervalConstants; |
||||
import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; |
||||
import com.fr.design.gui.frpane.AttributeChangeListener; |
||||
import com.fr.design.gui.frpane.UITabbedPane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.layout.TableLayout; |
||||
import com.fr.design.layout.TableLayoutHelper; |
||||
import com.fr.design.mainframe.theme.edit.CellStyleListEditPane; |
||||
import com.fr.design.mainframe.theme.edit.ChartStyleEditPane; |
||||
import com.fr.design.mainframe.theme.edit.ui.ColorListExtendedPane; |
||||
import com.fr.design.mainframe.theme.edit.ui.ColorListPane; |
||||
import com.fr.design.mainframe.theme.edit.ui.LabelUtils; |
||||
import com.fr.design.mainframe.theme.ui.AutoCheckTextField; |
||||
import com.fr.design.mainframe.theme.ui.AutoCheckThemeNameTextField; |
||||
import com.fr.design.mainframe.theme.ui.BorderUtils; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JComponent; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.event.ChangeEvent; |
||||
import javax.swing.event.ChangeListener; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Component; |
||||
import java.awt.Dimension; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author Starryi |
||||
* @version 1.0 |
||||
* Created by Starryi on 2021/8/13 |
||||
*/ |
||||
public abstract class TemplateThemeEditorPane<T extends TemplateTheme> extends JPanel { |
||||
public static final int TITLE_BORDER_FONT = 12; |
||||
public static final int LEFT_TITLE_PANE_HEIGHT = 539; |
||||
|
||||
public static final int RIGHT_PANE_WIDTH = 362; |
||||
public static final int RIGHT_PANE_HEIGHT = LEFT_TITLE_PANE_HEIGHT; |
||||
public static final int COLOR_SCHEME_TITLE_PANE_WIDTH = 298; |
||||
public static final int COLOR_SCHEME_TITLE_PANE_HEIGHT = 174 + TITLE_BORDER_FONT / 2; |
||||
|
||||
protected AutoCheckThemeNameTextField<T> nameTextField; |
||||
private UILabel nameErrorLabel; |
||||
protected ColorListPane colorListPane; |
||||
private ColorListExtendedPane colorListExtendedPane; |
||||
protected CellStyleListEditPane cellStyleSettingPane; |
||||
protected ChartStyleEditPane chartStyleSettingPane; |
||||
|
||||
protected boolean isPopulating = false; |
||||
protected UITabbedPane uiTabbedPane; |
||||
|
||||
private final TemplateThemeConfig<T> config; |
||||
|
||||
private boolean refreshingThemedColor = false; |
||||
private T theme; |
||||
|
||||
private AttributeChangeListener changeListener; |
||||
private AutoCheckTextField.CheckListener themeNameCheckListener; |
||||
|
||||
public TemplateThemeEditorPane(TemplateThemeConfig<T> config) { |
||||
super(); |
||||
this.config = config; |
||||
theme = config.createNewTheme(); |
||||
initializePane(); |
||||
} |
||||
|
||||
private void initializePane() { |
||||
setLayout(new BorderLayout(0, 0)); |
||||
setPreferredSize(new Dimension(RIGHT_PANE_WIDTH, RIGHT_PANE_HEIGHT)); |
||||
JPanel nameEditPane = createNameEditPane(); |
||||
add(nameEditPane, BorderLayout.NORTH); |
||||
|
||||
JPanel settingPane = new JPanel(new BorderLayout(0, IntervalConstants.INTERVAL_L1)); |
||||
settingPane.add(createColorSchemeEditPane(), BorderLayout.NORTH); |
||||
settingPane.add(createCustomEditorsPane(), BorderLayout.CENTER); |
||||
|
||||
add(settingPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
private JPanel createNameEditPane() { |
||||
nameErrorLabel = LabelUtils.createLabel(StringUtils.EMPTY, Color.RED); |
||||
nameErrorLabel.setVisible(false); |
||||
|
||||
nameTextField = new AutoCheckThemeNameTextField<>(); |
||||
nameTextField.setThemeConfig(config); |
||||
nameTextField.setEditable(false); |
||||
nameTextField.setEnabled(false); |
||||
nameTextField.setPreferredSize(new Dimension(165, 20)); |
||||
nameTextField.setNameCheckListener(new AutoCheckTextField.CheckListener() { |
||||
@Override |
||||
public void onChecked(String error, boolean valid) { |
||||
nameErrorLabel.setVisible(StringUtils.isNotEmpty(error)); |
||||
nameErrorLabel.setText(error); |
||||
|
||||
themeNameCheckListener.onChecked(error, valid); |
||||
} |
||||
}); |
||||
|
||||
double p = TableLayout.PREFERRED; |
||||
|
||||
JPanel container = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{ |
||||
new Component[] { LabelUtils.createLabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Name")), nameTextField }, |
||||
new Component[] { null, nameErrorLabel }, |
||||
}, new double[] { 20, 20}, new double[] { p, 165}, IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_W0); |
||||
|
||||
container.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); |
||||
return container; |
||||
} |
||||
|
||||
private JPanel createColorSchemeEditPane() { |
||||
colorListPane = new ColorListPane(); |
||||
colorListExtendedPane = new ColorListExtendedPane(); |
||||
|
||||
JPanel extendedContainer = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
colorListExtendedPane.setBackground(null); |
||||
colorListExtendedPane.setOpaque(false); |
||||
extendedContainer.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); |
||||
extendedContainer.setBackground(Color.WHITE); |
||||
extendedContainer.add(colorListExtendedPane); |
||||
|
||||
double p = TableLayout.PREFERRED; |
||||
double[] rowSize = new double[]{p, p, p}; |
||||
double[] columnSize = {p, p}; |
||||
|
||||
JPanel colorListContainerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
colorListContainerPane.add(colorListPane, BorderLayout.WEST); |
||||
|
||||
JPanel previewLabelPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
previewLabelPane.add(LabelUtils.createLabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Color_Scheme_Preview_Label")), BorderLayout.NORTH); |
||||
|
||||
UILabel tipLabel = LabelUtils.createLabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Color_Scheme_Edit_Tip"), new Color(153, 153, 153)); |
||||
tipLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); |
||||
|
||||
JPanel content = TableLayoutHelper.createGapTableLayoutPane(new JComponent[][]{ |
||||
{LabelUtils.createLabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Color_Scheme_Edit_Label")), colorListContainerPane}, |
||||
{null, tipLabel}, |
||||
{previewLabelPane, extendedContainer}, |
||||
}, |
||||
rowSize, columnSize, 18, 7); |
||||
content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); |
||||
|
||||
JPanel borderContainer = new JPanel(new BorderLayout()); |
||||
borderContainer.setPreferredSize(new Dimension(COLOR_SCHEME_TITLE_PANE_WIDTH, COLOR_SCHEME_TITLE_PANE_HEIGHT)); |
||||
borderContainer.setBorder(BorderUtils.createTitleBorder(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Color_Scheme_Title"))); |
||||
borderContainer.add(content); |
||||
|
||||
JPanel container = new JPanel(new BorderLayout()); |
||||
container.add(borderContainer, BorderLayout.WEST); |
||||
|
||||
colorListPane.addColorChangeListener(new ChangeListener() { |
||||
@Override |
||||
public void stateChanged(ChangeEvent e) { |
||||
if (refreshingThemedColor) { |
||||
return; |
||||
} |
||||
List<Color> colors = colorListPane.update(); |
||||
refreshingThemedColor = true; |
||||
onColorSchemeChanged(colors); |
||||
refreshingThemedColor = false; |
||||
|
||||
fireAttributeChange(); |
||||
} |
||||
}); |
||||
|
||||
return container; |
||||
} |
||||
private void onColorSchemeChanged(List<Color> colors) { |
||||
colorListExtendedPane.populate(colors); |
||||
FineColorManager.FineColorReplaceByColorScheme replaceByColorScheme = new FineColorManager.FineColorReplaceByColorScheme(colors); |
||||
T theme = updateBean(); |
||||
FineColorFlushUtils.replaceCacheObject(theme, replaceByColorScheme); |
||||
FineColorManager.traverse(theme, replaceByColorScheme); |
||||
populateBean4CustomEditors(theme); |
||||
//图表渐变色
|
||||
chartStyleSettingPane.populateGradientBar(colors); |
||||
this.repaint(); |
||||
} |
||||
|
||||
protected JPanel createCustomEditorsPane() { |
||||
JPanel container = new JPanel(new BorderLayout()); |
||||
container.setBorder(BorderUtils.createTitleBorder(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Custom_Settings_Title"))); |
||||
|
||||
uiTabbedPane = new UITabbedPane(); |
||||
uiTabbedPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 1)); |
||||
container.add(uiTabbedPane, BorderLayout.NORTH); |
||||
|
||||
return container; |
||||
} |
||||
|
||||
public void addCustomEditorPane(String title, final Component component) { |
||||
component.setPreferredSize(new Dimension(317, 239)); |
||||
AbstractAttrNoScrollPane settingPane = new NoBorderAbstractAttrNoScrollPane() { |
||||
@Override |
||||
protected JPanel createContentPane() { |
||||
JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
contentPane.add(component, BorderLayout.NORTH); |
||||
return contentPane; |
||||
} |
||||
}; |
||||
settingPane.addAttributeChangeListener(new AttributeChangeListener() { |
||||
@Override |
||||
public void attributeChange() { |
||||
fireAttributeChange(); |
||||
} |
||||
}); |
||||
uiTabbedPane.addTab(title, settingPane); |
||||
} |
||||
protected JPanel createCellStyleSettingPane() { |
||||
JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
cellStyleSettingPane = new CellStyleListEditPane(); |
||||
cellStyleSettingPane.registerAttrChangeListener(new AttributeChangeListener() { |
||||
@Override |
||||
public void attributeChange() { |
||||
fireAttributeChange(); |
||||
} |
||||
}); |
||||
container.add(cellStyleSettingPane); |
||||
return container; |
||||
} |
||||
protected JPanel createChartStyleSettingPane() { |
||||
JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
chartStyleSettingPane = new ChartStyleEditPane(); |
||||
container.add(chartStyleSettingPane); |
||||
return container; |
||||
} |
||||
|
||||
public void populateBean(T theme) { |
||||
this.theme = theme; |
||||
isPopulating = true; |
||||
|
||||
String name = theme.getName(); |
||||
setThemeNameEditable(StringUtils.isEmpty(name)); |
||||
|
||||
nameTextField.setText(name); |
||||
|
||||
colorListPane.populate(theme.getColorScheme().getColors()); |
||||
colorListExtendedPane.populate(colorListPane.update()); |
||||
|
||||
populateBean4CustomEditors(theme); |
||||
isPopulating = false; |
||||
} |
||||
|
||||
protected void populateBean4CustomEditors(T theme) { |
||||
cellStyleSettingPane.populateBean(theme.getCellStyleList()); |
||||
chartStyleSettingPane.populateBean(theme.getChartStyle()); |
||||
} |
||||
|
||||
public T updateBean() { |
||||
if (theme == null) { |
||||
theme = config.createNewTheme(); |
||||
} |
||||
|
||||
theme.setName(this.nameTextField.getText()); |
||||
|
||||
ThemedColorScheme colorScheme = theme.getColorScheme(); |
||||
colorScheme.setColors(this.colorListPane.update()); |
||||
theme.setColorScheme(colorScheme); |
||||
|
||||
updateBean4CustomEditors(theme); |
||||
|
||||
return theme; |
||||
} |
||||
|
||||
protected void updateBean4CustomEditors(T theme) { |
||||
ThemedCellStyleList cellStyleConfig = this.cellStyleSettingPane.updateBean(); |
||||
theme.setCellStyleList(cellStyleConfig); |
||||
|
||||
theme.setChartStyle(this.chartStyleSettingPane.updateBean()); |
||||
} |
||||
|
||||
public void setThemeNameEditable(boolean editable) { |
||||
nameTextField.setEditable(editable); |
||||
nameTextField.setEnabled(editable); |
||||
} |
||||
|
||||
public boolean checkNameValid() { |
||||
return nameTextField.checkValid(); |
||||
} |
||||
|
||||
public List<Color> getCurrentColorScheme() { |
||||
return colorListPane.update(); |
||||
} |
||||
|
||||
private void fireAttributeChange() { |
||||
if (!isPopulating && !refreshingThemedColor && changeListener != null) { |
||||
changeListener.attributeChange(); |
||||
} |
||||
} |
||||
|
||||
public void addAttributeChangeListener(AttributeChangeListener changeListener) { |
||||
this.changeListener = changeListener; |
||||
} |
||||
public void addThemeNameCheckListener(AutoCheckTextField.CheckListener checkListener) { |
||||
this.themeNameCheckListener = checkListener; |
||||
} |
||||
|
||||
private static abstract class NoBorderAbstractAttrNoScrollPane extends AbstractAttrNoScrollPane { |
||||
@Override |
||||
protected void initContentPane() { |
||||
super.initContentPane(); |
||||
if (leftContentPane != null) { |
||||
// 修正 AbstractAttrNoScrollPane 的默认行为
|
||||
leftContentPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,100 @@
|
||||
package com.fr.design.mainframe.theme.ui; |
||||
|
||||
import com.fr.design.gui.itextfield.UITextField; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
import java.awt.event.FocusEvent; |
||||
import java.awt.event.FocusListener; |
||||
|
||||
/** |
||||
* @author Starryi |
||||
* @version 1.0 |
||||
* Created by Starryi on 2021/9/18 |
||||
*/ |
||||
public class AutoCheckTextField extends UITextField implements DocumentListener, FocusListener { |
||||
private DuplicateChecker duplicatedChecker; |
||||
private CheckListener checkListener; |
||||
|
||||
public AutoCheckTextField() { |
||||
getDocument().addDocumentListener(this); |
||||
addFocusListener(this); |
||||
} |
||||
|
||||
public void setDuplicatedChecker(DuplicateChecker checker) { |
||||
this.duplicatedChecker = checker; |
||||
} |
||||
public void setNameCheckListener(CheckListener checkListener) { |
||||
this.checkListener = checkListener; |
||||
} |
||||
|
||||
private boolean isEmpty(String name) { |
||||
return StringUtils.isEmpty(name); |
||||
} |
||||
private boolean isDuplicated(String name) { |
||||
if (duplicatedChecker != null) { |
||||
return duplicatedChecker.isDuplicated(name); |
||||
} |
||||
return false; |
||||
} |
||||
private boolean checkValid(boolean notifyEmptyTip) { |
||||
String name = getText(); |
||||
|
||||
String error = StringUtils.EMPTY; |
||||
boolean valid = true; |
||||
if (isEditable()) { |
||||
if (isEmpty(name)) { |
||||
valid = false; |
||||
if (notifyEmptyTip) { |
||||
error = Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Empty_Name_Error_Tip"); |
||||
} |
||||
} else if (isDuplicated(name)) { |
||||
valid = false; |
||||
error = Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Duplicated_Name_Error_Tip"); |
||||
} |
||||
} |
||||
|
||||
if (checkListener != null) { |
||||
checkListener.onChecked(error, valid); |
||||
} |
||||
|
||||
return valid; |
||||
} |
||||
public boolean checkValid() { |
||||
return checkValid(true); |
||||
} |
||||
|
||||
@Override |
||||
public void insertUpdate(DocumentEvent e) { |
||||
checkValid(false); |
||||
} |
||||
|
||||
@Override |
||||
public void removeUpdate(DocumentEvent e) { |
||||
checkValid(false); |
||||
} |
||||
|
||||
@Override |
||||
public void changedUpdate(DocumentEvent e) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void focusGained(FocusEvent e) { |
||||
checkValid(false); |
||||
} |
||||
|
||||
@Override |
||||
public void focusLost(FocusEvent e) { |
||||
checkValid(true); |
||||
} |
||||
|
||||
public interface CheckListener { |
||||
void onChecked(String error, boolean valid); |
||||
} |
||||
public interface DuplicateChecker { |
||||
boolean isDuplicated(String name); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.fr.design.mainframe.theme.ui; |
||||
|
||||
import com.fr.base.theme.TemplateTheme; |
||||
import com.fr.base.theme.TemplateThemeConfig; |
||||
|
||||
/** |
||||
* @author Starryi |
||||
* @version 1.0 |
||||
* Created by Starryi on 2021/9/18 |
||||
*/ |
||||
public class AutoCheckThemeNameTextField<T extends TemplateTheme> extends AutoCheckTextField { |
||||
private TemplateThemeConfig<T> config; |
||||
|
||||
public AutoCheckThemeNameTextField() { |
||||
setDuplicatedChecker(new DuplicateChecker() { |
||||
@Override |
||||
public boolean isDuplicated(String name) { |
||||
return config != null && config.contains(name); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public void setThemeConfig(TemplateThemeConfig<T> config) { |
||||
this.config = config; |
||||
} |
||||
} |
Loading…
Reference in new issue