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