From fcaf293f105fdf6efcf3686549fd33ec0a311c34 Mon Sep 17 00:00:00 2001 From: Starryi Date: Mon, 18 Oct 2021 14:47:52 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-58744=20=E3=80=90=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E3=80=91=E6=92=A4=E9=94=80=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E6=A0=B7=E5=BC=8F=E8=AE=BE=E7=BD=AE=E4=B8=8D?= =?UTF-8?q?=E7=AC=A6=E5=90=88=E9=A2=84=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 目前的撤销回退机制是基于AbstractNoScrollPane的自动注册 回调来完成的,灵活性较低,且存在重复注册监听器的问题, 导致一个交互操作会产生多个撤销回退,不适用于日趋复杂的 交互逻辑,后面需要想办法重新设计下。 针对主题的撤销回退,主要原因是跟随主题切换到自定义时,需要将 自定义样式面板设置为跟随主题时一样的配置,但因为上述自动发送 属性更新的逻辑,导致中间产生了大量无效的撤销回退状态。因此 需要临时禁止AbstractAttrNoScrollPane的自动发送属性变化 事件的行为,待面板内容更新完毕后,再恢复自动发送. 【改动思路】 同上 --- .../gui/frpane/AbstractAttrNoScrollPane.java | 14 +++++- .../gui/frpane/AttributeChangeUtils.java | 47 ++++++++++++++++++ .../design/gui/style/FollowingThemePane.java | 16 +++--- .../cell/settingpane/style/StylePane.java | 49 +++++++++++-------- 4 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java index 381a9cd76..a9321879c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java @@ -24,6 +24,16 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane { private AttributeChangeListener listener; private String globalName = ""; + private boolean autoFireAttributesChanged = true; + + public boolean isAutoFireAttributesChanged() { + return this.autoFireAttributesChanged; + } + + public void setAutoFireAttributesChanged(boolean autoFireAttributesChanged) { + this.autoFireAttributesChanged = autoFireAttributesChanged; + } + protected AbstractAttrNoScrollPane() { initAll(); } @@ -127,7 +137,9 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane { public void attributeChanged() { synchronized (this) { if (listener != null) { - listener.attributeChange(); + if (autoFireAttributesChanged) { + listener.attributeChange(); + } } } } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java b/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java new file mode 100644 index 000000000..bfc1ff9d4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java @@ -0,0 +1,47 @@ +package com.fr.design.gui.frpane; + +import java.awt.Component; +import java.awt.Container; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/17 + */ +public class AttributeChangeUtils { + private static AbstractAttrNoScrollPane findNearestAttrNoScrollPaneAncestor(Component c) { + for(Container p = c.getParent(); p != null; p = p.getParent()) { + if (p instanceof AbstractAttrNoScrollPane) { + return (AbstractAttrNoScrollPane) p; + } + } + return null; + } + + public static void changeComposedUI(Component composedComponent, boolean fireMiddleStateChanged, UIChangeAction action) { + AbstractAttrNoScrollPane attrPane = findNearestAttrNoScrollPaneAncestor(composedComponent); + boolean oldAutoFire = true; + + if (!fireMiddleStateChanged) { + // 禁止属性面板自动处理属性更新 + if (attrPane != null) { + oldAutoFire = attrPane.isAutoFireAttributesChanged(); + attrPane.setAutoFireAttributesChanged(false); + } + } + + // 更新UI + action.changeComposedUI(); + + if (!fireMiddleStateChanged) { + // 恢复属性面板自动处理属性更新 + if (attrPane != null) { + attrPane.setAutoFireAttributesChanged(oldAutoFire); + } + } + } + + public interface UIChangeAction { + void changeComposedUI(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java b/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java index 2d596d612..bf06aa2fd 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java @@ -5,6 +5,7 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.event.UIObserver; import com.fr.design.event.UIObserverListener; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.frpane.AttributeChangeUtils; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; @@ -52,12 +53,15 @@ public class FollowingThemePane extends BasicPane implements UIObserver { followingThemeButtonGroup.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - for (FollowingThemeActionChangeListener changeListener : changeListeners) { - changeListener.onFollowingTheme(isFollowingTheme()); - } - invalidate(); - - // 与主题相关的属性面板更新完毕后,再通知外层更新数据 + AttributeChangeUtils.changeComposedUI(FollowingThemePane.this, false, new AttributeChangeUtils.UIChangeAction() { + @Override + public void changeComposedUI() { + for (FollowingThemeActionChangeListener changeListener : changeListeners) { + changeListener.onFollowingTheme(isFollowingTheme()); + } + invalidate(); + } + }); if (uiObserverListener != null) { uiObserverListener.doChange(); } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/StylePane.java b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/StylePane.java index d5019310a..bfd335f39 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/StylePane.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/StylePane.java @@ -6,6 +6,7 @@ import com.fr.design.designer.IntervalConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.event.UIObserver; import com.fr.design.event.UIObserverListener; +import com.fr.design.gui.frpane.AttributeChangeUtils; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; @@ -73,27 +74,13 @@ public class StylePane extends BasicPane implements UIObserver { followingThemeButtonGroup.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - int selectedIndex = followingThemeButtonGroup.getSelectedIndex(); - cardLayout.show(contentPane, FOLLOWING_THEME_STRING_ARRAYS[selectedIndex]); - if (selectedIndex == 1) { - // 对于同一个单元格,跟随主题切换到自定义,自定义中的配置与其保持一致 - NameStyle lastSelectedNameStyle = themedCellStyleListPane.updateBean(); - if (lastSelectedNameStyle != null) { - Style lastSelectedRealStyle = lastSelectedNameStyle.getRealStyle(); - try { - lastSelectedRealStyle = (Style) lastSelectedRealStyle.clone(); - if (lastSelectedRealStyle != null) { - customStylePane.populateBean(lastSelectedRealStyle); - } - } catch (CloneNotSupportedException ex) { - FineLoggerFactory.getLogger().error(ex.getMessage(), ex); - } + AttributeChangeUtils.changeComposedUI(StylePane.this, false, new AttributeChangeUtils.UIChangeAction() { + @Override + public void changeComposedUI() { + int selectedIndex = followingThemeButtonGroup.getSelectedIndex(); + onFollowingThemeSettingChanged(selectedIndex, selectedIndex == 0); } - } else { - // 对于同一个单元格,自定义切换到跟随主题,跟随主题选中"默认"样式,并使用默认样式设置选中的单元格 - themedCellStyleListPane.reset(); - } - + }); fireStateChanged(); } }); @@ -109,6 +96,28 @@ public class StylePane extends BasicPane implements UIObserver { IntervalConstants.INTERVAL_L1, 0); } + private void onFollowingThemeSettingChanged(int selectedIndex, boolean isFollowingTheme) { + cardLayout.show(contentPane, FOLLOWING_THEME_STRING_ARRAYS[selectedIndex]); + if (!isFollowingTheme) { + // 对于同一个单元格,跟随主题切换到自定义,自定义中的配置与其保持一致 + NameStyle lastSelectedNameStyle = themedCellStyleListPane.updateBean(); + if (lastSelectedNameStyle != null) { + Style lastSelectedRealStyle = lastSelectedNameStyle.getRealStyle(); + try { + lastSelectedRealStyle = (Style) lastSelectedRealStyle.clone(); + if (lastSelectedRealStyle != null) { + customStylePane.populateBean(lastSelectedRealStyle); + } + } catch (CloneNotSupportedException ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + } + } else { + // 对于同一个单元格,自定义切换到跟随主题,跟随主题选中"默认"样式,并使用默认样式设置选中的单元格 + themedCellStyleListPane.reset(); + } + } + protected JPanel createTabbedContentPane() { JPanel contentPane = new JPanel(cardLayout) { @Override