帆软报表设计器源代码。
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.

629 lines
25 KiB

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.ThemeThumbnail;
import com.fr.base.theme.settings.ThemedCellStyleList;
import com.fr.base.theme.settings.ThemedColorScheme;
import com.fr.design.designer.IntervalConstants;
import com.fr.design.dialog.FineJOptionPane;
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.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
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.dialog.TemplateThemeProfileDialog;
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.BorderUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.Inter;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.transaction.CallBackAdaptor;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import static com.fr.design.i18n.Toolkit.i18nText;
/**
* @author Starryi
* @version 1.0
* Created by Starryi on 2021/8/13
*/
public abstract class TemplateThemeProfilePane<T extends TemplateTheme> extends AbstractAttrNoScrollPane {
public static final int TITLE_BORDER_FONT = 12;
public static final int LEFT_TITLE_PANE_WIDTH = 627;
public static final int LEFT_TITLE_PANE_HEIGHT = 539;
public static final int PREVIEW_PANE_WIDTH = LEFT_TITLE_PANE_WIDTH - 10;
public static final int PREVIEW_PANE_HEIGHT = LEFT_TITLE_PANE_HEIGHT - TITLE_BORDER_FONT - 16;
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 TemplateThemePreviewPane<T> themePreviewPane;
protected UITextField 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 UIButton saveButton = new UIButton();
private UIButton saveAsButton = new UIButton();
private boolean refreshingThemedColor = false;
private boolean currentIsNewTheme;
private T theme;
public TemplateThemeProfilePane(TemplateThemeConfig<T> config) {
this.config = config;
theme = config.createNewTheme();
}
@Override
protected JPanel createContentPane() {
JPanel container = new JPanel(new BorderLayout(5, 0));
container.add(createLeftPane(), BorderLayout.CENTER);
container.add(createRightPane(), BorderLayout.EAST);
addAttributeChangeListener(new AttributeChangeListener() {
@Override
public void attributeChange() {
if (!isPopulating && !refreshingThemedColor) {
valueChangeAction();
}
}
});
return container;
}
@Override
protected void initContentPane() {
super.initContentPane();
if (leftContentPane != null) {
// 修正 AbstractAttrNoScrollPane 的默认行为
leftContentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 6));
}
}
public void valueChangeAction() {
themePreviewPane.refresh(updateBean());
}
@Override
public String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Dialog_Title");
}
private JPanel createLeftPane() {
JPanel titleContainer = FRGUIPaneFactory.createBorderLayout_S_Pane();
titleContainer.setPreferredSize(new Dimension(LEFT_TITLE_PANE_WIDTH, LEFT_TITLE_PANE_HEIGHT));
titleContainer.setBorder(BorderUtils.createTitleBorder(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Preview_Pane_Title"), TITLE_BORDER_FONT));
JPanel previewContainer = FRGUIPaneFactory.createBorderLayout_S_Pane();
previewContainer.setBorder(BorderFactory.createEmptyBorder(5, 4, 10, 4));
titleContainer.add(previewContainer, BorderLayout.CENTER);
themePreviewPane = createThemePreviewPane();
themePreviewPane.setPreferredSize(new Dimension(PREVIEW_PANE_WIDTH, PREVIEW_PANE_HEIGHT));
previewContainer.add(themePreviewPane, BorderLayout.CENTER);
return titleContainer;
}
private JPanel createRightPane() {
JPanel container = new JPanel(new BorderLayout(0, 0));
container.setPreferredSize(new Dimension(RIGHT_PANE_WIDTH, RIGHT_PANE_HEIGHT));
JPanel nameEditPane = createNameEditPane();
container.add(nameEditPane, BorderLayout.NORTH);
JPanel settingPane = new JPanel(new BorderLayout(0, IntervalConstants.INTERVAL_L1));
container.add(settingPane, BorderLayout.CENTER);
settingPane.add(createColorSchemeEditPane(), BorderLayout.NORTH);
settingPane.add(createCustomEditorsPane(), BorderLayout.CENTER);
uiTabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
valueChangeAction();
}
});
return container;
}
private JPanel createNameEditPane() {
nameErrorLabel = LabelUtils.createLabel(StringUtils.EMPTY, Color.RED);
nameErrorLabel.setVisible(false);
nameTextField = new UITextField();
nameTextField.setEnabled(false);
nameTextField.setPreferredSize(new Dimension(165, 20));
nameTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(currentIsNewTheme, false, currentIsNewTheme, true, nameTextField, nameErrorLabel, saveButton);
}
}
@Override
public void removeUpdate(DocumentEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(currentIsNewTheme, false, currentIsNewTheme, true, nameTextField, nameErrorLabel, saveButton);
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
nameTextField.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(currentIsNewTheme, false, currentIsNewTheme, true, nameTextField, nameErrorLabel, saveButton);
}
}
@Override
public void focusLost(FocusEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(currentIsNewTheme, true, currentIsNewTheme, true, nameTextField, nameErrorLabel, saveButton);
}
}
});
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;
}
});
return container;
}
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, JComponent component) {
component.setPreferredSize(new Dimension(317, 239));
uiTabbedPane.addTab(title, component);
}
protected JPanel createCellStyleSettingPane() {
JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane();
cellStyleSettingPane = new CellStyleListEditPane();
cellStyleSettingPane.registerAttrChangeListener(new AttributeChangeListener() {
@Override
public void attributeChange() {
valueChangeAction();
}
});
container.add(cellStyleSettingPane);
return container;
}
protected JPanel createChartStyleSettingPane() {
JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane();
chartStyleSettingPane = new ChartStyleEditPane();
container.add(chartStyleSettingPane);
return container;
}
public abstract TemplateThemePreviewPane<T> createThemePreviewPane();
public 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);
themePreviewPane.refresh(theme);
this.repaint();
}
public void populateBean(T theme) {
this.theme = theme;
isPopulating = true;
String name = theme.getName();
currentIsNewTheme = config.cachedFetch(name) == null;
nameTextField.setText(name);
nameTextField.setEnabled(StringUtils.isEmpty(name));
if (saveButton != null) {
saveButton.setEnabled(theme.isMutable() && !currentIsNewTheme);
}
if (saveAsButton != null) {
saveAsButton.setEnabled(!currentIsNewTheme);
}
colorListPane.populate(theme.getColorScheme().getColors());
colorListExtendedPane.populate(colorListPane.update());
populateBean4CustomEditors(theme);
themePreviewPane.refresh(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());
Image thumbnailImage = themePreviewPane.createThumbnailImage();
if (thumbnailImage != null) {
ThemeThumbnail thumbnail = new ThemeThumbnail();
thumbnail.setImage(thumbnailImage);
theme.setThumbnail(thumbnail);
}
ThemedCellStyleList cellStyleConfig = this.cellStyleSettingPane.updateBean();
theme.setCellStyleList(cellStyleConfig);
ThemedColorScheme colorScheme = theme.getColorScheme();
colorScheme.setColors(this.colorListPane.update());
theme.setColorScheme(colorScheme);
theme.setChartStyle(this.chartStyleSettingPane.updateBean());
updateBean(theme);
return theme;
}
public List<Color> getCurrentColorScheme() {
return colorListPane.update();
}
protected abstract void updateBean(T theme);
public UIButton createSaveButton() {
saveButton = new UIButton();
saveButton.setText(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save"));
saveButton.setEnabled(false);
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
T theme = updateBean();
boolean canBeSaved = checkThemeCanBeSavedAndUpdateUI(currentIsNewTheme, true, currentIsNewTheme, true, nameTextField, nameErrorLabel, saveButton);
if (canBeSaved && theme != null) {
theme.setName(nameTextField.getText());
config.addTheme(theme, true, new CallBackAdaptor() {
@Override
public void afterCommit() {
super.afterCommit();
currentIsNewTheme = false;
nameTextField.setEnabled(false);
saveAsButton.setEnabled(true);
}
@Override
public void afterRollback() {
super.afterRollback();
FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TemplateThemeProfilePane.this),
i18nText("Fine-Design_Basic_Template_Theme_Operation_Failed_Tip"),
i18nText("Fine-Design_Basic_Alert"),
JOptionPane.WARNING_MESSAGE);
}
});
}
}
});
return saveButton;
}
public UIButton createSaveAsButton(final TemplateThemeProfileDialog<T> profileDialog) {
saveAsButton = new UIButton();
saveAsButton.removeAll();
saveAsButton.setText(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save_As"));
saveAsButton.setEnabled(false);
saveAsButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new SaveAsDialog(profileDialog).setVisible(true);
}
});
return saveAsButton;
}
private class SaveAsDialog extends JDialog {
private final TemplateThemeProfileDialog<T> parent;
private UITextField nameTextField;
private UILabel nameErrorLabel;
private UIButton confirmButton;
public SaveAsDialog(TemplateThemeProfileDialog<T> dialog) {
super(dialog, ModalityType.APPLICATION_MODAL);
setTitle(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Save_As_Dialog_Title"));
setResizable(false);
setSize(new Dimension(300, 140));
GUICoreUtils.centerWindow(this);
parent = dialog;
initializeComponents();
add(createContentPane(), BorderLayout.CENTER);
add(createActionsContainer(), BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
exit();
}
});
}
private void initializeComponents() {
nameErrorLabel = LabelUtils.createLabel(StringUtils.EMPTY, Color.RED);
nameErrorLabel.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 0));
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.setEnabled(false);
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveAsNew(nameTextField.getText());
}
});
nameTextField = new UITextField();
nameTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(true, false, true, true, nameTextField, nameErrorLabel, confirmButton);
}
}
@Override
public void removeUpdate(DocumentEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(true, false, true, true, nameTextField, nameErrorLabel, confirmButton);
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
nameTextField.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(true, false, true, true, nameTextField, nameErrorLabel, confirmButton);
}
}
@Override
public void focusLost(FocusEvent e) {
if (isEnabled()) {
checkThemeCanBeSavedAndUpdateUI(true, true, true, true, nameTextField, nameErrorLabel, confirmButton);
}
}
});
nameTextField.setPreferredSize(new Dimension(180, 20));
}
private JPanel createActionsContainer() {
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exit();
}
});
JPanel container = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane();
container.add(confirmButton);
container.add(cancelButton);
return container;
}
private JPanel createContentPane() {
JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane();
JPanel nameTextPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(20, 5);
nameTextPane.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
nameTextPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Save_As_Pane_Name_Label")));
nameTextPane.add(nameTextField);
container.add(nameTextPane, BorderLayout.CENTER);
container.add(nameErrorLabel, BorderLayout.SOUTH);
return container;
}
private void saveAsNew(String name) {
T newThemeObject = null;
try {
newThemeObject = (T) updateBean().clone();
} catch (CloneNotSupportedException ex) {
FineLoggerFactory.getLogger().error(ex.getMessage(), ex);
return;
}
boolean canBeSaved = checkThemeCanBeSavedAndUpdateUI(true, true, true, true, nameTextField, nameErrorLabel, confirmButton);
if (canBeSaved && newThemeObject != null) {
newThemeObject.setName(name);
newThemeObject.setRemovable(true);
newThemeObject.setMutable(true);
config.addTheme(newThemeObject, true, new CallBackAdaptor() {
@Override
public void afterCommit() {
super.afterCommit();
exit();
parent.exit();
}
@Override
public void afterRollback() {
super.afterRollback();
FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TemplateThemeProfilePane.this),
i18nText("Fine-Design_Basic_Template_Theme_Operation_Failed_Tip"),
i18nText("Fine-Design_Basic_Alert"),
JOptionPane.WARNING_MESSAGE);
}
});
}
}
public void exit() {
this.dispose();
}
}
private boolean isThemeNameEmpty(String name) {
return StringUtils.isEmpty(name);
}
private boolean isThemeNameDuplicated(String name) {
return config.cachedFetch(name) != null;
}
private boolean checkThemeCanBeSavedAndUpdateUI(
boolean checkEmpty,
boolean displayEmptyTip,
boolean checkDuplicated,
boolean displayDuplicatedTip,
UITextField textField,
UILabel errorLabel, UIButton... actionButtons) {
String name = textField.getText();
boolean valid = true;
errorLabel.setText(StringUtils.EMPTY);
if (checkEmpty && isThemeNameEmpty(name)) {
valid = false;
if (displayEmptyTip) {
errorLabel.setText(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Empty_Name_Error_Tip"));
}
} else if (checkDuplicated && isThemeNameDuplicated(name)) {
valid = false;
if (displayDuplicatedTip) {
errorLabel.setText(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Edit_Pane_Duplicated_Name_Error_Tip"));
}
}
errorLabel.setVisible(!valid);
if (actionButtons != null && actionButtons.length > 0) {
for (UIButton button : actionButtons) {
if (button != null) {
button.setEnabled(valid);
}
}
}
return valid;
}
}